Merge "Snap for 6877830 from 8ba33eb34ba0c0acb3cc9273eadc34ed1ff9047b to sdk-release" into sdk-release
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 7933629..89bd66a 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -16,16 +16,25 @@
       "name": "adb_tls_connection_test"
     },
     {
+      "name": "CtsFsMgrTestCases"
+    },
+    {
       "name": "CtsInitTestCases"
     },
     {
+      "name": "CtsLiblogTestCases"
+    },
+    {
+      "name": "CtsLogdTestCases"
+    },
+    {
       "name": "debuggerd_test"
     },
     {
-      "name": "CtsFsMgrTestCases"
+      "name": "fs_mgr_vendor_overlay_test"
     },
     {
-      "name": "fs_mgr_vendor_overlay_test"
+      "name": "init_kill_services_test"
     },
     {
       "name": "libpackagelistparser_test"
@@ -58,5 +67,10 @@
     {
       "name": "propertyinfoserializer_tests"
     }
+  ],
+  "imports": [
+    {
+      "path": "frameworks/base/tests/StagedInstallTest"
+    }
   ]
 }
diff --git a/adb/Android.bp b/adb/Android.bp
index 2fc205f..5c1e1fe 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -12,6 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+tidy_errors = [
+    "-*",
+    "bugprone-inaccurate-erase",
+]
+
 cc_defaults {
     name: "adb_defaults",
 
@@ -20,6 +25,7 @@
         "-Wextra",
         "-Werror",
         "-Wexit-time-destructors",
+        "-Wno-non-virtual-dtor",
         "-Wno-unused-parameter",
         "-Wno-missing-field-initializers",
         "-Wthread-safety",
@@ -73,6 +79,10 @@
             ],
         },
     },
+
+    tidy: true,
+    tidy_checks: tidy_errors,
+    tidy_checks_as_errors: tidy_errors,
 }
 
 cc_defaults {
@@ -108,6 +118,7 @@
     static_libs: [
         "libadb_crypto",
         "libadb_pairing_connection",
+        "libadb_sysdeps",
         "libadb_tls_connection",
         "libadbd",
         "libadbd_core",
@@ -158,6 +169,7 @@
     "services.cpp",
     "sockets.cpp",
     "socket_spec.cpp",
+    "sysdeps/env.cpp",
     "sysdeps/errno.cpp",
     "transport.cpp",
     "transport_fd.cpp",
@@ -252,6 +264,45 @@
     ],
 }
 
+cc_library {
+    name: "libadb_sysdeps",
+    defaults: ["adb_defaults"],
+    recovery_available: true,
+    host_supported: true,
+    compile_multilib: "both",
+    min_sdk_version: "apex_inherit",
+    // This library doesn't use build::GetBuildNumber()
+    use_version_lib: false,
+
+    srcs: [
+        "sysdeps/env.cpp",
+    ],
+
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+
+    target: {
+        windows: {
+            enabled: true,
+            ldflags: ["-municode"],
+        },
+    },
+
+    export_include_dirs: ["."],
+
+    visibility: [
+        "//system/core/adb:__subpackages__",
+        "//bootable/recovery/minadbd:__subpackages__",
+    ],
+
+    apex_available: [
+        "com.android.adbd",
+        "test_com.android.adbd",
+    ],
+}
+
 cc_test_host {
     name: "adb_test",
     defaults: ["adb_defaults"],
@@ -265,6 +316,7 @@
         "libadb_pairing_auth_static",
         "libadb_pairing_connection_static",
         "libadb_protos_static",
+        "libadb_sysdeps",
         "libadb_tls_connection_static",
         "libbase",
         "libcutils",
@@ -321,6 +373,7 @@
         "libadb_pairing_auth",
         "libadb_pairing_connection",
         "libadb_protos",
+        "libadb_sysdeps",
         "libadb_tls_connection",
         "libandroidfw",
         "libapp_processes_protos_full",
@@ -702,6 +755,8 @@
         "mdns_test.cpp",
     ],
 
+    test_config: "adb_test.xml",
+
     shared_libs: [
         "liblog",
     ],
@@ -822,6 +877,7 @@
         "libadb_pairing_auth_static",
         "libadb_pairing_connection_static",
         "libadb_protos_static",
+        "libadb_sysdeps",
         "libadb_tls_connection_static",
         "libandroidfw",
         "libbase",
diff --git a/adb/README.md b/adb/README.md
new file mode 100644
index 0000000..224387c
--- /dev/null
+++ b/adb/README.md
@@ -0,0 +1,94 @@
+# ADB Internals
+
+If you are new to adb source code, you should start by reading [OVERVIEW.TXT](OVERVIEW.TXT) which describes the three components of adb pipeline.
+
+This document is here to boost what can be achieved within a "window of naive interest". You will not find function or class documentation here but rather the "big picture" which should allow you to build a mental map to help navigate the code.
+
+## Three components of adb pipeline
+
+As outlined in the overview, this codebase generates three components (Client, Server (a.k.a Host), and Daemon (a.k.a adbd)). The central part is the Server which runs on the Host computer. On one side the Server exposes a "Smart Socket" to Clients such as adb or DDMLIB. On the other side, the Server continuously monitors for connecting Daemons (as USB devices or TCP emulator). Communication with a device is done with a Transport.
+
+```
++----------+              +------------------------+
+|   ADB    +----------+   |      ADB SERVER        |                   +----------+
+|  CLIENT  |          |   |                        |              (USB)|   ADBD   |
++----------+          |   |                     Transport+-------------+ (DEVICE) |
+                      |   |                        |                   +----------+
++-----------          |   |                        |
+|   ADB    |          v   +                        |                   +----------+
+|  CLIENT  +--------->SmartSocket                  |              (USB)|   ADBD   |
++----------+          ^   | (TCP/IP)            Transport+-------------+ (DEVICE) |
+                      |   |                        |                   +----------+
++----------+          |   |                        |
+|  DDMLIB  |          |   |                     Transport+--+          +----------+
+|  CLIENT  +----------+   |                        |        |  (TCP/IP)|   ADBD   |
++----------+              +------------------------+        +----------|(EMULATOR)|
+                                                                       +----------+
+```
+
+The Client and the Server are contained in the same executable and both run on the Host machine. Code sections specific to the Host is enclosed within `ADB_HOST` guard. adbd runs on the Android Device. Daemon specific code is enclosed in `!ADB_HOST` but also sometimes with-in `__ANDROID__` guard.
+
+
+## "SMART SOCKET" and TRANSPORT
+
+A smart socket is a simple TCP socket with a smart protocol built on top of it. This is what Clients connect onto from the Host side. The Client must always initiate communication via a human readable request but the response format varies. The smart protocol is documented in [SERVICES.TXT](SERVICES.TXT).
+
+On the other side, the Server communicate with a device via a Transport. adb initially targeted devices connecting over USB, which is restricted to a fixed number of data streams. Therefore, adb multiplexes multiple byte streams over a single pipe via Transport. When devices connecting over other mechanisms (e.g. emulators over TCP) were introduced, the existing transport protocol was maintained.
+
+## THREADING MODEL and FDEVENT system
+
+At the heart of both the Server and Daemon is a main thread running an fdevent loop, which is an platform-independent abstraction over poll/epoll/WSAPoll monitoring file descriptors events. Requests and services are usually server from the main thread but some service requests result in new threads being spawned.
+
+To allow for operations to run on the Main thread, fdevent features a RunQueue combined with an interrupt fd to force polling to return.
+
+```
++------------+    +-------------------------^
+|  RUNQUEUE  |    |                         |
++------------+    |  POLLING (Main thread)  |
+| Function<> |    |                         |
++------------+    |                         |
+| Function<> |    ^-^-------^-------^------^^
++------------+      |       |       |       |
+|    ...     |      |       |       |       |
++------------+      |       |       |       |
+|            |      |       |       |       |
+|============|      |       |       |       |
+|Interrupt fd+------+  +----+  +----+  +----+
++------------+         fd      Socket  Pipe
+```
+
+## ASOCKET, APACKET, and AMESSAGE
+
+The asocket, apacket, and amessage constructs exist only to wrap data while it transits on a Transport. An asocket handles a stream of apackets. An apacket consists in a amessage header featuring a command (`A_SYNC`, `A_OPEN`, `A_CLSE`, `A_WRTE`, `A_OKAY`, ...) followed by a payload (find more documentation in [protocol.txt](protocol.txt). There is no `A_READ` command because an asocket is unidirectional. To model a bi-directional stream, asocket have a peer which go in the opposite direction.
+
+An asocket features a buffer where the elemental unit is an apacket. Is traffic is inbound, the buffer stores apacket until they are consumed. If the traffic is oubound, the buffer store apackets until they are sent down the wire (with `A_WRTE` commands).
+
+```
++---------------------ASocket------------------------+
+ |                                                   |
+ | +----------------APacket Queue------------------+ |
+ | |                                               | |
+ | |            APacket     APacket     APacket    | |
+ | |          +--------+  +--------+  +--------+   | |
+ | |          |AMessage|  |AMessage|  |AMessage|   | |
+ | |          +--------+  +--------+  +--------+   | |
+ | |          |        |  |        |  |        |   | |
+ | |  .....   |        |  |        |  |        |   | |
+ | |          |  Data  |  |  Data  |  |  Data  |   | |
+ | |          |        |  |        |  |        |   | |
+ | |          |        |  |        |  |        |   | |
+ | |          +--------+  +--------+  +--------+   | |
+ | |                                               | |
+ | +-----------------------------------------------+ |
+ +---------------------------------------------------+
+```
+
+This system allows to multiplex data streams on an unique byte stream.  Without entering too much into details, the amessage fields arg1 and arg2 are used alike in the TCP protocol where local and remote ports identify an unique stream. Note that unlike TCP which feature an "unacknowledged-send window", an apacket is sent only after the previous one has been confirmed to be received.
+
+The two types of asocket (Remote and Local) differentiate between outbound and inbound traffic.
+
+## adbd <-> APPPLICATION communication
+
+This pipeline is detailed in [services.cpp](services.cpp). The JDWP extension implemented by Dalvik/ART are documented in:
+- platform/dalvik/+/master/docs/debugmon.html
+- platform/dalvik/+/master/docs/debugger.html
diff --git a/adb/adb_test.xml b/adb/adb_test.xml
new file mode 100644
index 0000000..cc3302d
--- /dev/null
+++ b/adb/adb_test.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- This test config file is auto-generated. -->
+<configuration description="Runs adbd_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="adbd_test->/data/local/tmp/adbd_test" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="adbd_test" />
+    </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+      <option name="mainline-module-package-name" value="com.google.android.adbd" />
+    </object>
+</configuration>
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 66cba12..e72d8b6 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -55,7 +55,7 @@
 
 bool set_file_block_mode(borrowed_fd fd, bool block);
 
-// Given forward/reverse targets, returns true if they look sane. If an error is found, fills
+// Given forward/reverse targets, returns true if they look valid. If an error is found, fills
 // |error| and returns false.
 // Currently this only checks "tcp:" targets. Additional checking could be added for other targets
 // if needed.
diff --git a/adb/apex/apex_manifest.json b/adb/apex/apex_manifest.json
index ff2df12..4a07bdc 100644
--- a/adb/apex/apex_manifest.json
+++ b/adb/apex/apex_manifest.json
@@ -1,4 +1,4 @@
 {
   "name": "com.android.adbd",
-  "version": 1
+  "version": 300900700
 }
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 8bbe2a8..2e8b975 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -1053,7 +1053,7 @@
         if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, buf, data_length, dry_run)) {
             return false;
         }
-        return sc.ReadAcknowledgements();
+        return sc.ReadAcknowledgements(sync);
 #endif
     }
 
@@ -1077,7 +1077,7 @@
             return false;
         }
     }
-    return sc.ReadAcknowledgements();
+    return sc.ReadAcknowledgements(sync);
 }
 
 static bool sync_recv_v1(SyncConnection& sc, const char* rpath, const char* lpath, const char* name,
diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp
index 3033059..60735f8 100644
--- a/adb/client/incremental.cpp
+++ b/adb/client/incremental.cpp
@@ -55,9 +55,10 @@
         return {};
     }
 
-    std::vector<char> invalid_signature;
+    auto [signature, tree_size] = read_id_sig_headers(fd);
 
-    if (st.st_size > kMaxSignatureSize) {
+    std::vector<char> invalid_signature;
+    if (signature.size() > kMaxSignatureSize) {
         if (!silent) {
             fprintf(stderr, "Signature is too long. Max allowed is %d. Abort.\n",
                     kMaxSignatureSize);
@@ -65,7 +66,6 @@
         return {std::move(fd), std::move(invalid_signature)};
     }
 
-    auto [signature, tree_size] = read_id_sig_headers(fd);
     if (auto expected = verity_tree_size_for_file(file_size); tree_size != expected) {
         if (!silent) {
             fprintf(stderr,
diff --git a/adb/client/incremental_utils.cpp b/adb/client/incremental_utils.cpp
index dd117d2..1a071fd 100644
--- a/adb/client/incremental_utils.cpp
+++ b/adb/client/incremental_utils.cpp
@@ -305,6 +305,7 @@
 static std::vector<int32_t> InstallationPriorityBlocks(borrowed_fd fd, Size fileSize) {
     static constexpr std::array<std::string_view, 3> additional_matches = {
             "resources.arsc"sv, "AndroidManifest.xml"sv, "classes.dex"sv};
+
     auto [zip, _] = openZipArchive(fd, fileSize);
     if (!zip) {
         return {};
@@ -325,7 +326,7 @@
     }
 
     std::vector<int32_t> installationPriorityBlocks;
-    ZipEntry entry;
+    ZipEntry64 entry;
     std::string_view entryName;
     while (Next(cookie, &entry, &entryName) == 0) {
         if (entryName == "classes.dex"sv) {
@@ -358,7 +359,7 @@
 
 std::vector<int32_t> PriorityBlocksForFile(const std::string& filepath, borrowed_fd fd,
                                            Size fileSize) {
-    if (!android::base::EndsWithIgnoreCase(filepath, ".apk"sv)) {
+    if (!android::base::EndsWithIgnoreCase(filepath, ".apk")) {
         return {};
     }
     off64_t signerOffset = SignerBlockOffset(fd, fileSize);
diff --git a/adb/crypto/Android.bp b/adb/crypto/Android.bp
index 9d14b03..e2c27f1 100644
--- a/adb/crypto/Android.bp
+++ b/adb/crypto/Android.bp
@@ -48,6 +48,7 @@
 
     shared_libs: [
         "libadb_protos",
+        "libadb_sysdeps",
         "libbase",
         "liblog",
         "libcrypto",
@@ -76,5 +77,6 @@
 
     static_libs: [
         "libadb_protos_static",
+        "libadb_sysdeps",
     ],
 }
diff --git a/adb/crypto/rsa_2048_key.cpp b/adb/crypto/rsa_2048_key.cpp
index 7911af9..6d9ee30 100644
--- a/adb/crypto/rsa_2048_key.cpp
+++ b/adb/crypto/rsa_2048_key.cpp
@@ -20,32 +20,11 @@
 #include <crypto_utils/android_pubkey.h>
 #include <openssl/bn.h>
 #include <openssl/rsa.h>
+#include <sysdeps/env.h>
 
 namespace adb {
 namespace crypto {
 
-namespace {
-std::string get_user_info() {
-    std::string hostname;
-    if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
-#if !defined(_WIN32)
-    char buf[64];
-    if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
-#endif
-    if (hostname.empty()) hostname = "unknown";
-
-    std::string username;
-    if (getenv("LOGNAME")) username = getenv("LOGNAME");
-#if !defined(_WIN32)
-    if (username.empty() && getlogin()) username = getlogin();
-#endif
-    if (username.empty()) hostname = "unknown";
-
-    return " " + username + "@" + hostname;
-}
-
-}  // namespace
-
 bool CalculatePublicKey(std::string* out, RSA* private_key) {
     uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
     if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
@@ -63,7 +42,10 @@
     size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(out->data()), binary_key_data,
                                            sizeof(binary_key_data));
     out->resize(actual_length);
-    out->append(get_user_info());
+    out->append(" ");
+    out->append(sysdeps::GetLoginNameUTF8());
+    out->append("@");
+    out->append(sysdeps::GetHostNameUTF8());
     return true;
 }
 
diff --git a/adb/crypto/tests/Android.bp b/adb/crypto/tests/Android.bp
index b32dcf7..b041055 100644
--- a/adb/crypto/tests/Android.bp
+++ b/adb/crypto/tests/Android.bp
@@ -35,6 +35,7 @@
     static_libs: [
         "libadb_crypto_static",
         "libadb_protos_static",
+        "libadb_sysdeps",
     ],
 
     test_suites: ["device-tests"],
diff --git a/adb/daemon/adb_wifi.cpp b/adb/daemon/adb_wifi.cpp
index bce303b..2f9e9b4 100644
--- a/adb/daemon/adb_wifi.cpp
+++ b/adb/daemon/adb_wifi.cpp
@@ -42,7 +42,8 @@
 
 static void adb_disconnected(void* unused, atransport* t) {
     LOG(INFO) << "ADB wifi device disconnected";
-    adbd_auth_tls_device_disconnected(auth_ctx, kAdbTransportTypeWifi, t->auth_id);
+    CHECK(t->auth_id.has_value());
+    adbd_auth_tls_device_disconnected(auth_ctx, kAdbTransportTypeWifi, t->auth_id.value());
 }
 
 // TODO(b/31559095): need bionic host so that we can use 'prop_info' returned
diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp
index 2edf582..1a1e4ad 100644
--- a/adb/daemon/auth.cpp
+++ b/adb/daemon/auth.cpp
@@ -207,15 +207,27 @@
 }
 
 static void adbd_auth_key_authorized(void* arg, uint64_t id) {
-    LOG(INFO) << "adb client authorized";
+    LOG(INFO) << "adb client " << id << " authorized";
     fdevent_run_on_main_thread([=]() {
-        LOG(INFO) << "arg = " << reinterpret_cast<uintptr_t>(arg);
         auto* transport = transport_from_callback_arg(arg);
         if (!transport) {
-            LOG(ERROR) << "authorization received for deleted transport, ignoring";
+            LOG(ERROR) << "authorization received for deleted transport (" << id << "), ignoring";
             return;
         }
-        transport->auth_id = id;
+
+        if (transport->auth_id.has_value()) {
+            if (transport->auth_id.value() != id) {
+                LOG(ERROR)
+                        << "authorization received, but auth id doesn't match, ignoring (expected "
+                        << transport->auth_id.value() << ", got " << id << ")";
+                return;
+            }
+        } else {
+            // Older versions (i.e. dogfood/beta builds) of libadbd_auth didn't pass the initial
+            // auth id to us, so we'll just have to trust it until R ships and we can retcon this.
+            transport->auth_id = id;
+        }
+
         adbd_auth_verified(transport);
     });
 }
@@ -265,14 +277,20 @@
 
 static void adb_disconnected(void* unused, atransport* t) {
     LOG(INFO) << "ADB disconnect";
-    adbd_auth_notify_disconnect(auth_ctx, t->auth_id);
+    CHECK(t->auth_id.has_value());
+    adbd_auth_notify_disconnect(auth_ctx, t->auth_id.value());
 }
 
 void adbd_auth_confirm_key(atransport* t) {
     LOG(INFO) << "prompting user to authorize key";
     t->AddDisconnect(&adb_disconnect);
-    adbd_auth_prompt_user(auth_ctx, t->auth_key.data(), t->auth_key.size(),
-                          transport_to_callback_arg(t));
+    if (adbd_auth_prompt_user_with_id) {
+        t->auth_id = adbd_auth_prompt_user_with_id(auth_ctx, t->auth_key.data(), t->auth_key.size(),
+                                                   transport_to_callback_arg(t));
+    } else {
+        adbd_auth_prompt_user(auth_ctx, t->auth_key.data(), t->auth_key.size(),
+                              transport_to_callback_arg(t));
+    }
 }
 
 void adbd_notify_framework_connected_key(atransport* t) {
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index eb28668..8c41c5e 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -108,9 +108,12 @@
     // AID_NET_BW_STATS to read out qtaguid statistics
     // AID_READPROC for reading /proc entries across UID boundaries
     // AID_UHID for using 'hid' command to read/write to /dev/uhid
+    // AID_EXT_DATA_RW for writing to /sdcard/Android/data (devices without sdcardfs)
+    // AID_EXT_OBB_RW for writing to /sdcard/Android/obb (devices without sdcardfs)
     gid_t groups[] = {AID_ADB,          AID_LOG,          AID_INPUT,    AID_INET,
                       AID_NET_BT,       AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
-                      AID_NET_BW_STATS, AID_READPROC,     AID_UHID};
+                      AID_NET_BW_STATS, AID_READPROC,     AID_UHID,     AID_EXT_DATA_RW,
+                      AID_EXT_OBB_RW};
     minijail_set_supplementary_gids(jail.get(), arraysize(groups), groups);
 
     // Don't listen on a port (default 5037) if running in secure mode.
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index a663871..50d7364 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -584,12 +584,11 @@
                 incoming_header_ = msg;
             } else {
                 size_t bytes_left = incoming_header_->data_length - incoming_payload_.size();
-                Block payload = std::move(block->payload);
                 if (block->payload.size() > bytes_left) {
                     HandleError("received too many bytes while waiting for payload");
                     return false;
                 }
-                incoming_payload_.append(std::move(payload));
+                incoming_payload_.append(std::move(block->payload));
             }
 
             if (incoming_header_->data_length == incoming_payload_.size()) {
diff --git a/adb/fdevent/fdevent_test.h b/adb/fdevent/fdevent_test.h
index ecda4da..fcbf181 100644
--- a/adb/fdevent/fdevent_test.h
+++ b/adb/fdevent/fdevent_test.h
@@ -65,7 +65,7 @@
         ASSERT_EQ(0u, fdevent_installed_count());
     }
 
-    // Register a dummy socket used to wake up the fdevent loop to tell it to die.
+    // Register a placeholder socket used to wake up the fdevent loop to tell it to die.
     void PrepareThread() {
         int dummy_fds[2];
         if (adb_socketpair(dummy_fds) != 0) {
@@ -84,7 +84,7 @@
     }
 
     size_t GetAdditionalLocalSocketCount() {
-        // dummy socket installed in PrepareThread()
+        // placeholder socket installed in PrepareThread()
         return 1;
     }
 
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 13a4737..33b9524 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -856,7 +856,7 @@
     s->peer->shutdown = nullptr;
     s->peer->close = local_socket_close_notify;
     s->peer->peer = nullptr;
-    /* give him our transport and upref it */
+    /* give them our transport and upref it */
     s->peer->transport = s->transport;
 
     connect_to_remote(s->peer, std::string_view(s->smart_socket_data).substr(4));
diff --git a/adb/sysdeps/env.cpp b/adb/sysdeps/env.cpp
new file mode 100644
index 0000000..4058728
--- /dev/null
+++ b/adb/sysdeps/env.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "sysdeps/env.h"
+
+#ifdef _WIN32
+#include <lmcons.h>
+#include <windows.h>
+#endif  // _WIN32
+
+#include <android-base/utf8.h>
+
+namespace adb {
+namespace sysdeps {
+
+std::optional<std::string> GetEnvironmentVariable(std::string_view var) {
+    if (var.empty()) {
+        return std::nullopt;
+    }
+
+#ifdef _WIN32
+    constexpr size_t kMaxEnvVarSize = 32767;
+    wchar_t wbuf[kMaxEnvVarSize];
+    std::wstring wvar;
+    if (!android::base::UTF8ToWide(var.data(), &wvar)) {
+        return std::nullopt;
+    }
+
+    auto sz = ::GetEnvironmentVariableW(wvar.data(), wbuf, sizeof(wbuf));
+    if (sz == 0) {
+        return std::nullopt;
+    }
+
+    std::string val;
+    if (!android::base::WideToUTF8(wbuf, &val)) {
+        return std::nullopt;
+    }
+
+    return std::make_optional(val);
+#else  // !_WIN32
+    const char* val = getenv(var.data());
+    if (val == nullptr) {
+        return std::nullopt;
+    }
+
+    return std::make_optional(std::string(val));
+#endif
+}
+
+#ifdef _WIN32
+constexpr char kHostNameEnvVar[] = "COMPUTERNAME";
+constexpr char kUserNameEnvVar[] = "USERNAME";
+#else
+constexpr char kHostNameEnvVar[] = "HOSTNAME";
+constexpr char kUserNameEnvVar[] = "LOGNAME";
+#endif
+
+std::string GetHostNameUTF8() {
+    const auto hostName = GetEnvironmentVariable(kHostNameEnvVar);
+    if (hostName && !hostName->empty()) {
+        return *hostName;
+    }
+
+#ifdef _WIN32
+    wchar_t wbuf[MAX_COMPUTERNAME_LENGTH + 1];
+    DWORD size = sizeof(wbuf);
+    if (!GetComputerNameW(wbuf, &size) || size == 0) {
+        return "";
+    }
+
+    std::string name;
+    if (!android::base::WideToUTF8(wbuf, &name)) {
+        return "";
+    }
+
+    return name;
+#else   // !_WIN32
+    char buf[256];
+    return (gethostname(buf, sizeof(buf)) == -1) ? "" : buf;
+#endif  // _WIN32
+}
+
+std::string GetLoginNameUTF8() {
+    const auto userName = GetEnvironmentVariable(kUserNameEnvVar);
+    if (userName && !userName->empty()) {
+        return *userName;
+    }
+
+#ifdef _WIN32
+    wchar_t wbuf[UNLEN + 1];
+    DWORD size = sizeof(wbuf);
+    if (!GetUserNameW(wbuf, &size) || size == 0) {
+        return "";
+    }
+
+    std::string login;
+    if (!android::base::WideToUTF8(wbuf, &login)) {
+        return "";
+    }
+
+    return login;
+#else   // !_WIN32
+    const char* login = getlogin();
+    return login ? login : "";
+#endif  // _WIN32
+}
+
+}  // namespace sysdeps
+}  // namespace adb
diff --git a/adb/sysdeps/env.h b/adb/sysdeps/env.h
new file mode 100644
index 0000000..b39b675
--- /dev/null
+++ b/adb/sysdeps/env.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <optional>
+#include <string>
+
+namespace adb {
+namespace sysdeps {
+
+// Attempts to retrieve the environment variable value for |var|. Returns std::nullopt
+// if unset.
+std::optional<std::string> GetEnvironmentVariableUTF8(std::string_view var);
+
+// Gets the host name of the system. Returns empty string on failure.
+std::string GetHostNameUTF8();
+// Gets the current login user. Returns empty string on failure.
+std::string GetLoginNameUTF8();
+
+}  // namespace sysdeps
+}  // namespace adb
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index be82bc0..217a6b7 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -1010,55 +1010,6 @@
     return _fh_to_int(f);
 }
 
-static bool isBlankStr(const char* str) {
-    for (; *str != '\0'; ++str) {
-        if (!isblank(*str)) {
-            return false;
-        }
-    }
-    return true;
-}
-
-int adb_gethostname(char* name, size_t len) {
-    const char* computerName = adb_getenv("COMPUTERNAME");
-    if (computerName && !isBlankStr(computerName)) {
-        strncpy(name, computerName, len);
-        name[len - 1] = '\0';
-        return 0;
-    }
-
-    wchar_t buffer[MAX_COMPUTERNAME_LENGTH + 1];
-    DWORD size = sizeof(buffer);
-    if (!GetComputerNameW(buffer, &size)) {
-        return -1;
-    }
-    std::string name_utf8;
-    if (!android::base::WideToUTF8(buffer, &name_utf8)) {
-        return -1;
-    }
-
-    strncpy(name, name_utf8.c_str(), len);
-    name[len - 1] = '\0';
-    return 0;
-}
-
-int adb_getlogin_r(char* buf, size_t bufsize) {
-    wchar_t buffer[UNLEN + 1];
-    DWORD len = sizeof(buffer);
-    if (!GetUserNameW(buffer, &len)) {
-        return -1;
-    }
-
-    std::string login;
-    if (!android::base::WideToUTF8(buffer, &login)) {
-        return -1;
-    }
-
-    strncpy(buf, login.c_str(), bufsize);
-    buf[bufsize - 1] = '\0';
-    return 0;
-}
-
 #undef accept
 int adb_socket_accept(borrowed_fd serverfd, struct sockaddr* addr, socklen_t* addrlen) {
     FH serverfh = _fh_from_int(serverfd, __func__);
diff --git a/adb/test_device.py b/adb/test_device.py
index c1caafc..a92d4a7 100755
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -1271,6 +1271,31 @@
                 if temp_dir is not None:
                     shutil.rmtree(temp_dir)
 
+        def test_push_sync_multiple(self):
+            """Sync multiple host directories to a specific path."""
+
+            try:
+                temp_dir = tempfile.mkdtemp()
+                temp_files = make_random_host_files(in_dir=temp_dir, num_files=32)
+
+                device_dir = posixpath.join(self.DEVICE_TEMP_DIR, 'sync_src_dst')
+
+                # Clean up any stale files on the device.
+                device = adb.get_device()  # pylint: disable=no-member
+                device.shell(['rm', '-rf', device_dir])
+                device.shell(['mkdir', '-p', device_dir])
+
+                host_paths = [os.path.join(temp_dir, x.base_name) for x in temp_files]
+                device.push(host_paths, device_dir, sync=True)
+
+                self.verify_sync(device, temp_files, device_dir)
+
+                self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+            finally:
+                if temp_dir is not None:
+                    shutil.rmtree(temp_dir)
+
+
         def test_push_dry_run_nonexistent_file(self):
             """Push with dry run."""
 
diff --git a/adb/transport.h b/adb/transport.h
index b1f2744..d59be59 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -27,6 +27,7 @@
 #include <list>
 #include <memory>
 #include <mutex>
+#include <optional>
 #include <string>
 #include <string_view>
 #include <thread>
@@ -320,7 +321,7 @@
 #if !ADB_HOST
     // Used to provide the key to the framework.
     std::string auth_key;
-    uint64_t auth_id;
+    std::optional<uint64_t> auth_id;
 #endif
 
     bool IsTcpDevice() const { return type == kTransportLocal; }
diff --git a/bootstat/boot_event_record_store.h b/bootstat/boot_event_record_store.h
index f872c85..e852304 100644
--- a/bootstat/boot_event_record_store.h
+++ b/bootstat/boot_event_record_store.h
@@ -69,4 +69,4 @@
   DISALLOW_COPY_AND_ASSIGN(BootEventRecordStore);
 };
 
-#endif  // BOOT_EVENT_RECORD_STORE_H_
\ No newline at end of file
+#endif  // BOOT_EVENT_RECORD_STORE_H_
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index 2f2919f..7cff7dc 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -1331,7 +1331,7 @@
     shift
   fi
 
-  # Check if all conditions for the script are sane
+  # Check if all conditions for the script are valid
 
   if [ -z "${ANDROID_SERIAL}" ]; then
     ndev=`(
diff --git a/cli-test/cli-test.cpp b/cli-test/cli-test.cpp
index d6e27ee..d1ef1b4 100644
--- a/cli-test/cli-test.cpp
+++ b/cli-test/cli-test.cpp
@@ -146,6 +146,13 @@
       test->befores.push_back(line);
     } else if (Match(&line, "after:")) {
       test->afters.push_back(line);
+    } else if (Match(&line, "expected-exit-status:")) {
+      char* end_p;
+      errno = 0;
+      test->exit_status = strtol(line.c_str(), &end_p, 10);
+      if (errno != 0 || *end_p != '\0') {
+        Die(0, "%s:%zu: bad exit status: \"%s\"", g_file, g_line, line.c_str());
+      }
     } else if (Match(&line, "expected-stdout:")) {
       // Collect tab-indented lines.
       std::string text;
@@ -231,15 +238,15 @@
       V("running command \"%s\"", test.command.c_str());
       CapturedStdout test_stdout;
       CapturedStderr test_stderr;
-      int exit_status = system(test.command.c_str());
+      int status = system(test.command.c_str());
       test_stdout.Stop();
       test_stderr.Stop();
 
-      V("exit status %d", exit_status);
-      if (exit_status != test.exit_status) {
+      V("system() returned status %d", status);
+      if (WEXITSTATUS(status) != test.exit_status) {
         failed = true;
         fprintf(stderr, "Incorrect exit status: expected %d but %s\n", test.exit_status,
-                ExitStatusToString(exit_status).c_str());
+                ExitStatusToString(status).c_str());
       }
 
       if (!CheckOutput("stdout", test_stdout.str(), test.expected_stdout, FILES)) failed = true;
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 31c2d5d..99cabdd 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -253,7 +253,6 @@
         "libcutils",
         "libdebuggerd_client",
         "liblog",
-        "libminijail",
         "libnativehelper",
         "libunwindstack",
     ],
@@ -261,6 +260,7 @@
     static_libs: [
         "libdebuggerd",
         "libgmock",
+        "libminijail",
     ],
 
     header_libs: [
@@ -343,6 +343,12 @@
     apex_available: [
         "com.android.runtime",
     ],
+
+    product_variables: {
+        experimental_mte: {
+            cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+        },
+    },
 }
 
 cc_binary {
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index 5c02738..6bfb5f2 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -70,36 +70,6 @@
   tv->tv_usec = static_cast<long>(microseconds.count());
 }
 
-static void get_wchan_header(pid_t pid, std::stringstream& buffer) {
-  struct tm now;
-  time_t t = time(nullptr);
-  localtime_r(&t, &now);
-  char timestamp[32];
-  strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", &now);
-  std::string time_now(timestamp);
-
-  std::string path = "/proc/" + std::to_string(pid) + "/cmdline";
-
-  char proc_name_buf[1024];
-  const char* proc_name = nullptr;
-  std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(path.c_str(), "r"), &fclose);
-
-  if (fp) {
-    proc_name = fgets(proc_name_buf, sizeof(proc_name_buf), fp.get());
-  }
-
-  if (!proc_name) {
-    proc_name = "<unknown>";
-  }
-
-  buffer << "\n----- Waiting Channels: pid " << pid << " at " << time_now << " -----\n"
-         << "Cmd line: " << proc_name << "\n";
-}
-
-static void get_wchan_footer(pid_t pid, std::stringstream& buffer) {
-  buffer << "----- end " << std::to_string(pid) << " -----\n";
-}
-
 /**
  * Returns the wchan data for each thread in the process,
  * or empty string if unable to obtain any data.
@@ -125,9 +95,10 @@
   }
 
   if (std::string str = data.str(); !str.empty()) {
-    get_wchan_header(pid, buffer);
+    buffer << "\n----- Waiting Channels: pid " << pid << " at " << get_timestamp() << " -----\n"
+           << "Cmd line: " << get_process_name(pid) << "\n";
     buffer << "\n" << str << "\n";
-    get_wchan_footer(pid, buffer);
+    buffer << "----- end " << std::to_string(pid) << " -----\n";
     buffer << "\n";
   }
 
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index d7cb972..5280121 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -40,6 +40,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <bionic/mte_kernel.h>
 #include <bionic/reserved_signals.h>
 #include <cutils/sockets.h>
 #include <log/log.h>
@@ -486,6 +487,17 @@
         continue;
       }
 
+#ifdef ANDROID_EXPERIMENTAL_MTE
+      struct iovec iov = {
+          &info.tagged_addr_ctrl,
+          sizeof(info.tagged_addr_ctrl),
+      };
+      if (ptrace(PTRACE_GETREGSET, thread, NT_ARM_TAGGED_ADDR_CTRL,
+                 reinterpret_cast<void*>(&iov)) == -1) {
+        info.tagged_addr_ctrl = -1;
+      }
+#endif
+
       if (thread == g_target_thread) {
         // Read the thread's registers along with the rest of the crash info out of the pipe.
         ReadCrashInfo(input_pipe, &siginfo, &info.registers, &process_info);
@@ -585,8 +597,8 @@
   }
 
   // TODO: Use seccomp to lock ourselves down.
-  unwindstack::UnwinderFromPid unwinder(256, vm_pid);
-  if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
+  unwindstack::UnwinderFromPid unwinder(256, vm_pid, unwindstack::Regs::CurrentArch());
+  if (!unwinder.Init()) {
     LOG(FATAL) << "Failed to init unwinder object.";
   }
 
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 9d7658e..5ed9e57 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -18,6 +18,7 @@
 #include <fcntl.h>
 #include <stdlib.h>
 #include <sys/capability.h>
+#include <sys/mman.h>
 #include <sys/prctl.h>
 #include <sys/ptrace.h>
 #include <sys/resource.h>
@@ -172,6 +173,8 @@
   void StartCrasher(const std::string& crash_type);
   void FinishCrasher();
   void AssertDeath(int signo);
+
+  static void Trap(void* ptr);
 };
 
 CrasherTest::CrasherTest() {
@@ -306,6 +309,11 @@
   std::string result;
   ConsumeFd(std::move(output_fd), &result);
   ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
+
+  if (mte_supported()) {
+    // Test that the default TAGGED_ADDR_CTRL value is set.
+    ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)");
+  }
 }
 
 TEST_F(CrasherTest, tagged_fault_addr) {
@@ -334,6 +342,48 @@
       R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr (0x100000000000dead|0xdead))");
 }
 
+// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
+// compiler could still clobber the argument register before trapping, but that's unlikely.
+__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
+  __builtin_trap();
+}
+
+TEST_F(CrasherTest, heap_addr_in_register) {
+#if defined(__i386__)
+  GTEST_SKIP() << "architecture does not pass arguments in registers";
+#endif
+  int intercept_result;
+  unique_fd output_fd;
+  StartProcess([]() {
+    // Crash with a heap pointer in the first argument register.
+    Trap(malloc(1));
+  });
+
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  int status;
+  ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0)));
+  ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal";
+  // Don't test the signal number because different architectures use different signals for
+  // __builtin_trap().
+  FinishIntercept(&intercept_result);
+
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+
+#if defined(__aarch64__)
+  ASSERT_MATCH(result, "memory near x0");
+#elif defined(__arm__)
+  ASSERT_MATCH(result, "memory near r0");
+#elif defined(__x86_64__)
+  ASSERT_MATCH(result, "memory near rdi");
+#else
+  ASSERT_TRUE(false) << "unsupported architecture";
+#endif
+}
+
 #if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
 static void SetTagCheckingLevelSync() {
   int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
@@ -512,6 +562,55 @@
 #endif
 }
 
+#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
+static uintptr_t CreateTagMapping() {
+  uintptr_t mapping =
+      reinterpret_cast<uintptr_t>(mmap(nullptr, getpagesize(), PROT_READ | PROT_WRITE | PROT_MTE,
+                                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+  if (reinterpret_cast<void*>(mapping) == MAP_FAILED) {
+    return 0;
+  }
+  __asm__ __volatile__(".arch_extension mte; stg %0, [%0]"
+                       :
+                       : "r"(mapping + (1ULL << 56))
+                       : "memory");
+  return mapping;
+}
+#endif
+
+TEST_F(CrasherTest, mte_tag_dump) {
+#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE)
+  if (!mte_supported()) {
+    GTEST_SKIP() << "Requires MTE";
+  }
+
+  int intercept_result;
+  unique_fd output_fd;
+  StartProcess([&]() {
+    SetTagCheckingLevelSync();
+    Trap(reinterpret_cast<void *>(CreateTagMapping()));
+  });
+
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGTRAP);
+  FinishIntercept(&intercept_result);
+
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+
+  ASSERT_MATCH(result, R"(memory near x0:
+.*
+.*
+    01.............0 0000000000000000 0000000000000000  ................
+    00.............0)");
+#else
+  GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE";
+#endif
+}
+
 TEST_F(CrasherTest, LD_PRELOAD) {
   int intercept_result;
   unique_fd output_fd;
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 9bcbdb3..abcb2c4 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -82,16 +82,12 @@
     thread.pid = getpid();
     thread.tid = gettid();
     thread.thread_name = get_thread_name(gettid());
-    unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch();
-    thread.registers.reset(unwindstack::Regs::CreateFromUcontext(arch, ucontext));
+    thread.registers.reset(
+        unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
 
     // TODO: Create this once and store it in a global?
     unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
-    if (unwinder.Init(arch)) {
-      dump_backtrace_thread(output_fd, &unwinder, thread);
-    } else {
-      async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder.");
-    }
+    dump_backtrace_thread(output_fd, &unwinder, thread);
   }
   __linker_disable_fallback_allocator();
 }
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index c606970..c543a83 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -18,8 +18,9 @@
 
 #include "libdebuggerd/backtrace.h"
 
-#include <errno.h>
 #include <dirent.h>
+#include <errno.h>
+#include <inttypes.h>
 #include <limits.h>
 #include <stddef.h>
 #include <stdio.h>
@@ -27,7 +28,6 @@
 #include <string.h>
 #include <sys/ptrace.h>
 #include <sys/types.h>
-#include <time.h>
 #include <unistd.h>
 
 #include <map>
@@ -40,14 +40,10 @@
 
 #include "libdebuggerd/types.h"
 #include "libdebuggerd/utility.h"
+#include "util.h"
 
 static void dump_process_header(log_t* log, pid_t pid, const char* process_name) {
-  time_t t = time(NULL);
-  struct tm tm;
-  localtime_r(&t, &tm);
-  char timestr[64];
-  strftime(timestr, sizeof(timestr), "%F %T", &tm);
-  _LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr);
+  _LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, get_timestamp().c_str());
 
   if (process_name) {
     _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", process_name);
@@ -70,7 +66,11 @@
   unwinder->SetRegs(thread.registers.get());
   unwinder->Unwind();
   if (unwinder->NumFrames() == 0) {
-    _LOG(&log, logtype::THREAD, "Unwind failed: tid = %d", thread.tid);
+    _LOG(&log, logtype::THREAD, "Unwind failed: tid = %d\n", thread.tid);
+    if (unwinder->LastErrorCode() != unwindstack::ERROR_NONE) {
+      _LOG(&log, logtype::THREAD, "  Error code: %s\n", unwinder->LastErrorCodeString());
+      _LOG(&log, logtype::THREAD, "  Error address: 0x%" PRIx64 "\n", unwinder->LastErrorAddress());
+    }
     return;
   }
 
@@ -106,9 +106,8 @@
   log.tfd = output_fd;
   log.amfd_data = nullptr;
 
-  char process_name[128];
-  read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>");
-  dump_process_header(&log, getpid(), process_name);
+  pid_t pid = getpid();
+  dump_process_header(&log, pid, get_process_name(pid).c_str());
 }
 
 void dump_backtrace_footer(int output_fd) {
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index 04c4b5c..30e75e1 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -23,6 +23,7 @@
 
 struct ThreadInfo {
   std::unique_ptr<unwindstack::Regs> registers;
+  long tagged_addr_ctrl = -1;
 
   pid_t uid;
 
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 7bfcf5d..76155b1 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -83,8 +83,6 @@
 
 void dump_memory(log_t* log, unwindstack::Memory* backtrace, uint64_t addr, const std::string&);
 
-void read_with_default(const char* path, char* buf, size_t len, const char* default_value);
-
 void drop_capabilities();
 
 bool signal_has_sender(const siginfo_t*, pid_t caller_pid);
diff --git a/debuggerd/libdebuggerd/test/dump_memory_test.cpp b/debuggerd/libdebuggerd/test/dump_memory_test.cpp
index be39582..f16f578 100644
--- a/debuggerd/libdebuggerd/test/dump_memory_test.cpp
+++ b/debuggerd/libdebuggerd/test/dump_memory_test.cpp
@@ -30,39 +30,39 @@
 const char g_expected_full_dump[] =
 "\nmemory near r1:\n"
 #if defined(__LP64__)
-"    0000000012345658 0706050403020100 0f0e0d0c0b0a0908  ................\n"
-"    0000000012345668 1716151413121110 1f1e1d1c1b1a1918  ................\n"
-"    0000000012345678 2726252423222120 2f2e2d2c2b2a2928   !\"#$%&'()*+,-./\n"
-"    0000000012345688 3736353433323130 3f3e3d3c3b3a3938  0123456789:;<=>?\n"
-"    0000000012345698 4746454443424140 4f4e4d4c4b4a4948  @ABCDEFGHIJKLMNO\n"
-"    00000000123456a8 5756555453525150 5f5e5d5c5b5a5958  PQRSTUVWXYZ[\\]^_\n"
-"    00000000123456b8 6766656463626160 6f6e6d6c6b6a6968  `abcdefghijklmno\n"
-"    00000000123456c8 7776757473727170 7f7e7d7c7b7a7978  pqrstuvwxyz{|}~.\n"
-"    00000000123456d8 8786858483828180 8f8e8d8c8b8a8988  ................\n"
-"    00000000123456e8 9796959493929190 9f9e9d9c9b9a9998  ................\n"
-"    00000000123456f8 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8  ................\n"
-"    0000000012345708 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8  ................\n"
-"    0000000012345718 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8  ................\n"
-"    0000000012345728 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8  ................\n"
-"    0000000012345738 e7e6e5e4e3e2e1e0 efeeedecebeae9e8  ................\n"
-"    0000000012345748 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8  ................\n";
+"    0000000012345650 0706050403020100 0f0e0d0c0b0a0908  ................\n"
+"    0000000012345660 1716151413121110 1f1e1d1c1b1a1918  ................\n"
+"    0000000012345670 2726252423222120 2f2e2d2c2b2a2928   !\"#$%&'()*+,-./\n"
+"    0000000012345680 3736353433323130 3f3e3d3c3b3a3938  0123456789:;<=>?\n"
+"    0000000012345690 4746454443424140 4f4e4d4c4b4a4948  @ABCDEFGHIJKLMNO\n"
+"    00000000123456a0 5756555453525150 5f5e5d5c5b5a5958  PQRSTUVWXYZ[\\]^_\n"
+"    00000000123456b0 6766656463626160 6f6e6d6c6b6a6968  `abcdefghijklmno\n"
+"    00000000123456c0 7776757473727170 7f7e7d7c7b7a7978  pqrstuvwxyz{|}~.\n"
+"    00000000123456d0 8786858483828180 8f8e8d8c8b8a8988  ................\n"
+"    00000000123456e0 9796959493929190 9f9e9d9c9b9a9998  ................\n"
+"    00000000123456f0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8  ................\n"
+"    0000000012345700 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8  ................\n"
+"    0000000012345710 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8  ................\n"
+"    0000000012345720 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8  ................\n"
+"    0000000012345730 e7e6e5e4e3e2e1e0 efeeedecebeae9e8  ................\n"
+"    0000000012345740 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8  ................\n";
 #else
-"    12345658 03020100 07060504 0b0a0908 0f0e0d0c  ................\n"
-"    12345668 13121110 17161514 1b1a1918 1f1e1d1c  ................\n"
-"    12345678 23222120 27262524 2b2a2928 2f2e2d2c   !\"#$%&'()*+,-./\n"
-"    12345688 33323130 37363534 3b3a3938 3f3e3d3c  0123456789:;<=>?\n"
-"    12345698 43424140 47464544 4b4a4948 4f4e4d4c  @ABCDEFGHIJKLMNO\n"
-"    123456a8 53525150 57565554 5b5a5958 5f5e5d5c  PQRSTUVWXYZ[\\]^_\n"
-"    123456b8 63626160 67666564 6b6a6968 6f6e6d6c  `abcdefghijklmno\n"
-"    123456c8 73727170 77767574 7b7a7978 7f7e7d7c  pqrstuvwxyz{|}~.\n"
-"    123456d8 83828180 87868584 8b8a8988 8f8e8d8c  ................\n"
-"    123456e8 93929190 97969594 9b9a9998 9f9e9d9c  ................\n"
-"    123456f8 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac  ................\n"
-"    12345708 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc  ................\n"
-"    12345718 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc  ................\n"
-"    12345728 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc  ................\n"
-"    12345738 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec  ................\n"
-"    12345748 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc  ................\n";
+"    12345650 03020100 07060504 0b0a0908 0f0e0d0c  ................\n"
+"    12345660 13121110 17161514 1b1a1918 1f1e1d1c  ................\n"
+"    12345670 23222120 27262524 2b2a2928 2f2e2d2c   !\"#$%&'()*+,-./\n"
+"    12345680 33323130 37363534 3b3a3938 3f3e3d3c  0123456789:;<=>?\n"
+"    12345690 43424140 47464544 4b4a4948 4f4e4d4c  @ABCDEFGHIJKLMNO\n"
+"    123456a0 53525150 57565554 5b5a5958 5f5e5d5c  PQRSTUVWXYZ[\\]^_\n"
+"    123456b0 63626160 67666564 6b6a6968 6f6e6d6c  `abcdefghijklmno\n"
+"    123456c0 73727170 77767574 7b7a7978 7f7e7d7c  pqrstuvwxyz{|}~.\n"
+"    123456d0 83828180 87868584 8b8a8988 8f8e8d8c  ................\n"
+"    123456e0 93929190 97969594 9b9a9998 9f9e9d9c  ................\n"
+"    123456f0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac  ................\n"
+"    12345700 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc  ................\n"
+"    12345710 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc  ................\n"
+"    12345720 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc  ................\n"
+"    12345730 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec  ................\n"
+"    12345740 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc  ................\n";
 #endif
 
 const char g_expected_partial_dump[] = \
@@ -112,7 +112,10 @@
     if (last_read_addr_ > 0) {
       offset = addr - last_read_addr_;
     }
-    size_t bytes_available = buffer_.size() - offset;
+    size_t bytes_available = 0;
+    if (offset < buffer_.size()) {
+      bytes_available = buffer_.size() - offset;
+    }
 
     if (partial_read_) {
       bytes = std::min(bytes, bytes_partial_read_);
@@ -258,44 +261,7 @@
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
-  const char* expected_dump = \
-"\nmemory near pc:\n"
-#if defined(__LP64__)
-"    00000000a2345658 ---------------- ----------------  ................\n"
-"    00000000a2345668 ---------------- ----------------  ................\n"
-"    00000000a2345678 ---------------- ----------------  ................\n"
-"    00000000a2345688 ---------------- ----------------  ................\n"
-"    00000000a2345698 ---------------- ----------------  ................\n"
-"    00000000a23456a8 ---------------- ----------------  ................\n"
-"    00000000a23456b8 ---------------- ----------------  ................\n"
-"    00000000a23456c8 ---------------- ----------------  ................\n"
-"    00000000a23456d8 ---------------- ----------------  ................\n"
-"    00000000a23456e8 ---------------- ----------------  ................\n"
-"    00000000a23456f8 ---------------- ----------------  ................\n"
-"    00000000a2345708 ---------------- ----------------  ................\n"
-"    00000000a2345718 ---------------- ----------------  ................\n"
-"    00000000a2345728 ---------------- ----------------  ................\n"
-"    00000000a2345738 ---------------- ----------------  ................\n"
-"    00000000a2345748 ---------------- ----------------  ................\n";
-#else
-"    a2345658 -------- -------- -------- --------  ................\n"
-"    a2345668 -------- -------- -------- --------  ................\n"
-"    a2345678 -------- -------- -------- --------  ................\n"
-"    a2345688 -------- -------- -------- --------  ................\n"
-"    a2345698 -------- -------- -------- --------  ................\n"
-"    a23456a8 -------- -------- -------- --------  ................\n"
-"    a23456b8 -------- -------- -------- --------  ................\n"
-"    a23456c8 -------- -------- -------- --------  ................\n"
-"    a23456d8 -------- -------- -------- --------  ................\n"
-"    a23456e8 -------- -------- -------- --------  ................\n"
-"    a23456f8 -------- -------- -------- --------  ................\n"
-"    a2345708 -------- -------- -------- --------  ................\n"
-"    a2345718 -------- -------- -------- --------  ................\n"
-"    a2345728 -------- -------- -------- --------  ................\n"
-"    a2345738 -------- -------- -------- --------  ................\n"
-"    a2345748 -------- -------- -------- --------  ................\n";
-#endif
-  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+  ASSERT_STREQ("", tombstone_contents.c_str());
 
   // Verify that the log buf is empty, and no error messages.
   ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -429,57 +395,17 @@
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
-TEST_F(DumpMemoryTest, memory_address_too_low) {
-  uint8_t buffer[256];
-  memset(buffer, 0, sizeof(buffer));
-  memory_mock_->SetReadData(buffer, sizeof(buffer));
-
-  dump_memory(&log_, memory_mock_.get(), 0, "memory near r1");
-
-  std::string tombstone_contents;
-  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
-  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
-  ASSERT_STREQ("", tombstone_contents.c_str());
-
-  // Verify that the log buf is empty, and no error messages.
-  ASSERT_STREQ("", getFakeLogBuf().c_str());
-  ASSERT_STREQ("", getFakeLogPrint().c_str());
-}
-
 TEST_F(DumpMemoryTest, memory_address_too_high) {
   uint8_t buffer[256];
   memset(buffer, 0, sizeof(buffer));
   memory_mock_->SetReadData(buffer, sizeof(buffer));
 
 #if defined(__LP64__)
-  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL, "memory near r1");
-  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 32, "memory near r1");
-  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 216, "memory near r1");
+  dump_memory(&log_, memory_mock_.get(), -32, "memory near r1");
+  dump_memory(&log_, memory_mock_.get(), -208, "memory near r1");
 #else
-  dump_memory(&log_, memory_mock_.get(), 0xffff0000, "memory near r1");
-  dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 32, "memory near r1");
-  dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 220, "memory near r1");
-#endif
-
-  std::string tombstone_contents;
-  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
-  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
-  ASSERT_STREQ("", tombstone_contents.c_str());
-
-  // Verify that the log buf is empty, and no error messages.
-  ASSERT_STREQ("", getFakeLogBuf().c_str());
-  ASSERT_STREQ("", getFakeLogPrint().c_str());
-}
-
-TEST_F(DumpMemoryTest, memory_address_would_overflow) {
-  uint8_t buffer[256];
-  memset(buffer, 0, sizeof(buffer));
-  memory_mock_->SetReadData(buffer, sizeof(buffer));
-
-#if defined(__LP64__)
-  dump_memory(&log_, memory_mock_.get(), 0xfffffffffffffff0, "memory near r1");
-#else
-  dump_memory(&log_, memory_mock_.get(), 0xfffffff0, "memory near r1");
+  dump_memory(&log_, memory_mock_.get(), 0x100000000 - 32, "memory near r1");
+  dump_memory(&log_, memory_mock_.get(), 0x100000000 - 208, "memory near r1");
 #endif
 
   std::string tombstone_contents;
@@ -500,9 +426,9 @@
   memory_mock_->SetReadData(buffer, sizeof(buffer));
 
 #if defined(__LP64__)
-  dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 224, "memory near r4");
+  dump_memory(&log_, memory_mock_.get(), -224, "memory near r4");
 #else
-  dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 224, "memory near r4");
+  dump_memory(&log_, memory_mock_.get(), 0x100000000 - 224, "memory near r4");
 #endif
 
   std::string tombstone_contents;
@@ -510,40 +436,57 @@
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
   const char* expected_dump = \
 "\nmemory near r4:\n"
-#if defined(__LP64__)
-"    3fffffffffffff00 0706050403020100 0f0e0d0c0b0a0908  ................\n"
-"    3fffffffffffff10 1716151413121110 1f1e1d1c1b1a1918  ................\n"
-"    3fffffffffffff20 2726252423222120 2f2e2d2c2b2a2928   !\"#$%&'()*+,-./\n"
-"    3fffffffffffff30 3736353433323130 3f3e3d3c3b3a3938  0123456789:;<=>?\n"
-"    3fffffffffffff40 4746454443424140 4f4e4d4c4b4a4948  @ABCDEFGHIJKLMNO\n"
-"    3fffffffffffff50 5756555453525150 5f5e5d5c5b5a5958  PQRSTUVWXYZ[\\]^_\n"
-"    3fffffffffffff60 6766656463626160 6f6e6d6c6b6a6968  `abcdefghijklmno\n"
-"    3fffffffffffff70 7776757473727170 7f7e7d7c7b7a7978  pqrstuvwxyz{|}~.\n"
-"    3fffffffffffff80 8786858483828180 8f8e8d8c8b8a8988  ................\n"
-"    3fffffffffffff90 9796959493929190 9f9e9d9c9b9a9998  ................\n"
-"    3fffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8  ................\n"
-"    3fffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8  ................\n"
-"    3fffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8  ................\n"
-"    3fffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8  ................\n"
-"    3fffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8  ................\n"
-"    3ffffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8  ................\n";
+#if defined(__aarch64__)
+"    00ffffffffffff00 0706050403020100 0f0e0d0c0b0a0908  ................\n"
+"    00ffffffffffff10 1716151413121110 1f1e1d1c1b1a1918  ................\n"
+"    00ffffffffffff20 2726252423222120 2f2e2d2c2b2a2928   !\"#$%&'()*+,-./\n"
+"    00ffffffffffff30 3736353433323130 3f3e3d3c3b3a3938  0123456789:;<=>?\n"
+"    00ffffffffffff40 4746454443424140 4f4e4d4c4b4a4948  @ABCDEFGHIJKLMNO\n"
+"    00ffffffffffff50 5756555453525150 5f5e5d5c5b5a5958  PQRSTUVWXYZ[\\]^_\n"
+"    00ffffffffffff60 6766656463626160 6f6e6d6c6b6a6968  `abcdefghijklmno\n"
+"    00ffffffffffff70 7776757473727170 7f7e7d7c7b7a7978  pqrstuvwxyz{|}~.\n"
+"    00ffffffffffff80 8786858483828180 8f8e8d8c8b8a8988  ................\n"
+"    00ffffffffffff90 9796959493929190 9f9e9d9c9b9a9998  ................\n"
+"    00ffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8  ................\n"
+"    00ffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8  ................\n"
+"    00ffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8  ................\n"
+"    00ffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8  ................\n"
+"    00ffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8  ................\n"
+"    00fffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8  ................\n";
+#elif defined(__LP64__)
+"    ffffffffffffff00 0706050403020100 0f0e0d0c0b0a0908  ................\n"
+"    ffffffffffffff10 1716151413121110 1f1e1d1c1b1a1918  ................\n"
+"    ffffffffffffff20 2726252423222120 2f2e2d2c2b2a2928   !\"#$%&'()*+,-./\n"
+"    ffffffffffffff30 3736353433323130 3f3e3d3c3b3a3938  0123456789:;<=>?\n"
+"    ffffffffffffff40 4746454443424140 4f4e4d4c4b4a4948  @ABCDEFGHIJKLMNO\n"
+"    ffffffffffffff50 5756555453525150 5f5e5d5c5b5a5958  PQRSTUVWXYZ[\\]^_\n"
+"    ffffffffffffff60 6766656463626160 6f6e6d6c6b6a6968  `abcdefghijklmno\n"
+"    ffffffffffffff70 7776757473727170 7f7e7d7c7b7a7978  pqrstuvwxyz{|}~.\n"
+"    ffffffffffffff80 8786858483828180 8f8e8d8c8b8a8988  ................\n"
+"    ffffffffffffff90 9796959493929190 9f9e9d9c9b9a9998  ................\n"
+"    ffffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8  ................\n"
+"    ffffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8  ................\n"
+"    ffffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8  ................\n"
+"    ffffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8  ................\n"
+"    ffffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8  ................\n"
+"    fffffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8  ................\n";
 #else
-"    fffeff00 03020100 07060504 0b0a0908 0f0e0d0c  ................\n"
-"    fffeff10 13121110 17161514 1b1a1918 1f1e1d1c  ................\n"
-"    fffeff20 23222120 27262524 2b2a2928 2f2e2d2c   !\"#$%&'()*+,-./\n"
-"    fffeff30 33323130 37363534 3b3a3938 3f3e3d3c  0123456789:;<=>?\n"
-"    fffeff40 43424140 47464544 4b4a4948 4f4e4d4c  @ABCDEFGHIJKLMNO\n"
-"    fffeff50 53525150 57565554 5b5a5958 5f5e5d5c  PQRSTUVWXYZ[\\]^_\n"
-"    fffeff60 63626160 67666564 6b6a6968 6f6e6d6c  `abcdefghijklmno\n"
-"    fffeff70 73727170 77767574 7b7a7978 7f7e7d7c  pqrstuvwxyz{|}~.\n"
-"    fffeff80 83828180 87868584 8b8a8988 8f8e8d8c  ................\n"
-"    fffeff90 93929190 97969594 9b9a9998 9f9e9d9c  ................\n"
-"    fffeffa0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac  ................\n"
-"    fffeffb0 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc  ................\n"
-"    fffeffc0 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc  ................\n"
-"    fffeffd0 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc  ................\n"
-"    fffeffe0 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec  ................\n"
-"    fffefff0 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc  ................\n";
+"    ffffff00 03020100 07060504 0b0a0908 0f0e0d0c  ................\n"
+"    ffffff10 13121110 17161514 1b1a1918 1f1e1d1c  ................\n"
+"    ffffff20 23222120 27262524 2b2a2928 2f2e2d2c   !\"#$%&'()*+,-./\n"
+"    ffffff30 33323130 37363534 3b3a3938 3f3e3d3c  0123456789:;<=>?\n"
+"    ffffff40 43424140 47464544 4b4a4948 4f4e4d4c  @ABCDEFGHIJKLMNO\n"
+"    ffffff50 53525150 57565554 5b5a5958 5f5e5d5c  PQRSTUVWXYZ[\\]^_\n"
+"    ffffff60 63626160 67666564 6b6a6968 6f6e6d6c  `abcdefghijklmno\n"
+"    ffffff70 73727170 77767574 7b7a7978 7f7e7d7c  pqrstuvwxyz{|}~.\n"
+"    ffffff80 83828180 87868584 8b8a8988 8f8e8d8c  ................\n"
+"    ffffff90 93929190 97969594 9b9a9998 9f9e9d9c  ................\n"
+"    ffffffa0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac  ................\n"
+"    ffffffb0 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc  ................\n"
+"    ffffffc0 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc  ................\n"
+"    ffffffd0 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc  ................\n"
+"    ffffffe0 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec  ................\n"
+"    fffffff0 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc  ................\n";
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
@@ -570,39 +513,41 @@
   const char* expected_dump = \
 "\nmemory near r4:\n"
 #if defined(__LP64__)
-"    0000000010000f88 ---------------- ----------------  ................\n"
-"    0000000010000f98 ---------------- ----------------  ................\n"
-"    0000000010000fa8 ---------------- ----------------  ................\n"
-"    0000000010000fb8 ---------------- ----------------  ................\n"
-"    0000000010000fc8 ---------------- ----------------  ................\n"
-"    0000000010000fd8 ---------------- ----------------  ................\n"
-"    0000000010000fe8 ---------------- ----------------  ................\n"
-"    0000000010000ff8 ---------------- 7f7e7d7c7b7a7978  ........xyz{|}~.\n"
-"    0000000010001008 8786858483828180 8f8e8d8c8b8a8988  ................\n"
-"    0000000010001018 9796959493929190 9f9e9d9c9b9a9998  ................\n"
-"    0000000010001028 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8  ................\n"
-"    0000000010001038 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8  ................\n"
-"    0000000010001048 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8  ................\n"
-"    0000000010001058 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8  ................\n"
-"    0000000010001068 e7e6e5e4e3e2e1e0 efeeedecebeae9e8  ................\n"
-"    0000000010001078 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8  ................\n";
+R"(    0000000010000f80 ---------------- ----------------  ................
+    0000000010000f90 ---------------- ----------------  ................
+    0000000010000fa0 ---------------- ----------------  ................
+    0000000010000fb0 ---------------- ----------------  ................
+    0000000010000fc0 ---------------- ----------------  ................
+    0000000010000fd0 ---------------- ----------------  ................
+    0000000010000fe0 ---------------- ----------------  ................
+    0000000010000ff0 ---------------- ----------------  ................
+    0000000010001000 8786858483828180 8f8e8d8c8b8a8988  ................
+    0000000010001010 9796959493929190 9f9e9d9c9b9a9998  ................
+    0000000010001020 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8  ................
+    0000000010001030 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8  ................
+    0000000010001040 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8  ................
+    0000000010001050 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8  ................
+    0000000010001060 e7e6e5e4e3e2e1e0 efeeedecebeae9e8  ................
+    0000000010001070 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8  ................
+)";
 #else
-"    10000f88 -------- -------- -------- --------  ................\n"
-"    10000f98 -------- -------- -------- --------  ................\n"
-"    10000fa8 -------- -------- -------- --------  ................\n"
-"    10000fb8 -------- -------- -------- --------  ................\n"
-"    10000fc8 -------- -------- -------- --------  ................\n"
-"    10000fd8 -------- -------- -------- --------  ................\n"
-"    10000fe8 -------- -------- -------- --------  ................\n"
-"    10000ff8 -------- -------- 7b7a7978 7f7e7d7c  ........xyz{|}~.\n"
-"    10001008 83828180 87868584 8b8a8988 8f8e8d8c  ................\n"
-"    10001018 93929190 97969594 9b9a9998 9f9e9d9c  ................\n"
-"    10001028 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac  ................\n"
-"    10001038 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc  ................\n"
-"    10001048 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc  ................\n"
-"    10001058 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc  ................\n"
-"    10001068 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec  ................\n"
-"    10001078 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc  ................\n";
+R"(    10000f80 -------- -------- -------- --------  ................
+    10000f90 -------- -------- -------- --------  ................
+    10000fa0 -------- -------- -------- --------  ................
+    10000fb0 -------- -------- -------- --------  ................
+    10000fc0 -------- -------- -------- --------  ................
+    10000fd0 -------- -------- -------- --------  ................
+    10000fe0 -------- -------- -------- --------  ................
+    10000ff0 -------- -------- -------- --------  ................
+    10001000 83828180 87868584 8b8a8988 8f8e8d8c  ................
+    10001010 93929190 97969594 9b9a9998 9f9e9d9c  ................
+    10001020 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac  ................
+    10001030 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc  ................
+    10001040 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc  ................
+    10001050 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc  ................
+    10001060 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec  ................
+    10001070 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc  ................
+)";
 #endif
   ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
 
@@ -684,44 +629,7 @@
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
-  const char* expected_dump = \
-"\nmemory near r4:\n"
-#if defined(__LP64__)
-"    0000000010000000 ---------------- ----------------  ................\n"
-"    0000000010000010 ---------------- ----------------  ................\n"
-"    0000000010000020 ---------------- ----------------  ................\n"
-"    0000000010000030 ---------------- ----------------  ................\n"
-"    0000000010000040 ---------------- ----------------  ................\n"
-"    0000000010000050 ---------------- ----------------  ................\n"
-"    0000000010000060 ---------------- ----------------  ................\n"
-"    0000000010000070 ---------------- ----------------  ................\n"
-"    0000000010000080 ---------------- ----------------  ................\n"
-"    0000000010000090 ---------------- ----------------  ................\n"
-"    00000000100000a0 ---------------- ----------------  ................\n"
-"    00000000100000b0 ---------------- ----------------  ................\n"
-"    00000000100000c0 ---------------- ----------------  ................\n"
-"    00000000100000d0 ---------------- ----------------  ................\n"
-"    00000000100000e0 ---------------- ----------------  ................\n"
-"    00000000100000f0 ---------------- ----------------  ................\n";
-#else
-"    10000000 -------- -------- -------- --------  ................\n"
-"    10000010 -------- -------- -------- --------  ................\n"
-"    10000020 -------- -------- -------- --------  ................\n"
-"    10000030 -------- -------- -------- --------  ................\n"
-"    10000040 -------- -------- -------- --------  ................\n"
-"    10000050 -------- -------- -------- --------  ................\n"
-"    10000060 -------- -------- -------- --------  ................\n"
-"    10000070 -------- -------- -------- --------  ................\n"
-"    10000080 -------- -------- -------- --------  ................\n"
-"    10000090 -------- -------- -------- --------  ................\n"
-"    100000a0 -------- -------- -------- --------  ................\n"
-"    100000b0 -------- -------- -------- --------  ................\n"
-"    100000c0 -------- -------- -------- --------  ................\n"
-"    100000d0 -------- -------- -------- --------  ................\n"
-"    100000e0 -------- -------- -------- --------  ................\n"
-"    100000f0 -------- -------- -------- --------  ................\n";
-#endif
-  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+  ASSERT_STREQ("", tombstone_contents.c_str());
 
   // Verify that the log buf is empty, and no error messages.
   ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -744,44 +652,7 @@
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
   ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
-  const char* expected_dump = \
-"\nmemory near r4:\n"
-#if defined(__LP64__)
-"    0000000010000f00 ---------------- ----------------  ................\n"
-"    0000000010000f10 ---------------- ----------------  ................\n"
-"    0000000010000f20 ---------------- ----------------  ................\n"
-"    0000000010000f30 ---------------- ----------------  ................\n"
-"    0000000010000f40 ---------------- ----------------  ................\n"
-"    0000000010000f50 ---------------- ----------------  ................\n"
-"    0000000010000f60 ---------------- ----------------  ................\n"
-"    0000000010000f70 ---------------- ----------------  ................\n"
-"    0000000010000f80 ---------------- ----------------  ................\n"
-"    0000000010000f90 ---------------- ----------------  ................\n"
-"    0000000010000fa0 ---------------- ----------------  ................\n"
-"    0000000010000fb0 ---------------- ----------------  ................\n"
-"    0000000010000fc0 ---------------- ----------------  ................\n"
-"    0000000010000fd0 ---------------- ----------------  ................\n"
-"    0000000010000fe0 ---------------- ----------------  ................\n"
-"    0000000010000ff0 ---------------- ----------------  ................\n";
-#else
-"    10000f00 -------- -------- -------- --------  ................\n"
-"    10000f10 -------- -------- -------- --------  ................\n"
-"    10000f20 -------- -------- -------- --------  ................\n"
-"    10000f30 -------- -------- -------- --------  ................\n"
-"    10000f40 -------- -------- -------- --------  ................\n"
-"    10000f50 -------- -------- -------- --------  ................\n"
-"    10000f60 -------- -------- -------- --------  ................\n"
-"    10000f70 -------- -------- -------- --------  ................\n"
-"    10000f80 -------- -------- -------- --------  ................\n"
-"    10000f90 -------- -------- -------- --------  ................\n"
-"    10000fa0 -------- -------- -------- --------  ................\n"
-"    10000fb0 -------- -------- -------- --------  ................\n"
-"    10000fc0 -------- -------- -------- --------  ................\n"
-"    10000fd0 -------- -------- -------- --------  ................\n"
-"    10000fe0 -------- -------- -------- --------  ................\n"
-"    10000ff0 -------- -------- -------- --------  ................\n";
-#endif
-  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+  ASSERT_STREQ("", tombstone_contents.c_str());
 
   // Verify that the log buf is empty, and no error messages.
   ASSERT_STREQ("", getFakeLogBuf().c_str());
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index aec8c60..b42d70c 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -359,13 +359,6 @@
   ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
 }
 
-TEST_F(TombstoneTest, dump_timestamp) {
-  setenv("TZ", "UTC", 1);
-  tzset();
-  dump_timestamp(&log_, 0);
-  ASSERT_STREQ("Timestamp: 1970-01-01 00:00:00+0000\n", amfd_data_.c_str());
-}
-
 class GwpAsanCrashDataTest : public GwpAsanCrashData {
 public:
   GwpAsanCrashDataTest(
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index ab65dd1..d88c5a9 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -58,6 +58,7 @@
 #include "libdebuggerd/open_files_list.h"
 #include "libdebuggerd/scudo.h"
 #include "libdebuggerd/utility.h"
+#include "util.h"
 
 #include "gwp_asan/common.h"
 #include "gwp_asan/crash_handler.h"
@@ -80,15 +81,6 @@
   _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
 }
 
-static void dump_timestamp(log_t* log, time_t time) {
-  struct tm tm;
-  localtime_r(&time, &tm);
-
-  char buf[strlen("1970-01-01 00:00:00+0830") + 1];
-  strftime(buf, sizeof(buf), "%F %T%z", &tm);
-  _LOG(log, logtype::HEADER, "Timestamp: %s\n", buf);
-}
-
 static std::string get_stack_overflow_cause(uint64_t fault_addr, uint64_t sp,
                                             unwindstack::Maps* maps) {
   static constexpr uint64_t kMaxDifferenceBytes = 256;
@@ -182,16 +174,15 @@
 }
 
 static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) {
-  // Blacklist logd, logd.reader, logd.writer, logd.auditd, logd.control ...
-  // TODO: Why is this controlled by thread name?
-  if (thread_info.thread_name == "logd" ||
-      android::base::StartsWith(thread_info.thread_name, "logd.")) {
-    log->should_retrieve_logcat = false;
-  }
+  // Don't try to collect logs from the threads that implement the logging system itself.
+  if (thread_info.uid == AID_LOGD) log->should_retrieve_logcat = false;
 
   _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s  >>> %s <<<\n", thread_info.pid,
        thread_info.tid, thread_info.thread_name.c_str(), thread_info.process_name.c_str());
   _LOG(log, logtype::HEADER, "uid: %d\n", thread_info.uid);
+  if (thread_info.tagged_addr_ctrl != -1) {
+    _LOG(log, logtype::HEADER, "tagged_addr_ctrl: %016lx\n", thread_info.tagged_addr_ctrl);
+  }
 }
 
 static std::string get_addr_string(uint64_t addr) {
@@ -416,7 +407,11 @@
   unwinder->SetRegs(regs_copy.get());
   unwinder->Unwind();
   if (unwinder->NumFrames() == 0) {
-    _LOG(log, logtype::THREAD, "Failed to unwind");
+    _LOG(log, logtype::THREAD, "Failed to unwind\n");
+    if (unwinder->LastErrorCode() != unwindstack::ERROR_NONE) {
+      _LOG(log, logtype::THREAD, "  Error code: %s\n", unwinder->LastErrorCodeString());
+      _LOG(log, logtype::THREAD, "  Error address: 0x%" PRIx64 "\n", unwinder->LastErrorAddress());
+    }
   } else {
     _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
     log_backtrace(log, unwinder, "    ");
@@ -507,10 +502,9 @@
     // (although in this case the pid is redundant).
     char timeBuf[32];
     time_t sec = static_cast<time_t>(log_entry.entry.sec);
-    struct tm tmBuf;
-    struct tm* ptm;
-    ptm = localtime_r(&sec, &tmBuf);
-    strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
+    tm tm;
+    localtime_r(&sec, &tm);
+    strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", &tm);
 
     char* msg = log_entry.msg();
     if (msg == nullptr) {
@@ -571,28 +565,25 @@
   log.tfd = tombstone_fd;
   log.amfd_data = nullptr;
 
-  char thread_name[16];
-  char process_name[128];
-
-  read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>");
-  read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>");
+  std::string thread_name = get_thread_name(tid);
+  std::string process_name = get_process_name(pid);
 
   std::unique_ptr<unwindstack::Regs> regs(
       unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
 
   std::map<pid_t, ThreadInfo> threads;
-  threads[gettid()] = ThreadInfo{
+  threads[tid] = ThreadInfo{
       .registers = std::move(regs),
       .uid = uid,
       .tid = tid,
-      .thread_name = thread_name,
+      .thread_name = thread_name.c_str(),
       .pid = pid,
-      .process_name = process_name,
+      .process_name = process_name.c_str(),
       .siginfo = siginfo,
   };
 
-  unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid);
-  if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
+  unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid, unwindstack::Regs::CurrentArch());
+  if (!unwinder.Init()) {
     LOG(FATAL) << "Failed to init unwinder object.";
   }
 
@@ -606,8 +597,8 @@
                        const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
                        const ProcessInfo& process_info, OpenFilesList* open_files,
                        std::string* amfd_data) {
-  // don't copy log messages to tombstone unless this is a dev device
-  bool want_logs = android::base::GetBoolProperty("ro.debuggable", false);
+  // Don't copy log messages to tombstone unless this is a development device.
+  bool want_logs = GetBoolProperty("ro.debuggable", false);
 
   log_t log;
   log.current_tid = target_thread;
@@ -617,7 +608,7 @@
 
   _LOG(&log, logtype::HEADER, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
   dump_header_info(&log);
-  dump_timestamp(&log, time(nullptr));
+  _LOG(&log, logtype::HEADER, "Timestamp: %s\n", get_timestamp().c_str());
 
   auto it = threads.find(target_thread);
   if (it == threads.end()) {
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index c8a3431..4e6df09 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -44,7 +44,6 @@
 
 using android::base::unique_fd;
 
-// Whitelist output desired in the logcat output.
 bool is_allowed_in_logcat(enum logtype ltype) {
   if ((ltype == HEADER)
    || (ltype == REGISTERS)
@@ -129,24 +128,23 @@
 #define MEMORY_BYTES_PER_LINE 16
 
 void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const std::string& label) {
-  // Align the address to sizeof(long) and start 32 bytes before the address.
-  addr &= ~(sizeof(long) - 1);
+  // Align the address to the number of bytes per line to avoid confusing memory tag output if
+  // memory is tagged and we start from a misaligned address. Start 32 bytes before the address.
+  addr &= ~(MEMORY_BYTES_PER_LINE - 1);
   if (addr >= 4128) {
     addr -= 32;
   }
 
-  // Don't bother if the address looks too low, or looks too high.
-  if (addr < 4096 ||
-#if defined(__LP64__)
-      addr > 0x4000000000000000UL - MEMORY_BYTES_TO_DUMP) {
-#else
-      addr > 0xffff0000 - MEMORY_BYTES_TO_DUMP) {
-#endif
+  // We don't want the address tag to appear in the addresses in the memory dump.
+  addr = untag_address(addr);
+
+  // Don't bother if the address would overflow, taking tag bits into account. Note that
+  // untag_address truncates to 32 bits on 32-bit platforms as a side effect of returning a
+  // uintptr_t, so this also checks for 32-bit overflow.
+  if (untag_address(addr + MEMORY_BYTES_TO_DUMP - 1) < addr) {
     return;
   }
 
-  _LOG(log, logtype::MEMORY, "\n%s:\n", label.c_str());
-
   // Dump 256 bytes
   uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)];
   memset(data, 0, MEMORY_BYTES_TO_DUMP);
@@ -187,6 +185,15 @@
     }
   }
 
+  // If we were unable to read anything, it probably means that the register doesn't contain a
+  // valid pointer. In that case, skip the output for this register entirely rather than emitting 16
+  // lines of dashes.
+  if (bytes == 0) {
+    return;
+  }
+
+  _LOG(log, logtype::MEMORY, "\n%s:\n", label.c_str());
+
   // Dump the code around memory as:
   //  addr             contents                           ascii
   //  0000000000008d34 ef000000e8bd0090 e1b00000512fff1e  ............../Q
@@ -197,8 +204,13 @@
   size_t current = 0;
   size_t total_bytes = start + bytes;
   for (size_t line = 0; line < MEMORY_BYTES_TO_DUMP / MEMORY_BYTES_PER_LINE; line++) {
+    uint64_t tagged_addr = addr;
+    long tag = memory->ReadTag(addr);
+    if (tag >= 0) {
+      tagged_addr |= static_cast<uint64_t>(tag) << 56;
+    }
     std::string logline;
-    android::base::StringAppendF(&logline, "    %" PRIPTR, addr);
+    android::base::StringAppendF(&logline, "    %" PRIPTR, tagged_addr);
 
     addr += MEMORY_BYTES_PER_LINE;
     std::string ascii;
@@ -226,23 +238,6 @@
   }
 }
 
-void read_with_default(const char* path, char* buf, size_t len, const char* default_value) {
-  unique_fd fd(open(path, O_RDONLY | O_CLOEXEC));
-  if (fd != -1) {
-    int rc = TEMP_FAILURE_RETRY(read(fd.get(), buf, len - 1));
-    if (rc != -1) {
-      buf[rc] = '\0';
-
-      // Trim trailing newlines.
-      if (rc > 0 && buf[rc - 1] == '\n') {
-        buf[rc - 1] = '\0';
-      }
-      return;
-    }
-  }
-  strcpy(buf, default_value);
-}
-
 void drop_capabilities() {
   __user_cap_header_struct capheader;
   memset(&capheader, 0, sizeof(capheader));
diff --git a/debuggerd/util.cpp b/debuggerd/util.cpp
index a37b3b9..9d09210 100644
--- a/debuggerd/util.cpp
+++ b/debuggerd/util.cpp
@@ -17,6 +17,7 @@
 #include "util.h"
 
 #include <sys/socket.h>
+#include <time.h>
 
 #include <string>
 #include <utility>
@@ -38,3 +39,19 @@
   android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/comm", tid), &result);
   return android::base::Trim(result);
 }
+
+std::string get_timestamp() {
+  timespec ts;
+  clock_gettime(CLOCK_REALTIME, &ts);
+
+  tm tm;
+  localtime_r(&ts.tv_sec, &tm);
+
+  char buf[strlen("1970-01-01 00:00:00.123456789+0830") + 1];
+  char* s = buf;
+  size_t sz = sizeof(buf), n;
+  n = strftime(s, sz, "%F %H:%M", &tm), s += n, sz -= n;
+  n = snprintf(s, sz, ":%02d.%09ld", tm.tm_sec, ts.tv_nsec), s += n, sz -= n;
+  n = strftime(s, sz, "%z", &tm), s += n, sz -= n;
+  return buf;
+}
diff --git a/debuggerd/util.h b/debuggerd/util.h
index e964423..07e7e99 100644
--- a/debuggerd/util.h
+++ b/debuggerd/util.h
@@ -23,3 +23,5 @@
 
 std::string get_process_name(pid_t pid);
 std::string get_thread_name(pid_t tid);
+
+std::string get_timestamp();
diff --git a/diagnose_usb/diagnose_usb.cpp b/diagnose_usb/diagnose_usb.cpp
index 5695ece..35edb5e 100644
--- a/diagnose_usb/diagnose_usb.cpp
+++ b/diagnose_usb/diagnose_usb.cpp
@@ -49,7 +49,7 @@
     // additionally just to be sure.
     if (group_member(plugdev_group->gr_gid) || getegid() == plugdev_group->gr_gid) {
         // The user is in plugdev so the problem is likely with the udev rules.
-        return "user in plugdev group; are your udev rules wrong?";
+        return "missing udev rules? user is in the plugdev group";
     }
     passwd* pwd = getpwuid(getuid());
     return android::base::StringPrintf("user %s is not in the plugdev group",
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index bdb786c..e6f9ffa 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -147,6 +147,7 @@
     static_libs: [
         "libgtest_prod",
         "libhealthhalutils",
+        "libsnapshot_cow",
         "libsnapshot_nobinder",
         "update_metadata-protos",
     ],
@@ -251,7 +252,7 @@
         darwin: {
             srcs: ["usb_osx.cpp"],
         },
-        linux_glibc: {
+        linux: {
             srcs: ["usb_linux.cpp"],
         },
     },
@@ -271,6 +272,7 @@
     required: [
         "mke2fs",
         "make_f2fs",
+        "make_f2fs_casefold",
     ],
     dist: {
         targets: [
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index fd009e7..0e918a3 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -21,6 +21,7 @@
 my_dist_files := $(SOONG_HOST_OUT_EXECUTABLES)/mke2fs
 my_dist_files += $(SOONG_HOST_OUT_EXECUTABLES)/e2fsdroid
 my_dist_files += $(SOONG_HOST_OUT_EXECUTABLES)/make_f2fs
+my_dist_files += $(SOONG_HOST_OUT_EXECUTABLES)/make_f2fs_casefold
 my_dist_files += $(SOONG_HOST_OUT_EXECUTABLES)/sload_f2fs
 $(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
 my_dist_files :=
diff --git a/fastboot/fastboot.bash b/fastboot/fastboot.bash
index cc1366c..406e8b8 100644
--- a/fastboot/fastboot.bash
+++ b/fastboot/fastboot.bash
@@ -109,7 +109,7 @@
 
     cur="${COMP_WORDS[COMP_CWORD]}"
     if [[ $i -eq $COMP_CWORD ]]; then
-        partitions="boot bootloader dtbo modem odm oem product radio recovery system vbmeta vendor vendor_dlkm"
+        partitions="boot bootloader dtbo modem odm odm_dlkm oem product radio recovery system vbmeta vendor vendor_dlkm"
         COMPREPLY=( $(compgen -W "$partitions" -- $cur) )
     else
         _fastboot_util_complete_local_file "${cur}" '!*.img'
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 4ca6a6a..4bf791e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -145,6 +145,7 @@
     { "dtbo",     "dtbo.img",         "dtbo.sig",     "dtbo",     true,  ImageType::BootCritical },
     { "dts",      "dt.img",           "dt.sig",       "dts",      true,  ImageType::BootCritical },
     { "odm",      "odm.img",          "odm.sig",      "odm",      true,  ImageType::Normal },
+    { "odm_dlkm", "odm_dlkm.img",     "odm_dlkm.sig", "odm_dlkm", true,  ImageType::Normal },
     { "product",  "product.img",      "product.sig",  "product",  true,  ImageType::Normal },
     { "recovery", "recovery.img",     "recovery.sig", "recovery", true,  ImageType::BootCritical },
     { "super",    "super.img",        "super.sig",    "super",    true,  ImageType::Extra },
@@ -525,12 +526,15 @@
 
 static bool UnzipToMemory(ZipArchiveHandle zip, const std::string& entry_name,
                           std::vector<char>* out) {
-    ZipEntry zip_entry;
+    ZipEntry64 zip_entry;
     if (FindEntry(zip, entry_name, &zip_entry) != 0) {
         fprintf(stderr, "archive does not contain '%s'\n", entry_name.c_str());
         return false;
     }
 
+    if (zip_entry.uncompressed_length > std::numeric_limits<size_t>::max()) {
+      die("entry '%s' is too large: %" PRIu64, entry_name.c_str(), zip_entry.uncompressed_length);
+    }
     out->resize(zip_entry.uncompressed_length);
 
     fprintf(stderr, "extracting %s (%zu MB) to RAM...\n", entry_name.c_str(),
@@ -636,14 +640,14 @@
 static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
     unique_fd fd(make_temporary_fd(entry_name));
 
-    ZipEntry zip_entry;
+    ZipEntry64 zip_entry;
     if (FindEntry(zip, entry_name, &zip_entry) != 0) {
         fprintf(stderr, "archive does not contain '%s'\n", entry_name);
         errno = ENOENT;
         return -1;
     }
 
-    fprintf(stderr, "extracting %s (%" PRIu32 " MB) to disk...", entry_name,
+    fprintf(stderr, "extracting %s (%" PRIu64 " MB) to disk...", entry_name,
             zip_entry.uncompressed_length / 1024 / 1024);
     double start = now();
     int error = ExtractEntryToFile(zip, &zip_entry, fd);
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index e7f785b..34ab32c 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -1286,7 +1286,7 @@
     ASSERT_TRUE(PartitionHash(fb.get(), "userdata", &hash_buf, &retcode, &err_msg)) << err_msg;
     ASSERT_EQ(retcode, 0) << err_msg;
 
-    // Sanity check of hash
+    // Validity check of hash
     EXPECT_NE(hash_before, hash_buf)
             << "Writing a random buffer to 'userdata' had the same hash as after erasing it";
     SetLockState(true);  // Lock the device
diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING
index 6cd0430..a349408 100644
--- a/fs_mgr/TEST_MAPPING
+++ b/fs_mgr/TEST_MAPPING
@@ -7,7 +7,7 @@
       "name": "liblp_test"
     },
     {
-      "name": "fiemap_image_test_presubmit"
+      "name": "fiemap_image_test"
     },
     {
       "name": "fiemap_writer_test"
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 0ae5787..5ff01e1 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -301,13 +301,10 @@
     return true;
 }
 
-static bool needs_block_encryption(const FstabEntry& entry);
-static bool should_use_metadata_encryption(const FstabEntry& entry);
-
 // Read the primary superblock from an ext4 filesystem.  On failure return
 // false.  If it's not an ext4 filesystem, also set FS_STAT_INVALID_MAGIC.
-static bool read_ext4_superblock(const std::string& blk_device, const FstabEntry& entry,
-                                 struct ext4_super_block* sb, int* fs_stat) {
+static bool read_ext4_superblock(const std::string& blk_device, struct ext4_super_block* sb,
+                                 int* fs_stat) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device.c_str(), O_RDONLY | O_CLOEXEC)));
 
     if (fd < 0) {
@@ -324,29 +321,7 @@
         LINFO << "Invalid ext4 superblock on '" << blk_device << "'";
         // not a valid fs, tune2fs, fsck, and mount  will all fail.
         *fs_stat |= FS_STAT_INVALID_MAGIC;
-
-        bool encrypted = should_use_metadata_encryption(entry) || needs_block_encryption(entry);
-        if (entry.mount_point == "/data" &&
-            (!encrypted || android::base::StartsWith(blk_device, "/dev/block/dm-"))) {
-            // try backup superblock, if main superblock is corrupted
-            for (unsigned int blocksize = EXT4_MIN_BLOCK_SIZE; blocksize <= EXT4_MAX_BLOCK_SIZE;
-                 blocksize *= 2) {
-                uint64_t superblock = blocksize * 8;
-                if (blocksize == EXT4_MIN_BLOCK_SIZE) superblock++;
-
-                if (TEMP_FAILURE_RETRY(pread(fd, sb, sizeof(*sb), superblock * blocksize)) !=
-                    sizeof(*sb)) {
-                    PERROR << "Can't read '" << blk_device << "' superblock";
-                    return false;
-                }
-                if (is_ext4_superblock_valid(sb) &&
-                    (1 << (10 + sb->s_log_block_size) == blocksize)) {
-                    *fs_stat &= ~FS_STAT_INVALID_MAGIC;
-                    break;
-                }
-            }
-        }
-        if (*fs_stat & FS_STAT_INVALID_MAGIC) return false;
+        return false;
     }
     *fs_stat |= FS_STAT_IS_EXT4;
     LINFO << "superblock s_max_mnt_count:" << sb->s_max_mnt_count << "," << blk_device;
@@ -546,13 +521,13 @@
 }
 
 // Enable casefold if needed.
-static void tune_casefold(const std::string& blk_device, const struct ext4_super_block* sb,
-                          int* fs_stat) {
+static void tune_casefold(const std::string& blk_device, const FstabEntry& entry,
+                          const struct ext4_super_block* sb, int* fs_stat) {
     bool has_casefold = (sb->s_feature_incompat & cpu_to_le32(EXT4_FEATURE_INCOMPAT_CASEFOLD)) != 0;
     bool wants_casefold =
             android::base::GetBoolProperty("external_storage.casefold.enabled", false);
 
-    if (!wants_casefold || has_casefold) return;
+    if (entry.mount_point != "data" || !wants_casefold || has_casefold ) return;
 
     std::string casefold_support;
     if (!android::base::ReadFileToString(SYSFS_EXT4_CASEFOLD, &casefold_support)) {
@@ -607,7 +582,7 @@
 
     LINFO << "Enabling ext4 metadata_csum on " << blk_device;
 
-    // requires to give last_fsck_time to current to avoid insane time.
+    // Must give `-T now` to prevent last_fsck_time from growing too large,
     // otherwise, tune2fs won't enable metadata_csum.
     const char* tune2fs_args[] = {TUNE2FS_BIN, "-O",        "metadata_csum,64bit,extent",
                                   "-T",        "now", blk_device.c_str()};
@@ -687,7 +662,7 @@
     if (is_extfs(entry.fs_type)) {
         struct ext4_super_block sb;
 
-        if (read_ext4_superblock(blk_device, entry, &sb, &fs_stat)) {
+        if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
             if ((sb.s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) != 0 ||
                 (sb.s_state & EXT4_VALID_FS) == 0) {
                 LINFO << "Filesystem on " << blk_device << " was not cleanly shutdown; "
@@ -717,11 +692,11 @@
          entry.fs_mgr_flags.fs_verity || entry.fs_mgr_flags.ext_meta_csum)) {
         struct ext4_super_block sb;
 
-        if (read_ext4_superblock(blk_device, entry, &sb, &fs_stat)) {
+        if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
             tune_reserved_size(blk_device, entry, &sb, &fs_stat);
             tune_encrypt(blk_device, entry, &sb, &fs_stat);
             tune_verity(blk_device, entry, &sb, &fs_stat);
-            tune_casefold(blk_device, &sb, &fs_stat);
+            tune_casefold(blk_device, entry, &sb, &fs_stat);
             tune_metadata_csum(blk_device, entry, &sb, &fs_stat);
         }
     }
@@ -765,15 +740,33 @@
     unsigned long mountflags = entry.flags;
     int ret = 0;
     int save_errno = 0;
+    int gc_allowance = 0;
+    std::string opts;
+    bool try_f2fs_gc_allowance = is_f2fs(entry.fs_type) && entry.fs_checkpoint_opts.length() > 0;
+    Timer t;
+
     do {
+        if (save_errno == EINVAL && try_f2fs_gc_allowance) {
+            PINFO << "Kernel does not support checkpoint=disable:[n]%, trying without.";
+            try_f2fs_gc_allowance = false;
+        }
+        if (try_f2fs_gc_allowance) {
+            opts = entry.fs_options + entry.fs_checkpoint_opts + ":" +
+                   std::to_string(gc_allowance) + "%";
+        } else {
+            opts = entry.fs_options;
+        }
         if (save_errno == EAGAIN) {
             PINFO << "Retrying mount (source=" << source << ",target=" << target
-                  << ",type=" << entry.fs_type << ")=" << ret << "(" << save_errno << ")";
+                  << ",type=" << entry.fs_type << ", gc_allowance=" << gc_allowance << "%)=" << ret
+                  << "(" << save_errno << ")";
         }
         ret = mount(source.c_str(), target.c_str(), entry.fs_type.c_str(), mountflags,
-                    entry.fs_options.c_str());
+                    opts.c_str());
         save_errno = errno;
-    } while (ret && save_errno == EAGAIN);
+        if (try_f2fs_gc_allowance) gc_allowance += 10;
+    } while ((ret && save_errno == EAGAIN && gc_allowance <= 100) ||
+             (ret && save_errno == EINVAL && try_f2fs_gc_allowance));
     const char* target_missing = "";
     const char* source_missing = "";
     if (save_errno == ENOENT) {
@@ -789,6 +782,8 @@
     if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
         fs_mgr_set_blk_ro(source);
     }
+    android::base::SetProperty("ro.boottime.init.mount." + Basename(target),
+                               std::to_string(t.duration().count()));
     errno = save_errno;
     return ret;
 }
@@ -1001,6 +996,19 @@
     }
 }
 
+static void set_type_property(int status) {
+    switch (status) {
+        case FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED:
+            SetProperty("ro.crypto.type", "block");
+            break;
+        case FS_MGR_MNTALL_DEV_FILE_ENCRYPTED:
+        case FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED:
+        case FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION:
+            SetProperty("ro.crypto.type", "file");
+            break;
+    }
+}
+
 static bool call_vdc(const std::vector<std::string>& args, int* ret) {
     std::vector<char const*> argv;
     argv.emplace_back("/system/bin/vdc");
@@ -1104,7 +1112,7 @@
     bool UpdateCheckpointPartition(FstabEntry* entry, const std::string& block_device) {
         if (entry->fs_mgr_flags.checkpoint_fs) {
             if (is_f2fs(entry->fs_type)) {
-                entry->fs_options += ",checkpoint=disable";
+                entry->fs_checkpoint_opts = ",checkpoint=disable";
             } else {
                 LERROR << entry->fs_type << " does not implement checkpoints.";
             }
@@ -1138,10 +1146,9 @@
                 // metadata-encrypted device with smaller blocks, we must not change this for
                 // devices shipped with Q or earlier unless they explicitly selected dm-default-key
                 // v2
-                constexpr unsigned int pre_gki_level = __ANDROID_API_Q__;
                 unsigned int options_format_version = android::base::GetUintProperty<unsigned int>(
                         "ro.crypto.dm_default_key.options_format.version",
-                        (android::fscrypt::GetFirstApiLevel() <= pre_gki_level ? 1 : 2));
+                        (android::fscrypt::GetFirstApiLevel() <= __ANDROID_API_Q__ ? 1 : 2));
                 if (options_format_version > 1) {
                     bowTarget->SetBlockSize(4096);
                 }
@@ -1309,14 +1316,15 @@
 // When multiple fstab records share the same mount_point, it will try to mount each
 // one in turn, and ignore any duplicates after a first successful mount.
 // Returns -1 on error, and  FS_MGR_MNTALL_* otherwise.
-int fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
+MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
     int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
     int error_count = 0;
     CheckpointManager checkpoint_manager;
     AvbUniquePtr avb_handle(nullptr);
 
+    bool userdata_mounted = false;
     if (fstab->empty()) {
-        return FS_MGR_MNTALL_FAIL;
+        return {FS_MGR_MNTALL_FAIL, userdata_mounted};
     }
 
     // Keep i int to prevent unsigned integer overflow from (i = top_idx - 1),
@@ -1356,7 +1364,7 @@
         }
 
         // Terrible hack to make it possible to remount /data.
-        // TODO: refact fs_mgr_mount_all and get rid of this.
+        // TODO: refactor fs_mgr_mount_all and get rid of this.
         if (mount_mode == MOUNT_MODE_ONLY_USERDATA && current_entry.mount_point != "/data") {
             continue;
         }
@@ -1392,7 +1400,8 @@
                 avb_handle = AvbHandle::Open();
                 if (!avb_handle) {
                     LERROR << "Failed to open AvbHandle";
-                    return FS_MGR_MNTALL_FAIL;
+                    set_type_property(encryptable);
+                    return {FS_MGR_MNTALL_FAIL, userdata_mounted};
                 }
             }
             if (avb_handle->SetUpAvbHashtree(&current_entry, true /* wait_for_verity_dev */) ==
@@ -1434,7 +1443,7 @@
 
             if (status == FS_MGR_MNTALL_FAIL) {
                 // Fatal error - no point continuing.
-                return status;
+                return {status, userdata_mounted};
             }
 
             if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
@@ -1448,11 +1457,15 @@
                                    attempted_entry.mount_point},
                                   nullptr)) {
                         LERROR << "Encryption failed";
-                        return FS_MGR_MNTALL_FAIL;
+                        set_type_property(encryptable);
+                        return {FS_MGR_MNTALL_FAIL, userdata_mounted};
                     }
                 }
             }
 
+            if (current_entry.mount_point == "/data") {
+                userdata_mounted = true;
+            }
             // Success!  Go get the next one.
             continue;
         }
@@ -1545,14 +1558,16 @@
         }
     }
 
+    set_type_property(encryptable);
+
 #if ALLOW_ADBD_DISABLE_VERITY == 1  // "userdebug" build
     fs_mgr_overlayfs_mount_all(fstab);
 #endif
 
     if (error_count) {
-        return FS_MGR_MNTALL_FAIL;
+        return {FS_MGR_MNTALL_FAIL, userdata_mounted};
     } else {
-        return encryptable;
+        return {encryptable, userdata_mounted};
     }
 }
 
@@ -1774,8 +1789,8 @@
         }
         LINFO << "Remounting /data";
         // TODO(b/143970043): remove this hack after fs_mgr_mount_all is refactored.
-        int result = fs_mgr_mount_all(fstab, MOUNT_MODE_ONLY_USERDATA);
-        return result == FS_MGR_MNTALL_FAIL ? -1 : 0;
+        auto result = fs_mgr_mount_all(fstab, MOUNT_MODE_ONLY_USERDATA);
+        return result.code == FS_MGR_MNTALL_FAIL ? -1 : 0;
     }
     return 0;
 }
@@ -1957,21 +1972,19 @@
     return true;
 }
 
-static bool PrepareZramDevice(const std::string& loop, off64_t size, const std::string& bdev) {
-    if (loop.empty() && bdev.empty()) return true;
+static bool PrepareZramBackingDevice(off64_t size) {
 
-    if (bdev.length()) {
-        return InstallZramDevice(bdev);
-    }
+    constexpr const char* file_path = "/data/per_boot/zram_swap";
+    if (size == 0) return true;
 
     // Prepare target path
-    unique_fd target_fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600)));
+    unique_fd target_fd(TEMP_FAILURE_RETRY(open(file_path, O_RDWR | O_CREAT | O_CLOEXEC, 0600)));
     if (target_fd.get() == -1) {
-        PERROR << "Cannot open target path: " << loop;
+        PERROR << "Cannot open target path: " << file_path;
         return false;
     }
     if (fallocate(target_fd.get(), 0, 0, size) < 0) {
-        PERROR << "Cannot truncate target path: " << loop;
+        PERROR << "Cannot truncate target path: " << file_path;
         return false;
     }
 
@@ -2003,11 +2016,10 @@
             continue;
         }
 
-        if (!PrepareZramDevice(entry.zram_loopback_path, entry.zram_loopback_size, entry.zram_backing_dev_path)) {
-            LERROR << "Skipping losetup for '" << entry.blk_device << "'";
-        }
-
         if (entry.zram_size > 0) {
+	    if (!PrepareZramBackingDevice(entry.zram_backingdev_size)) {
+                LERROR << "Failure of zram backing device file for '" << entry.blk_device << "'";
+            }
             // 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
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 54102ec..63b7ad2 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -286,15 +286,10 @@
         } else if (StartsWith(flag, "sysfs_path=")) {
             // The path to trigger device gc by idle-maint of vold.
             entry->sysfs_path = arg;
-        } else if (StartsWith(flag, "zram_loopback_path=")) {
-            // The path to use loopback for zram.
-            entry->zram_loopback_path = arg;
-        } else if (StartsWith(flag, "zram_loopback_size=")) {
-            if (!ParseByteCount(arg, &entry->zram_loopback_size)) {
-                LWARNING << "Warning: zram_loopback_size= flag malformed: " << arg;
+        } else if (StartsWith(flag, "zram_backingdev_size=")) {
+            if (!ParseByteCount(arg, &entry->zram_backingdev_size)) {
+                LWARNING << "Warning: zram_backingdev_size= flag malformed: " << arg;
             }
-        } else if (StartsWith(flag, "zram_backing_dev_path=")) {
-            entry->zram_backing_dev_path = arg;
         } else {
             LWARNING << "Warning: unknown flag: " << flag;
         }
@@ -640,13 +635,14 @@
             entry.fs_mgr_flags.wait = true;
             entry.fs_mgr_flags.logical = true;
             entry.fs_mgr_flags.first_stage_mount = true;
+            fstab->emplace_back(entry);
         } else {
             // If the corresponding partition exists, transform all its Fstab
             // by pointing .blk_device to the DSU partition.
             for (auto&& entry : entries) {
                 entry->blk_device = partition;
                 // AVB keys for DSU should always be under kDsuKeysDir.
-                entry->avb_keys += kDsuKeysDir;
+                entry->avb_keys = kDsuKeysDir;
             }
             // Make sure the ext4 is included to support GSI.
             auto partition_ext4 =
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 1fa1aa1..a7704de 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -809,15 +809,26 @@
     entry.fs_type = mnt_type;
     if ((mnt_type == "f2fs") && !f2fs) entry.fs_type = "ext4";
     if ((mnt_type == "ext4") && !ext4) entry.fs_type = "f2fs";
-    entry.flags = MS_NOATIME;
-    if (readonly) {
-        entry.flags |= MS_RDONLY;
-    } else {
+    entry.flags = MS_NOATIME | MS_RDONLY;
+    auto mounted = true;
+    if (!readonly) {
+        if (entry.fs_type == "ext4") {
+            // check if ext4 de-dupe
+            entry.flags |= MS_RDONLY;
+            auto save_errno = errno;
+            mounted = fs_mgr_do_mount_one(entry) == 0;
+            if (mounted) {
+                mounted = !fs_mgr_has_shared_blocks(entry.mount_point, entry.blk_device);
+                fs_mgr_overlayfs_umount_scratch();
+            }
+            errno = save_errno;
+        }
+        entry.flags &= ~MS_RDONLY;
         fs_mgr_set_blk_ro(device_path, false);
     }
     entry.fs_mgr_flags.check = true;
     auto save_errno = errno;
-    auto mounted = fs_mgr_do_mount_one(entry) == 0;
+    if (mounted) mounted = fs_mgr_do_mount_one(entry) == 0;
     if (!mounted) {
         if ((entry.fs_type == "f2fs") && ext4) {
             entry.fs_type = "ext4";
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 2a67b8c..11e3664 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -60,8 +60,20 @@
 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
 #define FS_MGR_MNTALL_FAIL (-1)
+
+struct MountAllResult {
+    // One of the FS_MGR_MNTALL_* returned code defined above.
+    int code;
+    // Whether userdata was mounted as a result of |fs_mgr_mount_all| call.
+    bool userdata_mounted;
+};
+
 // fs_mgr_mount_all() updates fstab entries that reference device-mapper.
-int fs_mgr_mount_all(android::fs_mgr::Fstab* fstab, int mount_mode);
+// Returns a |MountAllResult|. The first element is one of the FS_MNG_MNTALL_* return codes
+// defined above, and the second element tells whether this call to fs_mgr_mount_all was responsible
+// for mounting userdata. Later is required for init to correctly enqueue fs-related events as part
+// of userdata remount during userspace reboot.
+MountAllResult fs_mgr_mount_all(android::fs_mgr::Fstab* fstab, int mount_mode);
 
 #define FS_MGR_DOMNT_FAILED (-1)
 #define FS_MGR_DOMNT_BUSY (-2)
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 7216402..4093445 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -36,6 +36,7 @@
     std::string fs_type;
     unsigned long flags = 0;
     std::string fs_options;
+    std::string fs_checkpoint_opts;
     std::string key_loc;
     std::string metadata_key_dir;
     std::string metadata_encryption;
@@ -51,9 +52,7 @@
     off64_t logical_blk_size = 0;
     std::string sysfs_path;
     std::string vbmeta_partition;
-    std::string zram_loopback_path;
-    uint64_t zram_loopback_size = 512 * 1024 * 1024;  // 512MB by default;
-    std::string zram_backing_dev_path;
+    uint64_t zram_backingdev_size = 0;
     std::string avb_keys;
 
     struct FsMgrFlags {
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 58241b3..e425284 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -42,6 +42,7 @@
             enabled: false,
         },
     },
+    ramdisk_available: true,
 }
 
 filegroup {
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index 7912688..bb7d8b3 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -427,6 +427,20 @@
     return true;
 }
 
+// Accepts a device mapper device name (like system_a, vendor_b etc) and
+// returns its UUID.
+bool DeviceMapper::GetDmDeviceUuidByName(const std::string& name, std::string* uuid) {
+    struct dm_ioctl io;
+    InitIo(&io, name);
+    if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
+        PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
+        return false;
+    }
+
+    *uuid = std::string(io.uuid);
+    return true;
+}
+
 bool DeviceMapper::GetDeviceNumber(const std::string& name, dev_t* dev) {
     struct dm_ioctl io;
     InitIo(&io, name);
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index abe9c4c..5d6db46 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -172,6 +172,13 @@
     // could race with ueventd.
     bool GetDmDevicePathByName(const std::string& name, std::string* path);
 
+    // Returns the device mapper UUID for a given name.  If the device does not
+    // exist, false is returned, and the path parameter is not set.
+    //
+    // WaitForFile() should not be used in conjunction with this call, since it
+    // could race with ueventd.
+    bool GetDmDeviceUuidByName(const std::string& name, std::string* path);
+
     // Returns a device's unique path as generated by ueventd. This will return
     // true as long as the device has been created, even if ueventd has not
     // processed it yet.
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index cae43e6..a622110 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -110,30 +110,3 @@
     auto_gen_config: true,
     require_root: true,
 }
-
-/* BUG(148874852) temporary test */
-cc_test {
-    name: "fiemap_image_test_presubmit",
-    cppflags: [
-        "-DSKIP_TEST_IN_PRESUBMIT",
-    ],
-    static_libs: [
-        "libcrypto_utils",
-        "libdm",
-        "libext4_utils",
-        "libfs_mgr",
-        "liblp",
-    ],
-    shared_libs: [
-        "libbase",
-        "libcrypto",
-        "libcutils",
-        "liblog",
-    ],
-    srcs: [
-        "image_test.cpp",
-    ],
-    test_suites: ["device-tests"],
-    auto_gen_config: true,
-    require_root: true,
-}
diff --git a/fs_mgr/libfiemap/fiemap_writer.cpp b/fs_mgr/libfiemap/fiemap_writer.cpp
index 4dd4bcc..621031a 100644
--- a/fs_mgr/libfiemap/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap/fiemap_writer.cpp
@@ -45,7 +45,7 @@
 
 using namespace android::dm;
 
-// We cap the maximum number of extents as a sanity measure.
+// We cap the maximum number of extents as a robustness measure.
 static constexpr uint32_t kMaxExtents = 50000;
 
 // TODO: Fallback to using fibmap if FIEMAP_EXTENT_MERGED is set.
diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index 3ee742f..93fc131 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -136,13 +136,13 @@
     return !!FindPartition(*metadata.get(), name);
 }
 
-static bool IsTestDir(const std::string& path) {
-    return android::base::StartsWith(path, kTestImageMetadataDir) ||
-           android::base::StartsWith(path, kOtaTestImageMetadataDir);
+bool ImageManager::MetadataDirIsTest() const {
+    return IsSubdir(metadata_dir_, kTestImageMetadataDir) ||
+           IsSubdir(metadata_dir_, kOtaTestImageMetadataDir);
 }
 
-static bool IsUnreliablePinningAllowed(const std::string& path) {
-    return android::base::StartsWith(path, "/data/gsi/dsu/") || IsTestDir(path);
+bool ImageManager::IsUnreliablePinningAllowed() const {
+    return IsSubdir(data_dir_, "/data/gsi/dsu/") || MetadataDirIsTest();
 }
 
 FiemapStatus ImageManager::CreateBackingImage(
@@ -159,7 +159,7 @@
     if (!FilesystemHasReliablePinning(data_path, &reliable_pinning)) {
         return FiemapStatus::Error();
     }
-    if (!reliable_pinning && !IsUnreliablePinningAllowed(data_path)) {
+    if (!reliable_pinning && !IsUnreliablePinningAllowed()) {
         // For historical reasons, we allow unreliable pinning for certain use
         // cases (DSUs, testing) because the ultimate use case is either
         // developer-oriented or ephemeral (the intent is to boot immediately
@@ -178,7 +178,7 @@
     // if device-mapper is stacked in some complex way not supported by
     // FiemapWriter.
     auto device_path = GetDevicePathForFile(fw.get());
-    if (android::base::StartsWith(device_path, "/dev/block/dm-") && !IsTestDir(metadata_dir_)) {
+    if (android::base::StartsWith(device_path, "/dev/block/dm-") && !MetadataDirIsTest()) {
         LOG(ERROR) << "Cannot persist images against device-mapper device: " << device_path;
 
         fw = {};
@@ -640,16 +640,22 @@
         return false;
     }
 
+    bool ok = true;
     for (const auto& partition : metadata->partitions) {
         auto name = GetPartitionName(partition);
         auto image_path = GetImageHeaderPath(name);
         auto fiemap = SplitFiemap::Open(image_path);
-        if (!fiemap || !fiemap->HasPinnedExtents()) {
-            LOG(ERROR) << "Image is missing or was moved: " << image_path;
-            return false;
+        if (fiemap == nullptr) {
+            LOG(ERROR) << "SplitFiemap::Open(\"" << image_path << "\") failed";
+            ok = false;
+            continue;
+        }
+        if (!fiemap->HasPinnedExtents()) {
+            LOG(ERROR) << "Image doesn't have pinned extents: " << image_path;
+            ok = false;
         }
     }
-    return true;
+    return ok;
 }
 
 bool ImageManager::DisableImage(const std::string& name) {
diff --git a/fs_mgr/libfiemap/image_test.cpp b/fs_mgr/libfiemap/image_test.cpp
index 6663391..6d09751 100644
--- a/fs_mgr/libfiemap/image_test.cpp
+++ b/fs_mgr/libfiemap/image_test.cpp
@@ -34,10 +34,13 @@
 #include <libdm/dm.h>
 #include <libfiemap/image_manager.h>
 
+#include "utility.h"
+
 using namespace android::dm;
 using namespace std::literals;
 using android::base::unique_fd;
 using android::fiemap::ImageManager;
+using android::fiemap::IsSubdir;
 using android::fs_mgr::BlockDeviceInfo;
 using android::fs_mgr::PartitionOpener;
 using android::fs_mgr::WaitForFile;
@@ -131,6 +134,51 @@
     ASSERT_TRUE(manager_->UnmapImageDevice(base_name_));
 }
 
+namespace {
+
+struct IsSubdirTestParam {
+    std::string child;
+    std::string parent;
+    bool result;
+};
+
+class IsSubdirTest : public ::testing::TestWithParam<IsSubdirTestParam> {};
+
+TEST_P(IsSubdirTest, Test) {
+    const auto& param = GetParam();
+    EXPECT_EQ(param.result, IsSubdir(param.child, param.parent))
+            << "IsSubdir(child=\"" << param.child << "\", parent=\"" << param.parent
+            << "\") != " << (param.result ? "true" : "false");
+}
+
+std::vector<IsSubdirTestParam> IsSubdirTestValues() {
+    // clang-format off
+    std::vector<IsSubdirTestParam> base_cases{
+            {"/foo/bar",     "/foo",     true},
+            {"/foo/bar/baz", "/foo",     true},
+            {"/foo",         "/foo",     true},
+            {"/foo",         "/",        true},
+            {"/",            "/",        true},
+            {"/foo",         "/foo/bar", false},
+            {"/foo",         "/bar",     false},
+            {"/foo-bar",     "/foo",     false},
+            {"/",            "/foo",     false},
+    };
+    // clang-format on
+    std::vector<IsSubdirTestParam> ret;
+    for (const auto& e : base_cases) {
+        ret.push_back(e);
+        ret.push_back({e.child + "/", e.parent, e.result});
+        ret.push_back({e.child, e.parent + "/", e.result});
+        ret.push_back({e.child + "/", e.parent + "/", e.result});
+    }
+    return ret;
+}
+
+INSTANTIATE_TEST_SUITE_P(IsSubdirTest, IsSubdirTest, ::testing::ValuesIn(IsSubdirTestValues()));
+
+}  // namespace
+
 bool Mkdir(const std::string& path) {
     if (mkdir(path.c_str(), 0700) && errno != EEXIST) {
         std::cerr << "Could not mkdir " << path << ": " << strerror(errno) << std::endl;
diff --git a/fs_mgr/libfiemap/include/libfiemap/image_manager.h b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
index 60b98dc..50f4f33 100644
--- a/fs_mgr/libfiemap/include/libfiemap/image_manager.h
+++ b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
@@ -176,6 +176,8 @@
     bool MapWithDmLinear(const IPartitionOpener& opener, const std::string& name,
                          const std::chrono::milliseconds& timeout_ms, std::string* path);
     bool UnmapImageDevice(const std::string& name, bool force);
+    bool IsUnreliablePinningAllowed() const;
+    bool MetadataDirIsTest() const;
 
     ImageManager(const ImageManager&) = delete;
     ImageManager& operator=(const ImageManager&) = delete;
diff --git a/fs_mgr/libfiemap/split_fiemap_writer.cpp b/fs_mgr/libfiemap/split_fiemap_writer.cpp
index 12c7397..36bb3df 100644
--- a/fs_mgr/libfiemap/split_fiemap_writer.cpp
+++ b/fs_mgr/libfiemap/split_fiemap_writer.cpp
@@ -266,7 +266,7 @@
         cursor_file_pos_ += bytes_to_write;
     }
 
-    // If we've reached the end of the current file, close it for sanity.
+    // If we've reached the end of the current file, close it.
     if (cursor_file_pos_ == file->size()) {
         cursor_fd_ = {};
     }
diff --git a/fs_mgr/libfiemap/utility.cpp b/fs_mgr/libfiemap/utility.cpp
index bbb0510..54cf183 100644
--- a/fs_mgr/libfiemap/utility.cpp
+++ b/fs_mgr/libfiemap/utility.cpp
@@ -139,8 +139,7 @@
     }
 
     *bdev_name = ::android::base::Basename(sysfs_bdev);
-    // Paranoid sanity check to make sure we just didn't get the
-    // input in return as-is.
+    // Check that the symlink doesn't point to itself.
     if (sysfs_bdev == *bdev_name) {
         LOG(ERROR) << "Malformed symlink for block device: " << sysfs_bdev;
         return false;
@@ -168,5 +167,30 @@
     return F2fsPinBeforeAllocate(fd, supported);
 }
 
+bool IsSubdir(const std::string& child, const std::string& parent) {
+    // Precondition: both are absolute paths.
+    CHECK(android::base::StartsWith(child, "/")) << "Not an absolute path: " << child;
+    CHECK(android::base::StartsWith(parent, "/")) << "Not an absolute path: " << parent;
+
+    // Remove extraneous "/" at the end.
+    std::string_view child_sv = child;
+    while (child_sv != "/" && android::base::ConsumeSuffix(&child_sv, "/"))
+        ;
+
+    std::string_view parent_sv = parent;
+    while (parent_sv != "/" && android::base::ConsumeSuffix(&parent_sv, "/"))
+        ;
+
+    // IsSubdir(anything, "/") => true
+    if (parent_sv == "/") return true;
+
+    // IsSubdir("/foo", "/foo") => true
+    if (parent_sv == child_sv) return true;
+
+    // IsSubdir("/foo/bar", "/foo") => true
+    // IsSubdir("/foo-bar", "/foo") => false
+    return android::base::StartsWith(child_sv, std::string(parent_sv) + "/");
+}
+
 }  // namespace fiemap
 }  // namespace android
diff --git a/fs_mgr/libfiemap/utility.h b/fs_mgr/libfiemap/utility.h
index 4c0bc2b..aa40f79 100644
--- a/fs_mgr/libfiemap/utility.h
+++ b/fs_mgr/libfiemap/utility.h
@@ -51,5 +51,9 @@
 // cases (such as snapshots or adb remount).
 bool FilesystemHasReliablePinning(const std::string& file, bool* supported);
 
+// Crude implementation to check if |child| is a subdir of |parent|.
+// Assume both are absolute paths.
+bool IsSubdir(const std::string& child, const std::string& parent);
+
 }  // namespace fiemap
 }  // namespace android
diff --git a/fs_mgr/libfs_avb/avb_ops.cpp b/fs_mgr/libfs_avb/avb_ops.cpp
index c192bf5..46072bb 100644
--- a/fs_mgr/libfs_avb/avb_ops.cpp
+++ b/fs_mgr/libfs_avb/avb_ops.cpp
@@ -52,16 +52,16 @@
             partition, offset, num_bytes, buffer, out_num_read);
 }
 
-static AvbIOResult dummy_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED,
-                                             size_t rollback_index_location ATTRIBUTE_UNUSED,
-                                             uint64_t* out_rollback_index) {
+static AvbIOResult no_op_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED,
+                                            size_t rollback_index_location ATTRIBUTE_UNUSED,
+                                            uint64_t* out_rollback_index) {
     // rollback_index has been checked in bootloader phase.
     // In user-space, returns the smallest value 0 to pass the check.
     *out_rollback_index = 0;
     return AVB_IO_RESULT_OK;
 }
 
-static AvbIOResult dummy_validate_vbmeta_public_key(
+static AvbIOResult no_op_validate_vbmeta_public_key(
         AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED,
         size_t public_key_length ATTRIBUTE_UNUSED,
         const uint8_t* public_key_metadata ATTRIBUTE_UNUSED,
@@ -76,8 +76,8 @@
     return AVB_IO_RESULT_OK;
 }
 
-static AvbIOResult dummy_read_is_device_unlocked(AvbOps* ops ATTRIBUTE_UNUSED,
-                                                 bool* out_is_unlocked) {
+static AvbIOResult no_op_read_is_device_unlocked(AvbOps* ops ATTRIBUTE_UNUSED,
+                                                bool* out_is_unlocked) {
     // The function is for bootloader to update the value into
     // androidboot.vbmeta.device_state in kernel cmdline.
     // In user-space, returns true as we don't need to update it anymore.
@@ -85,9 +85,9 @@
     return AVB_IO_RESULT_OK;
 }
 
-static AvbIOResult dummy_get_unique_guid_for_partition(AvbOps* ops ATTRIBUTE_UNUSED,
-                                                       const char* partition ATTRIBUTE_UNUSED,
-                                                       char* guid_buf, size_t guid_buf_size) {
+static AvbIOResult no_op_get_unique_guid_for_partition(AvbOps* ops ATTRIBUTE_UNUSED,
+                                                      const char* partition ATTRIBUTE_UNUSED,
+                                                      char* guid_buf, size_t guid_buf_size) {
     // The function is for bootloader to set the correct UUID
     // for a given partition in kernel cmdline.
     // In user-space, returns a faking one as we don't need to update
@@ -96,9 +96,9 @@
     return AVB_IO_RESULT_OK;
 }
 
-static AvbIOResult dummy_get_size_of_partition(AvbOps* ops ATTRIBUTE_UNUSED,
-                                               const char* partition ATTRIBUTE_UNUSED,
-                                               uint64_t* out_size_num_byte) {
+static AvbIOResult no_op_get_size_of_partition(AvbOps* ops ATTRIBUTE_UNUSED,
+                                              const char* partition ATTRIBUTE_UNUSED,
+                                              uint64_t* out_size_num_byte) {
     // The function is for bootloader to load entire content of AVB HASH partitions.
     // In user-space, returns 0 as we only need to set up AVB HASHTHREE partitions.
     *out_size_num_byte = 0;
@@ -123,15 +123,15 @@
     // We only need to provide the implementation of read_from_partition()
     // operation since that's all what is being used by the avb_slot_verify().
     // Other I/O operations are only required in bootloader but not in
-    // user-space so we set them as dummy operations. Also zero the entire
+    // user-space so we set them as no-op operations. Also zero the entire
     // struct so operations added in the future will be set to NULL.
     memset(&avb_ops_, 0, sizeof(AvbOps));
     avb_ops_.read_from_partition = read_from_partition;
-    avb_ops_.read_rollback_index = dummy_read_rollback_index;
-    avb_ops_.validate_vbmeta_public_key = dummy_validate_vbmeta_public_key;
-    avb_ops_.read_is_device_unlocked = dummy_read_is_device_unlocked;
-    avb_ops_.get_unique_guid_for_partition = dummy_get_unique_guid_for_partition;
-    avb_ops_.get_size_of_partition = dummy_get_size_of_partition;
+    avb_ops_.read_rollback_index = no_op_read_rollback_index;
+    avb_ops_.validate_vbmeta_public_key = no_op_validate_vbmeta_public_key;
+    avb_ops_.read_is_device_unlocked = no_op_read_is_device_unlocked;
+    avb_ops_.get_unique_guid_for_partition = no_op_get_unique_guid_for_partition;
+    avb_ops_.get_size_of_partition = no_op_get_size_of_partition;
 
     // Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps.
     avb_ops_.user_data = this;
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index 5d504ab..49333a1 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -226,7 +226,7 @@
             return nullptr;
     }
 
-    // Sanity check here because we have to use vbmeta_images_[0] below.
+    // Validity check here because we have to use vbmeta_images_[0] below.
     if (avb_handle->vbmeta_images_.size() < 1) {
         LERROR << "LoadAndVerifyVbmetaByPartition failed, no vbmeta loaded";
         return nullptr;
@@ -405,11 +405,11 @@
     //   - AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION (UNLOCKED only).
     //     Might occur in either the top-level vbmeta or a chained vbmeta.
     //   - AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED (UNLOCKED only).
-    //     Could only occur in a chained vbmeta. Because we have *dummy* operations in
+    //     Could only occur in a chained vbmeta. Because we have *no-op* operations in
     //     FsManagerAvbOps such that avb_ops->validate_vbmeta_public_key() used to validate
     //     the public key of the top-level vbmeta always pass in userspace here.
     //
-    // The following verify result won't happen, because the *dummy* operation
+    // The following verify result won't happen, because the *no-op* operation
     // avb_ops->read_rollback_index() always returns the minimum value zero. So rollbacked
     // vbmeta images, which should be caught in the bootloader stage, won't be detected here.
     //   - AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX
diff --git a/fs_mgr/libfs_avb/tests/util_test.cpp b/fs_mgr/libfs_avb/tests/util_test.cpp
index 5c388aa..a52a00d 100644
--- a/fs_mgr/libfs_avb/tests/util_test.cpp
+++ b/fs_mgr/libfs_avb/tests/util_test.cpp
@@ -222,7 +222,7 @@
     base::FilePath test_dir;
     ASSERT_TRUE(base::CreateTemporaryDirInDir(tmp_dir, "list-file-tests.", &test_dir));
 
-    // Generates dummy files to list.
+    // Generates test files to list.
     base::FilePath file_path_1 = test_dir.Append("1.txt");
     ASSERT_TRUE(base::WriteFile(file_path_1, "1", 1));
     base::FilePath file_path_2 = test_dir.Append("2.txt");
@@ -253,7 +253,7 @@
     base::FilePath test_dir;
     ASSERT_TRUE(base::CreateTemporaryDirInDir(tmp_dir, "list-file-tests.", &test_dir));
 
-    // Generates dummy files to list.
+    // Generates test files to list.
     base::FilePath file_path_1 = test_dir.Append("1.txt");
     ASSERT_TRUE(base::WriteFile(file_path_1, "1", 1));
     base::FilePath file_path_2 = test_dir.Append("2.txt");
@@ -281,7 +281,7 @@
     base::FilePath tmp_dir;
     ASSERT_TRUE(GetTempDir(&tmp_dir));
 
-    // Generates dummy files to list.
+    // Generates test files to list.
     base::FilePath no_such_dir = tmp_dir.Append("not_such_dir");
 
     auto fail = ListFiles(no_such_dir.value());
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index a21e09e..e4b617a 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -234,7 +234,7 @@
         EXPECT_EQ(lba, aligned_lba);
     }
 
-    // Sanity check one extent.
+    // Check one extent.
     EXPECT_EQ(exported->extents.back().target_data, 3072);
 }
 
diff --git a/fs_mgr/liblp/device_test.cpp b/fs_mgr/liblp/device_test.cpp
index 6af9d94..236fd8d 100644
--- a/fs_mgr/liblp/device_test.cpp
+++ b/fs_mgr/liblp/device_test.cpp
@@ -47,7 +47,7 @@
     BlockDeviceInfo device_info;
     ASSERT_TRUE(opener.GetInfo(fs_mgr_get_super_partition_name(), &device_info));
 
-    // Sanity check that the device doesn't give us some weird inefficient
+    // Check that the device doesn't give us some weird inefficient
     // alignment.
     EXPECT_EQ(device_info.alignment % LP_SECTOR_SIZE, 0);
     EXPECT_EQ(device_info.logical_block_size % LP_SECTOR_SIZE, 0);
diff --git a/fs_mgr/liblp/partition_opener.cpp b/fs_mgr/liblp/partition_opener.cpp
index 1d4db85..4696ff1 100644
--- a/fs_mgr/liblp/partition_opener.cpp
+++ b/fs_mgr/liblp/partition_opener.cpp
@@ -38,6 +38,9 @@
 namespace {
 
 std::string GetPartitionAbsolutePath(const std::string& path) {
+#if !defined(__ANDROID__)
+    return path;
+#else
     if (android::base::StartsWith(path, "/")) {
         return path;
     }
@@ -49,13 +52,14 @@
         // Dynamic System Update is installed to an sdcard, which won't be in
         // the boot device list.
         //
-        // We whitelist because most devices in /dev/block are not valid for
+        // mmcblk* is allowed because most devices in /dev/block are not valid for
         // storing fiemaps.
         if (android::base::StartsWith(path, "mmcblk")) {
             return "/dev/block/" + path;
         }
     }
     return by_name;
+#endif
 }
 
 bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info) {
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index e6fd9f7..24ccc0f 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -174,7 +174,7 @@
         return false;
     }
 
-    // Do basic sanity checks before computing the checksum.
+    // Do basic validity checks before computing the checksum.
     if (header.magic != LP_METADATA_HEADER_MAGIC) {
         LERROR << "Logical partition metadata has invalid magic value.";
         return false;
@@ -255,7 +255,7 @@
 
     LpMetadataHeader& header = metadata->header;
 
-    // Sanity check the table size.
+    // Check the table size.
     if (header.tables_size > geometry.metadata_max_size) {
         LERROR << "Invalid partition metadata header table size.";
         return nullptr;
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 8bf1ee9..2708efa 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -81,8 +81,8 @@
     return header_blob + tables;
 }
 
-// Perform sanity checks so we don't accidentally overwrite valid metadata
-// with potentially invalid metadata, or random partition data with metadata.
+// Perform checks so we don't accidentally overwrite valid metadata with
+// potentially invalid metadata, or random partition data with metadata.
 static bool ValidateAndSerializeMetadata([[maybe_unused]] const IPartitionOpener& opener,
                                          const LpMetadata& metadata, const std::string& slot_suffix,
                                          std::string* blob) {
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 95301ff..046ea74 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -30,6 +30,7 @@
     static_libs: [
         "libdm",
         "libfstab",
+        "libsnapshot_cow",
         "update_metadata-protos",
     ],
     whole_static_libs: [
@@ -38,7 +39,9 @@
         "libfstab",
     ],
     header_libs: [
+        "libchrome",
         "libfiemap_headers",
+        "libupdate_engine_headers",
     ],
     export_static_lib_headers: [
         "update_metadata-protos",
@@ -71,9 +74,11 @@
         "android/snapshot/snapshot.proto",
         "device_info.cpp",
         "snapshot.cpp",
+        "snapshot_reader.cpp",
         "snapshot_stats.cpp",
         "snapshot_stub.cpp",
         "snapshot_metadata_updater.cpp",
+        "snapshot_writer.cpp",
         "partition_cow_creator.cpp",
         "return.cpp",
         "utility.cpp",
@@ -122,6 +127,42 @@
     ],
 }
 
+cc_defaults {
+    name: "libsnapshot_cow_defaults",
+    defaults: [
+        "fs_mgr_defaults",
+    ],
+    cflags: [
+        "-D_FILE_OFFSET_BITS=64",
+        "-Wall",
+        "-Werror",
+    ],
+    export_include_dirs: ["include"],
+    srcs: [
+        "cow_decompress.cpp",
+        "cow_reader.cpp",
+        "cow_writer.cpp",
+    ],
+}
+
+cc_library_static {
+    name: "libsnapshot_cow",
+    defaults: [
+        "libsnapshot_cow_defaults",
+    ],
+    host_supported: true,
+    recovery_available: true,
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+    static_libs: [
+        "libbrotli",
+        "libz",
+    ],
+    ramdisk_available: true,
+}
+
 cc_library_static {
     name: "libsnapshot_test_helpers",
     defaults: ["libsnapshot_defaults"],
@@ -176,6 +217,7 @@
         "libgmock",
         "liblp",
         "libsnapshot",
+        "libsnapshot_cow",
         "libsnapshot_test_helpers",
         "libsparse",
     ],
@@ -210,6 +252,7 @@
     static_libs: [
         "libfstab",
         "libsnapshot",
+        "libsnapshot_cow",
         "update_metadata-protos",
     ],
     shared_libs: [
@@ -273,12 +316,15 @@
         "libgmock", // from libsnapshot_test_helpers
         "liblog",
         "liblp",
+        "libsnapshot_cow",
         "libsnapshot_test_helpers",
         "libprotobuf-mutator",
     ],
     header_libs: [
+        "libchrome",
         "libfiemap_headers",
         "libstorage_literals_headers",
+        "libupdate_engine_headers",
     ],
     proto: {
         type: "full",
@@ -310,3 +356,169 @@
     auto_gen_config: true,
     require_root: true,
 }
+
+cc_defaults {
+    name: "snapuserd_defaults",
+    defaults: [
+        "fs_mgr_defaults",
+    ],
+    srcs: [
+        "snapuserd.cpp",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror"
+    ],
+
+    static_libs: [
+        "libbase",
+        "libbrotli",
+        "liblog",
+        "libdm",
+        "libz",
+        "libsnapshot_cow",
+    ],
+}
+
+cc_binary {
+    name: "snapuserd",
+    defaults: ["snapuserd_defaults"],
+}
+
+cc_binary {
+    name: "snapuserd_ramdisk",
+    stem: "snapuserd",
+    defaults: ["snapuserd_defaults"],
+
+    ramdisk: true,
+    static_executable: true,
+}
+
+cc_test {
+    name: "cow_api_test",
+    defaults: [
+        "fs_mgr_defaults",
+    ],
+    srcs: [
+        "cow_api_test.cpp",
+    ],
+    cflags: [
+        "-D_FILE_OFFSET_BITS=64",
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcrypto",
+        "liblog",
+        "libz",
+    ],
+    static_libs: [
+        "libbrotli",
+        "libgtest",
+        "libsnapshot_cow",
+    ],
+    test_min_api_level: 30,
+    auto_gen_config: true,
+    require_root: false,
+    host_supported: true,
+}
+
+cc_binary {
+    name: "make_cow_from_ab_ota",
+    host_supported: true,
+    device_supported: false,
+    cflags: [
+        "-D_FILE_OFFSET_BITS=64",
+        "-Wall",
+        "-Werror",
+    ],
+    static_libs: [
+        "libbase",
+        "libbspatch",
+        "libbrotli",
+        "libbz",
+        "libchrome",
+        "libcrypto",
+        "libgflags",
+        "liblog",
+        "libprotobuf-cpp-lite",
+        "libpuffpatch",
+        "libsnapshot_cow",
+        "libsparse",
+        "libxz",
+        "libz",
+        "libziparchive",
+        "update_metadata-protos",
+    ],
+    srcs: [
+        "make_cow_from_ab_ota.cpp",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
+
+cc_binary {
+    name: "estimate_cow_from_nonab_ota",
+    host_supported: true,
+    device_supported: false,
+    cflags: [
+        "-D_FILE_OFFSET_BITS=64",
+        "-Wall",
+        "-Werror",
+    ],
+    static_libs: [
+        "libbase",
+        "libbrotli",
+        "libbz",
+        "libcrypto",
+        "libgflags",
+        "liblog",
+        "libsnapshot_cow",
+        "libsparse",
+        "libz",
+        "libziparchive",
+    ],
+    srcs: [
+        "estimate_cow_from_nonab_ota.cpp",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+}
+
+cc_test {
+    name: "cow_snapuserd_test",
+    defaults: [
+        "fs_mgr_defaults",
+    ],
+    srcs: [
+        "cow_snapuserd_test.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+    static_libs: [
+        "libbrotli",
+        "libgtest",
+        "libsnapshot_cow",
+        "libz",
+    ],
+    header_libs: [
+        "libstorage_literals_headers",
+    ],
+    test_min_api_level: 30,
+    auto_gen_config: true,
+    require_root: false,
+}
diff --git a/fs_mgr/libsnapshot/cow_api_test.cpp b/fs_mgr/libsnapshot/cow_api_test.cpp
new file mode 100644
index 0000000..40d5efb
--- /dev/null
+++ b/fs_mgr/libsnapshot/cow_api_test.cpp
@@ -0,0 +1,334 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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/stat.h>
+
+#include <cstdio>
+#include <iostream>
+#include <memory>
+#include <string_view>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <libsnapshot/cow_reader.h>
+#include <libsnapshot/cow_writer.h>
+
+namespace android {
+namespace snapshot {
+
+class CowTest : public ::testing::Test {
+  protected:
+    virtual void SetUp() override {
+        cow_ = std::make_unique<TemporaryFile>();
+        ASSERT_GE(cow_->fd, 0) << strerror(errno);
+    }
+
+    virtual void TearDown() override { cow_ = nullptr; }
+
+    std::unique_ptr<TemporaryFile> cow_;
+};
+
+// Sink that always appends to the end of a string.
+class StringSink : public IByteSink {
+  public:
+    void* GetBuffer(size_t requested, size_t* actual) override {
+        size_t old_size = stream_.size();
+        stream_.resize(old_size + requested, '\0');
+        *actual = requested;
+        return stream_.data() + old_size;
+    }
+    bool ReturnData(void*, size_t) override { return true; }
+    void Reset() { stream_.clear(); }
+
+    std::string& stream() { return stream_; }
+
+  private:
+    std::string stream_;
+};
+
+TEST_F(CowTest, ReadWrite) {
+    CowOptions options;
+    CowWriter writer(options);
+
+    ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+    std::string data = "This is some data, believe it";
+    data.resize(options.block_size, '\0');
+
+    ASSERT_TRUE(writer.AddCopy(10, 20));
+    ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
+    ASSERT_TRUE(writer.AddZeroBlocks(51, 2));
+    ASSERT_TRUE(writer.Flush());
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    CowReader reader;
+    CowHeader header;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+    ASSERT_TRUE(reader.GetHeader(&header));
+    ASSERT_EQ(header.magic, kCowMagicNumber);
+    ASSERT_EQ(header.major_version, kCowVersionMajor);
+    ASSERT_EQ(header.minor_version, kCowVersionMinor);
+    ASSERT_EQ(header.block_size, options.block_size);
+    ASSERT_EQ(header.num_ops, 4);
+
+    auto iter = reader.GetOpIter();
+    ASSERT_NE(iter, nullptr);
+    ASSERT_FALSE(iter->Done());
+    auto op = &iter->Get();
+
+    ASSERT_EQ(op->type, kCowCopyOp);
+    ASSERT_EQ(op->compression, kCowCompressNone);
+    ASSERT_EQ(op->data_length, 0);
+    ASSERT_EQ(op->new_block, 10);
+    ASSERT_EQ(op->source, 20);
+
+    StringSink sink;
+
+    iter->Next();
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+
+    ASSERT_EQ(op->type, kCowReplaceOp);
+    ASSERT_EQ(op->compression, kCowCompressNone);
+    ASSERT_EQ(op->data_length, 4096);
+    ASSERT_EQ(op->new_block, 50);
+    ASSERT_EQ(op->source, 106);
+    ASSERT_TRUE(reader.ReadData(*op, &sink));
+    ASSERT_EQ(sink.stream(), data);
+
+    iter->Next();
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+
+    // Note: the zero operation gets split into two blocks.
+    ASSERT_EQ(op->type, kCowZeroOp);
+    ASSERT_EQ(op->compression, kCowCompressNone);
+    ASSERT_EQ(op->data_length, 0);
+    ASSERT_EQ(op->new_block, 51);
+    ASSERT_EQ(op->source, 0);
+
+    iter->Next();
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+
+    ASSERT_EQ(op->type, kCowZeroOp);
+    ASSERT_EQ(op->compression, kCowCompressNone);
+    ASSERT_EQ(op->data_length, 0);
+    ASSERT_EQ(op->new_block, 52);
+    ASSERT_EQ(op->source, 0);
+
+    iter->Next();
+    ASSERT_TRUE(iter->Done());
+}
+
+TEST_F(CowTest, CompressGz) {
+    CowOptions options;
+    options.compression = "gz";
+    CowWriter writer(options);
+
+    ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+    std::string data = "This is some data, believe it";
+    data.resize(options.block_size, '\0');
+
+    ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
+    ASSERT_TRUE(writer.Flush());
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+
+    auto iter = reader.GetOpIter();
+    ASSERT_NE(iter, nullptr);
+    ASSERT_FALSE(iter->Done());
+    auto op = &iter->Get();
+
+    StringSink sink;
+
+    ASSERT_EQ(op->type, kCowReplaceOp);
+    ASSERT_EQ(op->compression, kCowCompressGz);
+    ASSERT_EQ(op->data_length, 56);  // compressed!
+    ASSERT_EQ(op->new_block, 50);
+    ASSERT_EQ(op->source, 106);
+    ASSERT_TRUE(reader.ReadData(*op, &sink));
+    ASSERT_EQ(sink.stream(), data);
+
+    iter->Next();
+    ASSERT_TRUE(iter->Done());
+}
+
+TEST_F(CowTest, CompressTwoBlocks) {
+    CowOptions options;
+    options.compression = "gz";
+    CowWriter writer(options);
+
+    ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+    std::string data = "This is some data, believe it";
+    data.resize(options.block_size * 2, '\0');
+
+    ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
+    ASSERT_TRUE(writer.Flush());
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+
+    auto iter = reader.GetOpIter();
+    ASSERT_NE(iter, nullptr);
+    ASSERT_FALSE(iter->Done());
+    iter->Next();
+    ASSERT_FALSE(iter->Done());
+
+    StringSink sink;
+
+    auto op = &iter->Get();
+    ASSERT_EQ(op->type, kCowReplaceOp);
+    ASSERT_EQ(op->compression, kCowCompressGz);
+    ASSERT_EQ(op->new_block, 51);
+    ASSERT_TRUE(reader.ReadData(*op, &sink));
+}
+
+// Only return 1-byte buffers, to stress test the partial read logic in
+// CowReader.
+class HorribleStringSink : public StringSink {
+  public:
+    void* GetBuffer(size_t, size_t* actual) override { return StringSink::GetBuffer(1, actual); }
+};
+
+class CompressionTest : public CowTest, public testing::WithParamInterface<const char*> {};
+
+TEST_P(CompressionTest, HorribleSink) {
+    CowOptions options;
+    options.compression = GetParam();
+    CowWriter writer(options);
+
+    ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+    std::string data = "This is some data, believe it";
+    data.resize(options.block_size, '\0');
+
+    ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
+    ASSERT_TRUE(writer.Flush());
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+
+    auto iter = reader.GetOpIter();
+    ASSERT_NE(iter, nullptr);
+    ASSERT_FALSE(iter->Done());
+
+    HorribleStringSink sink;
+    auto op = &iter->Get();
+    ASSERT_TRUE(reader.ReadData(*op, &sink));
+    ASSERT_EQ(sink.stream(), data);
+}
+
+INSTANTIATE_TEST_SUITE_P(CowApi, CompressionTest, testing::Values("none", "gz", "brotli"));
+
+TEST_F(CowTest, GetSize) {
+    CowOptions options;
+    CowWriter writer(options);
+    if (ftruncate(cow_->fd, 0) < 0) {
+        perror("Fails to set temp file size");
+        FAIL();
+    }
+    ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+    std::string data = "This is some data, believe it";
+    data.resize(options.block_size, '\0');
+
+    ASSERT_TRUE(writer.AddCopy(10, 20));
+    ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
+    ASSERT_TRUE(writer.AddZeroBlocks(51, 2));
+    auto size_before = writer.GetCowSize();
+    ASSERT_TRUE(writer.Flush());
+    auto size_after = writer.GetCowSize();
+    ASSERT_EQ(size_before, size_after);
+    struct stat buf;
+
+    if (fstat(cow_->fd, &buf) < 0) {
+        perror("Fails to determine size of cow image written");
+        FAIL();
+    }
+    ASSERT_EQ(buf.st_size, writer.GetCowSize());
+}
+
+TEST_F(CowTest, Append) {
+    CowOptions options;
+    auto writer = std::make_unique<CowWriter>(options);
+    ASSERT_TRUE(writer->Initialize(cow_->fd));
+
+    std::string data = "This is some data, believe it";
+    data.resize(options.block_size, '\0');
+    ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
+    ASSERT_TRUE(writer->Flush());
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    writer = std::make_unique<CowWriter>(options);
+    ASSERT_TRUE(writer->Initialize(cow_->fd, CowWriter::OpenMode::APPEND));
+
+    std::string data2 = "More data!";
+    data2.resize(options.block_size, '\0');
+    ASSERT_TRUE(writer->AddRawBlocks(51, data2.data(), data2.size()));
+    ASSERT_TRUE(writer->Flush());
+
+    ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+    struct stat buf;
+    ASSERT_EQ(fstat(cow_->fd, &buf), 0);
+    ASSERT_EQ(buf.st_size, writer->GetCowSize());
+
+    // Read back both operations.
+    CowReader reader;
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+
+    StringSink sink;
+
+    auto iter = reader.GetOpIter();
+    ASSERT_NE(iter, nullptr);
+
+    ASSERT_FALSE(iter->Done());
+    auto op = &iter->Get();
+    ASSERT_EQ(op->type, kCowReplaceOp);
+    ASSERT_TRUE(reader.ReadData(*op, &sink));
+    ASSERT_EQ(sink.stream(), data);
+
+    iter->Next();
+    sink.Reset();
+
+    ASSERT_FALSE(iter->Done());
+    op = &iter->Get();
+    ASSERT_EQ(op->type, kCowReplaceOp);
+    ASSERT_TRUE(reader.ReadData(*op, &sink));
+    ASSERT_EQ(sink.stream(), data2);
+
+    iter->Next();
+    ASSERT_TRUE(iter->Done());
+}
+
+}  // namespace snapshot
+}  // namespace android
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/fs_mgr/libsnapshot/cow_decompress.cpp b/fs_mgr/libsnapshot/cow_decompress.cpp
new file mode 100644
index 0000000..faceafe
--- /dev/null
+++ b/fs_mgr/libsnapshot/cow_decompress.cpp
@@ -0,0 +1,264 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 "cow_decompress.h"
+
+#include <utility>
+
+#include <android-base/logging.h>
+#include <brotli/decode.h>
+#include <zlib.h>
+
+namespace android {
+namespace snapshot {
+
+class NoDecompressor final : public IDecompressor {
+  public:
+    bool Decompress(size_t) override;
+};
+
+bool NoDecompressor::Decompress(size_t) {
+    size_t stream_remaining = stream_->Size();
+    while (stream_remaining) {
+        size_t buffer_size = stream_remaining;
+        uint8_t* buffer = reinterpret_cast<uint8_t*>(sink_->GetBuffer(buffer_size, &buffer_size));
+        if (!buffer) {
+            LOG(ERROR) << "Could not acquire buffer from sink";
+            return false;
+        }
+
+        // Read until we can fill the buffer.
+        uint8_t* buffer_pos = buffer;
+        size_t bytes_to_read = std::min(buffer_size, stream_remaining);
+        while (bytes_to_read) {
+            size_t read;
+            if (!stream_->Read(buffer_pos, bytes_to_read, &read)) {
+                return false;
+            }
+            if (!read) {
+                LOG(ERROR) << "Stream ended prematurely";
+                return false;
+            }
+            if (!sink_->ReturnData(buffer_pos, read)) {
+                LOG(ERROR) << "Could not return buffer to sink";
+                return false;
+            }
+            buffer_pos += read;
+            bytes_to_read -= read;
+            stream_remaining -= read;
+        }
+    }
+    return true;
+}
+
+std::unique_ptr<IDecompressor> IDecompressor::Uncompressed() {
+    return std::unique_ptr<IDecompressor>(new NoDecompressor());
+}
+
+// Read chunks of the COW and incrementally stream them to the decoder.
+class StreamDecompressor : public IDecompressor {
+  public:
+    bool Decompress(size_t output_bytes) override;
+
+    virtual bool Init() = 0;
+    virtual bool DecompressInput(const uint8_t* data, size_t length) = 0;
+    virtual bool Done() = 0;
+
+  protected:
+    bool GetFreshBuffer();
+
+    size_t output_bytes_;
+    size_t stream_remaining_;
+    uint8_t* output_buffer_ = nullptr;
+    size_t output_buffer_remaining_ = 0;
+};
+
+static constexpr size_t kChunkSize = 4096;
+
+bool StreamDecompressor::Decompress(size_t output_bytes) {
+    if (!Init()) {
+        return false;
+    }
+
+    stream_remaining_ = stream_->Size();
+    output_bytes_ = output_bytes;
+
+    uint8_t chunk[kChunkSize];
+    while (stream_remaining_) {
+        size_t read = std::min(stream_remaining_, sizeof(chunk));
+        if (!stream_->Read(chunk, read, &read)) {
+            return false;
+        }
+        if (!read) {
+            LOG(ERROR) << "Stream ended prematurely";
+            return false;
+        }
+        if (!DecompressInput(chunk, read)) {
+            return false;
+        }
+
+        stream_remaining_ -= read;
+
+        if (stream_remaining_ && Done()) {
+            LOG(ERROR) << "Decompressor terminated early";
+            return false;
+        }
+    }
+    if (!Done()) {
+        LOG(ERROR) << "Decompressor expected more bytes";
+        return false;
+    }
+    return true;
+}
+
+bool StreamDecompressor::GetFreshBuffer() {
+    size_t request_size = std::min(output_bytes_, kChunkSize);
+    output_buffer_ =
+            reinterpret_cast<uint8_t*>(sink_->GetBuffer(request_size, &output_buffer_remaining_));
+    if (!output_buffer_) {
+        LOG(ERROR) << "Could not acquire buffer from sink";
+        return false;
+    }
+    return true;
+}
+
+class GzDecompressor final : public StreamDecompressor {
+  public:
+    ~GzDecompressor();
+
+    bool Init() override;
+    bool DecompressInput(const uint8_t* data, size_t length) override;
+    bool Done() override { return ended_; }
+
+  private:
+    z_stream z_ = {};
+    bool ended_ = false;
+};
+
+bool GzDecompressor::Init() {
+    if (int rv = inflateInit(&z_); rv != Z_OK) {
+        LOG(ERROR) << "inflateInit returned error code " << rv;
+        return false;
+    }
+    return true;
+}
+
+GzDecompressor::~GzDecompressor() {
+    inflateEnd(&z_);
+}
+
+bool GzDecompressor::DecompressInput(const uint8_t* data, size_t length) {
+    z_.next_in = reinterpret_cast<Bytef*>(const_cast<uint8_t*>(data));
+    z_.avail_in = length;
+
+    while (z_.avail_in) {
+        // If no more output buffer, grab a new buffer.
+        if (z_.avail_out == 0) {
+            if (!GetFreshBuffer()) {
+                return false;
+            }
+            z_.next_out = reinterpret_cast<Bytef*>(output_buffer_);
+            z_.avail_out = output_buffer_remaining_;
+        }
+
+        // Remember the position of the output buffer so we can call ReturnData.
+        auto avail_out = z_.avail_out;
+
+        // Decompress.
+        int rv = inflate(&z_, Z_NO_FLUSH);
+        if (rv != Z_OK && rv != Z_STREAM_END) {
+            LOG(ERROR) << "inflate returned error code " << rv;
+            return false;
+        }
+
+        size_t returned = avail_out - z_.avail_out;
+        if (!sink_->ReturnData(output_buffer_, returned)) {
+            LOG(ERROR) << "Could not return buffer to sink";
+            return false;
+        }
+        output_buffer_ += returned;
+        output_buffer_remaining_ -= returned;
+
+        if (rv == Z_STREAM_END) {
+            if (z_.avail_in) {
+                LOG(ERROR) << "Gz stream ended prematurely";
+                return false;
+            }
+            ended_ = true;
+            return true;
+        }
+    }
+    return true;
+}
+
+std::unique_ptr<IDecompressor> IDecompressor::Gz() {
+    return std::unique_ptr<IDecompressor>(new GzDecompressor());
+}
+
+class BrotliDecompressor final : public StreamDecompressor {
+  public:
+    ~BrotliDecompressor();
+
+    bool Init() override;
+    bool DecompressInput(const uint8_t* data, size_t length) override;
+    bool Done() override { return BrotliDecoderIsFinished(decoder_); }
+
+  private:
+    BrotliDecoderState* decoder_ = nullptr;
+};
+
+bool BrotliDecompressor::Init() {
+    decoder_ = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
+    return true;
+}
+
+BrotliDecompressor::~BrotliDecompressor() {
+    if (decoder_) {
+        BrotliDecoderDestroyInstance(decoder_);
+    }
+}
+
+bool BrotliDecompressor::DecompressInput(const uint8_t* data, size_t length) {
+    size_t available_in = length;
+    const uint8_t* next_in = data;
+
+    bool needs_more_output = false;
+    while (available_in || needs_more_output) {
+        if (!output_buffer_remaining_ && !GetFreshBuffer()) {
+            return false;
+        }
+
+        auto output_buffer = output_buffer_;
+        auto r = BrotliDecoderDecompressStream(decoder_, &available_in, &next_in,
+                                               &output_buffer_remaining_, &output_buffer_, nullptr);
+        if (r == BROTLI_DECODER_RESULT_ERROR) {
+            LOG(ERROR) << "brotli decode failed";
+            return false;
+        }
+        if (!sink_->ReturnData(output_buffer, output_buffer_ - output_buffer)) {
+            return false;
+        }
+        needs_more_output = (r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
+    }
+    return true;
+}
+
+std::unique_ptr<IDecompressor> IDecompressor::Brotli() {
+    return std::unique_ptr<IDecompressor>(new BrotliDecompressor());
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/cow_decompress.h b/fs_mgr/libsnapshot/cow_decompress.h
new file mode 100644
index 0000000..f485256
--- /dev/null
+++ b/fs_mgr/libsnapshot/cow_decompress.h
@@ -0,0 +1,57 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <libsnapshot/cow_reader.h>
+
+namespace android {
+namespace snapshot {
+
+class IByteStream {
+  public:
+    virtual ~IByteStream() {}
+
+    // Read up to |length| bytes, storing the number of bytes read in the out-
+    // parameter. If the end of the stream is reached, 0 is returned.
+    virtual bool Read(void* buffer, size_t length, size_t* read) = 0;
+
+    // Size of the stream.
+    virtual size_t Size() const = 0;
+};
+
+class IDecompressor {
+  public:
+    virtual ~IDecompressor() {}
+
+    // Factory methods for decompression methods.
+    static std::unique_ptr<IDecompressor> Uncompressed();
+    static std::unique_ptr<IDecompressor> Gz();
+    static std::unique_ptr<IDecompressor> Brotli();
+
+    // |output_bytes| is the expected total number of bytes to sink.
+    virtual bool Decompress(size_t output_bytes) = 0;
+
+    void set_stream(IByteStream* stream) { stream_ = stream; }
+    void set_sink(IByteSink* sink) { sink_ = sink; }
+
+  protected:
+    IByteStream* stream_ = nullptr;
+    IByteSink* sink_ = nullptr;
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp
new file mode 100644
index 0000000..60093ab
--- /dev/null
+++ b/fs_mgr/libsnapshot/cow_reader.cpp
@@ -0,0 +1,256 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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/types.h>
+#include <unistd.h>
+
+#include <limits>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <libsnapshot/cow_reader.h>
+#include <zlib.h>
+#include "cow_decompress.h"
+
+namespace android {
+namespace snapshot {
+
+CowReader::CowReader() : fd_(-1), header_(), fd_size_(0) {}
+
+static void SHA256(const void*, size_t, uint8_t[]) {
+#if 0
+    SHA256_CTX c;
+    SHA256_Init(&c);
+    SHA256_Update(&c, data, length);
+    SHA256_Final(out, &c);
+#endif
+}
+
+bool CowReader::Parse(android::base::unique_fd&& fd) {
+    owned_fd_ = std::move(fd);
+    return Parse(android::base::borrowed_fd{owned_fd_});
+}
+
+bool CowReader::Parse(android::base::borrowed_fd fd) {
+    fd_ = fd;
+
+    auto pos = lseek(fd_.get(), 0, SEEK_END);
+    if (pos < 0) {
+        PLOG(ERROR) << "lseek end failed";
+        return false;
+    }
+    fd_size_ = pos;
+
+    if (lseek(fd_.get(), 0, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek header failed";
+        return false;
+    }
+    if (!android::base::ReadFully(fd_, &header_, sizeof(header_))) {
+        PLOG(ERROR) << "read header failed";
+        return false;
+    }
+
+    // Validity check the ops range.
+    if (header_.ops_offset >= fd_size_) {
+        LOG(ERROR) << "ops offset " << header_.ops_offset << " larger than fd size " << fd_size_;
+        return false;
+    }
+    if (fd_size_ - header_.ops_offset < header_.ops_size) {
+        LOG(ERROR) << "ops size " << header_.ops_size << " is too large";
+        return false;
+    }
+
+    if (header_.magic != kCowMagicNumber) {
+        LOG(ERROR) << "Header Magic corrupted. Magic: " << header_.magic
+                   << "Expected: " << kCowMagicNumber;
+        return false;
+    }
+    if (header_.header_size != sizeof(CowHeader)) {
+        LOG(ERROR) << "Header size unknown, read " << header_.header_size << ", expected "
+                   << sizeof(CowHeader);
+        return false;
+    }
+
+    if ((header_.major_version != kCowVersionMajor) ||
+        (header_.minor_version != kCowVersionMinor)) {
+        LOG(ERROR) << "Header version mismatch";
+        LOG(ERROR) << "Major version: " << header_.major_version
+                   << "Expected: " << kCowVersionMajor;
+        LOG(ERROR) << "Minor version: " << header_.minor_version
+                   << "Expected: " << kCowVersionMinor;
+        return false;
+    }
+
+    uint8_t header_csum[32];
+    {
+        CowHeader tmp = header_;
+        memset(&tmp.header_checksum, 0, sizeof(tmp.header_checksum));
+        memset(header_csum, 0, sizeof(uint8_t) * 32);
+
+        SHA256(&tmp, sizeof(tmp), header_csum);
+    }
+    if (memcmp(header_csum, header_.header_checksum, sizeof(header_csum)) != 0) {
+        LOG(ERROR) << "header checksum is invalid";
+        return false;
+    }
+
+    return true;
+}
+
+bool CowReader::GetHeader(CowHeader* header) {
+    *header = header_;
+    return true;
+}
+
+class CowOpIter final : public ICowOpIter {
+  public:
+    CowOpIter(std::unique_ptr<uint8_t[]>&& ops, size_t len);
+
+    bool Done() override;
+    const CowOperation& Get() override;
+    void Next() override;
+
+  private:
+    bool HasNext();
+
+    std::unique_ptr<uint8_t[]> ops_;
+    const uint8_t* pos_;
+    const uint8_t* end_;
+    bool done_;
+};
+
+CowOpIter::CowOpIter(std::unique_ptr<uint8_t[]>&& ops, size_t len)
+    : ops_(std::move(ops)), pos_(ops_.get()), end_(pos_ + len), done_(!HasNext()) {}
+
+bool CowOpIter::Done() {
+    return done_;
+}
+
+bool CowOpIter::HasNext() {
+    return pos_ < end_ && size_t(end_ - pos_) >= sizeof(CowOperation);
+}
+
+void CowOpIter::Next() {
+    CHECK(!Done());
+
+    pos_ += sizeof(CowOperation);
+    if (!HasNext()) done_ = true;
+}
+
+const CowOperation& CowOpIter::Get() {
+    CHECK(!Done());
+    CHECK(HasNext());
+    return *reinterpret_cast<const CowOperation*>(pos_);
+}
+
+std::unique_ptr<ICowOpIter> CowReader::GetOpIter() {
+    if (lseek(fd_.get(), header_.ops_offset, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek ops failed";
+        return nullptr;
+    }
+    auto ops_buffer = std::make_unique<uint8_t[]>(header_.ops_size);
+    if (!android::base::ReadFully(fd_, ops_buffer.get(), header_.ops_size)) {
+        PLOG(ERROR) << "read ops failed";
+        return nullptr;
+    }
+
+    uint8_t csum[32];
+    memset(csum, 0, sizeof(uint8_t) * 32);
+
+    SHA256(ops_buffer.get(), header_.ops_size, csum);
+    if (memcmp(csum, header_.ops_checksum, sizeof(csum)) != 0) {
+        LOG(ERROR) << "ops checksum does not match";
+        return nullptr;
+    }
+
+    return std::make_unique<CowOpIter>(std::move(ops_buffer), header_.ops_size);
+}
+
+bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read) {
+    // Validate the offset, taking care to acknowledge possible overflow of offset+len.
+    if (offset < sizeof(header_) || offset >= header_.ops_offset || len >= fd_size_ ||
+        offset + len > header_.ops_offset) {
+        LOG(ERROR) << "invalid data offset: " << offset << ", " << len << " bytes";
+        return false;
+    }
+    if (lseek(fd_.get(), offset, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek to read raw bytes failed";
+        return false;
+    }
+    ssize_t rv = TEMP_FAILURE_RETRY(::read(fd_.get(), buffer, len));
+    if (rv < 0) {
+        PLOG(ERROR) << "read failed";
+        return false;
+    }
+    *read = rv;
+    return true;
+}
+
+class CowDataStream final : public IByteStream {
+  public:
+    CowDataStream(CowReader* reader, uint64_t offset, size_t data_length)
+        : reader_(reader), offset_(offset), data_length_(data_length) {
+        remaining_ = data_length_;
+    }
+
+    bool Read(void* buffer, size_t length, size_t* read) override {
+        size_t to_read = std::min(length, remaining_);
+        if (!to_read) {
+            *read = 0;
+            return true;
+        }
+        if (!reader_->GetRawBytes(offset_, buffer, to_read, read)) {
+            return false;
+        }
+        offset_ += *read;
+        remaining_ -= *read;
+        return true;
+    }
+
+    size_t Size() const override { return data_length_; }
+
+  private:
+    CowReader* reader_;
+    uint64_t offset_;
+    size_t data_length_;
+    size_t remaining_;
+};
+
+bool CowReader::ReadData(const CowOperation& op, IByteSink* sink) {
+    std::unique_ptr<IDecompressor> decompressor;
+    switch (op.compression) {
+        case kCowCompressNone:
+            decompressor = IDecompressor::Uncompressed();
+            break;
+        case kCowCompressGz:
+            decompressor = IDecompressor::Gz();
+            break;
+        case kCowCompressBrotli:
+            decompressor = IDecompressor::Brotli();
+            break;
+        default:
+            LOG(ERROR) << "Unknown compression type: " << op.compression;
+            return false;
+    }
+
+    CowDataStream stream(this, op.source, op.data_length);
+    decompressor->set_stream(&stream);
+    decompressor->set_sink(sink);
+    return decompressor->Decompress(header_.block_size);
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
new file mode 100644
index 0000000..80acb4a
--- /dev/null
+++ b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
@@ -0,0 +1,351 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 <linux/fs.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <iostream>
+#include <memory>
+#include <string_view>
+
+#include <android-base/file.h>
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+#include <libsnapshot/cow_writer.h>
+#include <storage_literals/storage_literals.h>
+
+namespace android {
+namespace snapshot {
+
+using namespace android::storage_literals;
+using android::base::unique_fd;
+
+class SnapuserdTest : public ::testing::Test {
+  protected:
+    void SetUp() override {
+        cow_system_ = std::make_unique<TemporaryFile>();
+        ASSERT_GE(cow_system_->fd, 0) << strerror(errno);
+
+        cow_product_ = std::make_unique<TemporaryFile>();
+        ASSERT_GE(cow_product_->fd, 0) << strerror(errno);
+
+        size_ = 100_MiB;
+    }
+
+    void TearDown() override {
+        cow_system_ = nullptr;
+        cow_product_ = nullptr;
+    }
+
+    std::unique_ptr<TemporaryFile> cow_system_;
+    std::unique_ptr<TemporaryFile> cow_product_;
+
+    unique_fd sys_fd_;
+    unique_fd product_fd_;
+    size_t size_;
+
+    int system_blksize_;
+    int product_blksize_;
+    std::string system_device_name_;
+    std::string product_device_name_;
+
+    std::unique_ptr<uint8_t[]> random_buffer_1_;
+    std::unique_ptr<uint8_t[]> random_buffer_2_;
+    std::unique_ptr<uint8_t[]> zero_buffer_;
+    std::unique_ptr<uint8_t[]> system_buffer_;
+    std::unique_ptr<uint8_t[]> product_buffer_;
+
+    void Init();
+    void CreateCowDevice(std::unique_ptr<TemporaryFile>& cow);
+    void CreateSystemDmUser();
+    void CreateProductDmUser();
+    void StartSnapuserdDaemon();
+    void CreateSnapshotDevices();
+
+    void TestIO(unique_fd& snapshot_fd, std::unique_ptr<uint8_t[]>&& buf);
+};
+
+void SnapuserdTest::Init() {
+    unique_fd rnd_fd;
+    loff_t offset = 0;
+
+    rnd_fd.reset(open("/dev/random", O_RDONLY));
+    ASSERT_TRUE(rnd_fd > 0);
+
+    random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
+    random_buffer_2_ = std::make_unique<uint8_t[]>(size_);
+    system_buffer_ = std::make_unique<uint8_t[]>(size_);
+    product_buffer_ = std::make_unique<uint8_t[]>(size_);
+    zero_buffer_ = std::make_unique<uint8_t[]>(size_);
+
+    // Fill random data
+    for (size_t j = 0; j < (size_ / 1_MiB); j++) {
+        ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
+                  true);
+
+        ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_2_.get() + offset, 1_MiB, 0),
+                  true);
+
+        offset += 1_MiB;
+    }
+
+    sys_fd_.reset(open("/dev/block/mapper/system_a", O_RDONLY));
+    ASSERT_TRUE(sys_fd_ > 0);
+
+    product_fd_.reset(open("/dev/block/mapper/product_a", O_RDONLY));
+    ASSERT_TRUE(product_fd_ > 0);
+
+    // Read from system partition from offset 0 of size 100MB
+    ASSERT_EQ(ReadFullyAtOffset(sys_fd_, system_buffer_.get(), size_, 0), true);
+
+    // Read from system partition from offset 0 of size 100MB
+    ASSERT_EQ(ReadFullyAtOffset(product_fd_, product_buffer_.get(), size_, 0), true);
+}
+
+void SnapuserdTest::CreateCowDevice(std::unique_ptr<TemporaryFile>& cow) {
+    //================Create a COW file with the following operations===========
+    //
+    // Create COW file which is gz compressed
+    //
+    // 0-100 MB of replace operation with random data
+    // 100-200 MB of copy operation
+    // 200-300 MB of zero operation
+    // 300-400 MB of replace operation with random data
+
+    CowOptions options;
+    options.compression = "gz";
+    CowWriter writer(options);
+
+    ASSERT_TRUE(writer.Initialize(cow->fd));
+
+    // Write 100MB random data to COW file which is gz compressed from block 0
+    ASSERT_TRUE(writer.AddRawBlocks(0, random_buffer_1_.get(), size_));
+
+    size_t num_blocks = size_ / options.block_size;
+    size_t blk_start_copy = num_blocks;
+    size_t blk_end_copy = blk_start_copy + num_blocks;
+    size_t source_blk = 0;
+
+    // Copy blocks - source_blk starts from 0 as snapuserd
+    // has to read from block 0 in system_a partition
+    //
+    // This initializes copy operation from block 0 of size 100 MB from
+    // /dev/block/mapper/system_a or product_a
+    for (size_t i = blk_start_copy; i < blk_end_copy; i++) {
+        ASSERT_TRUE(writer.AddCopy(i, source_blk));
+        source_blk += 1;
+    }
+
+    size_t blk_zero_copy_start = blk_end_copy;
+    size_t blk_zero_copy_end = blk_zero_copy_start + num_blocks;
+
+    // 100 MB filled with zeroes
+    ASSERT_TRUE(writer.AddZeroBlocks(blk_zero_copy_start, num_blocks));
+
+    // Final 100MB filled with random data which is gz compressed
+    size_t blk_random2_replace_start = blk_zero_copy_end;
+
+    ASSERT_TRUE(writer.AddRawBlocks(blk_random2_replace_start, random_buffer_2_.get(), size_));
+
+    // Flush operations
+    ASSERT_TRUE(writer.Flush());
+
+    ASSERT_EQ(lseek(cow->fd, 0, SEEK_SET), 0);
+}
+
+void SnapuserdTest::CreateSystemDmUser() {
+    unique_fd system_a_fd;
+    std::string cmd;
+
+    // Create a COW device. Number of sectors is chosen random which can
+    // hold at least 400MB of data
+
+    system_a_fd.reset(open("/dev/block/mapper/system_a", O_RDONLY));
+    ASSERT_TRUE(system_a_fd > 0);
+
+    int err = ioctl(system_a_fd.get(), BLKGETSIZE, &system_blksize_);
+    ASSERT_GE(err, 0);
+
+    std::string str(cow_system_->path);
+    std::size_t found = str.find_last_of("/\\");
+    ASSERT_NE(found, std::string::npos);
+    system_device_name_ = str.substr(found + 1);
+    cmd = "dmctl create " + system_device_name_ + " user 0 " + std::to_string(system_blksize_);
+
+    system(cmd.c_str());
+}
+
+void SnapuserdTest::CreateProductDmUser() {
+    unique_fd product_a_fd;
+    std::string cmd;
+
+    // Create a COW device. Number of sectors is chosen random which can
+    // hold at least 400MB of data
+
+    product_a_fd.reset(open("/dev/block/mapper/product_a", O_RDONLY));
+    ASSERT_TRUE(product_a_fd > 0);
+
+    int err = ioctl(product_a_fd.get(), BLKGETSIZE, &product_blksize_);
+    ASSERT_GE(err, 0);
+
+    std::string str(cow_product_->path);
+    std::size_t found = str.find_last_of("/\\");
+    ASSERT_NE(found, std::string::npos);
+    product_device_name_ = str.substr(found + 1);
+    cmd = "dmctl create " + product_device_name_ + " user 0 " + std::to_string(product_blksize_);
+
+    system(cmd.c_str());
+}
+
+void SnapuserdTest::StartSnapuserdDaemon() {
+    // Start the snapuserd daemon
+    if (fork() == 0) {
+        const char* argv[] = {"/system/bin/snapuserd",       cow_system_->path,
+                              "/dev/block/mapper/system_a",  cow_product_->path,
+                              "/dev/block/mapper/product_a", nullptr};
+        if (execv(argv[0], const_cast<char**>(argv))) {
+            ASSERT_TRUE(0);
+        }
+    }
+}
+
+void SnapuserdTest::CreateSnapshotDevices() {
+    std::string cmd;
+
+    cmd = "dmctl create system-snapshot -ro snapshot 0 " + std::to_string(system_blksize_);
+    cmd += " /dev/block/mapper/system_a";
+    cmd += " /dev/block/mapper/" + system_device_name_;
+    cmd += " P 8";
+
+    system(cmd.c_str());
+
+    cmd.clear();
+
+    cmd = "dmctl create product-snapshot -ro snapshot 0 " + std::to_string(product_blksize_);
+    cmd += " /dev/block/mapper/product_a";
+    cmd += " /dev/block/mapper/" + product_device_name_;
+    cmd += " P 8";
+
+    system(cmd.c_str());
+}
+
+void SnapuserdTest::TestIO(unique_fd& snapshot_fd, std::unique_ptr<uint8_t[]>&& buf) {
+    loff_t offset = 0;
+    std::unique_ptr<uint8_t[]> buffer = std::move(buf);
+
+    std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(size_);
+
+    //================Start IO operation on dm-snapshot device=================
+    // This will test the following paths:
+    //
+    // 1: IO path for all three operations and interleaving of operations.
+    // 2: Merging of blocks in kernel during metadata read
+    // 3: Bulk IO issued by kernel duing merge operation
+
+    // Read from snapshot device of size 100MB from offset 0. This tests the
+    // 1st replace operation.
+    //
+    // IO path:
+    //
+    // dm-snap->dm-snap-persistent->dm-user->snapuserd->read_compressed_cow (replace
+    // op)->decompress_cow->return
+
+    ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
+
+    // Update the offset
+    offset += size_;
+
+    // Compare data with random_buffer_1_.
+    ASSERT_EQ(memcmp(snapuserd_buffer.get(), random_buffer_1_.get(), size_), 0);
+
+    // Clear the buffer
+    memset(snapuserd_buffer.get(), 0, size_);
+
+    // Read from snapshot device of size 100MB from offset 100MB. This tests the
+    // copy operation.
+    //
+    // IO path:
+    //
+    // dm-snap->dm-snap-persistent->dm-user->snapuserd->read_from_system_a_partition
+    // (copy op) -> return
+    ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
+
+    // Update the offset
+    offset += size_;
+
+    // Compare data with buffer.
+    ASSERT_EQ(memcmp(snapuserd_buffer.get(), buffer.get(), size_), 0);
+
+    // Read from snapshot device of size 100MB from offset 200MB. This tests the
+    // zero operation.
+    //
+    // IO path:
+    //
+    // dm-snap->dm-snap-persistent->dm-user->snapuserd->fill_memory_with_zero
+    // (zero op) -> return
+    ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
+
+    // Compare data with zero filled buffer
+    ASSERT_EQ(memcmp(snapuserd_buffer.get(), zero_buffer_.get(), size_), 0);
+
+    // Update the offset
+    offset += size_;
+
+    // Read from snapshot device of size 100MB from offset 300MB. This tests the
+    // final replace operation.
+    //
+    // IO path:
+    //
+    // dm-snap->dm-snap-persistent->dm-user->snapuserd->read_compressed_cow (replace
+    // op)->decompress_cow->return
+    ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
+
+    // Compare data with random_buffer_2_.
+    ASSERT_EQ(memcmp(snapuserd_buffer.get(), random_buffer_2_.get(), size_), 0);
+}
+
+TEST_F(SnapuserdTest, ReadWrite) {
+    unique_fd snapshot_fd;
+
+    Init();
+
+    CreateCowDevice(cow_system_);
+    CreateCowDevice(cow_product_);
+
+    CreateSystemDmUser();
+    CreateProductDmUser();
+
+    StartSnapuserdDaemon();
+
+    CreateSnapshotDevices();
+
+    snapshot_fd.reset(open("/dev/block/mapper/system-snapshot", O_RDONLY));
+    ASSERT_TRUE(snapshot_fd > 0);
+    TestIO(snapshot_fd, std::move(system_buffer_));
+
+    snapshot_fd.reset(open("/dev/block/mapper/product-snapshot", O_RDONLY));
+    ASSERT_TRUE(snapshot_fd > 0);
+    TestIO(snapshot_fd, std::move(product_buffer_));
+}
+
+}  // namespace snapshot
+}  // namespace android
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
new file mode 100644
index 0000000..f96f174
--- /dev/null
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -0,0 +1,358 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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/types.h>
+#include <unistd.h>
+
+#include <limits>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <brotli/encode.h>
+#include <libsnapshot/cow_reader.h>
+#include <libsnapshot/cow_writer.h>
+#include <zlib.h>
+
+namespace android {
+namespace snapshot {
+
+static_assert(sizeof(off_t) == sizeof(uint64_t));
+
+using android::base::borrowed_fd;
+using android::base::unique_fd;
+
+bool ICowWriter::AddCopy(uint64_t new_block, uint64_t old_block) {
+    if (!ValidateNewBlock(new_block)) {
+        return false;
+    }
+    return EmitCopy(new_block, old_block);
+}
+
+bool ICowWriter::AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
+    if (size % options_.block_size != 0) {
+        LOG(ERROR) << "AddRawBlocks: size " << size << " is not a multiple of "
+                   << options_.block_size;
+        return false;
+    }
+
+    uint64_t num_blocks = size / options_.block_size;
+    uint64_t last_block = new_block_start + num_blocks - 1;
+    if (!ValidateNewBlock(last_block)) {
+        return false;
+    }
+    return EmitRawBlocks(new_block_start, data, size);
+}
+
+bool ICowWriter::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
+    uint64_t last_block = new_block_start + num_blocks - 1;
+    if (!ValidateNewBlock(last_block)) {
+        return false;
+    }
+    return EmitZeroBlocks(new_block_start, num_blocks);
+}
+
+bool ICowWriter::ValidateNewBlock(uint64_t new_block) {
+    if (options_.max_blocks && new_block >= options_.max_blocks.value()) {
+        LOG(ERROR) << "New block " << new_block << " exceeds maximum block count "
+                   << options_.max_blocks.value();
+        return false;
+    }
+    return true;
+}
+
+CowWriter::CowWriter(const CowOptions& options) : ICowWriter(options), fd_(-1) {
+    SetupHeaders();
+}
+
+void CowWriter::SetupHeaders() {
+    header_ = {};
+    header_.magic = kCowMagicNumber;
+    header_.major_version = kCowVersionMajor;
+    header_.minor_version = kCowVersionMinor;
+    header_.header_size = sizeof(CowHeader);
+    header_.block_size = options_.block_size;
+}
+
+bool CowWriter::ParseOptions() {
+    if (options_.compression == "gz") {
+        compression_ = kCowCompressGz;
+    } else if (options_.compression == "brotli") {
+        compression_ = kCowCompressBrotli;
+    } else if (options_.compression == "none") {
+        compression_ = kCowCompressNone;
+    } else if (!options_.compression.empty()) {
+        LOG(ERROR) << "unrecognized compression: " << options_.compression;
+        return false;
+    }
+    return true;
+}
+
+bool CowWriter::Initialize(unique_fd&& fd, OpenMode mode) {
+    owned_fd_ = std::move(fd);
+    return Initialize(borrowed_fd{owned_fd_}, mode);
+}
+
+bool CowWriter::Initialize(borrowed_fd fd, OpenMode mode) {
+    fd_ = fd;
+
+    if (!ParseOptions()) {
+        return false;
+    }
+
+    switch (mode) {
+        case OpenMode::WRITE:
+            return OpenForWrite();
+        case OpenMode::APPEND:
+            return OpenForAppend();
+        default:
+            LOG(ERROR) << "Unknown open mode in CowWriter";
+            return false;
+    }
+}
+
+bool CowWriter::OpenForWrite() {
+    // This limitation is tied to the data field size in CowOperation.
+    if (header_.block_size > std::numeric_limits<uint16_t>::max()) {
+        LOG(ERROR) << "Block size is too large";
+        return false;
+    }
+
+    if (lseek(fd_.get(), 0, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek failed";
+        return false;
+    }
+
+    // Headers are not complete, but this ensures the file is at the right
+    // position.
+    if (!android::base::WriteFully(fd_, &header_, sizeof(header_))) {
+        PLOG(ERROR) << "write failed";
+        return false;
+    }
+
+    header_.ops_offset = header_.header_size;
+    return true;
+}
+
+bool CowWriter::OpenForAppend() {
+    auto reader = std::make_unique<CowReader>();
+    if (!reader->Parse(fd_) || !reader->GetHeader(&header_)) {
+        return false;
+    }
+    options_.block_size = header_.block_size;
+
+    // Reset this, since we're going to reimport all operations.
+    header_.num_ops = 0;
+
+    auto iter = reader->GetOpIter();
+    while (!iter->Done()) {
+        auto& op = iter->Get();
+        AddOperation(op);
+
+        iter->Next();
+    }
+
+    // Free reader so we own the descriptor position again.
+    reader = nullptr;
+
+    // Seek to the end of the data section.
+    if (lseek(fd_.get(), header_.ops_offset, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek failed";
+        return false;
+    }
+    return true;
+}
+
+bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
+    CowOperation op = {};
+    op.type = kCowCopyOp;
+    op.new_block = new_block;
+    op.source = old_block;
+    AddOperation(op);
+    return true;
+}
+
+bool CowWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
+    uint64_t pos;
+    if (!GetDataPos(&pos)) {
+        return false;
+    }
+
+    const uint8_t* iter = reinterpret_cast<const uint8_t*>(data);
+    for (size_t i = 0; i < size / header_.block_size; i++) {
+        CowOperation op = {};
+        op.type = kCowReplaceOp;
+        op.new_block = new_block_start + i;
+        op.source = pos;
+
+        if (compression_) {
+            auto data = Compress(iter, header_.block_size);
+            if (data.empty()) {
+                PLOG(ERROR) << "AddRawBlocks: compression failed";
+                return false;
+            }
+            if (data.size() > std::numeric_limits<uint16_t>::max()) {
+                LOG(ERROR) << "Compressed block is too large: " << data.size() << " bytes";
+                return false;
+            }
+            if (!WriteRawData(data.data(), data.size())) {
+                PLOG(ERROR) << "AddRawBlocks: write failed";
+                return false;
+            }
+            op.compression = compression_;
+            op.data_length = static_cast<uint16_t>(data.size());
+            pos += data.size();
+        } else {
+            op.data_length = static_cast<uint16_t>(header_.block_size);
+            pos += header_.block_size;
+        }
+
+        AddOperation(op);
+        iter += header_.block_size;
+    }
+
+    if (!compression_ && !WriteRawData(data, size)) {
+        PLOG(ERROR) << "AddRawBlocks: write failed";
+        return false;
+    }
+    return true;
+}
+
+bool CowWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
+    for (uint64_t i = 0; i < num_blocks; i++) {
+        CowOperation op = {};
+        op.type = kCowZeroOp;
+        op.new_block = new_block_start + i;
+        op.source = 0;
+        AddOperation(op);
+    }
+    return true;
+}
+
+std::basic_string<uint8_t> CowWriter::Compress(const void* data, size_t length) {
+    switch (compression_) {
+        case kCowCompressGz: {
+            auto bound = compressBound(length);
+            auto buffer = std::make_unique<uint8_t[]>(bound);
+
+            uLongf dest_len = bound;
+            auto rv = compress2(buffer.get(), &dest_len, reinterpret_cast<const Bytef*>(data),
+                                length, Z_BEST_COMPRESSION);
+            if (rv != Z_OK) {
+                LOG(ERROR) << "compress2 returned: " << rv;
+                return {};
+            }
+            return std::basic_string<uint8_t>(buffer.get(), dest_len);
+        }
+        case kCowCompressBrotli: {
+            auto bound = BrotliEncoderMaxCompressedSize(length);
+            if (!bound) {
+                LOG(ERROR) << "BrotliEncoderMaxCompressedSize returned 0";
+                return {};
+            }
+            auto buffer = std::make_unique<uint8_t[]>(bound);
+
+            size_t encoded_size = bound;
+            auto rv = BrotliEncoderCompress(
+                    BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, length,
+                    reinterpret_cast<const uint8_t*>(data), &encoded_size, buffer.get());
+            if (!rv) {
+                LOG(ERROR) << "BrotliEncoderCompress failed";
+                return {};
+            }
+            return std::basic_string<uint8_t>(buffer.get(), encoded_size);
+        }
+        default:
+            LOG(ERROR) << "unhandled compression type: " << compression_;
+            break;
+    }
+    return {};
+}
+
+// TODO: Fix compilation issues when linking libcrypto library
+// when snapuserd is compiled as part of ramdisk.
+static void SHA256(const void*, size_t, uint8_t[]) {
+#if 0
+    SHA256_CTX c;
+    SHA256_Init(&c);
+    SHA256_Update(&c, data, length);
+    SHA256_Final(out, &c);
+#endif
+}
+
+bool CowWriter::Flush() {
+    header_.ops_size = ops_.size();
+
+    memset(header_.ops_checksum, 0, sizeof(uint8_t) * 32);
+    memset(header_.header_checksum, 0, sizeof(uint8_t) * 32);
+
+    SHA256(ops_.data(), ops_.size(), header_.ops_checksum);
+    SHA256(&header_, sizeof(header_), header_.header_checksum);
+
+    if (lseek(fd_.get(), 0, SEEK_SET)) {
+        PLOG(ERROR) << "lseek failed";
+        return false;
+    }
+    if (!android::base::WriteFully(fd_, &header_, sizeof(header_))) {
+        PLOG(ERROR) << "write header failed";
+        return false;
+    }
+    if (lseek(fd_.get(), header_.ops_offset, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek ops failed";
+        return false;
+    }
+    if (!WriteFully(fd_, ops_.data(), ops_.size())) {
+        PLOG(ERROR) << "write ops failed";
+        return false;
+    }
+
+    // Re-position for any subsequent writes.
+    if (lseek(fd_.get(), header_.ops_offset, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek ops failed";
+        return false;
+    }
+    return true;
+}
+
+uint64_t CowWriter::GetCowSize() {
+    return header_.ops_offset + header_.num_ops * sizeof(CowOperation);
+}
+
+bool CowWriter::GetDataPos(uint64_t* pos) {
+    off_t offs = lseek(fd_.get(), 0, SEEK_CUR);
+    if (offs < 0) {
+        PLOG(ERROR) << "lseek failed";
+        return false;
+    }
+    *pos = offs;
+    return true;
+}
+
+void CowWriter::AddOperation(const CowOperation& op) {
+    header_.num_ops++;
+    ops_.insert(ops_.size(), reinterpret_cast<const uint8_t*>(&op), sizeof(op));
+}
+
+bool CowWriter::WriteRawData(const void* data, size_t size) {
+    if (!android::base::WriteFully(fd_, data, size)) {
+        return false;
+    }
+    header_.ops_offset += size;
+    return true;
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/estimate_cow_from_nonab_ota.cpp b/fs_mgr/libsnapshot/estimate_cow_from_nonab_ota.cpp
new file mode 100644
index 0000000..2a0136b
--- /dev/null
+++ b/fs_mgr/libsnapshot/estimate_cow_from_nonab_ota.cpp
@@ -0,0 +1,432 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <gflags/gflags.h>
+#include <libsnapshot/cow_writer.h>
+#include <openssl/sha.h>
+#include <sparse/sparse.h>
+#include <ziparchive/zip_archive.h>
+
+DEFINE_string(source_tf, "", "Source target files (dir or zip file)");
+DEFINE_string(ota_tf, "", "Target files of the build for an OTA");
+DEFINE_string(compression, "gz", "Compression (options: none, gz, brotli)");
+
+namespace android {
+namespace snapshot {
+
+using android::base::borrowed_fd;
+using android::base::unique_fd;
+
+static constexpr size_t kBlockSize = 4096;
+
+void MyLogger(android::base::LogId, android::base::LogSeverity severity, const char*, const char*,
+              unsigned int, const char* message) {
+    if (severity == android::base::ERROR) {
+        fprintf(stderr, "%s\n", message);
+    } else {
+        fprintf(stdout, "%s\n", message);
+    }
+}
+
+class TargetFilesPackage final {
+  public:
+    explicit TargetFilesPackage(const std::string& path);
+
+    bool Open();
+    bool HasFile(const std::string& path);
+    std::unordered_set<std::string> GetDynamicPartitionNames();
+    unique_fd OpenFile(const std::string& path);
+    unique_fd OpenImage(const std::string& path);
+
+  private:
+    std::string path_;
+    unique_fd fd_;
+    std::unique_ptr<ZipArchive, decltype(&CloseArchive)> zip_;
+};
+
+TargetFilesPackage::TargetFilesPackage(const std::string& path)
+    : path_(path), zip_(nullptr, &CloseArchive) {}
+
+bool TargetFilesPackage::Open() {
+    fd_.reset(open(path_.c_str(), O_RDONLY));
+    if (fd_ < 0) {
+        PLOG(ERROR) << "open failed: " << path_;
+        return false;
+    }
+
+    struct stat s;
+    if (fstat(fd_.get(), &s) < 0) {
+        PLOG(ERROR) << "fstat failed: " << path_;
+        return false;
+    }
+    if (S_ISDIR(s.st_mode)) {
+        return true;
+    }
+
+    // Otherwise, assume it's a zip file.
+    ZipArchiveHandle handle;
+    if (OpenArchiveFd(fd_.get(), path_.c_str(), &handle, false)) {
+        LOG(ERROR) << "Could not open " << path_ << " as a zip archive.";
+        return false;
+    }
+    zip_.reset(handle);
+    return true;
+}
+
+bool TargetFilesPackage::HasFile(const std::string& path) {
+    if (zip_) {
+        ZipEntry64 entry;
+        return !FindEntry(zip_.get(), path, &entry);
+    }
+
+    auto full_path = path_ + "/" + path;
+    return access(full_path.c_str(), F_OK) == 0;
+}
+
+unique_fd TargetFilesPackage::OpenFile(const std::string& path) {
+    if (!zip_) {
+        auto full_path = path_ + "/" + path;
+        unique_fd fd(open(full_path.c_str(), O_RDONLY));
+        if (fd < 0) {
+            PLOG(ERROR) << "open failed: " << full_path;
+            return {};
+        }
+        return fd;
+    }
+
+    ZipEntry64 entry;
+    if (FindEntry(zip_.get(), path, &entry)) {
+        LOG(ERROR) << path << " not found in archive: " << path_;
+        return {};
+    }
+
+    TemporaryFile temp;
+    if (temp.fd < 0) {
+        PLOG(ERROR) << "mkstemp failed";
+        return {};
+    }
+
+    LOG(INFO) << "Extracting " << path << " from " << path_ << " ...";
+    if (ExtractEntryToFile(zip_.get(), &entry, temp.fd)) {
+        LOG(ERROR) << "could not extract " << path << " from " << path_;
+        return {};
+    }
+    if (lseek(temp.fd, 0, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek failed";
+        return {};
+    }
+    return unique_fd{temp.release()};
+}
+
+unique_fd TargetFilesPackage::OpenImage(const std::string& path) {
+    auto fd = OpenFile(path);
+    if (fd < 0) {
+        return {};
+    }
+
+    LOG(INFO) << "Unsparsing " << path << " ...";
+    std::unique_ptr<struct sparse_file, decltype(&sparse_file_destroy)> s(
+            sparse_file_import(fd.get(), false, false), &sparse_file_destroy);
+    if (!s) {
+        return fd;
+    }
+
+    TemporaryFile temp;
+    if (temp.fd < 0) {
+        PLOG(ERROR) << "mkstemp failed";
+        return {};
+    }
+    if (sparse_file_write(s.get(), temp.fd, false, false, false) < 0) {
+        LOG(ERROR) << "sparse_file_write failed";
+        return {};
+    }
+    if (lseek(temp.fd, 0, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek failed";
+        return {};
+    }
+
+    fd.reset(temp.release());
+    return fd;
+}
+
+std::unordered_set<std::string> TargetFilesPackage::GetDynamicPartitionNames() {
+    auto fd = OpenFile("META/misc_info.txt");
+    if (fd < 0) {
+        return {};
+    }
+
+    std::string contents;
+    if (!android::base::ReadFdToString(fd, &contents)) {
+        PLOG(ERROR) << "read failed";
+        return {};
+    }
+
+    std::unordered_set<std::string> set;
+
+    auto lines = android::base::Split(contents, "\n");
+    for (const auto& line : lines) {
+        auto parts = android::base::Split(line, "=");
+        if (parts.size() == 2 && parts[0] == "dynamic_partition_list") {
+            auto partitions = android::base::Split(parts[1], " ");
+            for (const auto& name : partitions) {
+                if (!name.empty()) {
+                    set.emplace(name);
+                }
+            }
+            break;
+        }
+    }
+    return set;
+}
+
+class NonAbEstimator final {
+  public:
+    NonAbEstimator(const std::string& ota_tf_path, const std::string& source_tf_path)
+        : ota_tf_path_(ota_tf_path), source_tf_path_(source_tf_path) {}
+
+    bool Run();
+
+  private:
+    bool OpenPackages();
+    bool AnalyzePartition(const std::string& partition_name);
+    std::unordered_map<std::string, uint64_t> GetBlockMap(borrowed_fd fd);
+
+    std::string ota_tf_path_;
+    std::string source_tf_path_;
+    std::unique_ptr<TargetFilesPackage> ota_tf_;
+    std::unique_ptr<TargetFilesPackage> source_tf_;
+    uint64_t size_ = 0;
+};
+
+bool NonAbEstimator::Run() {
+    if (!OpenPackages()) {
+        return false;
+    }
+
+    auto partitions = ota_tf_->GetDynamicPartitionNames();
+    if (partitions.empty()) {
+        LOG(ERROR) << "No dynamic partitions found in META/misc_info.txt";
+        return false;
+    }
+    for (const auto& partition : partitions) {
+        if (!AnalyzePartition(partition)) {
+            return false;
+        }
+    }
+
+    int64_t size_in_mb = int64_t(double(size_) / 1024.0 / 1024.0);
+
+    std::cout << "Estimated COW size: " << size_ << " (" << size_in_mb << "MiB)\n";
+    return true;
+}
+
+bool NonAbEstimator::OpenPackages() {
+    ota_tf_ = std::make_unique<TargetFilesPackage>(ota_tf_path_);
+    if (!ota_tf_->Open()) {
+        return false;
+    }
+    if (!source_tf_path_.empty()) {
+        source_tf_ = std::make_unique<TargetFilesPackage>(source_tf_path_);
+        if (!source_tf_->Open()) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static std::string SHA256(const std::string& input) {
+    std::string hash(32, '\0');
+    SHA256_CTX c;
+    SHA256_Init(&c);
+    SHA256_Update(&c, input.data(), input.size());
+    SHA256_Final(reinterpret_cast<unsigned char*>(hash.data()), &c);
+    return hash;
+}
+
+bool NonAbEstimator::AnalyzePartition(const std::string& partition_name) {
+    auto path = "IMAGES/" + partition_name + ".img";
+    auto fd = ota_tf_->OpenImage(path);
+    if (fd < 0) {
+        return false;
+    }
+
+    unique_fd source_fd;
+    uint64_t source_size = 0;
+    std::unordered_map<std::string, uint64_t> source_blocks;
+    if (source_tf_) {
+        auto dap = source_tf_->GetDynamicPartitionNames();
+
+        source_fd = source_tf_->OpenImage(path);
+        if (source_fd >= 0) {
+            struct stat s;
+            if (fstat(source_fd.get(), &s)) {
+                PLOG(ERROR) << "fstat failed";
+                return false;
+            }
+            source_size = s.st_size;
+
+            std::cout << "Hashing blocks for " << partition_name << "...\n";
+            source_blocks = GetBlockMap(source_fd);
+            if (source_blocks.empty()) {
+                LOG(ERROR) << "Could not build a block map for source partition: "
+                           << partition_name;
+                return false;
+            }
+        } else {
+            if (dap.count(partition_name)) {
+                return false;
+            }
+            LOG(ERROR) << "Warning: " << partition_name
+                       << " has no incremental diff since it's not in the source image.";
+        }
+    }
+
+    TemporaryFile cow;
+    if (cow.fd < 0) {
+        PLOG(ERROR) << "mkstemp failed";
+        return false;
+    }
+
+    CowOptions options;
+    options.block_size = kBlockSize;
+    options.compression = FLAGS_compression;
+
+    auto writer = std::make_unique<CowWriter>(options);
+    if (!writer->Initialize(borrowed_fd{cow.fd})) {
+        LOG(ERROR) << "Could not initialize COW writer";
+        return false;
+    }
+
+    LOG(INFO) << "Analyzing " << partition_name << " ...";
+
+    std::string zeroes(kBlockSize, '\0');
+    std::string chunk(kBlockSize, '\0');
+    std::string src_chunk(kBlockSize, '\0');
+    uint64_t next_block_number = 0;
+    while (true) {
+        if (!android::base::ReadFully(fd, chunk.data(), chunk.size())) {
+            if (errno) {
+                PLOG(ERROR) << "read failed";
+                return false;
+            }
+            break;
+        }
+
+        uint64_t block_number = next_block_number++;
+        if (chunk == zeroes) {
+            if (!writer->AddZeroBlocks(block_number, 1)) {
+                LOG(ERROR) << "Could not add zero block";
+                return false;
+            }
+            continue;
+        }
+
+        uint64_t source_offset = block_number * kBlockSize;
+        if (source_fd >= 0 && source_offset <= source_size) {
+            off64_t offset = block_number * kBlockSize;
+            if (android::base::ReadFullyAtOffset(source_fd, src_chunk.data(), src_chunk.size(),
+                                                 offset)) {
+                if (chunk == src_chunk) {
+                    continue;
+                }
+            } else if (errno) {
+                PLOG(ERROR) << "pread failed";
+                return false;
+            }
+        }
+
+        auto hash = SHA256(chunk);
+        if (auto iter = source_blocks.find(hash); iter != source_blocks.end()) {
+            if (!writer->AddCopy(block_number, iter->second)) {
+                return false;
+            }
+            continue;
+        }
+
+        if (!writer->AddRawBlocks(block_number, chunk.data(), chunk.size())) {
+            return false;
+        }
+    }
+
+    if (!writer->Flush()) {
+        return false;
+    }
+
+    struct stat s;
+    if (fstat(cow.fd, &s) < 0) {
+        PLOG(ERROR) << "fstat failed";
+        return false;
+    }
+
+    size_ += s.st_size;
+    return true;
+}
+
+std::unordered_map<std::string, uint64_t> NonAbEstimator::GetBlockMap(borrowed_fd fd) {
+    std::string chunk(kBlockSize, '\0');
+
+    std::unordered_map<std::string, uint64_t> block_map;
+    uint64_t block_number = 0;
+    while (true) {
+        if (!android::base::ReadFully(fd, chunk.data(), chunk.size())) {
+            if (errno) {
+                PLOG(ERROR) << "read failed";
+                return {};
+            }
+            break;
+        }
+        auto hash = SHA256(chunk);
+        block_map[hash] = block_number;
+        block_number++;
+    }
+    return block_map;
+}
+
+}  // namespace snapshot
+}  // namespace android
+
+using namespace android::snapshot;
+
+int main(int argc, char** argv) {
+    android::base::InitLogging(argv, android::snapshot::MyLogger);
+    gflags::SetUsageMessage("Estimate VAB disk usage from Non A/B builds");
+    gflags::ParseCommandLineFlags(&argc, &argv, false);
+
+    if (FLAGS_ota_tf.empty()) {
+        std::cerr << "Must specify -ota_tf on the command-line." << std::endl;
+        return 1;
+    }
+
+    NonAbEstimator estimator(FLAGS_ota_tf, FLAGS_source_tf);
+    if (!estimator.Run()) {
+        return 1;
+    }
+    return 0;
+}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
new file mode 100644
index 0000000..4a6bd4e
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
@@ -0,0 +1,107 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <stdint.h>
+
+namespace android {
+namespace snapshot {
+
+static constexpr uint64_t kCowMagicNumber = 0x436f77634f572121ULL;
+static constexpr uint32_t kCowVersionMajor = 1;
+static constexpr uint32_t kCowVersionMinor = 0;
+
+// This header appears as the first sequence of bytes in the COW. All fields
+// in the layout are little-endian encoded. The on-disk layout is:
+//
+//      +-----------------------+
+//      |     Header (fixed)    |
+//      +-----------------------+
+//      |  Raw Data (variable)  |
+//      +-----------------------+
+//      | Operations (variable) |
+//      +-----------------------+
+//
+// The "raw data" occurs immediately after the header, and the operation
+// sequence occurs after the raw data. This ordering is intentional. While
+// streaming an OTA, we can immediately write compressed data, but store the
+// metadata in memory. At the end, we can simply append the metadata and flush
+// the file. There is no need to create separate files to store the metadata
+// and block data.
+struct CowHeader {
+    uint64_t magic;
+    uint16_t major_version;
+    uint16_t minor_version;
+
+    // Size of this struct.
+    uint16_t header_size;
+
+    // Offset to the location of the operation sequence, and size of the
+    // operation sequence buffer. |ops_offset| is also the end of the
+    // raw data region.
+    uint64_t ops_offset;
+    uint64_t ops_size;
+    uint64_t num_ops;
+
+    // The size of block operations, in bytes.
+    uint32_t block_size;
+
+    // SHA256 checksums of this header, with this field set to 0.
+    uint8_t header_checksum[32];
+
+    // SHA256 of the operation sequence.
+    uint8_t ops_checksum[32];
+} __attribute__((packed));
+
+// Cow operations are currently fixed-size entries, but this may change if
+// needed.
+struct CowOperation {
+    // The operation code (see the constants and structures below).
+    uint8_t type;
+
+    // If this operation reads from the data section of the COW, this contains
+    // the compression type of that data (see constants below).
+    uint8_t compression;
+
+    // If this operation reads from the data section of the COW, this contains
+    // the length.
+    uint16_t data_length;
+
+    // The block of data in the new image that this operation modifies.
+    uint64_t new_block;
+
+    // The value of |source| depends on the operation code.
+    //
+    // For copy operations, this is a block location in the source image.
+    //
+    // For replace operations, this is a byte offset within the COW's data
+    // section (eg, not landing within the header or metadata). It is an
+    // absolute position within the image.
+    //
+    // For zero operations (replace with all zeroes), this is unused and must
+    // be zero.
+    uint64_t source;
+} __attribute__((packed));
+
+static constexpr uint8_t kCowCopyOp = 1;
+static constexpr uint8_t kCowReplaceOp = 2;
+static constexpr uint8_t kCowZeroOp = 3;
+
+static constexpr uint8_t kCowCompressNone = 0;
+static constexpr uint8_t kCowCompressGz = 1;
+static constexpr uint8_t kCowCompressBrotli = 2;
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
new file mode 100644
index 0000000..3998776
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -0,0 +1,109 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <stdint.h>
+
+#include <functional>
+#include <memory>
+
+#include <android-base/unique_fd.h>
+#include <libsnapshot/cow_format.h>
+
+namespace android {
+namespace snapshot {
+
+class ICowOpIter;
+
+// A ByteSink object handles requests for a buffer of a specific size. It
+// always owns the underlying buffer. It's designed to minimize potential
+// copying as we parse or decompress the COW.
+class IByteSink {
+  public:
+    virtual ~IByteSink() {}
+
+    // Called when the reader has data. The size of the request is given. The
+    // sink must return a valid pointer (or null on failure), and return the
+    // maximum number of bytes that can be written to the returned buffer.
+    //
+    // The returned buffer is owned by IByteSink, but must remain valid until
+    // the ready operation has completed (or the entire buffer has been
+    // covered by calls to ReturnData).
+    //
+    // After calling GetBuffer(), all previous buffers returned are no longer
+    // valid.
+    virtual void* GetBuffer(size_t requested, size_t* actual) = 0;
+
+    // Called when a section returned by |GetBuffer| has been filled with data.
+    virtual bool ReturnData(void* buffer, size_t length) = 0;
+};
+
+// Interface for reading from a snapuserd COW.
+class ICowReader {
+  public:
+    virtual ~ICowReader() {}
+
+    // Return the file header.
+    virtual bool GetHeader(CowHeader* header) = 0;
+
+    // Return an iterator for retrieving CowOperation entries.
+    virtual std::unique_ptr<ICowOpIter> GetOpIter() = 0;
+
+    // Get decoded bytes from the data section, handling any decompression.
+    // All retrieved data is passed to the sink.
+    virtual bool ReadData(const CowOperation& op, IByteSink* sink) = 0;
+};
+
+// Iterate over a sequence of COW operations.
+class ICowOpIter {
+  public:
+    virtual ~ICowOpIter() {}
+
+    // True if there are more items to read, false otherwise.
+    virtual bool Done() = 0;
+
+    // Read the current operation.
+    virtual const CowOperation& Get() = 0;
+
+    // Advance to the next item.
+    virtual void Next() = 0;
+};
+
+class CowReader : public ICowReader {
+  public:
+    CowReader();
+
+    bool Parse(android::base::unique_fd&& fd);
+    bool Parse(android::base::borrowed_fd fd);
+
+    bool GetHeader(CowHeader* header) override;
+
+    // Create a CowOpIter object which contains header_.num_ops
+    // CowOperation objects. Get() returns a unique CowOperation object
+    // whose lifeteime depends on the CowOpIter object
+    std::unique_ptr<ICowOpIter> GetOpIter() override;
+    bool ReadData(const CowOperation& op, IByteSink* sink) override;
+
+    bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read);
+
+  private:
+    android::base::unique_fd owned_fd_;
+    android::base::borrowed_fd fd_;
+    CowHeader header_;
+    uint64_t fd_size_;
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
new file mode 100644
index 0000000..2bc0171
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -0,0 +1,118 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <stdint.h>
+
+#include <optional>
+#include <string>
+
+#include <android-base/unique_fd.h>
+#include <libsnapshot/cow_format.h>
+
+namespace android {
+namespace snapshot {
+
+struct CowOptions {
+    uint32_t block_size = 4096;
+    std::string compression;
+
+    // Maximum number of blocks that can be written.
+    std::optional<uint64_t> max_blocks;
+};
+
+// Interface for writing to a snapuserd COW. All operations are ordered; merges
+// will occur in the sequence they were added to the COW.
+class ICowWriter {
+  public:
+    explicit ICowWriter(const CowOptions& options) : options_(options) {}
+
+    virtual ~ICowWriter() {}
+
+    // Encode an operation that copies the contents of |old_block| to the
+    // location of |new_block|.
+    bool AddCopy(uint64_t new_block, uint64_t old_block);
+
+    // Encode a sequence of raw blocks. |size| must be a multiple of the block size.
+    bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size);
+
+    // Encode a sequence of zeroed blocks. |size| must be a multiple of the block size.
+    bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks);
+
+    // Flush all pending writes. This must be called before closing the writer
+    // to ensure that the correct headers and footers are written.
+    virtual bool Flush() = 0;
+
+    // Return number of bytes the cow image occupies on disk.
+    virtual uint64_t GetCowSize() = 0;
+
+    // Returns true if AddCopy() operations are supported.
+    virtual bool SupportsCopyOperation() const { return true; }
+
+    const CowOptions& options() { return options_; }
+
+  protected:
+    virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) = 0;
+    virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0;
+    virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) = 0;
+
+    bool ValidateNewBlock(uint64_t new_block);
+
+  protected:
+    CowOptions options_;
+};
+
+class CowWriter : public ICowWriter {
+  public:
+    enum class OpenMode { WRITE, APPEND };
+
+    explicit CowWriter(const CowOptions& options);
+
+    // Set up the writer.
+    bool Initialize(android::base::unique_fd&& fd, OpenMode mode = OpenMode::WRITE);
+    bool Initialize(android::base::borrowed_fd fd, OpenMode mode = OpenMode::WRITE);
+
+    bool Flush() override;
+
+    uint64_t GetCowSize() override;
+
+  protected:
+    virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
+    virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
+    virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
+
+  private:
+    void SetupHeaders();
+    bool ParseOptions();
+    bool OpenForWrite();
+    bool OpenForAppend();
+    bool GetDataPos(uint64_t* pos);
+    bool WriteRawData(const void* data, size_t size);
+    void AddOperation(const CowOperation& op);
+    std::basic_string<uint8_t> Compress(const void* data, size_t length);
+
+  private:
+    android::base::unique_fd owned_fd_;
+    android::base::borrowed_fd fd_;
+    CowHeader header_{};
+    int compression_ = 0;
+
+    // :TODO: this is not efficient, but stringstream ubsan aborts because some
+    // bytes overflow a signed char.
+    std::basic_string<uint8_t> ops_;
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
index 4457de3..13f19aa 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
@@ -15,6 +15,7 @@
 #pragma once
 
 #include <libsnapshot/snapshot.h>
+#include <payload_consumer/file_descriptor.h>
 
 #include <gmock/gmock.h>
 
@@ -37,6 +38,8 @@
                 (const android::fs_mgr::CreateLogicalPartitionParams& params,
                  std::string* snapshot_path),
                 (override));
+    MOCK_METHOD(std::unique_ptr<ISnapshotWriter>, OpenSnapshotWriter,
+                (const android::fs_mgr::CreateLogicalPartitionParams& params), (override));
     MOCK_METHOD(bool, UnmapUpdateSnapshot, (const std::string& target_partition_name), (override));
     MOCK_METHOD(bool, NeedSnapshotsInFirstStageMount, (), (override));
     MOCK_METHOD(bool, CreateLogicalAndSnapshotPartitions,
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 3c2c776..1bc972e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -36,6 +36,7 @@
 
 #include <libsnapshot/auto_device.h>
 #include <libsnapshot/return.h>
+#include <libsnapshot/snapshot_writer.h>
 
 #ifndef FRIEND_TEST
 #define FRIEND_TEST(test_set_name, individual_test) \
@@ -173,11 +174,21 @@
 
     // Map a snapshotted partition for OTA clients to write to. Write-protected regions are
     // determined previously in CreateSnapshots.
+    //
     // |snapshot_path| must not be nullptr.
+    //
+    // This method will return false if ro.virtual_ab.compression.enabled is true.
     virtual bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
                                    std::string* snapshot_path) = 0;
 
-    // Unmap a snapshot device that's previously mapped with MapUpdateSnapshot.
+    // Create an ISnapshotWriter to build a snapshot against a target partition. The partition name
+    // must be suffixed.
+    virtual std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
+            const android::fs_mgr::CreateLogicalPartitionParams& params) = 0;
+
+    // Unmap a snapshot device or CowWriter that was previously opened with MapUpdateSnapshot,
+    // OpenSnapshotWriter. All outstanding open descriptors, writers, or
+    // readers must be deleted before this is called.
     virtual bool UnmapUpdateSnapshot(const std::string& target_partition_name) = 0;
 
     // If this returns true, first-stage mount must call
@@ -288,6 +299,8 @@
     Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override;
     bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
                            std::string* snapshot_path) override;
+    std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
+            const android::fs_mgr::CreateLogicalPartitionParams& params) override;
     bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
     bool NeedSnapshotsInFirstStageMount() override;
     bool CreateLogicalAndSnapshotPartitions(
@@ -506,9 +519,39 @@
     std::string GetSnapshotDeviceName(const std::string& snapshot_name,
                                       const SnapshotStatus& status);
 
+    // Reason for calling MapPartitionWithSnapshot.
+    enum class SnapshotContext {
+        // For writing or verification (during update_engine).
+        Update,
+
+        // For mounting a full readable device.
+        Mount,
+    };
+
+    struct SnapshotPaths {
+        // Target/base device (eg system_b), always present.
+        std::string target_device;
+
+        // COW path (eg system_cow). Not present if no COW is needed.
+        std::string cow_device;
+
+        // dm-snapshot instance. Not present in Update mode for VABC.
+        std::string snapshot_device;
+    };
+
+    // Helpers for OpenSnapshotWriter.
+    std::unique_ptr<ISnapshotWriter> OpenCompressedSnapshotWriter(LockedFile* lock,
+                                                                  const std::string& partition_name,
+                                                                  const SnapshotStatus& status,
+                                                                  const SnapshotPaths& paths);
+    std::unique_ptr<ISnapshotWriter> OpenKernelSnapshotWriter(LockedFile* lock,
+                                                              const std::string& partition_name,
+                                                              const SnapshotStatus& status,
+                                                              const SnapshotPaths& paths);
+
     // Map the base device, COW devices, and snapshot device.
     bool MapPartitionWithSnapshot(LockedFile* lock, CreateLogicalPartitionParams params,
-                                  std::string* path);
+                                  SnapshotContext context, SnapshotPaths* paths);
 
     // Map the COW devices, including the partition in super and the images.
     // |params|:
@@ -553,9 +596,8 @@
     // This should only be called in recovery.
     bool UnmapAllPartitions();
 
-    // Sanity check no snapshot overflows. Note that this returns false negatives if the snapshot
-    // overflows, then is remapped and not written afterwards. Hence, the function may only serve
-    // as a sanity check.
+    // Check no snapshot overflows. Note that this returns false negatives if the snapshot
+    // overflows, then is remapped and not written afterwards.
     bool EnsureNoOverflowSnapshot(LockedFile* lock);
 
     enum class Slot { Unknown, Source, Target };
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
index 7a27fad..cda2bee 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
@@ -15,6 +15,7 @@
 #pragma once
 
 #include <libsnapshot/snapshot.h>
+#include <payload_consumer/file_descriptor.h>
 
 namespace android::snapshot {
 
@@ -35,6 +36,8 @@
             const chromeos_update_engine::DeltaArchiveManifest& manifest) override;
     bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
                            std::string* snapshot_path) override;
+    std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
+            const android::fs_mgr::CreateLogicalPartitionParams& params) override;
     bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
     bool NeedSnapshotsInFirstStageMount() override;
     bool CreateLogicalAndSnapshotPartitions(
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
new file mode 100644
index 0000000..bf57a00
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
@@ -0,0 +1,68 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+
+#include <libsnapshot/cow_writer.h>
+
+namespace chromeos_update_engine {
+class FileDescriptor;
+}  // namespace chromeos_update_engine
+
+namespace android {
+namespace snapshot {
+
+class ISnapshotWriter : public ICowWriter {
+  public:
+    using FileDescriptor = chromeos_update_engine::FileDescriptor;
+
+    explicit ISnapshotWriter(const CowOptions& options);
+
+    // Set the source device. This is used for AddCopy() operations, if the
+    // underlying writer needs the original bytes (for example if backed by
+    // dm-snapshot or if writing directly to an unsnapshotted region).
+    void SetSourceDevice(android::base::unique_fd&& source_fd);
+
+    virtual std::unique_ptr<FileDescriptor> OpenReader() = 0;
+
+  protected:
+    android::base::unique_fd source_fd_;
+};
+
+// Write directly to a dm-snapshot device.
+class OnlineKernelSnapshotWriter : public ISnapshotWriter {
+  public:
+    OnlineKernelSnapshotWriter(const CowOptions& options);
+
+    // Set the device used for all writes.
+    void SetSnapshotDevice(android::base::unique_fd&& snapshot_fd, uint64_t cow_size);
+
+    bool Flush() override;
+    uint64_t GetCowSize() override { return cow_size_; }
+    virtual std::unique_ptr<FileDescriptor> OpenReader() override;
+
+  protected:
+    bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
+    bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
+    bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
+
+  private:
+    android::base::unique_fd snapshot_fd_;
+    uint64_t cow_size_ = 0;
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
new file mode 100644
index 0000000..e757579
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
@@ -0,0 +1,99 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <stdint.h>
+
+namespace android {
+namespace snapshot {
+
+// Kernel COW header fields
+static constexpr uint32_t SNAP_MAGIC = 0x70416e53;
+
+static constexpr uint32_t SNAPSHOT_DISK_VERSION = 1;
+
+static constexpr uint32_t NUM_SNAPSHOT_HDR_CHUNKS = 1;
+
+static constexpr uint32_t SNAPSHOT_VALID = 1;
+
+/*
+ * The basic unit of block I/O is a sector. It is used in a number of contexts
+ * in Linux (blk, bio, genhd). The size of one sector is 512 = 2**9
+ * bytes. Variables of type sector_t represent an offset or size that is a
+ * multiple of 512 bytes. Hence these two constants.
+ */
+static constexpr uint32_t SECTOR_SHIFT = 9;
+
+typedef __u64 sector_t;
+typedef sector_t chunk_t;
+
+static constexpr uint32_t CHUNK_SIZE = 8;
+static constexpr uint32_t CHUNK_SHIFT = (__builtin_ffs(CHUNK_SIZE) - 1);
+
+static constexpr uint32_t BLOCK_SIZE = 4096;
+static constexpr uint32_t BLOCK_SHIFT = (__builtin_ffs(BLOCK_SIZE) - 1);
+
+// This structure represents the kernel COW header.
+// All the below fields should be in Little Endian format.
+struct disk_header {
+    uint32_t magic;
+
+    /*
+     * Is this snapshot valid.  There is no way of recovering
+     * an invalid snapshot.
+     */
+    uint32_t valid;
+
+    /*
+     * Simple, incrementing version. no backward
+     * compatibility.
+     */
+    uint32_t version;
+
+    /* In sectors */
+    uint32_t chunk_size;
+} __packed;
+
+// A disk exception is a mapping of old_chunk to new_chunk
+// old_chunk is the chunk ID of a dm-snapshot device.
+// new_chunk is the chunk ID of the COW device.
+struct disk_exception {
+    uint64_t old_chunk;
+    uint64_t new_chunk;
+} __packed;
+
+// Control structures to communicate with dm-user
+// It comprises of header and a payload
+struct dm_user_header {
+    __u64 seq;
+    __u64 type;
+    __u64 flags;
+    __u64 sector;
+    __u64 len;
+    __u64 io_in_progress;
+} __attribute__((packed));
+
+struct dm_user_payload {
+    __u8 buf[];
+};
+
+// Message comprising both header and payload
+struct dm_user_message {
+    struct dm_user_header header;
+    struct dm_user_payload payload;
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index 98bf56a..197aeaa 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -144,6 +144,7 @@
 // Expect space of |path| is multiple of 4K.
 bool WriteRandomData(const std::string& path, std::optional<size_t> expect_size = std::nullopt,
                      std::string* hash = nullptr);
+bool WriteRandomData(ICowWriter* writer, std::string* hash = nullptr);
 
 std::optional<std::string> GetHash(const std::string& path);
 
@@ -180,5 +181,22 @@
     uint64_t bsize_ = 0;
 };
 
+bool IsVirtualAbEnabled();
+
+#define SKIP_IF_NON_VIRTUAL_AB()                                                        \
+    do {                                                                                \
+        if (!IsVirtualAbEnabled()) GTEST_SKIP() << "Test for Virtual A/B devices only"; \
+    } while (0)
+
+#define RETURN_IF_NON_VIRTUAL_AB_MSG(msg) \
+    do {                                  \
+        if (!IsVirtualAbEnabled()) {      \
+            std::cerr << (msg);           \
+            return;                       \
+        }                                 \
+    } while (0)
+
+#define RETURN_IF_NON_VIRTUAL_AB() RETURN_IF_NON_VIRTUAL_AB_MSG("")
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp b/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp
new file mode 100644
index 0000000..f761077
--- /dev/null
+++ b/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp
@@ -0,0 +1,690 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 <arpa/inet.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <limits>
+#include <string>
+#include <unordered_set>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <bsdiff/bspatch.h>
+#include <bzlib.h>
+#include <gflags/gflags.h>
+#include <libsnapshot/cow_writer.h>
+#include <puffin/puffpatch.h>
+#include <sparse/sparse.h>
+#include <update_engine/update_metadata.pb.h>
+#include <xz.h>
+#include <ziparchive/zip_archive.h>
+
+namespace android {
+namespace snapshot {
+
+using android::base::borrowed_fd;
+using android::base::unique_fd;
+using chromeos_update_engine::DeltaArchiveManifest;
+using chromeos_update_engine::Extent;
+using chromeos_update_engine::InstallOperation;
+using chromeos_update_engine::PartitionUpdate;
+
+static constexpr uint64_t kBlockSize = 4096;
+
+DEFINE_string(source_tf, "", "Source target files (dir or zip file) for incremental payloads");
+DEFINE_string(compression, "gz", "Compression type to use (none or gz)");
+
+void MyLogger(android::base::LogId, android::base::LogSeverity severity, const char*, const char*,
+              unsigned int, const char* message) {
+    if (severity == android::base::ERROR) {
+        fprintf(stderr, "%s\n", message);
+    } else {
+        fprintf(stdout, "%s\n", message);
+    }
+}
+
+uint64_t ToLittleEndian(uint64_t value) {
+    union {
+        uint64_t u64;
+        char bytes[8];
+    } packed;
+    packed.u64 = value;
+    std::swap(packed.bytes[0], packed.bytes[7]);
+    std::swap(packed.bytes[1], packed.bytes[6]);
+    std::swap(packed.bytes[2], packed.bytes[5]);
+    std::swap(packed.bytes[3], packed.bytes[4]);
+    return packed.u64;
+}
+
+class PayloadConverter final {
+  public:
+    PayloadConverter(const std::string& in_file, const std::string& out_dir)
+        : in_file_(in_file), out_dir_(out_dir), source_tf_zip_(nullptr, &CloseArchive) {}
+
+    bool Run();
+
+  private:
+    bool OpenPayload();
+    bool OpenSourceTargetFiles();
+    bool ProcessPartition(const PartitionUpdate& update);
+    bool ProcessOperation(const InstallOperation& op);
+    bool ProcessZero(const InstallOperation& op);
+    bool ProcessCopy(const InstallOperation& op);
+    bool ProcessReplace(const InstallOperation& op);
+    bool ProcessDiff(const InstallOperation& op);
+    borrowed_fd OpenSourceImage();
+
+    std::string in_file_;
+    std::string out_dir_;
+    unique_fd in_fd_;
+    uint64_t payload_offset_ = 0;
+    DeltaArchiveManifest manifest_;
+    std::unordered_set<std::string> dap_;
+    unique_fd source_tf_fd_;
+    std::unique_ptr<ZipArchive, decltype(&CloseArchive)> source_tf_zip_;
+
+    // Updated during ProcessPartition().
+    std::string partition_name_;
+    std::unique_ptr<CowWriter> writer_;
+    unique_fd source_image_;
+};
+
+bool PayloadConverter::Run() {
+    if (!OpenPayload()) {
+        return false;
+    }
+
+    if (manifest_.has_dynamic_partition_metadata()) {
+        const auto& dpm = manifest_.dynamic_partition_metadata();
+        for (const auto& group : dpm.groups()) {
+            for (const auto& partition : group.partition_names()) {
+                dap_.emplace(partition);
+            }
+        }
+    }
+
+    if (dap_.empty()) {
+        LOG(ERROR) << "No dynamic partitions found.";
+        return false;
+    }
+
+    if (!OpenSourceTargetFiles()) {
+        return false;
+    }
+
+    for (const auto& update : manifest_.partitions()) {
+        if (!ProcessPartition(update)) {
+            return false;
+        }
+        writer_ = nullptr;
+        source_image_.reset();
+    }
+    return true;
+}
+
+bool PayloadConverter::OpenSourceTargetFiles() {
+    if (FLAGS_source_tf.empty()) {
+        return true;
+    }
+
+    source_tf_fd_.reset(open(FLAGS_source_tf.c_str(), O_RDONLY));
+    if (source_tf_fd_ < 0) {
+        LOG(ERROR) << "open failed: " << FLAGS_source_tf;
+        return false;
+    }
+
+    struct stat s;
+    if (fstat(source_tf_fd_.get(), &s) < 0) {
+        LOG(ERROR) << "fstat failed: " << FLAGS_source_tf;
+        return false;
+    }
+    if (S_ISDIR(s.st_mode)) {
+        return true;
+    }
+
+    // Otherwise, assume it's a zip file.
+    ZipArchiveHandle handle;
+    if (OpenArchiveFd(source_tf_fd_.get(), FLAGS_source_tf.c_str(), &handle, false)) {
+        LOG(ERROR) << "Could not open " << FLAGS_source_tf << " as a zip archive.";
+        return false;
+    }
+    source_tf_zip_.reset(handle);
+    return true;
+}
+
+bool PayloadConverter::ProcessPartition(const PartitionUpdate& update) {
+    auto partition_name = update.partition_name();
+    if (dap_.find(partition_name) == dap_.end()) {
+        // Skip non-DAP partitions.
+        return true;
+    }
+
+    auto path = out_dir_ + "/" + partition_name + ".cow";
+    unique_fd fd(open(path.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0644));
+    if (fd < 0) {
+        PLOG(ERROR) << "open failed: " << path;
+        return false;
+    }
+
+    CowOptions options;
+    options.block_size = kBlockSize;
+    options.compression = FLAGS_compression;
+
+    writer_ = std::make_unique<CowWriter>(options);
+    if (!writer_->Initialize(std::move(fd))) {
+        LOG(ERROR) << "Unable to initialize COW writer";
+        return false;
+    }
+
+    partition_name_ = partition_name;
+
+    for (const auto& op : update.operations()) {
+        if (!ProcessOperation(op)) {
+            return false;
+        }
+    }
+
+    if (!writer_->Flush()) {
+        LOG(ERROR) << "Unable to finalize COW for " << partition_name;
+        return false;
+    }
+    return true;
+}
+
+bool PayloadConverter::ProcessOperation(const InstallOperation& op) {
+    switch (op.type()) {
+        case InstallOperation::SOURCE_COPY:
+            return ProcessCopy(op);
+        case InstallOperation::BROTLI_BSDIFF:
+        case InstallOperation::PUFFDIFF:
+            return ProcessDiff(op);
+        case InstallOperation::REPLACE:
+        case InstallOperation::REPLACE_XZ:
+        case InstallOperation::REPLACE_BZ:
+            return ProcessReplace(op);
+        case InstallOperation::ZERO:
+            return ProcessZero(op);
+        default:
+            LOG(ERROR) << "Unsupported op: " << (int)op.type();
+            return false;
+    }
+    return true;
+}
+
+bool PayloadConverter::ProcessZero(const InstallOperation& op) {
+    for (const auto& extent : op.dst_extents()) {
+        if (!writer_->AddZeroBlocks(extent.start_block(), extent.num_blocks())) {
+            LOG(ERROR) << "Could not add zero operation";
+            return false;
+        }
+    }
+    return true;
+}
+
+template <typename T>
+static uint64_t SizeOfAllExtents(const T& extents) {
+    uint64_t total = 0;
+    for (const auto& extent : extents) {
+        total += extent.num_blocks() * kBlockSize;
+    }
+    return total;
+}
+
+class PuffInputStream final : public puffin::StreamInterface {
+  public:
+    PuffInputStream(uint8_t* buffer, size_t length) : buffer_(buffer), length_(length), pos_(0) {}
+
+    bool GetSize(uint64_t* size) const override {
+        *size = length_;
+        return true;
+    }
+    bool GetOffset(uint64_t* offset) const override {
+        *offset = pos_;
+        return true;
+    }
+    bool Seek(uint64_t offset) override {
+        if (offset > length_) return false;
+        pos_ = offset;
+        return true;
+    }
+    bool Read(void* buffer, size_t length) override {
+        if (length_ - pos_ < length) return false;
+        memcpy(buffer, buffer_ + pos_, length);
+        pos_ += length;
+        return true;
+    }
+    bool Write(const void*, size_t) override { return false; }
+    bool Close() override { return true; }
+
+  private:
+    uint8_t* buffer_;
+    size_t length_;
+    size_t pos_;
+};
+
+class PuffOutputStream final : public puffin::StreamInterface {
+  public:
+    PuffOutputStream(std::vector<uint8_t>& stream) : stream_(stream), pos_(0) {}
+
+    bool GetSize(uint64_t* size) const override {
+        *size = stream_.size();
+        return true;
+    }
+    bool GetOffset(uint64_t* offset) const override {
+        *offset = pos_;
+        return true;
+    }
+    bool Seek(uint64_t offset) override {
+        if (offset > stream_.size()) {
+            return false;
+        }
+        pos_ = offset;
+        return true;
+    }
+    bool Read(void* buffer, size_t length) override {
+        if (stream_.size() - pos_ < length) {
+            return false;
+        }
+        memcpy(buffer, &stream_[0] + pos_, length);
+        pos_ += length;
+        return true;
+    }
+    bool Write(const void* buffer, size_t length) override {
+        auto remaining = stream_.size() - pos_;
+        if (remaining < length) {
+            stream_.resize(stream_.size() + (length - remaining));
+        }
+        memcpy(&stream_[0] + pos_, buffer, length);
+        pos_ += length;
+        return true;
+    }
+    bool Close() override { return true; }
+
+  private:
+    std::vector<uint8_t>& stream_;
+    size_t pos_;
+};
+
+bool PayloadConverter::ProcessDiff(const InstallOperation& op) {
+    auto source_image = OpenSourceImage();
+    if (source_image < 0) {
+        return false;
+    }
+
+    uint64_t src_length = SizeOfAllExtents(op.src_extents());
+    auto src = std::make_unique<uint8_t[]>(src_length);
+    size_t src_pos = 0;
+
+    // Read source bytes.
+    for (const auto& extent : op.src_extents()) {
+        uint64_t offset = extent.start_block() * kBlockSize;
+        if (lseek(source_image.get(), offset, SEEK_SET) < 0) {
+            PLOG(ERROR) << "lseek source image failed";
+            return false;
+        }
+
+        uint64_t size = extent.num_blocks() * kBlockSize;
+        CHECK(src_length - src_pos >= size);
+        if (!android::base::ReadFully(source_image, src.get() + src_pos, size)) {
+            PLOG(ERROR) << "read source image failed";
+            return false;
+        }
+        src_pos += size;
+    }
+    CHECK(src_pos == src_length);
+
+    // Read patch bytes.
+    auto patch = std::make_unique<uint8_t[]>(op.data_length());
+    if (lseek(in_fd_.get(), payload_offset_ + op.data_offset(), SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek payload failed";
+        return false;
+    }
+    if (!android::base::ReadFully(in_fd_, patch.get(), op.data_length())) {
+        PLOG(ERROR) << "read payload failed";
+        return false;
+    }
+
+    std::vector<uint8_t> dest(SizeOfAllExtents(op.dst_extents()));
+
+    // Apply the diff.
+    if (op.type() == InstallOperation::BROTLI_BSDIFF) {
+        size_t dest_pos = 0;
+        auto sink = [&](const uint8_t* data, size_t length) -> size_t {
+            CHECK(dest.size() - dest_pos >= length);
+            memcpy(&dest[dest_pos], data, length);
+            dest_pos += length;
+            return length;
+        };
+        if (int rv = bsdiff::bspatch(src.get(), src_pos, patch.get(), op.data_length(), sink)) {
+            LOG(ERROR) << "bspatch failed, error code " << rv;
+            return false;
+        }
+    } else if (op.type() == InstallOperation::PUFFDIFF) {
+        auto src_stream = std::make_unique<PuffInputStream>(src.get(), src_length);
+        auto dest_stream = std::make_unique<PuffOutputStream>(dest);
+        bool ok = PuffPatch(std::move(src_stream), std::move(dest_stream), patch.get(),
+                            op.data_length());
+        if (!ok) {
+            LOG(ERROR) << "puffdiff operation failed to apply";
+            return false;
+        }
+    } else {
+        LOG(ERROR) << "unsupported diff operation: " << op.type();
+        return false;
+    }
+
+    // Write the final blocks to the COW.
+    size_t dest_pos = 0;
+    for (const auto& extent : op.dst_extents()) {
+        uint64_t size = extent.num_blocks() * kBlockSize;
+        CHECK(dest.size() - dest_pos >= size);
+
+        if (!writer_->AddRawBlocks(extent.start_block(), &dest[dest_pos], size)) {
+            return false;
+        }
+        dest_pos += size;
+    }
+    return true;
+}
+
+borrowed_fd PayloadConverter::OpenSourceImage() {
+    if (source_image_ >= 0) {
+        return source_image_;
+    }
+
+    unique_fd unzip_fd;
+
+    auto local_path = "IMAGES/" + partition_name_ + ".img";
+    if (source_tf_zip_) {
+        {
+            TemporaryFile tmp;
+            if (tmp.fd < 0) {
+                PLOG(ERROR) << "mkstemp failed";
+                return -1;
+            }
+            unzip_fd.reset(tmp.release());
+        }
+
+        ZipEntry64 entry;
+        if (FindEntry(source_tf_zip_.get(), local_path, &entry)) {
+            LOG(ERROR) << "not found in archive: " << local_path;
+            return -1;
+        }
+        if (ExtractEntryToFile(source_tf_zip_.get(), &entry, unzip_fd.get())) {
+            LOG(ERROR) << "could not extract " << local_path;
+            return -1;
+        }
+        if (lseek(unzip_fd.get(), 0, SEEK_SET) < 0) {
+            PLOG(ERROR) << "lseek failed";
+            return -1;
+        }
+    } else if (source_tf_fd_ >= 0) {
+        unzip_fd.reset(openat(source_tf_fd_.get(), local_path.c_str(), O_RDONLY));
+        if (unzip_fd < 0) {
+            PLOG(ERROR) << "open failed: " << FLAGS_source_tf << "/" << local_path;
+            return -1;
+        }
+    } else {
+        LOG(ERROR) << "No source target files package was specified; need -source_tf";
+        return -1;
+    }
+
+    std::unique_ptr<struct sparse_file, decltype(&sparse_file_destroy)> s(
+            sparse_file_import(unzip_fd.get(), false, false), &sparse_file_destroy);
+    if (s) {
+        TemporaryFile tmp;
+        if (tmp.fd < 0) {
+            PLOG(ERROR) << "mkstemp failed";
+            return -1;
+        }
+        if (sparse_file_write(s.get(), tmp.fd, false, false, false) < 0) {
+            LOG(ERROR) << "sparse_file_write failed";
+            return -1;
+        }
+        source_image_.reset(tmp.release());
+    } else {
+        source_image_ = std::move(unzip_fd);
+    }
+    return source_image_;
+}
+
+template <typename ContainerType>
+class ExtentIter final {
+  public:
+    ExtentIter(const ContainerType& container)
+        : iter_(container.cbegin()), end_(container.cend()), dst_index_(0) {}
+
+    bool GetNext(uint64_t* block) {
+        while (iter_ != end_) {
+            if (dst_index_ < iter_->num_blocks()) {
+                break;
+            }
+            iter_++;
+            dst_index_ = 0;
+        }
+        if (iter_ == end_) {
+            return false;
+        }
+        *block = iter_->start_block() + dst_index_;
+        dst_index_++;
+        return true;
+    }
+
+  private:
+    typename ContainerType::const_iterator iter_;
+    typename ContainerType::const_iterator end_;
+    uint64_t dst_index_;
+};
+
+bool PayloadConverter::ProcessCopy(const InstallOperation& op) {
+    ExtentIter dst_blocks(op.dst_extents());
+
+    for (const auto& extent : op.src_extents()) {
+        for (uint64_t i = 0; i < extent.num_blocks(); i++) {
+            uint64_t src_block = extent.start_block() + i;
+            uint64_t dst_block;
+            if (!dst_blocks.GetNext(&dst_block)) {
+                LOG(ERROR) << "SOURCE_COPY contained mismatching extents";
+                return false;
+            }
+            if (src_block == dst_block) continue;
+            if (!writer_->AddCopy(dst_block, src_block)) {
+                LOG(ERROR) << "Could not add copy operation";
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+bool PayloadConverter::ProcessReplace(const InstallOperation& op) {
+    auto buffer_size = op.data_length();
+    auto buffer = std::make_unique<char[]>(buffer_size);
+    uint64_t offs = payload_offset_ + op.data_offset();
+    if (lseek(in_fd_.get(), offs, SEEK_SET) < 0) {
+        PLOG(ERROR) << "lseek " << offs << " failed";
+        return false;
+    }
+    if (!android::base::ReadFully(in_fd_, buffer.get(), buffer_size)) {
+        PLOG(ERROR) << "read " << buffer_size << " bytes from offset " << offs << "failed";
+        return false;
+    }
+
+    uint64_t dst_size = 0;
+    for (const auto& extent : op.dst_extents()) {
+        dst_size += extent.num_blocks() * kBlockSize;
+    }
+
+    if (op.type() == InstallOperation::REPLACE_BZ) {
+        auto tmp = std::make_unique<char[]>(dst_size);
+
+        uint32_t actual_size;
+        if (dst_size > std::numeric_limits<typeof(actual_size)>::max()) {
+            LOG(ERROR) << "too many bytes to decompress: " << dst_size;
+            return false;
+        }
+        actual_size = static_cast<uint32_t>(dst_size);
+
+        auto rv = BZ2_bzBuffToBuffDecompress(tmp.get(), &actual_size, buffer.get(), buffer_size, 0,
+                                             0);
+        if (rv) {
+            LOG(ERROR) << "bz2 decompress failed: " << rv;
+            return false;
+        }
+        if (actual_size != dst_size) {
+            LOG(ERROR) << "bz2 returned " << actual_size << " bytes, expected " << dst_size;
+            return false;
+        }
+        buffer = std::move(tmp);
+        buffer_size = dst_size;
+    } else if (op.type() == InstallOperation::REPLACE_XZ) {
+        constexpr uint32_t kXzMaxDictSize = 64 * 1024 * 1024;
+
+        if (dst_size > std::numeric_limits<size_t>::max()) {
+            LOG(ERROR) << "too many bytes to decompress: " << dst_size;
+            return false;
+        }
+
+        std::unique_ptr<struct xz_dec, decltype(&xz_dec_end)> s(
+                xz_dec_init(XZ_DYNALLOC, kXzMaxDictSize), xz_dec_end);
+        if (!s) {
+            LOG(ERROR) << "xz_dec_init failed";
+            return false;
+        }
+
+        auto tmp = std::make_unique<char[]>(dst_size);
+
+        struct xz_buf args;
+        args.in = reinterpret_cast<const uint8_t*>(buffer.get());
+        args.in_pos = 0;
+        args.in_size = buffer_size;
+        args.out = reinterpret_cast<uint8_t*>(tmp.get());
+        args.out_pos = 0;
+        args.out_size = dst_size;
+
+        auto rv = xz_dec_run(s.get(), &args);
+        if (rv != XZ_STREAM_END) {
+            LOG(ERROR) << "xz decompress failed: " << (int)rv;
+            return false;
+        }
+        buffer = std::move(tmp);
+        buffer_size = dst_size;
+    }
+
+    uint64_t buffer_pos = 0;
+    for (const auto& extent : op.dst_extents()) {
+        uint64_t extent_size = extent.num_blocks() * kBlockSize;
+        if (buffer_size - buffer_pos < extent_size) {
+            LOG(ERROR) << "replace op ran out of input buffer";
+            return false;
+        }
+        if (!writer_->AddRawBlocks(extent.start_block(), buffer.get() + buffer_pos, extent_size)) {
+            LOG(ERROR) << "failed to add raw blocks from replace op";
+            return false;
+        }
+        buffer_pos += extent_size;
+    }
+    return true;
+}
+
+bool PayloadConverter::OpenPayload() {
+    in_fd_.reset(open(in_file_.c_str(), O_RDONLY));
+    if (in_fd_ < 0) {
+        PLOG(ERROR) << "open " << in_file_;
+        return false;
+    }
+
+    char magic[4];
+    if (!android::base::ReadFully(in_fd_, magic, sizeof(magic))) {
+        PLOG(ERROR) << "read magic";
+        return false;
+    }
+    if (std::string(magic, sizeof(magic)) != "CrAU") {
+        LOG(ERROR) << "Invalid magic in " << in_file_;
+        return false;
+    }
+
+    uint64_t version;
+    uint64_t manifest_size;
+    uint32_t manifest_signature_size = 0;
+    if (!android::base::ReadFully(in_fd_, &version, sizeof(version))) {
+        PLOG(ERROR) << "read version";
+        return false;
+    }
+    version = ToLittleEndian(version);
+    if (version < 2) {
+        LOG(ERROR) << "Only payload version 2 or higher is supported.";
+        return false;
+    }
+
+    if (!android::base::ReadFully(in_fd_, &manifest_size, sizeof(manifest_size))) {
+        PLOG(ERROR) << "read manifest_size";
+        return false;
+    }
+    manifest_size = ToLittleEndian(manifest_size);
+    if (!android::base::ReadFully(in_fd_, &manifest_signature_size,
+                                  sizeof(manifest_signature_size))) {
+        PLOG(ERROR) << "read manifest_signature_size";
+        return false;
+    }
+    manifest_signature_size = ntohl(manifest_signature_size);
+
+    auto manifest = std::make_unique<uint8_t[]>(manifest_size);
+    if (!android::base::ReadFully(in_fd_, manifest.get(), manifest_size)) {
+        PLOG(ERROR) << "read manifest";
+        return false;
+    }
+
+    // Skip past manifest signature.
+    auto offs = lseek(in_fd_, manifest_signature_size, SEEK_CUR);
+    if (offs < 0) {
+        PLOG(ERROR) << "lseek failed";
+        return false;
+    }
+    payload_offset_ = offs;
+
+    if (!manifest_.ParseFromArray(manifest.get(), manifest_size)) {
+        LOG(ERROR) << "could not parse manifest";
+        return false;
+    }
+    return true;
+}
+
+}  // namespace snapshot
+}  // namespace android
+
+int main(int argc, char** argv) {
+    android::base::InitLogging(argv, android::snapshot::MyLogger);
+    gflags::SetUsageMessage("Convert OTA payload to a Virtual A/B COW");
+    int arg_start = gflags::ParseCommandLineFlags(&argc, &argv, false);
+
+    xz_crc32_init();
+
+    if (argc - arg_start != 2) {
+        std::cerr << "Usage: [options] <payload.bin> <out-dir>\n";
+        return 1;
+    }
+
+    android::snapshot::PayloadConverter pc(argv[arg_start], argv[arg_start + 1]);
+    return pc.Run() ? 0 : 1;
+}
diff --git a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
index adfb975..2970222 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
@@ -41,8 +41,14 @@
 
 class PartitionCowCreatorTest : public ::testing::Test {
   public:
-    void SetUp() override { SnapshotTestPropertyFetcher::SetUp(); }
-    void TearDown() override { SnapshotTestPropertyFetcher::TearDown(); }
+    void SetUp() override {
+        SKIP_IF_NON_VIRTUAL_AB();
+        SnapshotTestPropertyFetcher::SetUp();
+    }
+    void TearDown() override {
+        RETURN_IF_NON_VIRTUAL_AB();
+        SnapshotTestPropertyFetcher::TearDown();
+    }
 };
 
 TEST_F(PartitionCowCreatorTest, IntersectSelf) {
@@ -223,6 +229,8 @@
 }
 
 TEST(DmSnapshotInternals, CowSizeCalculator) {
+    SKIP_IF_NON_VIRTUAL_AB();
+
     DmSnapCowSizeCalculator cc(512, 8);
     unsigned long int b;
 
@@ -286,7 +294,9 @@
     std::optional<InstallOperation> expected_output;
 };
 
-class OptimizeOperationTest : public ::testing::TestWithParam<OptimizeOperationTestParam> {};
+class OptimizeOperationTest : public ::testing::TestWithParam<OptimizeOperationTestParam> {
+    void SetUp() override { SKIP_IF_NON_VIRTUAL_AB(); }
+};
 TEST_P(OptimizeOperationTest, Test) {
     InstallOperation actual_output;
     EXPECT_EQ(GetParam().expected_output.has_value(),
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 7488bda..b672d0e 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -15,6 +15,7 @@
 #include <libsnapshot/snapshot.h>
 
 #include <dirent.h>
+#include <fcntl.h>
 #include <math.h>
 #include <sys/file.h>
 #include <sys/types.h>
@@ -27,6 +28,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
+#include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <ext4_utils/ext4_utils.h>
@@ -42,6 +44,7 @@
 #include "device_info.h"
 #include "partition_cow_creator.h"
 #include "snapshot_metadata_updater.h"
+#include "snapshot_reader.h"
 #include "utility.h"
 
 namespace android {
@@ -68,6 +71,7 @@
 using android::hardware::boot::V1_1::MergeStatus;
 using chromeos_update_engine::DeltaArchiveManifest;
 using chromeos_update_engine::Extent;
+using chromeos_update_engine::FileDescriptor;
 using chromeos_update_engine::InstallOperation;
 template <typename T>
 using RepeatedPtrField = google::protobuf::RepeatedPtrField<T>;
@@ -103,6 +107,10 @@
     metadata_dir_ = device_->GetMetadataDir();
 }
 
+static inline bool IsCompressionEnabled() {
+    return android::base::GetBoolProperty("ro.virtual_ab.compression.enabled", false);
+}
+
 static std::string GetCowName(const std::string& snapshot_name) {
     return snapshot_name + "-cow";
 }
@@ -300,9 +308,9 @@
         LOG(ERROR) << "SnapshotStatus has no name.";
         return false;
     }
-    // Sanity check these sizes. Like liblp, we guarantee the partition size
-    // is respected, which means it has to be sector-aligned. (This guarantee
-    // is useful for locating avb footers correctly). The COW file size, however,
+    // Check these sizes. Like liblp, we guarantee the partition size is
+    // respected, which means it has to be sector-aligned. (This guarantee is
+    // useful for locating avb footers correctly). The COW file size, however,
     // can be arbitrarily larger than specified, so we can safely round it up.
     if (status->device_size() % kSectorSize != 0) {
         LOG(ERROR) << "Snapshot " << status->name()
@@ -351,7 +359,6 @@
     }
 
     // The COW file size should have been rounded up to the nearest sector in CreateSnapshot.
-    // Sanity check this.
     if (status.cow_file_size() % kSectorSize != 0) {
         LOG(ERROR) << "Snapshot " << name << " COW file size is not a multiple of the sector size: "
                    << status.cow_file_size();
@@ -1565,7 +1572,8 @@
                 .timeout_ms = timeout_ms,
         };
         std::string ignore_path;
-        if (!MapPartitionWithSnapshot(lock.get(), std::move(params), &ignore_path)) {
+        if (!MapPartitionWithSnapshot(lock.get(), std::move(params), SnapshotContext::Mount,
+                                      nullptr)) {
             return false;
         }
     }
@@ -1593,11 +1601,10 @@
 
 bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
                                                CreateLogicalPartitionParams params,
-                                               std::string* path) {
+                                               SnapshotContext context, SnapshotPaths* paths) {
     auto begin = std::chrono::steady_clock::now();
 
     CHECK(lock);
-    path->clear();
 
     if (params.GetPartitionName() != params.GetDeviceName()) {
         LOG(ERROR) << "Mapping snapshot with a different name is unsupported: partition_name = "
@@ -1678,8 +1685,11 @@
     }
     created_devices.EmplaceBack<AutoUnmapDevice>(&dm, params.GetDeviceName());
 
+    if (paths) {
+        paths->target_device = base_path;
+    }
+
     if (!live_snapshot_status.has_value()) {
-        *path = base_path;
         created_devices.Release();
         return true;
     }
@@ -1706,21 +1716,33 @@
         LOG(ERROR) << "Could not determine major/minor for: " << cow_name;
         return false;
     }
+    if (paths) {
+        paths->cow_device = cow_device;
+    }
 
     remaining_time = GetRemainingTime(params.timeout_ms, begin);
     if (remaining_time.count() < 0) return false;
 
+    if (context == SnapshotContext::Update && IsCompressionEnabled()) {
+        // Stop here, we can't run dm-user yet, the COW isn't built.
+        return true;
+    }
+
+    std::string path;
     if (!MapSnapshot(lock, params.GetPartitionName(), base_device, cow_device, remaining_time,
-                     path)) {
+                     &path)) {
         LOG(ERROR) << "Could not map snapshot for partition: " << params.GetPartitionName();
         return false;
     }
     // No need to add params.GetPartitionName() to created_devices since it is immediately released.
 
+    if (paths) {
+        paths->snapshot_device = path;
+    }
+
     created_devices.Release();
 
-    LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << *path;
-
+    LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << path;
     return true;
 }
 
@@ -2421,6 +2443,11 @@
 
 bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
                                         std::string* snapshot_path) {
+    if (IsCompressionEnabled()) {
+        LOG(ERROR) << "MapUpdateSnapshot cannot be used in compression mode.";
+        return false;
+    }
+
     auto lock = LockShared();
     if (!lock) return false;
     if (!UnmapPartitionWithSnapshot(lock.get(), params.GetPartitionName())) {
@@ -2428,7 +2455,86 @@
                    << params.GetPartitionName();
         return false;
     }
-    return MapPartitionWithSnapshot(lock.get(), params, snapshot_path);
+
+    SnapshotPaths paths;
+    if (!MapPartitionWithSnapshot(lock.get(), params, SnapshotContext::Update, &paths)) {
+        return false;
+    }
+
+    if (paths.snapshot_device.empty()) {
+        *snapshot_path = paths.snapshot_device;
+    } else {
+        *snapshot_path = paths.target_device;
+    }
+    return true;
+}
+
+std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
+        const android::fs_mgr::CreateLogicalPartitionParams& params) {
+    // First unmap any existing mapping.
+    auto lock = LockShared();
+    if (!lock) return nullptr;
+    if (!UnmapPartitionWithSnapshot(lock.get(), params.GetPartitionName())) {
+        LOG(ERROR) << "Cannot unmap existing snapshot before re-mapping it: "
+                   << params.GetPartitionName();
+        return nullptr;
+    }
+
+    SnapshotPaths paths;
+    if (!MapPartitionWithSnapshot(lock.get(), params, SnapshotContext::Update, &paths)) {
+        return nullptr;
+    }
+
+    SnapshotStatus status;
+    if (!paths.cow_device.empty()) {
+        if (!ReadSnapshotStatus(lock.get(), params.GetPartitionName(), &status)) {
+            return nullptr;
+        }
+    } else {
+        // Currently, partition_cow_creator always creates snapshots. The
+        // reason is that if partition X shrinks while partition Y grows, we
+        // cannot bindly write to the newly freed extents in X. This would
+        // make the old slot unusable. So, the entire size of the target
+        // partition is currently considered snapshottable.
+        LOG(ERROR) << "No snapshot available for partition " << params.GetPartitionName();
+        return nullptr;
+    }
+
+    if (IsCompressionEnabled()) {
+        return OpenCompressedSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
+    } else {
+        return OpenKernelSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
+    }
+}
+
+std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
+        LockedFile*, const std::string&, const SnapshotStatus&, const SnapshotPaths&) {
+    LOG(ERROR) << "OpenSnapshotWriter not yet implemented for compression";
+    return nullptr;
+}
+
+std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenKernelSnapshotWriter(
+        LockedFile* lock, [[maybe_unused]] const std::string& partition_name,
+        const SnapshotStatus& status, const SnapshotPaths& paths) {
+    CHECK(lock);
+
+    CowOptions cow_options;
+    cow_options.max_blocks = {status.device_size() / cow_options.block_size};
+
+    auto writer = std::make_unique<OnlineKernelSnapshotWriter>(cow_options);
+
+    std::string_view path =
+            paths.snapshot_device.empty() ? paths.target_device : paths.snapshot_device;
+    unique_fd fd(open(path.data(), O_RDWR | O_CLOEXEC));
+    if (fd < 0) {
+        PLOG(ERROR) << "open failed: " << path;
+        return nullptr;
+    }
+
+    uint64_t cow_size = status.cow_partition_size() + status.cow_file_size();
+    writer->SetSnapshotDevice(std::move(fd), cow_size);
+
+    return writer;
 }
 
 bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_name) {
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz.cpp b/fs_mgr/libsnapshot/snapshot_fuzz.cpp
index 5b145c3..aced3ed 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz.cpp
+++ b/fs_mgr/libsnapshot/snapshot_fuzz.cpp
@@ -141,7 +141,7 @@
                        const RecoveryCreateSnapshotDevicesArgs& args) {
     std::unique_ptr<AutoDevice> device;
     if (args.has_metadata_device_object()) {
-        device = std::make_unique<DummyAutoDevice>(args.metadata_mounted());
+        device = std::make_unique<NoOpAutoDevice>(args.metadata_mounted());
     }
     return snapshot->RecoveryCreateSnapshotDevices(device);
 }
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
index fa327b8..5319e69 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
@@ -35,9 +35,9 @@
 class AutoMemBasedDir;
 class SnapshotFuzzDeviceInfo;
 
-class DummyAutoDevice : public AutoDevice {
+class NoOpAutoDevice : public AutoDevice {
   public:
-    DummyAutoDevice(bool mounted) : AutoDevice(mounted ? "dummy" : "") {}
+    NoOpAutoDevice(bool mounted) : AutoDevice(mounted ? "no_op" : "") {}
 };
 
 struct SnapshotTestModule {
diff --git a/fs_mgr/libsnapshot/snapshot_metadata_updater.cpp b/fs_mgr/libsnapshot/snapshot_metadata_updater.cpp
index 051584c..17a0c96 100644
--- a/fs_mgr/libsnapshot/snapshot_metadata_updater.cpp
+++ b/fs_mgr/libsnapshot/snapshot_metadata_updater.cpp
@@ -39,6 +39,8 @@
 SnapshotMetadataUpdater::SnapshotMetadataUpdater(MetadataBuilder* builder, uint32_t target_slot,
                                                  const DeltaArchiveManifest& manifest)
     : builder_(builder), target_suffix_(SlotSuffixForSlotNumber(target_slot)) {
+    partial_update_ = manifest.partial_update();
+
     if (!manifest.has_dynamic_partition_metadata()) {
         return;
     }
@@ -63,7 +65,6 @@
         }
     }
 
-    partial_update_ = manifest.partial_update();
 }
 
 bool SnapshotMetadataUpdater::ShrinkPartitions() const {
@@ -173,9 +174,9 @@
         if (iter != groups_.end()) {
             continue;
         }
-        // Update package metadata doesn't have this group. Before deleting it, sanity check that it
-        // doesn't have any partitions left. Update metadata shouldn't assign any partitions to this
-        // group, so all partitions that originally belong to this group should be moved by
+        // Update package metadata doesn't have this group. Before deleting it, check that it
+        // doesn't have any partitions left. Update metadata shouldn't assign any partitions to
+        // this group, so all partitions that originally belong to this group should be moved by
         // MovePartitionsToDefault at this point.
         auto existing_partitions_in_group = builder_->ListPartitionsInGroup(existing_group_name);
         if (!existing_partitions_in_group.empty()) {
diff --git a/fs_mgr/libsnapshot/snapshot_metadata_updater_test.cpp b/fs_mgr/libsnapshot/snapshot_metadata_updater_test.cpp
index 5530e59..0a16c03 100644
--- a/fs_mgr/libsnapshot/snapshot_metadata_updater_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_metadata_updater_test.cpp
@@ -43,11 +43,11 @@
 
 class SnapshotMetadataUpdaterTest : public ::testing::TestWithParam<uint32_t> {
   public:
-    SnapshotMetadataUpdaterTest() {
-        is_virtual_ab_ = android::base::GetBoolProperty("ro.virtual_ab.enabled", false);
-    }
+    SnapshotMetadataUpdaterTest() = default;
 
     void SetUp() override {
+        SKIP_IF_NON_VIRTUAL_AB();
+
         target_slot_ = GetParam();
         target_suffix_ = SlotSuffixForSlotNumber(target_slot_);
         SnapshotTestPropertyFetcher::SetUp(SlotSuffixForSlotNumber(1 - target_slot_));
@@ -68,7 +68,11 @@
         ASSERT_TRUE(FillFakeMetadata(builder_.get(), manifest_, target_suffix_));
     }
 
-    void TearDown() override { SnapshotTestPropertyFetcher::TearDown(); }
+    void TearDown() override {
+        RETURN_IF_NON_VIRTUAL_AB();
+
+        SnapshotTestPropertyFetcher::TearDown();
+    }
 
     // Append suffix to name.
     std::string T(std::string_view name) { return std::string(name) + target_suffix_; }
@@ -127,7 +131,6 @@
                                   << ".";
     }
 
-    bool is_virtual_ab_;
     std::unique_ptr<MetadataBuilder> builder_;
     uint32_t target_slot_;
     std::string target_suffix_;
diff --git a/fs_mgr/libsnapshot/snapshot_reader.cpp b/fs_mgr/libsnapshot/snapshot_reader.cpp
new file mode 100644
index 0000000..0d47468
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_reader.cpp
@@ -0,0 +1,77 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 <ext4_utils/ext4_utils.h>
+
+#include "snapshot_reader.h"
+
+namespace android {
+namespace snapshot {
+
+// Not supported.
+bool ReadOnlyFileDescriptor::Open(const char*, int, mode_t) {
+    errno = EINVAL;
+    return false;
+}
+
+bool ReadOnlyFileDescriptor::Open(const char*, int) {
+    errno = EINVAL;
+    return false;
+}
+
+ssize_t ReadOnlyFileDescriptor::Write(const void*, size_t) {
+    errno = EINVAL;
+    return false;
+}
+
+bool ReadOnlyFileDescriptor::BlkIoctl(int, uint64_t, uint64_t, int*) {
+    errno = EINVAL;
+    return false;
+}
+
+ReadFdFileDescriptor::ReadFdFileDescriptor(android::base::unique_fd&& fd) : fd_(std::move(fd)) {}
+
+ssize_t ReadFdFileDescriptor::Read(void* buf, size_t count) {
+    return read(fd_.get(), buf, count);
+}
+
+off64_t ReadFdFileDescriptor::Seek(off64_t offset, int whence) {
+    return lseek(fd_.get(), offset, whence);
+}
+
+uint64_t ReadFdFileDescriptor::BlockDevSize() {
+    return get_block_device_size(fd_.get());
+}
+
+bool ReadFdFileDescriptor::Close() {
+    fd_ = {};
+    return true;
+}
+
+bool ReadFdFileDescriptor::IsSettingErrno() {
+    return true;
+}
+
+bool ReadFdFileDescriptor::IsOpen() {
+    return fd_ >= 0;
+}
+
+bool ReadFdFileDescriptor::Flush() {
+    return true;
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_reader.h b/fs_mgr/libsnapshot/snapshot_reader.h
new file mode 100644
index 0000000..1f2ffe2
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_reader.h
@@ -0,0 +1,50 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#pragma once
+
+#include <android-base/file.h>
+#include <payload_consumer/file_descriptor.h>
+
+namespace android {
+namespace snapshot {
+
+class ReadOnlyFileDescriptor : public chromeos_update_engine::FileDescriptor {
+  public:
+    bool Open(const char* path, int flags, mode_t mode) override;
+    bool Open(const char* path, int flags) override;
+    ssize_t Write(const void* buf, size_t count) override;
+    bool BlkIoctl(int request, uint64_t start, uint64_t length, int* result) override;
+};
+
+class ReadFdFileDescriptor : public ReadOnlyFileDescriptor {
+  public:
+    explicit ReadFdFileDescriptor(android::base::unique_fd&& fd);
+
+    ssize_t Read(void* buf, size_t count) override;
+    off64_t Seek(off64_t offset, int whence) override;
+    uint64_t BlockDevSize() override;
+    bool Close() override;
+    bool IsSettingErrno() override;
+    bool IsOpen() override;
+    bool Flush() override;
+
+  private:
+    android::base::unique_fd fd_;
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp
index 9b6f758..41f5da4 100644
--- a/fs_mgr/libsnapshot/snapshot_stub.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stub.cpp
@@ -20,6 +20,7 @@
 
 using android::fs_mgr::CreateLogicalPartitionParams;
 using chromeos_update_engine::DeltaArchiveManifest;
+using chromeos_update_engine::FileDescriptor;
 
 namespace android::snapshot {
 
@@ -129,4 +130,10 @@
     return &snapshot_merge_stats;
 }
 
+std::unique_ptr<ISnapshotWriter> SnapshotManagerStub::OpenSnapshotWriter(
+        const CreateLogicalPartitionParams&) {
+    LOG(ERROR) << __FUNCTION__ << " should never be called.";
+    return nullptr;
+}
+
 }  // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 2bd0135..f2caaa4 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -80,12 +80,11 @@
 std::string fake_super;
 
 void MountMetadata();
+bool IsCompressionEnabled();
 
 class SnapshotTest : public ::testing::Test {
   public:
-    SnapshotTest() : dm_(DeviceMapper::Instance()) {
-        is_virtual_ab_ = android::base::GetBoolProperty("ro.virtual_ab.enabled", false);
-    }
+    SnapshotTest() : dm_(DeviceMapper::Instance()) {}
 
     // This is exposed for main.
     void Cleanup() {
@@ -95,7 +94,7 @@
 
   protected:
     void SetUp() override {
-        if (!is_virtual_ab_) GTEST_SKIP() << "Test for Virtual A/B devices only";
+        SKIP_IF_NON_VIRTUAL_AB();
 
         SnapshotTestPropertyFetcher::SetUp();
         InitializeState();
@@ -106,7 +105,7 @@
     }
 
     void TearDown() override {
-        if (!is_virtual_ab_) return;
+        RETURN_IF_NON_VIRTUAL_AB();
 
         lock_ = nullptr;
 
@@ -341,7 +340,6 @@
     }
 
     static constexpr std::chrono::milliseconds snapshot_timeout_ = 5s;
-    bool is_virtual_ab_;
     DeviceMapper& dm_;
     std::unique_ptr<SnapshotManager::LockedFile> lock_;
     android::fiemap::IImageManager* image_manager_ = nullptr;
@@ -722,11 +720,13 @@
 class LockTest : public ::testing::Test {
   public:
     void SetUp() {
+        SKIP_IF_NON_VIRTUAL_AB();
         first_consumer.StartHandleRequestsInBackground();
         second_consumer.StartHandleRequestsInBackground();
     }
 
     void TearDown() {
+        RETURN_IF_NON_VIRTUAL_AB();
         EXPECT_TRUE(first_consumer.MakeRequest(Request::EXIT));
         EXPECT_TRUE(second_consumer.MakeRequest(Request::EXIT));
     }
@@ -770,7 +770,7 @@
 class SnapshotUpdateTest : public SnapshotTest {
   public:
     void SetUp() override {
-        if (!is_virtual_ab_) GTEST_SKIP() << "Test for Virtual A/B devices only";
+        SKIP_IF_NON_VIRTUAL_AB();
 
         SnapshotTest::SetUp();
         Cleanup();
@@ -832,7 +832,7 @@
         }
     }
     void TearDown() override {
-        if (!is_virtual_ab_) return;
+        RETURN_IF_NON_VIRTUAL_AB();
 
         Cleanup();
         SnapshotTest::TearDown();
@@ -893,42 +893,39 @@
         return AssertionSuccess();
     }
 
-    AssertionResult MapUpdateSnapshot(const std::string& name, std::string* path = nullptr) {
-        std::string real_path;
-        if (!sm->MapUpdateSnapshot(
-                    CreateLogicalPartitionParams{
-                            .block_device = fake_super,
-                            .metadata_slot = 1,
-                            .partition_name = name,
-                            .timeout_ms = 10s,
-                            .partition_opener = opener_.get(),
-                    },
-                    &real_path)) {
-            return AssertionFailure() << "Unable to map snapshot " << name;
+    AssertionResult MapUpdateSnapshot(const std::string& name,
+                                      std::unique_ptr<ICowWriter>* writer = nullptr) {
+        CreateLogicalPartitionParams params{
+                .block_device = fake_super,
+                .metadata_slot = 1,
+                .partition_name = name,
+                .timeout_ms = 10s,
+                .partition_opener = opener_.get(),
+        };
+
+        auto result = sm->OpenSnapshotWriter(params);
+        if (!result) {
+            return AssertionFailure() << "Cannot open snapshot for writing: " << name;
         }
-        if (path) {
-            *path = real_path;
+
+        if (writer) {
+            *writer = std::move(result);
         }
-        return AssertionSuccess() << "Mapped snapshot " << name << " to " << real_path;
+        return AssertionSuccess();
     }
 
-    AssertionResult WriteSnapshotAndHash(const std::string& name,
-                                         std::optional<size_t> size = std::nullopt) {
-        std::string path;
-        auto res = MapUpdateSnapshot(name, &path);
+    AssertionResult WriteSnapshotAndHash(const std::string& name) {
+        std::unique_ptr<ICowWriter> writer;
+        auto res = MapUpdateSnapshot(name, &writer);
         if (!res) {
             return res;
         }
 
-        std::string size_string = size ? (std::to_string(*size) + " bytes") : "";
-
-        if (!WriteRandomData(path, size, &hashes_[name])) {
-            return AssertionFailure() << "Unable to write " << size_string << " to " << path
-                                      << " for partition " << name;
+        if (!WriteRandomData(writer.get(), &hashes_[name])) {
+            return AssertionFailure() << "Unable to write random data to snapshot " << name;
         }
 
-        return AssertionSuccess() << "Written " << size_string << " to " << path
-                                  << " for snapshot partition " << name
+        return AssertionSuccess() << "Written random data to snapshot " << name
                                   << ", hash: " << hashes_[name];
     }
 
@@ -1004,7 +1001,7 @@
 
     // Write some data to target partitions.
     for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
-        ASSERT_TRUE(WriteSnapshotAndHash(name, partition_size));
+        ASSERT_TRUE(WriteSnapshotAndHash(name));
     }
 
     // Assert that source partitions aren't affected.
@@ -1365,13 +1362,17 @@
     ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
 }
 
-class MetadataMountedTest : public SnapshotUpdateTest {
+class MetadataMountedTest : public ::testing::Test {
   public:
+    // This is so main() can instantiate this to invoke Cleanup.
+    virtual void TestBody() override {}
     void SetUp() override {
+        SKIP_IF_NON_VIRTUAL_AB();
         metadata_dir_ = test_device->GetMetadataDir();
         ASSERT_TRUE(ReadDefaultFstab(&fstab_));
     }
     void TearDown() override {
+        RETURN_IF_NON_VIRTUAL_AB();
         SetUp();
         // Remount /metadata
         test_device->set_recovery(false);
@@ -1403,6 +1404,10 @@
     MetadataMountedTest().TearDown();
 }
 
+bool IsCompressionEnabled() {
+    return android::base::GetBoolProperty("ro.virtual_ab.compression.enabled", false);
+}
+
 TEST_F(MetadataMountedTest, Android) {
     auto device = sm->EnsureMetadataMounted();
     EXPECT_NE(nullptr, device);
@@ -1620,7 +1625,7 @@
 
     // Map and write some data to target partition.
     ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
-    ASSERT_TRUE(WriteSnapshotAndHash("sys_b", partition_size));
+    ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
 
     // Finish update.
     ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
@@ -1652,7 +1657,7 @@
 
     // Map and write some data to target partitions.
     ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
-    ASSERT_TRUE(WriteSnapshotAndHash("sys_b", actual_write_size));
+    ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
 
     std::vector<android::dm::DeviceMapper::TargetInfo> table;
     ASSERT_TRUE(DeviceMapper::Instance().GetTableStatus("sys_b", &table));
@@ -1702,8 +1707,6 @@
 };
 
 TEST_P(FlashAfterUpdateTest, FlashSlotAfterUpdate) {
-    if (!is_virtual_ab_) GTEST_SKIP() << "Test for Virtual A/B devices only";
-
     // OTA client blindly unmaps all partitions that are possibly mapped.
     for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
         ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
@@ -1803,14 +1806,13 @@
 class ImageManagerTest : public SnapshotTest, public WithParamInterface<uint64_t> {
   protected:
     void SetUp() override {
-        if (!is_virtual_ab_) GTEST_SKIP() << "Test for Virtual A/B devices only";
-
+        SKIP_IF_NON_VIRTUAL_AB();
         SnapshotTest::SetUp();
         userdata_ = std::make_unique<LowSpaceUserdata>();
         ASSERT_TRUE(userdata_->Init(GetParam()));
     }
     void TearDown() override {
-        if (!is_virtual_ab_) return;
+        RETURN_IF_NON_VIRTUAL_AB();
         return;  // BUG(149738928)
 
         EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) ||
@@ -1852,11 +1854,6 @@
 
 INSTANTIATE_TEST_SUITE_P(ImageManagerTest, ImageManagerTest, ValuesIn(ImageManagerTestParams()));
 
-}  // namespace snapshot
-}  // namespace android
-
-using namespace android::snapshot;
-
 bool Mkdir(const std::string& path) {
     if (mkdir(path.c_str(), 0700) && errno != EEXIST) {
         std::cerr << "Could not mkdir " << path << ": " << strerror(errno) << std::endl;
@@ -1865,8 +1862,21 @@
     return true;
 }
 
-int main(int argc, char** argv) {
-    ::testing::InitGoogleTest(&argc, argv);
+class SnapshotTestEnvironment : public ::testing::Environment {
+  public:
+    ~SnapshotTestEnvironment() override {}
+    void SetUp() override;
+    void TearDown() override;
+
+  private:
+    std::unique_ptr<IImageManager> super_images_;
+};
+
+void SnapshotTestEnvironment::SetUp() {
+    // b/163082876: GTEST_SKIP in Environment will make atest report incorrect results. Until
+    // that is fixed, don't call GTEST_SKIP here, but instead call GTEST_SKIP in individual test
+    // suites.
+    RETURN_IF_NON_VIRTUAL_AB_MSG("Virtual A/B is not enabled, skipping global setup.\n");
 
     std::vector<std::string> paths = {
             // clang-format off
@@ -1879,18 +1889,13 @@
             // clang-format on
     };
     for (const auto& path : paths) {
-        if (!Mkdir(path)) {
-            return 1;
-        }
+        ASSERT_TRUE(Mkdir(path));
     }
 
     // Create this once, otherwise, gsid will start/stop between each test.
     test_device = new TestDeviceInfo();
     sm = SnapshotManager::New(test_device);
-    if (!sm) {
-        std::cerr << "Could not create snapshot manager\n";
-        return 1;
-    }
+    ASSERT_NE(nullptr, sm) << "Could not create snapshot manager";
 
     // Clean up previous run.
     MetadataMountedTest().TearDown();
@@ -1898,31 +1903,35 @@
     SnapshotTest().Cleanup();
 
     // Use a separate image manager for our fake super partition.
-    auto super_images = IImageManager::Open("ota/test/super", 10s);
-    if (!super_images) {
-        std::cerr << "Could not create image manager\n";
-        return 1;
-    }
+    super_images_ = IImageManager::Open("ota/test/super", 10s);
+    ASSERT_NE(nullptr, super_images_) << "Could not create image manager";
 
     // Clean up any old copy.
-    DeleteBackingImage(super_images.get(), "fake-super");
+    DeleteBackingImage(super_images_.get(), "fake-super");
 
     // Create and map the fake super partition.
     static constexpr int kImageFlags =
             IImageManager::CREATE_IMAGE_DEFAULT | IImageManager::CREATE_IMAGE_ZERO_FILL;
-    if (!super_images->CreateBackingImage("fake-super", kSuperSize, kImageFlags)) {
-        std::cerr << "Could not create fake super partition\n";
-        return 1;
-    }
-    if (!super_images->MapImageDevice("fake-super", 10s, &fake_super)) {
-        std::cerr << "Could not map fake super partition\n";
-        return 1;
-    }
+    ASSERT_TRUE(super_images_->CreateBackingImage("fake-super", kSuperSize, kImageFlags))
+            << "Could not create fake super partition";
+
+    ASSERT_TRUE(super_images_->MapImageDevice("fake-super", 10s, &fake_super))
+            << "Could not map fake super partition";
     test_device->set_fake_super(fake_super);
+}
 
-    auto result = RUN_ALL_TESTS();
+void SnapshotTestEnvironment::TearDown() {
+    RETURN_IF_NON_VIRTUAL_AB();
+    if (super_images_ != nullptr) {
+        DeleteBackingImage(super_images_.get(), "fake-super");
+    }
+}
 
-    DeleteBackingImage(super_images.get(), "fake-super");
+}  // namespace snapshot
+}  // namespace android
 
-    return result;
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ::testing::AddGlobalTestEnvironment(new ::android::snapshot::SnapshotTestEnvironment());
+    return RUN_ALL_TESTS();
 }
diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp
new file mode 100644
index 0000000..584f15e
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_writer.cpp
@@ -0,0 +1,97 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 <libsnapshot/snapshot_writer.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <payload_consumer/file_descriptor.h>
+#include "snapshot_reader.h"
+
+namespace android {
+namespace snapshot {
+
+using android::base::unique_fd;
+using chromeos_update_engine::FileDescriptor;
+
+ISnapshotWriter::ISnapshotWriter(const CowOptions& options) : ICowWriter(options) {}
+
+void ISnapshotWriter::SetSourceDevice(android::base::unique_fd&& source_fd) {
+    source_fd_ = std::move(source_fd);
+}
+
+OnlineKernelSnapshotWriter::OnlineKernelSnapshotWriter(const CowOptions& options)
+    : ISnapshotWriter(options) {}
+
+void OnlineKernelSnapshotWriter::SetSnapshotDevice(android::base::unique_fd&& snapshot_fd,
+                                                   uint64_t cow_size) {
+    snapshot_fd_ = std::move(snapshot_fd);
+    cow_size_ = cow_size;
+}
+
+bool OnlineKernelSnapshotWriter::Flush() {
+    if (fsync(snapshot_fd_.get()) < 0) {
+        PLOG(ERROR) << "fsync";
+        return false;
+    }
+    return true;
+}
+
+bool OnlineKernelSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data,
+                                               size_t size) {
+    uint64_t offset = new_block_start * options_.block_size;
+    if (lseek(snapshot_fd_.get(), offset, SEEK_SET) < 0) {
+        PLOG(ERROR) << "EmitRawBlocks lseek to offset " << offset;
+        return false;
+    }
+    if (!android::base::WriteFully(snapshot_fd_, data, size)) {
+        PLOG(ERROR) << "EmitRawBlocks write";
+        return false;
+    }
+    return true;
+}
+
+bool OnlineKernelSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
+    std::string zeroes(options_.block_size, 0);
+    for (uint64_t i = 0; i < num_blocks; i++) {
+        if (!EmitRawBlocks(new_block_start + i, zeroes.data(), zeroes.size())) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
+    std::string buffer(options_.block_size, 0);
+    uint64_t offset = old_block * options_.block_size;
+    if (!android::base::ReadFullyAtOffset(source_fd_, buffer.data(), buffer.size(), offset)) {
+        PLOG(ERROR) << "EmitCopy read";
+        return false;
+    }
+    return EmitRawBlocks(new_block, buffer.data(), buffer.size());
+}
+
+std::unique_ptr<FileDescriptor> OnlineKernelSnapshotWriter::OpenReader() {
+    unique_fd fd(dup(snapshot_fd_.get()));
+    if (fd < 0) {
+        PLOG(ERROR) << "dup2 failed in OpenReader";
+        return nullptr;
+    }
+    return std::make_unique<ReadFdFileDescriptor>(std::move(fd));
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp
new file mode 100644
index 0000000..d3f4f70
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd.cpp
@@ -0,0 +1,784 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <linux/types.h>
+#include <stdlib.h>
+
+#include <csignal>
+#include <cstring>
+#include <iostream>
+#include <limits>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <libdm/dm.h>
+#include <libsnapshot/cow_reader.h>
+#include <libsnapshot/cow_writer.h>
+#include <libsnapshot/snapuserd.h>
+
+namespace android {
+namespace snapshot {
+
+using namespace android;
+using namespace android::dm;
+using android::base::unique_fd;
+
+#define DM_USER_MAP_READ 0
+#define DM_USER_MAP_WRITE 1
+
+static constexpr size_t PAYLOAD_SIZE = (1UL << 16);
+
+static_assert(PAYLOAD_SIZE >= BLOCK_SIZE);
+
+class Target {
+  public:
+    // Represents an already-created Target, which is referenced by UUID.
+    Target(std::string uuid) : uuid_(uuid) {}
+
+    const auto& uuid() { return uuid_; }
+    std::string control_path() { return std::string("/dev/dm-user-") + uuid(); }
+
+  private:
+    const std::string uuid_;
+};
+
+class Daemon {
+    // The Daemon class is a singleton to avoid
+    // instantiating more than once
+  public:
+    static Daemon& Instance() {
+        static Daemon instance;
+        return instance;
+    }
+
+    bool IsRunning();
+
+  private:
+    bool is_running_;
+
+    Daemon();
+    Daemon(Daemon const&) = delete;
+    void operator=(Daemon const&) = delete;
+
+    static void SignalHandler(int signal);
+};
+
+Daemon::Daemon() {
+    is_running_ = true;
+    signal(SIGINT, Daemon::SignalHandler);
+    signal(SIGTERM, Daemon::SignalHandler);
+}
+
+bool Daemon::IsRunning() {
+    return is_running_;
+}
+
+void Daemon::SignalHandler(int signal) {
+    LOG(DEBUG) << "Snapuserd received signal: " << signal;
+    switch (signal) {
+        case SIGINT:
+        case SIGTERM: {
+            Daemon::Instance().is_running_ = false;
+            break;
+        }
+    }
+}
+
+class BufferSink : public IByteSink {
+  public:
+    void Initialize(size_t size) {
+        buffer_size_ = size;
+        buffer_offset_ = 0;
+        buffer_ = std::make_unique<uint8_t[]>(size);
+    }
+
+    void* GetBufPtr() { return buffer_.get(); }
+
+    void Clear() { memset(GetBufPtr(), 0, buffer_size_); }
+
+    void* GetPayloadBuffer(size_t size) {
+        if ((buffer_size_ - buffer_offset_) < size) return nullptr;
+
+        char* buffer = reinterpret_cast<char*>(GetBufPtr());
+        struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
+        return (char*)msg->payload.buf + buffer_offset_;
+    }
+
+    void* GetBuffer(size_t requested, size_t* actual) override {
+        void* buf = GetPayloadBuffer(requested);
+        if (!buf) {
+            *actual = 0;
+            return nullptr;
+        }
+        *actual = requested;
+        return buf;
+    }
+
+    void UpdateBufferOffset(size_t size) { buffer_offset_ += size; }
+
+    struct dm_user_header* GetHeaderPtr() {
+        CHECK(sizeof(struct dm_user_header) <= buffer_size_);
+        char* buf = reinterpret_cast<char*>(GetBufPtr());
+        struct dm_user_header* header = (struct dm_user_header*)(&(buf[0]));
+        return header;
+    }
+
+    bool ReturnData(void*, size_t) override { return true; }
+    void ResetBufferOffset() { buffer_offset_ = 0; }
+
+  private:
+    std::unique_ptr<uint8_t[]> buffer_;
+    loff_t buffer_offset_;
+    size_t buffer_size_;
+};
+
+class Snapuserd final {
+  public:
+    Snapuserd(const std::string& in_cow_device, const std::string& in_backing_store_device)
+        : in_cow_device_(in_cow_device),
+          in_backing_store_device_(in_backing_store_device),
+          metadata_read_done_(false) {}
+
+    int Run();
+    int ReadDmUserHeader();
+    int WriteDmUserPayload(size_t size);
+    int ConstructKernelCowHeader();
+    int ReadMetadata();
+    int ZerofillDiskExceptions(size_t read_size);
+    int ReadDiskExceptions(chunk_t chunk, size_t size);
+    int ReadData(chunk_t chunk, size_t size);
+
+  private:
+    int ProcessReplaceOp(const CowOperation* cow_op);
+    int ProcessCopyOp(const CowOperation* cow_op);
+    int ProcessZeroOp();
+
+    std::string in_cow_device_;
+    std::string in_backing_store_device_;
+
+    unique_fd cow_fd_;
+    unique_fd backing_store_fd_;
+    unique_fd ctrl_fd_;
+
+    uint32_t exceptions_per_area_;
+
+    std::unique_ptr<ICowOpIter> cowop_iter_;
+    std::unique_ptr<CowReader> reader_;
+
+    // Vector of disk exception which is a
+    // mapping of old-chunk to new-chunk
+    std::vector<std::unique_ptr<uint8_t[]>> vec_;
+
+    // Index - Chunk ID
+    // Value - cow operation
+    std::vector<const CowOperation*> chunk_vec_;
+
+    bool metadata_read_done_;
+    BufferSink bufsink_;
+};
+
+// Construct kernel COW header in memory
+// This header will be in sector 0. The IO
+// request will always be 4k. After constructing
+// the header, zero out the remaining block.
+int Snapuserd::ConstructKernelCowHeader() {
+    void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SIZE);
+    CHECK(buffer != nullptr);
+
+    memset(buffer, 0, BLOCK_SIZE);
+
+    struct disk_header* dh = reinterpret_cast<struct disk_header*>(buffer);
+
+    dh->magic = SNAP_MAGIC;
+    dh->valid = SNAPSHOT_VALID;
+    dh->version = SNAPSHOT_DISK_VERSION;
+    dh->chunk_size = CHUNK_SIZE;
+
+    return BLOCK_SIZE;
+}
+
+// Start the replace operation. This will read the
+// internal COW format and if the block is compressed,
+// it will be de-compressed.
+int Snapuserd::ProcessReplaceOp(const CowOperation* cow_op) {
+    if (!reader_->ReadData(*cow_op, &bufsink_)) {
+        LOG(ERROR) << "ReadData failed for chunk: " << cow_op->new_block;
+        return -EIO;
+    }
+
+    return BLOCK_SIZE;
+}
+
+// Start the copy operation. This will read the backing
+// block device which is represented by cow_op->source.
+int Snapuserd::ProcessCopyOp(const CowOperation* cow_op) {
+    void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SIZE);
+    CHECK(buffer != nullptr);
+
+    // Issue a single 4K IO. However, this can be optimized
+    // if the successive blocks are contiguous.
+    if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SIZE,
+                                          cow_op->source * BLOCK_SIZE)) {
+        LOG(ERROR) << "Copy-op failed. Read from backing store at: " << cow_op->source;
+        return -1;
+    }
+
+    return BLOCK_SIZE;
+}
+
+int Snapuserd::ProcessZeroOp() {
+    // Zero out the entire block
+    void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SIZE);
+    CHECK(buffer != nullptr);
+
+    memset(buffer, 0, BLOCK_SIZE);
+    return BLOCK_SIZE;
+}
+
+/*
+ * Read the data of size bytes from a given chunk.
+ *
+ * Kernel can potentially merge the blocks if the
+ * successive chunks are contiguous. For chunk size of 8,
+ * there can be 256 disk exceptions; and if
+ * all 256 disk exceptions are contiguous, kernel can merge
+ * them into a single IO.
+ *
+ * Since each chunk in the disk exception
+ * mapping represents a 4k block, kernel can potentially
+ * issue 256*4k = 1M IO in one shot.
+ *
+ * Even though kernel assumes that the blocks are
+ * contiguous, we need to split the 1M IO into 4k chunks
+ * as each operation represents 4k and it can either be:
+ *
+ * 1: Replace operation
+ * 2: Copy operation
+ * 3: Zero operation
+ *
+ */
+int Snapuserd::ReadData(chunk_t chunk, size_t size) {
+    int ret = 0;
+
+    size_t read_size = size;
+
+    chunk_t chunk_key = chunk;
+    uint32_t stride;
+    lldiv_t divresult;
+
+    // Size should always be aligned
+    CHECK((read_size & (BLOCK_SIZE - 1)) == 0);
+
+    while (read_size > 0) {
+        const CowOperation* cow_op = chunk_vec_[chunk_key];
+        CHECK(cow_op != nullptr);
+        int result;
+
+        switch (cow_op->type) {
+            case kCowReplaceOp: {
+                result = ProcessReplaceOp(cow_op);
+                break;
+            }
+
+            case kCowZeroOp: {
+                result = ProcessZeroOp();
+                break;
+            }
+
+            case kCowCopyOp: {
+                result = ProcessCopyOp(cow_op);
+                break;
+            }
+
+            default: {
+                LOG(ERROR) << "Unknown operation-type found: " << cow_op->type;
+                ret = -EIO;
+                goto done;
+            }
+        }
+
+        if (result < 0) {
+            ret = result;
+            goto done;
+        }
+
+        // Update the buffer offset
+        bufsink_.UpdateBufferOffset(BLOCK_SIZE);
+
+        read_size -= BLOCK_SIZE;
+        ret += BLOCK_SIZE;
+
+        // Start iterating the chunk incrementally; Since while
+        // constructing the metadata, we know that the chunk IDs
+        // are contiguous
+        chunk_key += 1;
+
+        // This is similar to the way when chunk IDs were assigned
+        // in ReadMetadata().
+        //
+        // Skip if the chunk id represents a metadata chunk.
+        stride = exceptions_per_area_ + 1;
+        divresult = lldiv(chunk_key, stride);
+        if (divresult.rem == NUM_SNAPSHOT_HDR_CHUNKS) {
+            // Crossing exception boundary. Kernel will never
+            // issue IO which is spanning between a data chunk
+            // and a metadata chunk. This should be perfectly aligned.
+            //
+            // Since the input read_size is 4k aligned, we will
+            // always end up reading all 256 data chunks in one area.
+            // Thus, every multiple of 4K IO represents 256 data chunks
+            CHECK(read_size == 0);
+            break;
+        }
+    }
+
+done:
+
+    // Reset the buffer offset
+    bufsink_.ResetBufferOffset();
+    return ret;
+}
+
+/*
+ * dm-snap does prefetch reads while reading disk-exceptions.
+ * By default, prefetch value is set to 12; this means that
+ * dm-snap will issue 12 areas wherein each area is a 4k page
+ * of disk-exceptions.
+ *
+ * If during prefetch, if the chunk-id seen is beyond the
+ * actual number of metadata page, fill the buffer with zero.
+ * When dm-snap starts parsing the buffer, it will stop
+ * reading metadata page once the buffer content is zero.
+ */
+int Snapuserd::ZerofillDiskExceptions(size_t read_size) {
+    size_t size = exceptions_per_area_ * sizeof(struct disk_exception);
+
+    if (read_size > size) return -EINVAL;
+
+    void* buffer = bufsink_.GetPayloadBuffer(size);
+    CHECK(buffer != nullptr);
+
+    memset(buffer, 0, size);
+    return size;
+}
+
+/*
+ * A disk exception is a simple mapping of old_chunk to new_chunk.
+ * When dm-snapshot device is created, kernel requests these mapping.
+ *
+ * Each disk exception is of size 16 bytes. Thus a single 4k page can
+ * have:
+ *
+ * exceptions_per_area_ = 4096/16 = 256. This entire 4k page
+ * is considered a metadata page and it is represented by chunk ID.
+ *
+ * Convert the chunk ID to index into the vector which gives us
+ * the metadata page.
+ */
+int Snapuserd::ReadDiskExceptions(chunk_t chunk, size_t read_size) {
+    uint32_t stride = exceptions_per_area_ + 1;
+    size_t size;
+
+    // ChunkID to vector index
+    lldiv_t divresult = lldiv(chunk, stride);
+
+    if (divresult.quot < vec_.size()) {
+        size = exceptions_per_area_ * sizeof(struct disk_exception);
+
+        if (read_size > size) return -EINVAL;
+
+        void* buffer = bufsink_.GetPayloadBuffer(size);
+        CHECK(buffer != nullptr);
+
+        memcpy(buffer, vec_[divresult.quot].get(), size);
+    } else {
+        size = ZerofillDiskExceptions(read_size);
+    }
+
+    return size;
+}
+
+/*
+ * Read the metadata from COW device and
+ * construct the metadata as required by the kernel.
+ *
+ * Please see design on kernel COW format
+ *
+ * 1: Read the metadata from internal COW device
+ * 2: There are 3 COW operations:
+ *     a: Replace op
+ *     b: Copy op
+ *     c: Zero op
+ * 3: For each of the 3 operations, op->new_block
+ *    represents the block number in the base device
+ *    for which one of the 3 operations have to be applied.
+ *    This represents the old_chunk in the kernel COW format
+ * 4: We need to assign new_chunk for a corresponding old_chunk
+ * 5: The algorithm is similar to how kernel assigns chunk number
+ *    while creating exceptions.
+ * 6: Use a monotonically increasing chunk number to assign the
+ *    new_chunk
+ * 7: Each chunk-id represents either a: Metadata page or b: Data page
+ * 8: Chunk-id representing a data page is stored in a vector. Index is the
+ *    chunk-id and value is the pointer to the CowOperation
+ * 9: Chunk-id representing a metadata page is converted into a vector
+ *    index. We store this in vector as kernel requests metadata during
+ *    two stage:
+ *       a: When initial dm-snapshot device is created, kernel requests
+ *          all the metadata and stores it in its internal data-structures.
+ *       b: During merge, kernel once again requests the same metadata
+ *          once-again.
+ *    In both these cases, a quick lookup based on chunk-id is done.
+ * 10: When chunk number is incremented, we need to make sure that
+ *    if the chunk is representing a metadata page and skip.
+ * 11: Each 4k page will contain 256 disk exceptions. We call this
+ *    exceptions_per_area_
+ * 12: Kernel will stop issuing metadata IO request when new-chunk ID is 0.
+ */
+int Snapuserd::ReadMetadata() {
+    reader_ = std::make_unique<CowReader>();
+    CowHeader header;
+
+    if (!reader_->Parse(cow_fd_)) {
+        LOG(ERROR) << "Failed to parse";
+        return 1;
+    }
+
+    if (!reader_->GetHeader(&header)) {
+        LOG(ERROR) << "Failed to get header";
+        return 1;
+    }
+
+    CHECK(header.block_size == BLOCK_SIZE);
+
+    LOG(DEBUG) << "Num-ops: " << std::hex << header.num_ops;
+    LOG(DEBUG) << "ops-offset: " << std::hex << header.ops_offset;
+    LOG(DEBUG) << "ops-size: " << std::hex << header.ops_size;
+
+    cowop_iter_ = reader_->GetOpIter();
+
+    if (cowop_iter_ == nullptr) {
+        LOG(ERROR) << "Failed to get cowop_iter";
+        return 1;
+    }
+
+    exceptions_per_area_ = (CHUNK_SIZE << SECTOR_SHIFT) / sizeof(struct disk_exception);
+
+    // Start from chunk number 2. Chunk 0 represents header and chunk 1
+    // represents first metadata page.
+    chunk_t next_free = NUM_SNAPSHOT_HDR_CHUNKS + 1;
+    chunk_vec_.push_back(nullptr);
+    chunk_vec_.push_back(nullptr);
+
+    loff_t offset = 0;
+    std::unique_ptr<uint8_t[]> de_ptr =
+            std::make_unique<uint8_t[]>(exceptions_per_area_ * sizeof(struct disk_exception));
+
+    // This memset is important. Kernel will stop issuing IO when new-chunk ID
+    // is 0. When Area is not filled completely will all 256 exceptions,
+    // this memset will ensure that metadata read is completed.
+    memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
+    size_t num_ops = 0;
+
+    while (!cowop_iter_->Done()) {
+        const CowOperation* cow_op = &cowop_iter_->Get();
+        struct disk_exception* de =
+                reinterpret_cast<struct disk_exception*>((char*)de_ptr.get() + offset);
+
+        if (!(cow_op->type == kCowReplaceOp || cow_op->type == kCowZeroOp ||
+              cow_op->type == kCowCopyOp)) {
+            LOG(ERROR) << "Unknown operation-type found: " << cow_op->type;
+            return 1;
+        }
+
+        // Construct the disk-exception
+        de->old_chunk = cow_op->new_block;
+        de->new_chunk = next_free;
+
+        LOG(DEBUG) << "Old-chunk: " << de->old_chunk << "New-chunk: " << de->new_chunk;
+
+        // Store operation pointer. Note, new-chunk ID is the index
+        chunk_vec_.push_back(cow_op);
+        CHECK(next_free == (chunk_vec_.size() - 1));
+
+        offset += sizeof(struct disk_exception);
+
+        cowop_iter_->Next();
+
+        // Find the next free chunk-id to be assigned. Check if the next free
+        // chunk-id represents a metadata page. If so, skip it.
+        next_free += 1;
+        uint32_t stride = exceptions_per_area_ + 1;
+        lldiv_t divresult = lldiv(next_free, stride);
+        num_ops += 1;
+
+        if (divresult.rem == NUM_SNAPSHOT_HDR_CHUNKS) {
+            CHECK(num_ops == exceptions_per_area_);
+            // Store it in vector at the right index. This maps the chunk-id to
+            // vector index.
+            vec_.push_back(std::move(de_ptr));
+            offset = 0;
+            num_ops = 0;
+
+            chunk_t metadata_chunk = (next_free - exceptions_per_area_ - NUM_SNAPSHOT_HDR_CHUNKS);
+
+            LOG(DEBUG) << "Area: " << vec_.size() - 1;
+            LOG(DEBUG) << "Metadata-chunk: " << metadata_chunk;
+            LOG(DEBUG) << "Sector number of Metadata-chunk: " << (metadata_chunk << CHUNK_SHIFT);
+
+            // Create buffer for next area
+            de_ptr = std::make_unique<uint8_t[]>(exceptions_per_area_ *
+                                                 sizeof(struct disk_exception));
+            memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
+
+            // Since this is a metadata, store at this index
+            chunk_vec_.push_back(nullptr);
+
+            // Find the next free chunk-id
+            next_free += 1;
+            if (cowop_iter_->Done()) {
+                vec_.push_back(std::move(de_ptr));
+            }
+        }
+    }
+
+    // Partially filled area
+    if (num_ops) {
+        LOG(DEBUG) << "Partially filled area num_ops: " << num_ops;
+        vec_.push_back(std::move(de_ptr));
+    }
+
+    return 0;
+}
+
+void MyLogger(android::base::LogId, android::base::LogSeverity severity, const char*, const char*,
+              unsigned int, const char* message) {
+    if (severity == android::base::ERROR) {
+        fprintf(stderr, "%s\n", message);
+    } else {
+        fprintf(stdout, "%s\n", message);
+    }
+}
+
+// Read Header from dm-user misc device. This gives
+// us the sector number for which IO is issued by dm-snapshot device
+int Snapuserd::ReadDmUserHeader() {
+    if (!android::base::ReadFully(ctrl_fd_, bufsink_.GetBufPtr(), sizeof(struct dm_user_header))) {
+        PLOG(ERROR) << "Control read failed";
+        return -1;
+    }
+
+    return sizeof(struct dm_user_header);
+}
+
+// Send the payload/data back to dm-user misc device.
+int Snapuserd::WriteDmUserPayload(size_t size) {
+    if (!android::base::WriteFully(ctrl_fd_, bufsink_.GetBufPtr(),
+                                   sizeof(struct dm_user_header) + size)) {
+        PLOG(ERROR) << "Write to dm-user failed";
+        return -1;
+    }
+
+    return sizeof(struct dm_user_header) + size;
+}
+
+// Start the daemon.
+// TODO: Handle signals
+int Snapuserd::Run() {
+    backing_store_fd_.reset(open(in_backing_store_device_.c_str(), O_RDONLY));
+    if (backing_store_fd_ < 0) {
+        LOG(ERROR) << "Open Failed: " << in_backing_store_device_;
+        return 1;
+    }
+
+    cow_fd_.reset(open(in_cow_device_.c_str(), O_RDWR));
+    if (cow_fd_ < 0) {
+        LOG(ERROR) << "Open Failed: " << in_cow_device_;
+        return 1;
+    }
+
+    std::string str(in_cow_device_);
+    std::size_t found = str.find_last_of("/\\");
+    CHECK(found != std::string::npos);
+    std::string device_name = str.substr(found + 1);
+
+    LOG(DEBUG) << "Fetching UUID for: " << device_name;
+
+    auto& dm = dm::DeviceMapper::Instance();
+    std::string uuid;
+    if (!dm.GetDmDeviceUuidByName(device_name, &uuid)) {
+        LOG(ERROR) << "Unable to find UUID for " << in_cow_device_;
+        return 1;
+    }
+
+    LOG(DEBUG) << "UUID: " << uuid;
+    Target t(uuid);
+
+    ctrl_fd_.reset(open(t.control_path().c_str(), O_RDWR));
+    if (ctrl_fd_ < 0) {
+        LOG(ERROR) << "Unable to open " << t.control_path();
+        return 1;
+    }
+
+    int ret = 0;
+
+    // Allocate the buffer which is used to communicate between
+    // daemon and dm-user. The buffer comprises of header and a fixed payload.
+    // If the dm-user requests a big IO, the IO will be broken into chunks
+    // of PAYLOAD_SIZE.
+    size_t buf_size = sizeof(struct dm_user_header) + PAYLOAD_SIZE;
+    bufsink_.Initialize(buf_size);
+
+    while (true) {
+        struct dm_user_header* header = bufsink_.GetHeaderPtr();
+
+        bufsink_.Clear();
+
+        ret = ReadDmUserHeader();
+        if (ret < 0) return ret;
+
+        LOG(DEBUG) << "dm-user returned " << ret << " bytes";
+
+        LOG(DEBUG) << "msg->seq: " << std::hex << header->seq;
+        LOG(DEBUG) << "msg->type: " << std::hex << header->type;
+        LOG(DEBUG) << "msg->flags: " << std::hex << header->flags;
+        LOG(DEBUG) << "msg->sector: " << std::hex << header->sector;
+        LOG(DEBUG) << "msg->len: " << std::hex << header->len;
+
+        switch (header->type) {
+            case DM_USER_MAP_READ: {
+                size_t remaining_size = header->len;
+                loff_t offset = 0;
+                header->io_in_progress = 0;
+                ret = 0;
+                do {
+                    size_t read_size = std::min(PAYLOAD_SIZE, remaining_size);
+
+                    // Request to sector 0 is always for kernel
+                    // representation of COW header. This IO should be only
+                    // once during dm-snapshot device creation. We should
+                    // never see multiple IO requests. Additionally this IO
+                    // will always be a single 4k.
+                    if (header->sector == 0) {
+                        // Read the metadata from internal COW device
+                        // and build the in-memory data structures
+                        // for all the operations in the internal COW.
+                        if (!metadata_read_done_ && ReadMetadata()) {
+                            LOG(ERROR) << "Metadata read failed";
+                            return 1;
+                        }
+                        metadata_read_done_ = true;
+
+                        CHECK(read_size == BLOCK_SIZE);
+                        ret = ConstructKernelCowHeader();
+                        if (ret < 0) return ret;
+                    } else {
+                        // Convert the sector number to a chunk ID.
+                        //
+                        // Check if the chunk ID represents a metadata
+                        // page. If the chunk ID is not found in the
+                        // vector, then it points to a metadata page.
+                        chunk_t chunk = (header->sector >> CHUNK_SHIFT);
+
+                        if (chunk >= chunk_vec_.size()) {
+                            ret = ZerofillDiskExceptions(read_size);
+                            if (ret < 0) {
+                                LOG(ERROR) << "ZerofillDiskExceptions failed";
+                                return ret;
+                            }
+                        } else if (chunk_vec_[chunk] == nullptr) {
+                            ret = ReadDiskExceptions(chunk, read_size);
+                            if (ret < 0) {
+                                LOG(ERROR) << "ReadDiskExceptions failed";
+                                return ret;
+                            }
+                        } else {
+                            chunk_t num_chunks_read = (offset >> BLOCK_SHIFT);
+                            ret = ReadData(chunk + num_chunks_read, read_size);
+                            if (ret < 0) {
+                                LOG(ERROR) << "ReadData failed";
+                                return ret;
+                            }
+                        }
+                    }
+
+                    ssize_t written = WriteDmUserPayload(ret);
+                    if (written < 0) return written;
+
+                    remaining_size -= ret;
+                    offset += ret;
+                    if (remaining_size) {
+                        LOG(DEBUG) << "Write done ret: " << ret
+                                   << " remaining size: " << remaining_size;
+                        bufsink_.GetHeaderPtr()->io_in_progress = 1;
+                    }
+                } while (remaining_size);
+
+                break;
+            }
+
+            case DM_USER_MAP_WRITE: {
+                // TODO: After merge operation is completed, kernel issues write
+                // to flush all the exception mappings where the merge is
+                // completed. If dm-user routes the WRITE IO, we need to clear
+                // in-memory data structures representing those exception
+                // mappings.
+                abort();
+                break;
+            }
+        }
+
+        LOG(DEBUG) << "read() finished, next message";
+    }
+
+    return 0;
+}
+
+}  // namespace snapshot
+}  // namespace android
+
+void run_thread(std::string cow_device, std::string backing_device) {
+    android::snapshot::Snapuserd snapd(cow_device, backing_device);
+    snapd.Run();
+}
+
+int main([[maybe_unused]] int argc, char** argv) {
+    android::base::InitLogging(argv, &android::base::KernelLogger);
+
+    android::snapshot::Daemon& daemon = android::snapshot::Daemon::Instance();
+
+    while (daemon.IsRunning()) {
+        // TODO: This is hardcoded wherein:
+        // argv[1] = system_cow, argv[2] = /dev/block/mapper/system_a
+        // argv[3] = product_cow, argv[4] = /dev/block/mapper/product_a
+        //
+        // This should be fixed based on some kind of IPC or setup a
+        // command socket and spin up the thread based when a new
+        // partition is visible.
+        std::thread system_a(run_thread, argv[1], argv[2]);
+        std::thread product_a(run_thread, argv[3], argv[4]);
+
+        system_a.join();
+        product_a.join();
+    }
+
+    return 0;
+}
diff --git a/fs_mgr/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp
index de3d912..6104c82 100644
--- a/fs_mgr/libsnapshot/test_helpers.cpp
+++ b/fs_mgr/libsnapshot/test_helpers.cpp
@@ -18,6 +18,7 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
@@ -126,6 +127,48 @@
     return true;
 }
 
+bool WriteRandomData(ICowWriter* writer, std::string* hash) {
+    unique_fd rand(open("/dev/urandom", O_RDONLY));
+    if (rand < 0) {
+        PLOG(ERROR) << "open /dev/urandom";
+        return false;
+    }
+
+    SHA256_CTX ctx;
+    if (hash) {
+        SHA256_Init(&ctx);
+    }
+
+    if (!writer->options().max_blocks) {
+        LOG(ERROR) << "CowWriter must specify maximum number of blocks";
+        return false;
+    }
+    uint64_t num_blocks = writer->options().max_blocks.value();
+
+    size_t block_size = writer->options().block_size;
+    std::string block(block_size, '\0');
+    for (uint64_t i = 0; i < num_blocks; i++) {
+        if (!ReadFully(rand, block.data(), block.size())) {
+            PLOG(ERROR) << "read /dev/urandom";
+            return false;
+        }
+        if (!writer->AddRawBlocks(i, block.data(), block.size())) {
+            LOG(ERROR) << "Failed to add raw block " << i;
+            return false;
+        }
+        if (hash) {
+            SHA256_Update(&ctx, block.data(), block.size());
+        }
+    }
+
+    if (hash) {
+        uint8_t out[32];
+        SHA256_Final(out, &ctx);
+        *hash = ToHexString(out, sizeof(out));
+    }
+    return true;
+}
+
 std::optional<std::string> GetHash(const std::string& path) {
     std::string content;
     if (!android::base::ReadFileToString(path, &content, true)) {
@@ -241,5 +284,9 @@
     return bsize_;
 }
 
+bool IsVirtualAbEnabled() {
+    return android::base::GetBoolProperty("ro.virtual_ab.enabled", false);
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 82c4262..d56f7f2 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -15,13 +15,17 @@
 
 adb remount tests
 
---color                     Dress output with highlighting colors
---help                      This help
---no-wait-screen            Do not wait for display screen to settle
---print-time                Report the test duration
---serial                    Specify device (must if multiple are present)
---wait-adb <duration>       adb wait timeout
---wait-fastboot <duration>  fastboot wait timeout
+-c --color                     Dress output with highlighting colors
+-h --help                      This help
+-D --no-wait-screen            Do not wait for display screen to settle
+-t --print-time                Report the test duration
+-s --serial                    Specify device (must if multiple are present)"
+if [ -n "`which timeout`" ]; then
+  USAGE="${USAGE}
+-a --wait-adb <duration>       adb wait timeout
+-f --wait-fastboot <duration>  fastboot wait timeout"
+fi
+USAGE="${USAGE}
 
 Conditions:
  - Must be a userdebug build.
@@ -46,10 +50,10 @@
 ESCAPE="`echo | tr '\n' '\033'`"
 # A _real_ embedded carriage return character
 CR="`echo | tr '\n' '\r'`"
-GREEN="${ESCAPE}[38;5;40m"
-RED="${ESCAPE}[38;5;196m"
-ORANGE="${ESCAPE}[38;5;255:165:0m"
-BLUE="${ESCAPE}[35m"
+GREEN="${ESCAPE}[32m"
+RED="${ESCAPE}[31m"
+YELLOW="${ESCAPE}[33m"
+BLUE="${ESCAPE}[34m"
 NORMAL="${ESCAPE}[0m"
 TMPDIR=${TMPDIR:-/tmp}
 print_time=false
@@ -72,7 +76,7 @@
     if [ -n "${ANDROID_SERIAL}" ]; then
       grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
     else
-      wc -l | grep '^1$' >/dev/null
+      wc -l | grep "^[${SPACE}${TAB}]*1\$" >/dev/null
     fi
 }
 
@@ -85,7 +89,7 @@
     if [ -n "${ANDROID_SERIAL}" ]; then
       grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
     else
-      wc -l | grep '^1$' >/dev/null
+      wc -l | grep "^[${SPACE}${TAB}]*1\$" >/dev/null
     fi
 }
 
@@ -100,7 +104,7 @@
       grep "^${ANDROID_SERIAL}[${SPACE}${TAB}][${SPACE}${TAB}]*recovery\$" >/dev/null
     return ${?}
   fi
-  if echo "${list}" | wc -l | grep '^1$' >/dev/null; then
+  if echo "${list}" | wc -l | grep "^[${SPACE}${TAB}]*1\$" >/dev/null; then
     echo "${list}" |
       grep "[${SPACE}${TAB}]recovery\$" >/dev/null
     return ${?}
@@ -143,7 +147,7 @@
   adb logcat "${@}" </dev/null |
     tr -d '\r' |
     grep -v 'logd    : logdr: UID=' |
-    sed -e '${/------- beginning of kernel/d}' -e 's/^[0-1][0-9]-[0-3][0-9] //'
+    sed -e '${ /------- beginning of kernel/d }' -e 's/^[0-1][0-9]-[0-3][0-9] //'
 }
 
 [ "USAGE: avc_check >/dev/stderr
@@ -160,7 +164,7 @@
   if [ -z "${L}" ]; then
     return
   fi
-  echo "${ORANGE}[  WARNING ]${NORMAL} unlabeled sepolicy violations:" >&2
+  echo "${YELLOW}[  WARNING ]${NORMAL} unlabeled sepolicy violations:" >&2
   echo "${L}" | sed "s/^/${INDENT}/" >&2
 }
 
@@ -284,7 +288,7 @@
   local start=`date +%s`
   local duration=
   local ret
-  if [ -n "${1}" ]; then
+  if [ -n "${1}" -a -n "`which timeout`" ]; then
     USB_DEVICE=`usb_devnum --next`
     duration=`format_duration ${1}`
     echo -n ". . . waiting ${duration}" ${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE} "${CR}"
@@ -299,7 +303,7 @@
   if [ 0 = ${ret} -a -n "${ACTIVE_SLOT}" ]; then
     local active_slot=`get_active_slot`
     if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then
-      echo "${ORANGE}[  WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}" >&2
+      echo "${YELLOW}[  WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}" >&2
     fi
   fi
   local end=`date +%s`
@@ -359,18 +363,22 @@
     echo "(In adb mode `adb_user`)"
   else
     echo "(USB stack borken for ${USB_ADDRESS})"
-    USB_DEVICE=`usb_devnum`
-    if [ -n "${USB_DEVICE}" ]; then
-      echo "# lsusb -v -s ${USB_DEVICE#dev}"
-      local D=`lsusb -v -s ${USB_DEVICE#dev} 2>&1`
-      if [ -n "${D}" ]; then
-        echo "${D}"
-      else
-        lsusb -v
+    if [ -n "`which usb_devnum`" ]; then
+      USB_DEVICE=`usb_devnum`
+      if [ -n "`which lsusb`" ]; then
+        if [ -n "${USB_DEVICE}" ]; then
+          echo "# lsusb -v -s ${USB_DEVICE#dev}"
+          local D=`lsusb -v -s ${USB_DEVICE#dev} 2>&1`
+          if [ -n "${D}" ]; then
+            echo "${D}"
+          else
+            lsusb -v
+          fi
+        else
+          echo "# lsusb -v (expected device missing)"
+          lsusb -v
+        fi
       fi
-    else
-      echo "# lsusb -v (expected device missing)"
-      lsusb -v
     fi >&2
   fi
 }
@@ -382,7 +390,7 @@
   local ret
   # fastboot has no wait-for-device, but it does an automatic
   # wait and requires (even a nonsensical) command to do so.
-  if [ -n "${1}" ]; then
+  if [ -n "${1}" -a -n "`which timeout`" ]; then
     USB_DEVICE=`usb_devnum --next`
     echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE} "${CR}"
     timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device >/dev/null 2>/dev/null
@@ -398,7 +406,7 @@
   if [ 0 = ${ret} -a -n "${ACTIVE_SLOT}" ]; then
     local active_slot=`get_active_slot`
     if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then
-      echo "${ORANGE}[  WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
+      echo "${YELLOW}[  WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
     fi >&2
   fi
   return ${ret}
@@ -409,7 +417,7 @@
 Returns: waits until the device has returned for recovery or optional timeout" ]
 recovery_wait() {
   local ret
-  if [ -n "${1}" ]; then
+  if [ -n "${1}" -a -n "`which timeout`" ]; then
     USB_DEVICE=`usb_devnum --next`
     echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE} "${CR}"
     timeout --preserve-status --signal=KILL ${1} adb wait-for-recovery 2>/dev/null
@@ -423,7 +431,7 @@
   if [ 0 = ${ret} -a -n "${ACTIVE_SLOT}" ]; then
     local active_slot=`get_active_slot`
     if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then
-      echo "${ORANGE}[  WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
+      echo "${YELLOW}[  WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
     fi >&2
   fi
   return ${ret}
@@ -732,6 +740,7 @@
   grep -v \
     -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\|bpf\) " \
     -e "^\(binfmt_misc\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
+    -e "^\(ramdumpfs\) " \
     -e " functionfs " \
     -e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
     -e "^rootfs / rootfs rw," \
@@ -753,13 +762,28 @@
 ##  MAINLINE
 ##
 
-OPTIONS=`getopt --alternative --unquoted \
-                --longoptions help,serial:,colour,color,no-colour,no-color \
-                --longoptions wait-adb:,wait-fastboot: \
-                --longoptions wait-screen,wait-display \
-                --longoptions no-wait-screen,no-wait-display \
-                --longoptions gtest_print_time,print-time \
-                -- "?hs:" ${*}` ||
+HOSTOS=`uname`
+GETOPTS="--alternative --unquoted
+         --longoptions help,serial:,colour,color,no-colour,no-color
+         --longoptions wait-adb:,wait-fastboot:
+         --longoptions wait-screen,wait-display
+         --longoptions no-wait-screen,no-wait-display
+         --longoptions gtest_print_time,print-time
+         --"
+if [ "Darwin" = "${HOSTOS}" ]; then
+  GETOPTS=
+  USAGE="`echo \"${USAGE}\" |
+            sed 's/--color/       /g
+                 1s/--help/-h/
+                 s/--help/      /g
+                 s/--no-wait-screen/                /g
+                 s/--print-time/            /g
+                 1s/--serial/-s/
+                 s/--serial/        /g
+                 s/--wait-adb/          /g
+                 s/--wait-fastboot/               /g'`"
+fi
+OPTIONS=`getopt ${GETOPTS} "?a:cCdDf:hs:t" ${*}` ||
   ( echo "${USAGE}" >&2 ; false ) ||
   die "getopt failure"
 set -- ${OPTIONS}
@@ -775,26 +799,26 @@
       export ANDROID_SERIAL=${2}
       shift
       ;;
-    --color | --colour)
+    -c | --color | --colour)
       color=true
       ;;
-    --no-color | --no-colour)
+    -C | --no-color | --no-colour)
       color=false
       ;;
-    --no-wait-display | --no-wait-screen)
+    -D | --no-wait-display | --no-wait-screen)
       screen_wait=false
       ;;
-    --wait-display | --wait-screen)
+    -d | --wait-display | --wait-screen)
       screen_wait=true
       ;;
-    --print-time | --gtest_print_time)
+    -t | --print-time | --gtest_print_time)
       print_time=true
       ;;
-    --wait-adb)
+    -a | --wait-adb)
       ADB_WAIT=${2}
       shift
       ;;
-    --wait-fastboot)
+    -f | --wait-fastboot)
       FASTBOOT_WAIT=${2}
       shift
       ;;
@@ -815,7 +839,7 @@
 if ! ${color}; then
   GREEN=""
   RED=""
-  ORANGE=""
+  YELLOW=""
   BLUE=""
   NORMAL=""
 fi
@@ -827,14 +851,14 @@
 inFastboot && die "device in fastboot mode"
 inRecovery && die "device in recovery mode"
 if ! inAdb; then
-  echo "${ORANGE}[  WARNING ]${NORMAL} device not in adb mode" >&2
+  echo "${YELLOW}[  WARNING ]${NORMAL} device not in adb mode" >&2
   adb_wait ${ADB_WAIT}
 fi
 inAdb || die "specified device not in adb mode"
 isDebuggable || die "device not a debug build"
 enforcing=true
 if ! adb_su getenforce </dev/null | grep 'Enforcing' >/dev/null; then
-  echo "${ORANGE}[  WARNING ]${NORMAL} device does not have sepolicy in enforcing mode" >&2
+  echo "${YELLOW}[  WARNING ]${NORMAL} device does not have sepolicy in enforcing mode" >&2
   enforcing=false
 fi
 
@@ -846,9 +870,13 @@
 [ -n "${D}" ] || D=`get_property ro.boot.serialno`
 [ -z "${D}" -o -n "${ANDROID_SERIAL}" ] || ANDROID_SERIAL=${D}
 USB_SERIAL=
-[ -z "${ANDROID_SERIAL}" ] || USB_SERIAL=`find /sys/devices -name serial |
-                                          grep usb |
-                                          xargs -r grep -l ${ANDROID_SERIAL}`
+if [ -n "${ANDROID_SERIAL}" -a "Darwin" != "${HOSTOS}" ]; then
+  USB_SERIAL="`find /sys/devices -name serial | grep usb`"
+  if [ -n "${USB_SERIAL}" ]; then
+    USB_SERIAL=`echo "${USB_SERIAL}" |
+                  xargs grep -l ${ANDROID_SERIAL}`
+  fi
+fi
 USB_ADDRESS=
 if [ -n "${USB_SERIAL}" ]; then
   USB_ADDRESS=${USB_SERIAL%/serial}
@@ -860,13 +888,16 @@
 BUILD_DESCRIPTION=`get_property ro.build.description`
 [ -z "${BUILD_DESCRIPTION}" ] ||
   echo "${BLUE}[     INFO ]${NORMAL} ${BUILD_DESCRIPTION}" >&2
+KERNEL_VERSION="`adb_su cat /proc/version </dev/null 2>/dev/null`"
+[ -z "${KERNEL_VERSION}" ] ||
+  echo "${BLUE}[     INFO ]${NORMAL} ${KERNEL_VERSION}" >&2
 ACTIVE_SLOT=`get_active_slot`
 [ -z "${ACTIVE_SLOT}" ] ||
   echo "${BLUE}[     INFO ]${NORMAL} active slot is ${ACTIVE_SLOT}" >&2
 
 # Acquire list of system partitions
 
-PARTITIONS=`adb_su cat /vendor/etc/fstab* |
+PARTITIONS=`adb_su cat /vendor/etc/fstab* </dev/null |
               skip_administrative_mounts |
               sed -n "s@^\([^ ${TAB}/][^ ${TAB}/]*\)[ ${TAB}].*[, ${TAB}]ro[, ${TAB}].*@\1@p" |
               sort -u |
@@ -903,9 +934,12 @@
   done
 
 # If reboot too soon after fresh flash, could trip device update failure logic
+if ${screen_wait}; then
+  echo "${YELLOW}[  WARNING ]${NORMAL} waiting for screen to come up. Consider --no-wait-screen option" >&2
+fi
 if ! wait_for_screen && ${screen_wait}; then
   screen_wait=false
-  echo "${ORANGE}[  WARNING ]${NORMAL} not healthy, no launcher, skipping wait for screen" >&2
+  echo "${YELLOW}[  WARNING ]${NORMAL} not healthy, no launcher, skipping wait for screen" >&2
 fi
 
 # Can we test remount -R command?
@@ -954,7 +988,7 @@
   adb_su remount -R system </dev/null
   err=${?}
   if [ "${err}" != 0 ]; then
-    echo "${ORANGE}[  WARNING ]${NORMAL} adb shell su root remount -R system = ${err}, likely did not reboot!" >&2
+    echo "${YELLOW}[  WARNING ]${NORMAL} adb shell su root remount -R system = ${err}, likely did not reboot!" >&2
     T="-t ${T}"
   else
     # Rebooted, logcat will be meaningless, and last logcat will likely be clear
@@ -980,7 +1014,7 @@
   adb_sh grep "nodev${TAB}overlay" /proc/filesystems </dev/null >/dev/null 2>/dev/null &&
   echo "${GREEN}[       OK ]${NORMAL} overlay module present" >&2 ||
   (
-    echo "${ORANGE}[  WARNING ]${NORMAL} overlay module not present" >&2 &&
+    echo "${YELLOW}[  WARNING ]${NORMAL} overlay module not present" >&2 &&
       false
   ) ||
   overlayfs_supported=false
@@ -989,7 +1023,7 @@
     echo "${GREEN}[       OK ]${NORMAL} overlay module supports override_creds" >&2 ||
     case `adb_sh uname -r </dev/null` in
       4.[456789].* | 4.[1-9][0-9]* | [56789].*)
-        echo "${ORANGE}[  WARNING ]${NORMAL} overlay module does not support override_creds" >&2 &&
+        echo "${YELLOW}[  WARNING ]${NORMAL} overlay module does not support override_creds" >&2 &&
         overlayfs_supported=false
         ;;
       *)
@@ -1011,14 +1045,14 @@
 reboot=false
 for d in ${OVERLAYFS_BACKING}; do
   if adb_sh ls -d /${d}/overlay </dev/null >/dev/null 2>/dev/null; then
-    echo "${ORANGE}[  WARNING ]${NORMAL} /${d}/overlay is setup, surgically wiping" >&2
+    echo "${YELLOW}[  WARNING ]${NORMAL} /${d}/overlay is setup, surgically wiping" >&2
     adb_sh rm -rf /${d}/overlay </dev/null ||
       die "/${d}/overlay wipe"
     reboot=true
   fi
 done
 if ${reboot}; then
-  echo "${ORANGE}[  WARNING ]${NORMAL} rebooting before test" >&2
+  echo "${YELLOW}[  WARNING ]${NORMAL} rebooting before test" >&2
   adb_reboot &&
     adb_wait ${ADB_WAIT} ||
     die "lost device after reboot after wipe `usb_status`"
@@ -1030,7 +1064,7 @@
   D=`echo "${D}" | grep -v " /vendor/..*$" | grep "^overlay "` &&
   echo "${H}" &&
   echo "${D}" &&
-  echo "${ORANGE}[  WARNING ]${NORMAL} overlays present before setup" >&2 ||
+  echo "${YELLOW}[  WARNING ]${NORMAL} overlays present before setup" >&2 ||
   echo "${GREEN}[       OK ]${NORMAL} no overlay present before setup" >&2
 overlayfs_needed=true
 D=`adb_sh cat /proc/mounts </dev/null |
@@ -1083,7 +1117,7 @@
 if [ X"${D}" != X"${H}" ]; then
   echo "${H}"
   if [ X"${D}" != X"${D##*setup failed}" ]; then
-    echo "${ORANGE}[  WARNING ]${NORMAL} overlayfs setup whined" >&2
+    echo "${YELLOW}[  WARNING ]${NORMAL} overlayfs setup whined" >&2
   fi
   D=`adb_sh df -k </dev/null` &&
     H=`echo "${D}" | head -1` &&
@@ -1130,7 +1164,7 @@
 elif ${rebooted}; then
   echo "${GREEN}[       OK ]${NORMAL} verity already disabled" >&2
 else
-  echo "${ORANGE}[  WARNING ]${NORMAL} verity already disabled" >&2
+  echo "${YELLOW}[  WARNING ]${NORMAL} verity already disabled" >&2
 fi
 
 echo "${GREEN}[ RUN      ]${NORMAL} remount" >&2
@@ -1160,7 +1194,7 @@
     die -t ${T} "overlay takeover failed"
   fi
   echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
-   echo "${ORANGE}[  WARNING ]${NORMAL} overlay takeover not complete" >&2
+   echo "${YELLOW}[  WARNING ]${NORMAL} overlay takeover not complete" >&2
   if [ -z "${virtual_ab}" ]; then
     scratch_partition=scratch
   fi
@@ -1292,7 +1326,7 @@
 
 fixup_from_recovery() {
   inRecovery || return 1
-  echo "${ORANGE}[    ERROR ]${NORMAL} Device in recovery" >&2
+  echo "${YELLOW}[    ERROR ]${NORMAL} Device in recovery" >&2
   adb reboot </dev/null
   adb_wait ${ADB_WAIT}
 }
@@ -1312,7 +1346,7 @@
   adb_su sed -n '1,/overlay \/system/p' /proc/mounts </dev/null |
     skip_administrative_mounts |
     grep -v ' \(erofs\|squashfs\|ext4\|f2fs\|vfat\) ' &&
-    echo "${ORANGE}[  WARNING ]${NORMAL} overlay takeover after first stage init" >&2 ||
+    echo "${YELLOW}[  WARNING ]${NORMAL} overlay takeover after first stage init" >&2 ||
     echo "${GREEN}[       OK ]${NORMAL} overlay takeover in first stage init" >&2
 fi
 
@@ -1373,20 +1407,20 @@
 is_userspace_fastboot=false
 
 if ! ${is_bootloader_fastboot}; then
-  echo "${ORANGE}[  WARNING ]${NORMAL} does not support fastboot, skipping"
+  echo "${YELLOW}[  WARNING ]${NORMAL} does not support fastboot, skipping"
 elif [ -z "${ANDROID_PRODUCT_OUT}" ]; then
-  echo "${ORANGE}[  WARNING ]${NORMAL} build tree not setup, skipping"
+  echo "${YELLOW}[  WARNING ]${NORMAL} build tree not setup, skipping"
 elif [ ! -s "${ANDROID_PRODUCT_OUT}/vendor.img" ]; then
-  echo "${ORANGE}[  WARNING ]${NORMAL} vendor image missing, skipping"
+  echo "${YELLOW}[  WARNING ]${NORMAL} vendor image missing, skipping"
 elif [ "${ANDROID_PRODUCT_OUT}" = "${ANDROID_PRODUCT_OUT%*/${H}}" ]; then
-  echo "${ORANGE}[  WARNING ]${NORMAL} wrong vendor image, skipping"
+  echo "${YELLOW}[  WARNING ]${NORMAL} wrong vendor image, skipping"
 elif [ -z "${ANDROID_HOST_OUT}" ]; then
-  echo "${ORANGE}[  WARNING ]${NORMAL} please run lunch, skipping"
+  echo "${YELLOW}[  WARNING ]${NORMAL} please run lunch, skipping"
 elif ! (
           adb_cat /vendor/build.prop |
           cmp -s ${ANDROID_PRODUCT_OUT}/vendor/build.prop
        ) >/dev/null 2>/dev/null; then
-  echo "${ORANGE}[  WARNING ]${NORMAL} vendor image signature mismatch, skipping"
+  echo "${YELLOW}[  WARNING ]${NORMAL} vendor image signature mismatch, skipping"
 else
   wait_for_screen
   avc_check
@@ -1432,7 +1466,7 @@
   fi
   fastboot reboot ||
     die "can not reboot out of fastboot"
-  echo "${ORANGE}[  WARNING ]${NORMAL} adb after fastboot"
+  echo "${YELLOW}[  WARNING ]${NORMAL} adb after fastboot"
   adb_wait ${ADB_WAIT} ||
     fixup_from_recovery ||
     die "did not reboot after formatting ${scratch_partition} `usb_status`"
@@ -1449,8 +1483,8 @@
       if ${is_userspace_fastboot}; then
         die  "overlay supposed to be minus /vendor takeover after flash vendor"
       else
-        echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
-        echo "${ORANGE}[  WARNING ]${NORMAL} overlay supposed to be minus /vendor takeover after flash vendor" >&2
+        echo "${YELLOW}[  WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
+        echo "${YELLOW}[  WARNING ]${NORMAL} overlay supposed to be minus /vendor takeover after flash vendor" >&2
       fi
   fi
   B="`adb_cat /system/hello`"
@@ -1468,7 +1502,7 @@
     check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
              vendor content after flash vendor
   else
-    echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
+    echo "${YELLOW}[  WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
     check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
              --warning vendor content after flash vendor
   fi
@@ -1489,7 +1523,7 @@
 L=
 D="${H%?Now reboot your device for settings to take effect*}"
 if [ X"${H}" != X"${D}" ]; then
-  echo "${ORANGE}[  WARNING ]${NORMAL} adb remount requires a reboot after partial flash (legacy avb)"
+  echo "${YELLOW}[  WARNING ]${NORMAL} adb remount requires a reboot after partial flash (legacy avb)"
   L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
   adb_reboot &&
     adb_wait ${ADB_WAIT} &&
@@ -1547,7 +1581,7 @@
   err=${?}
   if [ X"${D}" != "${D%?Now reboot your device for settings to take effect*}" ]
   then
-    echo "${ORANGE}[  WARNING ]${NORMAL} adb disable-verity requires a reboot after partial flash"
+    echo "${YELLOW}[  WARNING ]${NORMAL} adb disable-verity requires a reboot after partial flash"
     adb_reboot &&
       adb_wait ${ADB_WAIT} &&
       adb_root ||
@@ -1580,9 +1614,9 @@
   if [ -n "${ACTIVE_SLOT}" ]; then
     local active_slot=`get_active_slot`
     if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then
-      echo "${ORANGE}[    ERROR ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
+      echo "${YELLOW}[    ERROR ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}"
     else
-      echo "${ORANGE}[    ERROR ]${NORMAL} Active slot to be set to ${ACTIVE_SLOT}"
+      echo "${YELLOW}[    ERROR ]${NORMAL} Active slot to be set to ${ACTIVE_SLOT}"
     fi >&2
     fastboot --set-active=${ACTIVE_SLOT}
   fi
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 27c8aae..46f1c59 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -394,9 +394,9 @@
     TemporaryFile tf;
     ASSERT_TRUE(tf.fd != -1);
     std::string fstab_contents = R"fs(
-source none0       swap   defaults      encryptable,forceencrypt,fileencryption,forcefdeorfbe,keydirectory,length,swapprio,zramsize,max_comp_streams,reservedsize,eraseblk,logicalblk,sysfs_path,zram_loopback_path,zram_loopback_size,zram_backing_dev_path
+source none0       swap   defaults      encryptable,forceencrypt,fileencryption,forcefdeorfbe,keydirectory,length,swapprio,zramsize,max_comp_streams,reservedsize,eraseblk,logicalblk,sysfs_path,zram_backingdev_size
 
-source none1       swap   defaults      encryptable=,forceencrypt=,fileencryption=,keydirectory=,length=,swapprio=,zramsize=,max_comp_streams=,avb=,reservedsize=,eraseblk=,logicalblk=,sysfs_path=,zram_loopback_path=,zram_loopback_size=,zram_backing_dev_path=
+source none1       swap   defaults      encryptable=,forceencrypt=,fileencryption=,keydirectory=,length=,swapprio=,zramsize=,max_comp_streams=,avb=,reservedsize=,eraseblk=,logicalblk=,sysfs_path=,zram_backingdev_size=
 
 source none2       swap   defaults      forcefdeorfbe=
 
@@ -426,9 +426,7 @@
     EXPECT_EQ(0, entry->erase_blk_size);
     EXPECT_EQ(0, entry->logical_blk_size);
     EXPECT_EQ("", entry->sysfs_path);
-    EXPECT_EQ("", entry->zram_loopback_path);
-    EXPECT_EQ(512U * 1024U * 1024U, entry->zram_loopback_size);
-    EXPECT_EQ("", entry->zram_backing_dev_path);
+    EXPECT_EQ(0U, entry->zram_backingdev_size);
     entry++;
 
     EXPECT_EQ("none1", entry->mount_point);
@@ -453,9 +451,7 @@
     EXPECT_EQ(0, entry->erase_blk_size);
     EXPECT_EQ(0, entry->logical_blk_size);
     EXPECT_EQ("", entry->sysfs_path);
-    EXPECT_EQ("", entry->zram_loopback_path);
-    EXPECT_EQ(512U * 1024U * 1024U, entry->zram_loopback_size);
-    EXPECT_EQ("", entry->zram_backing_dev_path);
+    EXPECT_EQ(0U, entry->zram_backingdev_size);
     entry++;
 
     // forcefdeorfbe has its own encryption_options defaults, so test it separately.
@@ -960,14 +956,10 @@
     TemporaryFile tf;
     ASSERT_TRUE(tf.fd != -1);
     std::string fstab_contents = R"fs(
-source none0       swap   defaults      zram_loopback_path=/dev/path
-
-source none1       swap   defaults      zram_loopback_size=blah
-source none2       swap   defaults      zram_loopback_size=2
-source none3       swap   defaults      zram_loopback_size=1K
-source none4       swap   defaults      zram_loopback_size=2m
-
-source none5       swap   defaults      zram_backing_dev_path=/dev/path2
+source none1       swap   defaults      zram_backingdev_size=blah
+source none2       swap   defaults      zram_backingdev_size=2
+source none3       swap   defaults      zram_backingdev_size=1K
+source none4       swap   defaults      zram_backingdev_size=2m
 
 )fs";
 
@@ -975,31 +967,25 @@
 
     Fstab fstab;
     EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
-    ASSERT_EQ(6U, fstab.size());
+    ASSERT_EQ(4U, fstab.size());
 
     auto entry = fstab.begin();
-    EXPECT_EQ("none0", entry->mount_point);
-    EXPECT_EQ("/dev/path", entry->zram_loopback_path);
-    entry++;
 
     EXPECT_EQ("none1", entry->mount_point);
-    EXPECT_EQ(512U * 1024U * 1024U, entry->zram_loopback_size);
+    EXPECT_EQ(0U, entry->zram_backingdev_size);
     entry++;
 
     EXPECT_EQ("none2", entry->mount_point);
-    EXPECT_EQ(2U, entry->zram_loopback_size);
+    EXPECT_EQ(2U, entry->zram_backingdev_size);
     entry++;
 
     EXPECT_EQ("none3", entry->mount_point);
-    EXPECT_EQ(1024U, entry->zram_loopback_size);
+    EXPECT_EQ(1024U, entry->zram_backingdev_size);
     entry++;
 
     EXPECT_EQ("none4", entry->mount_point);
-    EXPECT_EQ(2U * 1024U * 1024U, entry->zram_loopback_size);
+    EXPECT_EQ(2U * 1024U * 1024U, entry->zram_backingdev_size);
     entry++;
-
-    EXPECT_EQ("none5", entry->mount_point);
-    EXPECT_EQ("/dev/path2", entry->zram_backing_dev_path);
 }
 
 TEST(fs_mgr, DefaultFstabContainsUserdata) {
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 7a3d9a9..9edcda7 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -38,6 +38,7 @@
 #include <vector>
 
 using namespace std::literals::string_literals;
+using namespace std::chrono_literals;
 using namespace android::dm;
 using DmBlockDevice = ::android::dm::DeviceMapper::DmBlockDevice;
 
@@ -49,6 +50,7 @@
     std::cerr << "  delete <dm-name>" << std::endl;
     std::cerr << "  list <devices | targets> [-v]" << std::endl;
     std::cerr << "  getpath <dm-name>" << std::endl;
+    std::cerr << "  getuuid <dm-name>" << std::endl;
     std::cerr << "  info <dm-name>" << std::endl;
     std::cerr << "  status <dm-name>" << std::endl;
     std::cerr << "  resume <dm-name>" << std::endl;
@@ -241,8 +243,9 @@
         return ret;
     }
 
+    std::string ignore_path;
     DeviceMapper& dm = DeviceMapper::Instance();
-    if (!dm.CreateDevice(name, table)) {
+    if (!dm.CreateDevice(name, table, &ignore_path, 5s)) {
         std::cerr << "Failed to create device-mapper device with name: " << name << std::endl;
         return -EIO;
     }
@@ -391,6 +394,22 @@
     return 0;
 }
 
+static int GetUuidCmdHandler(int argc, char** argv) {
+    if (argc != 1) {
+        std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
+        return -EINVAL;
+    }
+
+    DeviceMapper& dm = DeviceMapper::Instance();
+    std::string uuid;
+    if (!dm.GetDmDeviceUuidByName(argv[0], &uuid)) {
+        std::cerr << "Could not query uuid of device \"" << argv[0] << "\"." << std::endl;
+        return -EINVAL;
+    }
+    std::cout << uuid << std::endl;
+    return 0;
+}
+
 static int InfoCmdHandler(int argc, char** argv) {
     if (argc != 1) {
         std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
@@ -504,6 +523,7 @@
         {"list", DmListCmdHandler},
         {"help", HelpCmdHandler},
         {"getpath", GetPathCmdHandler},
+        {"getuuid", GetUuidCmdHandler},
         {"info", InfoCmdHandler},
         {"table", TableCmdHandler},
         {"status", StatusCmdHandler},
diff --git a/gatekeeperd/binder/android/service/gatekeeper/IGateKeeperService.aidl b/gatekeeperd/binder/android/service/gatekeeper/IGateKeeperService.aidl
index 57adaba..4646efc 100644
--- a/gatekeeperd/binder/android/service/gatekeeper/IGateKeeperService.aidl
+++ b/gatekeeperd/binder/android/service/gatekeeper/IGateKeeperService.aidl
@@ -30,7 +30,7 @@
 interface IGateKeeperService {
     /**
      * Enrolls a password, returning the handle to the enrollment to be stored locally.
-     * @param uid The Android user ID associated to this enrollment
+     * @param userId The Android user ID associated to this enrollment
      * @param currentPasswordHandle The previously enrolled handle, or null if none
      * @param currentPassword The previously enrolled plaintext password, or null if none.
      *                        If provided, must verify against the currentPasswordHandle.
@@ -38,22 +38,22 @@
      *                        upon success.
      * @return an EnrollResponse or null on failure
      */
-    GateKeeperResponse enroll(int uid, in @nullable byte[] currentPasswordHandle,
+    GateKeeperResponse enroll(int userId, in @nullable byte[] currentPasswordHandle,
             in @nullable byte[] currentPassword, in byte[] desiredPassword);
 
     /**
      * Verifies an enrolled handle against a provided, plaintext blob.
-     * @param uid The Android user ID associated to this enrollment
+     * @param userId The Android user ID associated to this enrollment
      * @param enrolledPasswordHandle The handle against which the provided password will be
      *                               verified.
      * @param The plaintext blob to verify against enrolledPassword.
      * @return a VerifyResponse, or null on failure.
      */
-    GateKeeperResponse verify(int uid, in byte[] enrolledPasswordHandle, in byte[] providedPassword);
+    GateKeeperResponse verify(int userId, in byte[] enrolledPasswordHandle, in byte[] providedPassword);
 
     /**
      * Verifies an enrolled handle against a provided, plaintext blob.
-     * @param uid The Android user ID associated to this enrollment
+     * @param userId The Android user ID associated to this enrollment
      * @param challenge a challenge to authenticate agaisnt the device credential. If successful
      *                  authentication occurs, this value will be written to the returned
      *                  authentication attestation.
@@ -62,22 +62,22 @@
      * @param The plaintext blob to verify against enrolledPassword.
      * @return a VerifyResponse with an attestation, or null on failure.
      */
-    GateKeeperResponse verifyChallenge(int uid, long challenge, in byte[] enrolledPasswordHandle,
+    GateKeeperResponse verifyChallenge(int userId, long challenge, in byte[] enrolledPasswordHandle,
             in byte[] providedPassword);
 
     /**
      * Retrieves the secure identifier for the user with the provided Android ID,
      * or 0 if none is found.
-     * @param uid the Android user id
+     * @param userId the Android user id
      */
-    long getSecureUserId(int uid);
+    long getSecureUserId(int userId);
 
     /**
      * Clears secure user id associated with the provided Android ID.
      * Must be called when password is set to NONE.
-     * @param uid the Android user id.
+     * @param userId the Android user id.
      */
-    void clearSecureUserId(int uid);
+    void clearSecureUserId(int userId);
 
     /**
      * Notifies gatekeeper that device setup has been completed and any potentially still existing
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index c81a80e..b982dbc 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -76,9 +76,9 @@
     virtual ~GateKeeperProxy() {
     }
 
-    void store_sid(uint32_t uid, uint64_t sid) {
+    void store_sid(uint32_t userId, uint64_t sid) {
         char filename[21];
-        snprintf(filename, sizeof(filename), "%u", uid);
+        snprintf(filename, sizeof(filename), "%u", userId);
         int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
         if (fd < 0) {
             ALOGE("could not open file: %s: %s", filename, strerror(errno));
@@ -117,18 +117,18 @@
         return false;
     }
 
-    void maybe_store_sid(uint32_t uid, uint64_t sid) {
+    void maybe_store_sid(uint32_t userId, uint64_t sid) {
         char filename[21];
-        snprintf(filename, sizeof(filename), "%u", uid);
+        snprintf(filename, sizeof(filename), "%u", userId);
         if (access(filename, F_OK) == -1) {
-            store_sid(uid, sid);
+            store_sid(userId, sid);
         }
     }
 
-    uint64_t read_sid(uint32_t uid) {
+    uint64_t read_sid(uint32_t userId) {
         char filename[21];
         uint64_t sid;
-        snprintf(filename, sizeof(filename), "%u", uid);
+        snprintf(filename, sizeof(filename), "%u", userId);
         int fd = open(filename, O_RDONLY);
         if (fd < 0) return 0;
         read(fd, &sid, sizeof(sid));
@@ -136,30 +136,30 @@
         return sid;
     }
 
-    void clear_sid(uint32_t uid) {
+    void clear_sid(uint32_t userId) {
         char filename[21];
-        snprintf(filename, sizeof(filename), "%u", uid);
+        snprintf(filename, sizeof(filename), "%u", userId);
         if (remove(filename) < 0) {
             ALOGE("%s: could not remove file [%s], attempting 0 write", __func__, strerror(errno));
-            store_sid(uid, 0);
+            store_sid(userId, 0);
         }
     }
 
-    // This should only be called on uids being passed to the GateKeeper HAL. It ensures that
+    // This should only be called on userIds being passed to the GateKeeper HAL. It ensures that
     // secure storage shared across a GSI image and a host image will not overlap.
-    uint32_t adjust_uid(uint32_t uid) {
+    uint32_t adjust_userId(uint32_t userId) {
         static constexpr uint32_t kGsiOffset = 1000000;
-        CHECK(uid < kGsiOffset);
+        CHECK(userId < kGsiOffset);
         CHECK(hw_device != nullptr);
         if (is_running_gsi) {
-            return uid + kGsiOffset;
+            return userId + kGsiOffset;
         }
-        return uid;
+        return userId;
     }
 
 #define GK_ERROR *gkResponse = GKResponse::error(), Status::ok()
 
-    Status enroll(int32_t uid, const std::optional<std::vector<uint8_t>>& currentPasswordHandle,
+    Status enroll(int32_t userId, const std::optional<std::vector<uint8_t>>& currentPasswordHandle,
                   const std::optional<std::vector<uint8_t>>& currentPassword,
                   const std::vector<uint8_t>& desiredPassword, GKResponse* gkResponse) override {
         IPCThreadState* ipc = IPCThreadState::self();
@@ -198,9 +198,10 @@
         android::hardware::hidl_vec<uint8_t> newPwd;
         newPwd.setToExternal(const_cast<uint8_t*>(desiredPassword.data()), desiredPassword.size());
 
-        uint32_t hw_uid = adjust_uid(uid);
+        uint32_t hw_userId = adjust_userId(userId);
         Return<void> hwRes = hw_device->enroll(
-                hw_uid, curPwdHandle, curPwd, newPwd, [&gkResponse](const GatekeeperResponse& rsp) {
+                hw_userId, curPwdHandle, curPwd, newPwd,
+                [&gkResponse](const GatekeeperResponse& rsp) {
                     if (rsp.code >= GatekeeperStatusCode::STATUS_OK) {
                         *gkResponse = GKResponse::ok({rsp.data.begin(), rsp.data.end()});
                     } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT &&
@@ -225,12 +226,12 @@
             const gatekeeper::password_handle_t* handle =
                     reinterpret_cast<const gatekeeper::password_handle_t*>(
                             gkResponse->payload().data());
-            store_sid(uid, handle->user_id);
+            store_sid(userId, handle->user_id);
 
             GKResponse verifyResponse;
             // immediately verify this password so we don't ask the user to enter it again
             // if they just created it.
-            auto status = verify(uid, gkResponse->payload(), desiredPassword, &verifyResponse);
+            auto status = verify(userId, gkResponse->payload(), desiredPassword, &verifyResponse);
             if (!status.isOk() || verifyResponse.response_code() != GKResponseCode::OK) {
                 LOG(ERROR) << "Failed to verify password after enrolling";
             }
@@ -239,13 +240,13 @@
         return Status::ok();
     }
 
-    Status verify(int32_t uid, const ::std::vector<uint8_t>& enrolledPasswordHandle,
+    Status verify(int32_t userId, const ::std::vector<uint8_t>& enrolledPasswordHandle,
                   const ::std::vector<uint8_t>& providedPassword, GKResponse* gkResponse) override {
-        return verifyChallenge(uid, 0 /* challenge */, enrolledPasswordHandle, providedPassword,
+        return verifyChallenge(userId, 0 /* challenge */, enrolledPasswordHandle, providedPassword,
                                gkResponse);
     }
 
-    Status verifyChallenge(int32_t uid, int64_t challenge,
+    Status verifyChallenge(int32_t userId, int64_t challenge,
                            const std::vector<uint8_t>& enrolledPasswordHandle,
                            const std::vector<uint8_t>& providedPassword,
                            GKResponse* gkResponse) override {
@@ -269,7 +270,7 @@
                 reinterpret_cast<const gatekeeper::password_handle_t*>(
                         enrolledPasswordHandle.data());
 
-        uint32_t hw_uid = adjust_uid(uid);
+        uint32_t hw_userId = adjust_userId(userId);
         android::hardware::hidl_vec<uint8_t> curPwdHandle;
         curPwdHandle.setToExternal(const_cast<uint8_t*>(enrolledPasswordHandle.data()),
                                    enrolledPasswordHandle.size());
@@ -278,7 +279,7 @@
                                  providedPassword.size());
 
         Return<void> hwRes = hw_device->verify(
-                hw_uid, challenge, curPwdHandle, enteredPwd,
+                hw_userId, challenge, curPwdHandle, enteredPwd,
                 [&gkResponse](const GatekeeperResponse& rsp) {
                     if (rsp.code >= GatekeeperStatusCode::STATUS_OK) {
                         *gkResponse = GKResponse::ok(
@@ -315,18 +316,18 @@
                 }
             }
 
-            maybe_store_sid(uid, handle->user_id);
+            maybe_store_sid(userId, handle->user_id);
         }
 
         return Status::ok();
     }
 
-    Status getSecureUserId(int32_t uid, int64_t* sid) override {
-        *sid = read_sid(uid);
+    Status getSecureUserId(int32_t userId, int64_t* sid) override {
+        *sid = read_sid(userId);
         return Status::ok();
     }
 
-    Status clearSecureUserId(int32_t uid) override {
+    Status clearSecureUserId(int32_t userId) override {
         IPCThreadState* ipc = IPCThreadState::self();
         const int calling_pid = ipc->getCallingPid();
         const int calling_uid = ipc->getCallingUid();
@@ -334,11 +335,11 @@
             ALOGE("%s: permission denied for [%d:%d]", __func__, calling_pid, calling_uid);
             return Status::ok();
         }
-        clear_sid(uid);
+        clear_sid(userId);
 
         if (hw_device) {
-            uint32_t hw_uid = adjust_uid(uid);
-            hw_device->deleteUser(hw_uid, [] (const GatekeeperResponse &){});
+            uint32_t hw_userId = adjust_userId(userId);
+            hw_device->deleteUser(hw_userId, [](const GatekeeperResponse&) {});
         }
         return Status::ok();
     }
diff --git a/healthd/Android.bp b/healthd/Android.bp
index 14d46b3..b3de9c4 100644
--- a/healthd/Android.bp
+++ b/healthd/Android.bp
@@ -240,3 +240,47 @@
     defaults: ["charger_defaults"],
     srcs: ["charger_test.cpp"],
 }
+
+cc_test {
+    name: "libhealthd_charger_test",
+    defaults: ["charger_defaults"],
+    srcs: [
+        "AnimationParser_test.cpp",
+        "healthd_mode_charger_test.cpp"
+    ],
+    static_libs: [
+        "libgmock",
+    ],
+    test_suites: [
+        "general-tests",
+        "device-tests",
+    ],
+    data: [
+        ":libhealthd_charger_test_data",
+    ],
+    require_root: true,
+}
+
+// /system/etc/res/images/charger/battery_fail.png
+prebuilt_etc {
+    name: "system_core_charger_res_images_battery_fail.png",
+    src: "images/battery_fail.png",
+    relative_install_path: "res/images/charger",
+    filename: "battery_fail.png",
+}
+
+// /system/etc/res/images/charger/battery_scale.png
+prebuilt_etc {
+    name: "system_core_charger_res_images_battery_scale.png",
+    src: "images/battery_scale.png",
+    relative_install_path: "res/images/charger",
+    filename: "battery_scale.png",
+}
+
+phony {
+    name: "charger_res_images",
+    required: [
+        "system_core_charger_res_images_battery_fail.png",
+        "system_core_charger_res_images_battery_scale.png",
+    ],
+}
diff --git a/healthd/Android.mk b/healthd/Android.mk
deleted file mode 100644
index 4b09cf8..0000000
--- a/healthd/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-
-LOCAL_PATH := $(call my-dir)
-
-ifeq ($(strip $(BOARD_CHARGER_NO_UI)),true)
-LOCAL_CHARGER_NO_UI := true
-endif
-
-### charger_res_images ###
-ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
-define _add-charger-image
-include $$(CLEAR_VARS)
-LOCAL_MODULE := system_core_charger_res_images_$(notdir $(1))
-LOCAL_MODULE_STEM := $(notdir $(1))
-_img_modules += $$(LOCAL_MODULE)
-LOCAL_SRC_FILES := $1
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $$(TARGET_ROOT_OUT)/res/images/charger
-include $$(BUILD_PREBUILT)
-endef
-
-_img_modules :=
-_images :=
-$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \
-  $(eval $(call _add-charger-image,$(_img))))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := charger_res_images
-LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := $(_img_modules)
-include $(BUILD_PHONY_PACKAGE)
-
-_add-charger-image :=
-_img_modules :=
-endif # LOCAL_CHARGER_NO_UI
diff --git a/healthd/AnimationParser.cpp b/healthd/AnimationParser.cpp
index fde3b95..6b08570 100644
--- a/healthd/AnimationParser.cpp
+++ b/healthd/AnimationParser.cpp
@@ -37,8 +37,8 @@
     return true;
 }
 
-bool remove_prefix(const std::string& line, const char* prefix, const char** rest) {
-    const char* str = line.c_str();
+bool remove_prefix(std::string_view line, const char* prefix, const char** rest) {
+    const char* str = line.data();
     int start;
     char c;
 
diff --git a/healthd/AnimationParser.h b/healthd/AnimationParser.h
index bc00845..f55b563 100644
--- a/healthd/AnimationParser.h
+++ b/healthd/AnimationParser.h
@@ -17,6 +17,8 @@
 #ifndef HEALTHD_ANIMATION_PARSER_H
 #define HEALTHD_ANIMATION_PARSER_H
 
+#include <string_view>
+
 #include "animation.h"
 
 namespace android {
@@ -24,7 +26,7 @@
 bool parse_animation_desc(const std::string& content, animation* anim);
 
 bool can_ignore_line(const char* str);
-bool remove_prefix(const std::string& str, const char* prefix, const char** rest);
+bool remove_prefix(std::string_view str, const char* prefix, const char** rest);
 bool parse_text_field(const char* in, animation::text_field* field);
 }  // namespace android
 
diff --git a/healthd/tests/AnimationParser_test.cpp b/healthd/AnimationParser_test.cpp
similarity index 100%
rename from healthd/tests/AnimationParser_test.cpp
rename to healthd/AnimationParser_test.cpp
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 599f500..fd810cb 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -79,7 +79,7 @@
 
     // HIDL enum values are zero initialized, so they need to be initialized
     // properly.
-    health_info_2_1->batteryCapacityLevel = BatteryCapacityLevel::UNKNOWN;
+    health_info_2_1->batteryCapacityLevel = BatteryCapacityLevel::UNSUPPORTED;
     health_info_2_1->batteryChargeTimeToFullNowSeconds =
             (int64_t)Constants::BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED;
     auto* props = &health_info_2_1->legacy.legacy;
diff --git a/healthd/TEST_MAPPING b/healthd/TEST_MAPPING
new file mode 100644
index 0000000..5893d10
--- /dev/null
+++ b/healthd/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "libhealthd_charger_test"
+    }
+  ]
+}
diff --git a/healthd/animation.h b/healthd/animation.h
index d02d7a7..c2d5f1c 100644
--- a/healthd/animation.h
+++ b/healthd/animation.h
@@ -18,6 +18,7 @@
 #define HEALTHD_ANIMATION_H
 
 #include <inttypes.h>
+
 #include <string>
 
 class GRSurface;
@@ -52,20 +53,11 @@
     // - When treating paths as relative paths, it adds ".png" suffix.
     // - When treating paths as absolute paths, it doesn't add the suffix. Hence, the suffix
     //   is added here.
-    void set_resource_root(const std::string& root) {
-        if (!animation_file.empty()) {
-            animation_file = root + animation_file + ".png";
-        }
-        if (!fail_file.empty()) {
-            fail_file = root + fail_file + ".png";
-        }
-        if (!text_clock.font_file.empty()) {
-            text_clock.font_file = root + text_clock.font_file + ".png";
-        }
-        if (!text_percent.font_file.empty()) {
-            text_percent.font_file = root + text_percent.font_file + ".png";
-        }
-    }
+    // If |backup_root| is provided, additionally check if file under |root| is accessbile or not.
+    // If not accessbile, use |backup_root| instead.
+    // Require that |root| starts and ends with "/". If |backup_root| is provided, require that
+    // |backup_root| starts and ends with "/".
+    void set_resource_root(const std::string& root, const std::string& backup_root = "");
 
     std::string animation_file;
     std::string fail_file;
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 386ba1a..e95efc0 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -33,7 +33,9 @@
 #include <optional>
 
 #include <android-base/file.h>
+#include <android-base/logging.h>
 #include <android-base/macros.h>
+#include <android-base/strings.h>
 
 #include <linux/netlink.h>
 #include <sys/socket.h>
@@ -58,6 +60,7 @@
 #include <health2impl/Health.h>
 #include <healthd/healthd.h>
 
+using std::string_literals::operator""s;
 using namespace android;
 using android::hardware::Return;
 using android::hardware::health::GetHealthServiceOrDefault;
@@ -103,7 +106,13 @@
 
 namespace android {
 
-// Resources in /product/etc/res overrides resources in /res.
+// Legacy animation resources are loaded from this directory.
+static constexpr const char* legacy_animation_root = "/res/images/";
+
+// Built-in animation resources are loaded from this directory.
+static constexpr const char* system_animation_root = "/system/etc/res/images/";
+
+// Resources in /product/etc/res overrides resources in /res and /system/etc/res.
 // If the device is using the Generic System Image (GSI), resources may exist in
 // both paths.
 static constexpr const char* product_animation_desc_path =
@@ -625,6 +634,12 @@
         batt_anim_.set_resource_root(product_animation_root);
     } else if (base::ReadFileToString(animation_desc_path, &content)) {
         parse_success = parse_animation_desc(content, &batt_anim_);
+        // Fallback resources always exist in system_animation_root. On legacy devices with an old
+        // ramdisk image, resources may be overridden under root. For example,
+        // /res/images/charger/battery_fail.png may not be the same as
+        // system/core/healthd/images/battery_fail.png in the source tree, but is a device-specific
+        // image. Hence, load from /res, and fall back to /system/etc/res.
+        batt_anim_.set_resource_root(legacy_animation_root, system_animation_root);
     } else {
         LOGW("Could not open animation description at %s\n", animation_desc_path);
         parse_success = false;
@@ -633,13 +648,13 @@
     if (!parse_success) {
         LOGW("Could not parse animation description. Using default animation.\n");
         batt_anim_ = BASE_ANIMATION;
-        batt_anim_.animation_file.assign("charger/battery_scale");
+        batt_anim_.animation_file.assign(system_animation_root + "charger/battery_scale.png"s);
         InitDefaultAnimationFrames();
         batt_anim_.frames = owned_frames_.data();
         batt_anim_.num_frames = owned_frames_.size();
     }
     if (batt_anim_.fail_file.empty()) {
-        batt_anim_.fail_file.assign("charger/battery_fail");
+        batt_anim_.fail_file.assign(system_animation_root + "charger/battery_fail.png"s);
     }
 
     LOGV("Animation Description:\n");
@@ -678,10 +693,11 @@
 
     InitAnimation();
 
-    ret = res_create_display_surface(batt_anim_.fail_file.c_str(), &surf_unknown_);
+    ret = CreateDisplaySurface(batt_anim_.fail_file, &surf_unknown_);
     if (ret < 0) {
         LOGE("Cannot load custom battery_fail image. Reverting to built in: %d\n", ret);
-        ret = res_create_display_surface("charger/battery_fail", &surf_unknown_);
+        ret = CreateDisplaySurface((system_animation_root + "charger/battery_fail.png"s).c_str(),
+                                   &surf_unknown_);
         if (ret < 0) {
             LOGE("Cannot load built in battery_fail image\n");
             surf_unknown_ = NULL;
@@ -692,8 +708,8 @@
     int scale_count;
     int scale_fps;  // Not in use (charger/battery_scale doesn't have FPS text
                     // chunk). We are using hard-coded frame.disp_time instead.
-    ret = res_create_multi_display_surface(batt_anim_.animation_file.c_str(), &scale_count,
-                                           &scale_fps, &scale_frames);
+    ret = CreateMultiDisplaySurface(batt_anim_.animation_file, &scale_count, &scale_fps,
+                                    &scale_frames);
     if (ret < 0) {
         LOGE("Cannot load battery_scale image\n");
         batt_anim_.num_frames = 0;
@@ -722,6 +738,43 @@
     boot_min_cap_ = config->boot_min_cap;
 }
 
+int Charger::CreateDisplaySurface(const std::string& name, GRSurface** surface) {
+    return res_create_display_surface(name.c_str(), surface);
+}
+
+int Charger::CreateMultiDisplaySurface(const std::string& name, int* frames, int* fps,
+                                       GRSurface*** surface) {
+    return res_create_multi_display_surface(name.c_str(), frames, fps, surface);
+}
+
+void set_resource_root_for(const std::string& root, const std::string& backup_root,
+                           std::string* value) {
+    if (value->empty()) {
+        return;
+    }
+
+    std::string new_value = root + *value + ".png";
+    // If |backup_root| is provided, additionally check whether the file under |root| is
+    // accessible or not. If not accessible, fallback to file under |backup_root|.
+    if (!backup_root.empty() && access(new_value.data(), F_OK) == -1) {
+        new_value = backup_root + *value + ".png";
+    }
+
+    *value = new_value;
+}
+
+void animation::set_resource_root(const std::string& root, const std::string& backup_root) {
+    CHECK(android::base::StartsWith(root, "/") && android::base::EndsWith(root, "/"))
+            << "animation root " << root << " must start and end with /";
+    CHECK(backup_root.empty() || (android::base::StartsWith(backup_root, "/") &&
+                                  android::base::EndsWith(backup_root, "/")))
+            << "animation backup root " << backup_root << " must start and end with /";
+    set_resource_root_for(root, backup_root, &animation_file);
+    set_resource_root_for(root, backup_root, &fail_file);
+    set_resource_root_for(root, backup_root, &text_clock.font_file);
+    set_resource_root_for(root, backup_root, &text_percent.font_file);
+}
+
 }  // namespace android
 
 int healthd_charger_main(int argc, char** argv) {
diff --git a/healthd/healthd_mode_charger.h b/healthd/healthd_mode_charger.h
index 6e569ee..6f9ae8c 100644
--- a/healthd/healthd_mode_charger.h
+++ b/healthd/healthd_mode_charger.h
@@ -53,6 +53,11 @@
     // HalHealthLoop overrides
     void OnHealthInfoChanged(const HealthInfo_2_1& health_info) override;
 
+    // Allowed to be mocked for testing.
+    virtual int CreateDisplaySurface(const std::string& name, GRSurface** surface);
+    virtual int CreateMultiDisplaySurface(const std::string& name, int* frames, int* fps,
+                                          GRSurface*** surface);
+
   private:
     void InitDefaultAnimationFrames();
     void UpdateScreenState(int64_t now);
diff --git a/healthd/healthd_mode_charger_test.cpp b/healthd/healthd_mode_charger_test.cpp
new file mode 100644
index 0000000..f444f66
--- /dev/null
+++ b/healthd/healthd_mode_charger_test.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <sysexits.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <health/utils.h>
+
+#include "healthd_mode_charger.h"
+
+using android::hardware::Return;
+using android::hardware::health::InitHealthdConfig;
+using std::string_literals::operator""s;
+using testing::_;
+using testing::Invoke;
+using testing::NiceMock;
+using testing::StrEq;
+using testing::Test;
+
+namespace android {
+
+// A replacement to ASSERT_* to be used in a forked process. When the condition is not met,
+// print a gtest message, then exit abnormally.
+class ChildAssertHelper : public std::stringstream {
+  public:
+    ChildAssertHelper(bool res, const char* expr, const char* file, int line) : res_(res) {
+        (*this) << file << ":" << line << ": `" << expr << "` evaluates to false\n";
+    }
+    ~ChildAssertHelper() {
+        EXPECT_TRUE(res_) << str();
+        if (!res_) exit(EX_SOFTWARE);
+    }
+
+  private:
+    bool res_;
+    DISALLOW_COPY_AND_ASSIGN(ChildAssertHelper);
+};
+#define CHILD_ASSERT_TRUE(expr) ChildAssertHelper(expr, #expr, __FILE__, __LINE__)
+
+// Run |test_body| in a chroot jail in a forked process. |subdir| is a sub-directory in testdata.
+// Within |test_body|,
+// - non-fatal errors may be reported using EXPECT_* macro as usual.
+// - fatal errors must be reported using CHILD_ASSERT_TRUE macro. ASSERT_* must not be used.
+void ForkTest(const std::string& subdir, const std::function<void(void)>& test_body) {
+    pid_t pid = fork();
+    ASSERT_GE(pid, 0) << "Fork fails: " << strerror(errno);
+    if (pid == 0) {
+        // child
+        CHILD_ASSERT_TRUE(
+                chroot((android::base::GetExecutableDirectory() + "/" + subdir).c_str()) != -1)
+                << "Failed to chroot to " << subdir << ": " << strerror(errno);
+        test_body();
+        // EXPECT_* macros may set the HasFailure bit without calling exit(). Set exit status
+        // accordingly.
+        exit(::testing::Test::HasFailure() ? EX_SOFTWARE : EX_OK);
+    }
+    // parent
+    int status;
+    ASSERT_NE(-1, waitpid(pid, &status, 0)) << "waitpid() fails: " << strerror(errno);
+    ASSERT_TRUE(WIFEXITED(status)) << "Test fails, waitpid() returns " << status;
+    ASSERT_EQ(EX_OK, WEXITSTATUS(status)) << "Test fails, child process returns " << status;
+}
+
+class MockHealth : public android::hardware::health::V2_1::IHealth {
+    MOCK_METHOD(Return<::android::hardware::health::V2_0::Result>, registerCallback,
+                (const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback));
+    MOCK_METHOD(Return<::android::hardware::health::V2_0::Result>, unregisterCallback,
+                (const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback));
+    MOCK_METHOD(Return<::android::hardware::health::V2_0::Result>, update, ());
+    MOCK_METHOD(Return<void>, getChargeCounter, (getChargeCounter_cb _hidl_cb));
+    MOCK_METHOD(Return<void>, getCurrentNow, (getCurrentNow_cb _hidl_cb));
+    MOCK_METHOD(Return<void>, getCurrentAverage, (getCurrentAverage_cb _hidl_cb));
+    MOCK_METHOD(Return<void>, getCapacity, (getCapacity_cb _hidl_cb));
+    MOCK_METHOD(Return<void>, getEnergyCounter, (getEnergyCounter_cb _hidl_cb));
+    MOCK_METHOD(Return<void>, getChargeStatus, (getChargeStatus_cb _hidl_cb));
+    MOCK_METHOD(Return<void>, getStorageInfo, (getStorageInfo_cb _hidl_cb));
+    MOCK_METHOD(Return<void>, getDiskStats, (getDiskStats_cb _hidl_cb));
+    MOCK_METHOD(Return<void>, getHealthInfo, (getHealthInfo_cb _hidl_cb));
+    MOCK_METHOD(Return<void>, getHealthConfig, (getHealthConfig_cb _hidl_cb));
+    MOCK_METHOD(Return<void>, getHealthInfo_2_1, (getHealthInfo_2_1_cb _hidl_cb));
+    MOCK_METHOD(Return<void>, shouldKeepScreenOn, (shouldKeepScreenOn_cb _hidl_cb));
+};
+
+class TestCharger : public Charger {
+  public:
+    // Inherit constructor.
+    using Charger::Charger;
+    // Expose protected functions to be used in tests.
+    void Init(struct healthd_config* config) override { Charger::Init(config); }
+    MOCK_METHOD(int, CreateDisplaySurface, (const std::string& name, GRSurface** surface));
+    MOCK_METHOD(int, CreateMultiDisplaySurface,
+                (const std::string& name, int* frames, int* fps, GRSurface*** surface));
+};
+
+// Intentionally leak TestCharger instance to avoid calling ~HealthLoop() because ~HealthLoop()
+// should never be called. But still verify expected calls upon destruction.
+class VerifiedTestCharger {
+  public:
+    VerifiedTestCharger(TestCharger* charger) : charger_(charger) {
+        testing::Mock::AllowLeak(charger_);
+    }
+    TestCharger& operator*() { return *charger_; }
+    TestCharger* operator->() { return charger_; }
+    ~VerifiedTestCharger() { testing::Mock::VerifyAndClearExpectations(charger_); }
+
+  private:
+    TestCharger* charger_;
+};
+
+// Do not use SetUp and TearDown of a test suite, as they will be invoked in the parent process, not
+// the child process. In particular, if the test suite contains mocks, they will not be verified in
+// the child process. Instead, create mocks within closures in each tests.
+void ExpectChargerResAt(const std::string& root) {
+    sp<NiceMock<MockHealth>> health(new NiceMock<MockHealth>());
+    VerifiedTestCharger charger(new NiceMock<TestCharger>(health));
+
+    // Only one frame in all testdata/**/animation.txt
+    GRSurface* multi[] = {nullptr};
+
+    EXPECT_CALL(*charger, CreateDisplaySurface(StrEq(root + "charger/battery_fail.png"), _))
+            .WillRepeatedly(Invoke([](const auto&, GRSurface** surface) {
+                *surface = nullptr;
+                return 0;
+            }));
+    EXPECT_CALL(*charger,
+                CreateMultiDisplaySurface(StrEq(root + "charger/battery_scale.png"), _, _, _))
+            .WillRepeatedly(Invoke([&](const auto&, int* frames, int* fps, GRSurface*** surface) {
+                *frames = arraysize(multi);
+                *fps = 60;  // Unused fps value
+                *surface = multi;
+                return 0;
+            }));
+    struct healthd_config healthd_config;
+    InitHealthdConfig(&healthd_config);
+    charger->Init(&healthd_config);
+};
+
+// Test that if resources does not exist in /res or in /product/etc/res, load from /system.
+TEST(ChargerLoadAnimationRes, Empty) {
+    ForkTest("empty", std::bind(&ExpectChargerResAt, "/system/etc/res/images/"));
+}
+
+// Test loading everything from /res
+TEST(ChargerLoadAnimationRes, Legacy) {
+    ForkTest("legacy", std::bind(&ExpectChargerResAt, "/res/images/"));
+}
+
+// Test loading animation text from /res but images from /system if images does not exist under
+// /res.
+TEST(ChargerLoadAnimationRes, LegacyTextSystemImages) {
+    ForkTest("legacy_text_system_images",
+             std::bind(&ExpectChargerResAt, "/system/etc/res/images/"));
+}
+
+// Test loading everything from /product
+TEST(ChargerLoadAnimationRes, Product) {
+    ForkTest("product", std::bind(&ExpectChargerResAt, "/product/etc/res/images/"));
+}
+
+}  // namespace android
diff --git a/healthd/testdata/Android.bp b/healthd/testdata/Android.bp
new file mode 100644
index 0000000..110c79a
--- /dev/null
+++ b/healthd/testdata/Android.bp
@@ -0,0 +1,20 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+filegroup {
+    name: "libhealthd_charger_test_data",
+    srcs: ["**/*.*"],
+}
diff --git a/healthd/testdata/empty/ensure_directory_creation.txt b/healthd/testdata/empty/ensure_directory_creation.txt
new file mode 100644
index 0000000..36ceff4
--- /dev/null
+++ b/healthd/testdata/empty/ensure_directory_creation.txt
@@ -0,0 +1 @@
+File is placed to ensure directory is created on the device.
diff --git a/libpixelflinger/MODULE_LICENSE_APACHE2 b/healthd/testdata/legacy/res/images/charger/battery_fail.png
similarity index 100%
rename from libpixelflinger/MODULE_LICENSE_APACHE2
rename to healthd/testdata/legacy/res/images/charger/battery_fail.png
diff --git a/libpixelflinger/MODULE_LICENSE_APACHE2 b/healthd/testdata/legacy/res/images/charger/battery_scale.png
similarity index 100%
copy from libpixelflinger/MODULE_LICENSE_APACHE2
copy to healthd/testdata/legacy/res/images/charger/battery_scale.png
diff --git a/healthd/testdata/legacy/res/values/charger/animation.txt b/healthd/testdata/legacy/res/values/charger/animation.txt
new file mode 100644
index 0000000..0753336
--- /dev/null
+++ b/healthd/testdata/legacy/res/values/charger/animation.txt
@@ -0,0 +1,9 @@
+# Sample Animation file for testing.
+
+# animation: num_cycles, first_frame_repeats, animation_file
+animation: 2 1 charger/battery_scale
+
+fail: charger/battery_fail
+
+# frame: disp_time min_level max_level
+frame: 15 0 100
diff --git a/healthd/testdata/legacy_text_system_images/res/values/charger/animation.txt b/healthd/testdata/legacy_text_system_images/res/values/charger/animation.txt
new file mode 100644
index 0000000..0753336
--- /dev/null
+++ b/healthd/testdata/legacy_text_system_images/res/values/charger/animation.txt
@@ -0,0 +1,9 @@
+# Sample Animation file for testing.
+
+# animation: num_cycles, first_frame_repeats, animation_file
+animation: 2 1 charger/battery_scale
+
+fail: charger/battery_fail
+
+# frame: disp_time min_level max_level
+frame: 15 0 100
diff --git a/libpixelflinger/MODULE_LICENSE_APACHE2 b/healthd/testdata/product/product/etc/res/images/charger/battery_fail.png
similarity index 100%
copy from libpixelflinger/MODULE_LICENSE_APACHE2
copy to healthd/testdata/product/product/etc/res/images/charger/battery_fail.png
diff --git a/libpixelflinger/MODULE_LICENSE_APACHE2 b/healthd/testdata/product/product/etc/res/images/charger/battery_scale.png
similarity index 100%
copy from libpixelflinger/MODULE_LICENSE_APACHE2
copy to healthd/testdata/product/product/etc/res/images/charger/battery_scale.png
diff --git a/healthd/testdata/product/product/etc/res/values/charger/animation.txt b/healthd/testdata/product/product/etc/res/values/charger/animation.txt
new file mode 100644
index 0000000..0753336
--- /dev/null
+++ b/healthd/testdata/product/product/etc/res/values/charger/animation.txt
@@ -0,0 +1,9 @@
+# Sample Animation file for testing.
+
+# animation: num_cycles, first_frame_repeats, animation_file
+animation: 2 1 charger/battery_scale
+
+fail: charger/battery_fail
+
+# frame: disp_time min_level max_level
+frame: 15 0 100
diff --git a/healthd/tests/Android.mk b/healthd/tests/Android.mk
deleted file mode 100644
index 87e8862..0000000
--- a/healthd/tests/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2016 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    AnimationParser_test.cpp \
-
-LOCAL_MODULE := healthd_test
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_STATIC_LIBRARIES := \
-	libhealthd_internal \
-
-LOCAL_SHARED_LIBRARIES := \
-	liblog \
-	libbase \
-	libcutils \
-
-include $(BUILD_NATIVE_TEST)
diff --git a/include/private/android_filesystem_capability.h b/include/private/android_filesystem_capability.h
deleted file mode 120000
index f310b35..0000000
--- a/include/private/android_filesystem_capability.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libcutils/include/private/android_filesystem_capability.h
\ No newline at end of file
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
deleted file mode 120000
index f187a6d..0000000
--- a/include/private/android_logger.h
+++ /dev/null
@@ -1 +0,0 @@
-../../liblog/include/private/android_logger.h
\ No newline at end of file
diff --git a/include/private/canned_fs_config.h b/include/private/canned_fs_config.h
deleted file mode 120000
index 8f92b2d..0000000
--- a/include/private/canned_fs_config.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libcutils/include/private/canned_fs_config.h
\ No newline at end of file
diff --git a/include/private/fs_config.h b/include/private/fs_config.h
deleted file mode 100644
index e9868a4..0000000
--- a/include/private/fs_config.h
+++ /dev/null
@@ -1,4 +0,0 @@
-// TODO(b/63135587) remove this file after the transitive dependency
-// from private/android_filesystem_config.h is resolved. All files that use
-// libcutils/include/private/fs_config.h should include the file directly, not
-// indirectly via private/android_filesystem_config.h.
diff --git a/include/sysutils b/include/sysutils
deleted file mode 120000
index 1c8e85b..0000000
--- a/include/sysutils
+++ /dev/null
@@ -1 +0,0 @@
-../libsysutils/include/sysutils/
\ No newline at end of file
diff --git a/init/Android.bp b/init/Android.bp
index 3f2cd07..c3dd7f6 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -129,6 +129,7 @@
         "libprotobuf-cpp-lite",
         "libpropertyinfoserializer",
         "libpropertyinfoparser",
+        "libsnapshot_cow",
         "libsnapshot_init",
         "libxml2",
         "lib_apex_manifest_proto_lite",
diff --git a/init/Android.mk b/init/Android.mk
index da94daf..998e0fd 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -112,6 +112,7 @@
     libmodprobe \
     libext2_uuid \
     libprotobuf-cpp-lite \
+    libsnapshot_cow \
     libsnapshot_init \
     update_metadata-protos \
 
diff --git a/init/AndroidTest.xml b/init/AndroidTest.xml
index 17f509a..6f22ab7 100644
--- a/init/AndroidTest.xml
+++ b/init/AndroidTest.xml
@@ -32,4 +32,7 @@
         <option name="module-name" value="CtsInitTestCases" />
         <option name="runtime-hint" value="65s" />
     </test>
+    <!-- Controller that will skip the module if a native bridge situation is detected -->
+    <!-- For example: module wants to run arm32 and device is x86 -->
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.NativeBridgeModuleController" />
 </configuration>
diff --git a/init/README.ueventd.md b/init/README.ueventd.md
index 053ebf8..4363f3c 100644
--- a/init/README.ueventd.md
+++ b/init/README.ueventd.md
@@ -86,6 +86,8 @@
 for a file matching the uevent `FIRMWARE`. It then forks a process to serve this firmware to the
 kernel.
 
+`/apex/*/etc/firmware` is also searched after a list of firmware directories.
+
 The list of firmware directories is customized by a `firmware_directories` line in a ueventd.rc
 file. This line takes the format of
 
diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp
index b423f86..8db9793 100644
--- a/init/block_dev_initializer.cpp
+++ b/init/block_dev_initializer.cpp
@@ -37,7 +37,15 @@
 }
 
 bool BlockDevInitializer::InitDeviceMapper() {
-    const std::string dm_path = "/devices/virtual/misc/device-mapper";
+    return InitMiscDevice("device-mapper");
+}
+
+bool BlockDevInitializer::InitDmUser() {
+    return InitMiscDevice("dm-user");
+}
+
+bool BlockDevInitializer::InitMiscDevice(const std::string& name) {
+    const std::string dm_path = "/devices/virtual/misc/" + name;
     bool found = false;
     auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
         if (uevent.path == dm_path) {
@@ -49,13 +57,13 @@
     };
     uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
     if (!found) {
-        LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent";
+        LOG(INFO) << name << " device not found in /sys, waiting for its uevent";
         Timer t;
         uevent_listener_.Poll(dm_callback, 10s);
-        LOG(INFO) << "Wait for device-mapper returned after " << t;
+        LOG(INFO) << "Wait for " << name << " returned after " << t;
     }
     if (!found) {
-        LOG(ERROR) << "device-mapper device not found after polling timeout";
+        LOG(ERROR) << name << " device not found after polling timeout";
         return false;
     }
     return true;
diff --git a/init/block_dev_initializer.h b/init/block_dev_initializer.h
index 0d4c6e9..b8dd3f1 100644
--- a/init/block_dev_initializer.h
+++ b/init/block_dev_initializer.h
@@ -27,12 +27,15 @@
     BlockDevInitializer();
 
     bool InitDeviceMapper();
+    bool InitDmUser();
     bool InitDevices(std::set<std::string> devices);
     bool InitDmDevice(const std::string& device);
 
   private:
     ListenerAction HandleUevent(const Uevent& uevent, std::set<std::string>* devices);
 
+    bool InitMiscDevice(const std::string& name);
+
     std::unique_ptr<DeviceHandler> device_handler_;
     UeventListener uevent_listener_;
 };
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 0b456e7..d00d1b1 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -570,7 +570,6 @@
             trigger_shutdown("reboot,requested-userdata-remount-on-fde-device");
         }
         SetProperty("ro.crypto.state", "encrypted");
-        SetProperty("ro.crypto.type", "block");
         ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
         return {};
     } else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
@@ -595,7 +594,6 @@
             return Error() << "FscryptInstallKeyring() failed";
         }
         SetProperty("ro.crypto.state", "encrypted");
-        SetProperty("ro.crypto.type", "file");
 
         // Although encrypted, we have device key, so we do not need to
         // do anything different from the nonencrypted case.
@@ -606,7 +604,6 @@
             return Error() << "FscryptInstallKeyring() failed";
         }
         SetProperty("ro.crypto.state", "encrypted");
-        SetProperty("ro.crypto.type", "file");
 
         // Although encrypted, vold has already set the device up, so we do not need to
         // do anything different from the nonencrypted case.
@@ -617,7 +614,6 @@
             return Error() << "FscryptInstallKeyring() failed";
         }
         SetProperty("ro.crypto.state", "encrypted");
-        SetProperty("ro.crypto.type", "file");
 
         // Although encrypted, vold has already set the device up, so we do not need to
         // do anything different from the nonencrypted case.
@@ -666,18 +662,26 @@
         }
     }
 
-    auto mount_fstab_return_code = fs_mgr_mount_all(&fstab, mount_all->mode);
+    auto mount_fstab_result = fs_mgr_mount_all(&fstab, mount_all->mode);
     SetProperty(prop_name, std::to_string(t.duration().count()));
 
     if (mount_all->import_rc) {
         import_late(mount_all->rc_paths);
     }
 
+    if (mount_fstab_result.userdata_mounted) {
+        // This call to fs_mgr_mount_all mounted userdata. Keep the result in
+        // order for userspace reboot to correctly remount userdata.
+        LOG(INFO) << "Userdata mounted using "
+                  << (mount_all->fstab_path.empty() ? "(default fstab)" : mount_all->fstab_path)
+                  << " result : " << mount_fstab_result.code;
+        initial_mount_fstab_return_code = mount_fstab_result.code;
+    }
+
     if (queue_event) {
         /* queue_fs_event will queue event based on mount_fstab return code
          * and return processed return code*/
-        initial_mount_fstab_return_code = mount_fstab_return_code;
-        auto queue_fs_result = queue_fs_event(mount_fstab_return_code, false);
+        auto queue_fs_result = queue_fs_event(mount_fstab_result.code, false);
         if (!queue_fs_result.ok()) {
             return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
         }
@@ -1177,6 +1181,10 @@
     }
     // TODO(b/135984674): check that fstab contains /data.
     if (auto rc = fs_mgr_remount_userdata_into_checkpointing(&fstab); rc < 0) {
+        std::string proc_mounts_output;
+        android::base::ReadFileToString("/proc/mounts", &proc_mounts_output, true);
+        android::base::WriteStringToFile(proc_mounts_output,
+                                         "/metadata/userspacereboot/mount_info.txt");
         trigger_shutdown("reboot,mount_userdata_failed");
     }
     if (auto result = queue_fs_event(initial_mount_fstab_return_code, true); !result.ok()) {
diff --git a/init/capabilities.cpp b/init/capabilities.cpp
index a91cd1d..0b9f161 100644
--- a/init/capabilities.cpp
+++ b/init/capabilities.cpp
@@ -28,47 +28,55 @@
 namespace init {
 
 static const std::map<std::string, int> cap_map = {
-    CAP_MAP_ENTRY(CHOWN),
-    CAP_MAP_ENTRY(DAC_OVERRIDE),
-    CAP_MAP_ENTRY(DAC_READ_SEARCH),
-    CAP_MAP_ENTRY(FOWNER),
-    CAP_MAP_ENTRY(FSETID),
-    CAP_MAP_ENTRY(KILL),
-    CAP_MAP_ENTRY(SETGID),
-    CAP_MAP_ENTRY(SETUID),
-    CAP_MAP_ENTRY(SETPCAP),
-    CAP_MAP_ENTRY(LINUX_IMMUTABLE),
-    CAP_MAP_ENTRY(NET_BIND_SERVICE),
-    CAP_MAP_ENTRY(NET_BROADCAST),
-    CAP_MAP_ENTRY(NET_ADMIN),
-    CAP_MAP_ENTRY(NET_RAW),
-    CAP_MAP_ENTRY(IPC_LOCK),
-    CAP_MAP_ENTRY(IPC_OWNER),
-    CAP_MAP_ENTRY(SYS_MODULE),
-    CAP_MAP_ENTRY(SYS_RAWIO),
-    CAP_MAP_ENTRY(SYS_CHROOT),
-    CAP_MAP_ENTRY(SYS_PTRACE),
-    CAP_MAP_ENTRY(SYS_PACCT),
-    CAP_MAP_ENTRY(SYS_ADMIN),
-    CAP_MAP_ENTRY(SYS_BOOT),
-    CAP_MAP_ENTRY(SYS_NICE),
-    CAP_MAP_ENTRY(SYS_RESOURCE),
-    CAP_MAP_ENTRY(SYS_TIME),
-    CAP_MAP_ENTRY(SYS_TTY_CONFIG),
-    CAP_MAP_ENTRY(MKNOD),
-    CAP_MAP_ENTRY(LEASE),
-    CAP_MAP_ENTRY(AUDIT_WRITE),
-    CAP_MAP_ENTRY(AUDIT_CONTROL),
-    CAP_MAP_ENTRY(SETFCAP),
-    CAP_MAP_ENTRY(MAC_OVERRIDE),
-    CAP_MAP_ENTRY(MAC_ADMIN),
-    CAP_MAP_ENTRY(SYSLOG),
-    CAP_MAP_ENTRY(WAKE_ALARM),
-    CAP_MAP_ENTRY(BLOCK_SUSPEND),
-    CAP_MAP_ENTRY(AUDIT_READ),
+        CAP_MAP_ENTRY(CHOWN),
+        CAP_MAP_ENTRY(DAC_OVERRIDE),
+        CAP_MAP_ENTRY(DAC_READ_SEARCH),
+        CAP_MAP_ENTRY(FOWNER),
+        CAP_MAP_ENTRY(FSETID),
+        CAP_MAP_ENTRY(KILL),
+        CAP_MAP_ENTRY(SETGID),
+        CAP_MAP_ENTRY(SETUID),
+        CAP_MAP_ENTRY(SETPCAP),
+        CAP_MAP_ENTRY(LINUX_IMMUTABLE),
+        CAP_MAP_ENTRY(NET_BIND_SERVICE),
+        CAP_MAP_ENTRY(NET_BROADCAST),
+        CAP_MAP_ENTRY(NET_ADMIN),
+        CAP_MAP_ENTRY(NET_RAW),
+        CAP_MAP_ENTRY(IPC_LOCK),
+        CAP_MAP_ENTRY(IPC_OWNER),
+        CAP_MAP_ENTRY(SYS_MODULE),
+        CAP_MAP_ENTRY(SYS_RAWIO),
+        CAP_MAP_ENTRY(SYS_CHROOT),
+        CAP_MAP_ENTRY(SYS_PTRACE),
+        CAP_MAP_ENTRY(SYS_PACCT),
+        CAP_MAP_ENTRY(SYS_ADMIN),
+        CAP_MAP_ENTRY(SYS_BOOT),
+        CAP_MAP_ENTRY(SYS_NICE),
+        CAP_MAP_ENTRY(SYS_RESOURCE),
+        CAP_MAP_ENTRY(SYS_TIME),
+        CAP_MAP_ENTRY(SYS_TTY_CONFIG),
+        CAP_MAP_ENTRY(MKNOD),
+        CAP_MAP_ENTRY(LEASE),
+        CAP_MAP_ENTRY(AUDIT_WRITE),
+        CAP_MAP_ENTRY(AUDIT_CONTROL),
+        CAP_MAP_ENTRY(SETFCAP),
+        CAP_MAP_ENTRY(MAC_OVERRIDE),
+        CAP_MAP_ENTRY(MAC_ADMIN),
+        CAP_MAP_ENTRY(SYSLOG),
+        CAP_MAP_ENTRY(WAKE_ALARM),
+        CAP_MAP_ENTRY(BLOCK_SUSPEND),
+        CAP_MAP_ENTRY(AUDIT_READ),
+#if defined(__BIONIC__)
+        CAP_MAP_ENTRY(PERFMON),
+        CAP_MAP_ENTRY(BPF),
+#endif
 };
 
+#if defined(__BIONIC__)
+static_assert(CAP_LAST_CAP == CAP_BPF, "CAP_LAST_CAP is not CAP_BPF");
+#else
 static_assert(CAP_LAST_CAP == CAP_AUDIT_READ, "CAP_LAST_CAP is not CAP_AUDIT_READ");
+#endif
 
 static bool ComputeCapAmbientSupported() {
 #if defined(__ANDROID__)
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index dff7b69..ba7e6bd 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -17,6 +17,7 @@
 #include "firmware_handler.h"
 
 #include <fcntl.h>
+#include <glob.h>
 #include <pwd.h>
 #include <signal.h>
 #include <stdlib.h>
@@ -30,6 +31,7 @@
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 
@@ -203,25 +205,28 @@
     }
 
     std::vector<std::string> attempted_paths_and_errors;
-
-    int booting = IsBooting();
-try_loading_again:
-    attempted_paths_and_errors.clear();
-    for (const auto& firmware_directory : firmware_directories_) {
+    auto TryLoadFirmware = [&](const std::string& firmware_directory) {
         std::string file = firmware_directory + firmware;
         unique_fd fw_fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
         if (fw_fd == -1) {
             attempted_paths_and_errors.emplace_back("firmware: attempted " + file +
                                                     ", open failed: " + strerror(errno));
-            continue;
+            return false;
         }
         struct stat sb;
         if (fstat(fw_fd, &sb) == -1) {
             attempted_paths_and_errors.emplace_back("firmware: attempted " + file +
                                                     ", fstat failed: " + strerror(errno));
-            continue;
+            return false;
         }
         LoadFirmware(firmware, root, fw_fd, sb.st_size, loading_fd, data_fd);
+        return true;
+    };
+
+    int booting = IsBooting();
+try_loading_again:
+    attempted_paths_and_errors.clear();
+    if (ForEachFirmwareDirectory(TryLoadFirmware)) {
         return;
     }
 
@@ -242,6 +247,33 @@
     write(loading_fd, "-1", 2);
 }
 
+bool FirmwareHandler::ForEachFirmwareDirectory(
+        std::function<bool(const std::string&)> handler) const {
+    for (const std::string& firmware_directory : firmware_directories_) {
+        if (std::invoke(handler, firmware_directory)) {
+            return true;
+        }
+    }
+
+    glob_t glob_result;
+    glob("/apex/*/etc/firmware/", GLOB_MARK, nullptr, &glob_result);
+    auto free_glob = android::base::make_scope_guard(std::bind(&globfree, &glob_result));
+    for (size_t i = 0; i < glob_result.gl_pathc; i++) {
+        char* apex_firmware_directory = glob_result.gl_pathv[i];
+        // Filter-out /apex/<name>@<ver> paths. The paths are bind-mounted to
+        // /apex/<name> paths, so unless we filter them out, we will look into the
+        // same apex twice.
+        if (strchr(apex_firmware_directory, '@')) {
+            continue;
+        }
+        if (std::invoke(handler, apex_firmware_directory)) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 void FirmwareHandler::HandleUevent(const Uevent& uevent) {
     if (uevent.subsystem != "firmware" || uevent.action != "add") return;
 
diff --git a/init/firmware_handler.h b/init/firmware_handler.h
index b4138f1..8b758ae 100644
--- a/init/firmware_handler.h
+++ b/init/firmware_handler.h
@@ -18,6 +18,7 @@
 
 #include <pwd.h>
 
+#include <functional>
 #include <string>
 #include <vector>
 
@@ -52,6 +53,7 @@
                                            const Uevent& uevent) const;
     std::string GetFirmwarePath(const Uevent& uevent) const;
     void ProcessFirmwareEvent(const std::string& root, const std::string& firmware) const;
+    bool ForEachFirmwareDirectory(std::function<bool(const std::string&)> handler) const;
 
     std::vector<std::string> firmware_directories_;
     std::vector<ExternalFirmwareHandler> external_firmware_handlers_;
diff --git a/init/init.cpp b/init/init.cpp
index ba880ea..7d00538 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -18,6 +18,7 @@
 
 #include <dirent.h>
 #include <fcntl.h>
+#include <paths.h>
 #include <pthread.h>
 #include <signal.h>
 #include <stdlib.h>
@@ -309,14 +310,14 @@
         // late_import is available only in Q and earlier release. As we don't
         // have system_ext in those versions, skip late_import for system_ext.
         parser.ParseConfig("/system_ext/etc/init");
-        if (!parser.ParseConfig("/product/etc/init")) {
-            late_import_paths.emplace_back("/product/etc/init");
+        if (!parser.ParseConfig("/vendor/etc/init")) {
+            late_import_paths.emplace_back("/vendor/etc/init");
         }
         if (!parser.ParseConfig("/odm/etc/init")) {
             late_import_paths.emplace_back("/odm/etc/init");
         }
-        if (!parser.ParseConfig("/vendor/etc/init")) {
-            late_import_paths.emplace_back("/vendor/etc/init");
+        if (!parser.ParseConfig("/product/etc/init")) {
+            late_import_paths.emplace_back("/product/etc/init");
         }
     } else {
         parser.ParseConfig(bootscript);
@@ -727,6 +728,12 @@
     InitSecondStageLogging(argv);
     LOG(INFO) << "init second stage started!";
 
+    // Update $PATH in the case the second stage init is newer than first stage init, where it is
+    // first set.
+    if (setenv("PATH", _PATH_DEFPATH, 1) != 0) {
+        PLOG(FATAL) << "Could not set $PATH to '" << _PATH_DEFPATH << "' in second stage";
+    }
+
     // Init should not crash because of a dependence on any other process, therefore we ignore
     // SIGPIPE and handle EPIPE at the call site directly.  Note that setting a signal to SIG_IGN
     // is inherited across exec, but custom signal handlers are not.  Since we do not want to
diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp
index 01abba8..46f8331 100644
--- a/init/mount_handler.cpp
+++ b/init/mount_handler.cpp
@@ -130,7 +130,11 @@
     char* buf = nullptr;
     size_t len = 0;
     while (getline(&buf, &len, fp_.get()) != -1) {
-        auto entry = ParseMount(std::string(buf));
+        auto buf_string = std::string(buf);
+        if (buf_string.find("/emulated") != std::string::npos) {
+            continue;
+        }
+        auto entry = ParseMount(buf_string);
         auto match = untouched.find(entry);
         if (match == untouched.end()) {
             touched.emplace_back(std::move(entry));
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index f8359bc..59cc140 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -44,50 +44,17 @@
 namespace init {
 namespace {
 
-static bool BindMount(const std::string& source, const std::string& mount_point,
-                      bool recursive = false) {
-    unsigned long mountflags = MS_BIND;
-    if (recursive) {
-        mountflags |= MS_REC;
-    }
-    if (mount(source.c_str(), mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
+static bool BindMount(const std::string& source, const std::string& mount_point) {
+    if (mount(source.c_str(), mount_point.c_str(), nullptr, MS_BIND | MS_REC, nullptr) == -1) {
         PLOG(ERROR) << "Failed to bind mount " << source;
         return false;
     }
     return true;
 }
 
-static bool MakeShared(const std::string& mount_point, bool recursive = false) {
-    unsigned long mountflags = MS_SHARED;
-    if (recursive) {
-        mountflags |= MS_REC;
-    }
+static bool ChangeMount(const std::string& mount_point, unsigned long mountflags) {
     if (mount(nullptr, mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
-        PLOG(ERROR) << "Failed to change propagation type to shared";
-        return false;
-    }
-    return true;
-}
-
-static bool MakeSlave(const std::string& mount_point, bool recursive = false) {
-    unsigned long mountflags = MS_SLAVE;
-    if (recursive) {
-        mountflags |= MS_REC;
-    }
-    if (mount(nullptr, mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
-        PLOG(ERROR) << "Failed to change propagation type to slave";
-        return false;
-    }
-    return true;
-}
-
-static bool MakePrivate(const std::string& mount_point, bool recursive = false) {
-    unsigned long mountflags = MS_PRIVATE;
-    if (recursive) {
-        mountflags |= MS_REC;
-    }
-    if (mount(nullptr, mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
-        PLOG(ERROR) << "Failed to change propagation type to private";
+        PLOG(ERROR) << "Failed to remount " << mount_point << " as " << std::hex << mountflags;
         return false;
     }
     return true;
@@ -225,17 +192,17 @@
     // needed for /foo/bar, then we will make /foo/bar as a mount point (by
     // bind-mounting by to itself) and set the propagation type of the mount
     // point to private.
-    if (!MakeShared("/", true /*recursive*/)) return false;
+    if (!ChangeMount("/", MS_SHARED | MS_REC)) return false;
 
     // /apex is a private mountpoint to give different sets of APEXes for
     // the bootstrap and default mount namespaces. The processes running with
     // the bootstrap namespace get APEXes from the read-only partition.
-    if (!(MakePrivate("/apex"))) return false;
+    if (!(ChangeMount("/apex", MS_PRIVATE))) return false;
 
     // /linkerconfig is a private mountpoint to give a different linker configuration
     // based on the mount namespace. Subdirectory will be bind-mounted based on current mount
     // namespace
-    if (!(MakePrivate("/linkerconfig"))) return false;
+    if (!(ChangeMount("/linkerconfig", MS_PRIVATE))) return false;
 
     // The two mount namespaces present challenges for scoped storage, because
     // vold, which is responsible for most of the mounting, lives in the
@@ -266,15 +233,15 @@
     if (!mkdir_recursive("/mnt/user", 0755)) return false;
     if (!mkdir_recursive("/mnt/installer", 0755)) return false;
     if (!mkdir_recursive("/mnt/androidwritable", 0755)) return false;
-    if (!(BindMount("/mnt/user", "/mnt/installer", true))) return false;
-    if (!(BindMount("/mnt/user", "/mnt/androidwritable", true))) return false;
+    if (!(BindMount("/mnt/user", "/mnt/installer"))) return false;
+    if (!(BindMount("/mnt/user", "/mnt/androidwritable"))) return false;
     // First, make /mnt/installer and /mnt/androidwritable a slave bind mount
-    if (!(MakeSlave("/mnt/installer"))) return false;
-    if (!(MakeSlave("/mnt/androidwritable"))) return false;
+    if (!(ChangeMount("/mnt/installer", MS_SLAVE))) return false;
+    if (!(ChangeMount("/mnt/androidwritable", MS_SLAVE))) return false;
     // Then, make it shared again - effectively creating a new peer group, that
     // will be inherited by new mount namespaces.
-    if (!(MakeShared("/mnt/installer"))) return false;
-    if (!(MakeShared("/mnt/androidwritable"))) return false;
+    if (!(ChangeMount("/mnt/installer", MS_SHARED))) return false;
+    if (!(ChangeMount("/mnt/androidwritable", MS_SHARED))) return false;
 
     bootstrap_ns_fd.reset(OpenMountNamespace());
     bootstrap_ns_id = GetMountNamespaceId();
diff --git a/init/perfboot.py b/init/perfboot.py
index 713290b..4b23ad2 100755
--- a/init/perfboot.py
+++ b/init/perfboot.py
@@ -349,9 +349,9 @@
     # Filter out invalid data.
     end_times = [get_last_value(record, end_tag) for record in record_list
                  if get_last_value(record, end_tag) != 0]
-    print 'mean: ', mean(end_times)
-    print 'median:', median(end_times)
-    print 'standard deviation:', stddev(end_times)
+    print 'mean:', int(round(mean(end_times))), 'ms'
+    print 'median:', int(round(median(end_times))), 'ms'
+    print 'standard deviation:', int(round(stddev(end_times))), 'ms'
 
 
 def do_iteration(device, interval_adjuster, event_tags_re, end_tag):
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 0c4a3c4..a1e0969 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -632,10 +632,11 @@
     char *key, *value, *eol, *sol, *tmp, *fn;
     size_t flen = 0;
 
-    static constexpr const char* const kVendorPathPrefixes[3] = {
+    static constexpr const char* const kVendorPathPrefixes[4] = {
             "/vendor",
             "/odm",
             "/vendor_dlkm",
+            "/odm_dlkm",
     };
 
     const char* context = kInitContext;
@@ -941,6 +942,7 @@
     // }
     load_properties_from_file("/vendor/build.prop", nullptr, &properties);
     load_properties_from_file("/vendor_dlkm/etc/build.prop", nullptr, &properties);
+    load_properties_from_file("/odm_dlkm/etc/build.prop", nullptr, &properties);
     load_properties_from_partition("odm", /* support_legacy_path_until */ 28);
     load_properties_from_partition("product", /* support_legacy_path_until */ 30);
 
@@ -992,7 +994,7 @@
                                       &property_infos)) {
             return;
         }
-        // Don't check for failure here, so we always have a sane list of properties.
+        // Don't check for failure here, since we don't always have all of these partitions.
         // E.g. In case of recovery, the vendor partition will not have mounted and we
         // still need the system / platform properties to function.
         if (access("/system_ext/etc/selinux/system_ext_property_contexts", R_OK) != -1) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 19e83cc..49baf9e 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -690,9 +690,12 @@
     // Reap subcontext pids.
     ReapAnyOutstandingChildren();
 
-    // 3. send volume shutdown to vold
+    // 3. send volume abort_fuse and volume shutdown to vold
     Service* vold_service = ServiceList::GetInstance().FindService("vold");
     if (vold_service != nullptr && vold_service->IsRunning()) {
+        // Manually abort FUSE connections, since the FUSE daemon is already dead
+        // at this point, and unmounting it might hang.
+        CallVdc("volume", "abort_fuse");
         CallVdc("volume", "shutdown");
         vold_service->Stop();
     } else {
@@ -804,11 +807,19 @@
     auto sigkill_timeout = GetMillisProperty("init.userspace_reboot.sigkill.timeoutmillis", 10s);
     LOG(INFO) << "Timeout to terminate services: " << sigterm_timeout.count() << "ms "
               << "Timeout to kill services: " << sigkill_timeout.count() << "ms";
+    std::string services_file_name = "/metadata/userspacereboot/services.txt";
+    const int flags = O_RDWR | O_CREAT | O_SYNC | O_APPEND | O_CLOEXEC;
     StopServicesAndLogViolations(stop_first, sigterm_timeout, true /* SIGTERM */);
     if (int r = StopServicesAndLogViolations(stop_first, sigkill_timeout, false /* SIGKILL */);
         r > 0) {
+        auto fd = unique_fd(TEMP_FAILURE_RETRY(open(services_file_name.c_str(), flags, 0666)));
+        android::base::WriteStringToFd("Post-data services still running: \n", fd);
+        for (const auto& s : stop_first) {
+            if (s->IsRunning()) {
+                android::base::WriteStringToFd(s->name() + "\n", fd);
+            }
+        }
         sub_reason = "sigkill";
-        // TODO(b/135984674): store information about offending services for debugging.
         return Error() << r << " post-data services are still running";
     }
     if (auto result = KillZramBackingDevice(); !result.ok()) {
@@ -822,8 +833,14 @@
     if (int r = StopServicesAndLogViolations(GetDebuggingServices(true /* only_post_data */),
                                              sigkill_timeout, false /* SIGKILL */);
         r > 0) {
+        auto fd = unique_fd(TEMP_FAILURE_RETRY(open(services_file_name.c_str(), flags, 0666)));
+        android::base::WriteStringToFd("Debugging services still running: \n", fd);
+        for (const auto& s : GetDebuggingServices(true)) {
+            if (s->IsRunning()) {
+                android::base::WriteStringToFd(s->name() + "\n", fd);
+            }
+        }
         sub_reason = "sigkill_debug";
-        // TODO(b/135984674): store information about offending services for debugging.
         return Error() << r << " debugging services are still running";
     }
     {
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index 05e632b..f2383d7 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -60,13 +60,14 @@
 Result<void> SetUpMountNamespace(bool remount_proc, bool remount_sys) {
     constexpr unsigned int kSafeFlags = MS_NODEV | MS_NOEXEC | MS_NOSUID;
 
-    // Recursively remount / as slave like zygote does so unmounting and mounting /proc
-    // doesn't interfere with the parent namespace's /proc mount. This will also
-    // prevent any other mounts/unmounts initiated by the service from interfering
-    // with the parent namespace but will still allow mount events from the parent
+    // Recursively remount / as MS_SLAVE like zygote does so that
+    // unmounting and mounting /proc doesn't interfere with the parent
+    // namespace's /proc mount. This will also prevent any other
+    // mounts/unmounts initiated by the service from interfering with the
+    // parent namespace but will still allow mount events from the parent
     // namespace to propagate to the child.
     if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) {
-        return ErrnoError() << "Could not remount(/) recursively as slave";
+        return ErrnoError() << "Could not remount(/) recursively as MS_SLAVE";
     }
 
     // umount() then mount() /proc and/or /sys
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 9d4ea8c..dc2455e 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -30,6 +30,7 @@
 
 #include "action.h"
 #include "builtins.h"
+#include "mount_namespace.h"
 #include "proto_utils.h"
 #include "util.h"
 
@@ -217,7 +218,13 @@
                 PLOG(FATAL) << "Could not set execcon for '" << context_ << "'";
             }
         }
-
+#if defined(__ANDROID__)
+        // subcontext init runs in "default" mount namespace
+        // so that it can access /apex/*
+        if (auto result = SwitchToMountNamespaceIfNeeded(NS_DEFAULT); !result.ok()) {
+            LOG(FATAL) << "Could not switch to \"default\" mount namespace: " << result.error();
+        }
+#endif
         auto init_path = GetExecutablePath();
         auto child_fd_string = std::to_string(child_fd);
         const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(),
diff --git a/init/sysprop/api/com.android.sysprop.init-latest.txt b/init/sysprop/api/com.android.sysprop.init-latest.txt
index c835b95..01f4e9a 100644
--- a/init/sysprop/api/com.android.sysprop.init-latest.txt
+++ b/init/sysprop/api/com.android.sysprop.init-latest.txt
@@ -1,8 +1,13 @@
 props {
   module: "android.sysprop.InitProperties"
   prop {
+    api_name: "is_userspace_reboot_supported"
+    prop_name: "init.userspace_reboot.is_supported"
+    integer_as_bool: true
+  }
+  prop {
     api_name: "userspace_reboot_in_progress"
-    scope: Public
+    access: ReadWrite
     prop_name: "sys.init.userspace_reboot.in_progress"
     integer_as_bool: true
   }
diff --git a/init/test_kill_services/init_kill_services_test.cpp b/init/test_kill_services/init_kill_services_test.cpp
index 7e543f2..66a3328 100644
--- a/init/test_kill_services/init_kill_services_test.cpp
+++ b/init/test_kill_services/init_kill_services_test.cpp
@@ -54,7 +54,7 @@
 TEST_P(InitKillServicesTest, KillCriticalProcesses) {
     ExpectKillingServiceRecovers(GetParam());
 
-    // sanity check init is still responding
+    // Ensure that init is still responding
     EXPECT_TRUE(SetProperty("test.death.test", "asdf"));
     EXPECT_EQ(GetProperty("test.death.test", ""), "asdf");
     EXPECT_TRUE(SetProperty("test.death.test", ""));
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index d8d9b36..7cd396a 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -95,20 +95,18 @@
     fcntl(device_fd_, F_SETFL, O_NONBLOCK);
 }
 
-bool UeventListener::ReadUevent(Uevent* uevent) const {
+ReadUeventResult UeventListener::ReadUevent(Uevent* uevent) const {
     char msg[UEVENT_MSG_LEN + 2];
     int n = uevent_kernel_multicast_recv(device_fd_, msg, UEVENT_MSG_LEN);
     if (n <= 0) {
         if (errno != EAGAIN && errno != EWOULDBLOCK) {
             PLOG(ERROR) << "Error reading from Uevent Fd";
         }
-        return false;
+        return ReadUeventResult::kFailed;
     }
     if (n >= UEVENT_MSG_LEN) {
         LOG(ERROR) << "Uevent overflowed buffer, discarding";
-        // Return true here even if we discard as we may have more uevents pending and we
-        // want to keep processing them.
-        return true;
+        return ReadUeventResult::kInvalid;
     }
 
     msg[n] = '\0';
@@ -116,7 +114,7 @@
 
     ParseEvent(msg, uevent);
 
-    return true;
+    return ReadUeventResult::kSuccess;
 }
 
 // RegenerateUevents*() walks parts of the /sys tree and pokes the uevent files to cause the kernel
@@ -137,7 +135,10 @@
         close(fd);
 
         Uevent uevent;
-        while (ReadUevent(&uevent)) {
+        ReadUeventResult result;
+        while ((result = ReadUevent(&uevent)) != ReadUeventResult::kFailed) {
+            // Skip processing the uevent if it is invalid.
+            if (result == ReadUeventResult::kInvalid) continue;
             if (callback(uevent) == ListenerAction::kStop) return ListenerAction::kStop;
         }
     }
@@ -212,7 +213,10 @@
             // We're non-blocking, so if we receive a poll event keep processing until
             // we have exhausted all uevent messages.
             Uevent uevent;
-            while (ReadUevent(&uevent)) {
+            ReadUeventResult result;
+            while ((result = ReadUevent(&uevent)) != ReadUeventResult::kFailed) {
+                // Skip processing the uevent if it is invalid.
+                if (result == ReadUeventResult::kInvalid) continue;
                 if (callback(uevent) == ListenerAction::kStop) return;
             }
         }
diff --git a/init/uevent_listener.h b/init/uevent_listener.h
index aea094e..2772860 100644
--- a/init/uevent_listener.h
+++ b/init/uevent_listener.h
@@ -27,7 +27,7 @@
 
 #include "uevent.h"
 
-#define UEVENT_MSG_LEN 2048
+#define UEVENT_MSG_LEN 8192
 
 namespace android {
 namespace init {
@@ -37,6 +37,12 @@
     kContinue,  // Continue regenerating uevents as we haven't seen the one(s) we're interested in.
 };
 
+enum class ReadUeventResult {
+    kSuccess = 0,  // Uevent was successfully read.
+    kFailed,       // Uevent reading has failed.
+    kInvalid,      // An Invalid Uevent was read (like say, the msg received is >= UEVENT_MSG_LEN).
+};
+
 using ListenerCallback = std::function<ListenerAction(const Uevent&)>;
 
 class UeventListener {
@@ -50,7 +56,7 @@
               const std::optional<std::chrono::milliseconds> relative_timeout = {}) const;
 
   private:
-    bool ReadUevent(Uevent* uevent) const;
+    ReadUeventResult ReadUevent(Uevent* uevent) const;
     ListenerAction RegenerateUeventsForDir(DIR* d, const ListenerCallback& callback) const;
 
     android::base::unique_fd device_fd_;
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index 038b59e..a506575 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -37,6 +37,12 @@
 #include "ThreadEntry.h"
 
 bool BacktraceCurrent::ReadWord(uint64_t ptr, word_t* out_value) {
+#if defined(__aarch64__)
+  // Tagged pointer after Android R would lead top byte to have random values
+  // https://source.android.com/devices/tech/debug/tagged-pointers
+  ptr &= (1ULL << 56) - 1;
+#endif
+
   if (!VerifyReadWordArgs(ptr, out_value)) {
     return false;
   }
@@ -54,6 +60,12 @@
 }
 
 size_t BacktraceCurrent::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
+#if defined(__aarch64__)
+  // Tagged pointer after Android R would lead top byte to have random values
+  // https://source.android.com/devices/tech/debug/tagged-pointers
+  addr &= (1ULL << 56) - 1;
+#endif
+
   backtrace_map_t map;
   FillInMap(addr, &map);
   if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index 624711f..82ff21c 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -52,11 +52,11 @@
   unwinder.SetResolveNames(stack_map->ResolveNames());
   stack_map->SetArch(regs->Arch());
   if (stack_map->GetJitDebug() != nullptr) {
-    unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
+    unwinder.SetJitDebug(stack_map->GetJitDebug());
   }
 #if !defined(NO_LIBDEXFILE_SUPPORT)
   if (stack_map->GetDexFiles() != nullptr) {
-    unwinder.SetDexFiles(stack_map->GetDexFiles(), regs->Arch());
+    unwinder.SetDexFiles(stack_map->GetDexFiles());
   }
 #endif
   unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore());
@@ -180,5 +180,10 @@
 }
 
 size_t UnwindStackPtrace::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
+#if defined(__aarch64__)
+  // Tagged pointer after Android R would lead top byte to have random values
+  // https://source.android.com/devices/tech/debug/tagged-pointers
+  addr &= (1ULL << 56) - 1;
+#endif
   return memory_->Read(addr, buffer, bytes);
 }
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index f4191b9..cc32b6d 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -1584,7 +1584,7 @@
   // Verify the flag is set.
   ASSERT_EQ(PROT_DEVICE_MAP, map.flags & PROT_DEVICE_MAP);
 
-  // Quick sanity checks.
+  // Quick basic checks of functionality.
   uint64_t offset;
   ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset));
   ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset, &map));
diff --git a/libcrypto_utils/.clang-format b/libcrypto_utils/.clang-format
new file mode 120000
index 0000000..fd0645f
--- /dev/null
+++ b/libcrypto_utils/.clang-format
@@ -0,0 +1 @@
+../.clang-format-2
\ No newline at end of file
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
index d7175e0..923b291 100644
--- a/libcrypto_utils/Android.bp
+++ b/libcrypto_utils/Android.bp
@@ -23,7 +23,7 @@
     },
     host_supported: true,
     srcs: [
-        "android_pubkey.c",
+        "android_pubkey.cpp",
     ],
     cflags: [
         "-Wall",
diff --git a/libcrypto_utils/android_pubkey.c b/libcrypto_utils/android_pubkey.cpp
similarity index 65%
rename from libcrypto_utils/android_pubkey.c
rename to libcrypto_utils/android_pubkey.cpp
index 3052e52..21e5663 100644
--- a/libcrypto_utils/android_pubkey.c
+++ b/libcrypto_utils/android_pubkey.cpp
@@ -35,37 +35,29 @@
 // little-endian 32 bit words. Note that Android only supports little-endian
 // processors, so we don't do any byte order conversions when parsing the binary
 // struct.
-typedef struct RSAPublicKey {
-    // Modulus length. This must be ANDROID_PUBKEY_MODULUS_SIZE.
-    uint32_t modulus_size_words;
+struct RSAPublicKey {
+  // Modulus length. This must be ANDROID_PUBKEY_MODULUS_SIZE.
+  uint32_t modulus_size_words;
 
-    // Precomputed montgomery parameter: -1 / n[0] mod 2^32
-    uint32_t n0inv;
+  // Precomputed montgomery parameter: -1 / n[0] mod 2^32
+  uint32_t n0inv;
 
-    // RSA modulus as a little-endian array.
-    uint8_t modulus[ANDROID_PUBKEY_MODULUS_SIZE];
+  // RSA modulus as a little-endian array.
+  uint8_t modulus[ANDROID_PUBKEY_MODULUS_SIZE];
 
-    // Montgomery parameter R^2 as a little-endian array of little-endian words.
-    uint8_t rr[ANDROID_PUBKEY_MODULUS_SIZE];
+  // Montgomery parameter R^2 as a little-endian array.
+  uint8_t rr[ANDROID_PUBKEY_MODULUS_SIZE];
 
-    // RSA modulus: 3 or 65537
-    uint32_t exponent;
-} RSAPublicKey;
-
-// Reverses byte order in |buffer|.
-static void reverse_bytes(uint8_t* buffer, size_t size) {
-  for (size_t i = 0; i < (size + 1) / 2; ++i) {
-    uint8_t tmp = buffer[i];
-    buffer[i] = buffer[size - i - 1];
-    buffer[size - i - 1] = tmp;
-  }
-}
+  // RSA modulus: 3 or 65537
+  uint32_t exponent;
+};
 
 bool android_pubkey_decode(const uint8_t* key_buffer, size_t size, RSA** key) {
   const RSAPublicKey* key_struct = (RSAPublicKey*)key_buffer;
   bool ret = false;
-  uint8_t modulus_buffer[ANDROID_PUBKEY_MODULUS_SIZE];
   RSA* new_key = RSA_new();
+  BIGNUM* n = NULL;
+  BIGNUM* e = NULL;
   if (!new_key) {
     goto cleanup;
   }
@@ -79,19 +71,24 @@
   }
 
   // Convert the modulus to big-endian byte order as expected by BN_bin2bn.
-  memcpy(modulus_buffer, key_struct->modulus, sizeof(modulus_buffer));
-  reverse_bytes(modulus_buffer, sizeof(modulus_buffer));
-  new_key->n = BN_bin2bn(modulus_buffer, sizeof(modulus_buffer), NULL);
-  if (!new_key->n) {
+  n = BN_le2bn(key_struct->modulus, ANDROID_PUBKEY_MODULUS_SIZE, NULL);
+  if (!n) {
     goto cleanup;
   }
 
   // Read the exponent.
-  new_key->e = BN_new();
-  if (!new_key->e || !BN_set_word(new_key->e, key_struct->exponent)) {
+  e = BN_new();
+  if (!e || !BN_set_word(e, key_struct->exponent)) {
     goto cleanup;
   }
 
+  if (!RSA_set0_key(new_key, n, e, NULL)) {
+    goto cleanup;
+  }
+  // RSA_set0_key takes ownership of its inputs on success.
+  n = NULL;
+  e = NULL;
+
   // Note that we don't extract the montgomery parameters n0inv and rr from
   // the RSAPublicKey structure. They assume a word size of 32 bits, but
   // BoringSSL may use a word size of 64 bits internally, so we're lacking the
@@ -101,24 +98,16 @@
   // pre-computed montgomery parameters.
 
   *key = new_key;
+  new_key = NULL;
   ret = true;
 
 cleanup:
-  if (!ret && new_key) {
-    RSA_free(new_key);
-  }
+  RSA_free(new_key);
+  BN_free(n);
+  BN_free(e);
   return ret;
 }
 
-static bool android_pubkey_encode_bignum(const BIGNUM* num, uint8_t* buffer) {
-  if (!BN_bn2bin_padded(buffer, ANDROID_PUBKEY_MODULUS_SIZE, num)) {
-    return false;
-  }
-
-  reverse_bytes(buffer, ANDROID_PUBKEY_MODULUS_SIZE);
-  return true;
-}
-
 bool android_pubkey_encode(const RSA* key, uint8_t* key_buffer, size_t size) {
   RSAPublicKey* key_struct = (RSAPublicKey*)key_buffer;
   bool ret = false;
@@ -127,8 +116,7 @@
   BIGNUM* n0inv = BN_new();
   BIGNUM* rr = BN_new();
 
-  if (sizeof(RSAPublicKey) > size ||
-      RSA_size(key) != ANDROID_PUBKEY_MODULUS_SIZE) {
+  if (sizeof(RSAPublicKey) > size || RSA_size(key) != ANDROID_PUBKEY_MODULUS_SIZE) {
     goto cleanup;
   }
 
@@ -136,27 +124,26 @@
   key_struct->modulus_size_words = ANDROID_PUBKEY_MODULUS_SIZE_WORDS;
 
   // Compute and store n0inv = -1 / N[0] mod 2^32.
-  if (!ctx || !r32 || !n0inv || !BN_set_bit(r32, 32) ||
-      !BN_mod(n0inv, key->n, r32, ctx) ||
+  if (!ctx || !r32 || !n0inv || !BN_set_bit(r32, 32) || !BN_mod(n0inv, RSA_get0_n(key), r32, ctx) ||
       !BN_mod_inverse(n0inv, n0inv, r32, ctx) || !BN_sub(n0inv, r32, n0inv)) {
     goto cleanup;
   }
   key_struct->n0inv = (uint32_t)BN_get_word(n0inv);
 
   // Store the modulus.
-  if (!android_pubkey_encode_bignum(key->n, key_struct->modulus)) {
+  if (!BN_bn2le_padded(key_struct->modulus, ANDROID_PUBKEY_MODULUS_SIZE, RSA_get0_n(key))) {
     goto cleanup;
   }
 
   // Compute and store rr = (2^(rsa_size)) ^ 2 mod N.
   if (!ctx || !rr || !BN_set_bit(rr, ANDROID_PUBKEY_MODULUS_SIZE * 8) ||
-      !BN_mod_sqr(rr, rr, key->n, ctx) ||
-      !android_pubkey_encode_bignum(rr, key_struct->rr)) {
+      !BN_mod_sqr(rr, rr, RSA_get0_n(key), ctx) ||
+      !BN_bn2le_padded(key_struct->rr, ANDROID_PUBKEY_MODULUS_SIZE, rr)) {
     goto cleanup;
   }
 
   // Store the exponent.
-  key_struct->exponent = (uint32_t)BN_get_word(key->e);
+  key_struct->exponent = (uint32_t)BN_get_word(RSA_get0_e(key));
 
   ret = true;
 
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 60400c9..524b715 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -28,6 +28,7 @@
     name: "libcutils_headers",
     vendor_available: true,
     recovery_available: true,
+    ramdisk_available: true,
     host_supported: true,
     apex_available: [
         "//apex_available:platform",
@@ -195,23 +196,17 @@
         },
 
         android_arm: {
-            srcs: ["arch-arm/memset32.S"],
             sanitize: {
                 misc_undefined: ["integer"],
             },
         },
         android_arm64: {
-            srcs: ["arch-arm64/android_memset.S"],
             sanitize: {
                 misc_undefined: ["integer"],
             },
         },
 
         android_x86: {
-            srcs: [
-                "arch-x86/android_memset16.S",
-                "arch-x86/android_memset32.S",
-            ],
             // TODO: This is to work around b/29412086.
             // Remove once __mulodi4 is available and move the "sanitize" block
             // to the android target.
@@ -221,10 +216,6 @@
         },
 
         android_x86_64: {
-            srcs: [
-                "arch-x86_64/android_memset16.S",
-                "arch-x86_64/android_memset32.S",
-            ],
             sanitize: {
                 misc_undefined: ["integer"],
             },
@@ -279,7 +270,6 @@
                 "android_get_control_socket_test.cpp",
                 "ashmem_test.cpp",
                 "fs_config_test.cpp",
-                "memset_test.cpp",
                 "multiuser_test.cpp",
                 "sched_policy_test.cpp",
                 "str_parms_test.cpp",
diff --git a/libcutils/arch-arm/memset32.S b/libcutils/arch-arm/memset32.S
deleted file mode 100644
index 1e89636..0000000
--- a/libcutils/arch-arm/memset32.S
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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.
- */
-/*
- *  memset32.S
- *
- */
-
-    .syntax unified
-
-    .text
-    .align
-
-    .global android_memset32
-    .type   android_memset32, %function
-    .global android_memset16
-    .type   android_memset16, %function
-
-        /*
-         * Optimized memset32 and memset16 for ARM.
-         *
-         * void android_memset16(uint16_t* dst, uint16_t value, size_t size);
-         * void android_memset32(uint32_t* dst, uint32_t value, size_t size);
-         *
-         */
-
-android_memset16:
-        .fnstart
-        cmp         r2, #1
-        bxle        lr
-
-        /* expand the data to 32 bits */
-        mov         r1, r1, lsl #16
-        orr         r1, r1, r1, lsr #16
-
-        /* align to 32 bits */
-        tst         r0, #2
-        strhne      r1, [r0], #2
-        subne       r2, r2, #2
-        .fnend
-
-android_memset32:
-        .fnstart
-        .cfi_startproc
-        str         lr, [sp, #-4]!
-        .cfi_def_cfa_offset 4
-        .cfi_rel_offset lr, 0
-
-        /* align the destination to a cache-line */
-        mov         r12, r1
-        mov         lr, r1
-        rsb         r3, r0, #0
-        ands        r3, r3, #0x1C
-        beq         .Laligned32
-        cmp         r3, r2
-        andhi       r3, r2, #0x1C
-        sub         r2, r2, r3
-
-        /* conditionally writes 0 to 7 words (length in r3) */
-        movs        r3, r3, lsl #28
-        stmiacs     r0!, {r1, lr}
-        stmiacs     r0!, {r1, lr}
-        stmiami     r0!, {r1, lr}
-        movs        r3, r3, lsl #2
-        strcs       r1, [r0], #4
-
-.Laligned32:
-        mov         r3, r1
-1:      subs        r2, r2, #32
-        stmiahs     r0!, {r1,r3,r12,lr}
-        stmiahs     r0!, {r1,r3,r12,lr}
-        bhs         1b
-        add         r2, r2, #32
-
-        /* conditionally stores 0 to 30 bytes */
-        movs        r2, r2, lsl #28
-        stmiacs     r0!, {r1,r3,r12,lr}
-        stmiami     r0!, {r1,lr}
-        movs        r2, r2, lsl #2
-        strcs       r1, [r0], #4
-        strhmi      lr, [r0], #2
-
-        ldr         lr, [sp], #4
-        .cfi_def_cfa_offset 0
-        .cfi_restore lr
-        bx          lr
-        .cfi_endproc
-        .fnend
diff --git a/libcutils/arch-arm64/android_memset.S b/libcutils/arch-arm64/android_memset.S
deleted file mode 100644
index 9a83a68..0000000
--- a/libcutils/arch-arm64/android_memset.S
+++ /dev/null
@@ -1,211 +0,0 @@
-/* Copyright (c) 2012, Linaro Limited
-   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 the Linaro 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
-   HOLDER 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.
-*/
-
-/* Assumptions:
- *
- * ARMv8-a, AArch64
- * Unaligned accesses
- *
- */
-
-/* By default we assume that the DC instruction can be used to zero
-   data blocks more efficiently.  In some circumstances this might be
-   unsafe, for example in an asymmetric multiprocessor environment with
-   different DC clear lengths (neither the upper nor lower lengths are
-   safe to use). */
-
-#define dst  		x0
-#define count		x2
-#define tmp1		x3
-#define tmp1w		w3
-#define tmp2		x4
-#define tmp2w		w4
-#define zva_len_x	x5
-#define zva_len		w5
-#define zva_bits_x	x6
-
-#define A_l		x1
-#define A_lw		w1
-#define tmp3w		w9
-
-#define ENTRY(f) \
-  .text; \
-  .globl f; \
-  .align 0; \
-  .type f, %function; \
-  f: \
-  .cfi_startproc \
-
-#define END(f) \
-  .cfi_endproc; \
-  .size f, .-f; \
-
-ENTRY(android_memset16)
-	ands   A_lw, A_lw, #0xffff
-	b.eq	.Lzero_mem
-	orr	A_lw, A_lw, A_lw, lsl #16
-	b .Lexpand_to_64
-END(android_memset16)
-
-ENTRY(android_memset32)
-	cmp	    A_lw, #0
-	b.eq	.Lzero_mem
-.Lexpand_to_64:
-	orr	A_l, A_l, A_l, lsl #32
-.Ltail_maybe_long:
-	cmp	count, #64
-	b.ge	.Lnot_short
-.Ltail_maybe_tiny:
-	cmp	count, #15
-	b.le	.Ltail15tiny
-.Ltail63:
-	ands	tmp1, count, #0x30
-	b.eq	.Ltail15
-	add	dst, dst, tmp1
-	cmp	tmp1w, #0x20
-	b.eq	1f
-	b.lt	2f
-	stp	A_l, A_l, [dst, #-48]
-1:
-	stp	A_l, A_l, [dst, #-32]
-2:
-	stp	A_l, A_l, [dst, #-16]
-
-.Ltail15:
-	and	count, count, #15
-	add	dst, dst, count
-	stp	A_l, A_l, [dst, #-16]	/* Repeat some/all of last store. */
-	ret
-
-.Ltail15tiny:
-	/* Set up to 15 bytes.  Does not assume earlier memory
-	   being set.  */
-	tbz	count, #3, 1f
-	str	A_l, [dst], #8
-1:
-	tbz	count, #2, 1f
-	str	A_lw, [dst], #4
-1:
-	tbz	count, #1, 1f
-	strh	A_lw, [dst], #2
-1:
-	ret
-
-	/* Critical loop.  Start at a new cache line boundary.  Assuming
-	 * 64 bytes per line, this ensures the entire loop is in one line.  */
-	.p2align 6
-.Lnot_short:
-	neg	tmp2, dst
-	ands	tmp2, tmp2, #15
-	b.eq	2f
-	/* Bring DST to 128-bit (16-byte) alignment.  We know that there's
-	 * more than that to set, so we simply store 16 bytes and advance by
-	 * the amount required to reach alignment.  */
-	sub	count, count, tmp2
-	stp	A_l, A_l, [dst]
-	add	dst, dst, tmp2
-	/* There may be less than 63 bytes to go now.  */
-	cmp	count, #63
-	b.le	.Ltail63
-2:
-	sub	dst, dst, #16		/* Pre-bias.  */
-	sub	count, count, #64
-1:
-	stp	A_l, A_l, [dst, #16]
-	stp	A_l, A_l, [dst, #32]
-	stp	A_l, A_l, [dst, #48]
-	stp	A_l, A_l, [dst, #64]!
-	subs	count, count, #64
-	b.ge	1b
-	tst	count, #0x3f
-	add	dst, dst, #16
-	b.ne	.Ltail63
-	ret
-
-	/* For zeroing memory, check to see if we can use the ZVA feature to
-	 * zero entire 'cache' lines.  */
-.Lzero_mem:
-	mov	A_l, #0
-	cmp	count, #63
-	b.le	.Ltail_maybe_tiny
-	neg	tmp2, dst
-	ands	tmp2, tmp2, #15
-	b.eq	1f
-	sub	count, count, tmp2
-	stp	A_l, A_l, [dst]
-	add	dst, dst, tmp2
-	cmp	count, #63
-	b.le	.Ltail63
-1:
-	/* For zeroing small amounts of memory, it's not worth setting up
-	 * the line-clear code.  */
-	cmp	count, #128
-	b.lt	.Lnot_short
-	mrs	tmp1, dczid_el0
-	tbnz	tmp1, #4, .Lnot_short
-	mov	tmp3w, #4
-	and	zva_len, tmp1w, #15	/* Safety: other bits reserved.  */
-	lsl	zva_len, tmp3w, zva_len
-
-.Lzero_by_line:
-	/* Compute how far we need to go to become suitably aligned.  We're
-	 * already at quad-word alignment.  */
-	cmp	count, zva_len_x
-	b.lt	.Lnot_short		/* Not enough to reach alignment.  */
-	sub	zva_bits_x, zva_len_x, #1
-	neg	tmp2, dst
-	ands	tmp2, tmp2, zva_bits_x
-	b.eq	1f			/* Already aligned.  */
-	/* Not aligned, check that there's enough to copy after alignment.  */
-	sub	tmp1, count, tmp2
-	cmp	tmp1, #64
-	ccmp	tmp1, zva_len_x, #8, ge	/* NZCV=0b1000 */
-	b.lt	.Lnot_short
-	/* We know that there's at least 64 bytes to zero and that it's safe
-	 * to overrun by 64 bytes.  */
-	mov	count, tmp1
-2:
-	stp	A_l, A_l, [dst]
-	stp	A_l, A_l, [dst, #16]
-	stp	A_l, A_l, [dst, #32]
-	subs	tmp2, tmp2, #64
-	stp	A_l, A_l, [dst, #48]
-	add	dst, dst, #64
-	b.ge	2b
-	/* We've overrun a bit, so adjust dst downwards.  */
-	add	dst, dst, tmp2
-1:
-	sub	count, count, zva_len_x
-3:
-	dc	zva, dst
-	add	dst, dst, zva_len_x
-	subs	count, count, zva_len_x
-	b.ge	3b
-	ands	count, count, zva_bits_x
-	b.ne	.Ltail_maybe_long
-	ret
-END(android_memset32)
diff --git a/libcutils/arch-x86/android_memset16.S b/libcutils/arch-x86/android_memset16.S
deleted file mode 100755
index f4d497e..0000000
--- a/libcutils/arch-x86/android_memset16.S
+++ /dev/null
@@ -1,721 +0,0 @@
-/*
- * 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.
- */
-
-#include "cache.h"
-
-#ifndef MEMSET
-# define MEMSET		android_memset16
-#endif
-
-#ifndef L
-# define L(label)	.L##label
-#endif
-
-#ifndef ALIGN
-# define ALIGN(n)	.p2align n
-#endif
-
-#ifndef cfi_startproc
-# define cfi_startproc			.cfi_startproc
-#endif
-
-#ifndef cfi_endproc
-# define cfi_endproc			.cfi_endproc
-#endif
-
-#ifndef cfi_rel_offset
-# define cfi_rel_offset(reg, off)	.cfi_rel_offset reg, off
-#endif
-
-#ifndef cfi_restore
-# define cfi_restore(reg)		.cfi_restore reg
-#endif
-
-#ifndef cfi_adjust_cfa_offset
-# define cfi_adjust_cfa_offset(off)	.cfi_adjust_cfa_offset off
-#endif
-
-#ifndef ENTRY
-# define ENTRY(name)			\
-	.type name,  @function; 	\
-	.globl name;			\
-	.p2align 4;			\
-name:					\
-	cfi_startproc
-#endif
-
-#ifndef END
-# define END(name)			\
-	cfi_endproc;			\
-	.size name, .-name
-#endif
-
-#define CFI_PUSH(REG)						\
-  cfi_adjust_cfa_offset (4);					\
-  cfi_rel_offset (REG, 0)
-
-#define CFI_POP(REG)						\
-  cfi_adjust_cfa_offset (-4);					\
-  cfi_restore (REG)
-
-#define PUSH(REG)	pushl REG; CFI_PUSH (REG)
-#define POP(REG)	popl REG; CFI_POP (REG)
-
-#ifdef USE_AS_BZERO16
-# define DEST		PARMS
-# define LEN		DEST+4
-# define SETRTNVAL
-#else
-# define DEST		PARMS
-# define CHR		DEST+4
-# define LEN		CHR+4
-# define SETRTNVAL	movl DEST(%esp), %eax
-#endif
-
-#if (defined SHARED || defined __PIC__)
-# define ENTRANCE	PUSH (%ebx);
-# define RETURN_END	POP (%ebx); ret
-# define RETURN		RETURN_END; CFI_PUSH (%ebx)
-# define PARMS		8		/* Preserve EBX.  */
-# define JMPTBL(I, B)	I - B
-
-/* Load an entry in a jump table into EBX and branch to it.  TABLE is a
-   jump table with relative offsets.   */
-# define BRANCH_TO_JMPTBL_ENTRY(TABLE)				\
-    /* We first load PC into EBX.  */				\
-    call	__x86.get_pc_thunk.bx;				\
-    /* Get the address of the jump table.  */			\
-    add		$(TABLE - .), %ebx;				\
-    /* Get the entry and convert the relative offset to the	\
-       absolute address.  */					\
-    add		(%ebx,%ecx,4), %ebx;				\
-    /* We loaded the jump table and adjuested EDX. Go.  */	\
-    jmp		*%ebx
-
-	.section	.text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
-	.globl	__x86.get_pc_thunk.bx
-	.hidden	__x86.get_pc_thunk.bx
-	ALIGN (4)
-	.type	__x86.get_pc_thunk.bx,@function
-__x86.get_pc_thunk.bx:
-	cfi_startproc
-	movl	(%esp), %ebx
-	ret
-	cfi_endproc
-#else
-# define ENTRANCE
-# define RETURN_END	ret
-# define RETURN		RETURN_END
-# define PARMS		4
-# define JMPTBL(I, B)	I
-
-/* Branch to an entry in a jump table.  TABLE is a jump table with
-   absolute offsets.  */
-# define BRANCH_TO_JMPTBL_ENTRY(TABLE)				\
-    jmp		*TABLE(,%ecx,4)
-#endif
-
-	.section .text.sse2,"ax",@progbits
-	ALIGN (4)
-ENTRY (MEMSET)
-	ENTRANCE
-
-	movl	LEN(%esp), %ecx
-	shr	$1, %ecx
-#ifdef USE_AS_BZERO16
-	xor	%eax, %eax
-#else
-	movzwl	CHR(%esp), %eax
-	mov	%eax, %edx
-	shl	$16, %eax
-	or	%edx, %eax
-#endif
-	movl	DEST(%esp), %edx
-	cmp	$32, %ecx
-	jae	L(32wordsormore)
-
-L(write_less32words):
-	lea	(%edx, %ecx, 2), %edx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_less32words))
-
-
-	.pushsection .rodata.sse2,"a",@progbits
-	ALIGN (2)
-L(table_less32words):
-	.int	JMPTBL (L(write_0words), L(table_less32words))
-	.int	JMPTBL (L(write_1words), L(table_less32words))
-	.int	JMPTBL (L(write_2words), L(table_less32words))
-	.int	JMPTBL (L(write_3words), L(table_less32words))
-	.int	JMPTBL (L(write_4words), L(table_less32words))
-	.int	JMPTBL (L(write_5words), L(table_less32words))
-	.int	JMPTBL (L(write_6words), L(table_less32words))
-	.int	JMPTBL (L(write_7words), L(table_less32words))
-	.int	JMPTBL (L(write_8words), L(table_less32words))
-	.int	JMPTBL (L(write_9words), L(table_less32words))
-	.int	JMPTBL (L(write_10words), L(table_less32words))
-	.int	JMPTBL (L(write_11words), L(table_less32words))
-	.int	JMPTBL (L(write_12words), L(table_less32words))
-	.int	JMPTBL (L(write_13words), L(table_less32words))
-	.int	JMPTBL (L(write_14words), L(table_less32words))
-	.int	JMPTBL (L(write_15words), L(table_less32words))
-	.int	JMPTBL (L(write_16words), L(table_less32words))
-	.int	JMPTBL (L(write_17words), L(table_less32words))
-	.int	JMPTBL (L(write_18words), L(table_less32words))
-	.int	JMPTBL (L(write_19words), L(table_less32words))
-	.int	JMPTBL (L(write_20words), L(table_less32words))
-	.int	JMPTBL (L(write_21words), L(table_less32words))
-	.int	JMPTBL (L(write_22words), L(table_less32words))
-	.int	JMPTBL (L(write_23words), L(table_less32words))
-	.int	JMPTBL (L(write_24words), L(table_less32words))
-	.int	JMPTBL (L(write_25words), L(table_less32words))
-	.int	JMPTBL (L(write_26words), L(table_less32words))
-	.int	JMPTBL (L(write_27words), L(table_less32words))
-	.int	JMPTBL (L(write_28words), L(table_less32words))
-	.int	JMPTBL (L(write_29words), L(table_less32words))
-	.int	JMPTBL (L(write_30words), L(table_less32words))
-	.int	JMPTBL (L(write_31words), L(table_less32words))
-	.popsection
-
-	ALIGN (4)
-L(write_28words):
-	movl	%eax, -56(%edx)
-	movl	%eax, -52(%edx)
-L(write_24words):
-	movl	%eax, -48(%edx)
-	movl	%eax, -44(%edx)
-L(write_20words):
-	movl	%eax, -40(%edx)
-	movl	%eax, -36(%edx)
-L(write_16words):
-	movl	%eax, -32(%edx)
-	movl	%eax, -28(%edx)
-L(write_12words):
-	movl	%eax, -24(%edx)
-	movl	%eax, -20(%edx)
-L(write_8words):
-	movl	%eax, -16(%edx)
-	movl	%eax, -12(%edx)
-L(write_4words):
-	movl	%eax, -8(%edx)
-	movl	%eax, -4(%edx)
-L(write_0words):
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(write_29words):
-	movl	%eax, -58(%edx)
-	movl	%eax, -54(%edx)
-L(write_25words):
-	movl	%eax, -50(%edx)
-	movl	%eax, -46(%edx)
-L(write_21words):
-	movl	%eax, -42(%edx)
-	movl	%eax, -38(%edx)
-L(write_17words):
-	movl	%eax, -34(%edx)
-	movl	%eax, -30(%edx)
-L(write_13words):
-	movl	%eax, -26(%edx)
-	movl	%eax, -22(%edx)
-L(write_9words):
-	movl	%eax, -18(%edx)
-	movl	%eax, -14(%edx)
-L(write_5words):
-	movl	%eax, -10(%edx)
-	movl	%eax, -6(%edx)
-L(write_1words):
-	mov	%ax, -2(%edx)
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(write_30words):
-	movl	%eax, -60(%edx)
-	movl	%eax, -56(%edx)
-L(write_26words):
-	movl	%eax, -52(%edx)
-	movl	%eax, -48(%edx)
-L(write_22words):
-	movl	%eax, -44(%edx)
-	movl	%eax, -40(%edx)
-L(write_18words):
-	movl	%eax, -36(%edx)
-	movl	%eax, -32(%edx)
-L(write_14words):
-	movl	%eax, -28(%edx)
-	movl	%eax, -24(%edx)
-L(write_10words):
-	movl	%eax, -20(%edx)
-	movl	%eax, -16(%edx)
-L(write_6words):
-	movl	%eax, -12(%edx)
-	movl	%eax, -8(%edx)
-L(write_2words):
-	movl	%eax, -4(%edx)
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(write_31words):
-	movl	%eax, -62(%edx)
-	movl	%eax, -58(%edx)
-L(write_27words):
-	movl	%eax, -54(%edx)
-	movl	%eax, -50(%edx)
-L(write_23words):
-	movl	%eax, -46(%edx)
-	movl	%eax, -42(%edx)
-L(write_19words):
-	movl	%eax, -38(%edx)
-	movl	%eax, -34(%edx)
-L(write_15words):
-	movl	%eax, -30(%edx)
-	movl	%eax, -26(%edx)
-L(write_11words):
-	movl	%eax, -22(%edx)
-	movl	%eax, -18(%edx)
-L(write_7words):
-	movl	%eax, -14(%edx)
-	movl	%eax, -10(%edx)
-L(write_3words):
-	movl	%eax, -6(%edx)
-	movw	%ax, -2(%edx)
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-
-L(32wordsormore):
-	shl	$1, %ecx
-	test	$0x01, %edx
-	jz	L(aligned2bytes)
-	mov	%eax, (%edx)
-	mov	%eax, -4(%edx, %ecx)
-	sub	$2, %ecx
-	add	$1, %edx
-	rol	$8, %eax
-L(aligned2bytes):
-#ifdef USE_AS_BZERO16
-	pxor	%xmm0, %xmm0
-#else
-	movd	%eax, %xmm0
-	pshufd	$0, %xmm0, %xmm0
-#endif
-	testl	$0xf, %edx
-	jz	L(aligned_16)
-/* ECX > 32 and EDX is not 16 byte aligned.  */
-L(not_aligned_16):
-	movdqu	%xmm0, (%edx)
-	movl	%edx, %eax
-	and	$-16, %edx
-	add	$16, %edx
-	sub	%edx, %eax
-	add	%eax, %ecx
-	movd	%xmm0, %eax
-
-	ALIGN (4)
-L(aligned_16):
-	cmp	$128, %ecx
-	jae	L(128bytesormore)
-
-L(aligned_16_less128bytes):
-	add	%ecx, %edx
-	shr	$1, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	ALIGN (4)
-L(128bytesormore):
-#ifdef SHARED_CACHE_SIZE
-	PUSH (%ebx)
-	mov	$SHARED_CACHE_SIZE, %ebx
-#else
-# if (defined SHARED || defined __PIC__)
-	call	__x86.get_pc_thunk.bx
-	add	$_GLOBAL_OFFSET_TABLE_, %ebx
-	mov	__x86_shared_cache_size@GOTOFF(%ebx), %ebx
-# else
-	PUSH (%ebx)
-	mov	__x86_shared_cache_size, %ebx
-# endif
-#endif
-	cmp	%ebx, %ecx
-	jae	L(128bytesormore_nt_start)
-
-
-#ifdef DATA_CACHE_SIZE
-	POP (%ebx)
-# define RESTORE_EBX_STATE CFI_PUSH (%ebx)
-	cmp	$DATA_CACHE_SIZE, %ecx
-#else
-# if (defined SHARED || defined __PIC__)
-#  define RESTORE_EBX_STATE
-	call	__x86.get_pc_thunk.bx
-	add	$_GLOBAL_OFFSET_TABLE_, %ebx
-	cmp	__x86_data_cache_size@GOTOFF(%ebx), %ecx
-# else
-	POP (%ebx)
-#  define RESTORE_EBX_STATE CFI_PUSH (%ebx)
-	cmp	__x86_data_cache_size, %ecx
-# endif
-#endif
-
-	jae	L(128bytes_L2_normal)
-	subl	$128, %ecx
-L(128bytesormore_normal):
-	sub	$128, %ecx
-	movdqa	%xmm0, (%edx)
-	movdqa	%xmm0, 0x10(%edx)
-	movdqa	%xmm0, 0x20(%edx)
-	movdqa	%xmm0, 0x30(%edx)
-	movdqa	%xmm0, 0x40(%edx)
-	movdqa	%xmm0, 0x50(%edx)
-	movdqa	%xmm0, 0x60(%edx)
-	movdqa	%xmm0, 0x70(%edx)
-	lea	128(%edx), %edx
-	jb	L(128bytesless_normal)
-
-
-	sub	$128, %ecx
-	movdqa	%xmm0, (%edx)
-	movdqa	%xmm0, 0x10(%edx)
-	movdqa	%xmm0, 0x20(%edx)
-	movdqa	%xmm0, 0x30(%edx)
-	movdqa	%xmm0, 0x40(%edx)
-	movdqa	%xmm0, 0x50(%edx)
-	movdqa	%xmm0, 0x60(%edx)
-	movdqa	%xmm0, 0x70(%edx)
-	lea	128(%edx), %edx
-	jae	L(128bytesormore_normal)
-
-L(128bytesless_normal):
-	lea	128(%ecx), %ecx
-	add	%ecx, %edx
-	shr	$1, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	ALIGN (4)
-L(128bytes_L2_normal):
-	prefetcht0	0x380(%edx)
-	prefetcht0	0x3c0(%edx)
-	sub	$128, %ecx
-	movdqa	%xmm0, (%edx)
-	movaps	%xmm0, 0x10(%edx)
-	movaps	%xmm0, 0x20(%edx)
-	movaps	%xmm0, 0x30(%edx)
-	movaps	%xmm0, 0x40(%edx)
-	movaps	%xmm0, 0x50(%edx)
-	movaps	%xmm0, 0x60(%edx)
-	movaps	%xmm0, 0x70(%edx)
-	add	$128, %edx
-	cmp	$128, %ecx
-	jae	L(128bytes_L2_normal)
-
-L(128bytesless_L2_normal):
-	add	%ecx, %edx
-	shr	$1, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	RESTORE_EBX_STATE
-L(128bytesormore_nt_start):
-	sub	%ebx, %ecx
-	mov	%ebx, %eax
-	and	$0x7f, %eax
-	add	%eax, %ecx
-	movd	%xmm0, %eax
-	ALIGN (4)
-L(128bytesormore_shared_cache_loop):
-	prefetcht0	0x3c0(%edx)
-	prefetcht0	0x380(%edx)
-	sub	$0x80, %ebx
-	movdqa	%xmm0, (%edx)
-	movdqa	%xmm0, 0x10(%edx)
-	movdqa	%xmm0, 0x20(%edx)
-	movdqa	%xmm0, 0x30(%edx)
-	movdqa	%xmm0, 0x40(%edx)
-	movdqa	%xmm0, 0x50(%edx)
-	movdqa	%xmm0, 0x60(%edx)
-	movdqa	%xmm0, 0x70(%edx)
-	add	$0x80, %edx
-	cmp	$0x80, %ebx
-	jae	L(128bytesormore_shared_cache_loop)
-	cmp	$0x80, %ecx
-	jb	L(shared_cache_loop_end)
-	ALIGN (4)
-L(128bytesormore_nt):
-	sub	$0x80, %ecx
-	movntdq	%xmm0, (%edx)
-	movntdq	%xmm0, 0x10(%edx)
-	movntdq	%xmm0, 0x20(%edx)
-	movntdq	%xmm0, 0x30(%edx)
-	movntdq	%xmm0, 0x40(%edx)
-	movntdq	%xmm0, 0x50(%edx)
-	movntdq	%xmm0, 0x60(%edx)
-	movntdq	%xmm0, 0x70(%edx)
-	add	$0x80, %edx
-	cmp	$0x80, %ecx
-	jae	L(128bytesormore_nt)
-	sfence
-L(shared_cache_loop_end):
-#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__)
-	POP (%ebx)
-#endif
-	add	%ecx, %edx
-	shr	$1, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-
-	.pushsection .rodata.sse2,"a",@progbits
-	ALIGN (2)
-L(table_16_128bytes):
-	.int	JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_2bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_6bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_10bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_14bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_18bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_22bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_26bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_30bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_34bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_38bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_42bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_46bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_50bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_54bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_58bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_62bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_66bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_70bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_74bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_78bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_82bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_86bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_90bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_94bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_98bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_102bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_106bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_110bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_114bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_118bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_122bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_126bytes), L(table_16_128bytes))
-	.popsection
-
-
-	ALIGN (4)
-L(aligned_16_112bytes):
-	movdqa	%xmm0, -112(%edx)
-L(aligned_16_96bytes):
-	movdqa	%xmm0, -96(%edx)
-L(aligned_16_80bytes):
-	movdqa	%xmm0, -80(%edx)
-L(aligned_16_64bytes):
-	movdqa	%xmm0, -64(%edx)
-L(aligned_16_48bytes):
-	movdqa	%xmm0, -48(%edx)
-L(aligned_16_32bytes):
-	movdqa	%xmm0, -32(%edx)
-L(aligned_16_16bytes):
-	movdqa	%xmm0, -16(%edx)
-L(aligned_16_0bytes):
-	SETRTNVAL
-	RETURN
-
-
-	ALIGN (4)
-L(aligned_16_114bytes):
-	movdqa	%xmm0, -114(%edx)
-L(aligned_16_98bytes):
-	movdqa	%xmm0, -98(%edx)
-L(aligned_16_82bytes):
-	movdqa	%xmm0, -82(%edx)
-L(aligned_16_66bytes):
-	movdqa	%xmm0, -66(%edx)
-L(aligned_16_50bytes):
-	movdqa	%xmm0, -50(%edx)
-L(aligned_16_34bytes):
-	movdqa	%xmm0, -34(%edx)
-L(aligned_16_18bytes):
-	movdqa	%xmm0, -18(%edx)
-L(aligned_16_2bytes):
-	movw	%ax, -2(%edx)
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(aligned_16_116bytes):
-	movdqa	%xmm0, -116(%edx)
-L(aligned_16_100bytes):
-	movdqa	%xmm0, -100(%edx)
-L(aligned_16_84bytes):
-	movdqa	%xmm0, -84(%edx)
-L(aligned_16_68bytes):
-	movdqa	%xmm0, -68(%edx)
-L(aligned_16_52bytes):
-	movdqa	%xmm0, -52(%edx)
-L(aligned_16_36bytes):
-	movdqa	%xmm0, -36(%edx)
-L(aligned_16_20bytes):
-	movdqa	%xmm0, -20(%edx)
-L(aligned_16_4bytes):
-	movl	%eax, -4(%edx)
-	SETRTNVAL
-	RETURN
-
-
-	ALIGN (4)
-L(aligned_16_118bytes):
-	movdqa	%xmm0, -118(%edx)
-L(aligned_16_102bytes):
-	movdqa	%xmm0, -102(%edx)
-L(aligned_16_86bytes):
-	movdqa	%xmm0, -86(%edx)
-L(aligned_16_70bytes):
-	movdqa	%xmm0, -70(%edx)
-L(aligned_16_54bytes):
-	movdqa	%xmm0, -54(%edx)
-L(aligned_16_38bytes):
-	movdqa	%xmm0, -38(%edx)
-L(aligned_16_22bytes):
-	movdqa	%xmm0, -22(%edx)
-L(aligned_16_6bytes):
-	movl	%eax, -6(%edx)
-	movw	%ax, -2(%edx)
-	SETRTNVAL
-	RETURN
-
-
-	ALIGN (4)
-L(aligned_16_120bytes):
-	movdqa	%xmm0, -120(%edx)
-L(aligned_16_104bytes):
-	movdqa	%xmm0, -104(%edx)
-L(aligned_16_88bytes):
-	movdqa	%xmm0, -88(%edx)
-L(aligned_16_72bytes):
-	movdqa	%xmm0, -72(%edx)
-L(aligned_16_56bytes):
-	movdqa	%xmm0, -56(%edx)
-L(aligned_16_40bytes):
-	movdqa	%xmm0, -40(%edx)
-L(aligned_16_24bytes):
-	movdqa	%xmm0, -24(%edx)
-L(aligned_16_8bytes):
-	movq	%xmm0, -8(%edx)
-	SETRTNVAL
-	RETURN
-
-
-	ALIGN (4)
-L(aligned_16_122bytes):
-	movdqa	%xmm0, -122(%edx)
-L(aligned_16_106bytes):
-	movdqa	%xmm0, -106(%edx)
-L(aligned_16_90bytes):
-	movdqa	%xmm0, -90(%edx)
-L(aligned_16_74bytes):
-	movdqa	%xmm0, -74(%edx)
-L(aligned_16_58bytes):
-	movdqa	%xmm0, -58(%edx)
-L(aligned_16_42bytes):
-	movdqa	%xmm0, -42(%edx)
-L(aligned_16_26bytes):
-	movdqa	%xmm0, -26(%edx)
-L(aligned_16_10bytes):
-	movq	%xmm0, -10(%edx)
-	movw	%ax, -2(%edx)
-	SETRTNVAL
-	RETURN
-
-
-	ALIGN (4)
-L(aligned_16_124bytes):
-	movdqa	%xmm0, -124(%edx)
-L(aligned_16_108bytes):
-	movdqa	%xmm0, -108(%edx)
-L(aligned_16_92bytes):
-	movdqa	%xmm0, -92(%edx)
-L(aligned_16_76bytes):
-	movdqa	%xmm0, -76(%edx)
-L(aligned_16_60bytes):
-	movdqa	%xmm0, -60(%edx)
-L(aligned_16_44bytes):
-	movdqa	%xmm0, -44(%edx)
-L(aligned_16_28bytes):
-	movdqa	%xmm0, -28(%edx)
-L(aligned_16_12bytes):
-	movq	%xmm0, -12(%edx)
-	movl	%eax, -4(%edx)
-	SETRTNVAL
-	RETURN
-
-
-	ALIGN (4)
-L(aligned_16_126bytes):
-	movdqa	%xmm0, -126(%edx)
-L(aligned_16_110bytes):
-	movdqa	%xmm0, -110(%edx)
-L(aligned_16_94bytes):
-	movdqa	%xmm0, -94(%edx)
-L(aligned_16_78bytes):
-	movdqa	%xmm0, -78(%edx)
-L(aligned_16_62bytes):
-	movdqa	%xmm0, -62(%edx)
-L(aligned_16_46bytes):
-	movdqa	%xmm0, -46(%edx)
-L(aligned_16_30bytes):
-	movdqa	%xmm0, -30(%edx)
-L(aligned_16_14bytes):
-	movq	%xmm0, -14(%edx)
-	movl	%eax, -6(%edx)
-	movw	%ax, -2(%edx)
-	SETRTNVAL
-	RETURN
-
-END (MEMSET)
diff --git a/libcutils/arch-x86/android_memset32.S b/libcutils/arch-x86/android_memset32.S
deleted file mode 100755
index b928f6b..0000000
--- a/libcutils/arch-x86/android_memset32.S
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * 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.
- */
-
-#include "cache.h"
-
-#ifndef MEMSET
-# define MEMSET 	android_memset32
-#endif
-
-#ifndef L
-# define L(label)	.L##label
-#endif
-
-#ifndef ALIGN
-# define ALIGN(n)	.p2align n
-#endif
-
-#ifndef cfi_startproc
-# define cfi_startproc			.cfi_startproc
-#endif
-
-#ifndef cfi_endproc
-# define cfi_endproc			.cfi_endproc
-#endif
-
-#ifndef cfi_rel_offset
-# define cfi_rel_offset(reg, off)	.cfi_rel_offset reg, off
-#endif
-
-#ifndef cfi_restore
-# define cfi_restore(reg)		.cfi_restore reg
-#endif
-
-#ifndef cfi_adjust_cfa_offset
-# define cfi_adjust_cfa_offset(off)	.cfi_adjust_cfa_offset off
-#endif
-
-#ifndef ENTRY
-# define ENTRY(name)			\
-	.type name,  @function; 	\
-	.globl name;			\
-	.p2align 4;			\
-name:					\
-	cfi_startproc
-#endif
-
-#ifndef END
-# define END(name)			\
-	cfi_endproc;			\
-	.size name, .-name
-#endif
-
-#define CFI_PUSH(REG)						\
-  cfi_adjust_cfa_offset (4);					\
-  cfi_rel_offset (REG, 0)
-
-#define CFI_POP(REG)						\
-  cfi_adjust_cfa_offset (-4);					\
-  cfi_restore (REG)
-
-#define PUSH(REG)	pushl REG; CFI_PUSH (REG)
-#define POP(REG)	popl REG; CFI_POP (REG)
-
-#ifdef USE_AS_BZERO32
-# define DEST		PARMS
-# define LEN		DEST+4
-# define SETRTNVAL
-#else
-# define DEST		PARMS
-# define DWDS		DEST+4
-# define LEN		DWDS+4
-# define SETRTNVAL	movl DEST(%esp), %eax
-#endif
-
-#if (defined SHARED || defined __PIC__)
-# define ENTRANCE	PUSH (%ebx);
-# define RETURN_END	POP (%ebx); ret
-# define RETURN		RETURN_END; CFI_PUSH (%ebx)
-# define PARMS		8		/* Preserve EBX.  */
-# define JMPTBL(I, B)	I - B
-
-/* Load an entry in a jump table into EBX and branch to it.  TABLE is a
-   jump table with relative offsets.   */
-# define BRANCH_TO_JMPTBL_ENTRY(TABLE)				\
-    /* We first load PC into EBX.  */				\
-    call	__x86.get_pc_thunk.bx;				\
-    /* Get the address of the jump table.  */			\
-    add		$(TABLE - .), %ebx;				\
-    /* Get the entry and convert the relative offset to the	\
-       absolute address.  */					\
-    add		(%ebx,%ecx,4), %ebx;				\
-    /* We loaded the jump table and adjuested EDX. Go.  */	\
-    jmp		*%ebx
-
-	.section	.text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
-	.globl	__x86.get_pc_thunk.bx
-	.hidden	__x86.get_pc_thunk.bx
-	ALIGN (4)
-	.type	__x86.get_pc_thunk.bx,@function
-__x86.get_pc_thunk.bx:
-	cfi_startproc
-	movl	(%esp), %ebx
-	ret
-	cfi_endproc
-#else
-# define ENTRANCE
-# define RETURN_END	ret
-# define RETURN		RETURN_END
-# define PARMS		4
-# define JMPTBL(I, B)	I
-
-/* Branch to an entry in a jump table.  TABLE is a jump table with
-   absolute offsets.  */
-# define BRANCH_TO_JMPTBL_ENTRY(TABLE)				\
-    jmp		*TABLE(,%ecx,4)
-#endif
-
-	.section .text.sse2,"ax",@progbits
-	ALIGN (4)
-ENTRY (MEMSET)
-	ENTRANCE
-
-	movl	LEN(%esp), %ecx
-	shr     $2, %ecx
-#ifdef USE_AS_BZERO32
-	xor	%eax, %eax
-#else
-	mov	DWDS(%esp), %eax
-	mov	%eax, %edx
-#endif
-	movl	DEST(%esp), %edx
-	cmp	$16, %ecx
-	jae	L(16dbwordsormore)
-
-L(write_less16dbwords):
-	lea	(%edx, %ecx, 4), %edx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_less16dbwords))
-
-	.pushsection .rodata.sse2,"a",@progbits
-	ALIGN (2)
-L(table_less16dbwords):
-	.int	JMPTBL (L(write_0dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_1dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_2dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_3dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_4dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_5dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_6dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_7dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_8dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_9dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_10dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_11dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_12dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_13dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_14dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_15dbwords), L(table_less16dbwords))
-	.popsection
-
-	ALIGN (4)
-L(write_15dbwords):
-	movl	%eax, -60(%edx)
-L(write_14dbwords):
-	movl	%eax, -56(%edx)
-L(write_13dbwords):
-	movl	%eax, -52(%edx)
-L(write_12dbwords):
-	movl	%eax, -48(%edx)
-L(write_11dbwords):
-	movl	%eax, -44(%edx)
-L(write_10dbwords):
-	movl	%eax, -40(%edx)
-L(write_9dbwords):
-	movl	%eax, -36(%edx)
-L(write_8dbwords):
-	movl	%eax, -32(%edx)
-L(write_7dbwords):
-	movl	%eax, -28(%edx)
-L(write_6dbwords):
-	movl	%eax, -24(%edx)
-L(write_5dbwords):
-	movl	%eax, -20(%edx)
-L(write_4dbwords):
-	movl	%eax, -16(%edx)
-L(write_3dbwords):
-	movl	%eax, -12(%edx)
-L(write_2dbwords):
-	movl	%eax, -8(%edx)
-L(write_1dbwords):
-	movl	%eax, -4(%edx)
-L(write_0dbwords):
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(16dbwordsormore):
-	test	$3, %edx
-	jz	L(aligned4bytes)
-	mov	%eax, (%edx)
-	mov	%eax, -4(%edx, %ecx, 4)
-	sub	$1, %ecx
-	rol	$24, %eax
-	add	$1, %edx
-	test	$3, %edx
-	jz	L(aligned4bytes)
-	ror	$8, %eax
-	add	$1, %edx
-	test	$3, %edx
-	jz	L(aligned4bytes)
-	ror	$8, %eax
-	add	$1, %edx
-L(aligned4bytes):
-	shl	$2, %ecx
-
-#ifdef USE_AS_BZERO32
-	pxor	%xmm0, %xmm0
-#else
-	movd	%eax, %xmm0
-	pshufd	$0, %xmm0, %xmm0
-#endif
-	testl	$0xf, %edx
-	jz	L(aligned_16)
-/* ECX > 32 and EDX is not 16 byte aligned.  */
-L(not_aligned_16):
-	movdqu	%xmm0, (%edx)
-	movl	%edx, %eax
-	and	$-16, %edx
-	add	$16, %edx
-	sub	%edx, %eax
-	add	%eax, %ecx
-	movd	%xmm0, %eax
-	ALIGN (4)
-L(aligned_16):
-	cmp	$128, %ecx
-	jae	L(128bytesormore)
-
-L(aligned_16_less128bytes):
-	add	%ecx, %edx
-	shr	$2, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	ALIGN (4)
-L(128bytesormore):
-#ifdef SHARED_CACHE_SIZE
-	PUSH (%ebx)
-	mov	$SHARED_CACHE_SIZE, %ebx
-#else
-# if (defined SHARED || defined __PIC__)
-	call	__x86.get_pc_thunk.bx
-	add	$_GLOBAL_OFFSET_TABLE_, %ebx
-	mov	__x86_shared_cache_size@GOTOFF(%ebx), %ebx
-# else
-	PUSH (%ebx)
-	mov	__x86_shared_cache_size, %ebx
-# endif
-#endif
-	cmp	%ebx, %ecx
-	jae	L(128bytesormore_nt_start)
-
-#ifdef DATA_CACHE_SIZE
-	POP (%ebx)
-# define RESTORE_EBX_STATE CFI_PUSH (%ebx)
-	cmp	$DATA_CACHE_SIZE, %ecx
-#else
-# if (defined SHARED || defined __PIC__)
-#  define RESTORE_EBX_STATE
-	call	__x86.get_pc_thunk.bx
-	add	$_GLOBAL_OFFSET_TABLE_, %ebx
-	cmp	__x86_data_cache_size@GOTOFF(%ebx), %ecx
-# else
-	POP (%ebx)
-#  define RESTORE_EBX_STATE CFI_PUSH (%ebx)
-	cmp	__x86_data_cache_size, %ecx
-# endif
-#endif
-
-	jae	L(128bytes_L2_normal)
-	subl	$128, %ecx
-L(128bytesormore_normal):
-	sub	$128, %ecx
-	movdqa	%xmm0, (%edx)
-	movdqa	%xmm0, 0x10(%edx)
-	movdqa	%xmm0, 0x20(%edx)
-	movdqa	%xmm0, 0x30(%edx)
-	movdqa	%xmm0, 0x40(%edx)
-	movdqa	%xmm0, 0x50(%edx)
-	movdqa	%xmm0, 0x60(%edx)
-	movdqa	%xmm0, 0x70(%edx)
-	lea	128(%edx), %edx
-	jb	L(128bytesless_normal)
-
-
-	sub	$128, %ecx
-	movdqa	%xmm0, (%edx)
-	movdqa	%xmm0, 0x10(%edx)
-	movdqa	%xmm0, 0x20(%edx)
-	movdqa	%xmm0, 0x30(%edx)
-	movdqa	%xmm0, 0x40(%edx)
-	movdqa	%xmm0, 0x50(%edx)
-	movdqa	%xmm0, 0x60(%edx)
-	movdqa	%xmm0, 0x70(%edx)
-	lea	128(%edx), %edx
-	jae	L(128bytesormore_normal)
-
-L(128bytesless_normal):
-	lea	128(%ecx), %ecx
-	add	%ecx, %edx
-	shr	$2, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	ALIGN (4)
-L(128bytes_L2_normal):
-	prefetcht0	0x380(%edx)
-	prefetcht0	0x3c0(%edx)
-	sub	$128, %ecx
-	movdqa	%xmm0, (%edx)
-	movaps	%xmm0, 0x10(%edx)
-	movaps	%xmm0, 0x20(%edx)
-	movaps	%xmm0, 0x30(%edx)
-	movaps	%xmm0, 0x40(%edx)
-	movaps	%xmm0, 0x50(%edx)
-	movaps	%xmm0, 0x60(%edx)
-	movaps	%xmm0, 0x70(%edx)
-	add	$128, %edx
-	cmp	$128, %ecx
-	jae	L(128bytes_L2_normal)
-
-L(128bytesless_L2_normal):
-	add	%ecx, %edx
-	shr	$2, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	RESTORE_EBX_STATE
-L(128bytesormore_nt_start):
-	sub	%ebx, %ecx
-	mov	%ebx, %eax
-	and	$0x7f, %eax
-	add	%eax, %ecx
-	movd	%xmm0, %eax
-	ALIGN (4)
-L(128bytesormore_shared_cache_loop):
-	prefetcht0	0x3c0(%edx)
-	prefetcht0	0x380(%edx)
-	sub	$0x80, %ebx
-	movdqa	%xmm0, (%edx)
-	movdqa	%xmm0, 0x10(%edx)
-	movdqa	%xmm0, 0x20(%edx)
-	movdqa	%xmm0, 0x30(%edx)
-	movdqa	%xmm0, 0x40(%edx)
-	movdqa	%xmm0, 0x50(%edx)
-	movdqa	%xmm0, 0x60(%edx)
-	movdqa	%xmm0, 0x70(%edx)
-	add	$0x80, %edx
-	cmp	$0x80, %ebx
-	jae	L(128bytesormore_shared_cache_loop)
-	cmp	$0x80, %ecx
-	jb	L(shared_cache_loop_end)
-
-	ALIGN (4)
-L(128bytesormore_nt):
-	sub	$0x80, %ecx
-	movntdq	%xmm0, (%edx)
-	movntdq	%xmm0, 0x10(%edx)
-	movntdq	%xmm0, 0x20(%edx)
-	movntdq	%xmm0, 0x30(%edx)
-	movntdq	%xmm0, 0x40(%edx)
-	movntdq	%xmm0, 0x50(%edx)
-	movntdq	%xmm0, 0x60(%edx)
-	movntdq	%xmm0, 0x70(%edx)
-	add	$0x80, %edx
-	cmp	$0x80, %ecx
-	jae	L(128bytesormore_nt)
-	sfence
-L(shared_cache_loop_end):
-#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__)
-	POP (%ebx)
-#endif
-	add	%ecx, %edx
-	shr	$2, %ecx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-	.pushsection .rodata.sse2,"a",@progbits
-	ALIGN (2)
-L(table_16_128bytes):
-	.int	JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
-	.popsection
-
-	ALIGN (4)
-L(aligned_16_112bytes):
-	movdqa	%xmm0, -112(%edx)
-L(aligned_16_96bytes):
-	movdqa	%xmm0, -96(%edx)
-L(aligned_16_80bytes):
-	movdqa	%xmm0, -80(%edx)
-L(aligned_16_64bytes):
-	movdqa	%xmm0, -64(%edx)
-L(aligned_16_48bytes):
-	movdqa	%xmm0, -48(%edx)
-L(aligned_16_32bytes):
-	movdqa	%xmm0, -32(%edx)
-L(aligned_16_16bytes):
-	movdqa	%xmm0, -16(%edx)
-L(aligned_16_0bytes):
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(aligned_16_116bytes):
-	movdqa	%xmm0, -116(%edx)
-L(aligned_16_100bytes):
-	movdqa	%xmm0, -100(%edx)
-L(aligned_16_84bytes):
-	movdqa	%xmm0, -84(%edx)
-L(aligned_16_68bytes):
-	movdqa	%xmm0, -68(%edx)
-L(aligned_16_52bytes):
-	movdqa	%xmm0, -52(%edx)
-L(aligned_16_36bytes):
-	movdqa	%xmm0, -36(%edx)
-L(aligned_16_20bytes):
-	movdqa	%xmm0, -20(%edx)
-L(aligned_16_4bytes):
-	movl	%eax, -4(%edx)
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(aligned_16_120bytes):
-	movdqa	%xmm0, -120(%edx)
-L(aligned_16_104bytes):
-	movdqa	%xmm0, -104(%edx)
-L(aligned_16_88bytes):
-	movdqa	%xmm0, -88(%edx)
-L(aligned_16_72bytes):
-	movdqa	%xmm0, -72(%edx)
-L(aligned_16_56bytes):
-	movdqa	%xmm0, -56(%edx)
-L(aligned_16_40bytes):
-	movdqa	%xmm0, -40(%edx)
-L(aligned_16_24bytes):
-	movdqa	%xmm0, -24(%edx)
-L(aligned_16_8bytes):
-	movq	%xmm0, -8(%edx)
-	SETRTNVAL
-	RETURN
-
-	ALIGN (4)
-L(aligned_16_124bytes):
-	movdqa	%xmm0, -124(%edx)
-L(aligned_16_108bytes):
-	movdqa	%xmm0, -108(%edx)
-L(aligned_16_92bytes):
-	movdqa	%xmm0, -92(%edx)
-L(aligned_16_76bytes):
-	movdqa	%xmm0, -76(%edx)
-L(aligned_16_60bytes):
-	movdqa	%xmm0, -60(%edx)
-L(aligned_16_44bytes):
-	movdqa	%xmm0, -44(%edx)
-L(aligned_16_28bytes):
-	movdqa	%xmm0, -28(%edx)
-L(aligned_16_12bytes):
-	movq	%xmm0, -12(%edx)
-	movl	%eax, -4(%edx)
-	SETRTNVAL
-	RETURN
-
-END (MEMSET)
diff --git a/libcutils/arch-x86_64/android_memset16.S b/libcutils/arch-x86_64/android_memset16.S
deleted file mode 100644
index cb6d4a3..0000000
--- a/libcutils/arch-x86_64/android_memset16.S
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "cache.h"
-
-#ifndef MEMSET
-# define MEMSET		android_memset16
-#endif
-
-#ifndef L
-# define L(label)	.L##label
-#endif
-
-#ifndef ALIGN
-# define ALIGN(n)	.p2align n
-#endif
-
-#ifndef cfi_startproc
-# define cfi_startproc			.cfi_startproc
-#endif
-
-#ifndef cfi_endproc
-# define cfi_endproc			.cfi_endproc
-#endif
-
-#ifndef ENTRY
-# define ENTRY(name)			\
-	.type name,  @function; 	\
-	.globl name;			\
-	.p2align 4;			\
-name:					\
-	cfi_startproc
-#endif
-
-#ifndef END
-# define END(name)			\
-	cfi_endproc;			\
-	.size name, .-name
-#endif
-
-#define JMPTBL(I, B)	I - B
-
-/* Branch to an entry in a jump table.  TABLE is a jump table with
-   relative offsets.  INDEX is a register contains the index into the
-   jump table.  SCALE is the scale of INDEX.  */
-#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \
-	lea    TABLE(%rip), %r11;						\
-	movslq (%r11, INDEX, SCALE), INDEX;				\
-	lea    (%r11, INDEX), INDEX;					\
-	jmp    *INDEX
-
-	.section .text.sse2,"ax",@progbits
-	ALIGN (4)
-ENTRY (MEMSET)	// Address in rdi
-	shr    $1, %rdx			// Count in rdx
-	movzwl %si, %ecx
-	/* Fill the whole ECX with pattern.  */
-	shl    $16, %esi
-	or     %esi, %ecx		// Pattern in ecx
-
-	cmp    $32, %rdx
-	jae    L(32wordsormore)
-
-L(write_less32words):
-	lea    (%rdi, %rdx, 2), %rdi
-	BRANCH_TO_JMPTBL_ENTRY (L(table_less32words), %rdx, 4)
-
-	.pushsection .rodata.sse2,"a",@progbits
-	ALIGN (2)
-L(table_less32words):
-	.int	JMPTBL (L(write_0words), L(table_less32words))
-	.int	JMPTBL (L(write_1words), L(table_less32words))
-	.int	JMPTBL (L(write_2words), L(table_less32words))
-	.int	JMPTBL (L(write_3words), L(table_less32words))
-	.int	JMPTBL (L(write_4words), L(table_less32words))
-	.int	JMPTBL (L(write_5words), L(table_less32words))
-	.int	JMPTBL (L(write_6words), L(table_less32words))
-	.int	JMPTBL (L(write_7words), L(table_less32words))
-	.int	JMPTBL (L(write_8words), L(table_less32words))
-	.int	JMPTBL (L(write_9words), L(table_less32words))
-	.int	JMPTBL (L(write_10words), L(table_less32words))
-	.int	JMPTBL (L(write_11words), L(table_less32words))
-	.int	JMPTBL (L(write_12words), L(table_less32words))
-	.int	JMPTBL (L(write_13words), L(table_less32words))
-	.int	JMPTBL (L(write_14words), L(table_less32words))
-	.int	JMPTBL (L(write_15words), L(table_less32words))
-	.int	JMPTBL (L(write_16words), L(table_less32words))
-	.int	JMPTBL (L(write_17words), L(table_less32words))
-	.int	JMPTBL (L(write_18words), L(table_less32words))
-	.int	JMPTBL (L(write_19words), L(table_less32words))
-	.int	JMPTBL (L(write_20words), L(table_less32words))
-	.int	JMPTBL (L(write_21words), L(table_less32words))
-	.int	JMPTBL (L(write_22words), L(table_less32words))
-	.int	JMPTBL (L(write_23words), L(table_less32words))
-	.int	JMPTBL (L(write_24words), L(table_less32words))
-	.int	JMPTBL (L(write_25words), L(table_less32words))
-	.int	JMPTBL (L(write_26words), L(table_less32words))
-	.int	JMPTBL (L(write_27words), L(table_less32words))
-	.int	JMPTBL (L(write_28words), L(table_less32words))
-	.int	JMPTBL (L(write_29words), L(table_less32words))
-	.int	JMPTBL (L(write_30words), L(table_less32words))
-	.int	JMPTBL (L(write_31words), L(table_less32words))
-	.popsection
-
-	ALIGN (4)
-L(write_28words):
-	movl   %ecx, -56(%rdi)
-	movl   %ecx, -52(%rdi)
-L(write_24words):
-	movl   %ecx, -48(%rdi)
-	movl   %ecx, -44(%rdi)
-L(write_20words):
-	movl   %ecx, -40(%rdi)
-	movl   %ecx, -36(%rdi)
-L(write_16words):
-	movl   %ecx, -32(%rdi)
-	movl   %ecx, -28(%rdi)
-L(write_12words):
-	movl   %ecx, -24(%rdi)
-	movl   %ecx, -20(%rdi)
-L(write_8words):
-	movl   %ecx, -16(%rdi)
-	movl   %ecx, -12(%rdi)
-L(write_4words):
-	movl   %ecx, -8(%rdi)
-	movl   %ecx, -4(%rdi)
-L(write_0words):
-	ret
-
-	ALIGN (4)
-L(write_29words):
-	movl   %ecx, -58(%rdi)
-	movl   %ecx, -54(%rdi)
-L(write_25words):
-	movl   %ecx, -50(%rdi)
-	movl   %ecx, -46(%rdi)
-L(write_21words):
-	movl   %ecx, -42(%rdi)
-	movl   %ecx, -38(%rdi)
-L(write_17words):
-	movl   %ecx, -34(%rdi)
-	movl   %ecx, -30(%rdi)
-L(write_13words):
-	movl   %ecx, -26(%rdi)
-	movl   %ecx, -22(%rdi)
-L(write_9words):
-	movl   %ecx, -18(%rdi)
-	movl   %ecx, -14(%rdi)
-L(write_5words):
-	movl   %ecx, -10(%rdi)
-	movl   %ecx, -6(%rdi)
-L(write_1words):
-	mov	%cx, -2(%rdi)
-	ret
-
-	ALIGN (4)
-L(write_30words):
-	movl   %ecx, -60(%rdi)
-	movl   %ecx, -56(%rdi)
-L(write_26words):
-	movl   %ecx, -52(%rdi)
-	movl   %ecx, -48(%rdi)
-L(write_22words):
-	movl   %ecx, -44(%rdi)
-	movl   %ecx, -40(%rdi)
-L(write_18words):
-	movl   %ecx, -36(%rdi)
-	movl   %ecx, -32(%rdi)
-L(write_14words):
-	movl   %ecx, -28(%rdi)
-	movl   %ecx, -24(%rdi)
-L(write_10words):
-	movl   %ecx, -20(%rdi)
-	movl   %ecx, -16(%rdi)
-L(write_6words):
-	movl   %ecx, -12(%rdi)
-	movl   %ecx, -8(%rdi)
-L(write_2words):
-	movl   %ecx, -4(%rdi)
-	ret
-
-	ALIGN (4)
-L(write_31words):
-	movl   %ecx, -62(%rdi)
-	movl   %ecx, -58(%rdi)
-L(write_27words):
-	movl   %ecx, -54(%rdi)
-	movl   %ecx, -50(%rdi)
-L(write_23words):
-	movl   %ecx, -46(%rdi)
-	movl   %ecx, -42(%rdi)
-L(write_19words):
-	movl   %ecx, -38(%rdi)
-	movl   %ecx, -34(%rdi)
-L(write_15words):
-	movl   %ecx, -30(%rdi)
-	movl   %ecx, -26(%rdi)
-L(write_11words):
-	movl   %ecx, -22(%rdi)
-	movl   %ecx, -18(%rdi)
-L(write_7words):
-	movl   %ecx, -14(%rdi)
-	movl   %ecx, -10(%rdi)
-L(write_3words):
-	movl   %ecx, -6(%rdi)
-	movw   %cx, -2(%rdi)
-	ret
-
-	ALIGN (4)
-L(32wordsormore):
-	shl    $1, %rdx
-	test   $0x01, %edi
-	jz     L(aligned2bytes)
-	mov    %ecx, (%rdi)
-	mov    %ecx, -4(%rdi, %rdx)
-	sub    $2, %rdx
-	add    $1, %rdi
-	rol    $8, %ecx
-L(aligned2bytes):
-	/* Fill xmm0 with the pattern.  */
-	movd   %ecx, %xmm0
-	pshufd $0, %xmm0, %xmm0
-
-	testl  $0xf, %edi
-	jz     L(aligned_16)
-/* RDX > 32 and RDI is not 16 byte aligned.  */
-	movdqu %xmm0, (%rdi)
-	mov    %rdi, %rsi
-	and    $-16, %rdi
-	add    $16, %rdi
-	sub    %rdi, %rsi
-	add    %rsi, %rdx
-
-	ALIGN (4)
-L(aligned_16):
-	cmp    $128, %rdx
-	jge    L(128bytesormore)
-
-L(aligned_16_less128bytes):
-	add    %rdx, %rdi
-	shr    $1, %rdx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
-
-	ALIGN (4)
-L(128bytesormore):
-	cmp    $SHARED_CACHE_SIZE, %rdx
-	jg     L(128bytesormore_nt)
-
-L(128bytesormore_normal):
-	sub    $128, %rdx
-	movdqa %xmm0, (%rdi)
-	movdqa %xmm0, 0x10(%rdi)
-	movdqa %xmm0, 0x20(%rdi)
-	movdqa %xmm0, 0x30(%rdi)
-	movdqa %xmm0, 0x40(%rdi)
-	movdqa %xmm0, 0x50(%rdi)
-	movdqa %xmm0, 0x60(%rdi)
-	movdqa %xmm0, 0x70(%rdi)
-	lea    128(%rdi), %rdi
-	cmp    $128, %rdx
-	jl     L(128bytesless_normal)
-
-	sub    $128, %rdx
-	movdqa %xmm0, (%rdi)
-	movdqa %xmm0, 0x10(%rdi)
-	movdqa %xmm0, 0x20(%rdi)
-	movdqa %xmm0, 0x30(%rdi)
-	movdqa %xmm0, 0x40(%rdi)
-	movdqa %xmm0, 0x50(%rdi)
-	movdqa %xmm0, 0x60(%rdi)
-	movdqa %xmm0, 0x70(%rdi)
-	lea    128(%rdi), %rdi
-	cmp    $128, %rdx
-	jl     L(128bytesless_normal)
-
-	sub    $128, %rdx
-	movdqa %xmm0, (%rdi)
-	movdqa %xmm0, 0x10(%rdi)
-	movdqa %xmm0, 0x20(%rdi)
-	movdqa %xmm0, 0x30(%rdi)
-	movdqa %xmm0, 0x40(%rdi)
-	movdqa %xmm0, 0x50(%rdi)
-	movdqa %xmm0, 0x60(%rdi)
-	movdqa %xmm0, 0x70(%rdi)
-	lea    128(%rdi), %rdi
-	cmp    $128, %rdx
-	jl     L(128bytesless_normal)
-
-	sub    $128, %rdx
-	movdqa %xmm0, (%rdi)
-	movdqa %xmm0, 0x10(%rdi)
-	movdqa %xmm0, 0x20(%rdi)
-	movdqa %xmm0, 0x30(%rdi)
-	movdqa %xmm0, 0x40(%rdi)
-	movdqa %xmm0, 0x50(%rdi)
-	movdqa %xmm0, 0x60(%rdi)
-	movdqa %xmm0, 0x70(%rdi)
-	lea    128(%rdi), %rdi
-	cmp    $128, %rdx
-	jge    L(128bytesormore_normal)
-
-L(128bytesless_normal):
-	add    %rdx, %rdi
-	shr    $1, %rdx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
-
-	ALIGN (4)
-L(128bytesormore_nt):
-	sub    $128, %rdx
-	movntdq %xmm0, (%rdi)
-	movntdq %xmm0, 0x10(%rdi)
-	movntdq %xmm0, 0x20(%rdi)
-	movntdq %xmm0, 0x30(%rdi)
-	movntdq %xmm0, 0x40(%rdi)
-	movntdq %xmm0, 0x50(%rdi)
-	movntdq %xmm0, 0x60(%rdi)
-	movntdq %xmm0, 0x70(%rdi)
-	lea    128(%rdi), %rdi
-	cmp    $128, %rdx
-	jge    L(128bytesormore_nt)
-
-	sfence
-	add    %rdx, %rdi
-	shr    $1, %rdx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
-
-	.pushsection .rodata.sse2,"a",@progbits
-	ALIGN (2)
-L(table_16_128bytes):
-	.int	JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_2bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_6bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_10bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_14bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_18bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_22bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_26bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_30bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_34bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_38bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_42bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_46bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_50bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_54bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_58bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_62bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_66bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_70bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_74bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_78bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_82bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_86bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_90bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_94bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_98bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_102bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_106bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_110bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_114bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_118bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_122bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_126bytes), L(table_16_128bytes))
-	.popsection
-
-	ALIGN (4)
-L(aligned_16_112bytes):
-	movdqa %xmm0, -112(%rdi)
-L(aligned_16_96bytes):
-	movdqa %xmm0, -96(%rdi)
-L(aligned_16_80bytes):
-	movdqa %xmm0, -80(%rdi)
-L(aligned_16_64bytes):
-	movdqa %xmm0, -64(%rdi)
-L(aligned_16_48bytes):
-	movdqa %xmm0, -48(%rdi)
-L(aligned_16_32bytes):
-	movdqa %xmm0, -32(%rdi)
-L(aligned_16_16bytes):
-	movdqa %xmm0, -16(%rdi)
-L(aligned_16_0bytes):
-	ret
-
-	ALIGN (4)
-L(aligned_16_114bytes):
-	movdqa %xmm0, -114(%rdi)
-L(aligned_16_98bytes):
-	movdqa %xmm0, -98(%rdi)
-L(aligned_16_82bytes):
-	movdqa %xmm0, -82(%rdi)
-L(aligned_16_66bytes):
-	movdqa %xmm0, -66(%rdi)
-L(aligned_16_50bytes):
-	movdqa %xmm0, -50(%rdi)
-L(aligned_16_34bytes):
-	movdqa %xmm0, -34(%rdi)
-L(aligned_16_18bytes):
-	movdqa %xmm0, -18(%rdi)
-L(aligned_16_2bytes):
-	movw   %cx, -2(%rdi)
-	ret
-
-	ALIGN (4)
-L(aligned_16_116bytes):
-	movdqa %xmm0, -116(%rdi)
-L(aligned_16_100bytes):
-	movdqa %xmm0, -100(%rdi)
-L(aligned_16_84bytes):
-	movdqa %xmm0, -84(%rdi)
-L(aligned_16_68bytes):
-	movdqa %xmm0, -68(%rdi)
-L(aligned_16_52bytes):
-	movdqa %xmm0, -52(%rdi)
-L(aligned_16_36bytes):
-	movdqa %xmm0, -36(%rdi)
-L(aligned_16_20bytes):
-	movdqa %xmm0, -20(%rdi)
-L(aligned_16_4bytes):
-	movl   %ecx, -4(%rdi)
-	ret
-
-	ALIGN (4)
-L(aligned_16_118bytes):
-	movdqa %xmm0, -118(%rdi)
-L(aligned_16_102bytes):
-	movdqa %xmm0, -102(%rdi)
-L(aligned_16_86bytes):
-	movdqa %xmm0, -86(%rdi)
-L(aligned_16_70bytes):
-	movdqa %xmm0, -70(%rdi)
-L(aligned_16_54bytes):
-	movdqa %xmm0, -54(%rdi)
-L(aligned_16_38bytes):
-	movdqa %xmm0, -38(%rdi)
-L(aligned_16_22bytes):
-	movdqa %xmm0, -22(%rdi)
-L(aligned_16_6bytes):
-	movl   %ecx, -6(%rdi)
-	movw   %cx, -2(%rdi)
-	ret
-
-	ALIGN (4)
-L(aligned_16_120bytes):
-	movdqa %xmm0, -120(%rdi)
-L(aligned_16_104bytes):
-	movdqa %xmm0, -104(%rdi)
-L(aligned_16_88bytes):
-	movdqa %xmm0, -88(%rdi)
-L(aligned_16_72bytes):
-	movdqa %xmm0, -72(%rdi)
-L(aligned_16_56bytes):
-	movdqa %xmm0, -56(%rdi)
-L(aligned_16_40bytes):
-	movdqa %xmm0, -40(%rdi)
-L(aligned_16_24bytes):
-	movdqa %xmm0, -24(%rdi)
-L(aligned_16_8bytes):
-	movq   %xmm0, -8(%rdi)
-	ret
-
-	ALIGN (4)
-L(aligned_16_122bytes):
-	movdqa %xmm0, -122(%rdi)
-L(aligned_16_106bytes):
-	movdqa %xmm0, -106(%rdi)
-L(aligned_16_90bytes):
-	movdqa %xmm0, -90(%rdi)
-L(aligned_16_74bytes):
-	movdqa %xmm0, -74(%rdi)
-L(aligned_16_58bytes):
-	movdqa %xmm0, -58(%rdi)
-L(aligned_16_42bytes):
-	movdqa %xmm0, -42(%rdi)
-L(aligned_16_26bytes):
-	movdqa %xmm0, -26(%rdi)
-L(aligned_16_10bytes):
-	movq   %xmm0, -10(%rdi)
-	movw   %cx, -2(%rdi)
-	ret
-
-	ALIGN (4)
-L(aligned_16_124bytes):
-	movdqa %xmm0, -124(%rdi)
-L(aligned_16_108bytes):
-	movdqa %xmm0, -108(%rdi)
-L(aligned_16_92bytes):
-	movdqa %xmm0, -92(%rdi)
-L(aligned_16_76bytes):
-	movdqa %xmm0, -76(%rdi)
-L(aligned_16_60bytes):
-	movdqa %xmm0, -60(%rdi)
-L(aligned_16_44bytes):
-	movdqa %xmm0, -44(%rdi)
-L(aligned_16_28bytes):
-	movdqa %xmm0, -28(%rdi)
-L(aligned_16_12bytes):
-	movq   %xmm0, -12(%rdi)
-	movl   %ecx, -4(%rdi)
-	ret
-
-	ALIGN (4)
-L(aligned_16_126bytes):
-	movdqa %xmm0, -126(%rdi)
-L(aligned_16_110bytes):
-	movdqa %xmm0, -110(%rdi)
-L(aligned_16_94bytes):
-	movdqa %xmm0, -94(%rdi)
-L(aligned_16_78bytes):
-	movdqa %xmm0, -78(%rdi)
-L(aligned_16_62bytes):
-	movdqa %xmm0, -62(%rdi)
-L(aligned_16_46bytes):
-	movdqa %xmm0, -46(%rdi)
-L(aligned_16_30bytes):
-	movdqa %xmm0, -30(%rdi)
-L(aligned_16_14bytes):
-	movq   %xmm0, -14(%rdi)
-	movl   %ecx, -6(%rdi)
-	movw   %cx, -2(%rdi)
-	ret
-
-END (MEMSET)
diff --git a/libcutils/arch-x86_64/android_memset32.S b/libcutils/arch-x86_64/android_memset32.S
deleted file mode 100644
index 1514aa2..0000000
--- a/libcutils/arch-x86_64/android_memset32.S
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "cache.h"
-
-#ifndef MEMSET
-# define MEMSET		android_memset32
-#endif
-
-#ifndef L
-# define L(label)	.L##label
-#endif
-
-#ifndef ALIGN
-# define ALIGN(n)	.p2align n
-#endif
-
-#ifndef cfi_startproc
-# define cfi_startproc			.cfi_startproc
-#endif
-
-#ifndef cfi_endproc
-# define cfi_endproc			.cfi_endproc
-#endif
-
-#ifndef ENTRY
-# define ENTRY(name)			\
-	.type name,  @function; 	\
-	.globl name;			\
-	.p2align 4;			\
-name:					\
-	cfi_startproc
-#endif
-
-#ifndef END
-# define END(name)			\
-	cfi_endproc;			\
-	.size name, .-name
-#endif
-
-#define JMPTBL(I, B)	I - B
-
-/* Branch to an entry in a jump table.  TABLE is a jump table with
-   relative offsets.  INDEX is a register contains the index into the
-   jump table.  SCALE is the scale of INDEX.  */
-#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \
-	lea    TABLE(%rip), %r11;						\
-	movslq (%r11, INDEX, SCALE), INDEX;				\
-	lea    (%r11, INDEX), INDEX;					\
-	jmp    *INDEX
-
-	.section .text.sse2,"ax",@progbits
-	ALIGN (4)
-ENTRY (MEMSET)	// Address in rdi
-	shr    $2, %rdx			// Count in rdx
-	movl   %esi, %ecx		// Pattern in ecx
-
-	cmp    $16, %rdx
-	jae    L(16dbwordsormore)
-
-L(write_less16dbwords):
-	lea    (%rdi, %rdx, 4), %rdi
-	BRANCH_TO_JMPTBL_ENTRY (L(table_less16dbwords), %rdx, 4)
-
-	.pushsection .rodata.sse2,"a",@progbits
-	ALIGN (2)
-L(table_less16dbwords):
-	.int	JMPTBL (L(write_0dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_1dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_2dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_3dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_4dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_5dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_6dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_7dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_8dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_9dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_10dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_11dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_12dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_13dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_14dbwords), L(table_less16dbwords))
-	.int	JMPTBL (L(write_15dbwords), L(table_less16dbwords))
-	.popsection
-
-	ALIGN (4)
-L(write_15dbwords):
-	movl   %ecx, -60(%rdi)
-L(write_14dbwords):
-	movl   %ecx, -56(%rdi)
-L(write_13dbwords):
-	movl   %ecx, -52(%rdi)
-L(write_12dbwords):
-	movl   %ecx, -48(%rdi)
-L(write_11dbwords):
-	movl   %ecx, -44(%rdi)
-L(write_10dbwords):
-	movl   %ecx, -40(%rdi)
-L(write_9dbwords):
-	movl   %ecx, -36(%rdi)
-L(write_8dbwords):
-	movl   %ecx, -32(%rdi)
-L(write_7dbwords):
-	movl   %ecx, -28(%rdi)
-L(write_6dbwords):
-	movl   %ecx, -24(%rdi)
-L(write_5dbwords):
-	movl   %ecx, -20(%rdi)
-L(write_4dbwords):
-	movl   %ecx, -16(%rdi)
-L(write_3dbwords):
-	movl   %ecx, -12(%rdi)
-L(write_2dbwords):
-	movl   %ecx, -8(%rdi)
-L(write_1dbwords):
-	movl   %ecx, -4(%rdi)
-L(write_0dbwords):
-	ret
-
-	ALIGN (4)
-L(16dbwordsormore):
-	test   $3, %edi
-	jz     L(aligned4bytes)
-	mov    %ecx, (%rdi)
-	mov    %ecx, -4(%rdi, %rdx, 4)
-	sub    $1, %rdx
-	rol    $24, %ecx
-	add    $1, %rdi
-	test   $3, %edi
-	jz     L(aligned4bytes)
-	ror    $8, %ecx
-	add    $1, %rdi
-	test   $3, %edi
-	jz     L(aligned4bytes)
-	ror    $8, %ecx
-	add    $1, %rdi
-L(aligned4bytes):
-	shl    $2, %rdx
-
-	/* Fill xmm0 with the pattern.  */
-	movd   %ecx, %xmm0
-	pshufd $0, %xmm0, %xmm0
-
-	testl  $0xf, %edi
-	jz     L(aligned_16)
-/* RDX > 32 and RDI is not 16 byte aligned.  */
-	movdqu %xmm0, (%rdi)
-	mov    %rdi, %rsi
-	and    $-16, %rdi
-	add    $16, %rdi
-	sub    %rdi, %rsi
-	add    %rsi, %rdx
-
-	ALIGN (4)
-L(aligned_16):
-	cmp    $128, %rdx
-	jge    L(128bytesormore)
-
-L(aligned_16_less128bytes):
-	add    %rdx, %rdi
-	shr    $2, %rdx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
-
-	ALIGN (4)
-L(128bytesormore):
-	cmp    $SHARED_CACHE_SIZE, %rdx
-	jg     L(128bytesormore_nt)
-
-L(128bytesormore_normal):
-	sub    $128, %rdx
-	movdqa %xmm0, (%rdi)
-	movdqa %xmm0, 0x10(%rdi)
-	movdqa %xmm0, 0x20(%rdi)
-	movdqa %xmm0, 0x30(%rdi)
-	movdqa %xmm0, 0x40(%rdi)
-	movdqa %xmm0, 0x50(%rdi)
-	movdqa %xmm0, 0x60(%rdi)
-	movdqa %xmm0, 0x70(%rdi)
-	lea    128(%rdi), %rdi
-	cmp    $128, %rdx
-	jl     L(128bytesless_normal)
-
-	sub    $128, %rdx
-	movdqa %xmm0, (%rdi)
-	movdqa %xmm0, 0x10(%rdi)
-	movdqa %xmm0, 0x20(%rdi)
-	movdqa %xmm0, 0x30(%rdi)
-	movdqa %xmm0, 0x40(%rdi)
-	movdqa %xmm0, 0x50(%rdi)
-	movdqa %xmm0, 0x60(%rdi)
-	movdqa %xmm0, 0x70(%rdi)
-	lea    128(%rdi), %rdi
-	cmp    $128, %rdx
-	jl     L(128bytesless_normal)
-
-	sub    $128, %rdx
-	movdqa %xmm0, (%rdi)
-	movdqa %xmm0, 0x10(%rdi)
-	movdqa %xmm0, 0x20(%rdi)
-	movdqa %xmm0, 0x30(%rdi)
-	movdqa %xmm0, 0x40(%rdi)
-	movdqa %xmm0, 0x50(%rdi)
-	movdqa %xmm0, 0x60(%rdi)
-	movdqa %xmm0, 0x70(%rdi)
-	lea    128(%rdi), %rdi
-	cmp    $128, %rdx
-	jl     L(128bytesless_normal)
-
-	sub    $128, %rdx
-	movdqa %xmm0, (%rdi)
-	movdqa %xmm0, 0x10(%rdi)
-	movdqa %xmm0, 0x20(%rdi)
-	movdqa %xmm0, 0x30(%rdi)
-	movdqa %xmm0, 0x40(%rdi)
-	movdqa %xmm0, 0x50(%rdi)
-	movdqa %xmm0, 0x60(%rdi)
-	movdqa %xmm0, 0x70(%rdi)
-	lea    128(%rdi), %rdi
-	cmp    $128, %rdx
-	jge    L(128bytesormore_normal)
-
-L(128bytesless_normal):
-	add    %rdx, %rdi
-	shr    $2, %rdx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
-
-	ALIGN (4)
-L(128bytesormore_nt):
-	sub    $128, %rdx
-	movntdq %xmm0, (%rdi)
-	movntdq %xmm0, 0x10(%rdi)
-	movntdq %xmm0, 0x20(%rdi)
-	movntdq %xmm0, 0x30(%rdi)
-	movntdq %xmm0, 0x40(%rdi)
-	movntdq %xmm0, 0x50(%rdi)
-	movntdq %xmm0, 0x60(%rdi)
-	movntdq %xmm0, 0x70(%rdi)
-	lea    128(%rdi), %rdi
-	cmp    $128, %rdx
-	jge    L(128bytesormore_nt)
-
-	sfence
-	add    %rdx, %rdi
-	shr    $2, %rdx
-	BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
-
-	.pushsection .rodata.sse2,"a",@progbits
-	ALIGN (2)
-L(table_16_128bytes):
-	.int	JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
-	.int	JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
-	.popsection
-
-	ALIGN (4)
-L(aligned_16_112bytes):
-	movdqa	%xmm0, -112(%rdi)
-L(aligned_16_96bytes):
-	movdqa	%xmm0, -96(%rdi)
-L(aligned_16_80bytes):
-	movdqa	%xmm0, -80(%rdi)
-L(aligned_16_64bytes):
-	movdqa	%xmm0, -64(%rdi)
-L(aligned_16_48bytes):
-	movdqa	%xmm0, -48(%rdi)
-L(aligned_16_32bytes):
-	movdqa	%xmm0, -32(%rdi)
-L(aligned_16_16bytes):
-	movdqa	%xmm0, -16(%rdi)
-L(aligned_16_0bytes):
-	ret
-
-	ALIGN (4)
-L(aligned_16_116bytes):
-	movdqa	%xmm0, -116(%rdi)
-L(aligned_16_100bytes):
-	movdqa	%xmm0, -100(%rdi)
-L(aligned_16_84bytes):
-	movdqa	%xmm0, -84(%rdi)
-L(aligned_16_68bytes):
-	movdqa	%xmm0, -68(%rdi)
-L(aligned_16_52bytes):
-	movdqa	%xmm0, -52(%rdi)
-L(aligned_16_36bytes):
-	movdqa	%xmm0, -36(%rdi)
-L(aligned_16_20bytes):
-	movdqa	%xmm0, -20(%rdi)
-L(aligned_16_4bytes):
-	movl	%ecx, -4(%rdi)
-	ret
-
-	ALIGN (4)
-L(aligned_16_120bytes):
-	movdqa	%xmm0, -120(%rdi)
-L(aligned_16_104bytes):
-	movdqa	%xmm0, -104(%rdi)
-L(aligned_16_88bytes):
-	movdqa	%xmm0, -88(%rdi)
-L(aligned_16_72bytes):
-	movdqa	%xmm0, -72(%rdi)
-L(aligned_16_56bytes):
-	movdqa	%xmm0, -56(%rdi)
-L(aligned_16_40bytes):
-	movdqa	%xmm0, -40(%rdi)
-L(aligned_16_24bytes):
-	movdqa	%xmm0, -24(%rdi)
-L(aligned_16_8bytes):
-	movq	%xmm0, -8(%rdi)
-	ret
-
-	ALIGN (4)
-L(aligned_16_124bytes):
-	movdqa	%xmm0, -124(%rdi)
-L(aligned_16_108bytes):
-	movdqa	%xmm0, -108(%rdi)
-L(aligned_16_92bytes):
-	movdqa	%xmm0, -92(%rdi)
-L(aligned_16_76bytes):
-	movdqa	%xmm0, -76(%rdi)
-L(aligned_16_60bytes):
-	movdqa	%xmm0, -60(%rdi)
-L(aligned_16_44bytes):
-	movdqa	%xmm0, -44(%rdi)
-L(aligned_16_28bytes):
-	movdqa	%xmm0, -28(%rdi)
-L(aligned_16_12bytes):
-	movq	%xmm0, -12(%rdi)
-	movl	%ecx, -4(%rdi)
-	ret
-
-END (MEMSET)
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
index 8c232f0..6a27f9a 100644
--- a/libcutils/ashmem-dev.cpp
+++ b/libcutils/ashmem-dev.cpp
@@ -122,7 +122,8 @@
         return true;
     }
 
-    /* If its not a number, assume string, but check if its a sane string */
+    // Non-numeric should be a single ASCII character. Characters after the
+    // first are ignored.
     if (tolower(vndk_version[0]) < 'a' || tolower(vndk_version[0]) > 'z') {
         ALOGE("memfd: ro.vndk.version not defined or invalid (%s), this is mandated since P.\n",
               vndk_version.c_str());
@@ -158,9 +159,11 @@
         return false;
     }
 
-    /* Check if kernel support exists, otherwise fall back to ashmem */
+    // Check if kernel support exists, otherwise fall back to ashmem.
+    // This code needs to build on old API levels, so we can't use the libc
+    // wrapper.
     android::base::unique_fd fd(
-            syscall(__NR_memfd_create, "test_android_memfd", MFD_ALLOW_SEALING));
+            syscall(__NR_memfd_create, "test_android_memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING));
     if (fd == -1) {
         ALOGE("memfd_create failed: %s, no memfd support.\n", strerror(errno));
         return false;
@@ -211,13 +214,16 @@
 
     // fallback for APEX w/ use_vendor on Q, which would have still used /dev/ashmem
     if (fd < 0) {
+        int saved_errno = errno;
         fd = TEMP_FAILURE_RETRY(open("/dev/ashmem", O_RDWR | O_CLOEXEC));
+        if (fd < 0) {
+            /* Q launching devices and newer must not reach here since they should have been
+             * able to open ashmem_device_path */
+            ALOGE("Unable to open ashmem device %s (error = %s) and /dev/ashmem(error = %s)",
+                  ashmem_device_path.c_str(), strerror(saved_errno), strerror(errno));
+            return fd;
+        }
     }
-
-    if (fd < 0) {
-        return fd;
-    }
-
     struct stat st;
     int ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
     if (ret < 0) {
@@ -329,7 +335,9 @@
 }
 
 static int memfd_create_region(const char* name, size_t size) {
-    android::base::unique_fd fd(syscall(__NR_memfd_create, name, MFD_ALLOW_SEALING));
+    // This code needs to build on old API levels, so we can't use the libc
+    // wrapper.
+    android::base::unique_fd fd(syscall(__NR_memfd_create, name, MFD_CLOEXEC | MFD_ALLOW_SEALING));
 
     if (fd == -1) {
         ALOGE("memfd_create(%s, %zd) failed: %s\n", name, size, strerror(errno));
diff --git a/libcutils/ashmem_test.cpp b/libcutils/ashmem_test.cpp
index b37d020..fb657f6 100644
--- a/libcutils/ashmem_test.cpp
+++ b/libcutils/ashmem_test.cpp
@@ -35,6 +35,11 @@
     ASSERT_TRUE(ashmem_valid(fd));
     ASSERT_EQ(size, static_cast<size_t>(ashmem_get_size_region(fd)));
     ASSERT_EQ(0, ashmem_set_prot_region(fd, prot));
+
+    // We've been inconsistent historically about whether or not these file
+    // descriptors were CLOEXEC. Make sure we're consistent going forward.
+    // https://issuetracker.google.com/165667331
+    ASSERT_EQ(FD_CLOEXEC, (fcntl(fd, F_GETFD) & FD_CLOEXEC));
 }
 
 void TestMmap(const unique_fd& fd, size_t size, int prot, void** region, off_t off = 0) {
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 5805a4d..31e1679 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -80,6 +80,7 @@
     { 00771, AID_SYSTEM,       AID_SYSTEM,       0, "data" },
     { 00755, AID_ROOT,         AID_SYSTEM,       0, "mnt" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "product/bin" },
+    { 00751, AID_ROOT,         AID_SHELL,        0, "product/apex/*/bin" },
     { 00777, AID_ROOT,         AID_ROOT,         0, "sdcard" },
     { 00751, AID_ROOT,         AID_SDCARD_R,     0, "storage" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "system/bin" },
@@ -90,6 +91,7 @@
     { 00751, AID_ROOT,         AID_SHELL,        0, "system_ext/bin" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "system_ext/apex/*/bin" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "vendor/bin" },
+    { 00751, AID_ROOT,         AID_SHELL,        0, "vendor/apex/*/bin" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "vendor" },
     { 00755, AID_ROOT,         AID_ROOT,         0, 0 },
         // clang-format on
@@ -203,18 +205,21 @@
     { 00755, AID_ROOT,      AID_ROOT,      0, "first_stage_ramdisk/system/bin/e2fsck" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "first_stage_ramdisk/system/bin/tune2fs" },
     { 00755, AID_ROOT,      AID_ROOT,      0, "first_stage_ramdisk/system/bin/resize2fs" },
+    { 00755, AID_ROOT,      AID_ROOT,      0, "first_stage_ramdisk/system/bin/snapuserd" },
     // generic defaults
     { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
     { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "init*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "odm/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "product/bin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "product/apex/*bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/apex/*/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system_ext/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system_ext/apex/*/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/apex/*bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/xbin/*" },
     { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
         // clang-format on
diff --git a/libcutils/include/cutils/memory.h b/libcutils/include/cutils/memory.h
index 4d26882..c6476c1 100644
--- a/libcutils/include/cutils/memory.h
+++ b/libcutils/include/cutils/memory.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_CUTILS_MEMORY_H
-#define ANDROID_CUTILS_MEMORY_H
+#pragma once
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -24,12 +23,6 @@
 extern "C" {
 #endif
 
-/* size is given in bytes and must be multiple of 2 */
-void android_memset16(uint16_t* dst, uint16_t value, size_t size);
-
-/* size is given in bytes and must be multiple of 4 */
-void android_memset32(uint32_t* dst, uint32_t value, size_t size);
-
 #if defined(__GLIBC__) || defined(_WIN32)
 /* Declaration of strlcpy() for platforms that don't already have it. */
 size_t strlcpy(char *dst, const char *src, size_t size);
@@ -38,5 +31,3 @@
 #ifdef __cplusplus
 } // extern "C"
 #endif
-
-#endif // ANDROID_CUTILS_MEMORY_H
diff --git a/libcutils/include/cutils/trace.h b/libcutils/include/cutils/trace.h
index c74ee3e..793e2ce 100644
--- a/libcutils/include/cutils/trace.h
+++ b/libcutils/include/cutils/trace.h
@@ -75,7 +75,8 @@
 #define ATRACE_TAG_AIDL             (1<<24)
 #define ATRACE_TAG_NNAPI            (1<<25)
 #define ATRACE_TAG_RRO              (1<<26)
-#define ATRACE_TAG_LAST             ATRACE_TAG_RRO
+#define ATRACE_TAG_SYSPROP          (1<<27)
+#define ATRACE_TAG_LAST             ATRACE_TAG_SYSPROP
 
 // Reserved for initialization.
 #define ATRACE_TAG_NOT_READY        (1ULL<<63)
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index e4f45a8..b4fe2e6 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -36,7 +36,7 @@
 
 #pragma once
 
-/* This is the master Users and Groups config for the platform.
+/* This is the main Users and Groups config for the platform.
  * DO NOT EVER RENUMBER
  */
 
diff --git a/libcutils/memset_test.cpp b/libcutils/memset_test.cpp
deleted file mode 100644
index a98485f..0000000
--- a/libcutils/memset_test.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-
-#include <memory>
-
-#include <cutils/memory.h>
-#include <gtest/gtest.h>
-
-#define FENCEPOST_LENGTH 8
-
-#define MAX_TEST_SIZE (64*1024)
-// Choose values that have no repeating byte values.
-#define MEMSET16_PATTERN 0xb139
-#define MEMSET32_PATTERN 0x48193a27
-
-enum test_e {
-  MEMSET16 = 0,
-  MEMSET32,
-};
-
-static int g_memset16_aligns[][2] = {
-  { 2, 0 },
-  { 4, 0 },
-  { 8, 0 },
-  { 16, 0 },
-  { 32, 0 },
-  { 64, 0 },
-  { 128, 0 },
-
-  { 4, 2 },
-
-  { 8, 2 },
-  { 8, 4 },
-  { 8, 6 },
-
-  { 128, 2 },
-  { 128, 4 },
-  { 128, 6 },
-  { 128, 8 },
-  { 128, 10 },
-  { 128, 12 },
-  { 128, 14 },
-  { 128, 16 },
-};
-
-static int g_memset32_aligns[][2] = {
-  { 4, 0 },
-  { 8, 0 },
-  { 16, 0 },
-  { 32, 0 },
-  { 64, 0 },
-  { 128, 0 },
-
-  { 8, 4 },
-
-  { 128, 4 },
-  { 128, 8 },
-  { 128, 12 },
-  { 128, 16 },
-};
-
-static size_t GetIncrement(size_t len, size_t min_incr) {
-  if (len >= 4096) {
-    return 1024;
-  } else if (len >= 1024) {
-    return 256;
-  }
-  return min_incr;
-}
-
-// Return a pointer into the current buffer with the specified alignment.
-static void *GetAlignedPtr(void *orig_ptr, int alignment, int or_mask) {
-  uint64_t ptr = reinterpret_cast<uint64_t>(orig_ptr);
-  if (alignment > 0) {
-      // When setting the alignment, set it to exactly the alignment chosen.
-      // The pointer returned will be guaranteed not to be aligned to anything
-      // more than that.
-      ptr += alignment - (ptr & (alignment - 1));
-      ptr |= alignment | or_mask;
-  }
-
-  return reinterpret_cast<void*>(ptr);
-}
-
-static void SetFencepost(uint8_t *buffer) {
-  for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
-    buffer[i] = 0xde;
-    buffer[i+1] = 0xad;
-  }
-}
-
-static void VerifyFencepost(uint8_t *buffer) {
-  for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
-    if (buffer[i] != 0xde || buffer[i+1] != 0xad) {
-      uint8_t expected_value;
-      if (buffer[i] == 0xde) {
-        i++;
-        expected_value = 0xad;
-      } else {
-        expected_value = 0xde;
-      }
-      ASSERT_EQ(expected_value, buffer[i]);
-    }
-  }
-}
-
-void RunMemsetTests(test_e test_type, uint32_t value, int align[][2], size_t num_aligns) {
-  size_t min_incr = 4;
-  if (test_type == MEMSET16) {
-    min_incr = 2;
-    value |= value << 16;
-  }
-  std::unique_ptr<uint32_t[]> expected_buf(new uint32_t[MAX_TEST_SIZE/sizeof(uint32_t)]);
-  for (size_t i = 0; i < MAX_TEST_SIZE/sizeof(uint32_t); i++) {
-    expected_buf[i] = value;
-  }
-
-  // Allocate one large buffer with lots of extra space so that we can
-  // guarantee that all possible alignments will fit.
-  std::unique_ptr<uint8_t[]> buf(new uint8_t[3*MAX_TEST_SIZE]);
-  uint8_t *buf_align;
-  for (size_t i = 0; i < num_aligns; i++) {
-    size_t incr = min_incr;
-    for (size_t len = incr; len <= MAX_TEST_SIZE; len += incr) {
-      incr = GetIncrement(len, min_incr);
-
-      buf_align = reinterpret_cast<uint8_t*>(GetAlignedPtr(
-          buf.get()+FENCEPOST_LENGTH, align[i][0], align[i][1]));
-
-      SetFencepost(&buf_align[-FENCEPOST_LENGTH]);
-      SetFencepost(&buf_align[len]);
-
-      memset(buf_align, 0xff, len);
-      if (test_type == MEMSET16) {
-        android_memset16(reinterpret_cast<uint16_t*>(buf_align), value, len);
-      } else {
-        android_memset32(reinterpret_cast<uint32_t*>(buf_align), value, len);
-      }
-      ASSERT_EQ(0, memcmp(expected_buf.get(), buf_align, len))
-          << "Failed size " << len << " align " << align[i][0] << " " << align[i][1] << "\n";
-
-      VerifyFencepost(&buf_align[-FENCEPOST_LENGTH]);
-      VerifyFencepost(&buf_align[len]);
-    }
-  }
-}
-
-TEST(libcutils, android_memset16_non_zero) {
-  RunMemsetTests(MEMSET16, MEMSET16_PATTERN, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
-}
-
-TEST(libcutils, android_memset16_zero) {
-  RunMemsetTests(MEMSET16, 0, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
-}
-
-TEST(libcutils, android_memset32_non_zero) {
-  RunMemsetTests(MEMSET32, MEMSET32_PATTERN, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
-}
-
-TEST(libcutils, android_memset32_zero) {
-  RunMemsetTests(MEMSET32, 0, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
-}
diff --git a/libcutils/qtaguid.cpp b/libcutils/qtaguid.cpp
index b94d134..2fe877c 100644
--- a/libcutils/qtaguid.cpp
+++ b/libcutils/qtaguid.cpp
@@ -38,24 +38,24 @@
     int (*netdDeleteTagData)(uint32_t, uid_t);
 };
 
-int dummyTagSocket(int, uint32_t, uid_t) {
+int stubTagSocket(int, uint32_t, uid_t) {
     return -EREMOTEIO;
 }
 
-int dummyUntagSocket(int) {
+int stubUntagSocket(int) {
     return -EREMOTEIO;
 }
 
-int dummySetCounterSet(uint32_t, uid_t) {
+int stubSetCounterSet(uint32_t, uid_t) {
     return -EREMOTEIO;
 }
 
-int dummyDeleteTagData(uint32_t, uid_t) {
+int stubDeleteTagData(uint32_t, uid_t) {
     return -EREMOTEIO;
 }
 
 netdHandler initHandler(void) {
-    netdHandler handler = {dummyTagSocket, dummyUntagSocket, dummySetCounterSet, dummyDeleteTagData};
+    netdHandler handler = {stubTagSocket, stubUntagSocket, stubSetCounterSet, stubDeleteTagData};
 
     void* netdClientHandle = dlopen("libnetd_client.so", RTLD_NOW);
     if (!netdClientHandle) {
diff --git a/libcutils/trace-dev.cpp b/libcutils/trace-dev.cpp
index 5a09a2d..1ab63dc 100644
--- a/libcutils/trace-dev.cpp
+++ b/libcutils/trace-dev.cpp
@@ -30,9 +30,9 @@
 
 static void atrace_init_once()
 {
-    atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
+    atrace_marker_fd = open("/sys/kernel/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
     if (atrace_marker_fd == -1) {
-        atrace_marker_fd = open("/sys/kernel/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
+        atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
     }
 
     if (atrace_marker_fd == -1) {
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index 3ec98b3..6543426 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -198,7 +198,7 @@
 }
 
 #define WRITE_MSG(format_begin, format_end, name, value) { \
-    char buf[ATRACE_MESSAGE_LENGTH]; \
+    char buf[ATRACE_MESSAGE_LENGTH] __attribute__((uninitialized));     \
     int pid = getpid(); \
     int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \
         name, value); \
diff --git a/libcutils/uevent.cpp b/libcutils/uevent.cpp
index bf244d2..40bbd5c 100644
--- a/libcutils/uevent.cpp
+++ b/libcutils/uevent.cpp
@@ -101,7 +101,7 @@
 
     memset(&addr, 0, sizeof(addr));
     addr.nl_family = AF_NETLINK;
-    addr.nl_pid = getpid();
+    addr.nl_pid = 0;
     addr.nl_groups = 0xffffffff;
 
     s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT);
diff --git a/libkeyutils/keyutils_test.cpp b/libkeyutils/keyutils_test.cpp
index d41c91b..d03747b 100644
--- a/libkeyutils/keyutils_test.cpp
+++ b/libkeyutils/keyutils_test.cpp
@@ -33,7 +33,7 @@
 #include <gtest/gtest.h>
 
 TEST(keyutils, smoke) {
-  // Check that the exported type is sane.
+  // Check that the exported type is the right size.
   ASSERT_EQ(4U, sizeof(key_serial_t));
 
   // Check that all the functions actually exist.
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 6051ac7..8f15541 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -43,6 +43,7 @@
         "//apex_available:anyapex",
     ],
     min_sdk_version: "29",
+    sdk_version: "minimum",
     native_bridge_supported: true,
     export_include_dirs: ["include"],
     system_shared_libs: [],
@@ -97,6 +98,7 @@
 
     header_libs: [
         "libbase_headers",
+        "libcutils_headers",
         "liblog_headers",
     ],
     export_header_lib_headers: ["liblog_headers"],
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index 51c5e60..85556e8 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -31,84 +31,13 @@
 #include <unordered_map>
 
 #include <log/event_tag_map.h>
-#include <log/log_properties.h>
 #include <private/android_logger.h>
 #include <utils/FastStrcmp.h>
 #include <utils/RWLock.h>
 
-#include "logd_reader.h"
-
 #define OUT_TAG "EventTagMap"
 
-class MapString {
- private:
-  const std::string* alloc;                  // HAS-AN
-  const std::string_view str;                // HAS-A
-
- public:
-  operator const std::string_view() const {
-    return str;
-  }
-
-  const char* data() const {
-    return str.data();
-  }
-  size_t length() const {
-    return str.length();
-  }
-
-  bool operator==(const MapString& rval) const {
-    if (length() != rval.length()) return false;
-    if (length() == 0) return true;
-    return fastcmp<strncmp>(data(), rval.data(), length()) == 0;
-  }
-  bool operator!=(const MapString& rval) const {
-    return !(*this == rval);
-  }
-
-  MapString(const char* str, size_t len) : alloc(NULL), str(str, len) {
-  }
-  explicit MapString(const std::string& str)
-      : alloc(new std::string(str)), str(alloc->data(), alloc->length()) {
-  }
-  MapString(MapString&& rval) noexcept
-      : alloc(rval.alloc), str(rval.data(), rval.length()) {
-    rval.alloc = NULL;
-  }
-  explicit MapString(const MapString& rval)
-      : alloc(rval.alloc ? new std::string(*rval.alloc) : NULL),
-        str(alloc ? alloc->data() : rval.data(), rval.length()) {
-  }
-
-  ~MapString() {
-    if (alloc) delete alloc;
-  }
-};
-
-// Hash for MapString
-template <>
-struct std::hash<MapString>
-    : public std::unary_function<const MapString&, size_t> {
-  size_t operator()(const MapString& __t) const noexcept {
-    if (!__t.length()) return 0;
-    return std::hash<std::string_view>()(std::string_view(__t));
-  }
-};
-
-typedef std::pair<MapString, MapString> TagFmt;
-
-template <>
-struct std::hash<TagFmt> : public std::unary_function<const TagFmt&, size_t> {
-  size_t operator()(const TagFmt& __t) const noexcept {
-    // Tag is typically unique.  Will cost us an extra 100ns for the
-    // unordered_map lookup if we instead did a hash that combined
-    // both of tag and fmt members, e.g.:
-    //
-    // return std::hash<MapString>()(__t.first) ^
-    //        std::hash<MapString>()(__t.second);
-    return std::hash<MapString>()(__t.first);
-  }
-};
+typedef std::pair<std::string_view, std::string_view> TagFmt;
 
 // Map
 struct EventTagMap {
@@ -119,8 +48,7 @@
 
  private:
   std::unordered_map<uint32_t, TagFmt> Idx2TagFmt;
-  std::unordered_map<TagFmt, uint32_t> TagFmt2Idx;
-  std::unordered_map<MapString, uint32_t> Tag2Idx;
+  std::unordered_map<std::string_view, uint32_t> Tag2Idx;
   // protect unordered sets
   android::RWLock rwlock;
 
@@ -132,7 +60,6 @@
 
   ~EventTagMap() {
     Idx2TagFmt.clear();
-    TagFmt2Idx.clear();
     Tag2Idx.clear();
     for (size_t which = 0; which < NUM_MAPS; ++which) {
       if (mapAddr[which]) {
@@ -144,8 +71,7 @@
 
   bool emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose = false);
   const TagFmt* find(uint32_t tag) const;
-  int find(TagFmt&& tagfmt) const;
-  int find(MapString&& tag) const;
+  int find(std::string_view tag) const;
 };
 
 bool EventTagMap::emplaceUnique(uint32_t tag, const TagFmt& tagfmt,
@@ -156,8 +82,7 @@
               ":%.*s:%.*s)\n";
   android::RWLock::AutoWLock writeLock(rwlock);
   {
-    std::unordered_map<uint32_t, TagFmt>::const_iterator it;
-    it = Idx2TagFmt.find(tag);
+    auto it = Idx2TagFmt.find(tag);
     if (it != Idx2TagFmt.end()) {
       if (verbose) {
         fprintf(stderr, errorFormat, it->first, (int)it->second.first.length(),
@@ -173,25 +98,7 @@
   }
 
   {
-    std::unordered_map<TagFmt, uint32_t>::const_iterator it;
-    it = TagFmt2Idx.find(tagfmt);
-    if (it != TagFmt2Idx.end()) {
-      if (verbose) {
-        fprintf(stderr, errorFormat, it->second, (int)it->first.first.length(),
-                it->first.first.data(), (int)it->first.second.length(),
-                it->first.second.data(), tag, (int)tagfmt.first.length(),
-                tagfmt.first.data(), (int)tagfmt.second.length(),
-                tagfmt.second.data());
-      }
-      ret = false;
-    } else {
-      TagFmt2Idx.emplace(std::make_pair(tagfmt, tag));
-    }
-  }
-
-  {
-    std::unordered_map<MapString, uint32_t>::const_iterator it;
-    it = Tag2Idx.find(tagfmt.first);
+    auto it = Tag2Idx.find(tagfmt.first);
     if (!tagfmt.second.length() && (it != Tag2Idx.end())) {
       Tag2Idx.erase(it);
       it = Tag2Idx.end();
@@ -205,25 +112,15 @@
 }
 
 const TagFmt* EventTagMap::find(uint32_t tag) const {
-  std::unordered_map<uint32_t, TagFmt>::const_iterator it;
   android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
-  it = Idx2TagFmt.find(tag);
+  auto it = Idx2TagFmt.find(tag);
   if (it == Idx2TagFmt.end()) return NULL;
   return &(it->second);
 }
 
-int EventTagMap::find(TagFmt&& tagfmt) const {
-  std::unordered_map<TagFmt, uint32_t>::const_iterator it;
+int EventTagMap::find(std::string_view tag) const {
   android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
-  it = TagFmt2Idx.find(std::move(tagfmt));
-  if (it == TagFmt2Idx.end()) return -1;
-  return it->second;
-}
-
-int EventTagMap::find(MapString&& tag) const {
-  std::unordered_map<MapString, uint32_t>::const_iterator it;
-  android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
-  it = Tag2Idx.find(std::move(tag));
+  auto it = Tag2Idx.find(std::move(tag));
   if (it == Tag2Idx.end()) return -1;
   return it->second;
 }
@@ -241,29 +138,20 @@
 // successful return, it will be pointing to the last character in the
 // tag line (i.e. the character before the start of the next line).
 //
-// lineNum = 0 removes verbose comments and requires us to cache the
-// content rather than make direct raw references since the content
-// will disappear after the call. A non-zero lineNum means we own the
-// data and it will outlive the call.
-//
 // Returns 0 on success, nonzero on failure.
-static int scanTagLine(EventTagMap* map, const char*& pData, int lineNum) {
+static int scanTagLine(EventTagMap* map, const char*& pData, int line_num) {
   char* ep;
   unsigned long val = strtoul(pData, &ep, 10);
   const char* cp = ep;
   if (cp == pData) {
-    if (lineNum) {
-      fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", lineNum);
-    }
+    fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", line_num);
     errno = EINVAL;
     return -1;
   }
 
   uint32_t tagIndex = val;
   if (tagIndex != val) {
-    if (lineNum) {
-      fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", lineNum);
-    }
+    fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", line_num);
     errno = ERANGE;
     return -1;
   }
@@ -272,9 +160,7 @@
   }
 
   if (*cp == '\n') {
-    if (lineNum) {
-      fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", lineNum);
-    }
+    fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", line_num);
     errno = EINVAL;
     return -1;
   }
@@ -284,10 +170,7 @@
   size_t tagLen = cp - tag;
 
   if (!isspace(*cp)) {
-    if (lineNum) {
-      fprintf(stderr, OUT_TAG ": invalid tag char %c on line %d\n", *cp,
-              lineNum);
-    }
+    fprintf(stderr, OUT_TAG ": invalid tag char %c on line %d\n", *cp, line_num);
     errno = EINVAL;
     return -1;
   }
@@ -317,25 +200,15 @@
 
   while (*cp && (*cp != '\n')) ++cp;
 #ifdef DEBUG
-  fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - pData), pData);
+  fprintf(stderr, "%d: %p: %.*s\n", line_num, tag, (int)(cp - pData), pData);
 #endif
   pData = cp;
 
-  if (lineNum) {
-    if (map->emplaceUnique(tagIndex,
-                           TagFmt(std::make_pair(MapString(tag, tagLen),
-                                                 MapString(fmt, fmtLen))),
-                           verbose)) {
-      return 0;
-    }
-  } else {
-    // cache
-    if (map->emplaceUnique(
-            tagIndex,
-            TagFmt(std::make_pair(MapString(std::string(tag, tagLen)),
-                                  MapString(std::string(fmt, fmtLen)))))) {
-      return 0;
-    }
+  if (map->emplaceUnique(
+          tagIndex,
+          TagFmt(std::make_pair(std::string_view(tag, tagLen), std::string_view(fmt, fmtLen))),
+          verbose)) {
+    return 0;
   }
   errno = EMLINK;
   return -1;
@@ -491,57 +364,10 @@
   if (map) delete map;
 }
 
-// Cache miss, go to logd to acquire a public reference.
-// Because we lack access to a SHARED PUBLIC /dev/event-log-tags file map?
-static const TagFmt* __getEventTag([[maybe_unused]] EventTagMap* map, unsigned int tag) {
-  // call event tag service to arrange for a new tag
-  char* buf = NULL;
-  // Can not use android::base::StringPrintf, asprintf + free instead.
-  static const char command_template[] = "getEventTag id=%u";
-  int ret = asprintf(&buf, command_template, tag);
-  if (ret > 0) {
-    // Add some buffer margin for an estimate of the full return content.
-    size_t size =
-        ret - strlen(command_template) +
-        strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
-    if (size > (size_t)ret) {
-      char* np = static_cast<char*>(realloc(buf, size));
-      if (np) {
-        buf = np;
-      } else {
-        size = ret;
-      }
-    } else {
-      size = ret;
-    }
-#ifdef __ANDROID__
-    // Ask event log tag service for an existing entry
-    if (SendLogdControlMessage(buf, size) >= 0) {
-      buf[size - 1] = '\0';
-      char* ep;
-      unsigned long val = strtoul(buf, &ep, 10);  // return size
-      const char* cp = ep;
-      if ((buf != cp) && (val > 0) && (*cp == '\n')) {  // truncation OK
-        ++cp;
-        if (!scanTagLine(map, cp, 0)) {
-          free(buf);
-          return map->find(tag);
-        }
-      }
-    }
-#endif
-    free(buf);
-  }
-  return NULL;
-}
-
 // Look up an entry in the map.
 const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len, unsigned int tag) {
   if (len) *len = 0;
   const TagFmt* str = map->find(tag);
-  if (!str) {
-    str = __getEventTag(const_cast<EventTagMap*>(map), tag);
-  }
   if (!str) return NULL;
   if (len) *len = str->first.length();
   return str->first.data();
@@ -551,98 +377,8 @@
 const char* android_lookupEventFormat_len(const EventTagMap* map, size_t* len, unsigned int tag) {
   if (len) *len = 0;
   const TagFmt* str = map->find(tag);
-  if (!str) {
-    str = __getEventTag(const_cast<EventTagMap*>(map), tag);
-  }
   if (!str) return NULL;
   if (len) *len = str->second.length();
   return str->second.data();
 }
 
-// This function is deprecated and replaced with android_lookupEventTag_len
-// since it will cause the map to change from Shared and backed by a file,
-// to Private Dirty and backed up by swap, albeit highly compressible. By
-// deprecating this function everywhere, we save 100s of MB of memory space.
-const char* android_lookupEventTag(const EventTagMap* map, unsigned int tag) {
-  size_t len;
-  const char* tagStr = android_lookupEventTag_len(map, &len, tag);
-
-  if (!tagStr) return tagStr;
-  char* cp = const_cast<char*>(tagStr);
-  cp += len;
-  if (*cp) *cp = '\0';  // Trigger copy on write :-( and why deprecated.
-  return tagStr;
-}
-
-// Look up tagname, generate one if necessary, and return a tag
-int android_lookupEventTagNum(EventTagMap* map, const char* tagname, const char* format, int prio) {
-  const char* ep = endOfTag(tagname);
-  size_t len = ep - tagname;
-  if (!len || *ep) {
-    errno = EINVAL;
-    return -1;
-  }
-
-  if ((prio != ANDROID_LOG_UNKNOWN) && (prio < ANDROID_LOG_SILENT) &&
-      !__android_log_is_loggable_len(prio, tagname, len,
-                                     __android_log_is_debuggable()
-                                         ? ANDROID_LOG_VERBOSE
-                                         : ANDROID_LOG_DEBUG)) {
-    errno = EPERM;
-    return -1;
-  }
-
-  if (!format) format = "";
-  ssize_t fmtLen = strlen(format);
-  int ret = map->find(TagFmt(
-      std::make_pair(MapString(tagname, len), MapString(format, fmtLen))));
-  if (ret != -1) return ret;
-
-  // call event tag service to arrange for a new tag
-  char* buf = NULL;
-  // Can not use android::base::StringPrintf, asprintf + free instead.
-  static const char command_template[] = "getEventTag name=%s format=\"%s\"";
-  ret = asprintf(&buf, command_template, tagname, format);
-  if (ret > 0) {
-    // Add some buffer margin for an estimate of the full return content.
-    char* cp;
-    size_t size =
-        ret - strlen(command_template) +
-        strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
-    if (size > (size_t)ret) {
-      cp = static_cast<char*>(realloc(buf, size));
-      if (cp) {
-        buf = cp;
-      } else {
-        size = ret;
-      }
-    } else {
-      size = ret;
-    }
-#ifdef __ANDROID__
-    // Ask event log tag service for an allocation
-    if (SendLogdControlMessage(buf, size) >= 0) {
-      buf[size - 1] = '\0';
-      unsigned long val = strtoul(buf, &cp, 10);        // return size
-      if ((buf != cp) && (val > 0) && (*cp == '\n')) {  // truncation OK
-        val = strtoul(cp + 1, &cp, 10);                 // allocated tag number
-        if ((val > 0) && (val < UINT32_MAX) && (*cp == '\t')) {
-          free(buf);
-          ret = val;
-          // cache
-          map->emplaceUnique(ret, TagFmt(std::make_pair(
-                                      MapString(std::string(tagname, len)),
-                                      MapString(std::string(format, fmtLen)))));
-          return ret;
-        }
-      }
-    }
-#endif
-    free(buf);
-  }
-
-  // Hail Mary
-  ret = map->find(MapString(tagname, len));
-  if (ret == -1) errno = ESRCH;
-  return ret;
-}
diff --git a/liblog/include/log/event_tag_map.h b/liblog/include/log/event_tag_map.h
index f7ec208..de49fbf 100644
--- a/liblog/include/log/event_tag_map.h
+++ b/liblog/include/log/event_tag_map.h
@@ -40,14 +40,6 @@
 void android_closeEventTagMap(EventTagMap* map);
 
 /*
- * Look up a tag by index.  Returns the tag string, or NULL if not found.
- */
-const char* android_lookupEventTag(const EventTagMap* map, unsigned int tag)
-    __attribute__((
-        deprecated("use android_lookupEventTag_len() instead to minimize "
-                   "MAP_PRIVATE copy-on-write memory impact")));
-
-/*
  * Look up a tag by index.  Returns the tag string & string length, or NULL if
  * not found.  Returned string is not guaranteed to be nul terminated.
  */
@@ -61,12 +53,6 @@
 const char* android_lookupEventFormat_len(const EventTagMap* map, size_t* len,
                                           unsigned int tag);
 
-/*
- * Look up tagname, generate one if necessary, and return a tag
- */
-int android_lookupEventTagNum(EventTagMap* map, const char* tagname,
-                              const char* format, int prio);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/liblog/include/log/log_properties.h b/liblog/include/log/log_properties.h
index 3497d63..2a0230f 100644
--- a/liblog/include/log/log_properties.h
+++ b/liblog/include/log/log_properties.h
@@ -20,6 +20,7 @@
 extern "C" {
 #endif
 
+/* Returns `1` if the device is debuggable or `0` if not. */
 int __android_log_is_debuggable();
 
 #ifdef __cplusplus
diff --git a/liblog/include/log/log_read.h b/liblog/include/log/log_read.h
index 23d76f4..1736934 100644
--- a/liblog/include/log/log_read.h
+++ b/liblog/include/log/log_read.h
@@ -81,10 +81,17 @@
 
 log_id_t android_logger_get_id(struct logger* logger);
 
+/* Clears the given log buffer. */
 int android_logger_clear(struct logger* logger);
+/* Return the allotted size for the given log buffer. */
 long android_logger_get_log_size(struct logger* logger);
+/* Set the allotted size for the given log buffer. */
 int android_logger_set_log_size(struct logger* logger, unsigned long size);
+/* Return the actual, uncompressed size that can be read from the given log buffer. */
 long android_logger_get_log_readable_size(struct logger* logger);
+/* Return the actual, compressed size that the given log buffer is consuming. */
+long android_logger_get_log_consumed_size(struct logger* logger);
+/* Deprecated.  Always returns '4' regardless of input. */
 int android_logger_get_log_version(struct logger* logger);
 
 struct logger_list;
diff --git a/liblog/include/private/android_logger.h b/liblog/include/private/android_logger.h
index d3b72bc..166f387 100644
--- a/liblog/include/private/android_logger.h
+++ b/liblog/include/private/android_logger.h
@@ -144,21 +144,6 @@
 int __android_log_security_bswrite(int32_t tag, const char* payload);
 int __android_log_security(); /* Device Owner is present */
 
-#define BOOL_DEFAULT_FLAG_TRUE_FALSE 0x1
-#define BOOL_DEFAULT_FALSE 0x0        /* false if property not present   */
-#define BOOL_DEFAULT_TRUE 0x1         /* true if property not present    */
-#define BOOL_DEFAULT_FLAG_PERSIST 0x2 /* <key>, persist.<key>, ro.<key>  */
-#define BOOL_DEFAULT_FLAG_ENG 0x4     /* off for user                    */
-#define BOOL_DEFAULT_FLAG_SVELTE 0x8  /* off for low_ram                 */
-bool __android_logger_property_get_bool(const char* key, int flag);
-
-#define LOG_BUFFER_SIZE (256 * 1024) /* Tuned with ro.logd.size per-platform \
-                                      */
-#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
-#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
-unsigned long __android_logger_get_buffer_size(log_id_t logId);
-bool __android_logger_valid_buffer_size(unsigned long value);
-
 /* Retrieve the composed event buffer */
 int android_log_write_list_buffer(android_log_context ctx, const char** msg);
 
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 161fcf1..f8d5ef0 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -84,13 +84,10 @@
   global:
     __android_log_pmsg_file_read;
     __android_log_pmsg_file_write;
-    __android_logger_get_buffer_size;
-    __android_logger_property_get_bool;
     android_openEventTagMap;
     android_log_processBinaryLogBuffer;
     android_log_processLogBuffer;
     android_log_read_next;
     android_log_write_list_buffer;
-    android_lookupEventTagNum;
     create_android_log_parser;
 };
diff --git a/liblog/logd_reader.cpp b/liblog/logd_reader.cpp
index 82ed6b2..611caed 100644
--- a/liblog/logd_reader.cpp
+++ b/liblog/logd_reader.cpp
@@ -35,13 +35,14 @@
 
 #include <string>
 
+#include <android-base/parseint.h>
 #include <private/android_logger.h>
 
 #include "logger.h"
 
 // Connects to /dev/socket/<name> and returns the associated fd or returns -1 on error.
 // O_CLOEXEC is always set.
-static int socket_local_client(const std::string& name, int type) {
+static int socket_local_client(const std::string& name, int type, bool timeout) {
   sockaddr_un addr = {.sun_family = AF_LOCAL};
 
   std::string path = "/dev/socket/" + name;
@@ -55,6 +56,18 @@
     return -1;
   }
 
+  if (timeout) {
+    // Sending and receiving messages should be instantaneous, but we don't want to wait forever if
+    // logd is hung, so we set a gracious 2s timeout.
+    struct timeval t = {2, 0};
+    if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t)) == -1) {
+      return -1;
+    }
+    if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t)) == -1) {
+      return -1;
+    }
+  }
+
   if (connect(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
     close(fd);
     return -1;
@@ -69,7 +82,7 @@
   size_t len;
   char* cp;
   int errno_save = 0;
-  int sock = socket_local_client("logd", SOCK_STREAM);
+  int sock = socket_local_client("logd", SOCK_STREAM, true);
   if (sock < 0) {
     return sock;
   }
@@ -148,26 +161,56 @@
   return check_log_success(buf, SendLogdControlMessage(buf, sizeof(buf)));
 }
 
-/* returns the total size of the log's ring buffer */
-long android_logger_get_log_size(struct logger* logger) {
+enum class LogSizeType : uint32_t {
+  kAllotted = 0,
+  kReadable,
+  kConsumed,
+};
+
+static long GetLogSize(struct logger* logger, LogSizeType type) {
   if (!android_logger_is_logd(logger)) {
     return -EINVAL;
   }
 
   uint32_t log_id = android_logger_get_id(logger);
   char buf[512];
-  snprintf(buf, sizeof(buf), "getLogSize %" PRIu32, log_id);
+  switch (type) {
+    case LogSizeType::kAllotted:
+      snprintf(buf, sizeof(buf), "getLogSize %" PRIu32, log_id);
+      break;
+    case LogSizeType::kReadable:
+      snprintf(buf, sizeof(buf), "getLogSizeReadable %" PRIu32, log_id);
+      break;
+    case LogSizeType::kConsumed:
+      snprintf(buf, sizeof(buf), "getLogSizeUsed %" PRIu32, log_id);
+      break;
+    default:
+      abort();
+  }
 
   ssize_t ret = SendLogdControlMessage(buf, sizeof(buf));
   if (ret < 0) {
     return ret;
   }
 
-  if ((buf[0] < '0') || ('9' < buf[0])) {
+  long size;
+  if (!android::base::ParseInt(buf, &size)) {
     return -1;
   }
 
-  return atol(buf);
+  return size;
+}
+
+long android_logger_get_log_size(struct logger* logger) {
+  return GetLogSize(logger, LogSizeType::kAllotted);
+}
+
+long android_logger_get_log_readable_size(struct logger* logger) {
+  return GetLogSize(logger, LogSizeType::kReadable);
+}
+
+long android_logger_get_log_consumed_size(struct logger* logger) {
+  return GetLogSize(logger, LogSizeType::kConsumed);
 }
 
 int android_logger_set_log_size(struct logger* logger, unsigned long size) {
@@ -182,31 +225,6 @@
   return check_log_success(buf, SendLogdControlMessage(buf, sizeof(buf)));
 }
 
-/*
- * returns the readable size of the log's ring buffer (that is, amount of the
- * log consumed)
- */
-long android_logger_get_log_readable_size(struct logger* logger) {
-  if (!android_logger_is_logd(logger)) {
-    return -EINVAL;
-  }
-
-  uint32_t log_id = android_logger_get_id(logger);
-  char buf[512];
-  snprintf(buf, sizeof(buf), "getLogSizeUsed %" PRIu32, log_id);
-
-  ssize_t ret = SendLogdControlMessage(buf, sizeof(buf));
-  if (ret < 0) {
-    return ret;
-  }
-
-  if ((buf[0] < '0') || ('9' < buf[0])) {
-    return -1;
-  }
-
-  return atol(buf);
-}
-
 int android_logger_get_log_version(struct logger*) {
   return 4;
 }
@@ -268,7 +286,7 @@
     return sock;
   }
 
-  sock = socket_local_client("logdr", SOCK_SEQPACKET);
+  sock = socket_local_client("logdr", SOCK_SEQPACKET, false);
   if (sock <= 0) {
     if ((sock == -1) && errno) {
       return -errno;
diff --git a/liblog/logd_writer.cpp b/liblog/logd_writer.cpp
index a230749..f5d19ca 100644
--- a/liblog/logd_writer.cpp
+++ b/liblog/logd_writer.cpp
@@ -59,8 +59,7 @@
     return;
   }
 
-  int new_socket =
-      TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
+  int new_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
   if (new_socket <= 0) {
     return;
   }
@@ -91,8 +90,6 @@
   struct iovec newVec[nr + headerLength];
   android_log_header_t header;
   size_t i, payloadSize;
-  static atomic_int dropped;
-  static atomic_int droppedSecurity;
 
   GetSocket();
 
@@ -110,6 +107,7 @@
     return 0;
   }
 
+  header.id = logId;
   header.tid = gettid();
   header.realtime.tv_sec = ts->tv_sec;
   header.realtime.tv_nsec = ts->tv_nsec;
@@ -117,44 +115,6 @@
   newVec[0].iov_base = (unsigned char*)&header;
   newVec[0].iov_len = sizeof(header);
 
-  int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0, memory_order_relaxed);
-  if (snapshot) {
-    android_log_event_int_t buffer;
-
-    header.id = LOG_ID_SECURITY;
-    buffer.header.tag = LIBLOG_LOG_TAG;
-    buffer.payload.type = EVENT_TYPE_INT;
-    buffer.payload.data = snapshot;
-
-    newVec[headerLength].iov_base = &buffer;
-    newVec[headerLength].iov_len = sizeof(buffer);
-
-    ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, 2));
-    if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
-      atomic_fetch_add_explicit(&droppedSecurity, snapshot, memory_order_relaxed);
-    }
-  }
-  snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
-  if (snapshot && __android_log_is_loggable_len(ANDROID_LOG_INFO, "liblog", strlen("liblog"),
-                                                ANDROID_LOG_VERBOSE)) {
-    android_log_event_int_t buffer;
-
-    header.id = LOG_ID_EVENTS;
-    buffer.header.tag = LIBLOG_LOG_TAG;
-    buffer.payload.type = EVENT_TYPE_INT;
-    buffer.payload.data = snapshot;
-
-    newVec[headerLength].iov_base = &buffer;
-    newVec[headerLength].iov_len = sizeof(buffer);
-
-    ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, 2));
-    if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
-      atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
-    }
-  }
-
-  header.id = logId;
-
   for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
     newVec[i].iov_base = vec[i - headerLength].iov_base;
     payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
@@ -168,11 +128,8 @@
     }
   }
 
-  // The write below could be lost, but will never block.
-  // EAGAIN occurs if logd is overloaded, other errors indicate that something went wrong with
-  // the connection, so we reset it and try again.
   ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
-  if (ret < 0 && errno != EAGAIN) {
+  if (ret < 0) {
     LogdConnect();
 
     ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
@@ -182,14 +139,5 @@
     ret = -errno;
   }
 
-  if (ret > (ssize_t)sizeof(header)) {
-    ret -= sizeof(header);
-  } else if (ret < 0) {
-    atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
-    if (logId == LOG_ID_SECURITY) {
-      atomic_fetch_add_explicit(&droppedSecurity, 1, memory_order_relaxed);
-    }
-  }
-
   return ret;
 }
diff --git a/liblog/properties.cpp b/liblog/properties.cpp
index 2392112..88f0bf1 100644
--- a/liblog/properties.cpp
+++ b/liblog/properties.cpp
@@ -294,33 +294,12 @@
 }
 
 int __android_log_is_debuggable() {
-  static uint32_t serial;
-  static struct cache_char tag_cache;
-  static const char key[] = "ro.debuggable";
-  int ret;
+  static int is_debuggable = [] {
+    char value[PROP_VALUE_MAX] = {};
+    return __system_property_get("ro.debuggable", value) > 0 && !strcmp(value, "1");
+  }();
 
-  if (tag_cache.c) { /* ro property does not change after set */
-    ret = tag_cache.c == '1';
-  } else if (lock()) {
-    struct cache_char temp_cache = {{NULL, 0xFFFFFFFF}, '\0'};
-    refresh_cache(&temp_cache, key);
-    ret = temp_cache.c == '1';
-  } else {
-    int change_detected = check_cache(&tag_cache.cache);
-    uint32_t current_serial = __system_property_area_serial();
-    if (current_serial != serial) {
-      change_detected = 1;
-    }
-    if (change_detected) {
-      refresh_cache(&tag_cache, key);
-      serial = current_serial;
-    }
-    ret = tag_cache.c == '1';
-
-    unlock();
-  }
-
-  return ret;
+  return is_debuggable;
 }
 
 /*
@@ -385,216 +364,6 @@
   return do_cache2_char(&security);
 }
 
-/*
- * Interface that represents the logd buffer size determination so that others
- * need not guess our intentions.
- */
-
-/* Property helper */
-static bool check_flag(const char* prop, const char* flag) {
-  const char* cp = strcasestr(prop, flag);
-  if (!cp) {
-    return false;
-  }
-  /* We only will document comma (,) */
-  static const char sep[] = ",:;|+ \t\f";
-  if ((cp != prop) && !strchr(sep, cp[-1])) {
-    return false;
-  }
-  cp += strlen(flag);
-  return !*cp || !!strchr(sep, *cp);
-}
-
-/* cache structure */
-struct cache_property {
-  struct cache cache;
-  char property[PROP_VALUE_MAX];
-};
-
-static void refresh_cache_property(struct cache_property* cache, const char* key) {
-  if (!cache->cache.pinfo) {
-    cache->cache.pinfo = __system_property_find(key);
-    if (!cache->cache.pinfo) {
-      return;
-    }
-  }
-  cache->cache.serial = __system_property_serial(cache->cache.pinfo);
-  __system_property_read(cache->cache.pinfo, 0, cache->property);
-}
-
-/* get boolean with the logger twist that supports eng adjustments */
-bool __android_logger_property_get_bool(const char* key, int flag) {
-  struct cache_property property = {{NULL, 0xFFFFFFFF}, {0}};
-  if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
-    char newkey[strlen("persist.") + strlen(key) + 1];
-    snprintf(newkey, sizeof(newkey), "ro.%s", key);
-    refresh_cache_property(&property, newkey);
-    property.cache.pinfo = NULL;
-    property.cache.serial = 0xFFFFFFFF;
-    snprintf(newkey, sizeof(newkey), "persist.%s", key);
-    refresh_cache_property(&property, newkey);
-    property.cache.pinfo = NULL;
-    property.cache.serial = 0xFFFFFFFF;
-  }
-
-  refresh_cache_property(&property, key);
-
-  if (check_flag(property.property, "true")) {
-    return true;
-  }
-  if (check_flag(property.property, "false")) {
-    return false;
-  }
-  if (property.property[0]) {
-    flag &= ~(BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE);
-  }
-  if (check_flag(property.property, "eng")) {
-    flag |= BOOL_DEFAULT_FLAG_ENG;
-  }
-  /* this is really a "not" flag */
-  if (check_flag(property.property, "svelte")) {
-    flag |= BOOL_DEFAULT_FLAG_SVELTE;
-  }
-
-  /* Sanity Check */
-  if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) {
-    flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE;
-    flag |= BOOL_DEFAULT_TRUE;
-  }
-
-  if ((flag & BOOL_DEFAULT_FLAG_SVELTE) &&
-      __android_logger_property_get_bool("ro.config.low_ram", BOOL_DEFAULT_FALSE)) {
-    return false;
-  }
-  if ((flag & BOOL_DEFAULT_FLAG_ENG) && !__android_log_is_debuggable()) {
-    return false;
-  }
-
-  return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
-}
-
-bool __android_logger_valid_buffer_size(unsigned long value) {
-  return LOG_BUFFER_MIN_SIZE <= value && value <= LOG_BUFFER_MAX_SIZE;
-}
-
-struct cache2_property_size {
-  pthread_mutex_t lock;
-  uint32_t serial;
-  const char* key_persist;
-  struct cache_property cache_persist;
-  const char* key_ro;
-  struct cache_property cache_ro;
-  unsigned long (*const evaluate)(const struct cache2_property_size* self);
-};
-
-static inline unsigned long do_cache2_property_size(struct cache2_property_size* self) {
-  uint32_t current_serial;
-  int change_detected;
-  unsigned long v;
-
-  if (pthread_mutex_trylock(&self->lock)) {
-    /* We are willing to accept some race in this context */
-    return self->evaluate(self);
-  }
-
-  change_detected = check_cache(&self->cache_persist.cache) || check_cache(&self->cache_ro.cache);
-  current_serial = __system_property_area_serial();
-  if (current_serial != self->serial) {
-    change_detected = 1;
-  }
-  if (change_detected) {
-    refresh_cache_property(&self->cache_persist, self->key_persist);
-    refresh_cache_property(&self->cache_ro, self->key_ro);
-    self->serial = current_serial;
-  }
-  v = self->evaluate(self);
-
-  pthread_mutex_unlock(&self->lock);
-
-  return v;
-}
-
-static unsigned long property_get_size_from_cache(const struct cache_property* cache) {
-  char* cp;
-  unsigned long value = strtoul(cache->property, &cp, 10);
-
-  switch (*cp) {
-    case 'm':
-    case 'M':
-      value *= 1024;
-      [[fallthrough]];
-    case 'k':
-    case 'K':
-      value *= 1024;
-      [[fallthrough]];
-    case '\0':
-      break;
-
-    default:
-      value = 0;
-  }
-
-  if (!__android_logger_valid_buffer_size(value)) {
-    value = 0;
-  }
-
-  return value;
-}
-
-static unsigned long evaluate_property_get_size(const struct cache2_property_size* self) {
-  unsigned long size = property_get_size_from_cache(&self->cache_persist);
-  if (size) {
-    return size;
-  }
-  return property_get_size_from_cache(&self->cache_ro);
-}
-
-unsigned long __android_logger_get_buffer_size(log_id_t logId) {
-  static const char global_tunable[] = "persist.logd.size"; /* Settings App */
-  static const char global_default[] = "ro.logd.size";      /* BoardConfig.mk */
-  static struct cache2_property_size global = {
-      /* clang-format off */
-    PTHREAD_MUTEX_INITIALIZER, 0,
-    global_tunable, { { NULL, 0xFFFFFFFF }, {} },
-    global_default, { { NULL, 0xFFFFFFFF }, {} },
-    evaluate_property_get_size
-      /* clang-format on */
-  };
-  char key_persist[strlen(global_tunable) + strlen(".security") + 1];
-  char key_ro[strlen(global_default) + strlen(".security") + 1];
-  struct cache2_property_size local = {
-      /* clang-format off */
-    PTHREAD_MUTEX_INITIALIZER, 0,
-    key_persist, { { NULL, 0xFFFFFFFF }, {} },
-    key_ro,      { { NULL, 0xFFFFFFFF }, {} },
-    evaluate_property_get_size
-      /* clang-format on */
-  };
-  unsigned long property_size, default_size;
-
-  default_size = do_cache2_property_size(&global);
-  if (!default_size) {
-    default_size = __android_logger_property_get_bool("ro.config.low_ram", BOOL_DEFAULT_FALSE)
-                       ? LOG_BUFFER_MIN_SIZE /* 64K  */
-                       : LOG_BUFFER_SIZE;    /* 256K */
-  }
-
-  snprintf(key_persist, sizeof(key_persist), "%s.%s", global_tunable,
-           android_log_id_to_name(logId));
-  snprintf(key_ro, sizeof(key_ro), "%s.%s", global_default, android_log_id_to_name(logId));
-  property_size = do_cache2_property_size(&local);
-
-  if (!property_size) {
-    property_size = default_size;
-  }
-
-  if (!property_size) {
-    property_size = LOG_BUFFER_SIZE;
-  }
-
-  return property_size;
-}
-
 #else
 
 int __android_log_is_loggable(int prio, const char*, int) {
@@ -613,4 +382,4 @@
   return 1;
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp
index 2a6424b..a17d90c 100644
--- a/liblog/tests/Android.bp
+++ b/liblog/tests/Android.bp
@@ -97,6 +97,7 @@
     cflags: ["-DNO_PSTORE"],
     test_suites: [
         "cts",
+        "device-tests",
         "vts10",
     ],
 }
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 3bd5cf2..d2f12d6 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -879,30 +879,6 @@
 }
 BENCHMARK(BM_lookupEventFormat);
 
-/*
- *	Measure the time it takes for android_lookupEventTagNum plus above
- */
-static void BM_lookupEventTagNum(benchmark::State& state) {
-  prechargeEventMap();
-
-  std::unordered_set<uint32_t>::const_iterator it = set.begin();
-
-  while (state.KeepRunning()) {
-    size_t len;
-    const char* name = android_lookupEventTag_len(map, &len, (*it));
-    std::string Name(name, len);
-    const char* format = android_lookupEventFormat_len(map, &len, (*it));
-    std::string Format(format, len);
-    state.ResumeTiming();
-    android_lookupEventTagNum(map, Name.c_str(), Format.c_str(),
-                              ANDROID_LOG_UNKNOWN);
-    state.PauseTiming();
-    ++it;
-    if (it == set.end()) it = set.begin();
-  }
-}
-BENCHMARK(BM_lookupEventTagNum);
-
 // Must be functionally identical to liblog internal SendLogdControlMessage()
 static void send_to_control(char* buf, size_t len) {
   int sock =
diff --git a/liblog/tests/liblog_global_state.cpp b/liblog/tests/liblog_global_state.cpp
index 3508818..1d7ff9f 100644
--- a/liblog/tests/liblog_global_state.cpp
+++ b/liblog/tests/liblog_global_state.cpp
@@ -153,56 +153,65 @@
   message_seen = false;
 }
 
+static std::string UniqueLogTag() {
+  std::string tag = LOG_TAG;
+  tag += "-" + std::to_string(getpid());
+  return tag;
+}
+
 TEST(liblog_global_state, is_loggable_both_default) {
-  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  auto tag = UniqueLogTag();
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 }
 
 TEST(liblog_global_state, is_loggable_minimum_log_priority_only) {
-  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  auto tag = UniqueLogTag();
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
   EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
   EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN));
-  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
   EXPECT_EQ(android::base::WARNING, android::base::SetMinimumLogSeverity(android::base::DEBUG));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
   EXPECT_EQ(android::base::DEBUG, android::base::SetMinimumLogSeverity(android::base::WARNING));
-  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 }
 
 TEST(liblog_global_state, is_loggable_tag_log_priority_only) {
 #ifdef __ANDROID__
-  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  auto tag = UniqueLogTag();
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
-  auto log_tag_property = std::string("log.tag.") + LOG_TAG;
-  android::base::SetProperty(log_tag_property, "d");
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  auto log_tag_property = std::string("log.tag.") + tag;
+  ASSERT_TRUE(android::base::SetProperty(log_tag_property, "d"));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
-  android::base::SetProperty(log_tag_property, "w");
-  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  ASSERT_TRUE(android::base::SetProperty(log_tag_property, "w"));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
-  android::base::SetProperty(log_tag_property, "");
+  ASSERT_TRUE(android::base::SetProperty(log_tag_property, ""));
 #else
   GTEST_SKIP() << "No log tag properties on host";
 #endif
@@ -210,39 +219,40 @@
 
 TEST(liblog_global_state, is_loggable_both_set) {
 #ifdef __ANDROID__
-  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  auto tag = UniqueLogTag();
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
   // When both a tag and a minimum priority are set, we use the lower value of the two.
 
   // tag = warning, minimum_priority = debug, expect 'debug'
-  auto log_tag_property = std::string("log.tag.") + LOG_TAG;
-  android::base::SetProperty(log_tag_property, "w");
+  auto log_tag_property = std::string("log.tag.") + tag;
+  ASSERT_TRUE(android::base::SetProperty(log_tag_property, "w"));
   EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
   // tag = warning, minimum_priority = warning, expect 'warning'
   EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN));
-  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
   // tag = debug, minimum_priority = warning, expect 'debug'
-  android::base::SetProperty(log_tag_property, "d");
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  ASSERT_TRUE(android::base::SetProperty(log_tag_property, "d"));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
   // tag = debug, minimum_priority = debug, expect 'debug'
   EXPECT_EQ(ANDROID_LOG_WARN, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
-  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
 
-  android::base::SetProperty(log_tag_property, "");
+  ASSERT_TRUE(android::base::SetProperty(log_tag_property, ""));
 #else
   GTEST_SKIP() << "No log tag properties on host";
 #endif
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index fbc3d7a..c49d87b 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -2768,20 +2768,3 @@
 #endif
 }
 #endif  // ENABLE_FLAKY_TESTS
-
-TEST(liblog, android_lookupEventTagNum) {
-#ifdef __ANDROID__
-  EventTagMap* map = android_openEventTagMap(NULL);
-  EXPECT_TRUE(NULL != map);
-  std::string Name = android::base::StringPrintf("a%d", getpid());
-  int tag = android_lookupEventTagNum(map, Name.c_str(), "(new|1)",
-                                      ANDROID_LOG_UNKNOWN);
-  android_closeEventTagMap(map);
-  if (tag == -1) system("tail -3 /dev/event-log-tags >&2");
-  EXPECT_NE(-1, tag);
-  EXPECT_NE(0, tag);
-  EXPECT_GT(UINT32_MAX, (unsigned)tag);
-#else
-  GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
diff --git a/liblog/tests/log_read_test.cpp b/liblog/tests/log_read_test.cpp
index 3e09617..7acd363 100644
--- a/liblog/tests/log_read_test.cpp
+++ b/liblog/tests/log_read_test.cpp
@@ -20,6 +20,7 @@
 
 #include <string>
 
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android/log.h>  // minimal logging API
 #include <gtest/gtest.h>
@@ -29,6 +30,8 @@
 // Do not use anything in log/log_time.h despite side effects of the above.
 #include <private/android_logger.h>
 
+using android::base::GetBoolProperty;
+
 TEST(liblog, android_logger_get_) {
 #ifdef __ANDROID__
   // This test assumes the log buffers are filled with noise from
@@ -38,31 +41,27 @@
 
   for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
     log_id_t id = static_cast<log_id_t>(i);
-    const char* name = android_log_id_to_name(id);
-    if (id != android_name_to_log_id(name)) {
-      continue;
-    }
-    fprintf(stderr, "log buffer %s\r", name);
+    std::string name = android_log_id_to_name(id);
+    fprintf(stderr, "log buffer %s\r", name.c_str());
     struct logger* logger;
     EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id)));
     EXPECT_EQ(id, android_logger_get_id(logger));
     ssize_t get_log_size = android_logger_get_log_size(logger);
     /* security buffer is allowed to be denied */
-    if (strcmp("security", name)) {
-      EXPECT_LT(0, get_log_size);
+    if (name != "security") {
+      EXPECT_GT(get_log_size, 0);
       // crash buffer is allowed to be empty, that is actually healthy!
-      // kernel buffer is allowed to be empty on "user" builds
-      // stats buffer is allowed to be empty TEMPORARILY.
-      // TODO: remove stats buffer from here once we start to use it in
-      // framework (b/68266385).
-      EXPECT_LE(  // boolean 1 or 0 depending on expected content or empty
-          !!((strcmp("crash", name) != 0) &&
-             ((strcmp("kernel", name) != 0) ||
-              __android_logger_property_get_bool(
-                  "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG |
-                                        BOOL_DEFAULT_FLAG_SVELTE)) &&
-             (strcmp("stats", name) != 0)),
-          android_logger_get_log_readable_size(logger));
+      // stats buffer is no longer in use.
+      if (name == "crash" || name == "stats") {
+        continue;
+      }
+
+      // kernel buffer is empty if ro.logd.kernel is false
+      if (name == "kernel" && !GetBoolProperty("ro.logd.kernel", false)) {
+        continue;
+      }
+
+      EXPECT_LE(0, android_logger_get_log_readable_size(logger));
     } else {
       EXPECT_NE(0, get_log_size);
       if (get_log_size < 0) {
@@ -71,7 +70,6 @@
         EXPECT_LE(0, android_logger_get_log_readable_size(logger));
       }
     }
-    EXPECT_LT(0, android_logger_get_log_version(logger));
   }
 
   android_logger_list_close(logger_list);
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index bbdd317..ceabf62 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -336,7 +336,6 @@
     }
 
     ParseKernelCmdlineOptions();
-    android::base::SetMinimumLogSeverity(android::base::INFO);
 }
 
 void Modprobe::EnableBlocklist(bool enable) {
diff --git a/libpixelflinger/Android.bp b/libpixelflinger/Android.bp
deleted file mode 100644
index 45a32da..0000000
--- a/libpixelflinger/Android.bp
+++ /dev/null
@@ -1,97 +0,0 @@
-cc_defaults {
-    name: "pixelflinger_defaults",
-
-    cflags: [
-        "-fstrict-aliasing",
-        "-fomit-frame-pointer",
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-function",
-    ],
-    export_include_dirs: ["include"],
-    header_libs: ["libbase_headers"],
-    shared_libs: [
-        "libcutils",
-        "liblog",
-        "libutils",
-    ],
-
-    arch: {
-        arm: {
-            neon: {
-                cflags: ["-D__ARM_HAVE_NEON"],
-            },
-        },
-    },
-}
-
-cc_library_static {
-    name: "libpixelflinger-arm",
-    defaults: ["pixelflinger_defaults"],
-
-    srcs: [
-        "fixed.cpp",
-        "picker.cpp",
-        "pixelflinger.cpp",
-        "trap.cpp",
-        "scanline.cpp",
-    ],
-
-    arch: {
-        arm: {
-            instruction_set: "arm",
-        },
-    },
-}
-
-// For the tests to use
-cc_library_headers {
-    name: "libpixelflinger_internal",
-    export_include_dirs: [
-        "include",
-        ".",
-    ],
-}
-
-cc_library {
-    name: "libpixelflinger",
-    defaults: ["pixelflinger_defaults"],
-
-    srcs: [
-        "codeflinger/ARMAssemblerInterface.cpp",
-        "codeflinger/ARMAssemblerProxy.cpp",
-        "codeflinger/CodeCache.cpp",
-        "codeflinger/GGLAssembler.cpp",
-        "codeflinger/load_store.cpp",
-        "codeflinger/blending.cpp",
-        "codeflinger/texturing.cpp",
-        "format.cpp",
-        "clear.cpp",
-        "raster.cpp",
-        "buffer.cpp",
-    ],
-    whole_static_libs: ["libpixelflinger-arm"],
-
-    arch: {
-        arm: {
-            srcs: [
-                "codeflinger/ARMAssembler.cpp",
-                "codeflinger/disassem.c",
-                "col32cb16blend.S",
-                "t32cb16blend.S",
-            ],
-
-            neon: {
-                srcs: ["col32cb16blend_neon.S"],
-            },
-        },
-        arm64: {
-            srcs: [
-                "codeflinger/Arm64Assembler.cpp",
-                "codeflinger/Arm64Disassembler.cpp",
-                "arch-arm64/col32cb16blend.S",
-                "arch-arm64/t32cb16blend.S",
-            ],
-        },
-    },
-}
diff --git a/libpixelflinger/NOTICE b/libpixelflinger/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/libpixelflinger/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   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/libpixelflinger/arch-arm64/col32cb16blend.S b/libpixelflinger/arch-arm64/col32cb16blend.S
deleted file mode 100644
index 84596f9..0000000
--- a/libpixelflinger/arch-arm64/col32cb16blend.S
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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
-    .balign 0
-
-    .global scanline_col32cb16blend_arm64
-
-//
-// 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_arm64:
-
-    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-arm64/t32cb16blend.S b/libpixelflinger/arch-arm64/t32cb16blend.S
deleted file mode 100644
index a9733c0..0000000
--- a/libpixelflinger/arch-arm64/t32cb16blend.S
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * 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
-    .balign 0
-
-    .global scanline_t32cb16blend_arm64
-
-/*
- * .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, w15, w16, w17
- *
- */
-
-.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     w15, \FB, w16, lsl #(16 + 11)
-    csel    \FB, w17, w15, 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     w15, \FB, w6, lsl #(16 + 5)
-        csel    \FB, w17, w15, 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     w15, \FB, w16, lsl #16
-            csel    \FB, w17, w15, 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     w15, w16, #11
-    csel    \FB, w17, w15, 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     w15, \FB, w6, lsl #5
-        csel    \FB, w17, w15, 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     w15, \FB, w16
-            csel    \FB, w17, w15, 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_arm64:
-
-    // 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
deleted file mode 100644
index ea9514c..0000000
--- a/libpixelflinger/buffer.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-/* libs/pixelflinger/buffer.cpp
-**
-** Copyright 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.
-*/
-
-
-#include <assert.h>
-
-#include <android-base/macros.h>
-
-#include "buffer.h"
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-static void read_pixel(const surface_t* s, context_t* c,
-        uint32_t x, uint32_t y, pixel_t* pixel);
-static void write_pixel(const surface_t* s, context_t* c,
-        uint32_t x, uint32_t y, const pixel_t* pixel);
-static void readRGB565(const surface_t* s, context_t* c,
-        uint32_t x, uint32_t y, pixel_t* pixel);
-static void readABGR8888(const surface_t* s, context_t* c,
-        uint32_t x, uint32_t y, pixel_t* pixel);
-
-static uint32_t logic_op(int op, uint32_t s, uint32_t d);
-static uint32_t extract(uint32_t v, int h, int l, int bits);
-static uint32_t expand(uint32_t v, int sbits, int dbits);
-static uint32_t downshift_component(uint32_t in, uint32_t v,
-        int sh, int sl, int dh, int dl, int ch, int cl, int dither);
-
-// ----------------------------------------------------------------------------
-
-void ggl_init_texture(context_t* c)
-{
-    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
-        texture_t& t = c->state.texture[i];
-        t.s_coord = GGL_ONE_TO_ONE;
-        t.t_coord = GGL_ONE_TO_ONE;
-        t.s_wrap = GGL_REPEAT;
-        t.t_wrap = GGL_REPEAT;
-        t.min_filter = GGL_NEAREST;
-        t.mag_filter = GGL_NEAREST;
-        t.env = GGL_MODULATE;
-    }
-    c->activeTMU = &(c->state.texture[0]);
-}
-
-void ggl_set_surface(context_t* c, surface_t* dst, const GGLSurface* src)
-{
-    dst->width = src->width;
-    dst->height = src->height;
-    dst->stride = src->stride;
-    dst->data = src->data;
-    dst->format = src->format;
-    dst->dirty = 1;
-    if (__builtin_expect(dst->stride < 0, false)) {
-        const GGLFormat& pixelFormat(c->formats[dst->format]);
-        const int32_t bpr = -dst->stride * pixelFormat.size;
-        dst->data += bpr * (dst->height-1);
-    }
-}
-
-static void pick_read_write(surface_t* s)
-{
-    // Choose best reader/writers.
-    switch (s->format) {
-        case GGL_PIXEL_FORMAT_RGBA_8888:    s->read = readABGR8888;  break;
-        case GGL_PIXEL_FORMAT_RGB_565:      s->read = readRGB565;    break;
-        default:                            s->read = read_pixel;    break;
-    }
-    s->write = write_pixel;
-}
-
-void ggl_pick_texture(context_t* c)
-{
-    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
-        surface_t& s = c->state.texture[i].surface;
-        if ((!c->state.texture[i].enable) || (!s.dirty))
-            continue;
-        s.dirty = 0;
-        pick_read_write(&s);
-        generated_tex_vars_t& gen = c->generated_vars.texture[i];
-        gen.width   = s.width;
-        gen.height  = s.height;
-        gen.stride  = s.stride;
-        gen.data    = uintptr_t(s.data);
-    }
-}
-
-void ggl_pick_cb(context_t* c)
-{
-    surface_t& s = c->state.buffers.color;
-    if (s.dirty) {
-        s.dirty = 0;
-        pick_read_write(&s);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-void read_pixel(const surface_t* s, context_t* c,
-        uint32_t x, uint32_t y, pixel_t* pixel)
-{
-    assert((x < s->width) && (y < s->height));
-
-    const GGLFormat* f = &(c->formats[s->format]);
-    int32_t index = x + (s->stride * y);
-    uint8_t* const data = s->data + index * f->size;
-    uint32_t v = 0;
-    switch (f->size) {
-        case 1:		v = *data;									break;
-        case 2:		v = *(uint16_t*)data;						break;
-        case 3:		v = (data[2]<<16)|(data[1]<<8)|data[0];     break;
-        case 4:		v = GGL_RGBA_TO_HOST(*(uint32_t*)data);		break;
-    }
-    for (int i=0 ; i<4 ; i++) {
-        pixel->s[i] = f->c[i].h - f->c[i].l;
-        if (pixel->s[i])
-            pixel->c[i] = extract(v,  f->c[i].h,  f->c[i].l, f->size*8);
-    }
-}
-
-void readRGB565(const surface_t* s, context_t* /*c*/,
-        uint32_t x, uint32_t y, pixel_t* pixel)
-{
-    uint16_t v = *(reinterpret_cast<uint16_t*>(s->data) + (x + (s->stride * y)));
-    pixel->c[0] = 0;
-    pixel->c[1] = v>>11;
-    pixel->c[2] = (v>>5)&0x3F;
-    pixel->c[3] = v&0x1F;
-    pixel->s[0] = 0;
-    pixel->s[1] = 5;
-    pixel->s[2] = 6;
-    pixel->s[3] = 5;
-}
-
-void readABGR8888(const surface_t* s, context_t* /*c*/,
-        uint32_t x, uint32_t y, pixel_t* pixel)
-{
-    uint32_t v = *(reinterpret_cast<uint32_t*>(s->data) + (x + (s->stride * y)));
-    v = GGL_RGBA_TO_HOST(v);
-    pixel->c[0] = v>>24;        // A
-    pixel->c[1] = v&0xFF;       // R
-    pixel->c[2] = (v>>8)&0xFF;  // G
-    pixel->c[3] = (v>>16)&0xFF; // B
-    pixel->s[0] = 
-    pixel->s[1] = 
-    pixel->s[2] = 
-    pixel->s[3] = 8;
-}
-
-void write_pixel(const surface_t* s, context_t* c,
-        uint32_t x, uint32_t y, const pixel_t* pixel)
-{
-    assert((x < s->width) && (y < s->height));
-
-    int dither = -1;
-    if (c->state.enables & GGL_ENABLE_DITHER) {
-        dither = c->ditherMatrix[ (x & GGL_DITHER_MASK) +
-                ((y & GGL_DITHER_MASK)<<GGL_DITHER_ORDER_SHIFT) ];
-    }
-
-    const GGLFormat* f = &(c->formats[s->format]);
-    int32_t index = x + (s->stride * y);
-    uint8_t* const data = s->data + index * f->size;
-        
-    uint32_t mask = 0;
-    uint32_t v = 0;
-    for (int i=0 ; i<4 ; i++) {
-        const int component_mask = 1 << i;
-        if (f->components>=GGL_LUMINANCE &&
-                (i==GGLFormat::GREEN || i==GGLFormat::BLUE)) {
-            // destinations L formats don't have G or B
-            continue;
-        }
-        const int l = f->c[i].l;
-        const int h = f->c[i].h;
-        if (h && (c->state.mask.color & component_mask)) {
-            mask |= (((1<<(h-l))-1)<<l);
-            uint32_t u = pixel->c[i];
-            int32_t pixelSize = pixel->s[i];
-            if (pixelSize < (h-l)) {
-                u = expand(u, pixelSize, h-l);
-                pixelSize = h-l;
-            }
-            v = downshift_component(v, u, pixelSize, 0, h, l, 0, 0, dither);
-        }
-    }
-
-    if ((c->state.mask.color != 0xF) || 
-        (c->state.enables & GGL_ENABLE_LOGIC_OP)) {
-        uint32_t d = 0;
-        switch (f->size) {
-            case 1:	d = *data;									break;
-            case 2:	d = *(uint16_t*)data;						break;
-            case 3:	d = (data[2]<<16)|(data[1]<<8)|data[0];     break;
-            case 4:	d = GGL_RGBA_TO_HOST(*(uint32_t*)data);		break;
-        }
-        if (c->state.enables & GGL_ENABLE_LOGIC_OP) {
-            v = logic_op(c->state.logic_op.opcode, v, d);            
-            v &= mask;
-        }
-        v |= (d & ~mask);
-    }
-
-    switch (f->size) {
-        case 1:		*data = v;									break;
-        case 2:		*(uint16_t*)data = v;						break;
-        case 3:
-            data[0] = v;
-            data[1] = v>>8;
-            data[2] = v>>16;
-            break;
-        case 4:		*(uint32_t*)data = GGL_HOST_TO_RGBA(v);     break;
-    }
-}
-
-static uint32_t logic_op(int op, uint32_t s, uint32_t d)
-{
-    switch(op) {
-    case GGL_CLEAR:         return 0;
-    case GGL_AND:           return s & d;
-    case GGL_AND_REVERSE:   return s & ~d;
-    case GGL_COPY:          return s;
-    case GGL_AND_INVERTED:  return ~s & d;
-    case GGL_NOOP:          return d;
-    case GGL_XOR:           return s ^ d;
-    case GGL_OR:            return s | d;
-    case GGL_NOR:           return ~(s | d);
-    case GGL_EQUIV:         return ~(s ^ d);
-    case GGL_INVERT:        return ~d;
-    case GGL_OR_REVERSE:    return s | ~d;
-    case GGL_COPY_INVERTED: return ~s;
-    case GGL_OR_INVERTED:   return ~s | d;
-    case GGL_NAND:          return ~(s & d);
-    case GGL_SET:           return ~0;
-    };
-    return s;
-}            
-
-
-uint32_t ggl_expand(uint32_t v, int sbits, int dbits)
-{
-    return expand(v, sbits, dbits);
-}
-
-uint32_t ggl_pack_color(context_t* c, int32_t format,
-        GGLcolor r, GGLcolor g, GGLcolor b, GGLcolor a)
-{
-    const GGLFormat* f = &(c->formats[format]);
-    uint32_t p = 0;
-    const int32_t hbits = GGL_COLOR_BITS;
-    const int32_t lbits = GGL_COLOR_BITS - 8;
-    p = downshift_component(p, r,   hbits, lbits,  f->rh, f->rl, 0, 1, -1);
-    p = downshift_component(p, g,   hbits, lbits,  f->gh, f->gl, 0, 1, -1);
-    p = downshift_component(p, b,   hbits, lbits,  f->bh, f->bl, 0, 1, -1);
-    p = downshift_component(p, a,   hbits, lbits,  f->ah, f->al, 0, 1, -1);
-    switch (f->size) {
-        case 1:
-            p |= p << 8;
-            FALLTHROUGH_INTENDED;
-        case 2:
-            p |= p << 16;
-    }
-    return p;
-}
-
-// ----------------------------------------------------------------------------
-
-// extract a component from a word
-uint32_t extract(uint32_t v, int h, int l, int bits)
-{
-	assert(h);
-	if (l) {
-		v >>= l;
-	}
-	if (h != bits) {
-		v &= (1<<(h-l))-1;
-	}
-	return v;
-}
-
-// expand a component from sbits to dbits
-uint32_t expand(uint32_t v, int sbits, int dbits)
-{
-    if (dbits > sbits) {
-        assert(sbits);
-        if (sbits==1) {
-            v = (v<<dbits) - v;
-        } else {
-            if (dbits % sbits) {
-                v <<= (dbits-sbits);
-                dbits -= sbits;
-                do {
-                    v |= v>>sbits;
-                    dbits -= sbits;
-                    sbits *= 2;
-                } while (dbits>0);
-            } else {
-                dbits -= sbits;
-                do {
-                    v |= v<<sbits;
-                    dbits -= sbits;
-                    if (sbits*2 < dbits) {
-                        sbits *= 2;
-                    }
-                } while (dbits > 0);
-            }
-        }
-    }
-	return v;
-}
-
-// downsample a component from sbits to dbits
-// and shift / construct the pixel
-uint32_t downshift_component(	uint32_t in, uint32_t v,
-                                int sh, int sl,		// src
-                                int dh, int dl,		// dst
-                                int ch, int cl,		// clear
-                                int dither)
-{
-	const int sbits = sh-sl;
-	const int dbits = dh-dl;
-    
-	assert(sbits>=dbits);
-
-
-    if (sbits>dbits) {
-        if (dither>=0) {
-            v -= (v>>dbits);				// fix up
-            const int shift = (GGL_DITHER_BITS - (sbits-dbits));
-            if (shift >= 0)   v += (dither >> shift) << sl;
-            else              v += (dither << (-shift)) << sl;
-        } else {
-            // don't do that right now, so we can reproduce the same
-            // artifacts we get on ARM (Where we don't do this)
-            // -> this is not really needed if we don't dither
-            //if (dBits > 1) { // result already OK if dBits==1
-            //    v -= (v>>dbits);				// fix up
-            //    v += 1 << ((sbits-dbits)-1);	// rounding
-            //}
-        }
-    }
-
-
-	// we need to clear the high bits of the source
-	if (ch) {
-		v <<= 32-sh;
-		sl += 32-sh;
-        sh = 32;
-	}
-	
-	if (dl) {
-		if (cl || (sbits>dbits)) {
-			v >>= sh-dbits;
-			sl = 0;
-			sh = dbits;
-            in |= v<<dl;
-		} else {
-			// sbits==dbits and we don't need to clean the lower bits
-			// so we just have to shift the component to the right location
-            int shift = dh-sh;
-            in |= v<<shift;
-		}
-	} else {
-		// destination starts at bit 0
-		// ie: sh-dh == sh-dbits
-		int shift = sh-dh;
-		if (shift > 0)      in |= v>>shift;
-		else if (shift < 0) in |= v<<shift;
-		else                in |= v;
-	}
-	return in;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
diff --git a/libpixelflinger/buffer.h b/libpixelflinger/buffer.h
deleted file mode 100644
index 9c9e4bc..0000000
--- a/libpixelflinger/buffer.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* libs/pixelflinger/buffer.h
-**
-** Copyright 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 ANDROID_GGL_TEXTURE_H
-#define ANDROID_GGL_TEXTURE_H
-
-#include <private/pixelflinger/ggl_context.h>
-
-namespace android {
-
-void ggl_init_texture(context_t* c);
-
-void ggl_set_surface(context_t* c, surface_t* dst, const GGLSurface* src);
-
-void ggl_pick_texture(context_t* c);
-void ggl_pick_cb(context_t* c);
-
-uint32_t ggl_expand(uint32_t v, int sbits, int dbits);
-uint32_t ggl_pack_color(context_t* c, int32_t format,
-            GGLcolor r, GGLcolor g, GGLcolor b, GGLcolor a);
-
-}; // namespace android
-
-#endif // ANDROID_GGL_TEXTURE_H
diff --git a/libpixelflinger/clear.cpp b/libpixelflinger/clear.cpp
deleted file mode 100644
index b962456..0000000
--- a/libpixelflinger/clear.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/* libs/pixelflinger/clear.cpp
-**
-** Copyright 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.
-*/
-
-#include <cutils/memory.h>
-
-#include "clear.h"
-#include "buffer.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-static void ggl_clear(void* c, GGLbitfield mask);
-static void ggl_clearColorx(void* c,
-        GGLclampx r, GGLclampx g, GGLclampx b, GGLclampx a);        
-static void ggl_clearDepthx(void* c, GGLclampx depth);
-static void ggl_clearStencil(void* c, GGLint s);
-
-// ----------------------------------------------------------------------------
-
-void ggl_init_clear(context_t* c)
-{
-    GGLContext& procs = *(GGLContext*)c;
-    GGL_INIT_PROC(procs, clear);
-    GGL_INIT_PROC(procs, clearColorx);
-    GGL_INIT_PROC(procs, clearDepthx);
-    GGL_INIT_PROC(procs, clearStencil);
-    c->state.clear.dirty =  GGL_STENCIL_BUFFER_BIT |
-                            GGL_COLOR_BUFFER_BIT |
-                            GGL_DEPTH_BUFFER_BIT;
-    c->state.clear.depth = FIXED_ONE;
-}
-
-// ----------------------------------------------------------------------------
-
-static void memset2d(context_t* c, const surface_t& s, uint32_t packed,
-        uint32_t l, uint32_t t, uint32_t w, uint32_t h)
-{
-    const uint32_t size = c->formats[s.format].size;
-    const int32_t stride = s.stride * size;
-    uint8_t* dst = (uint8_t*)s.data + (l + t*s.stride)*size;
-    w *= size;
-
-    if (ggl_likely(int32_t(w) == stride)) {
-        // clear the whole thing in one call
-        w *= h;
-        h = 1;
-    }
-
-    switch (size) {
-    case 1:
-        do {
-            memset(dst, packed, w);
-            dst += stride;
-        } while(--h);
-        break;
-    case 2:
-        do {
-            android_memset16((uint16_t*)dst, packed, w);
-            dst += stride;
-        } while(--h);
-        break;
-    case 3: // XXX: 24-bit clear.
-        break;
-    case 4:
-        do {
-            android_memset32((uint32_t*)dst, packed, w);
-            dst += stride;
-        } while(--h);
-        break;
-    }    
-}
-
-static inline GGLfixed fixedToZ(GGLfixed z) {
-    return GGLfixed(((int64_t(z) << 16) - z) >> 16);
-}
-
-static void ggl_clear(void* con, GGLbitfield mask)
-{
-    GGL_CONTEXT(c, con);
-
-    // XXX: rgba-dithering, rgba-masking
-    // XXX: handle all formats of Z and S
-
-    const uint32_t l = c->state.scissor.left;
-    const uint32_t t = c->state.scissor.top;
-    uint32_t w = c->state.scissor.right - l;
-    uint32_t h = c->state.scissor.bottom - t;
-
-    if (!w || !h)
-        return;
-
-    // unexsiting buffers have no effect...
-    if (c->state.buffers.color.format == 0)
-        mask &= ~GGL_COLOR_BUFFER_BIT;
-
-    if (c->state.buffers.depth.format == 0)
-        mask &= ~GGL_DEPTH_BUFFER_BIT;
-
-    if (c->state.buffers.stencil.format == 0)
-        mask &= ~GGL_STENCIL_BUFFER_BIT;
-
-    if (mask & GGL_COLOR_BUFFER_BIT) {
-        if (c->state.clear.dirty & GGL_COLOR_BUFFER_BIT) {
-            c->state.clear.dirty &= ~GGL_COLOR_BUFFER_BIT;
-
-            uint32_t colorPacked = ggl_pack_color(c,
-                    c->state.buffers.color.format,
-                    gglFixedToIteratedColor(c->state.clear.r),
-                    gglFixedToIteratedColor(c->state.clear.g),
-                    gglFixedToIteratedColor(c->state.clear.b),
-                    gglFixedToIteratedColor(c->state.clear.a));
-
-            c->state.clear.colorPacked = GGL_HOST_TO_RGBA(colorPacked);
-        }
-        const uint32_t packed = c->state.clear.colorPacked;
-        memset2d(c, c->state.buffers.color, packed, l, t, w, h);
-    }
-    if (mask & GGL_DEPTH_BUFFER_BIT) {
-        if (c->state.clear.dirty & GGL_DEPTH_BUFFER_BIT) {
-            c->state.clear.dirty &= ~GGL_DEPTH_BUFFER_BIT;
-            uint32_t depth = fixedToZ(c->state.clear.depth);
-            c->state.clear.depthPacked = (depth<<16)|depth;
-        }
-        const uint32_t packed = c->state.clear.depthPacked;
-        memset2d(c, c->state.buffers.depth, packed, l, t, w, h);
-    }
-
-    // XXX: do stencil buffer
-}
-
-static void ggl_clearColorx(void* con,
-        GGLclampx r, GGLclampx g, GGLclampx b, GGLclampx a)
-{
-    GGL_CONTEXT(c, con);
-    c->state.clear.r = gglClampx(r);
-    c->state.clear.g = gglClampx(g);
-    c->state.clear.b = gglClampx(b);
-    c->state.clear.a = gglClampx(a);
-    c->state.clear.dirty |= GGL_COLOR_BUFFER_BIT;
-}
-
-static void ggl_clearDepthx(void* con, GGLclampx depth)
-{
-    GGL_CONTEXT(c, con);
-    c->state.clear.depth = gglClampx(depth);
-    c->state.clear.dirty |= GGL_DEPTH_BUFFER_BIT;
-}
-
-static void ggl_clearStencil(void* con, GGLint s)
-{
-    GGL_CONTEXT(c, con);
-    c->state.clear.stencil = s;
-    c->state.clear.dirty |= GGL_STENCIL_BUFFER_BIT;
-}
-
-}; // namespace android
diff --git a/libpixelflinger/clear.h b/libpixelflinger/clear.h
deleted file mode 100644
index b071df0..0000000
--- a/libpixelflinger/clear.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* libs/pixelflinger/clear.h
-**
-** Copyright 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 ANDROID_GGL_CLEAR_H
-#define ANDROID_GGL_CLEAR_H
-
-#include <pixelflinger/pixelflinger.h>
-#include <private/pixelflinger/ggl_context.h>
-
-namespace android {
-
-void ggl_init_clear(context_t* c);
-
-}; // namespace android
-
-#endif // ANDROID_GGL_CLEAR_H
diff --git a/libpixelflinger/codeflinger/ARMAssembler.cpp b/libpixelflinger/codeflinger/ARMAssembler.cpp
deleted file mode 100644
index f47b6e4..0000000
--- a/libpixelflinger/codeflinger/ARMAssembler.cpp
+++ /dev/null
@@ -1,579 +0,0 @@
-/* libs/pixelflinger/codeflinger/ARMAssembler.cpp
-**
-** Copyright 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.
-*/
-
-#define LOG_TAG "ARMAssembler"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <cutils/properties.h>
-#include <log/log.h>
-#include <private/pixelflinger/ggl_context.h>
-
-#include "ARMAssembler.h"
-#include "CodeCache.h"
-#include "disassem.h"
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark ARMAssembler...
-#endif
-
-ARMAssembler::ARMAssembler(const sp<Assembly>& assembly)
-    :   ARMAssemblerInterface(),
-        mAssembly(assembly)
-{
-    mBase = mPC = (uint32_t *)assembly->base();
-    mDuration = ggl_system_time();
-}
-
-ARMAssembler::~ARMAssembler()
-{
-}
-
-uint32_t* ARMAssembler::pc() const
-{
-    return mPC;
-}
-
-uint32_t* ARMAssembler::base() const
-{
-    return mBase;
-}
-
-void ARMAssembler::reset()
-{
-    mBase = mPC = (uint32_t *)mAssembly->base();
-    mBranchTargets.clear();
-    mLabels.clear();
-    mLabelsInverseMapping.clear();
-    mComments.clear();
-}
-
-int ARMAssembler::getCodegenArch()
-{
-    return CODEGEN_ARCH_ARM;
-}
-
-// ----------------------------------------------------------------------------
-
-void ARMAssembler::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("%08x:    %08x    ", uintptr_t(i), int(i[0]));
-        ::disassemble((uintptr_t)i);
-        i++;
-    }
-}
-
-void ARMAssembler::comment(const char* string)
-{
-    mComments.add(mPC, string);
-}
-
-void ARMAssembler::label(const char* theLabel)
-{
-    mLabels.add(theLabel, mPC);
-    mLabelsInverseMapping.add(mPC, theLabel);
-}
-
-void ARMAssembler::B(int cc, const char* label)
-{
-    mBranchTargets.add(branch_target_t(label, mPC));
-    *mPC++ = (cc<<28) | (0xA<<24) | 0;
-}
-
-void ARMAssembler::BL(int cc, const char* label)
-{
-    mBranchTargets.add(branch_target_t(label, mPC));
-    *mPC++ = (cc<<28) | (0xB<<24) | 0;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Prolog/Epilog & Generate...
-#endif
-
-
-void ARMAssembler::prolog()
-{
-    // write dummy prolog code
-    mPrologPC = mPC;
-    STM(AL, FD, SP, 1, LSAVED);
-}
-
-void ARMAssembler::epilog(uint32_t touched)
-{
-    touched &= LSAVED;
-    if (touched) {
-        // write prolog code
-        uint32_t* pc = mPC;
-        mPC = mPrologPC;
-        STM(AL, FD, SP, 1, touched | LLR);
-        mPC = pc;
-        // write epilog code
-        LDM(AL, FD, SP, 1, touched | LLR);
-        BX(AL, LR);
-    } else {   // heh, no registers to save!
-        // write prolog code
-        uint32_t* pc = mPC;
-        mPC = mPrologPC;
-        MOV(AL, 0, R0, R0); // NOP
-        mPC = pc;
-        // write epilog code
-        BX(AL, LR);
-    }
-}
-
-int ARMAssembler::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+2));
-        *bt.pc |= offset & 0xFFFFFF;
-    }
-
-    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 %lld 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 OK;
-}
-
-uint32_t* ARMAssembler::pcForLabel(const char* label)
-{
-    return mLabels.valueFor(label);
-}
-
-// ----------------------------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Data Processing...
-#endif
-
-void ARMAssembler::dataProcessing(int opcode, int cc,
-        int s, int Rd, int Rn, uint32_t Op2)
-{
-    *mPC++ = (cc<<28) | (opcode<<21) | (s<<20) | (Rn<<16) | (Rd<<12) | Op2;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Multiply...
-#endif
-
-// multiply...
-void ARMAssembler::MLA(int cc, int s,
-        int Rd, int Rm, int Rs, int Rn) {
-    if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
-    LOG_FATAL_IF(Rd==Rm, "MLA(r%u,r%u,r%u,r%u)", Rd,Rm,Rs,Rn);
-    *mPC++ =    (cc<<28) | (1<<21) | (s<<20) |
-                (Rd<<16) | (Rn<<12) | (Rs<<8) | 0x90 | Rm;
-}
-void ARMAssembler::MUL(int cc, int s,
-        int Rd, int Rm, int Rs) {
-    if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
-    LOG_FATAL_IF(Rd==Rm, "MUL(r%u,r%u,r%u)", Rd,Rm,Rs);
-    *mPC++ = (cc<<28) | (s<<20) | (Rd<<16) | (Rs<<8) | 0x90 | Rm;
-}
-void ARMAssembler::UMULL(int cc, int s,
-        int RdLo, int RdHi, int Rm, int Rs) {
-    LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
-                        "UMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
-    *mPC++ =    (cc<<28) | (1<<23) | (s<<20) |
-                (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-}
-void ARMAssembler::UMUAL(int cc, int s,
-        int RdLo, int RdHi, int Rm, int Rs) {
-    LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
-                        "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
-    *mPC++ =    (cc<<28) | (1<<23) | (1<<21) | (s<<20) |
-                (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-}
-void ARMAssembler::SMULL(int cc, int s,
-        int RdLo, int RdHi, int Rm, int Rs) {
-    LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
-                        "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
-    *mPC++ =    (cc<<28) | (1<<23) | (1<<22) | (s<<20) |
-                (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-}
-void ARMAssembler::SMUAL(int cc, int s,
-        int RdLo, int RdHi, int Rm, int Rs) {
-    LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
-                        "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
-    *mPC++ =    (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) |
-                (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Branches...
-#endif
-
-// branches...
-void ARMAssembler::B(int cc, uint32_t* pc)
-{
-    int32_t offset = int32_t(pc - (mPC+2));
-    *mPC++ = (cc<<28) | (0xA<<24) | (offset & 0xFFFFFF);
-}
-
-void ARMAssembler::BL(int cc, uint32_t* pc)
-{
-    int32_t offset = int32_t(pc - (mPC+2));
-    *mPC++ = (cc<<28) | (0xB<<24) | (offset & 0xFFFFFF);
-}
-
-void ARMAssembler::BX(int cc, int Rn)
-{
-    *mPC++ = (cc<<28) | 0x12FFF10 | Rn;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Data Transfer...
-#endif
-
-// data transfert...
-void ARMAssembler::LDR(int cc, int Rd, int Rn, uint32_t offset) {
-    *mPC++ = (cc<<28) | (1<<26) | (1<<20) | (Rn<<16) | (Rd<<12) | offset;
-}
-void ARMAssembler::LDRB(int cc, int Rd, int Rn, uint32_t offset) {
-    *mPC++ = (cc<<28) | (1<<26) | (1<<22) | (1<<20) | (Rn<<16) | (Rd<<12) | offset;
-}
-void ARMAssembler::STR(int cc, int Rd, int Rn, uint32_t offset) {
-    *mPC++ = (cc<<28) | (1<<26) | (Rn<<16) | (Rd<<12) | offset;
-}
-void ARMAssembler::STRB(int cc, int Rd, int Rn, uint32_t offset) {
-    *mPC++ = (cc<<28) | (1<<26) | (1<<22) | (Rn<<16) | (Rd<<12) | offset;
-}
-
-void ARMAssembler::LDRH(int cc, int Rd, int Rn, uint32_t offset) {
-    *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xB0 | offset;
-}
-void ARMAssembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset) {
-    *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xD0 | offset;
-}
-void ARMAssembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset) {
-    *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xF0 | offset;
-}
-void ARMAssembler::STRH(int cc, int Rd, int Rn, uint32_t offset) {
-    *mPC++ = (cc<<28) | (Rn<<16) | (Rd<<12) | 0xB0 | offset;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Block Data Transfer...
-#endif
-
-// block data transfer...
-void ARMAssembler::LDM(int cc, int dir,
-        int Rn, int W, uint32_t reg_list)
-{   //                    ED FD EA FA      IB IA DB DA
-    const uint8_t P[8] = { 1, 0, 1, 0,      1, 0, 1, 0 };
-    const uint8_t U[8] = { 1, 1, 0, 0,      1, 1, 0, 0 };
-    *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
-            (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list;
-}
-
-void ARMAssembler::STM(int cc, int dir,
-        int Rn, int W, uint32_t reg_list)
-{   //                    ED FD EA FA      IB IA DB DA
-    const uint8_t P[8] = { 0, 1, 0, 1,      1, 0, 1, 0 };
-    const uint8_t U[8] = { 0, 0, 1, 1,      1, 1, 0, 0 };
-    *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
-            (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Special...
-#endif
-
-// special...
-void ARMAssembler::SWP(int cc, int Rn, int Rd, int Rm) {
-    *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
-}
-void ARMAssembler::SWPB(int cc, int Rn, int Rd, int Rm) {
-    *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
-}
-void ARMAssembler::SWI(int cc, uint32_t comment) {
-    *mPC++ = (cc<<28) | (0xF<<24) | comment;
-}
-
-#if 0
-#pragma mark -
-#pragma mark DSP instructions...
-#endif
-
-// DSP instructions...
-void ARMAssembler::PLD(int Rn, uint32_t offset) {
-    LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))),
-                        "PLD only P=1, W=0");
-    *mPC++ = 0xF550F000 | (Rn<<16) | offset;
-}
-
-void ARMAssembler::CLZ(int cc, int Rd, int Rm)
-{
-    *mPC++ = (cc<<28) | 0x16F0F10| (Rd<<12) | Rm;
-}
-
-void ARMAssembler::QADD(int cc,  int Rd, int Rm, int Rn)
-{
-    *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm;
-}
-
-void ARMAssembler::QDADD(int cc,  int Rd, int Rm, int Rn)
-{
-    *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm;
-}
-
-void ARMAssembler::QSUB(int cc,  int Rd, int Rm, int Rn)
-{
-    *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm;
-}
-
-void ARMAssembler::QDSUB(int cc,  int Rd, int Rm, int Rn)
-{
-    *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm;
-}
-
-void ARMAssembler::SMUL(int cc, int xy,
-                int Rd, int Rm, int Rs)
-{
-    *mPC++ = (cc<<28) | 0x1600080 | (Rd<<16) | (Rs<<8) | (xy<<4) | Rm;
-}
-
-void ARMAssembler::SMULW(int cc, int y,
-                int Rd, int Rm, int Rs)
-{
-    *mPC++ = (cc<<28) | 0x12000A0 | (Rd<<16) | (Rs<<8) | (y<<4) | Rm;
-}
-
-void ARMAssembler::SMLA(int cc, int xy,
-                int Rd, int Rm, int Rs, int Rn)
-{
-    *mPC++ = (cc<<28) | 0x1000080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (xy<<4) | Rm;
-}
-
-void ARMAssembler::SMLAL(int cc, int xy,
-                int RdHi, int RdLo, int Rs, int Rm)
-{
-    *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm;
-}
-
-void ARMAssembler::SMLAW(int cc, int y,
-                int Rd, int Rm, int Rs, int Rn)
-{
-    *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Byte/half word extract and extend (ARMv6+ only)...
-#endif
-
-void ARMAssembler::UXTB16(int cc, int Rd, int Rm, int rotate)
-{
-    *mPC++ = (cc<<28) | 0x6CF0070 | (Rd<<12) | ((rotate >> 3) << 10) | Rm;
-}
-#if 0
-#pragma mark -
-#pragma mark Bit manipulation (ARMv7+ only)...
-#endif
-
-// Bit manipulation (ARMv7+ only)...
-void ARMAssembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
-{
-    *mPC++ = (cc<<28) | 0x7E00000 | ((width-1)<<16) | (Rd<<12) | (lsb<<7) | 0x50 | Rn;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Addressing modes...
-#endif
-
-int ARMAssembler::buildImmediate(
-        uint32_t immediate, uint32_t& rot, uint32_t& imm)
-{
-    rot = 0;
-    imm = immediate;
-    if (imm > 0x7F) { // skip the easy cases
-        while (!(imm&3)  || (imm&0xFC000000)) {
-            uint32_t newval;
-            newval = imm >> 2;
-            newval |= (imm&3) << 30;
-            imm = newval;
-            rot += 2;
-            if (rot == 32) {
-                rot = 0;
-                break;
-            }
-        }
-    }
-    rot = (16 - (rot>>1)) & 0xF;
-
-    if (imm>=0x100)
-        return -EINVAL;
-
-    if (((imm>>(rot<<1)) | (imm<<(32-(rot<<1)))) != immediate)
-        return -1;
-
-    return 0;
-}
-
-// shifters...
-
-bool ARMAssembler::isValidImmediate(uint32_t immediate)
-{
-    uint32_t rot, imm;
-    return buildImmediate(immediate, rot, imm) == 0;
-}
-
-uint32_t ARMAssembler::imm(uint32_t immediate)
-{
-    uint32_t rot, imm;
-    int err = buildImmediate(immediate, rot, imm);
-
-    LOG_ALWAYS_FATAL_IF(err==-EINVAL,
-                        "immediate %08x cannot be encoded",
-                        immediate);
-
-    LOG_ALWAYS_FATAL_IF(err,
-                        "immediate (%08x) encoding bogus!",
-                        immediate);
-
-    return (1<<25) | (rot<<8) | imm;
-}
-
-uint32_t ARMAssembler::reg_imm(int Rm, int type, uint32_t shift)
-{
-    return ((shift&0x1F)<<7) | ((type&0x3)<<5) | (Rm&0xF);
-}
-
-uint32_t ARMAssembler::reg_rrx(int Rm)
-{
-    return (ROR<<5) | (Rm&0xF);
-}
-
-uint32_t ARMAssembler::reg_reg(int Rm, int type, int Rs)
-{
-    return ((Rs&0xF)<<8) | ((type&0x3)<<5) | (1<<4) | (Rm&0xF);
-}
-
-// addressing modes...
-// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
-uint32_t ARMAssembler::immed12_pre(int32_t immed12, int W)
-{
-    LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
-                        "LDR(B)/STR(B)/PLD immediate too big (%08x)",
-                        immed12);
-    return (1<<24) | (((uint32_t(immed12)>>31)^1)<<23) |
-            ((W&1)<<21) | (abs(immed12)&0x7FF);
-}
-
-uint32_t ARMAssembler::immed12_post(int32_t immed12)
-{
-    LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
-                        "LDR(B)/STR(B)/PLD immediate too big (%08x)",
-                        immed12);
-
-    return (((uint32_t(immed12)>>31)^1)<<23) | (abs(immed12)&0x7FF);
-}
-
-uint32_t ARMAssembler::reg_scale_pre(int Rm, int type,
-        uint32_t shift, int W)
-{
-    return  (1<<25) | (1<<24) |
-            (((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) |
-            reg_imm(abs(Rm), type, shift);
-}
-
-uint32_t ARMAssembler::reg_scale_post(int Rm, int type, uint32_t shift)
-{
-    return (1<<25) | (((uint32_t(Rm)>>31)^1)<<23) | reg_imm(abs(Rm), type, shift);
-}
-
-// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0)
-uint32_t ARMAssembler::immed8_pre(int32_t immed8, int W)
-{
-    uint32_t offset = abs(immed8);
-
-    LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
-                        "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
-                        immed8);
-
-    return  (1<<24) | (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
-            ((W&1)<<21) | (((offset&0xF0)<<4)|(offset&0xF));
-}
-
-uint32_t ARMAssembler::immed8_post(int32_t immed8)
-{
-    uint32_t offset = abs(immed8);
-
-    LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
-                        "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
-                        immed8);
-
-    return (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
-            (((offset&0xF0)<<4) | (offset&0xF));
-}
-
-uint32_t ARMAssembler::reg_pre(int Rm, int W)
-{
-    return (1<<24) | (((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) | (abs(Rm)&0xF);
-}
-
-uint32_t ARMAssembler::reg_post(int Rm)
-{
-    return (((uint32_t(Rm)>>31)^1)<<23) | (abs(Rm)&0xF);
-}
-
-}; // namespace android
diff --git a/libpixelflinger/codeflinger/ARMAssembler.h b/libpixelflinger/codeflinger/ARMAssembler.h
deleted file mode 100644
index 76acf7e..0000000
--- a/libpixelflinger/codeflinger/ARMAssembler.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/* libs/pixelflinger/codeflinger/ARMAssembler.h
-**
-** Copyright 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 ANDROID_ARMASSEMBLER_H
-#define ANDROID_ARMASSEMBLER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "tinyutils/smartpointer.h"
-#include "utils/Vector.h"
-#include "utils/KeyedVector.h"
-
-#include "ARMAssemblerInterface.h"
-#include "CodeCache.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class ARMAssembler : public ARMAssemblerInterface
-{
-public:
-    explicit    ARMAssembler(const sp<Assembly>& assembly);
-    virtual     ~ARMAssembler();
-
-    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...
-    // LDR(B)/STR(B)/PLD
-    // (immediate and Rm can be negative, which indicates U=0)
-    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);
-
-    // LDRH/LDRSB/LDRSH/STRH
-    // (immediate and Rm can be negative, which indicates U=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 LDR (int cc, int Rd,
-                int Rn, uint32_t offset = __immed12_pre(0));
-    virtual void LDRB(int cc, int Rd,
-                int Rn, uint32_t offset = __immed12_pre(0));
-    virtual void STR (int cc, int Rd,
-                int Rn, uint32_t offset = __immed12_pre(0));
-    virtual void STRB(int cc, int Rd,
-                int Rn, uint32_t offset = __immed12_pre(0));
-    virtual void LDRH (int cc, int Rd,
-                int Rn, uint32_t offset = __immed8_pre(0));
-    virtual void LDRSB(int cc, int Rd, 
-                int Rn, uint32_t offset = __immed8_pre(0));
-    virtual void LDRSH(int cc, int Rd,
-                int Rn, uint32_t offset = __immed8_pre(0));
-    virtual void STRH (int cc, int Rd,
-                int Rn, uint32_t offset = __immed8_pre(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:
-                ARMAssembler(const ARMAssembler& rhs);
-                ARMAssembler& operator = (const ARMAssembler& rhs);
-
-    sp<Assembly>    mAssembly;
-    uint32_t*       mBase;
-    uint32_t*       mPC;
-    uint32_t*       mPrologPC;
-    int64_t         mDuration;
-    
-    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;
-    };
-    
-    Vector<branch_target_t>                 mBranchTargets;
-    KeyedVector< const char*, uint32_t* >   mLabels;
-    KeyedVector< uint32_t*, const char* >   mLabelsInverseMapping;
-    KeyedVector< uint32_t*, const char* >   mComments;
-};
-
-}; // namespace android
-
-#endif //ANDROID_ARMASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
deleted file mode 100644
index c96cf4b..0000000
--- a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/* libs/pixelflinger/codeflinger/ARMAssemblerInterface.cpp
-**
-** Copyright 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.
-*/
-#define LOG_TAG "pixelflinger-code"
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <log/log.h>
-
-#include "ARMAssemblerInterface.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-ARMAssemblerInterface::~ARMAssemblerInterface()
-{
-}
-
-// --------------------------------------------------------------------
-
-// The following two functions are static and used for initializers
-// in the original ARM code. The above versions (without __), are now
-// virtual, and can be overridden in the MIPS code. But since these are
-// needed at initialization time, they must be static. Not thrilled with
-// this implementation, but it works...
-
-uint32_t ARMAssemblerInterface::__immed12_pre(int32_t immed12, int W)
-{
-    LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
-                        "LDR(B)/STR(B)/PLD immediate too big (%08x)",
-                        immed12);
-    return (1<<24) | (((uint32_t(immed12)>>31)^1)<<23) |
-            ((W&1)<<21) | (abs(immed12)&0x7FF);
-}
-
-uint32_t ARMAssemblerInterface::__immed8_pre(int32_t immed8, int W)
-{
-    uint32_t offset = abs(immed8);
-
-    LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
-                        "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
-                        immed8);
-
-    return  (1<<24) | (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
-            ((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
deleted file mode 100644
index 72935ac..0000000
--- a/libpixelflinger/codeflinger/ARMAssemblerInterface.h
+++ /dev/null
@@ -1,349 +0,0 @@
-/* libs/pixelflinger/codeflinger/ARMAssemblerInterface.h
-**
-** Copyright 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 ANDROID_ARMASSEMBLER_INTERFACE_H
-#define ANDROID_ARMASSEMBLER_INTERFACE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class ARMAssemblerInterface
-{
-public:
-    virtual ~ARMAssemblerInterface();
-
-    enum {
-        EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV,
-        HS = CS,
-        LO = CC
-    };
-    enum {
-        S = 1
-    };
-    enum {
-        LSL, LSR, ASR, ROR
-    };
-    enum {
-        ED, FD, EA, FA,
-        IB, IA, DB, DA
-    };
-    enum {
-        R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15,
-        SP = R13,
-        LR = R14,
-        PC = R15
-    };
-    enum {
-        #define LIST(rr) L##rr=1<<rr
-        LIST(R0), LIST(R1), LIST(R2), LIST(R3), LIST(R4), LIST(R5), LIST(R6),
-        LIST(R7), LIST(R8), LIST(R9), LIST(R10), LIST(R11), LIST(R12),
-        LIST(R13), LIST(R14), LIST(R15),
-        LIST(SP), LIST(LR), LIST(PC),
-        #undef LIST
-        LSAVED = LR4|LR5|LR6|LR7|LR8|LR9|LR10|LR11 | LLR
-    };
-
-    enum {
-        CODEGEN_ARCH_ARM = 1, CODEGEN_ARCH_MIPS, CODEGEN_ARCH_ARM64, CODEGEN_ARCH_MIPS64
-    };
-
-    // -----------------------------------------------------------------------
-    // shifters and addressing modes
-    // -----------------------------------------------------------------------
-
-    // these static versions are used for initializers on LDxx/STxx below
-    static uint32_t    __immed12_pre(int32_t immed12, int W=0);
-    static uint32_t    __immed8_pre(int32_t immed12, int W=0);
-
-    virtual bool        isValidImmediate(uint32_t immed) = 0;
-    virtual int         buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm) = 0;
-
-    virtual uint32_t    imm(uint32_t immediate) = 0;
-    virtual uint32_t    reg_imm(int Rm, int type, uint32_t shift) = 0;
-    virtual uint32_t    reg_rrx(int Rm) = 0;
-    virtual uint32_t    reg_reg(int Rm, int type, int Rs) = 0;
-
-    // addressing modes... 
-    // LDR(B)/STR(B)/PLD
-    // (immediate and Rm can be negative, which indicates U=0)
-    virtual uint32_t    immed12_pre(int32_t immed12, int W=0) = 0;
-    virtual uint32_t    immed12_post(int32_t immed12) = 0;
-    virtual uint32_t    reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0) = 0;
-    virtual uint32_t    reg_scale_post(int Rm, int type=0, uint32_t shift=0) = 0;
-
-    // LDRH/LDRSB/LDRSH/STRH
-    // (immediate and Rm can be negative, which indicates U=0)
-    virtual uint32_t    immed8_pre(int32_t immed8, int W=0) = 0;
-    virtual uint32_t    immed8_post(int32_t immed8) = 0;
-    virtual uint32_t    reg_pre(int Rm, int W=0) = 0;
-    virtual uint32_t    reg_post(int Rm) = 0;
-
-    // -----------------------------------------------------------------------
-    // basic instructions & code generation
-    // -----------------------------------------------------------------------
-
-    // generate the code
-    virtual void reset() = 0;
-    virtual int  generate(const char* name) = 0;
-    virtual void disassemble(const char* name) = 0;
-    virtual int  getCodegenArch() = 0;
-    
-    // construct prolog and epilog
-    virtual void prolog() = 0;
-    virtual void epilog(uint32_t touched) = 0;
-    virtual void comment(const char* string) = 0;
-
-    // data processing...
-    enum {
-        opAND, opEOR, opSUB, opRSB, opADD, opADC, opSBC, opRSC, 
-        opTST, opTEQ, opCMP, opCMN, opORR, opMOV, opBIC, opMVN,
-        opADD64, opSUB64
-    };
-
-    virtual void
-            dataProcessing( int opcode, int cc, int s,
-                            int Rd, int Rn,
-                            uint32_t Op2) = 0;
-    
-    // multiply...
-    virtual void MLA(int cc, int s,
-                int Rd, int Rm, int Rs, int Rn) = 0;
-    virtual void MUL(int cc, int s,
-                int Rd, int Rm, int Rs) = 0;
-    virtual void UMULL(int cc, int s,
-                int RdLo, int RdHi, int Rm, int Rs) = 0;
-    virtual void UMUAL(int cc, int s,
-                int RdLo, int RdHi, int Rm, int Rs) = 0;
-    virtual void SMULL(int cc, int s,
-                int RdLo, int RdHi, int Rm, int Rs) = 0;
-    virtual void SMUAL(int cc, int s,
-                int RdLo, int RdHi, int Rm, int Rs) = 0;
-
-    // branches...
-    virtual void B(int cc, uint32_t* pc) = 0;
-    virtual void BL(int cc, uint32_t* pc) = 0;
-    virtual void BX(int cc, int Rn) = 0;
-
-    virtual void label(const char* theLabel) = 0;
-    virtual void B(int cc, const char* label) = 0;
-    virtual void BL(int cc, const char* label) = 0;
-
-    // valid only after generate() has been called
-    virtual uint32_t* pcForLabel(const char* label) = 0;
-
-    // data transfer...
-    virtual void LDR (int cc, int Rd,
-                int Rn, uint32_t offset = __immed12_pre(0)) = 0;
-    virtual void LDRB(int cc, int Rd,
-                int Rn, uint32_t offset = __immed12_pre(0)) = 0;
-    virtual void STR (int cc, int Rd,
-                int Rn, uint32_t offset = __immed12_pre(0)) = 0;
-    virtual void STRB(int cc, int Rd,
-                int Rn, uint32_t offset = __immed12_pre(0)) = 0;
-
-    virtual void LDRH (int cc, int Rd,
-                int Rn, uint32_t offset = __immed8_pre(0)) = 0;
-    virtual void LDRSB(int cc, int Rd, 
-                int Rn, uint32_t offset = __immed8_pre(0)) = 0;
-    virtual void LDRSH(int cc, int Rd,
-                int Rn, uint32_t offset = __immed8_pre(0)) = 0;
-    virtual void STRH (int cc, int Rd,
-                int Rn, uint32_t offset = __immed8_pre(0)) = 0;
-
-    // block data transfer...
-    virtual void LDM(int cc, int dir,
-                int Rn, int W, uint32_t reg_list) = 0;
-    virtual void STM(int cc, int dir,
-                int Rn, int W, uint32_t reg_list) = 0;
-
-    // special...
-    virtual void SWP(int cc, int Rn, int Rd, int Rm) = 0;
-    virtual void SWPB(int cc, int Rn, int Rd, int Rm) = 0;
-    virtual void SWI(int cc, uint32_t comment) = 0;
-
-    // DSP instructions...
-    enum {
-        // B=0, T=1
-        //     yx
-        xyBB = 0, // 0000,
-        xyTB = 2, // 0010,
-        xyBT = 4, // 0100,
-        xyTT = 6, // 0110,
-        yB   = 0, // 0000,
-        yT   = 4, // 0100
-    };
-
-    virtual void PLD(int Rn, uint32_t offset) = 0;
-
-    virtual void CLZ(int cc, int Rd, int Rm) = 0;
-    
-    virtual void QADD(int cc, int Rd, int Rm, int Rn) = 0;
-    virtual void QDADD(int cc, int Rd, int Rm, int Rn) = 0;
-    virtual void QSUB(int cc, int Rd, int Rm, int Rn) = 0;
-    virtual void QDSUB(int cc, int Rd, int Rm, int Rn) = 0;
-    
-    virtual void SMUL(int cc, int xy,
-                int Rd, int Rm, int Rs) = 0;
-    virtual void SMULW(int cc, int y,
-                int Rd, int Rm, int Rs) = 0;
-    virtual void SMLA(int cc, int xy,
-                int Rd, int Rm, int Rs, int Rn) = 0;
-    virtual void SMLAL(int cc, int xy,
-                int RdHi, int RdLo, int Rs, int Rm) = 0;
-    virtual void SMLAW(int cc, int y,
-                int Rd, int Rm, int Rs, int Rn) = 0;
-
-    // byte/half word extract...
-    virtual void UXTB16(int cc, int Rd, int Rm, int rotate) = 0;
-
-    // bit manipulation...
-    virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width) = 0;
-
-    // -----------------------------------------------------------------------
-    // convenience...
-    // -----------------------------------------------------------------------
-    inline void
-    ADC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
-        dataProcessing(opADC, cc, s, Rd, Rn, Op2);
-    }
-    inline void
-    ADD(int cc, int s, int Rd, int Rn, uint32_t Op2) {
-        dataProcessing(opADD, cc, s, Rd, Rn, Op2);
-    }
-    inline void
-    AND(int cc, int s, int Rd, int Rn, uint32_t Op2) {
-        dataProcessing(opAND, cc, s, Rd, Rn, Op2);
-    }
-    inline void
-    BIC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
-        dataProcessing(opBIC, cc, s, Rd, Rn, Op2);
-    }
-    inline void
-    EOR(int cc, int s, int Rd, int Rn, uint32_t Op2) {
-        dataProcessing(opEOR, cc, s, Rd, Rn, Op2);
-    }
-    inline void
-    MOV(int cc, int s, int Rd, uint32_t Op2) {
-        dataProcessing(opMOV, cc, s, Rd, 0, Op2);
-    }
-    inline void
-    MVN(int cc, int s, int Rd, uint32_t Op2) {
-        dataProcessing(opMVN, cc, s, Rd, 0, Op2);
-    }
-    inline void
-    ORR(int cc, int s, int Rd, int Rn, uint32_t Op2) {
-        dataProcessing(opORR, cc, s, Rd, Rn, Op2);
-    }
-    inline void
-    RSB(int cc, int s, int Rd, int Rn, uint32_t Op2) {
-        dataProcessing(opRSB, cc, s, Rd, Rn, Op2);
-    }
-    inline void
-    RSC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
-        dataProcessing(opRSC, cc, s, Rd, Rn, Op2);
-    }
-    inline void
-    SBC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
-        dataProcessing(opSBC, cc, s, Rd, Rn, Op2);
-    }
-    inline void
-    SUB(int cc, int s, int Rd, int Rn, uint32_t Op2) {
-        dataProcessing(opSUB, cc, s, Rd, Rn, Op2);
-    }
-    inline void
-    TEQ(int cc, int Rn, uint32_t Op2) {
-        dataProcessing(opTEQ, cc, 1, 0, Rn, Op2);
-    }
-    inline void
-    TST(int cc, int Rn, uint32_t Op2) {
-        dataProcessing(opTST, cc, 1, 0, Rn, Op2);
-    }
-    inline void
-    CMP(int cc, int Rn, uint32_t Op2) {
-        dataProcessing(opCMP, cc, 1, 0, Rn, Op2);
-    }
-    inline void
-    CMN(int cc, int Rn, uint32_t Op2) {
-        dataProcessing(opCMN, cc, 1, 0, Rn, Op2);
-    }
-
-    inline void SMULBB(int cc, int Rd, int Rm, int Rs) {
-        SMUL(cc, xyBB, Rd, Rm, Rs);    }
-    inline void SMULTB(int cc, int Rd, int Rm, int Rs) {
-        SMUL(cc, xyTB, Rd, Rm, Rs);    }
-    inline void SMULBT(int cc, int Rd, int Rm, int Rs) {
-        SMUL(cc, xyBT, Rd, Rm, Rs);    }
-    inline void SMULTT(int cc, int Rd, int Rm, int Rs) {
-        SMUL(cc, xyTT, Rd, Rm, Rs);    }
-
-    inline void SMULWB(int cc, int Rd, int Rm, int Rs) {
-        SMULW(cc, yB, Rd, Rm, Rs);    }
-    inline void SMULWT(int cc, int Rd, int Rm, int Rs) {
-        SMULW(cc, yT, Rd, Rm, Rs);    }
-
-    inline void
-    SMLABB(int cc, int Rd, int Rm, int Rs, int Rn) {
-        SMLA(cc, xyBB, Rd, Rm, Rs, Rn);    }
-    inline void
-    SMLATB(int cc, int Rd, int Rm, int Rs, int Rn) {
-        SMLA(cc, xyTB, Rd, Rm, Rs, Rn);    }
-    inline void
-    SMLABT(int cc, int Rd, int Rm, int Rs, int Rn) {
-        SMLA(cc, xyBT, Rd, Rm, Rs, Rn);    }
-    inline void
-    SMLATT(int cc, int Rd, int Rm, int Rs, int Rn) {
-        SMLA(cc, xyTT, Rd, Rm, Rs, Rn);    }
-
-    inline void
-    SMLALBB(int cc, int RdHi, int RdLo, int Rs, int Rm) {
-        SMLAL(cc, xyBB, RdHi, RdLo, Rs, Rm);    }
-    inline void
-    SMLALTB(int cc, int RdHi, int RdLo, int Rs, int Rm) {
-        SMLAL(cc, xyTB, RdHi, RdLo, Rs, Rm);    }
-    inline void
-    SMLALBT(int cc, int RdHi, int RdLo, int Rs, int Rm) {
-        SMLAL(cc, xyBT, RdHi, RdLo, Rs, Rm);    }
-    inline void
-    SMLALTT(int cc, int RdHi, int RdLo, int Rs, int Rm) {
-        SMLAL(cc, xyTT, RdHi, RdLo, Rs, Rm);    }
-
-    inline void
-    SMLAWB(int cc, int Rd, int Rm, int Rs, int Rn) {
-        SMLAW(cc, yB, Rd, Rm, Rs, Rn);    }
-    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
-
-#endif //ANDROID_ARMASSEMBLER_INTERFACE_H
diff --git a/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp b/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
deleted file mode 100644
index 816de48..0000000
--- a/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
+++ /dev/null
@@ -1,311 +0,0 @@
-/* libs/pixelflinger/codeflinger/ARMAssemblerProxy.cpp
-**
-** Copyright 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.
-*/
-
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "ARMAssemblerProxy.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-ARMAssemblerProxy::ARMAssemblerProxy()
-    : mTarget(0)
-{
-}
-
-ARMAssemblerProxy::ARMAssemblerProxy(ARMAssemblerInterface* target)
-    : mTarget(target)
-{
-}
-
-ARMAssemblerProxy::~ARMAssemblerProxy()
-{
-    delete mTarget;
-}
-
-void ARMAssemblerProxy::setTarget(ARMAssemblerInterface* target)
-{
-    delete mTarget;
-    mTarget = target;
-}
-
-void ARMAssemblerProxy::reset() {
-    mTarget->reset();
-}
-int ARMAssemblerProxy::generate(const char* name) {
-    return mTarget->generate(name);
-}
-void ARMAssemblerProxy::disassemble(const char* name) {
-    return mTarget->disassemble(name);
-}
-int ARMAssemblerProxy::getCodegenArch()
-{
-    return mTarget->getCodegenArch();
-}
-void ARMAssemblerProxy::prolog() {
-    mTarget->prolog();
-}
-void ARMAssemblerProxy::epilog(uint32_t touched) {
-    mTarget->epilog(touched);
-}
-void ARMAssemblerProxy::comment(const char* string) {
-    mTarget->comment(string);
-}
-
-
-
-// addressing modes
-
-bool ARMAssemblerProxy::isValidImmediate(uint32_t immed)
-{
-    return mTarget->isValidImmediate(immed);
-}
-
-int ARMAssemblerProxy::buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm)
-{
-    return mTarget->buildImmediate(i, rot, imm);
-}
-
-
-
-uint32_t ARMAssemblerProxy::imm(uint32_t immediate)
-{
-    return mTarget->imm(immediate);
-}
-
-uint32_t ARMAssemblerProxy::reg_imm(int Rm, int type, uint32_t shift)
-{
-    return mTarget->reg_imm(Rm, type, shift);
-}
-
-uint32_t ARMAssemblerProxy::reg_rrx(int Rm)
-{
-    return mTarget->reg_rrx(Rm);
-}
-
-uint32_t ARMAssemblerProxy::reg_reg(int Rm, int type, int Rs)
-{
-    return mTarget->reg_reg(Rm, type, Rs);
-}
-
-
-// addressing modes...
-// LDR(B)/STR(B)/PLD
-// (immediate and Rm can be negative, which indicates U=0)
-uint32_t ARMAssemblerProxy::immed12_pre(int32_t immed12, int W)
-{
-    return mTarget->immed12_pre(immed12, W);
-}
-
-uint32_t ARMAssemblerProxy::immed12_post(int32_t immed12)
-{
-    return mTarget->immed12_post(immed12);
-}
-
-uint32_t ARMAssemblerProxy::reg_scale_pre(int Rm, int type, uint32_t shift, int W)
-{
-    return mTarget->reg_scale_pre(Rm, type, shift, W);
-}
-
-uint32_t ARMAssemblerProxy::reg_scale_post(int Rm, int type, uint32_t shift)
-{
-    return mTarget->reg_scale_post(Rm, type, shift);
-}
-
-
-// LDRH/LDRSB/LDRSH/STRH
-// (immediate and Rm can be negative, which indicates U=0)
-uint32_t ARMAssemblerProxy::immed8_pre(int32_t immed8, int W)
-{
-    return mTarget->immed8_pre(immed8, W);
-}
-
-uint32_t ARMAssemblerProxy::immed8_post(int32_t immed8)
-{
-    return mTarget->immed8_post(immed8);
-}
-
-uint32_t ARMAssemblerProxy::reg_pre(int Rm, int W)
-{
-    return mTarget->reg_pre(Rm, W);
-}
-
-uint32_t ARMAssemblerProxy::reg_post(int Rm)
-{
-    return mTarget->reg_post(Rm);
-}
-
-
-//------------------------------------------------------------------------
-
-
-
-void ARMAssemblerProxy::dataProcessing( int opcode, int cc, int s,
-                                        int Rd, int Rn, uint32_t Op2)
-{
-    mTarget->dataProcessing(opcode, cc, s, Rd, Rn, Op2);
-}
-
-void ARMAssemblerProxy::MLA(int cc, int s, int Rd, int Rm, int Rs, int Rn) {
-    mTarget->MLA(cc, s, Rd, Rm, Rs, Rn);
-}
-void ARMAssemblerProxy::MUL(int cc, int s, int Rd, int Rm, int Rs) {
-    mTarget->MUL(cc, s, Rd, Rm, Rs);
-}
-void ARMAssemblerProxy::UMULL(int cc, int s,
-            int RdLo, int RdHi, int Rm, int Rs) {
-    mTarget->UMULL(cc, s, RdLo, RdHi, Rm, Rs); 
-}
-void ARMAssemblerProxy::UMUAL(int cc, int s,
-            int RdLo, int RdHi, int Rm, int Rs) {
-    mTarget->UMUAL(cc, s, RdLo, RdHi, Rm, Rs); 
-}
-void ARMAssemblerProxy::SMULL(int cc, int s,
-            int RdLo, int RdHi, int Rm, int Rs) {
-    mTarget->SMULL(cc, s, RdLo, RdHi, Rm, Rs); 
-}
-void ARMAssemblerProxy::SMUAL(int cc, int s,
-            int RdLo, int RdHi, int Rm, int Rs) {
-    mTarget->SMUAL(cc, s, RdLo, RdHi, Rm, Rs); 
-}
-
-void ARMAssemblerProxy::B(int cc, uint32_t* pc) {
-    mTarget->B(cc, pc); 
-}
-void ARMAssemblerProxy::BL(int cc, uint32_t* pc) {
-    mTarget->BL(cc, pc); 
-}
-void ARMAssemblerProxy::BX(int cc, int Rn) {
-    mTarget->BX(cc, Rn); 
-}
-void ARMAssemblerProxy::label(const char* theLabel) {
-    mTarget->label(theLabel);
-}
-void ARMAssemblerProxy::B(int cc, const char* label) {
-    mTarget->B(cc, label);
-}
-void ARMAssemblerProxy::BL(int cc, const char* label) {
-    mTarget->BL(cc, label);
-}
-
-uint32_t* ARMAssemblerProxy::pcForLabel(const char* label) {
-    return mTarget->pcForLabel(label);
-}
-
-void ARMAssemblerProxy::LDR(int cc, int Rd, int Rn, uint32_t offset) {
-    mTarget->LDR(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::LDRB(int cc, int Rd, int Rn, uint32_t offset) {
-    mTarget->LDRB(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::STR(int cc, int Rd, int Rn, uint32_t offset) {
-    mTarget->STR(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::STRB(int cc, int Rd, int Rn, uint32_t offset) {
-    mTarget->STRB(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::LDRH(int cc, int Rd, int Rn, uint32_t offset) {
-    mTarget->LDRH(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::LDRSB(int cc, int Rd, int Rn, uint32_t offset) {
-    mTarget->LDRSB(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::LDRSH(int cc, int Rd, int Rn, uint32_t offset) {
-    mTarget->LDRSH(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::STRH(int cc, int Rd, int Rn, uint32_t offset) {
-    mTarget->STRH(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::LDM(int cc, int dir, int Rn, int W, uint32_t reg_list) {
-    mTarget->LDM(cc, dir, Rn, W, reg_list);
-}
-void ARMAssemblerProxy::STM(int cc, int dir, int Rn, int W, uint32_t reg_list) {
-    mTarget->STM(cc, dir, Rn, W, reg_list);
-}
-
-void ARMAssemblerProxy::SWP(int cc, int Rn, int Rd, int Rm) {
-    mTarget->SWP(cc, Rn, Rd, Rm);
-}
-void ARMAssemblerProxy::SWPB(int cc, int Rn, int Rd, int Rm) {
-    mTarget->SWPB(cc, Rn, Rd, Rm);
-}
-void ARMAssemblerProxy::SWI(int cc, uint32_t comment) {
-    mTarget->SWI(cc, comment);
-}
-
-
-void ARMAssemblerProxy::PLD(int Rn, uint32_t offset) {
-    mTarget->PLD(Rn, offset);
-}
-void ARMAssemblerProxy::CLZ(int cc, int Rd, int Rm) {
-    mTarget->CLZ(cc, Rd, Rm);
-}
-void ARMAssemblerProxy::QADD(int cc, int Rd, int Rm, int Rn) {
-    mTarget->QADD(cc, Rd, Rm, Rn);
-}
-void ARMAssemblerProxy::QDADD(int cc, int Rd, int Rm, int Rn) {
-    mTarget->QDADD(cc, Rd, Rm, Rn);
-}
-void ARMAssemblerProxy::QSUB(int cc, int Rd, int Rm, int Rn) {
-    mTarget->QSUB(cc, Rd, Rm, Rn);
-}
-void ARMAssemblerProxy::QDSUB(int cc, int Rd, int Rm, int Rn) {
-    mTarget->QDSUB(cc, Rd, Rm, Rn);
-}
-void ARMAssemblerProxy::SMUL(int cc, int xy, int Rd, int Rm, int Rs) {
-    mTarget->SMUL(cc, xy, Rd, Rm, Rs);
-}
-void ARMAssemblerProxy::SMULW(int cc, int y, int Rd, int Rm, int Rs) {
-    mTarget->SMULW(cc, y, Rd, Rm, Rs);
-}
-void ARMAssemblerProxy::SMLA(int cc, int xy, int Rd, int Rm, int Rs, int Rn) {
-    mTarget->SMLA(cc, xy, Rd, Rm, Rs, Rn);
-}
-void ARMAssemblerProxy::SMLAL(  int cc, int xy,
-                                int RdHi, int RdLo, int Rs, int Rm) {
-    mTarget->SMLAL(cc, xy, RdHi, RdLo, Rs, Rm);
-}
-void ARMAssemblerProxy::SMLAW(int cc, int y, int Rd, int Rm, int Rs, int Rn) {
-    mTarget->SMLAW(cc, y, Rd, Rm, Rs, Rn);
-}
-
-void ARMAssemblerProxy::UXTB16(int cc, int Rd, int Rm, int rotate) {
-    mTarget->UXTB16(cc, Rd, Rm, rotate);
-}
-
-void ARMAssemblerProxy::UBFX(int cc, int Rd, int Rn, int lsb, int width) {
-    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
deleted file mode 100644
index 10d0390..0000000
--- a/libpixelflinger/codeflinger/ARMAssemblerProxy.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/* libs/pixelflinger/codeflinger/ARMAssemblerProxy.h
-**
-** Copyright 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 ANDROID_ARMASSEMBLER_PROXY_H
-#define ANDROID_ARMASSEMBLER_PROXY_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "ARMAssemblerInterface.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class ARMAssemblerProxy : public ARMAssemblerInterface
-{
-public:
-    // ARMAssemblerProxy take ownership of the target
-
-                ARMAssemblerProxy();
-    explicit    ARMAssemblerProxy(ARMAssemblerInterface* target);
-    virtual     ~ARMAssemblerProxy();
-
-    void setTarget(ARMAssemblerInterface* target);
-
-    virtual void    reset();
-    virtual int     generate(const char* name);
-    virtual void    disassemble(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
-    // -----------------------------------------------------------------------
-
-    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...
-    // LDR(B)/STR(B)/PLD
-    // (immediate and Rm can be negative, which indicates U=0)
-    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);
-
-    // LDRH/LDRSB/LDRSH/STRH
-    // (immediate and Rm can be negative, which indicates U=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);
-
-    uint32_t* pcForLabel(const char* label);
-
-    virtual void LDR (int cc, int Rd,
-                int Rn, uint32_t offset = __immed12_pre(0));
-    virtual void LDRB(int cc, int Rd,
-                int Rn, uint32_t offset = __immed12_pre(0));
-    virtual void STR (int cc, int Rd,
-                int Rn, uint32_t offset = __immed12_pre(0));
-    virtual void STRB(int cc, int Rd,
-                int Rn, uint32_t offset = __immed12_pre(0));
-    virtual void LDRH (int cc, int Rd,
-                int Rn, uint32_t offset = __immed8_pre(0));
-    virtual void LDRSB(int cc, int Rd, 
-                int Rn, uint32_t offset = __immed8_pre(0));
-    virtual void LDRSH(int cc, int Rd,
-                int Rn, uint32_t offset = __immed8_pre(0));
-    virtual void STRH (int cc, int Rd,
-                int Rn, uint32_t offset = __immed8_pre(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);
-
-    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;
-};
-
-}; // namespace android
-
-#endif //ANDROID_ARMASSEMBLER_PROXY_H
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.cpp b/libpixelflinger/codeflinger/Arm64Assembler.cpp
deleted file mode 100644
index 8926776..0000000
--- a/libpixelflinger/codeflinger/Arm64Assembler.cpp
+++ /dev/null
@@ -1,1240 +0,0 @@
-/*
- * 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 "ArmToArm64Assembler"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <cutils/properties.h>
-#include <log/log.h>
-#include <private/pixelflinger/ggl_context.h>
-
-#include "codeflinger/Arm64Assembler.h"
-#include "codeflinger/Arm64Disassembler.h"
-#include "codeflinger/CodeCache.h"
-
-/*
-** --------------------------------------------
-** Support for Arm64 in GGLAssembler JIT
-** --------------------------------------------
-**
-** Approach
-** - GGLAssembler and associated files are largely un-changed.
-** - A translator class maps ArmAssemblerInterface calls to
-**   generate Arm64 instructions.
-**
-** ----------------------
-** ArmToArm64Assembler
-** ----------------------
-**
-** - Subclassed from ArmAssemblerInterface
-**
-** - Translates each ArmAssemblerInterface call to generate
-**   one or more Arm64 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 Arm64 instructions. These functions also log the instruction
-**   to LOG, if ARM64_ASM_DEBUG define is set to 1
-**
-** - Dumps machine code and eqvt assembly if "debug.pf.disasm" option is set
-**   It uses arm64_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 Arm64
-**
-** - 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.
-**
-** --------------------------------------------
-** ArmToArm64Assembler unit test bench
-** --------------------------------------------
-**
-** - Tests ArmToArm64Assembler 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.
-**
-** ----------------------
-** Arm64 disassembler
-** ----------------------
-** - This disassembler disassembles only those machine codes which can be
-**   generated by ArmToArm64Assembler. 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.
-**
-** - ArmToArm64Assembler maps these functions to appropriate 64 bit
-**   functions.
-**
-** ----------------------
-** GGLAssembler changes
-** ----------------------
-** - Since ArmToArm64Assembler can generate 4 Arm64 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 ARM64_ASM_DEBUG 0
-
-#if ARM64_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 __unused const char* shift_codes[] =
-{
-    "LSL", "LSR", "ASR", "ROR"
-};
-static __unused const char *cc_codes[] =
-{
-    "EQ", "NE", "CS", "CC", "MI",
-    "PL", "VS", "VC", "HI", "LS",
-    "GE", "LT", "GT", "LE", "AL", "NV"
-};
-
-ArmToArm64Assembler::ArmToArm64Assembler(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;
-}
-
-ArmToArm64Assembler::ArmToArm64Assembler(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;
-}
-
-ArmToArm64Assembler::~ArmToArm64Assembler()
-{
-}
-
-uint32_t* ArmToArm64Assembler::pc() const
-{
-    return mPC;
-}
-
-uint32_t* ArmToArm64Assembler::base() const
-{
-    return mBase;
-}
-
-void ArmToArm64Assembler::reset()
-{
-    if(mAssembly == NULL)
-        mPC = mBase;
-    else
-        mBase = mPC = (uint32_t *)mAssembly->base();
-    mBranchTargets.clear();
-    mLabels.clear();
-    mLabelsInverseMapping.clear();
-    mComments.clear();
-#if ARM64_ASM_DEBUG
-    ALOGI("RESET\n");
-#endif
-}
-
-int ArmToArm64Assembler::getCodegenArch()
-{
-    return CODEGEN_ARCH_ARM64;
-}
-
-// ----------------------------------------------------------------------------
-
-void ArmToArm64Assembler::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];
-            ::arm64_disassemble(*i, instr);
-            printf("%s\n", instr);
-        }
-        i++;
-    }
-}
-
-void ArmToArm64Assembler::comment(const char* string)
-{
-    mComments.add(mPC, string);
-    LOG_INSTR("//%s\n", string);
-}
-
-void ArmToArm64Assembler::label(const char* theLabel)
-{
-    mLabels.add(theLabel, mPC);
-    mLabelsInverseMapping.add(mPC, theLabel);
-    LOG_LABEL("%s:\n", theLabel);
-}
-
-void ArmToArm64Assembler::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 ArmToArm64Assembler::BL(int /*cc*/, const char* /*label*/)
-{
-    NOT_IMPLEMENTED(); //Not Required
-}
-
-// ----------------------------------------------------------------------------
-//Prolog/Epilog & Generate...
-// ----------------------------------------------------------------------------
-
-void ArmToArm64Assembler::prolog()
-{
-    // write prolog code
-    mPrologPC = mPC;
-    *mPC++ = A64_MOVZ_X(mZeroReg,0,0);
-}
-
-void ArmToArm64Assembler::epilog(uint32_t /*touched*/)
-{
-    // write epilog code
-    static const int XLR = 30;
-    *mPC++ = A64_RET(XLR);
-}
-
-int ArmToArm64Assembler::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 OK;
-}
-
-uint32_t* ArmToArm64Assembler::pcForLabel(const char* label)
-{
-    return mLabels.valueFor(label);
-}
-
-// ----------------------------------------------------------------------------
-// Data Processing...
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::UMULL(int /*cc*/, int /*s*/,
-        int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-void ArmToArm64Assembler::UMUAL(int /*cc*/, int /*s*/,
-        int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-void ArmToArm64Assembler::SMULL(int /*cc*/, int /*s*/,
-        int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-void ArmToArm64Assembler::SMUAL(int /*cc*/, int /*s*/,
-        int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-
-// ----------------------------------------------------------------------------
-// branches relative to PC...
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::B(int /*cc*/, uint32_t* /*pc*/){
-    NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::BL(int /*cc*/, uint32_t* /*pc*/){
-    NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::BX(int /*cc*/, int /*Rn*/){
-    NOT_IMPLEMENTED(); //Not required
-}
-
-// ----------------------------------------------------------------------------
-// data transfer...
-// ----------------------------------------------------------------------------
-enum dataTransferOp
-{
-    opLDR,opLDRB,opLDRH,opSTR,opSTRB,opSTRH
-};
-
-void ArmToArm64Assembler::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 ArmToArm64Assembler::ADDR_LDR(int cc, int Rd, int Rn, uint32_t op_type)
-{
-    return dataTransfer(opLDR, cc, Rd, Rn, op_type, 64);
-}
-void ArmToArm64Assembler::ADDR_STR(int cc, int Rd, int Rn, uint32_t op_type)
-{
-    return dataTransfer(opSTR, cc, Rd, Rn, op_type, 64);
-}
-void ArmToArm64Assembler::LDR(int cc, int Rd, int Rn, uint32_t op_type)
-{
-    return dataTransfer(opLDR, cc, Rd, Rn, op_type);
-}
-void ArmToArm64Assembler::LDRB(int cc, int Rd, int Rn, uint32_t op_type)
-{
-    return dataTransfer(opLDRB, cc, Rd, Rn, op_type);
-}
-void ArmToArm64Assembler::STR(int cc, int Rd, int Rn, uint32_t op_type)
-{
-    return dataTransfer(opSTR, cc, Rd, Rn, op_type);
-}
-
-void ArmToArm64Assembler::STRB(int cc, int Rd, int Rn, uint32_t op_type)
-{
-    return dataTransfer(opSTRB, cc, Rd, Rn, op_type);
-}
-
-void ArmToArm64Assembler::LDRH(int cc, int Rd, int Rn, uint32_t op_type)
-{
-    return dataTransfer(opLDRH, cc, Rd, Rn, op_type);
-}
-void ArmToArm64Assembler::LDRSB(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-void ArmToArm64Assembler::LDRSH(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::STRH(int cc, int Rd, int Rn, uint32_t op_type)
-{
-    return dataTransfer(opSTRH, cc, Rd, Rn, op_type);
-}
-
-// ----------------------------------------------------------------------------
-// block data transfer...
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::SWP(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-void ArmToArm64Assembler::SWPB(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-void ArmToArm64Assembler::SWI(int /*cc*/, uint32_t /*comment*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-
-// ----------------------------------------------------------------------------
-// DSP instructions...
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::PLD(int /*Rn*/, uint32_t /*offset*/) {
-    NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::CLZ(int /*cc*/, int /*Rd*/, int /*Rm*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::QADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::QDADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::QSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::QDSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-}
-
-// ----------------------------------------------------------------------------
-// 16 x 16 multiplication
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::SMLAL(int /*cc*/, int /*xy*/,
-                int /*RdHi*/, int /*RdLo*/, int /*Rs*/, int /*Rm*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-    return;
-}
-
-void ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::buildImmediate(
-        uint32_t immediate, uint32_t& rot, uint32_t& imm)
-{
-    rot = 0;
-    imm = immediate;
-    return 0; // Always true
-}
-
-
-bool ArmToArm64Assembler::isValidImmediate(uint32_t immediate)
-{
-    uint32_t rot, imm;
-    return buildImmediate(immediate, rot, imm) == 0;
-}
-
-uint32_t ArmToArm64Assembler::imm(uint32_t immediate)
-{
-    mAddrMode.immediate = immediate;
-    mAddrMode.writeback = false;
-    mAddrMode.preindex  = false;
-    mAddrMode.postindex = false;
-    return OPERAND_IMM;
-
-}
-
-uint32_t ArmToArm64Assembler::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 ArmToArm64Assembler::reg_rrx(int /*Rm*/)
-{
-    NOT_IMPLEMENTED();
-    return OPERAND_UNSUPPORTED;
-}
-
-uint32_t ArmToArm64Assembler::reg_reg(int /*Rm*/, int /*type*/, int /*Rs*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-    return OPERAND_UNSUPPORTED;
-}
-// ----------------------------------------------------------------------------
-// Addressing modes...
-// ----------------------------------------------------------------------------
-uint32_t ArmToArm64Assembler::immed12_pre(int32_t immed12, int W)
-{
-    mAddrMode.immediate = immed12;
-    mAddrMode.writeback = W;
-    mAddrMode.preindex  = true;
-    mAddrMode.postindex = false;
-    return OPERAND_IMM;
-}
-
-uint32_t ArmToArm64Assembler::immed12_post(int32_t immed12)
-{
-    mAddrMode.immediate = immed12;
-    mAddrMode.writeback = true;
-    mAddrMode.preindex  = false;
-    mAddrMode.postindex = true;
-    return OPERAND_IMM;
-}
-
-uint32_t ArmToArm64Assembler::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 ArmToArm64Assembler::reg_scale_post(int /*Rm*/, int /*type*/, uint32_t /*shift*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-    return OPERAND_UNSUPPORTED;
-}
-
-uint32_t ArmToArm64Assembler::immed8_pre(int32_t immed8, int W)
-{
-    mAddrMode.immediate = immed8;
-    mAddrMode.writeback = W;
-    mAddrMode.preindex  = true;
-    mAddrMode.postindex = false;
-    return OPERAND_IMM;
-}
-
-uint32_t ArmToArm64Assembler::immed8_post(int32_t immed8)
-{
-    mAddrMode.immediate = immed8;
-    mAddrMode.writeback = true;
-    mAddrMode.preindex  = false;
-    mAddrMode.postindex = true;
-    return OPERAND_IMM;
-}
-
-uint32_t ArmToArm64Assembler::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 ArmToArm64Assembler::reg_post(int /*Rm*/)
-{
-    NOT_IMPLEMENTED(); //Not required
-    return OPERAND_UNSUPPORTED;
-}
-
-// ----------------------------------------------------------------------------
-// A64 instructions
-// ----------------------------------------------------------------------------
-
-static __unused 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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::A64_RET(uint32_t Rn)
-{
-    LOG_INSTR("RET X%d\n", Rn);
-    return ((0xD6 << 24) | (0x1 << 22) | (0x1F << 16) | (Rn << 5));
-}
-
-uint32_t ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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 ArmToArm64Assembler::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/Arm64Assembler.h b/libpixelflinger/codeflinger/Arm64Assembler.h
deleted file mode 100644
index 527c757..0000000
--- a/libpixelflinger/codeflinger/Arm64Assembler.h
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * 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_ARMTOARM64ASSEMBLER_H
-#define ANDROID_ARMTOARM64ASSEMBLER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "tinyutils/smartpointer.h"
-#include "utils/Vector.h"
-#include "utils/KeyedVector.h"
-
-#include "tinyutils/smartpointer.h"
-#include "codeflinger/ARMAssemblerInterface.h"
-#include "codeflinger/CodeCache.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class ArmToArm64Assembler : public ARMAssemblerInterface
-{
-public:
-    explicit    ArmToArm64Assembler(const sp<Assembly>& assembly);
-    explicit    ArmToArm64Assembler(void *base);
-    virtual     ~ArmToArm64Assembler();
-
-    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:
-    ArmToArm64Assembler(const ArmToArm64Assembler& rhs);
-    ArmToArm64Assembler& operator = (const ArmToArm64Assembler& 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);
-
-    // -----------------------------------------------------------------------
-    // Arm64 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_ARM64ASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/Arm64Disassembler.cpp b/libpixelflinger/codeflinger/Arm64Disassembler.cpp
deleted file mode 100644
index 70f1ff1..0000000
--- a/libpixelflinger/codeflinger/Arm64Disassembler.cpp
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * 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 arm64_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/Arm64Disassembler.h b/libpixelflinger/codeflinger/Arm64Disassembler.h
deleted file mode 100644
index 86f3aba..0000000
--- a/libpixelflinger/codeflinger/Arm64Disassembler.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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_ARM64DISASSEMBLER_H
-#define ANDROID_ARM64DISASSEMBLER_H
-
-#include <inttypes.h>
-int arm64_disassemble(uint32_t code, char* instr);
-
-#endif //ANDROID_ARM64ASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
deleted file mode 100644
index 32691a3..0000000
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/* libs/pixelflinger/codeflinger/CodeCache.cpp
-**
-** Copyright 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.
-*/
-
-#define LOG_TAG "CodeCache"
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <cutils/ashmem.h>
-#include <log/log.h>
-
-#include "CodeCache.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-#if defined(__arm__) || defined(__aarch64__)
-#include <unistd.h>
-#include <errno.h>
-#endif
-
-#if defined(__mips__)
-#include <asm/cachectl.h>
-#include <errno.h>
-#endif
-
-// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
-
-// A dlmalloc mspace is used to manage the code cache over a mmaped region.
-#define HAVE_MMAP 0
-#define HAVE_MREMAP 0
-#define HAVE_MORECORE 0
-#define MALLOC_ALIGNMENT 16
-#define MSPACES 1
-#define NO_MALLINFO 1
-#define ONLY_MSPACES 1
-// Custom heap error handling.
-#define PROCEED_ON_ERROR 0
-static void heap_error(const char* msg, const char* function, void* p);
-#define CORRUPTION_ERROR_ACTION(m) \
-    heap_error("HEAP MEMORY CORRUPTION", __FUNCTION__, NULL)
-#define USAGE_ERROR_ACTION(m,p) \
-    heap_error("ARGUMENT IS INVALID HEAP ADDRESS", __FUNCTION__, p)
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wexpansion-to-defined"
-#pragma GCC diagnostic ignored "-Wnull-pointer-arithmetic"
-#include "../../../../external/dlmalloc/malloc.c"
-#pragma GCC diagnostic pop
-
-static void heap_error(const char* msg, const char* function, void* p) {
-    ALOG(LOG_FATAL, LOG_TAG, "@@@ ABORTING: CODE FLINGER: %s IN %s addr=%p",
-         msg, function, p);
-    /* So that we can get a memory dump around p */
-    *((int **) 0xdeadbaad) = (int *) p;
-}
-
-// ----------------------------------------------------------------------------
-
-static void* gExecutableStore = NULL;
-static mspace gMspace = NULL;
-const size_t kMaxCodeCacheCapacity = 1024 * 1024;
-
-static mspace getMspace()
-{
-    if (gExecutableStore == NULL) {
-        int fd = ashmem_create_region("CodeFlinger code cache",
-                                      kMaxCodeCacheCapacity);
-        LOG_ALWAYS_FATAL_IF(fd < 0,
-                            "Creating code cache, ashmem_create_region "
-                            "failed with error '%s'", strerror(errno));
-        gExecutableStore = mmap(NULL, kMaxCodeCacheCapacity,
-                                PROT_READ | PROT_WRITE | PROT_EXEC,
-                                MAP_PRIVATE, fd, 0);
-        LOG_ALWAYS_FATAL_IF(gExecutableStore == MAP_FAILED,
-                            "Creating code cache, mmap failed with error "
-                            "'%s'", strerror(errno));
-        close(fd);
-        gMspace = create_mspace_with_base(gExecutableStore, kMaxCodeCacheCapacity,
-                                          /*locked=*/ false);
-        mspace_set_footprint_limit(gMspace, kMaxCodeCacheCapacity);
-    }
-    return gMspace;
-}
-
-Assembly::Assembly(size_t size)
-    : mCount(0), mSize(0)
-{
-    mBase = (uint32_t*)mspace_malloc(getMspace(), size);
-    LOG_ALWAYS_FATAL_IF(mBase == NULL,
-                        "Failed to create Assembly of size %zd in executable "
-                        "store of size %zd", size, kMaxCodeCacheCapacity);
-    mSize = size;
-}
-
-Assembly::~Assembly()
-{
-    mspace_free(getMspace(), mBase);
-}
-
-void Assembly::incStrong(const void*) const
-{
-    mCount.fetch_add(1, std::memory_order_relaxed);
-}
-
-void Assembly::decStrong(const void*) const
-{
-    if (mCount.fetch_sub(1, std::memory_order_acq_rel) == 1) {
-        delete this;
-    }
-}
-
-ssize_t Assembly::size() const
-{
-    if (!mBase) return NO_MEMORY;
-    return mSize;
-}
-
-uint32_t* Assembly::base() const
-{
-    return mBase;
-}
-
-ssize_t Assembly::resize(size_t newSize)
-{
-    mBase = (uint32_t*)mspace_realloc(getMspace(), mBase, newSize);
-    LOG_ALWAYS_FATAL_IF(mBase == NULL,
-                        "Failed to resize Assembly to %zd in code cache "
-                        "of size %zd", newSize, kMaxCodeCacheCapacity);
-    mSize = newSize;
-    return size();
-}
-
-// ----------------------------------------------------------------------------
-
-CodeCache::CodeCache(size_t size)
-    : mCacheSize(size), mCacheInUse(0)
-{
-    pthread_mutex_init(&mLock, 0);
-}
-
-CodeCache::~CodeCache()
-{
-    pthread_mutex_destroy(&mLock);
-}
-
-sp<Assembly> CodeCache::lookup(const AssemblyKeyBase& keyBase) const
-{
-    pthread_mutex_lock(&mLock);
-    sp<Assembly> r;
-    ssize_t index = mCacheData.indexOfKey(key_t(keyBase));
-    if (index >= 0) {
-        const cache_entry_t& e = mCacheData.valueAt(index);
-        e.when = mWhen++;
-        r = e.entry;
-    }
-    pthread_mutex_unlock(&mLock);
-    return r;
-}
-
-int CodeCache::cache(  const AssemblyKeyBase& keyBase,
-                            const sp<Assembly>& assembly)
-{
-    pthread_mutex_lock(&mLock);
-
-    const ssize_t assemblySize = assembly->size();
-    while (mCacheInUse + assemblySize > mCacheSize) {
-        // evict the LRU
-        size_t lru = 0;
-        size_t count = mCacheData.size();
-        for (size_t i=0 ; i<count ; i++) {
-            const cache_entry_t& e = mCacheData.valueAt(i);
-            if (e.when < mCacheData.valueAt(lru).when) {
-                lru = i;
-            }
-        }
-        const cache_entry_t& e = mCacheData.valueAt(lru);
-        mCacheInUse -= e.entry->size();
-        mCacheData.removeItemsAt(lru);
-    }
-
-    ssize_t err = mCacheData.add(key_t(keyBase), cache_entry_t(assembly, mWhen));
-    if (err >= 0) {
-        mCacheInUse += assemblySize;
-        mWhen++;
-        // synchronize caches...
-        char* base = reinterpret_cast<char*>(assembly->base());
-        char* curr = reinterpret_cast<char*>(base + assembly->size());
-        __builtin___clear_cache(base, curr);
-    }
-
-    pthread_mutex_unlock(&mLock);
-    return err;
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libpixelflinger/codeflinger/CodeCache.h b/libpixelflinger/codeflinger/CodeCache.h
deleted file mode 100644
index 9326453..0000000
--- a/libpixelflinger/codeflinger/CodeCache.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/* libs/pixelflinger/codeflinger/CodeCache.h
-**
-** Copyright 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 ANDROID_CODECACHE_H
-#define ANDROID_CODECACHE_H
-
-#include <atomic>
-#include <stdint.h>
-#include <pthread.h>
-#include <sys/types.h>
-
-#include "utils/KeyedVector.h"
-#include "tinyutils/smartpointer.h"
-
-namespace android {
-
-using namespace tinyutils;
-
-// ----------------------------------------------------------------------------
-
-class AssemblyKeyBase {
-public:
-    virtual ~AssemblyKeyBase() { }
-    virtual int compare_type(const AssemblyKeyBase& key) const = 0;
-};
-
-template  <typename T>
-class AssemblyKey : public AssemblyKeyBase
-{
-public:
-    explicit AssemblyKey(const T& rhs) : mKey(rhs) { }
-    virtual int compare_type(const AssemblyKeyBase& key) const {
-        const T& rhs = static_cast<const AssemblyKey&>(key).mKey;
-        return android::compare_type(mKey, rhs);
-    }
-private:
-    T mKey;
-};
-
-// ----------------------------------------------------------------------------
-
-class Assembly
-{
-public:
-    explicit    Assembly(size_t size);
-    virtual     ~Assembly();
-
-    ssize_t     size() const;
-    uint32_t*   base() const;
-    ssize_t     resize(size_t size);
-
-    // protocol for sp<>
-            void    incStrong(const void* id) const;
-            void    decStrong(const void* id) const;
-    typedef void    weakref_type;
-
-private:
-    mutable std::atomic<int32_t>     mCount;
-            uint32_t*   mBase;
-            size_t      mSize;
-};
-
-// ----------------------------------------------------------------------------
-
-class CodeCache
-{
-public:
-// pretty simple cache API...
-    explicit            CodeCache(size_t size);
-                        ~CodeCache();
-
-    sp<Assembly>        lookup(const AssemblyKeyBase& key) const;
-
-    int                 cache(const AssemblyKeyBase& key,
-                              const sp<Assembly>& assembly);
-
-private:
-    // nothing to see here...
-    struct cache_entry_t {
-        inline cache_entry_t() { }
-        inline cache_entry_t(const sp<Assembly>& a, int64_t w)
-                : entry(a), when(w) { }
-        sp<Assembly>            entry;
-        mutable int64_t         when;
-    };
-
-    class key_t {
-        friend int compare_type(
-            const key_value_pair_t<key_t, cache_entry_t>&,
-            const key_value_pair_t<key_t, cache_entry_t>&);
-        const AssemblyKeyBase* mKey;
-    public:
-        key_t() { };
-        explicit key_t(const AssemblyKeyBase& k) : mKey(&k)  { }
-    };
-
-    mutable pthread_mutex_t             mLock;
-    mutable int64_t                     mWhen;
-    size_t                              mCacheSize;
-    size_t                              mCacheInUse;
-    KeyedVector<key_t, cache_entry_t>   mCacheData;
-
-    friend int compare_type(
-        const key_value_pair_t<key_t, cache_entry_t>&,
-        const key_value_pair_t<key_t, cache_entry_t>&);
-};
-
-// KeyedVector uses compare_type(), which is more efficient, than
-// just using operator < ()
-inline int compare_type(
-    const key_value_pair_t<CodeCache::key_t, CodeCache::cache_entry_t>& lhs,
-    const key_value_pair_t<CodeCache::key_t, CodeCache::cache_entry_t>& rhs)
-{
-    return lhs.key.mKey->compare_type(*(rhs.key.mKey));
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif //ANDROID_CODECACHE_H
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
deleted file mode 100644
index 04e285d..0000000
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ /dev/null
@@ -1,1195 +0,0 @@
-/* libs/pixelflinger/codeflinger/GGLAssembler.cpp
-**
-** Copyright 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.
-*/
-
-#define LOG_TAG "GGLAssembler"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <log/log.h>
-
-#include "GGLAssembler.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-GGLAssembler::GGLAssembler(ARMAssemblerInterface* target)
-    : ARMAssemblerProxy(target),
-      RegisterAllocator(ARMAssemblerProxy::getCodegenArch()), mOptLevel(7)
-{
-}
-
-GGLAssembler::~GGLAssembler()
-{
-}
-
-void GGLAssembler::prolog()
-{
-    ARMAssemblerProxy::prolog();
-}
-
-void GGLAssembler::epilog(uint32_t touched)
-{
-    ARMAssemblerProxy::epilog(touched);
-}
-
-void GGLAssembler::reset(int opt_level)
-{
-    ARMAssemblerProxy::reset();
-    RegisterAllocator::reset();
-    mOptLevel = opt_level;
-}
-
-// ---------------------------------------------------------------------------
-
-int GGLAssembler::scanline(const needs_t& needs, context_t const* c)
-{
-    int err = 0;
-    int opt_level = mOptLevel;
-    while (opt_level >= 0) {
-        reset(opt_level);
-        err = scanline_core(needs, c);
-        if (err == 0)
-            break;
-        opt_level--;
-    }
-    
-    // XXX: in theory, pcForLabel is not valid before generate()
-    uint32_t* fragment_start_pc = pcForLabel("fragment_loop");
-    uint32_t* fragment_end_pc = pcForLabel("epilog");
-    const int per_fragment_ops = int(fragment_end_pc - fragment_start_pc);
-    
-    // build a name for our pipeline
-    char name[64];    
-    sprintf(name,
-            "scanline__%08X:%08X_%08X_%08X [%3d ipp]",
-            needs.p, needs.n, needs.t[0], needs.t[1], per_fragment_ops);
-
-    if (err) {
-        ALOGE("Error while generating ""%s""\n", name);
-        disassemble(name);
-        return -1;
-    }
-
-    return generate(name);
-}
-
-int GGLAssembler::scanline_core(const needs_t& needs, context_t const* c)
-{
-    mBlendFactorCached = 0;
-    mBlending = 0;
-    mMasking = 0;
-    mAA        = GGL_READ_NEEDS(P_AA, needs.p);
-    mDithering = GGL_READ_NEEDS(P_DITHER, needs.p);
-    mAlphaTest = GGL_READ_NEEDS(P_ALPHA_TEST, needs.p) + GGL_NEVER;
-    mDepthTest = GGL_READ_NEEDS(P_DEPTH_TEST, needs.p) + GGL_NEVER;
-    mFog       = GGL_READ_NEEDS(P_FOG, needs.p) != 0;
-    mSmooth    = GGL_READ_NEEDS(SHADE, needs.n) != 0;
-    mBuilderContext.needs = needs;
-    mBuilderContext.c = c;
-    mBuilderContext.Rctx = reserveReg(R0); // context always in R0
-    mCbFormat = c->formats[ GGL_READ_NEEDS(CB_FORMAT, needs.n) ];
-
-    // ------------------------------------------------------------------------
-
-    decodeLogicOpNeeds(needs);
-
-    decodeTMUNeeds(needs, c);
-
-    mBlendSrc  = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_SRC, needs.n));
-    mBlendDst  = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_DST, needs.n));
-    mBlendSrcA = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_SRCA, needs.n));
-    mBlendDstA = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_DSTA, needs.n));
-
-    if (!mCbFormat.c[GGLFormat::ALPHA].h) {
-        if ((mBlendSrc == GGL_ONE_MINUS_DST_ALPHA) ||
-            (mBlendSrc == GGL_DST_ALPHA)) {
-            mBlendSrc = GGL_ONE;
-        }
-        if ((mBlendSrcA == GGL_ONE_MINUS_DST_ALPHA) ||
-            (mBlendSrcA == GGL_DST_ALPHA)) {
-            mBlendSrcA = GGL_ONE;
-        }
-        if ((mBlendDst == GGL_ONE_MINUS_DST_ALPHA) ||
-            (mBlendDst == GGL_DST_ALPHA)) {
-            mBlendDst = GGL_ONE;
-        }
-        if ((mBlendDstA == GGL_ONE_MINUS_DST_ALPHA) ||
-            (mBlendDstA == GGL_DST_ALPHA)) {
-            mBlendDstA = GGL_ONE;
-        }
-    }
-
-    // if we need the framebuffer, read it now
-    const int blending =    blending_codes(mBlendSrc, mBlendDst) |
-                            blending_codes(mBlendSrcA, mBlendDstA);
-
-    // XXX: handle special cases, destination not modified...
-    if ((mBlendSrc==GGL_ZERO) && (mBlendSrcA==GGL_ZERO) &&
-        (mBlendDst==GGL_ONE) && (mBlendDstA==GGL_ONE)) {
-        // Destination unmodified (beware of logic ops)
-    } else if ((mBlendSrc==GGL_ZERO) && (mBlendSrcA==GGL_ZERO) &&
-        (mBlendDst==GGL_ZERO) && (mBlendDstA==GGL_ZERO)) {
-        // Destination is zero (beware of logic ops)
-    }
-    
-    int fbComponents = 0;
-    const int masking = GGL_READ_NEEDS(MASK_ARGB, needs.n);
-    for (int i=0 ; i<4 ; i++) {
-        const int mask = 1<<i;
-        component_info_t& info = mInfo[i];
-        int fs = i==GGLFormat::ALPHA ? mBlendSrcA : mBlendSrc;
-        int fd = i==GGLFormat::ALPHA ? mBlendDstA : mBlendDst;
-        if (fs==GGL_SRC_ALPHA_SATURATE && i==GGLFormat::ALPHA)
-            fs = GGL_ONE;
-        info.masked =   !!(masking & mask);
-        info.inDest =   !info.masked && mCbFormat.c[i].h && 
-                        ((mLogicOp & LOGIC_OP_SRC) || (!mLogicOp));
-        if (mCbFormat.components >= GGL_LUMINANCE &&
-                (i==GGLFormat::GREEN || i==GGLFormat::BLUE)) {
-            info.inDest = false;
-        }
-        info.needed =   (i==GGLFormat::ALPHA) && 
-                        (isAlphaSourceNeeded() || mAlphaTest != GGL_ALWAYS);
-        info.replaced = !!(mTextureMachine.replaced & mask);
-        info.iterated = (!info.replaced && (info.inDest || info.needed)); 
-        info.smooth =   mSmooth && info.iterated;
-        info.fog =      mFog && info.inDest && (i != GGLFormat::ALPHA);
-        info.blend =    (fs != int(GGL_ONE)) || (fd > int(GGL_ZERO));
-
-        mBlending |= (info.blend ? mask : 0);
-        mMasking |= (mCbFormat.c[i].h && info.masked) ? mask : 0;
-        fbComponents |= mCbFormat.c[i].h ? mask : 0;
-    }
-
-    mAllMasked = (mMasking == fbComponents);
-    if (mAllMasked) {
-        mDithering = 0;
-    }
-    
-    fragment_parts_t parts;
-
-    // ------------------------------------------------------------------------
-    prolog();
-    // ------------------------------------------------------------------------
-
-    build_scanline_prolog(parts, needs);
-
-    if (registerFile().status())
-        return registerFile().status();
-
-    // ------------------------------------------------------------------------
-    label("fragment_loop");
-    // ------------------------------------------------------------------------
-    {
-        Scratch regs(registerFile());
-
-        if (mDithering) {
-            // update the dither index.
-            MOV(AL, 0, parts.count.reg,
-                    reg_imm(parts.count.reg, ROR, GGL_DITHER_ORDER_SHIFT));
-            ADD(AL, 0, parts.count.reg, parts.count.reg,
-                    imm( 1 << (32 - GGL_DITHER_ORDER_SHIFT)));
-            MOV(AL, 0, parts.count.reg,
-                    reg_imm(parts.count.reg, ROR, 32 - GGL_DITHER_ORDER_SHIFT));
-        }
-
-        // XXX: could we do an early alpha-test here in some cases?
-        // It would probaly be used only with smooth-alpha and no texture
-        // (or no alpha component in the texture).
-
-        // Early z-test
-        if (mAlphaTest==GGL_ALWAYS) {
-            build_depth_test(parts, Z_TEST|Z_WRITE);
-        } else {
-            // we cannot do the z-write here, because
-            // it might be killed by the alpha-test later
-            build_depth_test(parts, Z_TEST);
-        }
-
-        { // texture coordinates
-            Scratch scratches(registerFile());
-
-            // texel generation
-            build_textures(parts, regs);
-            if (registerFile().status())
-                return registerFile().status();
-        }
-
-        if ((blending & (FACTOR_DST|BLEND_DST)) || 
-                (mMasking && !mAllMasked) ||
-                (mLogicOp & LOGIC_OP_DST)) 
-        {
-            // blending / logic_op / masking need the framebuffer
-            mDstPixel.setTo(regs.obtain(), &mCbFormat);
-
-            // load the framebuffer pixel
-            comment("fetch color-buffer");
-            load(parts.cbPtr, mDstPixel);
-        }
-
-        if (registerFile().status())
-            return registerFile().status();
-
-        pixel_t pixel;
-        int directTex = mTextureMachine.directTexture;
-        if (directTex | parts.packed) {
-            // note: we can't have both here
-            // iterated color or direct texture
-            pixel = directTex ? parts.texel[directTex-1] : parts.iterated;
-            pixel.flags &= ~CORRUPTIBLE;
-        } else {
-            if (mDithering) {
-                const int ctxtReg = mBuilderContext.Rctx;
-                const int mask = GGL_DITHER_SIZE-1;
-                parts.dither = reg_t(regs.obtain());
-                AND(AL, 0, parts.dither.reg, parts.count.reg, imm(mask));
-                ADDR_ADD(AL, 0, parts.dither.reg, ctxtReg, parts.dither.reg);
-                LDRB(AL, parts.dither.reg, parts.dither.reg,
-                        immed12_pre(GGL_OFFSETOF(ditherMatrix)));
-            }
-        
-            // allocate a register for the resulting pixel
-            pixel.setTo(regs.obtain(), &mCbFormat, FIRST);
-
-            build_component(pixel, parts, GGLFormat::ALPHA,    regs);
-
-            if (mAlphaTest!=GGL_ALWAYS) {
-                // only handle the z-write part here. We know z-test
-                // was successful, as well as alpha-test.
-                build_depth_test(parts, Z_WRITE);
-            }
-
-            build_component(pixel, parts, GGLFormat::RED,      regs);
-            build_component(pixel, parts, GGLFormat::GREEN,    regs);
-            build_component(pixel, parts, GGLFormat::BLUE,     regs);
-
-            pixel.flags |= CORRUPTIBLE;
-        }
-
-        if (registerFile().status())
-            return registerFile().status();
-        
-        if (pixel.reg == -1) {
-            // be defensive here. if we're here it's probably
-            // that this whole fragment is a no-op.
-            pixel = mDstPixel;
-        }
-        
-        if (!mAllMasked) {
-            // logic operation
-            build_logic_op(pixel, regs);
-    
-            // masking
-            build_masking(pixel, regs); 
-    
-            comment("store");
-            store(parts.cbPtr, pixel, WRITE_BACK);
-        }
-    }
-
-    if (registerFile().status())
-        return registerFile().status();
-
-    // update the iterated color...
-    if (parts.reload != 3) {
-        build_smooth_shade(parts);
-    }
-
-    // update iterated z
-    build_iterate_z(parts);
-
-    // update iterated fog
-    build_iterate_f(parts);
-
-    SUB(AL, S, parts.count.reg, parts.count.reg, imm(1<<16));
-    B(PL, "fragment_loop");
-    label("epilog");
-    epilog(registerFile().touched());
-
-    if ((mAlphaTest!=GGL_ALWAYS) || (mDepthTest!=GGL_ALWAYS)) {
-        if (mDepthTest!=GGL_ALWAYS) {
-            label("discard_before_textures");
-            build_iterate_texture_coordinates(parts);
-        }
-        label("discard_after_textures");
-        build_smooth_shade(parts);
-        build_iterate_z(parts);
-        build_iterate_f(parts);
-        if (!mAllMasked) {
-            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");
-        epilog(registerFile().touched());
-    }
-
-    return registerFile().status();
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_scanline_prolog(
-    fragment_parts_t& parts, const needs_t& needs)
-{
-    Scratch scratches(registerFile());
-
-    // compute count
-    comment("compute ct (# of pixels to process)");
-    parts.count.setTo(obtainReg());
-    int Rx = scratches.obtain();    
-    int Ry = scratches.obtain();
-    CONTEXT_LOAD(Rx, iterators.xl);
-    CONTEXT_LOAD(parts.count.reg, iterators.xr);
-    CONTEXT_LOAD(Ry, iterators.y);
-
-    // parts.count = iterators.xr - Rx
-    SUB(AL, 0, parts.count.reg, parts.count.reg, Rx);
-    SUB(AL, 0, parts.count.reg, parts.count.reg, imm(1));
-
-    if (mDithering) {
-        // parts.count.reg = 0xNNNNXXDD
-        // NNNN = count-1
-        // DD   = dither offset
-        // XX   = 0xxxxxxx (x = garbage)
-        Scratch scratches(registerFile());
-        int tx = scratches.obtain();
-        int ty = scratches.obtain();
-        AND(AL, 0, tx, Rx, imm(GGL_DITHER_MASK));
-        AND(AL, 0, ty, Ry, imm(GGL_DITHER_MASK));
-        ADD(AL, 0, tx, tx, reg_imm(ty, LSL, GGL_DITHER_ORDER_SHIFT));
-        ORR(AL, 0, parts.count.reg, tx, reg_imm(parts.count.reg, LSL, 16));
-    } else {
-        // parts.count.reg = 0xNNNN0000
-        // NNNN = count-1
-        MOV(AL, 0, parts.count.reg, reg_imm(parts.count.reg, LSL, 16));
-    }
-
-    if (!mAllMasked) {
-        // compute dst ptr
-        comment("compute color-buffer pointer");
-        const int cb_bits = mCbFormat.size*8;
-        int Rs = scratches.obtain();
-        parts.cbPtr.setTo(obtainReg(), cb_bits);
-        CONTEXT_LOAD(Rs, state.buffers.color.stride);
-        CONTEXT_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);
-    }
-    
-    // init fog
-    const int need_fog = GGL_READ_NEEDS(P_FOG, needs.p);
-    if (need_fog) {
-        comment("compute initial fog coordinate");
-        Scratch scratches(registerFile());
-        int dfdx = scratches.obtain();
-        int ydfdy = scratches.obtain();
-        int f = ydfdy;
-        CONTEXT_LOAD(dfdx,  generated_vars.dfdx);
-        CONTEXT_LOAD(ydfdy, iterators.ydfdy);
-        MLA(AL, 0, f, Rx, dfdx, ydfdy);
-        CONTEXT_STORE(f, generated_vars.f);
-    }
-
-    // init Z coordinate
-    if ((mDepthTest != GGL_ALWAYS) || GGL_READ_NEEDS(P_MASK_Z, needs.p)) {
-        parts.z = reg_t(obtainReg());
-        comment("compute initial Z coordinate");
-        Scratch scratches(registerFile());
-        int dzdx = scratches.obtain();
-        int ydzdy = parts.z.reg;
-        CONTEXT_LOAD(dzdx,  generated_vars.dzdx);   // 1.31 fixed-point
-        CONTEXT_LOAD(ydzdy, iterators.ydzdy);       // 1.31 fixed-point
-        MLA(AL, 0, parts.z.reg, Rx, dzdx, ydzdy);
-
-        // we're going to index zbase of parts.count
-        // zbase = base + (xl-count + stride*y)*2
-        int Rs = dzdx;
-        int zbase = scratches.obtain();
-        CONTEXT_LOAD(Rs, state.buffers.depth.stride);
-        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));
-        ADDR_ADD(AL, 0, zbase, zbase, reg_imm(Rs, LSL, 1));
-        CONTEXT_ADDR_STORE(zbase, generated_vars.zbase);
-    }
-
-    // init texture coordinates
-    init_textures(parts.coords, reg_t(Rx), reg_t(Ry));
-    scratches.recycle(Ry);
-
-    // iterated color
-    init_iterated_color(parts, reg_t(Rx));
-
-    // init coverage factor application (anti-aliasing)
-    if (mAA) {
-        parts.covPtr.setTo(obtainReg(), 16);
-        CONTEXT_ADDR_LOAD(parts.covPtr.reg, state.buffers.coverage);
-        ADDR_ADD(AL, 0, parts.covPtr.reg, parts.covPtr.reg, reg_imm(Rx, LSL, 1));
-    }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_component( pixel_t& pixel,
-                                    const fragment_parts_t& parts,
-                                    int component,
-                                    Scratch& regs)
-{
-    static char const * comments[] = {"alpha", "red", "green", "blue"};
-    comment(comments[component]);
-
-    // local register file
-    Scratch scratches(registerFile());
-    const int dst_component_size = pixel.component_size(component);
-
-    component_t temp(-1);
-    build_incoming_component( temp, dst_component_size,
-            parts, component, scratches, regs);
-
-    if (mInfo[component].inDest) {
-
-        // blending...
-        build_blending( temp, mDstPixel, component, scratches );
-
-        // downshift component and rebuild pixel...
-        downshift(pixel, component, temp, parts.dither);
-    }
-}
-
-void GGLAssembler::build_incoming_component(
-                                    component_t& temp,
-                                    int dst_size,
-                                    const fragment_parts_t& parts,
-                                    int component,
-                                    Scratch& scratches,
-                                    Scratch& global_regs)
-{
-    const uint32_t component_mask = 1<<component;
-
-    // Figure out what we need for the blending stage...
-    int fs = component==GGLFormat::ALPHA ? mBlendSrcA : mBlendSrc;
-    int fd = component==GGLFormat::ALPHA ? mBlendDstA : mBlendDst;
-    if (fs==GGL_SRC_ALPHA_SATURATE && component==GGLFormat::ALPHA) {
-        fs = GGL_ONE;
-    }
-
-    // Figure out what we need to extract and for what reason
-    const int blending = blending_codes(fs, fd);
-
-    // Are we actually going to blend?
-    const int need_blending = (fs != int(GGL_ONE)) || (fd > int(GGL_ZERO));
-    
-    // expand the source if the destination has more bits
-    int need_expander = false;
-    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT-1 ; i++) {
-        texture_unit_t& tmu = mTextureMachine.tmu[i];
-        if ((tmu.format_idx) &&
-            (parts.texel[i].component_size(component) < dst_size)) {
-            need_expander = true;
-        }
-    }
-
-    // do we need to extract this component?
-    const bool multiTexture = mTextureMachine.activeUnits > 1;
-    const int blend_needs_alpha_source = (component==GGLFormat::ALPHA) &&
-                                        (isAlphaSourceNeeded());
-    int need_extract = mInfo[component].needed;
-    if (mInfo[component].inDest)
-    {
-        need_extract |= ((need_blending ?
-                (blending & (BLEND_SRC|FACTOR_SRC)) : need_expander));
-        need_extract |= (mTextureMachine.mask != mTextureMachine.replaced);
-        need_extract |= mInfo[component].smooth;
-        need_extract |= mInfo[component].fog;
-        need_extract |= mDithering;
-        need_extract |= multiTexture;
-    }
-
-    if (need_extract) {
-        Scratch& regs = blend_needs_alpha_source ? global_regs : scratches;
-        component_t fragment;
-
-        // iterated color
-        build_iterated_color(fragment, parts, component, regs);
-
-        // texture environement (decal, modulate, replace)
-        build_texture_environment(fragment, parts, component, regs);
-
-        // expand the source if the destination has more bits
-        if (need_expander && (fragment.size() < dst_size)) {
-            // we're here only if we fetched a texel
-            // (so we know for sure fragment is CORRUPTIBLE)
-            expand(fragment, fragment, dst_size);
-        }
-
-        // We have a few specific things to do for the alpha-channel
-        if ((component==GGLFormat::ALPHA) &&
-            (mInfo[component].needed || fragment.size()<dst_size))
-        {
-            // convert to integer_t first and make sure
-            // we don't corrupt a needed register
-            if (fragment.l) {
-                component_t incoming(fragment);
-                modify(fragment, regs);
-                MOV(AL, 0, fragment.reg, reg_imm(incoming.reg, LSR, incoming.l));
-                fragment.h -= fragment.l;
-                fragment.l = 0;
-            }
-
-            // coverage factor application
-            build_coverage_application(fragment, parts, regs);
-
-            // alpha-test
-            build_alpha_test(fragment, parts);
-
-            if (blend_needs_alpha_source) {
-                // We keep only 8 bits for the blending stage
-                const int shift = fragment.h <= 8 ? 0 : fragment.h-8;
-                if (fragment.flags & CORRUPTIBLE) {
-                    fragment.flags &= ~CORRUPTIBLE;
-                    mAlphaSource.setTo(fragment.reg,
-                            fragment.size(), fragment.flags);
-                    if (shift) {
-                        MOV(AL, 0, mAlphaSource.reg,
-                            reg_imm(mAlphaSource.reg, LSR, shift));
-                    }
-                } else {
-                    // XXX: it would better to do this in build_blend_factor()
-                    // so we can avoid the extra MOV below.
-                    mAlphaSource.setTo(regs.obtain(),
-                            fragment.size(), CORRUPTIBLE);
-                    if (shift) {
-                        MOV(AL, 0, mAlphaSource.reg,
-                            reg_imm(fragment.reg, LSR, shift));
-                    } else {
-                        MOV(AL, 0, mAlphaSource.reg, fragment.reg);
-                    }
-                }
-                mAlphaSource.s -= shift;
-            }
-        }
-
-        // fog...
-        build_fog( fragment, component, regs );
-
-        temp = fragment;
-    } else {
-        if (mInfo[component].inDest) {
-            // extraction not needed and replace
-            // we just select the right component
-            if ((mTextureMachine.replaced & component_mask) == 0) {
-                // component wasn't replaced, so use it!
-                temp = component_t(parts.iterated, component);
-            }
-            for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
-                const texture_unit_t& tmu = mTextureMachine.tmu[i];
-                if ((tmu.mask & component_mask) &&
-                    ((tmu.replaced & component_mask) == 0)) {
-                    temp = component_t(parts.texel[i], component);
-                }
-            }
-        }
-    }
-}
-
-bool GGLAssembler::isAlphaSourceNeeded() const
-{
-    // XXX: also needed for alpha-test
-    const int bs = mBlendSrc;
-    const int bd = mBlendDst;
-    return  bs==GGL_SRC_ALPHA_SATURATE ||
-            bs==GGL_SRC_ALPHA || bs==GGL_ONE_MINUS_SRC_ALPHA ||
-            bd==GGL_SRC_ALPHA || bd==GGL_ONE_MINUS_SRC_ALPHA ; 
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_smooth_shade(const fragment_parts_t& parts)
-{
-    if (mSmooth && !parts.iterated_packed) {
-        // update the iterated color in a pipelined way...
-        comment("update iterated color");
-        Scratch scratches(registerFile());
-
-        const int reload = parts.reload;
-        for (int i=0 ; i<4 ; i++) {
-            if (!mInfo[i].iterated) 
-                continue;
-                
-            int c = parts.argb[i].reg;
-            int dx = parts.argb_dx[i].reg;
-            
-            if (reload & 1) {
-                c = scratches.obtain();
-                CONTEXT_LOAD(c, generated_vars.argb[i].c);
-            }
-            if (reload & 2) {
-                dx = scratches.obtain();
-                CONTEXT_LOAD(dx, generated_vars.argb[i].dx);
-            }
-            
-            if (mSmooth) {
-                ADD(AL, 0, c, c, dx);
-            }
-            
-            if (reload & 1) {
-                CONTEXT_STORE(c, generated_vars.argb[i].c);
-                scratches.recycle(c);
-            }
-            if (reload & 2) {
-                scratches.recycle(dx);
-            }
-        }
-    }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_coverage_application(component_t& fragment,
-        const fragment_parts_t& parts, Scratch& regs)
-{
-    // here fragment.l is guarenteed to be 0
-    if (mAA) {
-        // coverages are 1.15 fixed-point numbers
-        comment("coverage application");
-
-        component_t incoming(fragment);
-        modify(fragment, regs);
-
-        Scratch scratches(registerFile());
-        int cf = scratches.obtain();
-        LDRH(AL, cf, parts.covPtr.reg, immed8_post(2));
-        if (fragment.h > 31) {
-            fragment.h--;
-            SMULWB(AL, fragment.reg, incoming.reg, cf);
-        } else {
-            MOV(AL, 0, fragment.reg, reg_imm(incoming.reg, LSL, 1));
-            SMULWB(AL, fragment.reg, fragment.reg, cf);
-        }
-    }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_alpha_test(component_t& fragment,
-                                    const fragment_parts_t& /*parts*/)
-{
-    if (mAlphaTest != GGL_ALWAYS) {
-        comment("Alpha Test");
-        Scratch scratches(registerFile());
-        int ref = scratches.obtain();
-        const int shift = GGL_COLOR_BITS-fragment.size();
-        CONTEXT_LOAD(ref, state.alpha_test.ref);
-        if (shift) CMP(AL, fragment.reg, reg_imm(ref, LSR, shift));
-        else       CMP(AL, fragment.reg, ref);
-        int cc = NV;
-        switch (mAlphaTest) {
-        case GGL_NEVER:     cc = NV;    break;
-        case GGL_LESS:      cc = LT;    break;
-        case GGL_EQUAL:     cc = EQ;    break;
-        case GGL_LEQUAL:    cc = LS;    break;
-        case GGL_GREATER:   cc = HI;    break;
-        case GGL_NOTEQUAL:  cc = NE;    break;
-        case GGL_GEQUAL:    cc = HS;    break;
-        }
-        B(cc^1, "discard_after_textures");
-    }
-}
-
-// ---------------------------------------------------------------------------
-            
-void GGLAssembler::build_depth_test(
-        const fragment_parts_t& parts, uint32_t mask)
-{
-    mask &= Z_TEST|Z_WRITE;
-    const needs_t& needs = mBuilderContext.needs;
-    const int zmask = GGL_READ_NEEDS(P_MASK_Z, needs.p);
-    Scratch scratches(registerFile());
-
-    if (mDepthTest != GGL_ALWAYS || zmask) {
-        int cc=AL, ic=AL;
-        switch (mDepthTest) {
-        case GGL_LESS:      ic = HI;    break;
-        case GGL_EQUAL:     ic = EQ;    break;
-        case GGL_LEQUAL:    ic = HS;    break;
-        case GGL_GREATER:   ic = LT;    break;
-        case GGL_NOTEQUAL:  ic = NE;    break;
-        case GGL_GEQUAL:    ic = LS;    break;
-        case GGL_NEVER:
-            // this never happens, because it's taken care of when 
-            // computing the needs. but we keep it for completness.
-            comment("Depth Test (NEVER)");
-            B(AL, "discard_before_textures");
-            return;
-        case GGL_ALWAYS:
-            // we're here because zmask is enabled
-            mask &= ~Z_TEST;    // test always passes.
-            break;
-        }
-        
-        // inverse the condition
-        cc = ic^1;
-        
-        if ((mask & Z_WRITE) && !zmask) {
-            mask &= ~Z_WRITE;
-        }
-        
-        if (!mask)
-            return;
-
-        comment("Depth Test");
-
-        int zbase = scratches.obtain();
-        int depth = scratches.obtain();
-        int z = parts.z.reg;
-        
-        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) {
-            LDRH(AL, depth, zbase);  // stall
-            CMP(AL, depth, reg_imm(z, LSR, 16));
-            B(cc, "discard_before_textures");
-        }
-        if (mask & Z_WRITE) {
-            if (mask == Z_WRITE) {
-                // only z-write asked, cc is meaningless
-                ic = AL;
-            }
-            MOV(AL, 0, depth, reg_imm(z, LSR, 16));
-            STRH(ic, depth, zbase);
-        }
-    }
-}
-
-void GGLAssembler::build_iterate_z(const fragment_parts_t& parts)
-{
-    const needs_t& needs = mBuilderContext.needs;
-    if ((mDepthTest != GGL_ALWAYS) || GGL_READ_NEEDS(P_MASK_Z, needs.p)) {
-        Scratch scratches(registerFile());
-        int dzdx = scratches.obtain();
-        CONTEXT_LOAD(dzdx, generated_vars.dzdx);    // stall
-        ADD(AL, 0, parts.z.reg, parts.z.reg, dzdx); 
-    }
-}
-
-void GGLAssembler::build_iterate_f(const fragment_parts_t& /*parts*/)
-{
-    const needs_t& needs = mBuilderContext.needs;
-    if (GGL_READ_NEEDS(P_FOG, needs.p)) {
-        Scratch scratches(registerFile());
-        int dfdx = scratches.obtain();
-        int f = scratches.obtain();
-        CONTEXT_LOAD(f,     generated_vars.f);
-        CONTEXT_LOAD(dfdx,  generated_vars.dfdx);   // stall
-        ADD(AL, 0, f, f, dfdx);
-        CONTEXT_STORE(f,    generated_vars.f);
-    }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_logic_op(pixel_t& pixel, Scratch& regs)
-{
-    const needs_t& needs = mBuilderContext.needs;
-    const int opcode = GGL_READ_NEEDS(LOGIC_OP, needs.n) | GGL_CLEAR;
-    if (opcode == GGL_COPY)
-        return;
-    
-    comment("logic operation");
-
-    pixel_t s(pixel);
-    if (!(pixel.flags & CORRUPTIBLE)) {
-        pixel.reg = regs.obtain();
-        pixel.flags |= CORRUPTIBLE;
-    }
-    
-    pixel_t d(mDstPixel);
-    switch(opcode) {
-    case GGL_CLEAR:         MOV(AL, 0, pixel.reg, imm(0));          break;
-    case GGL_AND:           AND(AL, 0, pixel.reg, s.reg, d.reg);    break;
-    case GGL_AND_REVERSE:   BIC(AL, 0, pixel.reg, s.reg, d.reg);    break;
-    case GGL_COPY:                                                  break;
-    case GGL_AND_INVERTED:  BIC(AL, 0, pixel.reg, d.reg, s.reg);    break;
-    case GGL_NOOP:          MOV(AL, 0, pixel.reg, d.reg);           break;
-    case GGL_XOR:           EOR(AL, 0, pixel.reg, s.reg, d.reg);    break;
-    case GGL_OR:            ORR(AL, 0, pixel.reg, s.reg, d.reg);    break;
-    case GGL_NOR:           ORR(AL, 0, pixel.reg, s.reg, d.reg);
-                            MVN(AL, 0, pixel.reg, pixel.reg);       break;
-    case GGL_EQUIV:         EOR(AL, 0, pixel.reg, s.reg, d.reg);
-                            MVN(AL, 0, pixel.reg, pixel.reg);       break;
-    case GGL_INVERT:        MVN(AL, 0, pixel.reg, d.reg);           break;
-    case GGL_OR_REVERSE:    // s | ~d == ~(~s & d)
-                            BIC(AL, 0, pixel.reg, d.reg, s.reg);
-                            MVN(AL, 0, pixel.reg, pixel.reg);       break;
-    case GGL_COPY_INVERTED: MVN(AL, 0, pixel.reg, s.reg);           break;
-    case GGL_OR_INVERTED:   // ~s | d == ~(s & ~d)
-                            BIC(AL, 0, pixel.reg, s.reg, d.reg);
-                            MVN(AL, 0, pixel.reg, pixel.reg);       break;
-    case GGL_NAND:          AND(AL, 0, pixel.reg, s.reg, d.reg);
-                            MVN(AL, 0, pixel.reg, pixel.reg);       break;
-    case GGL_SET:           MVN(AL, 0, pixel.reg, imm(0));          break;
-    };        
-}
-
-// ---------------------------------------------------------------------------
-
-static uint32_t find_bottom(uint32_t val)
-{
-    uint32_t i = 0;
-    while (!(val & (3<<i)))
-        i+= 2;
-    return i;
-}
-
-static void normalize(uint32_t& val, uint32_t& rot)
-{
-    rot = 0;
-    while (!(val&3)  || (val & 0xFC000000)) {
-        uint32_t newval;
-        newval = val >> 2;
-        newval |= (val&3) << 30;
-        val = newval;
-        rot += 2;
-        if (rot == 32) {
-            rot = 0;
-            break;
-        }
-    }
-}
-
-void GGLAssembler::build_and_immediate(int d, int s, uint32_t mask, int bits)
-{
-    uint32_t rot;
-    uint32_t size = ((bits>=32) ? 0 : (1LU << bits)) - 1;
-    mask &= size;
-
-    if (mask == size) {
-        if (d != s)
-            MOV( AL, 0, d, s);
-        return;
-    }
-    
-    if ((getCodegenArch() == CODEGEN_ARCH_MIPS) ||
-        (getCodegenArch() == CODEGEN_ARCH_MIPS64)) {
-        // MIPS can do 16-bit imm in 1 instr, 32-bit in 3 instr
-        // the below ' while (mask)' code is buggy on mips
-        // since mips returns true on isValidImmediate()
-        // then we get multiple AND instr (positive logic)
-        AND( AL, 0, d, s, imm(mask) );
-        return;
-    }
-    else if (getCodegenArch() == CODEGEN_ARCH_ARM64) {
-        AND( AL, 0, d, s, imm(mask) );
-        return;
-    }
-
-    int negative_logic = !isValidImmediate(mask);
-    if (negative_logic) {
-        mask = ~mask & size;
-    }
-    normalize(mask, rot);
-
-    if (mask) {
-        while (mask) {
-            uint32_t bitpos = find_bottom(mask);
-            int shift = rot + bitpos;
-            uint32_t m = mask & (0xff << bitpos);
-            mask &= ~m;
-            m >>= bitpos;
-            int32_t newMask =  (m<<shift) | (m>>(32-shift));
-            if (!negative_logic) {
-                AND( AL, 0, d, s, imm(newMask) );
-            } else {
-                BIC( AL, 0, d, s, imm(newMask) );
-            }
-            s = d;
-        }
-    } else {
-        MOV( AL, 0, d, imm(0));
-    }
-}		
-
-void GGLAssembler::build_masking(pixel_t& pixel, Scratch& regs)
-{
-    if (!mMasking || mAllMasked) {
-        return;
-    }
-
-    comment("color mask");
-
-    pixel_t fb(mDstPixel);
-    pixel_t s(pixel);
-    if (!(pixel.flags & CORRUPTIBLE)) {
-        pixel.reg = regs.obtain();
-        pixel.flags |= CORRUPTIBLE;
-    }
-
-    int mask = 0;
-    for (int i=0 ; i<4 ; i++) {
-        const int component_mask = 1<<i;
-        const int h = fb.format.c[i].h;
-        const int l = fb.format.c[i].l;
-        if (h && (!(mMasking & component_mask))) {
-            mask |= ((1<<(h-l))-1) << l;
-        }
-    }
-
-    // There is no need to clear the masked components of the source
-    // (unless we applied a logic op), because they're already zeroed 
-    // by construction (masked components are not computed)
-
-    if (mLogicOp) {
-        const needs_t& needs = mBuilderContext.needs;
-        const int opcode = GGL_READ_NEEDS(LOGIC_OP, needs.n) | GGL_CLEAR;
-        if (opcode != GGL_CLEAR) {
-            // clear masked component of source
-            build_and_immediate(pixel.reg, s.reg, mask, fb.size());
-            s = pixel;
-        }
-    }
-
-    // clear non masked components of destination
-    build_and_immediate(fb.reg, fb.reg, ~mask, fb.size()); 
-
-    // or back the channels that were masked
-    if (s.reg == fb.reg) {
-         // this is in fact a MOV
-        if (s.reg == pixel.reg) {
-            // ugh. this in in fact a nop
-        } else {
-            MOV(AL, 0, pixel.reg, fb.reg);
-        }
-    } else {
-        ORR(AL, 0, pixel.reg, s.reg, fb.reg);
-    }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::base_offset(
-        const pointer_t& d, const pointer_t& b, const reg_t& o)
-{
-    switch (b.size) {
-    case 32:
-        ADDR_ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 2));
-        break;
-    case 24:
-        if (d.reg == b.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 {
-            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:
-        ADDR_ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 1));
-        break;
-    case 8:
-        ADDR_ADD(AL, 0, d.reg, b.reg, o.reg);
-        break;
-    }
-}
-
-// ----------------------------------------------------------------------------
-// cheezy register allocator...
-// ----------------------------------------------------------------------------
-
-// Modified to support MIPS processors, in a very simple way. We retain the
-// (Arm) limit of 16 total registers, but shift the mapping of those registers
-// from 0-15, to 2-17. Register 0 on Mips cannot be used as GP registers, and
-// register 1 has a traditional use as a temp).
-
-RegisterAllocator::RegisterAllocator(int arch) : mRegs(arch)
-{
-}
-
-void RegisterAllocator::reset()
-{
-    mRegs.reset();
-}
-
-int RegisterAllocator::reserveReg(int reg)
-{
-    return mRegs.reserve(reg);
-}
-
-int RegisterAllocator::obtainReg()
-{
-    return mRegs.obtain();
-}
-
-void RegisterAllocator::recycleReg(int reg)
-{
-    mRegs.recycle(reg);
-}
-
-RegisterAllocator::RegisterFile& RegisterAllocator::registerFile()
-{
-    return mRegs;
-}
-
-// ----------------------------------------------------------------------------
-
-RegisterAllocator::RegisterFile::RegisterFile(int codegen_arch)
-    : mRegs(0), mTouched(0), mStatus(0), mArch(codegen_arch), mRegisterOffset(0)
-{
-    if ((mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) ||
-        (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS64)) {
-        mRegisterOffset = 2;    // ARM has regs 0..15, MIPS offset to 2..17
-    }
-    reserve(ARMAssemblerInterface::SP);
-    reserve(ARMAssemblerInterface::PC);
-}
-
-RegisterAllocator::RegisterFile::RegisterFile(const RegisterFile& rhs, int codegen_arch)
-    : mRegs(rhs.mRegs), mTouched(rhs.mTouched), mArch(codegen_arch), mRegisterOffset(0)
-{
-    if ((mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) ||
-        (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS64)) {
-        mRegisterOffset = 2;    // ARM has regs 0..15, MIPS offset to 2..17
-    }
-}
-
-RegisterAllocator::RegisterFile::~RegisterFile()
-{
-}
-
-bool RegisterAllocator::RegisterFile::operator == (const RegisterFile& rhs) const
-{
-    return (mRegs == rhs.mRegs);
-}
-
-void RegisterAllocator::RegisterFile::reset()
-{
-    mRegs = mTouched = mStatus = 0;
-    reserve(ARMAssemblerInterface::SP);
-    reserve(ARMAssemblerInterface::PC);
-}
-
-// RegisterFile::reserve() take a register parameter in the
-// range 0-15 (Arm compatible), but on a Mips processor, will
-// return the actual allocated register in the range 2-17.
-int RegisterAllocator::RegisterFile::reserve(int reg)
-{
-    reg += mRegisterOffset;
-    LOG_ALWAYS_FATAL_IF(isUsed(reg),
-                        "reserving register %d, but already in use",
-                        reg);
-    mRegs |= (1<<reg);
-    mTouched |= mRegs;
-    return reg;
-}
-
-// This interface uses regMask in range 2-17 on MIPS, no translation.
-void RegisterAllocator::RegisterFile::reserveSeveral(uint32_t regMask)
-{
-    mRegs |= regMask;
-    mTouched |= regMask;
-}
-
-int RegisterAllocator::RegisterFile::isUsed(int reg) const
-{
-    LOG_ALWAYS_FATAL_IF(reg>=16+(int)mRegisterOffset, "invalid register %d", reg);
-    return mRegs & (1<<reg);
-}
-
-int RegisterAllocator::RegisterFile::obtain()
-{
-    const char priorityList[14] = {  0,  1, 2, 3, 
-                                    12, 14, 4, 5, 
-                                     6,  7, 8, 9,
-                                    10, 11 };
-    const int nbreg = sizeof(priorityList);
-    int i, r, reg;
-    for (i=0 ; i<nbreg ; i++) {
-        r = priorityList[i];
-        if (!isUsed(r + mRegisterOffset)) {
-            break;
-        }
-    }
-    // this is not an error anymore because, we'll try again with
-    // a lower optimization level.
-    //ALOGE_IF(i >= nbreg, "pixelflinger ran out of registers\n");
-    if (i >= nbreg) {
-        mStatus |= OUT_OF_REGISTERS;
-        // we return SP so we can more easily debug things
-        // the code will never be run anyway.
-        return ARMAssemblerInterface::SP; 
-    }
-    reg = reserve(r);  // Param in Arm range 0-15, returns range 2-17 on Mips.
-    return reg;
-}
-
-bool RegisterAllocator::RegisterFile::hasFreeRegs() const
-{
-    uint32_t regs = mRegs >> mRegisterOffset;   // MIPS fix.
-    return ((regs & 0xFFFF) == 0xFFFF) ? false : true;
-}
-
-int RegisterAllocator::RegisterFile::countFreeRegs() const
-{
-    uint32_t regs = mRegs >> mRegisterOffset;   // MIPS fix.
-    int f = ~regs & 0xFFFF;
-    // now count number of 1
-   f = (f & 0x5555) + ((f>>1) & 0x5555);
-   f = (f & 0x3333) + ((f>>2) & 0x3333);
-   f = (f & 0x0F0F) + ((f>>4) & 0x0F0F);
-   f = (f & 0x00FF) + ((f>>8) & 0x00FF);
-   return f;
-}
-
-void RegisterAllocator::RegisterFile::recycle(int reg)
-{
-    // commented out, since common failure of running out of regs
-    // triggers this assertion. Since the code is not execectued
-    // in that case, it does not matter. No reason to FATAL err.
-    // LOG_FATAL_IF(!isUsed(reg),
-    //         "recycling unallocated register %d",
-    //         reg);
-    mRegs &= ~(1<<reg);
-}
-
-void RegisterAllocator::RegisterFile::recycleSeveral(uint32_t regMask)
-{
-    // commented out, since common failure of running out of regs
-    // triggers this assertion. Since the code is not execectued
-    // in that case, it does not matter. No reason to FATAL err.
-    // LOG_FATAL_IF((mRegs & regMask)!=regMask,
-    //         "recycling unallocated registers "
-    //         "(recycle=%08x, allocated=%08x, unallocated=%08x)",
-    //         regMask, mRegs, mRegs&regMask);
-    mRegs &= ~regMask;
-}
-
-uint32_t RegisterAllocator::RegisterFile::touched() const
-{
-    return mTouched;
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
diff --git a/libpixelflinger/codeflinger/GGLAssembler.h b/libpixelflinger/codeflinger/GGLAssembler.h
deleted file mode 100644
index 47dbf3a..0000000
--- a/libpixelflinger/codeflinger/GGLAssembler.h
+++ /dev/null
@@ -1,572 +0,0 @@
-/* libs/pixelflinger/codeflinger/GGLAssembler.h
-**
-** Copyright 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 ANDROID_GGLASSEMBLER_H
-#define ANDROID_GGLASSEMBLER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <private/pixelflinger/ggl_context.h>
-
-#include "ARMAssemblerProxy.h"
-
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-#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)))
-
-#define CONTEXT_STORE(REG, FIELD) \
-    STR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
-
-
-class RegisterAllocator
-{
-public:
-    class RegisterFile;
-    
-                    RegisterAllocator(int arch);  // NOLINT, implicit
-    RegisterFile&   registerFile();
-    int             reserveReg(int reg);
-    int             obtainReg();
-    void            recycleReg(int reg);
-    void            reset();
-
-    class RegisterFile
-    {
-    public:
-                            RegisterFile(int arch);  // NOLINT, implicit
-                            RegisterFile(const RegisterFile& rhs, int arch);
-                            ~RegisterFile();
-
-                void        reset();
-
-                bool operator == (const RegisterFile& rhs) const;
-                bool operator != (const RegisterFile& rhs) const {
-                    return !operator == (rhs);
-                }
-
-                int         reserve(int reg);
-                void        reserveSeveral(uint32_t regMask);
-
-                void        recycle(int reg);
-                void        recycleSeveral(uint32_t regMask);
-
-                int         obtain();
-        inline  int         isUsed(int reg) const;
-
-                bool        hasFreeRegs() const;
-                int         countFreeRegs() const;                
-
-                uint32_t    touched() const;
-        inline  uint32_t    status() const { return mStatus; }
-        
-        enum {
-            OUT_OF_REGISTERS = 0x1
-        };
-
-    private:
-        uint32_t    mRegs;
-        uint32_t    mTouched;
-        uint32_t    mStatus;
-        int         mArch;
-        uint32_t    mRegisterOffset;    // lets reg alloc use 2..17 for mips
-                                        // while arm uses 0..15
-    };
- 
-    class Scratch
-    {
-    public:
-            explicit Scratch(RegisterFile& regFile)
-                : mRegFile(regFile), mScratch(0) { 
-            }
-            ~Scratch() {
-                mRegFile.recycleSeveral(mScratch);
-            }
-        int obtain() { 
-            int reg = mRegFile.obtain();
-            mScratch |= 1<<reg;
-            return reg;
-        }
-        void recycle(int reg) {
-            mRegFile.recycle(reg);
-            mScratch &= ~(1<<reg);
-        }
-        bool isUsed(int reg) {
-            return (mScratch & (1<<reg));
-        }
-        int countFreeRegs() {
-            return mRegFile.countFreeRegs();
-        }
-    private:
-        RegisterFile&   mRegFile;
-        uint32_t        mScratch;
-    };
-
-    class Spill
-    {
-    public:
-        Spill(RegisterFile& regFile, ARMAssemblerInterface& gen, uint32_t reglist)
-            : mRegFile(regFile), mGen(gen), mRegList(reglist), mCount(0)
-        {
-            if (reglist) {
-                int count = 0;
-                while (reglist) {
-                    count++;
-                    reglist &= ~(1 << (31 - __builtin_clz(reglist)));
-                }
-                if (count == 1) {
-                    int reg = 31 - __builtin_clz(mRegList);
-                    mGen.STR(mGen.AL, reg, mGen.SP, mGen.immed12_pre(-4, 1));
-                } else {
-                    mGen.STM(mGen.AL, mGen.DB, mGen.SP, 1, mRegList);
-                }
-                mRegFile.recycleSeveral(mRegList);
-                mCount = count;
-            }
-        }
-        ~Spill() {
-            if (mRegList) {
-                if (mCount == 1) {
-                    int reg = 31 - __builtin_clz(mRegList);
-                    mGen.LDR(mGen.AL, reg, mGen.SP, mGen.immed12_post(4));
-                } else {
-                    mGen.LDM(mGen.AL, mGen.IA, mGen.SP, 1, mRegList);
-                }
-                mRegFile.reserveSeveral(mRegList);
-            }
-        }
-    private:
-        RegisterFile&           mRegFile;
-        ARMAssemblerInterface&  mGen;
-        uint32_t                mRegList;
-        int                     mCount;
-    };
-    
-private:
-    RegisterFile    mRegs;
-};
-
-// ----------------------------------------------------------------------------
-
-class GGLAssembler : public ARMAssemblerProxy, public RegisterAllocator
-{
-public:
-
-    explicit    GGLAssembler(ARMAssemblerInterface* target);
-    virtual     ~GGLAssembler();
-
-    uint32_t*   base() const { return 0; } // XXX
-    uint32_t*   pc() const { return 0; } // XXX
-
-    void        reset(int opt_level);
-
-    virtual void    prolog();
-    virtual void    epilog(uint32_t touched);
-
-        // generate scanline code for given needs
-    int         scanline(const needs_t& needs, context_t const* c);
-    int         scanline_core(const needs_t& needs, context_t const* c);
-
-        enum {
-            CLEAR_LO    = 0x0001,
-            CLEAR_HI    = 0x0002,
-            CORRUPTIBLE = 0x0004,
-            FIRST       = 0x0008
-        };
-
-        enum { //load/store flags
-            WRITE_BACK  = 0x0001
-        };
-
-        struct reg_t {
-            reg_t() : reg(-1), flags(0) {
-            }
-            reg_t(int r, int f=0)  // NOLINT, implicit
-                : reg(r), flags(f) {
-            }
-            void setTo(int r, int f=0) {
-                reg=r; flags=f;
-            }
-            int         reg;
-            uint16_t    flags;
-        };
-
-        struct integer_t : public reg_t {
-            integer_t() : reg_t(), s(0) {
-            }
-            integer_t(int r, int sz=32, int f=0)  // NOLINT, implicit
-                : reg_t(r, f), s(sz) {
-            }
-            void setTo(int r, int sz=32, int f=0) {
-                reg_t::setTo(r, f); s=sz;
-            }
-            int8_t s;
-            inline int size() const { return s; }
-        };
-        
-        struct pixel_t : public reg_t {
-            pixel_t() : reg_t() {
-                memset(&format, 0, sizeof(GGLFormat));
-            }
-            pixel_t(int r, const GGLFormat* fmt, int f=0)
-                : reg_t(r, f), format(*fmt) {
-            }
-            void setTo(int r, const GGLFormat* fmt, int f=0) {
-                reg_t::setTo(r, f); format = *fmt;
-            }
-            GGLFormat format;
-            inline int hi(int c) const { return format.c[c].h; }
-            inline int low(int c) const { return format.c[c].l; }
-            inline int mask(int c) const { return ((1<<size(c))-1) << low(c); }
-            inline int size() const { return format.size*8; }
-            inline int size(int c) const { return component_size(c); }
-            inline int component_size(int c) const { return hi(c) - low(c); }
-        };
-
-        struct component_t : public reg_t {
-            component_t() : reg_t(), h(0), l(0) {
-            }
-            component_t(int r, int f=0)  // NOLINT, implicit
-                : reg_t(r, f), h(0), l(0) {
-            }
-            component_t(int r, int lo, int hi, int f=0)
-                : reg_t(r, f), h(hi), l(lo) {
-            }
-            explicit component_t(const integer_t& rhs)
-                : reg_t(rhs.reg, rhs.flags), h(rhs.s), l(0) {
-            }
-            explicit component_t(const pixel_t& rhs, int component) {
-                setTo(  rhs.reg, 
-                        rhs.format.c[component].l,
-                        rhs.format.c[component].h,
-                        rhs.flags|CLEAR_LO|CLEAR_HI);
-            }
-            void setTo(int r, int lo=0, int hi=0, int f=0) {
-                reg_t::setTo(r, f); h=hi; l=lo;
-            }
-            int8_t h;
-            int8_t l;
-            inline int size() const { return h-l; }
-        };
-
-        struct pointer_t : public reg_t {
-            pointer_t() : reg_t(), size(0) {
-            }
-            pointer_t(int r, int s, int f=0)
-                : reg_t(r, f), size(s) {
-            }
-            void setTo(int r, int s, int f=0) {
-                reg_t::setTo(r, f); size=s;
-            }
-            int8_t size;
-        };
-
-
-private:
-    // GGLAssembler hides RegisterAllocator's and ARMAssemblerProxy's reset
-    // methods by providing a reset method with a different parameter set. The
-    // intent of GGLAssembler's reset method is to wrap the inherited reset
-    // methods, so make these methods private in order to prevent direct calls
-    // to these methods from clients.
-    using RegisterAllocator::reset;
-    using ARMAssemblerProxy::reset;
-
-    struct tex_coord_t {
-        reg_t       s;
-        reg_t       t;
-        pointer_t   ptr;
-    };
-
-    struct fragment_parts_t {
-        uint32_t    packed  : 1;
-        uint32_t    reload  : 2;
-        uint32_t    iterated_packed  : 1;
-        pixel_t     iterated;
-        pointer_t   cbPtr;
-        pointer_t   covPtr;
-        reg_t       count;
-        reg_t       argb[4];
-        reg_t       argb_dx[4];
-        reg_t       z;
-        reg_t       dither;
-        pixel_t     texel[GGL_TEXTURE_UNIT_COUNT];
-        tex_coord_t coords[GGL_TEXTURE_UNIT_COUNT];
-    };
-    
-    struct texture_unit_t {
-        int         format_idx;
-        GGLFormat   format;
-        int         bits;
-        int         swrap;
-        int         twrap;
-        int         env;
-        int         pot;
-        int         linear;
-        uint8_t     mask;
-        uint8_t     replaced;
-    };
-
-    struct texture_machine_t {
-        texture_unit_t  tmu[GGL_TEXTURE_UNIT_COUNT];
-        uint8_t         mask;
-        uint8_t         replaced;
-        uint8_t         directTexture;
-        uint8_t         activeUnits;
-    };
-
-    struct component_info_t {
-        bool    masked      : 1;
-        bool    inDest      : 1;
-        bool    needed      : 1;
-        bool    replaced    : 1;
-        bool    iterated    : 1;
-        bool    smooth      : 1;
-        bool    blend       : 1;
-        bool    fog         : 1;
-    };
-
-    struct builder_context_t {
-        context_t const*    c;
-        needs_t             needs;
-        int                 Rctx;
-    };
-
-    template <typename T>
-    void modify(T& r, Scratch& regs)
-    {
-        if (!(r.flags & CORRUPTIBLE)) {
-            r.reg = regs.obtain();
-            r.flags |= CORRUPTIBLE;
-        }
-    }
-
-    // helpers
-    void    base_offset(const pointer_t& d, const pointer_t& b, const reg_t& o);
-
-    // texture environement
-    void    modulate(   component_t& dest,
-                        const component_t& incoming,
-                        const pixel_t& texel, int component);
-
-    void    decal(  component_t& dest,
-                    const component_t& incoming,
-                    const pixel_t& texel, int component);
-
-    void    blend(  component_t& dest,
-                    const component_t& incoming,
-                    const pixel_t& texel, int component, int tmu);
-
-    void    add(  component_t& dest,
-                    const component_t& incoming,
-                    const pixel_t& texel, int component);
-
-    // load/store stuff
-    void    store(const pointer_t& addr, const pixel_t& src, uint32_t flags=0);
-    void    load(const pointer_t& addr, const pixel_t& dest, uint32_t flags=0);
-    void    extract(integer_t& d, const pixel_t& s, int component);    
-    void    extract(component_t& d, const pixel_t& s, int component);    
-    void    extract(integer_t& d, int s, int h, int l, int bits=32);
-    void    expand(integer_t& d, const integer_t& s, int dbits);
-    void    expand(integer_t& d, const component_t& s, int dbits);
-    void    expand(component_t& d, const component_t& s, int dbits);
-    void    downshift(pixel_t& d, int component, component_t s, const reg_t& dither);
-
-
-    void    mul_factor( component_t& d,
-                        const integer_t& v,
-                        const integer_t& f);
-
-    void    mul_factor_add( component_t& d,
-                            const integer_t& v,
-                            const integer_t& f,
-                            const component_t& a);
-
-    void    component_add(  component_t& d,
-                            const integer_t& dst,
-                            const integer_t& src);
-
-    void    component_sat(  const component_t& v);
-
-
-    void    build_scanline_prolog(  fragment_parts_t& parts,
-                                    const needs_t& needs);
-
-    void    build_smooth_shade(const fragment_parts_t& parts);
-
-    void    build_component(    pixel_t& pixel,
-                                const fragment_parts_t& parts,
-                                int component,
-                                Scratch& global_scratches);
-                                
-    void    build_incoming_component(
-                                component_t& temp,
-                                int dst_size,
-                                const fragment_parts_t& parts,
-                                int component,
-                                Scratch& scratches,
-                                Scratch& global_scratches);
-
-    void    init_iterated_color(fragment_parts_t& parts, const reg_t& x);
-
-    void    build_iterated_color(   component_t& fragment,
-                                    const fragment_parts_t& parts,
-                                    int component,
-                                    Scratch& regs);
-
-    void    decodeLogicOpNeeds(const needs_t& needs);
-    
-    void    decodeTMUNeeds(const needs_t& needs, context_t const* c);
-
-    void    init_textures(  tex_coord_t* coords,
-                            const reg_t& x,
-                            const reg_t& y);
-
-    void    build_textures( fragment_parts_t& parts,
-                            Scratch& regs);
-
-    void    filter8(   const fragment_parts_t& parts,
-                        pixel_t& texel, const texture_unit_t& tmu,
-                        int U, int V, pointer_t& txPtr,
-                        int FRAC_BITS);
-
-    void    filter16(   const fragment_parts_t& parts,
-                        pixel_t& texel, const texture_unit_t& tmu,
-                        int U, int V, pointer_t& txPtr,
-                        int FRAC_BITS);
-
-    void    filter24(   const fragment_parts_t& parts,
-                        pixel_t& texel, const texture_unit_t& tmu,
-                        int U, int V, pointer_t& txPtr,
-                        int FRAC_BITS);
-
-    void    filter32(   const fragment_parts_t& parts,
-                        pixel_t& texel, const texture_unit_t& tmu,
-                        int U, int V, pointer_t& txPtr,
-                        int FRAC_BITS);
-
-    void    build_texture_environment(  component_t& fragment,
-                                        const fragment_parts_t& parts,
-                                        int component,
-                                        Scratch& regs);
-
-    void    wrapping(   int d,
-                        int coord, int size,
-                        int tx_wrap, int tx_linear);
-
-    void    build_fog(  component_t& temp,
-                        int component,
-                        Scratch& parent_scratches);
-
-    void    build_blending(     component_t& in_out,
-                                const pixel_t& pixel,
-                                int component,
-                                Scratch& parent_scratches);
-
-    void    build_blend_factor(
-                integer_t& factor, int f, int component,
-                const pixel_t& dst_pixel,
-                integer_t& fragment,
-                integer_t& fb,
-                Scratch& scratches);
-
-    void    build_blendFOneMinusF(  component_t& temp,
-                                    const integer_t& factor, 
-                                    const integer_t& fragment,
-                                    const integer_t& fb);
-
-    void    build_blendOneMinusFF(  component_t& temp,
-                                    const integer_t& factor, 
-                                    const integer_t& fragment,
-                                    const integer_t& fb);
-
-    void build_coverage_application(component_t& fragment,
-                                    const fragment_parts_t& parts,
-                                    Scratch& regs);
-
-    void build_alpha_test(component_t& fragment, const fragment_parts_t& parts);
-
-    enum { Z_TEST=1, Z_WRITE=2 }; 
-    void build_depth_test(const fragment_parts_t& parts, uint32_t mask);
-    void build_iterate_z(const fragment_parts_t& parts);
-    void build_iterate_f(const fragment_parts_t& parts);
-    void build_iterate_texture_coordinates(const fragment_parts_t& parts);
-
-    void build_logic_op(pixel_t& pixel, Scratch& regs);
-
-    void build_masking(pixel_t& pixel, Scratch& regs);
-
-    void build_and_immediate(int d, int s, uint32_t mask, int bits);
-
-    bool    isAlphaSourceNeeded() const;
-
-    enum {
-        FACTOR_SRC=1, FACTOR_DST=2, BLEND_SRC=4, BLEND_DST=8 
-    };
-    
-    enum {
-        LOGIC_OP=1, LOGIC_OP_SRC=2, LOGIC_OP_DST=4
-    };
-
-    static int blending_codes(int fs, int fd);
-
-    builder_context_t   mBuilderContext;
-    texture_machine_t   mTextureMachine;
-    component_info_t    mInfo[4];
-    int                 mBlending;
-    int                 mMasking;
-    int                 mAllMasked;
-    int                 mLogicOp;
-    int                 mAlphaTest;
-    int                 mAA;
-    int                 mDithering;
-    int                 mDepthTest;
-
-    int             mSmooth;
-    int             mFog;
-    pixel_t         mDstPixel;
-    
-    GGLFormat       mCbFormat;
-    
-    int             mBlendFactorCached;
-    integer_t       mAlphaSource;
-    
-    int             mBaseRegister;
-    
-    int             mBlendSrc;
-    int             mBlendDst;
-    int             mBlendSrcA;
-    int             mBlendDstA;
-    
-    int             mOptLevel;
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GGLASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.cpp b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
deleted file mode 100644
index d6d2156..0000000
--- a/libpixelflinger/codeflinger/MIPS64Assembler.cpp
+++ /dev/null
@@ -1,1447 +0,0 @@
-/* libs/pixelflinger/codeflinger/MIPS64Assembler.cpp
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-
-/* MIPS64 assembler and ARM->MIPS64 assembly translator
-**
-** The approach is utilize MIPSAssembler generator, using inherited MIPS64Assembler
-** that overrides just the specific MIPS64r6 instructions.
-** For now ArmToMips64Assembler is copied over from ArmToMipsAssembler class,
-** changing some MIPS64r6 related stuff.
-**
-*/
-
-#define LOG_TAG "MIPS64Assembler"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <cutils/properties.h>
-#include <log/log.h>
-#include <private/pixelflinger/ggl_context.h>
-
-#include "MIPS64Assembler.h"
-#include "CodeCache.h"
-#include "mips64_disassem.h"
-
-#define NOT_IMPLEMENTED()  LOG_ALWAYS_FATAL("Arm instruction %s not yet implemented\n", __func__)
-#define __unused __attribute__((__unused__))
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark ArmToMips64Assembler...
-#endif
-
-ArmToMips64Assembler::ArmToMips64Assembler(const sp<Assembly>& assembly,
-                                           char *abuf, int linesz, int instr_count)
-    :   ARMAssemblerInterface(),
-        mArmDisassemblyBuffer(abuf),
-        mArmLineLength(linesz),
-        mArmInstrCount(instr_count),
-        mInum(0),
-        mAssembly(assembly)
-{
-    mMips = new MIPS64Assembler(assembly, this);
-    mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *));
-    init_conditional_labels();
-}
-
-ArmToMips64Assembler::ArmToMips64Assembler(void* assembly)
-    :   ARMAssemblerInterface(),
-        mArmDisassemblyBuffer(NULL),
-        mInum(0),
-        mAssembly(NULL)
-{
-    mMips = new MIPS64Assembler(assembly, this);
-    mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *));
-    init_conditional_labels();
-}
-
-ArmToMips64Assembler::~ArmToMips64Assembler()
-{
-    delete mMips;
-    free((void *) mArmPC);
-}
-
-uint32_t* ArmToMips64Assembler::pc() const
-{
-    return mMips->pc();
-}
-
-uint32_t* ArmToMips64Assembler::base() const
-{
-    return mMips->base();
-}
-
-void ArmToMips64Assembler::reset()
-{
-    cond.labelnum = 0;
-    mInum = 0;
-    mMips->reset();
-}
-
-int ArmToMips64Assembler::getCodegenArch()
-{
-    return CODEGEN_ARCH_MIPS64;
-}
-
-void ArmToMips64Assembler::comment(const char* string)
-{
-    mMips->comment(string);
-}
-
-void ArmToMips64Assembler::label(const char* theLabel)
-{
-    mMips->label(theLabel);
-}
-
-void ArmToMips64Assembler::disassemble(const char* name)
-{
-    mMips->disassemble(name);
-}
-
-void ArmToMips64Assembler::init_conditional_labels()
-{
-    int i;
-    for (i=0;i<99; ++i) {
-        sprintf(cond.label[i], "cond_%d", i);
-    }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Prolog/Epilog & Generate...
-#endif
-
-void ArmToMips64Assembler::prolog()
-{
-    mArmPC[mInum++] = pc();  // save starting PC for this instr
-
-    mMips->DADDIU(R_sp, R_sp, -(5 * 8));
-    mMips->SD(R_s0, R_sp, 0);
-    mMips->SD(R_s1, R_sp, 8);
-    mMips->SD(R_s2, R_sp, 16);
-    mMips->SD(R_s3, R_sp, 24);
-    mMips->SD(R_s4, R_sp, 32);
-    mMips->MOVE(R_v0, R_a0);    // move context * passed in a0 to v0 (arm r0)
-}
-
-void ArmToMips64Assembler::epilog(uint32_t touched __unused)
-{
-    mArmPC[mInum++] = pc();  // save starting PC for this instr
-
-    mMips->LD(R_s0, R_sp, 0);
-    mMips->LD(R_s1, R_sp, 8);
-    mMips->LD(R_s2, R_sp, 16);
-    mMips->LD(R_s3, R_sp, 24);
-    mMips->LD(R_s4, R_sp, 32);
-    mMips->DADDIU(R_sp, R_sp, (5 * 8));
-    mMips->JR(R_ra);
-
-}
-
-int ArmToMips64Assembler::generate(const char* name)
-{
-    return mMips->generate(name);
-}
-
-void ArmToMips64Assembler::fix_branches()
-{
-    mMips->fix_branches();
-}
-
-uint32_t* ArmToMips64Assembler::pcForLabel(const char* label)
-{
-    return mMips->pcForLabel(label);
-}
-
-void ArmToMips64Assembler::set_condition(int mode, int R1, int R2) {
-    if (mode == 2) {
-        cond.type = SBIT_COND;
-    } else {
-        cond.type = CMP_COND;
-    }
-    cond.r1 = R1;
-    cond.r2 = R2;
-}
-
-//----------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Addressing modes & shifters...
-#endif
-
-
-// do not need this for MIPS, but it is in the Interface (virtual)
-int ArmToMips64Assembler::buildImmediate(
-        uint32_t immediate, uint32_t& rot, uint32_t& imm)
-{
-    // for MIPS, any 32-bit immediate is OK
-    rot = 0;
-    imm = immediate;
-    return 0;
-}
-
-// shifters...
-
-bool ArmToMips64Assembler::isValidImmediate(uint32_t immediate __unused)
-{
-    // for MIPS, any 32-bit immediate is OK
-    return true;
-}
-
-uint32_t ArmToMips64Assembler::imm(uint32_t immediate)
-{
-    amode.value = immediate;
-    return AMODE_IMM;
-}
-
-uint32_t ArmToMips64Assembler::reg_imm(int Rm, int type, uint32_t shift)
-{
-    amode.reg = Rm;
-    amode.stype = type;
-    amode.value = shift;
-    return AMODE_REG_IMM;
-}
-
-uint32_t ArmToMips64Assembler::reg_rrx(int Rm __unused)
-{
-    // reg_rrx mode is not used in the GLLAssember code at this time
-    return AMODE_UNSUPPORTED;
-}
-
-uint32_t ArmToMips64Assembler::reg_reg(int Rm __unused, int type __unused,
-                                       int Rs __unused)
-{
-    // reg_reg mode is not used in the GLLAssember code at this time
-    return AMODE_UNSUPPORTED;
-}
-
-
-// addressing modes...
-// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
-uint32_t ArmToMips64Assembler::immed12_pre(int32_t immed12, int W)
-{
-    LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
-                        "LDR(B)/STR(B)/PLD immediate too big (%08x)",
-                        immed12);
-    amode.value = immed12;
-    amode.writeback = W;
-    return AMODE_IMM_12_PRE;
-}
-
-uint32_t ArmToMips64Assembler::immed12_post(int32_t immed12)
-{
-    LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
-                        "LDR(B)/STR(B)/PLD immediate too big (%08x)",
-                        immed12);
-
-    amode.value = immed12;
-    return AMODE_IMM_12_POST;
-}
-
-uint32_t ArmToMips64Assembler::reg_scale_pre(int Rm, int type,
-        uint32_t shift, int W)
-{
-    LOG_ALWAYS_FATAL_IF(W | type | shift, "reg_scale_pre adv modes not yet implemented");
-
-    amode.reg = Rm;
-    // amode.stype = type;      // more advanced modes not used in GGLAssembler yet
-    // amode.value = shift;
-    // amode.writeback = W;
-    return AMODE_REG_SCALE_PRE;
-}
-
-uint32_t ArmToMips64Assembler::reg_scale_post(int Rm __unused, int type __unused,
-                                              uint32_t shift __unused)
-{
-    LOG_ALWAYS_FATAL("adr mode reg_scale_post not yet implemented\n");
-    return AMODE_UNSUPPORTED;
-}
-
-// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0)
-uint32_t ArmToMips64Assembler::immed8_pre(int32_t immed8, int W __unused)
-{
-    LOG_ALWAYS_FATAL("adr mode immed8_pre not yet implemented\n");
-
-    LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
-                        "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
-                        immed8);
-    return AMODE_IMM_8_PRE;
-}
-
-uint32_t ArmToMips64Assembler::immed8_post(int32_t immed8)
-{
-    LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
-                        "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
-                        immed8);
-    amode.value = immed8;
-    return AMODE_IMM_8_POST;
-}
-
-uint32_t ArmToMips64Assembler::reg_pre(int Rm, int W)
-{
-    LOG_ALWAYS_FATAL_IF(W, "reg_pre writeback not yet implemented");
-    amode.reg = Rm;
-    return AMODE_REG_PRE;
-}
-
-uint32_t ArmToMips64Assembler::reg_post(int Rm __unused)
-{
-    LOG_ALWAYS_FATAL("adr mode reg_post not yet implemented\n");
-    return AMODE_UNSUPPORTED;
-}
-
-
-
-// ----------------------------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Data Processing...
-#endif
-
-// check if the operand registers from a previous CMP or S-bit instruction
-// would be overwritten by this instruction. If so, move the value to a
-// safe register.
-// Note that we cannot tell at _this_ instruction time if a future (conditional)
-// instruction will _also_ use this value (a defect of the simple 1-pass, one-
-// instruction-at-a-time translation). Therefore we must be conservative and
-// save the value before it is overwritten. This costs an extra MOVE instr.
-
-void ArmToMips64Assembler::protectConditionalOperands(int Rd)
-{
-    if (Rd == cond.r1) {
-        mMips->MOVE(R_cmp, cond.r1);
-        cond.r1 = R_cmp;
-    }
-    if (cond.type == CMP_COND && Rd == cond.r2) {
-        mMips->MOVE(R_cmp2, cond.r2);
-        cond.r2 = R_cmp2;
-    }
-}
-
-
-// interprets the addressing mode, and generates the common code
-// used by the majority of data-processing ops. Many MIPS instructions
-// have a register-based form and a different immediate form. See
-// opAND below for an example. (this could be inlined)
-//
-// this works with the imm(), reg_imm() methods above, which are directly
-// called by the GLLAssembler.
-// note: _signed parameter defaults to false (un-signed)
-// note: tmpReg parameter defaults to 1, MIPS register AT
-int ArmToMips64Assembler::dataProcAdrModes(int op, int& source, bool _signed, int tmpReg)
-{
-    if (op < AMODE_REG) {
-        source = op;
-        return SRC_REG;
-    } else if (op == AMODE_IMM) {
-        if ((!_signed && amode.value > 0xffff)
-                || (_signed && ((int)amode.value < -32768 || (int)amode.value > 32767) )) {
-            mMips->LUI(tmpReg, (amode.value >> 16));
-            if (amode.value & 0x0000ffff) {
-                mMips->ORI(tmpReg, tmpReg, (amode.value & 0x0000ffff));
-            }
-            source = tmpReg;
-            return SRC_REG;
-        } else {
-            source = amode.value;
-            return SRC_IMM;
-        }
-    } else if (op == AMODE_REG_IMM) {
-        switch (amode.stype) {
-            case LSL: mMips->SLL(tmpReg, amode.reg, amode.value); break;
-            case LSR: mMips->SRL(tmpReg, amode.reg, amode.value); break;
-            case ASR: mMips->SRA(tmpReg, amode.reg, amode.value); break;
-            case ROR: mMips->ROTR(tmpReg, amode.reg, amode.value); break;
-        }
-        source = tmpReg;
-        return SRC_REG;
-    } else {  // adr mode RRX is not used in GGL Assembler at this time
-        // we are screwed, this should be exception, assert-fail or something
-        LOG_ALWAYS_FATAL("adr mode reg_rrx not yet implemented\n");
-        return SRC_ERROR;
-    }
-}
-
-
-void ArmToMips64Assembler::dataProcessing(int opcode, int cc,
-        int s, int Rd, int Rn, uint32_t Op2)
-{
-    int src;    // src is modified by dataProcAdrModes() - passed as int&
-
-    if (cc != AL) {
-        protectConditionalOperands(Rd);
-        // the branch tests register(s) set by prev CMP or instr with 'S' bit set
-        // inverse the condition to jump past this conditional instruction
-        ArmToMips64Assembler::B(cc^1, cond.label[++cond.labelnum]);
-    } else {
-        mArmPC[mInum++] = pc();  // save starting PC for this instr
-    }
-
-    switch (opcode) {
-    case opAND:
-        if (dataProcAdrModes(Op2, src) == SRC_REG) {
-            mMips->AND(Rd, Rn, src);
-        } else {                        // adr mode was SRC_IMM
-            mMips->ANDI(Rd, Rn, src);
-        }
-        break;
-
-    case opADD:
-        // set "signed" to true for adr modes
-        if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
-            mMips->ADDU(Rd, Rn, src);
-        } else {                        // adr mode was SRC_IMM
-            mMips->ADDIU(Rd, Rn, src);
-        }
-        break;
-
-    case opSUB:
-        // set "signed" to true for adr modes
-        if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
-            mMips->SUBU(Rd, Rn, src);
-        } else {                        // adr mode was SRC_IMM
-            mMips->SUBIU(Rd, Rn, src);
-        }
-        break;
-
-    case opADD64:
-        // set "signed" to true for adr modes
-        if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
-            mMips->DADDU(Rd, Rn, src);
-        } else {                        // adr mode was SRC_IMM
-            mMips->DADDIU(Rd, Rn, src);
-        }
-        break;
-
-    case opSUB64:
-        // set "signed" to true for adr modes
-        if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
-            mMips->DSUBU(Rd, Rn, src);
-        } else {                        // adr mode was SRC_IMM
-            mMips->DSUBIU(Rd, Rn, src);
-        }
-        break;
-
-    case opEOR:
-        if (dataProcAdrModes(Op2, src) == SRC_REG) {
-            mMips->XOR(Rd, Rn, src);
-        } else {                        // adr mode was SRC_IMM
-            mMips->XORI(Rd, Rn, src);
-        }
-        break;
-
-    case opORR:
-        if (dataProcAdrModes(Op2, src) == SRC_REG) {
-            mMips->OR(Rd, Rn, src);
-        } else {                        // adr mode was SRC_IMM
-            mMips->ORI(Rd, Rn, src);
-        }
-        break;
-
-    case opBIC:
-        if (dataProcAdrModes(Op2, src) == SRC_IMM) {
-            // if we are 16-bit imnmediate, load to AT reg
-            mMips->ORI(R_at, 0, src);
-            src = R_at;
-        }
-        mMips->NOT(R_at, src);
-        mMips->AND(Rd, Rn, R_at);
-        break;
-
-    case opRSB:
-        if (dataProcAdrModes(Op2, src) == SRC_IMM) {
-            // if we are 16-bit imnmediate, load to AT reg
-            mMips->ORI(R_at, 0, src);
-            src = R_at;
-        }
-        mMips->SUBU(Rd, src, Rn);   // subu with the parameters reversed
-        break;
-
-    case opMOV:
-        if (Op2 < AMODE_REG) {  // op2 is reg # in this case
-            mMips->MOVE(Rd, Op2);
-        } else if (Op2 == AMODE_IMM) {
-            if (amode.value > 0xffff) {
-                mMips->LUI(Rd, (amode.value >> 16));
-                if (amode.value & 0x0000ffff) {
-                    mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
-                }
-             } else {
-                mMips->ORI(Rd, 0, amode.value);
-            }
-        } else if (Op2 == AMODE_REG_IMM) {
-            switch (amode.stype) {
-            case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
-            case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
-            case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
-            case ROR: mMips->ROTR(Rd, amode.reg, amode.value); break;
-            }
-        }
-        else {
-            // adr mode RRX is not used in GGL Assembler at this time
-            mMips->UNIMPL();
-        }
-        break;
-
-    case opMVN:     // this is a 1's complement: NOT
-        if (Op2 < AMODE_REG) {  // op2 is reg # in this case
-            mMips->NOR(Rd, Op2, 0);     // NOT is NOR with 0
-            break;
-        } else if (Op2 == AMODE_IMM) {
-            if (amode.value > 0xffff) {
-                mMips->LUI(Rd, (amode.value >> 16));
-                if (amode.value & 0x0000ffff) {
-                    mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
-                }
-             } else {
-                mMips->ORI(Rd, 0, amode.value);
-             }
-        } else if (Op2 == AMODE_REG_IMM) {
-            switch (amode.stype) {
-            case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
-            case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
-            case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
-            case ROR: mMips->ROTR(Rd, amode.reg, amode.value); break;
-            }
-        }
-        else {
-            // adr mode RRX is not used in GGL Assembler at this time
-            mMips->UNIMPL();
-        }
-        mMips->NOR(Rd, Rd, 0);     // NOT is NOR with 0
-        break;
-
-    case opCMP:
-        // Either operand of a CMP instr could get overwritten by a subsequent
-        // conditional instruction, which is ok, _UNLESS_ there is a _second_
-        // conditional instruction. Under MIPS, this requires doing the comparison
-        // again (SLT), and the original operands must be available. (and this
-        // pattern of multiple conditional instructions from same CMP _is_ used
-        // in GGL-Assembler)
-        //
-        // For now, if a conditional instr overwrites the operands, we will
-        // move them to dedicated temp regs. This is ugly, and inefficient,
-        // and should be optimized.
-        //
-        // WARNING: making an _Assumption_ that CMP operand regs will NOT be
-        // trashed by intervening NON-conditional instructions. In the general
-        // case this is legal, but it is NOT currently done in GGL-Assembler.
-
-        cond.type = CMP_COND;
-        cond.r1 = Rn;
-        if (dataProcAdrModes(Op2, src, false, R_cmp2) == SRC_REG) {
-            cond.r2 = src;
-        } else {                        // adr mode was SRC_IMM
-            mMips->ORI(R_cmp2, R_zero, src);
-            cond.r2 = R_cmp2;
-        }
-
-        break;
-
-
-    case opTST:
-    case opTEQ:
-    case opCMN:
-    case opADC:
-    case opSBC:
-    case opRSC:
-        mMips->UNIMPL(); // currently unused in GGL Assembler code
-        break;
-    }
-
-    if (cc != AL) {
-        mMips->label(cond.label[cond.labelnum]);
-    }
-    if (s && opcode != opCMP) {
-        cond.type = SBIT_COND;
-        cond.r1 = Rd;
-    }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Multiply...
-#endif
-
-// multiply, accumulate
-void ArmToMips64Assembler::MLA(int cc __unused, int s,
-        int Rd, int Rm, int Rs, int Rn) {
-
-    //ALOGW("MLA");
-    mArmPC[mInum++] = pc();  // save starting PC for this instr
-
-    mMips->MUL(R_at, Rm, Rs);
-    mMips->ADDU(Rd, R_at, Rn);
-    if (s) {
-        cond.type = SBIT_COND;
-        cond.r1 = Rd;
-    }
-}
-
-void ArmToMips64Assembler::MUL(int cc __unused, int s,
-        int Rd, int Rm, int Rs) {
-    mArmPC[mInum++] = pc();
-    mMips->MUL(Rd, Rm, Rs);
-    if (s) {
-        cond.type = SBIT_COND;
-        cond.r1 = Rd;
-    }
-}
-
-void ArmToMips64Assembler::UMULL(int cc __unused, int s,
-        int RdLo, int RdHi, int Rm, int Rs) {
-    mArmPC[mInum++] = pc();
-    mMips->MUH(RdHi, Rm, Rs);
-    mMips->MUL(RdLo, Rm, Rs);
-
-    if (s) {
-        cond.type = SBIT_COND;
-        cond.r1 = RdHi;     // BUG...
-        LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
-    }
-}
-
-void ArmToMips64Assembler::UMUAL(int cc __unused, int s,
-        int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
-    LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
-                        "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
-    // *mPC++ =    (cc<<28) | (1<<23) | (1<<21) | (s<<20) |
-    //             (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-    if (s) {
-        cond.type = SBIT_COND;
-        cond.r1 = RdHi;     // BUG...
-        LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
-    }
-}
-
-void ArmToMips64Assembler::SMULL(int cc __unused, int s,
-        int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
-    LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
-                        "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
-    // *mPC++ =    (cc<<28) | (1<<23) | (1<<22) | (s<<20) |
-    //             (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-    if (s) {
-        cond.type = SBIT_COND;
-        cond.r1 = RdHi;     // BUG...
-        LOG_ALWAYS_FATAL("Condition on SMULL must be on 64-bit result\n");
-    }
-}
-void ArmToMips64Assembler::SMUAL(int cc __unused, int s,
-        int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
-    LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
-                        "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
-    // *mPC++ =    (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) |
-    //             (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-    if (s) {
-        cond.type = SBIT_COND;
-        cond.r1 = RdHi;     // BUG...
-        LOG_ALWAYS_FATAL("Condition on SMUAL must be on 64-bit result\n");
-    }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Branches...
-#endif
-
-// branches...
-
-void ArmToMips64Assembler::B(int cc, const char* label)
-{
-    mArmPC[mInum++] = pc();
-    if (cond.type == SBIT_COND) { cond.r2 = R_zero; }
-
-    switch(cc) {
-        case EQ: mMips->BEQ(cond.r1, cond.r2, label); break;
-        case NE: mMips->BNE(cond.r1, cond.r2, label); break;
-        case HS: mMips->BGEU(cond.r1, cond.r2, label); break;
-        case LO: mMips->BLTU(cond.r1, cond.r2, label); break;
-        case MI: mMips->BLT(cond.r1, cond.r2, label); break;
-        case PL: mMips->BGE(cond.r1, cond.r2, label); break;
-
-        case HI: mMips->BGTU(cond.r1, cond.r2, label); break;
-        case LS: mMips->BLEU(cond.r1, cond.r2, label); break;
-        case GE: mMips->BGE(cond.r1, cond.r2, label); break;
-        case LT: mMips->BLT(cond.r1, cond.r2, label); break;
-        case GT: mMips->BGT(cond.r1, cond.r2, label); break;
-        case LE: mMips->BLE(cond.r1, cond.r2, label); break;
-        case AL: mMips->B(label); break;
-        case NV: /* B Never - no instruction */ break;
-
-        case VS:
-        case VC:
-        default:
-            LOG_ALWAYS_FATAL("Unsupported cc: %02x\n", cc);
-            break;
-    }
-}
-
-void ArmToMips64Assembler::BL(int cc __unused, const char* label __unused)
-{
-    LOG_ALWAYS_FATAL("branch-and-link not supported yet\n");
-    mArmPC[mInum++] = pc();
-}
-
-// no use for Branches with integer PC, but they're in the Interface class ....
-void ArmToMips64Assembler::B(int cc __unused, uint32_t* to_pc __unused)
-{
-    LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
-    mArmPC[mInum++] = pc();
-}
-
-void ArmToMips64Assembler::BL(int cc __unused, uint32_t* to_pc __unused)
-{
-    LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
-    mArmPC[mInum++] = pc();
-}
-
-void ArmToMips64Assembler::BX(int cc __unused, int Rn __unused)
-{
-    LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
-    mArmPC[mInum++] = pc();
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Data Transfer...
-#endif
-
-// data transfer...
-void ArmToMips64Assembler::LDR(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed12_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            amode.writeback = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_12_PRE:
-            if (Rn == ARMAssemblerInterface::SP) {
-                Rn = R_sp;      // convert LDR via Arm SP to LW via Mips SP
-            }
-            mMips->LW(Rd, Rn, amode.value);
-            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
-                mMips->DADDIU(Rn, Rn, amode.value);
-            }
-            break;
-        case AMODE_IMM_12_POST:
-            if (Rn == ARMAssemblerInterface::SP) {
-                Rn = R_sp;      // convert STR thru Arm SP to STR thru Mips SP
-            }
-            mMips->LW(Rd, Rn, 0);
-            mMips->DADDIU(Rn, Rn, amode.value);
-            break;
-        case AMODE_REG_SCALE_PRE:
-            // we only support simple base + index, no advanced modes for this one yet
-            mMips->DADDU(R_at, Rn, amode.reg);
-            mMips->LW(Rd, R_at, 0);
-            break;
-    }
-}
-
-void ArmToMips64Assembler::LDRB(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed12_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            amode.writeback = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_12_PRE:
-            mMips->LBU(Rd, Rn, amode.value);
-            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
-                mMips->DADDIU(Rn, Rn, amode.value);
-            }
-            break;
-        case AMODE_IMM_12_POST:
-            mMips->LBU(Rd, Rn, 0);
-            mMips->DADDIU(Rn, Rn, amode.value);
-            break;
-        case AMODE_REG_SCALE_PRE:
-            // we only support simple base + index, no advanced modes for this one yet
-            mMips->DADDU(R_at, Rn, amode.reg);
-            mMips->LBU(Rd, R_at, 0);
-            break;
-    }
-
-}
-
-void ArmToMips64Assembler::STR(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed12_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            amode.writeback = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_12_PRE:
-            if (Rn == ARMAssemblerInterface::SP) {
-                Rn = R_sp;  // convert STR thru Arm SP to SW thru Mips SP
-            }
-            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
-                // If we will writeback, then update the index reg, then store.
-                // This correctly handles stack-push case.
-                mMips->DADDIU(Rn, Rn, amode.value);
-                mMips->SW(Rd, Rn, 0);
-            } else {
-                // No writeback so store offset by value
-                mMips->SW(Rd, Rn, amode.value);
-            }
-            break;
-        case AMODE_IMM_12_POST:
-            mMips->SW(Rd, Rn, 0);
-            mMips->DADDIU(Rn, Rn, amode.value);  // post index always writes back
-            break;
-        case AMODE_REG_SCALE_PRE:
-            // we only support simple base + index, no advanced modes for this one yet
-            mMips->DADDU(R_at, Rn, amode.reg);
-            mMips->SW(Rd, R_at, 0);
-            break;
-    }
-}
-
-void ArmToMips64Assembler::STRB(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed12_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            amode.writeback = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_12_PRE:
-            mMips->SB(Rd, Rn, amode.value);
-            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
-                mMips->DADDIU(Rn, Rn, amode.value);
-            }
-            break;
-        case AMODE_IMM_12_POST:
-            mMips->SB(Rd, Rn, 0);
-            mMips->DADDIU(Rn, Rn, amode.value);
-            break;
-        case AMODE_REG_SCALE_PRE:
-            // we only support simple base + index, no advanced modes for this one yet
-            mMips->DADDU(R_at, Rn, amode.reg);
-            mMips->SB(Rd, R_at, 0);
-            break;
-    }
-}
-
-void ArmToMips64Assembler::LDRH(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed8_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_8_PRE:      // no support yet for writeback
-            mMips->LHU(Rd, Rn, amode.value);
-            break;
-        case AMODE_IMM_8_POST:
-            mMips->LHU(Rd, Rn, 0);
-            mMips->DADDIU(Rn, Rn, amode.value);
-            break;
-        case AMODE_REG_PRE:
-            // we only support simple base +/- index
-            if (amode.reg >= 0) {
-                mMips->DADDU(R_at, Rn, amode.reg);
-            } else {
-                mMips->DSUBU(R_at, Rn, abs(amode.reg));
-            }
-            mMips->LHU(Rd, R_at, 0);
-            break;
-    }
-}
-
-void ArmToMips64Assembler::LDRSB(int cc __unused, int Rd __unused,
-                                 int Rn __unused, uint32_t offset __unused)
-{
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::LDRSH(int cc __unused, int Rd __unused,
-                                 int Rn __unused, uint32_t offset __unused)
-{
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::STRH(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed8_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_8_PRE:      // no support yet for writeback
-            mMips->SH(Rd, Rn, amode.value);
-            break;
-        case AMODE_IMM_8_POST:
-            mMips->SH(Rd, Rn, 0);
-            mMips->DADDIU(Rn, Rn, amode.value);
-            break;
-        case AMODE_REG_PRE:
-            // we only support simple base +/- index
-            if (amode.reg >= 0) {
-                mMips->DADDU(R_at, Rn, amode.reg);
-            } else {
-                mMips->DSUBU(R_at, Rn, abs(amode.reg));
-            }
-            mMips->SH(Rd, R_at, 0);
-            break;
-    }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Block Data Transfer...
-#endif
-
-// block data transfer...
-void ArmToMips64Assembler::LDM(int cc __unused, int dir __unused,
-        int Rn __unused, int W __unused, uint32_t reg_list __unused)
-{   //                        ED FD EA FA      IB IA DB DA
-    // const uint8_t P[8] = { 1, 0, 1, 0,      1, 0, 1, 0 };
-    // const uint8_t U[8] = { 1, 1, 0, 0,      1, 1, 0, 0 };
-    // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
-    //         (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::STM(int cc __unused, int dir __unused,
-        int Rn __unused, int W __unused, uint32_t reg_list __unused)
-{   //                        FA EA FD ED      IB IA DB DA
-    // const uint8_t P[8] = { 0, 1, 0, 1,      1, 0, 1, 0 };
-    // const uint8_t U[8] = { 0, 0, 1, 1,      1, 1, 0, 0 };
-    // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
-    //         (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Special...
-#endif
-
-// special...
-void ArmToMips64Assembler::SWP(int cc __unused, int Rn __unused,
-                               int Rd __unused, int Rm __unused) {
-    // *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::SWPB(int cc __unused, int Rn __unused,
-                                int Rd __unused, int Rm __unused) {
-    // *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::SWI(int cc __unused, uint32_t comment __unused) {
-    // *mPC++ = (cc<<28) | (0xF<<24) | comment;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-
-#if 0
-#pragma mark -
-#pragma mark DSP instructions...
-#endif
-
-// DSP instructions...
-void ArmToMips64Assembler::PLD(int Rn __unused, uint32_t offset) {
-    LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))),
-                        "PLD only P=1, W=0");
-    // *mPC++ = 0xF550F000 | (Rn<<16) | offset;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::CLZ(int cc __unused, int Rd, int Rm)
-{
-    mArmPC[mInum++] = pc();
-    mMips->CLZ(Rd, Rm);
-}
-
-void ArmToMips64Assembler::QADD(int cc __unused, int Rd __unused,
-                                int Rm __unused, int Rn __unused)
-{
-    // *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::QDADD(int cc __unused, int Rd __unused,
-                                 int Rm __unused, int Rn __unused)
-{
-    // *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::QSUB(int cc __unused, int Rd __unused,
-                                int Rm __unused, int Rn __unused)
-{
-    // *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::QDSUB(int cc __unused, int Rd __unused,
-                                 int Rm __unused, int Rn __unused)
-{
-    // *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-// 16 x 16 signed multiply (like SMLAxx without the accumulate)
-void ArmToMips64Assembler::SMUL(int cc __unused, int xy,
-                int Rd, int Rm, int Rs)
-{
-    mArmPC[mInum++] = pc();
-
-    // the 16 bits may be in the top or bottom half of 32-bit source reg,
-    // as defined by the codes BB, BT, TB, TT (compressed param xy)
-    // where x corresponds to Rm and y to Rs
-
-    // select half-reg for Rm
-    if (xy & xyTB) {
-        // use top 16-bits
-        mMips->SRA(R_at, Rm, 16);
-    } else {
-        // use bottom 16, but sign-extend to 32
-        mMips->SEH(R_at, Rm);
-    }
-    // select half-reg for Rs
-    if (xy & xyBT) {
-        // use top 16-bits
-        mMips->SRA(R_at2, Rs, 16);
-    } else {
-        // use bottom 16, but sign-extend to 32
-        mMips->SEH(R_at2, Rs);
-    }
-    mMips->MUL(Rd, R_at, R_at2);
-}
-
-// signed 32b x 16b multiple, save top 32-bits of 48-bit result
-void ArmToMips64Assembler::SMULW(int cc __unused, int y,
-                int Rd, int Rm, int Rs)
-{
-    mArmPC[mInum++] = pc();
-
-    // the selector yT or yB refers to reg Rs
-    if (y & yT) {
-        // zero the bottom 16-bits, with 2 shifts, it can affect result
-        mMips->SRL(R_at, Rs, 16);
-        mMips->SLL(R_at, R_at, 16);
-
-    } else {
-        // move low 16-bit half, to high half
-        mMips->SLL(R_at, Rs, 16);
-    }
-    mMips->MUH(Rd, Rm, R_at);
-}
-
-// 16 x 16 signed multiply, accumulate: Rd = Rm{16} * Rs{16} + Rn
-void ArmToMips64Assembler::SMLA(int cc __unused, int xy,
-                int Rd, int Rm, int Rs, int Rn)
-{
-    mArmPC[mInum++] = pc();
-
-    // the 16 bits may be in the top or bottom half of 32-bit source reg,
-    // as defined by the codes BB, BT, TB, TT (compressed param xy)
-    // where x corresponds to Rm and y to Rs
-
-    // select half-reg for Rm
-    if (xy & xyTB) {
-        // use top 16-bits
-        mMips->SRA(R_at, Rm, 16);
-    } else {
-        // use bottom 16, but sign-extend to 32
-        mMips->SEH(R_at, Rm);
-    }
-    // select half-reg for Rs
-    if (xy & xyBT) {
-        // use top 16-bits
-        mMips->SRA(R_at2, Rs, 16);
-    } else {
-        // use bottom 16, but sign-extend to 32
-        mMips->SEH(R_at2, Rs);
-    }
-
-    mMips->MUL(R_at, R_at, R_at2);
-    mMips->ADDU(Rd, R_at, Rn);
-}
-
-void ArmToMips64Assembler::SMLAL(int cc __unused, int xy __unused,
-                                 int RdHi __unused, int RdLo __unused,
-                                 int Rs __unused, int Rm __unused)
-{
-    // *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::SMLAW(int cc __unused, int y __unused,
-                                 int Rd __unused, int Rm __unused,
-                                 int Rs __unused, int Rn __unused)
-{
-    // *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-// used by ARMv6 version of GGLAssembler::filter32
-void ArmToMips64Assembler::UXTB16(int cc __unused, int Rd, int Rm, int rotate)
-{
-    mArmPC[mInum++] = pc();
-
-    //Rd[31:16] := ZeroExtend((Rm ROR (8 * sh))[23:16]),
-    //Rd[15:0] := ZeroExtend((Rm ROR (8 * sh))[7:0]). sh 0-3.
-
-    mMips->ROTR(R_at2, Rm, rotate * 8);
-    mMips->LUI(R_at, 0xFF);
-    mMips->ORI(R_at, R_at, 0xFF);
-    mMips->AND(Rd, R_at2, R_at);
-}
-
-void ArmToMips64Assembler::UBFX(int cc __unused, int Rd __unused, int Rn __unused,
-                                int lsb __unused, int width __unused)
-{
-     /* Placeholder for UBFX */
-     mArmPC[mInum++] = pc();
-
-     mMips->NOP2();
-     NOT_IMPLEMENTED();
-}
-
-// ----------------------------------------------------------------------------
-// Address Processing...
-// ----------------------------------------------------------------------------
-
-void ArmToMips64Assembler::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
-    dataProcessing(opADD64, cc, s, Rd, Rn, Op2);
-}
-
-void ArmToMips64Assembler::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
-    dataProcessing(opSUB64, cc, s, Rd, Rn, Op2);
-}
-
-void ArmToMips64Assembler::ADDR_LDR(int cc __unused, int Rd,
-                                    int Rn, uint32_t offset) {
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed12_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            amode.writeback = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_12_PRE:
-            if (Rn == ARMAssemblerInterface::SP) {
-                Rn = R_sp;      // convert LDR via Arm SP to LW via Mips SP
-            }
-            mMips->LD(Rd, Rn, amode.value);
-            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
-                mMips->DADDIU(Rn, Rn, amode.value);
-            }
-            break;
-        case AMODE_IMM_12_POST:
-            if (Rn == ARMAssemblerInterface::SP) {
-                Rn = R_sp;      // convert STR thru Arm SP to STR thru Mips SP
-            }
-            mMips->LD(Rd, Rn, 0);
-            mMips->DADDIU(Rn, Rn, amode.value);
-            break;
-        case AMODE_REG_SCALE_PRE:
-            // we only support simple base + index, no advanced modes for this one yet
-            mMips->DADDU(R_at, Rn, amode.reg);
-            mMips->LD(Rd, R_at, 0);
-            break;
-    }
-}
-
-void ArmToMips64Assembler::ADDR_STR(int cc __unused, int Rd,
-                                    int Rn, uint32_t offset) {
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed12_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            amode.writeback = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_12_PRE:
-            if (Rn == ARMAssemblerInterface::SP) {
-                Rn = R_sp;  // convert STR thru Arm SP to SW thru Mips SP
-            }
-            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
-                // If we will writeback, then update the index reg, then store.
-                // This correctly handles stack-push case.
-                mMips->DADDIU(Rn, Rn, amode.value);
-                mMips->SD(Rd, Rn, 0);
-            } else {
-                // No writeback so store offset by value
-                mMips->SD(Rd, Rn, amode.value);
-            }
-            break;
-        case AMODE_IMM_12_POST:
-            mMips->SD(Rd, Rn, 0);
-            mMips->DADDIU(Rn, Rn, amode.value);  // post index always writes back
-            break;
-        case AMODE_REG_SCALE_PRE:
-            // we only support simple base + index, no advanced modes for this one yet
-            mMips->DADDU(R_at, Rn, amode.reg);
-            mMips->SD(Rd, R_at, 0);
-            break;
-    }
-}
-
-#if 0
-#pragma mark -
-#pragma mark MIPS Assembler...
-#endif
-
-
-//**************************************************************************
-//**************************************************************************
-//**************************************************************************
-
-
-/* MIPS64 assembler
-** this is a subset of mips64r6, targeted specifically at ARM instruction
-** replacement in the pixelflinger/codeflinger code.
-**
-** This class is extended from MIPSAssembler class and overrides only
-** MIPS64r6 specific stuff.
-*/
-
-MIPS64Assembler::MIPS64Assembler(const sp<Assembly>& assembly, ArmToMips64Assembler *parent)
-    : MIPSAssembler::MIPSAssembler(assembly, NULL), mParent(parent)
-{
-}
-
-MIPS64Assembler::MIPS64Assembler(void* assembly, ArmToMips64Assembler *parent)
-    : MIPSAssembler::MIPSAssembler(assembly), mParent(parent)
-{
-}
-
-MIPS64Assembler::~MIPS64Assembler()
-{
-}
-
-void MIPS64Assembler::reset()
-{
-    if (mAssembly != NULL) {
-        mBase = mPC = (uint32_t *)mAssembly->base();
-    } else {
-        mPC = mBase = base();
-    }
-    mBranchTargets.clear();
-    mLabels.clear();
-    mLabelsInverseMapping.clear();
-    mComments.clear();
-}
-
-
-void MIPS64Assembler::disassemble(const char* name __unused)
-{
-    char di_buf[140];
-
-    bool arm_disasm_fmt = (mParent->mArmDisassemblyBuffer == NULL) ? false : true;
-
-    typedef char dstr[40];
-    dstr *lines = (dstr *)mParent->mArmDisassemblyBuffer;
-
-    if (mParent->mArmDisassemblyBuffer != NULL) {
-        for (int i=0; i<mParent->mArmInstrCount; ++i) {
-            string_detab(lines[i]);
-        }
-    }
-
-    size_t count = pc()-base();
-    uint32_t* mipsPC = base();
-
-    while (count--) {
-        ssize_t label = mLabelsInverseMapping.indexOfKey(mipsPC);
-        if (label >= 0) {
-            ALOGW("%s:\n", mLabelsInverseMapping.valueAt(label));
-        }
-        ssize_t comment = mComments.indexOfKey(mipsPC);
-        if (comment >= 0) {
-            ALOGW("; %s\n", mComments.valueAt(comment));
-        }
-        ::mips_disassem(mipsPC, di_buf, arm_disasm_fmt);
-        string_detab(di_buf);
-        string_pad(di_buf, 30);
-        ALOGW("%08lx:    %08x    %s", uintptr_t(mipsPC), uint32_t(*mipsPC), di_buf);
-        mipsPC++;
-    }
-}
-
-void MIPS64Assembler::fix_branches()
-{
-    // 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+1));
-        *bt.pc |= offset & 0x00FFFF;
-    }
-}
-
-void MIPS64Assembler::DADDU(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (daddu_fn<<FUNC_SHF)
-                    | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF);
-}
-
-void MIPS64Assembler::DADDIU(int Rt, int Rs, int16_t imm)
-{
-    *mPC++ = (daddiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-void MIPS64Assembler::DSUBU(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (dsubu_fn<<FUNC_SHF) |
-                        (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
-}
-
-void MIPS64Assembler::DSUBIU(int Rt, int Rs, int16_t imm)   // really addiu(d, s, -j)
-{
-    *mPC++ = (daddiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | ((-imm) & MSK_16);
-}
-
-void MIPS64Assembler::MUL(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (mul_fn<<RE_SHF) | (sop30_fn<<FUNC_SHF) |
-                        (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
-}
-
-void MIPS64Assembler::MUH(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (muh_fn<<RE_SHF) | (sop30_fn<<FUNC_SHF) |
-                        (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
-}
-
-void MIPS64Assembler::CLO(int Rd, int Rs)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (17<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (1<<RE_SHF);
-}
-
-void MIPS64Assembler::CLZ(int Rd, int Rs)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (16<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (1<<RE_SHF);
-}
-
-void MIPS64Assembler::LD(int Rt, int Rbase, int16_t offset)
-{
-    *mPC++ = (ld_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPS64Assembler::SD(int Rt, int Rbase, int16_t offset)
-{
-    *mPC++ = (sd_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPS64Assembler::LUI(int Rt, int16_t offset)
-{
-    *mPC++ = (aui_op<<OP_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-
-void MIPS64Assembler::JR(int Rs)
-{
-        *mPC++ = (spec_op<<OP_SHF) | (Rs<<RS_SHF) | (jalr_fn << FUNC_SHF);
-        MIPS64Assembler::NOP();
-}
-
-}; // namespace android:
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.h b/libpixelflinger/codeflinger/MIPS64Assembler.h
deleted file mode 100644
index b43e5da..0000000
--- a/libpixelflinger/codeflinger/MIPS64Assembler.h
+++ /dev/null
@@ -1,404 +0,0 @@
-/* libs/pixelflinger/codeflinger/MIPS64Assembler.h
-**
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT 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_MIPS64ASSEMBLER_H
-#define ANDROID_MIPS64ASSEMBLER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "utils/KeyedVector.h"
-#include "utils/Vector.h"
-#include "tinyutils/smartpointer.h"
-
-#include "ARMAssemblerInterface.h"
-#include "MIPSAssembler.h"
-#include "CodeCache.h"
-
-namespace android {
-
-class MIPS64Assembler;    // forward reference
-
-// this class mimics ARMAssembler interface
-// intent is to translate each ARM instruction to 1 or more MIPS instr
-// implementation calls MIPS64Assembler class to generate mips code
-class ArmToMips64Assembler : public ARMAssemblerInterface
-{
-public:
-                ArmToMips64Assembler(const sp<Assembly>& assembly,
-                        char *abuf = 0, int linesz = 0, int instr_count = 0);
-                ArmToMips64Assembler(void* assembly);
-    virtual     ~ArmToMips64Assembler();
-
-    uint32_t*   base() const;
-    uint32_t*   pc() const;
-    void        disassemble(const char* name);
-
-    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);
-    // for testing purposes
-    void        fix_branches();
-    void        set_condition(int mode, int R1, int R2);
-
-
-    // -----------------------------------------------------------------------
-    // 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...
-    // LDR(B)/STR(B)/PLD
-    // (immediate and Rm can be negative, which indicates U=0)
-    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);
-
-    // LDRH/LDRSB/LDRSH/STRH
-    // (immediate and Rm can be negative, which indicates U=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 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);
-
-    // byte/half word extract...
-    virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
-
-    // bit manipulation...
-    virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
-
-    // 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);
-
-    // this is some crap to share is MIPS64Assembler class for debug
-    char *      mArmDisassemblyBuffer;
-    int         mArmLineLength;
-    int         mArmInstrCount;
-
-    int         mInum;      // current arm instuction number (0..n)
-    uint32_t**  mArmPC;     // array: PC for 1st mips instr of
-                            //      each translated ARM instr
-
-
-private:
-    ArmToMips64Assembler(const ArmToMips64Assembler& rhs);
-    ArmToMips64Assembler& operator = (const ArmToMips64Assembler& rhs);
-
-    void init_conditional_labels(void);
-
-    void protectConditionalOperands(int Rd);
-
-    // reg__tmp set to MIPS AT, reg 1
-    int dataProcAdrModes(int op, int& source, bool sign = false, int reg_tmp = 1);
-
-    sp<Assembly>        mAssembly;
-    MIPS64Assembler*    mMips;
-
-
-    enum misc_constants_t {
-        ARM_MAX_INSTUCTIONS = 512  // based on ASSEMBLY_SCRATCH_SIZE
-    };
-
-    enum {
-        SRC_REG = 0,
-        SRC_IMM,
-        SRC_ERROR = -1
-    };
-
-    enum addr_modes {
-        // start above the range of legal mips reg #'s (0-31)
-        AMODE_REG = 0x20,
-        AMODE_IMM, AMODE_REG_IMM,               // for data processing
-        AMODE_IMM_12_PRE, AMODE_IMM_12_POST,    // for load/store
-        AMODE_REG_SCALE_PRE, AMODE_IMM_8_PRE,
-        AMODE_IMM_8_POST, AMODE_REG_PRE,
-        AMODE_UNSUPPORTED
-    };
-
-    struct addr_mode_t {    // address modes for current ARM instruction
-        int         reg;
-        int         stype;
-        uint32_t    value;
-        bool        writeback;  // writeback the adr reg after modification
-    } amode;
-
-    enum cond_types {
-        CMP_COND = 1,
-        SBIT_COND
-    };
-
-    struct cond_mode_t {    // conditional-execution info for current ARM instruction
-        cond_types  type;
-        int         r1;
-        int         r2;
-        int         labelnum;
-        char        label[100][10];
-    } cond;
-};
-
-
-
-
-// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
-
-// This is the basic MIPS64 assembler, which just creates the opcodes in memory.
-// All the more complicated work is done in ArmToMips64Assember above.
-// Inherits MIPSAssembler class, and overrides only MIPS64r6 specific stuff
-
-class MIPS64Assembler : public MIPSAssembler
-{
-public:
-                MIPS64Assembler(const sp<Assembly>& assembly, ArmToMips64Assembler *parent);
-                MIPS64Assembler(void* assembly, ArmToMips64Assembler *parent);
-    virtual     ~MIPS64Assembler();
-
-    virtual void        reset();
-    virtual void        disassemble(const char* name);
-
-    void        fix_branches();
-
-    // ------------------------------------------------------------------------
-    // MIPS64AssemblerInterface...
-    // ------------------------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Arithmetic...
-#endif
-
-    void DADDU(int Rd, int Rs, int Rt);
-    void DADDIU(int Rt, int Rs, int16_t imm);
-    void DSUBU(int Rd, int Rs, int Rt);
-    void DSUBIU(int Rt, int Rs, int16_t imm);
-    virtual void MUL(int Rd, int Rs, int Rt);
-    void MUH(int Rd, int Rs, int Rt);
-
-#if 0
-#pragma mark -
-#pragma mark Logical...
-#endif
-
-    virtual void CLO(int Rd, int Rs);
-    virtual void CLZ(int Rd, int Rs);
-
-#if 0
-#pragma mark -
-#pragma mark Load/store...
-#endif
-
-    void LD(int Rt, int Rbase, int16_t offset);
-    void SD(int Rt, int Rbase, int16_t offset);
-    virtual void LUI(int Rt, int16_t offset);
-
-#if 0
-#pragma mark -
-#pragma mark Branch...
-#endif
-
-    void JR(int Rs);
-
-
-protected:
-    ArmToMips64Assembler *mParent;
-
-    // opcode field of all instructions
-    enum opcode_field {
-        spec_op, regimm_op, j_op, jal_op,                  // 0x00 - 0x03
-        beq_op, bne_op, pop06_op, pop07_op,                // 0x04 - 0x07
-        pop10_op, addiu_op, slti_op, sltiu_op,             // 0x08 - 0x0b
-        andi_op, ori_op, xori_op, aui_op,                  // 0x0c - 0x0f
-        cop0_op, cop1_op, cop2_op, rsrv_opc_0,             // 0x10 - 0x13
-        rsrv_opc_1, rsrv_opc_2, pop26_op, pop27_op,        // 0x14 - 0x17
-        pop30_op, daddiu_op, rsrv_opc_3, rsrv_opc_4,       // 0x18 - 0x1b
-        rsrv_opc_5, daui_op, msa_op, spec3_op,             // 0x1c - 0x1f
-        lb_op, lh_op, rsrv_opc_6, lw_op,                   // 0x20 - 0x23
-        lbu_op, lhu_op, rsrv_opc_7, lwu_op,                // 0x24 - 0x27
-        sb_op, sh_op, rsrv_opc_8, sw_op,                   // 0x28 - 0x2b
-        rsrv_opc_9, rsrv_opc_10, rsrv_opc_11, rsrv_opc_12, // 0x2c - 0x2f
-        rsrv_opc_13, lwc1_op, bc_op, rsrv_opc_14,          // 0x2c - 0x2f
-        rsrv_opc_15, ldc1_op, pop66_op, ld_op,             // 0x30 - 0x33
-        rsrv_opc_16, swc1_op, balc_op, pcrel_op,           // 0x34 - 0x37
-        rsrv_opc_17, sdc1_op, pop76_op, sd_op              // 0x38 - 0x3b
-    };
-
-
-    // func field for special opcode
-    enum func_spec_op {
-        sll_fn, rsrv_spec_0, srl_fn, sra_fn,
-        sllv_fn, lsa_fn, srlv_fn, srav_fn,
-        rsrv_spec_1, jalr_fn, rsrv_spec_2, rsrv_spec_3,
-        syscall_fn, break_fn, sdbbp_fn, sync_fn,
-        clz_fn, clo_fn, dclz_fn, dclo_fn,
-        dsllv_fn, dlsa_fn, dsrlv_fn, dsrav_fn,
-        sop30_fn, sop31_fn, sop32_fn, sop33_fn,
-        sop34_fn, sop35_fn, sop36_fn, sop37_fn,
-        add_fn, addu_fn, sub_fn, subu_fn,
-        and_fn, or_fn, xor_fn, nor_fn,
-        rsrv_spec_4, rsrv_spec_5, slt_fn, sltu_fn,
-        dadd_fn, daddu_fn, dsub_fn, dsubu_fn,
-        tge_fn, tgeu_fn, tlt_fn, tltu_fn,
-        teq_fn, seleqz_fn, tne_fn, selnez_fn,
-        dsll_fn, rsrv_spec_6, dsrl_fn, dsra_fn,
-        dsll32_fn, rsrv_spec_7, dsrl32_fn, dsra32_fn
-    };
-
-    // func field for spec3 opcode
-    enum func_spec3_op {
-        ext_fn, dextm_fn, dextu_fn, dext_fn,
-        ins_fn, dinsm_fn, dinsu_fn, dins_fn,
-        cachee_fn = 0x1b, sbe_fn, she_fn, sce_fn, swe_fn,
-        bshfl_fn, prefe_fn = 0x23, dbshfl_fn, cache_fn, sc_fn, scd_fn,
-        lbue_fn, lhue_fn, lbe_fn = 0x2c, lhe_fn, lle_fn, lwe_fn,
-        pref_fn = 0x35, ll_fn, lld_fn, rdhwr_fn = 0x3b
-    };
-
-    // sa field for spec3 opcodes, with BSHFL function
-    enum func_spec3_bshfl {
-        bitswap_fn,
-        wsbh_fn = 0x02,
-        dshd_fn = 0x05,
-        seb_fn = 0x10,
-        seh_fn = 0x18
-    };
-
-    // rt field of regimm opcodes.
-    enum regimm_fn {
-        bltz_fn, bgez_fn,
-        dahi_fn = 0x6,
-        nal_fn = 0x10, bal_fn, bltzall_fn, bgezall_fn,
-        sigrie_fn = 0x17,
-        dati_fn = 0x1e, synci_fn
-    };
-
-    enum muldiv_fn {
-        mul_fn = 0x02, muh_fn
-    };
-
-    enum mips_inst_shifts {
-        OP_SHF       = 26,
-        JTARGET_SHF  = 0,
-        RS_SHF       = 21,
-        RT_SHF       = 16,
-        RD_SHF       = 11,
-        RE_SHF       = 6,
-        SA_SHF       = RE_SHF,  // synonym
-        IMM_SHF      = 0,
-        FUNC_SHF     = 0,
-
-        // mask values
-        MSK_16       = 0xffff,
-
-
-        CACHEOP_SHF  = 18,
-        CACHESEL_SHF = 16,
-    };
-};
-
-
-}; // namespace android
-
-#endif //ANDROID_MIPS64ASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp
deleted file mode 100644
index 7de8cc1..0000000
--- a/libpixelflinger/codeflinger/MIPSAssembler.cpp
+++ /dev/null
@@ -1,1955 +0,0 @@
-/* libs/pixelflinger/codeflinger/MIPSAssembler.cpp
-**
-** Copyright 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.
-*/
-
-
-/* MIPS assembler and ARM->MIPS assembly translator
-**
-** The approach is to leave the GGLAssembler and associated files largely
-** un-changed, still utilizing all Arm instruction generation. Via the
-** ArmToMipsAssembler (subclassed from ArmAssemblerInterface) each Arm
-** instruction is translated to one or more Mips instructions as necessary. This
-** is clearly less efficient than a direct implementation within the
-** GGLAssembler, but is far cleaner, more maintainable, and has yielded very
-** significant performance gains on Mips compared to the generic pixel pipeline.
-**
-**
-** GGLAssembler changes
-**
-** - The register allocator has been modified to re-map Arm registers 0-15 to mips
-** registers 2-17. Mips register 0 cannot be used as general-purpose register,
-** and register 1 has traditional uses as a short-term temporary.
-**
-** - Added some early bailouts for OUT_OF_REGISTERS in texturing.cpp and
-** GGLAssembler.cpp, since this is not fatal, and can be retried at lower
-** optimization level.
-**
-**
-** ARMAssembler and ARMAssemblerInterface changes
-**
-** Refactored ARM address-mode static functions (imm(), reg_imm(), imm12_pre(), etc.)
-** to virtual, so they can be overridden in MIPSAssembler. The implementation of these
-** functions on ARM is moved from ARMAssemblerInterface.cpp to ARMAssembler.cpp, and
-** is unchanged from the original. (This required duplicating 2 of these as static
-** functions in ARMAssemblerInterface.cpp so they could be used as static initializers).
-*/
-
-#define LOG_TAG "MIPSAssembler"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-#include <cutils/properties.h>
-#include <log/log.h>
-#include <private/pixelflinger/ggl_context.h>
-
-#include "CodeCache.h"
-#include "MIPSAssembler.h"
-#include "mips_disassem.h"
-
-#define __unused __attribute__((__unused__))
-
-// Choose MIPS arch variant following gcc flags
-#if defined(__mips__) && __mips==32 && __mips_isa_rev>=2
-#define mips32r2 1
-#else
-#define mips32r2 0
-#endif
-
-
-#define NOT_IMPLEMENTED()  LOG_ALWAYS_FATAL("Arm instruction %s not yet implemented\n", __func__)
-
-
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark ArmToMipsAssembler...
-#endif
-
-ArmToMipsAssembler::ArmToMipsAssembler(const sp<Assembly>& assembly,
-                                       char *abuf, int linesz, int instr_count)
-    :   ARMAssemblerInterface(),
-        mArmDisassemblyBuffer(abuf),
-        mArmLineLength(linesz),
-        mArmInstrCount(instr_count),
-        mInum(0),
-        mAssembly(assembly)
-{
-    mMips = new MIPSAssembler(assembly, this);
-    mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *));
-    init_conditional_labels();
-}
-
-ArmToMipsAssembler::~ArmToMipsAssembler()
-{
-    delete mMips;
-    free((void *) mArmPC);
-}
-
-uint32_t* ArmToMipsAssembler::pc() const
-{
-    return mMips->pc();
-}
-
-uint32_t* ArmToMipsAssembler::base() const
-{
-    return mMips->base();
-}
-
-void ArmToMipsAssembler::reset()
-{
-    cond.labelnum = 0;
-    mInum = 0;
-    mMips->reset();
-}
-
-int ArmToMipsAssembler::getCodegenArch()
-{
-    return CODEGEN_ARCH_MIPS;
-}
-
-void ArmToMipsAssembler::comment(const char* string)
-{
-    mMips->comment(string);
-}
-
-void ArmToMipsAssembler::label(const char* theLabel)
-{
-    mMips->label(theLabel);
-}
-
-void ArmToMipsAssembler::disassemble(const char* name)
-{
-    mMips->disassemble(name);
-}
-
-void ArmToMipsAssembler::init_conditional_labels()
-{
-    int i;
-    for (i=0;i<99; ++i) {
-        sprintf(cond.label[i], "cond_%d", i);
-    }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Prolog/Epilog & Generate...
-#endif
-
-void ArmToMipsAssembler::prolog()
-{
-    mArmPC[mInum++] = pc();  // save starting PC for this instr
-
-    mMips->ADDIU(R_sp, R_sp, -(5 * 4));
-    mMips->SW(R_s0, R_sp, 0);
-    mMips->SW(R_s1, R_sp, 4);
-    mMips->SW(R_s2, R_sp, 8);
-    mMips->SW(R_s3, R_sp, 12);
-    mMips->SW(R_s4, R_sp, 16);
-    mMips->MOVE(R_v0, R_a0);    // move context * passed in a0 to v0 (arm r0)
-}
-
-void ArmToMipsAssembler::epilog(uint32_t touched __unused)
-{
-    mArmPC[mInum++] = pc();  // save starting PC for this instr
-
-    mMips->LW(R_s0, R_sp, 0);
-    mMips->LW(R_s1, R_sp, 4);
-    mMips->LW(R_s2, R_sp, 8);
-    mMips->LW(R_s3, R_sp, 12);
-    mMips->LW(R_s4, R_sp, 16);
-    mMips->ADDIU(R_sp, R_sp, (5 * 4));
-    mMips->JR(R_ra);
-
-}
-
-int ArmToMipsAssembler::generate(const char* name)
-{
-    return mMips->generate(name);
-}
-
-uint32_t* ArmToMipsAssembler::pcForLabel(const char* label)
-{
-    return mMips->pcForLabel(label);
-}
-
-
-
-//----------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Addressing modes & shifters...
-#endif
-
-
-// do not need this for MIPS, but it is in the Interface (virtual)
-int ArmToMipsAssembler::buildImmediate(
-        uint32_t immediate, uint32_t& rot, uint32_t& imm)
-{
-    // for MIPS, any 32-bit immediate is OK
-    rot = 0;
-    imm = immediate;
-    return 0;
-}
-
-// shifters...
-
-bool ArmToMipsAssembler::isValidImmediate(uint32_t immediate __unused)
-{
-    // for MIPS, any 32-bit immediate is OK
-    return true;
-}
-
-uint32_t ArmToMipsAssembler::imm(uint32_t immediate)
-{
-    // ALOGW("immediate value %08x at pc %08x\n", immediate, (int)pc());
-    amode.value = immediate;
-    return AMODE_IMM;
-}
-
-uint32_t ArmToMipsAssembler::reg_imm(int Rm, int type, uint32_t shift)
-{
-    amode.reg = Rm;
-    amode.stype = type;
-    amode.value = shift;
-    return AMODE_REG_IMM;
-}
-
-uint32_t ArmToMipsAssembler::reg_rrx(int Rm __unused)
-{
-    // reg_rrx mode is not used in the GLLAssember code at this time
-    return AMODE_UNSUPPORTED;
-}
-
-uint32_t ArmToMipsAssembler::reg_reg(int Rm __unused, int type __unused,
-                                     int Rs __unused)
-{
-    // reg_reg mode is not used in the GLLAssember code at this time
-    return AMODE_UNSUPPORTED;
-}
-
-
-// addressing modes...
-// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
-uint32_t ArmToMipsAssembler::immed12_pre(int32_t immed12, int W)
-{
-    LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
-                        "LDR(B)/STR(B)/PLD immediate too big (%08x)",
-                        immed12);
-    amode.value = immed12;
-    amode.writeback = W;
-    return AMODE_IMM_12_PRE;
-}
-
-uint32_t ArmToMipsAssembler::immed12_post(int32_t immed12)
-{
-    LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
-                        "LDR(B)/STR(B)/PLD immediate too big (%08x)",
-                        immed12);
-
-    amode.value = immed12;
-    return AMODE_IMM_12_POST;
-}
-
-uint32_t ArmToMipsAssembler::reg_scale_pre(int Rm, int type,
-        uint32_t shift, int W)
-{
-    LOG_ALWAYS_FATAL_IF(W | type | shift, "reg_scale_pre adv modes not yet implemented");
-
-    amode.reg = Rm;
-    // amode.stype = type;      // more advanced modes not used in GGLAssembler yet
-    // amode.value = shift;
-    // amode.writeback = W;
-    return AMODE_REG_SCALE_PRE;
-}
-
-uint32_t ArmToMipsAssembler::reg_scale_post(int Rm __unused, int type __unused,
-                                            uint32_t shift __unused)
-{
-    LOG_ALWAYS_FATAL("adr mode reg_scale_post not yet implemented\n");
-    return AMODE_UNSUPPORTED;
-}
-
-// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0)
-uint32_t ArmToMipsAssembler::immed8_pre(int32_t immed8, int W __unused)
-{
-    // uint32_t offset = abs(immed8);
-
-    LOG_ALWAYS_FATAL("adr mode immed8_pre not yet implemented\n");
-
-    LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
-                        "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
-                        immed8);
-    return AMODE_IMM_8_PRE;
-}
-
-uint32_t ArmToMipsAssembler::immed8_post(int32_t immed8)
-{
-    // uint32_t offset = abs(immed8);
-
-    LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
-                        "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
-                        immed8);
-    amode.value = immed8;
-    return AMODE_IMM_8_POST;
-}
-
-uint32_t ArmToMipsAssembler::reg_pre(int Rm, int W)
-{
-    LOG_ALWAYS_FATAL_IF(W, "reg_pre writeback not yet implemented");
-    amode.reg = Rm;
-    return AMODE_REG_PRE;
-}
-
-uint32_t ArmToMipsAssembler::reg_post(int Rm __unused)
-{
-    LOG_ALWAYS_FATAL("adr mode reg_post not yet implemented\n");
-    return AMODE_UNSUPPORTED;
-}
-
-
-
-// ----------------------------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Data Processing...
-#endif
-
-// check if the operand registers from a previous CMP or S-bit instruction
-// would be overwritten by this instruction. If so, move the value to a
-// safe register.
-// Note that we cannot tell at _this_ instruction time if a future (conditional)
-// instruction will _also_ use this value (a defect of the simple 1-pass, one-
-// instruction-at-a-time translation). Therefore we must be conservative and
-// save the value before it is overwritten. This costs an extra MOVE instr.
-
-void ArmToMipsAssembler::protectConditionalOperands(int Rd)
-{
-    if (Rd == cond.r1) {
-        mMips->MOVE(R_cmp, cond.r1);
-        cond.r1 = R_cmp;
-    }
-    if (cond.type == CMP_COND && Rd == cond.r2) {
-        mMips->MOVE(R_cmp2, cond.r2);
-        cond.r2 = R_cmp2;
-    }
-}
-
-
-// interprets the addressing mode, and generates the common code
-// used by the majority of data-processing ops. Many MIPS instructions
-// have a register-based form and a different immediate form. See
-// opAND below for an example. (this could be inlined)
-//
-// this works with the imm(), reg_imm() methods above, which are directly
-// called by the GLLAssembler.
-// note: _signed parameter defaults to false (un-signed)
-// note: tmpReg parameter defaults to 1, MIPS register AT
-int ArmToMipsAssembler::dataProcAdrModes(int op, int& source, bool _signed, int tmpReg)
-{
-    if (op < AMODE_REG) {
-        source = op;
-        return SRC_REG;
-    } else if (op == AMODE_IMM) {
-        if ((!_signed && amode.value > 0xffff)
-                || (_signed && ((int)amode.value < -32768 || (int)amode.value > 32767) )) {
-            mMips->LUI(tmpReg, (amode.value >> 16));
-            if (amode.value & 0x0000ffff) {
-                mMips->ORI(tmpReg, tmpReg, (amode.value & 0x0000ffff));
-            }
-            source = tmpReg;
-            return SRC_REG;
-        } else {
-            source = amode.value;
-            return SRC_IMM;
-        }
-    } else if (op == AMODE_REG_IMM) {
-        switch (amode.stype) {
-            case LSL: mMips->SLL(tmpReg, amode.reg, amode.value); break;
-            case LSR: mMips->SRL(tmpReg, amode.reg, amode.value); break;
-            case ASR: mMips->SRA(tmpReg, amode.reg, amode.value); break;
-            case ROR: if (mips32r2) {
-                          mMips->ROTR(tmpReg, amode.reg, amode.value);
-                      } else {
-                          mMips->RORIsyn(tmpReg, amode.reg, amode.value);
-                      }
-                      break;
-        }
-        source = tmpReg;
-        return SRC_REG;
-    } else {  // adr mode RRX is not used in GGL Assembler at this time
-        // we are screwed, this should be exception, assert-fail or something
-        LOG_ALWAYS_FATAL("adr mode reg_rrx not yet implemented\n");
-        return SRC_ERROR;
-    }
-}
-
-
-void ArmToMipsAssembler::dataProcessing(int opcode, int cc,
-        int s, int Rd, int Rn, uint32_t Op2)
-{
-    int src;    // src is modified by dataProcAdrModes() - passed as int&
-
-
-    if (cc != AL) {
-        protectConditionalOperands(Rd);
-        // the branch tests register(s) set by prev CMP or instr with 'S' bit set
-        // inverse the condition to jump past this conditional instruction
-        ArmToMipsAssembler::B(cc^1, cond.label[++cond.labelnum]);
-    } else {
-        mArmPC[mInum++] = pc();  // save starting PC for this instr
-    }
-
-    switch (opcode) {
-    case opAND:
-        if (dataProcAdrModes(Op2, src) == SRC_REG) {
-            mMips->AND(Rd, Rn, src);
-        } else {                        // adr mode was SRC_IMM
-            mMips->ANDI(Rd, Rn, src);
-        }
-        break;
-
-    case opADD:
-        // set "signed" to true for adr modes
-        if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
-            mMips->ADDU(Rd, Rn, src);
-        } else {                        // adr mode was SRC_IMM
-            mMips->ADDIU(Rd, Rn, src);
-        }
-        break;
-
-    case opSUB:
-        // set "signed" to true for adr modes
-        if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
-            mMips->SUBU(Rd, Rn, src);
-        } else {                        // adr mode was SRC_IMM
-            mMips->SUBIU(Rd, Rn, src);
-        }
-        break;
-
-    case opEOR:
-        if (dataProcAdrModes(Op2, src) == SRC_REG) {
-            mMips->XOR(Rd, Rn, src);
-        } else {                        // adr mode was SRC_IMM
-            mMips->XORI(Rd, Rn, src);
-        }
-        break;
-
-    case opORR:
-        if (dataProcAdrModes(Op2, src) == SRC_REG) {
-            mMips->OR(Rd, Rn, src);
-        } else {                        // adr mode was SRC_IMM
-            mMips->ORI(Rd, Rn, src);
-        }
-        break;
-
-    case opBIC:
-        if (dataProcAdrModes(Op2, src) == SRC_IMM) {
-            // if we are 16-bit imnmediate, load to AT reg
-            mMips->ORI(R_at, 0, src);
-            src = R_at;
-        }
-        mMips->NOT(R_at, src);
-        mMips->AND(Rd, Rn, R_at);
-        break;
-
-    case opRSB:
-        if (dataProcAdrModes(Op2, src) == SRC_IMM) {
-            // if we are 16-bit imnmediate, load to AT reg
-            mMips->ORI(R_at, 0, src);
-            src = R_at;
-        }
-        mMips->SUBU(Rd, src, Rn);   // subu with the parameters reversed
-        break;
-
-    case opMOV:
-        if (Op2 < AMODE_REG) {  // op2 is reg # in this case
-            mMips->MOVE(Rd, Op2);
-        } else if (Op2 == AMODE_IMM) {
-            if (amode.value > 0xffff) {
-                mMips->LUI(Rd, (amode.value >> 16));
-                if (amode.value & 0x0000ffff) {
-                    mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
-                }
-             } else {
-                mMips->ORI(Rd, 0, amode.value);
-            }
-        } else if (Op2 == AMODE_REG_IMM) {
-            switch (amode.stype) {
-            case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
-            case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
-            case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
-            case ROR: if (mips32r2) {
-                          mMips->ROTR(Rd, amode.reg, amode.value);
-                      } else {
-                          mMips->RORIsyn(Rd, amode.reg, amode.value);
-                      }
-                      break;
-            }
-        }
-        else {
-            // adr mode RRX is not used in GGL Assembler at this time
-            mMips->UNIMPL();
-        }
-        break;
-
-    case opMVN:     // this is a 1's complement: NOT
-        if (Op2 < AMODE_REG) {  // op2 is reg # in this case
-            mMips->NOR(Rd, Op2, 0);     // NOT is NOR with 0
-            break;
-        } else if (Op2 == AMODE_IMM) {
-            if (amode.value > 0xffff) {
-                mMips->LUI(Rd, (amode.value >> 16));
-                if (amode.value & 0x0000ffff) {
-                    mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
-                }
-             } else {
-                mMips->ORI(Rd, 0, amode.value);
-             }
-        } else if (Op2 == AMODE_REG_IMM) {
-            switch (amode.stype) {
-            case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
-            case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
-            case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
-            case ROR: if (mips32r2) {
-                          mMips->ROTR(Rd, amode.reg, amode.value);
-                      } else {
-                          mMips->RORIsyn(Rd, amode.reg, amode.value);
-                      }
-                      break;
-            }
-        }
-        else {
-            // adr mode RRX is not used in GGL Assembler at this time
-            mMips->UNIMPL();
-        }
-        mMips->NOR(Rd, Rd, 0);     // NOT is NOR with 0
-        break;
-
-    case opCMP:
-        // Either operand of a CMP instr could get overwritten by a subsequent
-        // conditional instruction, which is ok, _UNLESS_ there is a _second_
-        // conditional instruction. Under MIPS, this requires doing the comparison
-        // again (SLT), and the original operands must be available. (and this
-        // pattern of multiple conditional instructions from same CMP _is_ used
-        // in GGL-Assembler)
-        //
-        // For now, if a conditional instr overwrites the operands, we will
-        // move them to dedicated temp regs. This is ugly, and inefficient,
-        // and should be optimized.
-        //
-        // WARNING: making an _Assumption_ that CMP operand regs will NOT be
-        // trashed by intervening NON-conditional instructions. In the general
-        // case this is legal, but it is NOT currently done in GGL-Assembler.
-
-        cond.type = CMP_COND;
-        cond.r1 = Rn;
-        if (dataProcAdrModes(Op2, src, false, R_cmp2) == SRC_REG) {
-            cond.r2 = src;
-        } else {                        // adr mode was SRC_IMM
-            mMips->ORI(R_cmp2, R_zero, src);
-            cond.r2 = R_cmp2;
-        }
-
-        break;
-
-
-    case opTST:
-    case opTEQ:
-    case opCMN:
-    case opADC:
-    case opSBC:
-    case opRSC:
-        mMips->UNIMPL(); // currently unused in GGL Assembler code
-        break;
-    }
-
-    if (cc != AL) {
-        mMips->label(cond.label[cond.labelnum]);
-    }
-    if (s && opcode != opCMP) {
-        cond.type = SBIT_COND;
-        cond.r1 = Rd;
-    }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Multiply...
-#endif
-
-// multiply, accumulate
-void ArmToMipsAssembler::MLA(int cc __unused, int s,
-        int Rd, int Rm, int Rs, int Rn) {
-
-    mArmPC[mInum++] = pc();  // save starting PC for this instr
-
-    mMips->MUL(R_at, Rm, Rs);
-    mMips->ADDU(Rd, R_at, Rn);
-    if (s) {
-        cond.type = SBIT_COND;
-        cond.r1 = Rd;
-    }
-}
-
-void ArmToMipsAssembler::MUL(int cc __unused, int s,
-        int Rd, int Rm, int Rs) {
-    mArmPC[mInum++] = pc();
-    mMips->MUL(Rd, Rm, Rs);
-    if (s) {
-        cond.type = SBIT_COND;
-        cond.r1 = Rd;
-    }
-}
-
-void ArmToMipsAssembler::UMULL(int cc __unused, int s,
-        int RdLo, int RdHi, int Rm, int Rs) {
-    mArmPC[mInum++] = pc();
-    mMips->MULT(Rm, Rs);
-    mMips->MFHI(RdHi);
-    mMips->MFLO(RdLo);
-    if (s) {
-        cond.type = SBIT_COND;
-        cond.r1 = RdHi;     // BUG...
-        LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
-    }
-}
-
-void ArmToMipsAssembler::UMUAL(int cc __unused, int s,
-        int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
-    LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
-                        "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
-    // *mPC++ =    (cc<<28) | (1<<23) | (1<<21) | (s<<20) |
-    //             (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-    if (s) {
-        cond.type = SBIT_COND;
-        cond.r1 = RdHi;     // BUG...
-        LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
-    }
-}
-
-void ArmToMipsAssembler::SMULL(int cc __unused, int s,
-        int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
-    LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
-                        "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
-    // *mPC++ =    (cc<<28) | (1<<23) | (1<<22) | (s<<20) |
-    //             (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-    if (s) {
-        cond.type = SBIT_COND;
-        cond.r1 = RdHi;     // BUG...
-        LOG_ALWAYS_FATAL("Condition on SMULL must be on 64-bit result\n");
-    }
-}
-void ArmToMipsAssembler::SMUAL(int cc __unused, int s,
-        int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
-    LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
-                        "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
-    // *mPC++ =    (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) |
-    //             (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-    if (s) {
-        cond.type = SBIT_COND;
-        cond.r1 = RdHi;     // BUG...
-        LOG_ALWAYS_FATAL("Condition on SMUAL must be on 64-bit result\n");
-    }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Branches...
-#endif
-
-// branches...
-
-void ArmToMipsAssembler::B(int cc, const char* label)
-{
-    mArmPC[mInum++] = pc();
-    if (cond.type == SBIT_COND) { cond.r2 = R_zero; }
-
-    switch(cc) {
-        case EQ: mMips->BEQ(cond.r1, cond.r2, label); break;
-        case NE: mMips->BNE(cond.r1, cond.r2, label); break;
-        case HS: mMips->BGEU(cond.r1, cond.r2, label); break;
-        case LO: mMips->BLTU(cond.r1, cond.r2, label); break;
-        case MI: mMips->BLT(cond.r1, cond.r2, label); break;
-        case PL: mMips->BGE(cond.r1, cond.r2, label); break;
-
-        case HI: mMips->BGTU(cond.r1, cond.r2, label); break;
-        case LS: mMips->BLEU(cond.r1, cond.r2, label); break;
-        case GE: mMips->BGE(cond.r1, cond.r2, label); break;
-        case LT: mMips->BLT(cond.r1, cond.r2, label); break;
-        case GT: mMips->BGT(cond.r1, cond.r2, label); break;
-        case LE: mMips->BLE(cond.r1, cond.r2, label); break;
-        case AL: mMips->B(label); break;
-        case NV: /* B Never - no instruction */ break;
-
-        case VS:
-        case VC:
-        default:
-            LOG_ALWAYS_FATAL("Unsupported cc: %02x\n", cc);
-            break;
-    }
-}
-
-void ArmToMipsAssembler::BL(int cc __unused, const char* label __unused)
-{
-    LOG_ALWAYS_FATAL("branch-and-link not supported yet\n");
-    mArmPC[mInum++] = pc();
-}
-
-// no use for Branches with integer PC, but they're in the Interface class ....
-void ArmToMipsAssembler::B(int cc __unused, uint32_t* to_pc __unused)
-{
-    LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
-    mArmPC[mInum++] = pc();
-}
-
-void ArmToMipsAssembler::BL(int cc __unused, uint32_t* to_pc __unused)
-{
-    LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
-    mArmPC[mInum++] = pc();
-}
-
-void ArmToMipsAssembler::BX(int cc __unused, int Rn __unused)
-{
-    LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
-    mArmPC[mInum++] = pc();
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Data Transfer...
-#endif
-
-// data transfer...
-void ArmToMipsAssembler::LDR(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed12_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            amode.writeback = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_12_PRE:
-            if (Rn == ARMAssemblerInterface::SP) {
-                Rn = R_sp;      // convert LDR via Arm SP to LW via Mips SP
-            }
-            mMips->LW(Rd, Rn, amode.value);
-            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
-                mMips->ADDIU(Rn, Rn, amode.value);
-            }
-            break;
-        case AMODE_IMM_12_POST:
-            if (Rn == ARMAssemblerInterface::SP) {
-                Rn = R_sp;      // convert STR thru Arm SP to STR thru Mips SP
-            }
-            mMips->LW(Rd, Rn, 0);
-            mMips->ADDIU(Rn, Rn, amode.value);
-            break;
-        case AMODE_REG_SCALE_PRE:
-            // we only support simple base + index, no advanced modes for this one yet
-            mMips->ADDU(R_at, Rn, amode.reg);
-            mMips->LW(Rd, R_at, 0);
-            break;
-    }
-}
-
-void ArmToMipsAssembler::LDRB(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed12_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            amode.writeback = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_12_PRE:
-            mMips->LBU(Rd, Rn, amode.value);
-            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
-                mMips->ADDIU(Rn, Rn, amode.value);
-            }
-            break;
-        case AMODE_IMM_12_POST:
-            mMips->LBU(Rd, Rn, 0);
-            mMips->ADDIU(Rn, Rn, amode.value);
-            break;
-        case AMODE_REG_SCALE_PRE:
-            // we only support simple base + index, no advanced modes for this one yet
-            mMips->ADDU(R_at, Rn, amode.reg);
-            mMips->LBU(Rd, R_at, 0);
-            break;
-    }
-
-}
-
-void ArmToMipsAssembler::STR(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed12_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            amode.writeback = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_12_PRE:
-            if (Rn == ARMAssemblerInterface::SP) {
-                Rn = R_sp;  // convert STR thru Arm SP to SW thru Mips SP
-            }
-            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
-                // If we will writeback, then update the index reg, then store.
-                // This correctly handles stack-push case.
-                mMips->ADDIU(Rn, Rn, amode.value);
-                mMips->SW(Rd, Rn, 0);
-            } else {
-                // No writeback so store offset by value
-                mMips->SW(Rd, Rn, amode.value);
-            }
-            break;
-        case AMODE_IMM_12_POST:
-            mMips->SW(Rd, Rn, 0);
-            mMips->ADDIU(Rn, Rn, amode.value);  // post index always writes back
-            break;
-        case AMODE_REG_SCALE_PRE:
-            // we only support simple base + index, no advanced modes for this one yet
-            mMips->ADDU(R_at, Rn, amode.reg);
-            mMips->SW(Rd, R_at, 0);
-            break;
-    }
-}
-
-void ArmToMipsAssembler::STRB(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed12_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            amode.writeback = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_12_PRE:
-            mMips->SB(Rd, Rn, amode.value);
-            if (amode.writeback) {      // OPTIONAL writeback on pre-index mode
-                mMips->ADDIU(Rn, Rn, amode.value);
-            }
-            break;
-        case AMODE_IMM_12_POST:
-            mMips->SB(Rd, Rn, 0);
-            mMips->ADDIU(Rn, Rn, amode.value);
-            break;
-        case AMODE_REG_SCALE_PRE:
-            // we only support simple base + index, no advanced modes for this one yet
-            mMips->ADDU(R_at, Rn, amode.reg);
-            mMips->SB(Rd, R_at, 0);
-            break;
-    }
-}
-
-void ArmToMipsAssembler::LDRH(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed8_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_8_PRE:      // no support yet for writeback
-            mMips->LHU(Rd, Rn, amode.value);
-            break;
-        case AMODE_IMM_8_POST:
-            mMips->LHU(Rd, Rn, 0);
-            mMips->ADDIU(Rn, Rn, amode.value);
-            break;
-        case AMODE_REG_PRE:
-            // we only support simple base +/- index
-            if (amode.reg >= 0) {
-                mMips->ADDU(R_at, Rn, amode.reg);
-            } else {
-                mMips->SUBU(R_at, Rn, abs(amode.reg));
-            }
-            mMips->LHU(Rd, R_at, 0);
-            break;
-    }
-}
-
-void ArmToMipsAssembler::LDRSB(int cc __unused, int Rd __unused,
-                               int Rn __unused, uint32_t offset __unused)
-{
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::LDRSH(int cc __unused, int Rd __unused,
-                               int Rn __unused, uint32_t offset __unused)
-{
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::STRH(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
-    mArmPC[mInum++] = pc();
-    // work-around for ARM default address mode of immed8_pre(0)
-    if (offset > AMODE_UNSUPPORTED) offset = 0;
-    switch (offset) {
-        case 0:
-            amode.value = 0;
-            // fall thru to next case ....
-        case AMODE_IMM_8_PRE:      // no support yet for writeback
-            mMips->SH(Rd, Rn, amode.value);
-            break;
-        case AMODE_IMM_8_POST:
-            mMips->SH(Rd, Rn, 0);
-            mMips->ADDIU(Rn, Rn, amode.value);
-            break;
-        case AMODE_REG_PRE:
-            // we only support simple base +/- index
-            if (amode.reg >= 0) {
-                mMips->ADDU(R_at, Rn, amode.reg);
-            } else {
-                mMips->SUBU(R_at, Rn, abs(amode.reg));
-            }
-            mMips->SH(Rd, R_at, 0);
-            break;
-    }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Block Data Transfer...
-#endif
-
-// block data transfer...
-void ArmToMipsAssembler::LDM(int cc __unused, int dir __unused,
-        int Rn __unused, int W __unused, uint32_t reg_list __unused)
-{   //                        ED FD EA FA      IB IA DB DA
-    // const uint8_t P[8] = { 1, 0, 1, 0,      1, 0, 1, 0 };
-    // const uint8_t U[8] = { 1, 1, 0, 0,      1, 1, 0, 0 };
-    // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
-    //         (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::STM(int cc __unused, int dir __unused,
-        int Rn __unused, int W __unused, uint32_t reg_list __unused)
-{   //                        FA EA FD ED      IB IA DB DA
-    // const uint8_t P[8] = { 0, 1, 0, 1,      1, 0, 1, 0 };
-    // const uint8_t U[8] = { 0, 0, 1, 1,      1, 1, 0, 0 };
-    // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
-    //         (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Special...
-#endif
-
-// special...
-void ArmToMipsAssembler::SWP(int cc __unused, int Rn __unused,
-                             int Rd __unused, int Rm __unused) {
-    // *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::SWPB(int cc __unused, int Rn __unused,
-                              int Rd __unused, int Rm __unused) {
-    // *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::SWI(int cc __unused, uint32_t comment __unused) {
-    // *mPC++ = (cc<<28) | (0xF<<24) | comment;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-
-#if 0
-#pragma mark -
-#pragma mark DSP instructions...
-#endif
-
-// DSP instructions...
-void ArmToMipsAssembler::PLD(int Rn __unused, uint32_t offset) {
-    LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))),
-                        "PLD only P=1, W=0");
-    // *mPC++ = 0xF550F000 | (Rn<<16) | offset;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::CLZ(int cc __unused, int Rd, int Rm)
-{
-    mArmPC[mInum++] = pc();
-    mMips->CLZ(Rd, Rm);
-}
-
-void ArmToMipsAssembler::QADD(int cc __unused,  int Rd __unused,
-                              int Rm __unused, int Rn __unused)
-{
-    // *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::QDADD(int cc __unused,  int Rd __unused,
-                               int Rm __unused, int Rn __unused)
-{
-    // *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::QSUB(int cc __unused,  int Rd __unused,
-                              int Rm __unused, int Rn __unused)
-{
-    // *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::QDSUB(int cc __unused,  int Rd __unused,
-                               int Rm __unused, int Rn __unused)
-{
-    // *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-// 16 x 16 signed multiply (like SMLAxx without the accumulate)
-void ArmToMipsAssembler::SMUL(int cc __unused, int xy,
-                int Rd, int Rm, int Rs)
-{
-    mArmPC[mInum++] = pc();
-
-    // the 16 bits may be in the top or bottom half of 32-bit source reg,
-    // as defined by the codes BB, BT, TB, TT (compressed param xy)
-    // where x corresponds to Rm and y to Rs
-
-    // select half-reg for Rm
-    if (xy & xyTB) {
-        // use top 16-bits
-        mMips->SRA(R_at, Rm, 16);
-    } else {
-        // use bottom 16, but sign-extend to 32
-        if (mips32r2) {
-            mMips->SEH(R_at, Rm);
-        } else {
-            mMips->SLL(R_at, Rm, 16);
-            mMips->SRA(R_at, R_at, 16);
-        }
-    }
-    // select half-reg for Rs
-    if (xy & xyBT) {
-        // use top 16-bits
-        mMips->SRA(R_at2, Rs, 16);
-    } else {
-        // use bottom 16, but sign-extend to 32
-        if (mips32r2) {
-            mMips->SEH(R_at2, Rs);
-        } else {
-            mMips->SLL(R_at2, Rs, 16);
-            mMips->SRA(R_at2, R_at2, 16);
-        }
-    }
-    mMips->MUL(Rd, R_at, R_at2);
-}
-
-// signed 32b x 16b multiple, save top 32-bits of 48-bit result
-void ArmToMipsAssembler::SMULW(int cc __unused, int y,
-                int Rd, int Rm, int Rs)
-{
-    mArmPC[mInum++] = pc();
-
-    // the selector yT or yB refers to reg Rs
-    if (y & yT) {
-        // zero the bottom 16-bits, with 2 shifts, it can affect result
-        mMips->SRL(R_at, Rs, 16);
-        mMips->SLL(R_at, R_at, 16);
-
-    } else {
-        // move low 16-bit half, to high half
-        mMips->SLL(R_at, Rs, 16);
-    }
-    mMips->MULT(Rm, R_at);
-    mMips->MFHI(Rd);
-}
-
-// 16 x 16 signed multiply, accumulate: Rd = Rm{16} * Rs{16} + Rn
-void ArmToMipsAssembler::SMLA(int cc __unused, int xy,
-                int Rd, int Rm, int Rs, int Rn)
-{
-    mArmPC[mInum++] = pc();
-
-    // the 16 bits may be in the top or bottom half of 32-bit source reg,
-    // as defined by the codes BB, BT, TB, TT (compressed param xy)
-    // where x corresponds to Rm and y to Rs
-
-    // select half-reg for Rm
-    if (xy & xyTB) {
-        // use top 16-bits
-        mMips->SRA(R_at, Rm, 16);
-    } else {
-        // use bottom 16, but sign-extend to 32
-        if (mips32r2) {
-            mMips->SEH(R_at, Rm);
-        } else {
-            mMips->SLL(R_at, Rm, 16);
-            mMips->SRA(R_at, R_at, 16);
-        }
-    }
-    // select half-reg for Rs
-    if (xy & xyBT) {
-        // use top 16-bits
-        mMips->SRA(R_at2, Rs, 16);
-    } else {
-        // use bottom 16, but sign-extend to 32
-        if (mips32r2) {
-            mMips->SEH(R_at2, Rs);
-        } else {
-            mMips->SLL(R_at2, Rs, 16);
-            mMips->SRA(R_at2, R_at2, 16);
-        }
-    }
-
-    mMips->MUL(R_at, R_at, R_at2);
-    mMips->ADDU(Rd, R_at, Rn);
-}
-
-void ArmToMipsAssembler::SMLAL(int cc __unused, int xy __unused,
-                               int RdHi __unused, int RdLo __unused,
-                               int Rs __unused, int Rm __unused)
-{
-    // *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::SMLAW(int cc __unused, int y __unused,
-                               int Rd __unused, int Rm __unused,
-                               int Rs __unused, int Rn __unused)
-{
-    // *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm;
-    mArmPC[mInum++] = pc();
-    mMips->NOP2();
-    NOT_IMPLEMENTED();
-}
-
-// used by ARMv6 version of GGLAssembler::filter32
-void ArmToMipsAssembler::UXTB16(int cc __unused, int Rd, int Rm, int rotate)
-{
-    mArmPC[mInum++] = pc();
-
-    //Rd[31:16] := ZeroExtend((Rm ROR (8 * sh))[23:16]),
-    //Rd[15:0] := ZeroExtend((Rm ROR (8 * sh))[7:0]). sh 0-3.
-
-    mMips->ROTR(Rm, Rm, rotate * 8);
-    mMips->AND(Rd, Rm, 0x00FF00FF);
-}
-
-void ArmToMipsAssembler::UBFX(int cc __unused, int Rd __unused,
-                              int Rn __unused, int lsb __unused,
-                              int width __unused)
-{
-     /* Placeholder for UBFX */
-     mArmPC[mInum++] = pc();
-
-     mMips->NOP2();
-     NOT_IMPLEMENTED();
-}
-
-
-
-
-
-#if 0
-#pragma mark -
-#pragma mark MIPS Assembler...
-#endif
-
-
-//**************************************************************************
-//**************************************************************************
-//**************************************************************************
-
-
-/* mips assembler
-** this is a subset of mips32r2, targeted specifically at ARM instruction
-** replacement in the pixelflinger/codeflinger code.
-**
-** To that end, there is no need for floating point, or priviledged
-** instructions. This all runs in user space, no float.
-**
-** The syntax makes no attempt to be as complete as the assember, with
-** synthetic instructions, and automatic recognition of immedate operands
-** (use the immediate form of the instruction), etc.
-**
-** We start with mips32r1, and may add r2 and dsp extensions if cpu
-** supports. Decision will be made at compile time, based on gcc
-** options. (makes sense since android will be built for a a specific
-** device)
-*/
-
-MIPSAssembler::MIPSAssembler(const sp<Assembly>& assembly, ArmToMipsAssembler *parent)
-    : mParent(parent),
-    mAssembly(assembly)
-{
-    mBase = mPC = (uint32_t *)assembly->base();
-    mDuration = ggl_system_time();
-}
-
-MIPSAssembler::MIPSAssembler(void* assembly)
-    : mParent(NULL), mAssembly(NULL)
-{
-    mBase = mPC = (uint32_t *)assembly;
-}
-
-MIPSAssembler::~MIPSAssembler()
-{
-}
-
-
-uint32_t* MIPSAssembler::pc() const
-{
-    return mPC;
-}
-
-uint32_t* MIPSAssembler::base() const
-{
-    return mBase;
-}
-
-void MIPSAssembler::reset()
-{
-    mBase = mPC = (uint32_t *)mAssembly->base();
-    mBranchTargets.clear();
-    mLabels.clear();
-    mLabelsInverseMapping.clear();
-    mComments.clear();
-}
-
-
-// convert tabs to spaces, and remove any newline
-// works with strings of limited size (makes a temp copy)
-#define TABSTOP 8
-void MIPSAssembler::string_detab(char *s)
-{
-    char *os = s;
-    char temp[100];
-    char *t = temp;
-    int len = 99;
-    int i = TABSTOP;
-
-    while (*s && len-- > 0) {
-        if (*s == '\n') { s++; continue; }
-        if (*s == '\t') {
-            s++;
-            for ( ; i>0; i--) {*t++ = ' '; len--; }
-        } else {
-            *t++ = *s++;
-        }
-        if (i <= 0) i = TABSTOP;
-        i--;
-    }
-    *t = '\0';
-    strcpy(os, temp);
-}
-
-void MIPSAssembler::string_pad(char *s, int padded_len)
-{
-    int len = strlen(s);
-    s += len;
-    for (int i = padded_len - len; i > 0; --i) {
-        *s++ = ' ';
-    }
-    *s = '\0';
-}
-
-// ----------------------------------------------------------------------------
-
-void MIPSAssembler::disassemble(const char* name)
-{
-    char di_buf[140];
-
-    if (name) {
-        ALOGW("%s:\n", name);
-    }
-
-    bool arm_disasm_fmt = (mParent->mArmDisassemblyBuffer == NULL) ? false : true;
-
-    typedef char dstr[40];
-    dstr *lines = (dstr *)mParent->mArmDisassemblyBuffer;
-
-    if (mParent->mArmDisassemblyBuffer != NULL) {
-        for (int i=0; i<mParent->mArmInstrCount; ++i) {
-            string_detab(lines[i]);
-        }
-    }
-
-    size_t count = pc()-base();
-    uint32_t* mipsPC = base();
-    while (count--) {
-        ssize_t label = mLabelsInverseMapping.indexOfKey(mipsPC);
-        if (label >= 0) {
-            ALOGW("%s:\n", mLabelsInverseMapping.valueAt(label));
-        }
-        ssize_t comment = mComments.indexOfKey(mipsPC);
-        if (comment >= 0) {
-            ALOGW("; %s\n", mComments.valueAt(comment));
-        }
-        // ALOGW("%08x:    %08x    ", int(i), int(i[0]));
-        ::mips_disassem(mipsPC, di_buf, arm_disasm_fmt);
-        string_detab(di_buf);
-        string_pad(di_buf, 30);
-        ALOGW("0x%p:    %08x    %s", mipsPC, uint32_t(*mipsPC), di_buf);
-        mipsPC++;
-    }
-}
-
-void MIPSAssembler::comment(const char* string)
-{
-    mComments.add(pc(), string);
-}
-
-void MIPSAssembler::label(const char* theLabel)
-{
-    mLabels.add(theLabel, pc());
-    mLabelsInverseMapping.add(pc(), theLabel);
-}
-
-
-void MIPSAssembler::prolog()
-{
-    // empty - done in ArmToMipsAssembler
-}
-
-void MIPSAssembler::epilog(uint32_t touched __unused)
-{
-    // empty - done in ArmToMipsAssembler
-}
-
-int MIPSAssembler::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+1));
-        *bt.pc |= offset & 0x00FFFF;
-    }
-
-    mAssembly->resize( int(pc()-base())*4 );
-
-    // the instruction & data caches are flushed by CodeCache
-    const int64_t duration = ggl_system_time() - mDuration;
-    const char * const format = "generated %s (%d ins) at [%p:%p] in %" PRId64 " ns\n";
-    ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
-
-    char value[PROPERTY_VALUE_MAX];
-    value[0] = '\0';
-
-    property_get("debug.pf.disasm", value, "0");
-
-    if (atoi(value) != 0) {
-        disassemble(name);
-    }
-
-    return OK;
-}
-
-uint32_t* MIPSAssembler::pcForLabel(const char* label)
-{
-    return mLabels.valueFor(label);
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Arithmetic...
-#endif
-
-void MIPSAssembler::ADDU(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (addu_fn<<FUNC_SHF)
-                    | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF);
-}
-
-// MD00086 pdf says this is: ADDIU rt, rs, imm -- they do not use Rd
-void MIPSAssembler::ADDIU(int Rt, int Rs, int16_t imm)
-{
-    *mPC++ = (addiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-
-void MIPSAssembler::SUBU(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (subu_fn<<FUNC_SHF) |
-                        (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
-}
-
-
-void MIPSAssembler::SUBIU(int Rt, int Rs, int16_t imm)   // really addiu(d, s, -j)
-{
-    *mPC++ = (addiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | ((-imm) & MSK_16);
-}
-
-
-void MIPSAssembler::NEGU(int Rd, int Rs)    // really subu(d, zero, s)
-{
-    MIPSAssembler::SUBU(Rd, 0, Rs);
-}
-
-void MIPSAssembler::MUL(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec2_op<<OP_SHF) | (mul_fn<<FUNC_SHF) |
-                        (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
-}
-
-void MIPSAssembler::MULT(int Rs, int Rt)    // dest is hi,lo
-{
-    *mPC++ = (spec_op<<OP_SHF) | (mult_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
-}
-
-void MIPSAssembler::MULTU(int Rs, int Rt)    // dest is hi,lo
-{
-    *mPC++ = (spec_op<<OP_SHF) | (multu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
-}
-
-void MIPSAssembler::MADD(int Rs, int Rt)    // hi,lo = hi,lo + Rs * Rt
-{
-    *mPC++ = (spec2_op<<OP_SHF) | (madd_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
-}
-
-void MIPSAssembler::MADDU(int Rs, int Rt)    // hi,lo = hi,lo + Rs * Rt
-{
-    *mPC++ = (spec2_op<<OP_SHF) | (maddu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
-}
-
-
-void MIPSAssembler::MSUB(int Rs, int Rt)    // hi,lo = hi,lo - Rs * Rt
-{
-    *mPC++ = (spec2_op<<OP_SHF) | (msub_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
-}
-
-void MIPSAssembler::MSUBU(int Rs, int Rt)    // hi,lo = hi,lo - Rs * Rt
-{
-    *mPC++ = (spec2_op<<OP_SHF) | (msubu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
-}
-
-
-void MIPSAssembler::SEB(int Rd, int Rt)    // sign-extend byte (mips32r2)
-{
-    *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (seb_fn << SA_SHF) |
-                    (Rt<<RT_SHF) | (Rd<<RD_SHF);
-}
-
-void MIPSAssembler::SEH(int Rd, int Rt)    // sign-extend half-word (mips32r2)
-{
-    *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (seh_fn << SA_SHF) |
-                    (Rt<<RT_SHF) | (Rd<<RD_SHF);
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Comparisons...
-#endif
-
-void MIPSAssembler::SLT(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (slt_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::SLTI(int Rt, int Rs, int16_t imm)
-{
-    *mPC++ = (slti_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-
-void MIPSAssembler::SLTU(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (sltu_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::SLTIU(int Rt, int Rs, int16_t imm)
-{
-    *mPC++ = (sltiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Logical...
-#endif
-
-void MIPSAssembler::AND(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (and_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::ANDI(int Rt, int Rs, uint16_t imm)      // todo: support larger immediate
-{
-    *mPC++ = (andi_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-
-void MIPSAssembler::OR(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (or_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::ORI(int Rt, int Rs, uint16_t imm)
-{
-    *mPC++ = (ori_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-void MIPSAssembler::NOR(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (nor_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::NOT(int Rd, int Rs)
-{
-    MIPSAssembler::NOR(Rd, Rs, 0);  // NOT(d,s) = NOR(d,s,zero)
-}
-
-void MIPSAssembler::XOR(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (xor_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::XORI(int Rt, int Rs, uint16_t imm)  // todo: support larger immediate
-{
-    *mPC++ = (xori_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-void MIPSAssembler::SLL(int Rd, int Rt, int shft)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
-}
-
-void MIPSAssembler::SLLV(int Rd, int Rt, int Rs)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (sllv_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::SRL(int Rd, int Rt, int shft)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (srl_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
-}
-
-void MIPSAssembler::SRLV(int Rd, int Rt, int Rs)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (srlv_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::SRA(int Rd, int Rt, int shft)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (sra_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
-}
-
-void MIPSAssembler::SRAV(int Rd, int Rt, int Rs)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (srav_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::ROTR(int Rd, int Rt, int shft)      // mips32r2
-{
-    // note weird encoding (SRL + 1)
-    *mPC++ = (spec_op<<OP_SHF) | (srl_fn<<FUNC_SHF) |
-                        (1<<RS_SHF) | (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
-}
-
-void MIPSAssembler::ROTRV(int Rd, int Rt, int Rs)       // mips32r2
-{
-    // note weird encoding (SRLV + 1)
-    *mPC++ = (spec_op<<OP_SHF) | (srlv_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (1<<RE_SHF);
-}
-
-// uses at2 register (mapped to some appropriate mips reg)
-void MIPSAssembler::RORsyn(int Rd, int Rt, int Rs)
-{
-    // synthetic: d = t rotated by s
-    MIPSAssembler::NEGU(R_at2, Rs);
-    MIPSAssembler::SLLV(R_at2, Rt, R_at2);
-    MIPSAssembler::SRLV(Rd, Rt, Rs);
-    MIPSAssembler::OR(Rd, Rd, R_at2);
-}
-
-// immediate version - uses at2 register (mapped to some appropriate mips reg)
-void MIPSAssembler::RORIsyn(int Rd, int Rt, int rot)
-{
-    // synthetic: d = t rotated by immed rot
-    // d = s >> rot | s << (32-rot)
-    MIPSAssembler::SLL(R_at2, Rt, 32-rot);
-    MIPSAssembler::SRL(Rd, Rt, rot);
-    MIPSAssembler::OR(Rd, Rd, R_at2);
-}
-
-void MIPSAssembler::CLO(int Rd, int Rs)
-{
-    // Rt field must have same gpr # as Rd
-    *mPC++ = (spec2_op<<OP_SHF) | (clo_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rd<<RT_SHF);
-}
-
-void MIPSAssembler::CLZ(int Rd, int Rs)
-{
-    // Rt field must have same gpr # as Rd
-    *mPC++ = (spec2_op<<OP_SHF) | (clz_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rd<<RT_SHF);
-}
-
-void MIPSAssembler::WSBH(int Rd, int Rt)      // mips32r2
-{
-    *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (wsbh_fn << SA_SHF) |
-                        (Rt<<RT_SHF) | (Rd<<RD_SHF);
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Load/store...
-#endif
-
-void MIPSAssembler::LW(int Rt, int Rbase, int16_t offset)
-{
-    *mPC++ = (lw_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPSAssembler::SW(int Rt, int Rbase, int16_t offset)
-{
-    *mPC++ = (sw_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-// lb is sign-extended
-void MIPSAssembler::LB(int Rt, int Rbase, int16_t offset)
-{
-    *mPC++ = (lb_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPSAssembler::LBU(int Rt, int Rbase, int16_t offset)
-{
-    *mPC++ = (lbu_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPSAssembler::SB(int Rt, int Rbase, int16_t offset)
-{
-    *mPC++ = (sb_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-// lh is sign-extended
-void MIPSAssembler::LH(int Rt, int Rbase, int16_t offset)
-{
-    *mPC++ = (lh_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPSAssembler::LHU(int Rt, int Rbase, int16_t offset)
-{
-    *mPC++ = (lhu_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPSAssembler::SH(int Rt, int Rbase, int16_t offset)
-{
-    *mPC++ = (sh_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPSAssembler::LUI(int Rt, int16_t offset)
-{
-    *mPC++ = (lui_op<<OP_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Register move...
-#endif
-
-void MIPSAssembler::MOVE(int Rd, int Rs)
-{
-    // encoded as "or rd, rs, zero"
-    *mPC++ = (spec_op<<OP_SHF) | (or_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (0<<RT_SHF);
-}
-
-void MIPSAssembler::MOVN(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (movn_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::MOVZ(int Rd, int Rs, int Rt)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (movz_fn<<FUNC_SHF) |
-                        (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::MFHI(int Rd)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (mfhi_fn<<FUNC_SHF) | (Rd<<RD_SHF);
-}
-
-void MIPSAssembler::MFLO(int Rd)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (mflo_fn<<FUNC_SHF) | (Rd<<RD_SHF);
-}
-
-void MIPSAssembler::MTHI(int Rs)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (mthi_fn<<FUNC_SHF) | (Rs<<RS_SHF);
-}
-
-void MIPSAssembler::MTLO(int Rs)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (mtlo_fn<<FUNC_SHF) | (Rs<<RS_SHF);
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Branch...
-#endif
-
-// temporarily forcing a NOP into branch-delay slot, just to be safe
-// todo: remove NOP, optimze use of delay slots
-void MIPSAssembler::B(const char* label)
-{
-    mBranchTargets.add(branch_target_t(label, mPC));
-
-    // encoded as BEQ zero, zero, offset
-    *mPC++ = (beq_op<<OP_SHF) | (0<<RT_SHF)
-                        | (0<<RS_SHF) | 0;  // offset filled in later
-
-    MIPSAssembler::NOP();
-}
-
-void MIPSAssembler::BEQ(int Rs, int Rt, const char* label)
-{
-    mBranchTargets.add(branch_target_t(label, mPC));
-    *mPC++ = (beq_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | 0;
-    MIPSAssembler::NOP();
-}
-
-void MIPSAssembler::BNE(int Rs, int Rt, const char* label)
-{
-    mBranchTargets.add(branch_target_t(label, mPC));
-    *mPC++ = (bne_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | 0;
-    MIPSAssembler::NOP();
-}
-
-void MIPSAssembler::BLEZ(int Rs, const char* label)
-{
-    mBranchTargets.add(branch_target_t(label, mPC));
-    *mPC++ = (blez_op<<OP_SHF) | (0<<RT_SHF) | (Rs<<RS_SHF) | 0;
-    MIPSAssembler::NOP();
-}
-
-void MIPSAssembler::BLTZ(int Rs, const char* label)
-{
-    mBranchTargets.add(branch_target_t(label, mPC));
-    *mPC++ = (regimm_op<<OP_SHF) | (bltz_fn<<RT_SHF) | (Rs<<RS_SHF) | 0;
-    MIPSAssembler::NOP();
-}
-
-void MIPSAssembler::BGTZ(int Rs, const char* label)
-{
-    mBranchTargets.add(branch_target_t(label, mPC));
-    *mPC++ = (bgtz_op<<OP_SHF) | (0<<RT_SHF) | (Rs<<RS_SHF) | 0;
-    MIPSAssembler::NOP();
-}
-
-
-void MIPSAssembler::BGEZ(int Rs, const char* label)
-{
-    mBranchTargets.add(branch_target_t(label, mPC));
-    *mPC++ = (regimm_op<<OP_SHF) | (bgez_fn<<RT_SHF) | (Rs<<RS_SHF) | 0;
-    MIPSAssembler::NOP();
-}
-
-void MIPSAssembler::JR(int Rs)
-{
-    *mPC++ = (spec_op<<OP_SHF) | (Rs<<RS_SHF) | (jr_fn << FUNC_SHF);
-    MIPSAssembler::NOP();
-}
-
-
-#if 0
-#pragma mark -
-#pragma mark Synthesized Branch...
-#endif
-
-// synthetic variants of branches (using slt & friends)
-void MIPSAssembler::BEQZ(int Rs, const char* label)
-{
-    BEQ(Rs, R_zero, label);
-}
-
-void MIPSAssembler::BNEZ(int Rs __unused, const char* label)
-{
-    BNE(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BGE(int Rs, int Rt, const char* label)
-{
-    SLT(R_at, Rs, Rt);
-    BEQ(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BGEU(int Rs, int Rt, const char* label)
-{
-    SLTU(R_at, Rs, Rt);
-    BEQ(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BGT(int Rs, int Rt, const char* label)
-{
-    SLT(R_at, Rt, Rs);   // rev
-    BNE(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BGTU(int Rs, int Rt, const char* label)
-{
-    SLTU(R_at, Rt, Rs);   // rev
-    BNE(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BLE(int Rs, int Rt, const char* label)
-{
-    SLT(R_at, Rt, Rs);   // rev
-    BEQ(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BLEU(int Rs, int Rt, const char* label)
-{
-    SLTU(R_at, Rt, Rs);  // rev
-    BEQ(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BLT(int Rs, int Rt, const char* label)
-{
-    SLT(R_at, Rs, Rt);
-    BNE(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BLTU(int Rs, int Rt, const char* label)
-{
-    SLTU(R_at, Rs, Rt);
-    BNE(R_at, R_zero, label);
-}
-
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Misc...
-#endif
-
-void MIPSAssembler::NOP(void)
-{
-    // encoded as "sll zero, zero, 0", which is all zero
-    *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF);
-}
-
-// using this as special opcode for not-yet-implemented ARM instruction
-void MIPSAssembler::NOP2(void)
-{
-    // encoded as "sll zero, zero, 2", still a nop, but a unique code
-    *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) | (2 << RE_SHF);
-}
-
-// using this as special opcode for purposefully NOT implemented ARM instruction
-void MIPSAssembler::UNIMPL(void)
-{
-    // encoded as "sll zero, zero, 3", still a nop, but a unique code
-    *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) | (3 << RE_SHF);
-}
-
-
-}; // namespace android:
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.h b/libpixelflinger/codeflinger/MIPSAssembler.h
deleted file mode 100644
index c1178b6..0000000
--- a/libpixelflinger/codeflinger/MIPSAssembler.h
+++ /dev/null
@@ -1,557 +0,0 @@
-/* libs/pixelflinger/codeflinger/MIPSAssembler.h
-**
-** Copyright 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_MIPSASSEMBLER_H
-#define ANDROID_MIPSASSEMBLER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "tinyutils/smartpointer.h"
-#include "utils/KeyedVector.h"
-#include "utils/Vector.h"
-
-#include "ARMAssemblerInterface.h"
-#include "CodeCache.h"
-
-namespace android {
-
-class MIPSAssembler;    // forward reference
-
-// this class mimics ARMAssembler interface
-//  intent is to translate each ARM instruction to 1 or more MIPS instr
-//  implementation calls MIPSAssembler class to generate mips code
-class ArmToMipsAssembler : public ARMAssemblerInterface
-{
-public:
-                ArmToMipsAssembler(const sp<Assembly>& assembly,
-                        char *abuf = 0, int linesz = 0, int instr_count = 0);
-    virtual     ~ArmToMipsAssembler();
-
-    uint32_t*   base() const;
-    uint32_t*   pc() const;
-    void        disassemble(const char* name);
-
-    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...
-    // LDR(B)/STR(B)/PLD
-    // (immediate and Rm can be negative, which indicates U=0)
-    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);
-
-    // LDRH/LDRSB/LDRSH/STRH
-    // (immediate and Rm can be negative, which indicates U=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 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);
-
-    // byte/half word extract...
-    virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
-
-    // bit manipulation...
-    virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
-
-    // this is some crap to share is MIPSAssembler class for debug
-    char *      mArmDisassemblyBuffer;
-    int         mArmLineLength;
-    int         mArmInstrCount;
-
-    int         mInum;      // current arm instuction number (0..n)
-    uint32_t**  mArmPC;     // array: PC for 1st mips instr of
-                            //      each translated ARM instr
-
-
-private:
-    ArmToMipsAssembler(const ArmToMipsAssembler& rhs);
-    ArmToMipsAssembler& operator = (const ArmToMipsAssembler& rhs);
-
-    void init_conditional_labels(void);
-
-    void protectConditionalOperands(int Rd);
-
-    // reg__tmp set to MIPS AT, reg 1
-    int dataProcAdrModes(int op, int& source, bool sign = false, int reg_tmp = 1);
-
-    sp<Assembly>        mAssembly;
-    MIPSAssembler*      mMips;
-
-
-    enum misc_constants_t {
-        ARM_MAX_INSTUCTIONS = 512  // based on ASSEMBLY_SCRATCH_SIZE
-    };
-
-    enum {
-        SRC_REG = 0,
-        SRC_IMM,
-        SRC_ERROR = -1
-    };
-
-    enum addr_modes {
-        // start above the range of legal mips reg #'s (0-31)
-        AMODE_REG = 0x20,
-        AMODE_IMM, AMODE_REG_IMM,               // for data processing
-        AMODE_IMM_12_PRE, AMODE_IMM_12_POST,    // for load/store
-        AMODE_REG_SCALE_PRE, AMODE_IMM_8_PRE,
-        AMODE_IMM_8_POST, AMODE_REG_PRE,
-        AMODE_UNSUPPORTED
-    };
-
-    struct addr_mode_t {    // address modes for current ARM instruction
-        int         reg;
-        int         stype;
-        uint32_t    value;
-        bool        writeback;  // writeback the adr reg after modification
-    } amode;
-
-    enum cond_types {
-        CMP_COND = 1,
-        SBIT_COND
-    };
-
-    struct cond_mode_t {    // conditional-execution info for current ARM instruction
-        cond_types  type;
-        int         r1;
-        int         r2;
-        int         labelnum;
-        char        label[100][10];
-    } cond;
-
-};
-
-
-
-
-// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
-
-// This is the basic MIPS assembler, which just creates the opcodes in memory.
-// All the more complicated work is done in ArmToMipsAssember above.
-
-class MIPSAssembler
-{
-public:
-                MIPSAssembler(const sp<Assembly>& assembly, ArmToMipsAssembler *parent);
-                MIPSAssembler(void* assembly);
-    virtual     ~MIPSAssembler();
-
-    virtual uint32_t*   base() const;
-    virtual uint32_t*   pc() const;
-    virtual void        reset();
-
-    virtual void        disassemble(const char* name);
-
-    virtual void        prolog();
-    virtual void        epilog(uint32_t touched);
-    virtual int         generate(const char* name);
-    virtual void        comment(const char* string);
-    virtual void        label(const char* string);
-
-    // valid only after generate() has been called
-    virtual uint32_t*   pcForLabel(const char* label);
-
-
-    // ------------------------------------------------------------------------
-    // MIPSAssemblerInterface...
-    // ------------------------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Arithmetic...
-#endif
-
-    void ADDU(int Rd, int Rs, int Rt);
-    void ADDIU(int Rt, int Rs, int16_t imm);
-    void SUBU(int Rd, int Rs, int Rt);
-    void SUBIU(int Rt, int Rs, int16_t imm);
-    void NEGU(int Rd, int Rs);
-    void MUL(int Rd, int Rs, int Rt);
-    void MULT(int Rs, int Rt);      // dest is hi,lo
-    void MULTU(int Rs, int Rt);     // dest is hi,lo
-    void MADD(int Rs, int Rt);      // hi,lo = hi,lo + Rs * Rt
-    void MADDU(int Rs, int Rt);     // hi,lo = hi,lo + Rs * Rt
-    void MSUB(int Rs, int Rt);      // hi,lo = hi,lo - Rs * Rt
-    void MSUBU(int Rs, int Rt);     // hi,lo = hi,lo - Rs * Rt
-    void SEB(int Rd, int Rt);       // sign-extend byte (mips32r2)
-    void SEH(int Rd, int Rt);       // sign-extend half-word (mips32r2)
-
-
-#if 0
-#pragma mark -
-#pragma mark Comparisons...
-#endif
-
-    void SLT(int Rd, int Rs, int Rt);
-    void SLTI(int Rt, int Rs, int16_t imm);
-    void SLTU(int Rd, int Rs, int Rt);
-    void SLTIU(int Rt, int Rs, int16_t imm);
-
-
-#if 0
-#pragma mark -
-#pragma mark Logical...
-#endif
-
-    void AND(int Rd, int Rs, int Rt);
-    void ANDI(int Rd, int Rs, uint16_t imm);
-    void OR(int Rd, int Rs, int Rt);
-    void ORI(int Rt, int Rs, uint16_t imm);
-    void NOR(int Rd, int Rs, int Rt);
-    void NOT(int Rd, int Rs);
-    void XOR(int Rd, int Rs, int Rt);
-    void XORI(int Rt, int Rs, uint16_t imm);
-
-    void SLL(int Rd, int Rt, int shft);
-    void SLLV(int Rd, int Rt, int Rs);
-    void SRL(int Rd, int Rt, int shft);
-    void SRLV(int Rd, int Rt, int Rs);
-    void SRA(int Rd, int Rt, int shft);
-    void SRAV(int Rd, int Rt, int Rs);
-    void ROTR(int Rd, int Rt, int shft);    // mips32r2
-    void ROTRV(int Rd, int Rt, int Rs);     // mips32r2
-    void RORsyn(int Rd, int Rs, int Rt);    // synthetic: d = s rotated by t
-    void RORIsyn(int Rd, int Rt, int rot);  // synthetic: d = s rotated by immed
-
-    void CLO(int Rd, int Rs);
-    void CLZ(int Rd, int Rs);
-    void WSBH(int Rd, int Rt);
-
-
-#if 0
-#pragma mark -
-#pragma mark Load/store...
-#endif
-
-    void LW(int Rt, int Rbase, int16_t offset);
-    void SW(int Rt, int Rbase, int16_t offset);
-    void LB(int Rt, int Rbase, int16_t offset);
-    void LBU(int Rt, int Rbase, int16_t offset);
-    void SB(int Rt, int Rbase, int16_t offset);
-    void LH(int Rt, int Rbase, int16_t offset);
-    void LHU(int Rt, int Rbase, int16_t offset);
-    void SH(int Rt, int Rbase, int16_t offset);
-    void LUI(int Rt, int16_t offset);
-
-#if 0
-#pragma mark -
-#pragma mark Register moves...
-#endif
-
-    void MOVE(int Rd, int Rs);
-    void MOVN(int Rd, int Rs, int Rt);
-    void MOVZ(int Rd, int Rs, int Rt);
-    void MFHI(int Rd);
-    void MFLO(int Rd);
-    void MTHI(int Rs);
-    void MTLO(int Rs);
-
-#if 0
-#pragma mark -
-#pragma mark Branch...
-#endif
-
-    void B(const char* label);
-    void BEQ(int Rs, int Rt, const char* label);
-    void BNE(int Rs, int Rt, const char* label);
-    void BGEZ(int Rs, const char* label);
-    void BGTZ(int Rs, const char* label);
-    void BLEZ(int Rs, const char* label);
-    void BLTZ(int Rs, const char* label);
-    void JR(int Rs);
-
-
-#if 0
-#pragma mark -
-#pragma mark Synthesized Branch...
-#endif
-
-    // synthetic variants of above (using slt & friends)
-    void BEQZ(int Rs, const char* label);
-    void BNEZ(int Rs, const char* label);
-    void BGE(int Rs, int Rt, const char* label);
-    void BGEU(int Rs, int Rt, const char* label);
-    void BGT(int Rs, int Rt, const char* label);
-    void BGTU(int Rs, int Rt, const char* label);
-    void BLE(int Rs, int Rt, const char* label);
-    void BLEU(int Rs, int Rt, const char* label);
-    void BLT(int Rs, int Rt, const char* label);
-    void BLTU(int Rs, int Rt, const char* label);
-
-#if 0
-#pragma mark -
-#pragma mark Misc...
-#endif
-
-    void NOP(void);
-    void NOP2(void);
-    void UNIMPL(void);
-
-
-
-
-
-protected:
-    virtual void string_detab(char *s);
-    virtual void string_pad(char *s, int padded_len);
-
-    ArmToMipsAssembler *mParent;
-    sp<Assembly>    mAssembly;
-    uint32_t*       mBase;
-    uint32_t*       mPC;
-    uint32_t*       mPrologPC;
-    int64_t         mDuration;
-
-    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;
-    };
-
-    Vector<branch_target_t>                 mBranchTargets;
-    KeyedVector< const char*, uint32_t* >   mLabels;
-    KeyedVector< uint32_t*, const char* >   mLabelsInverseMapping;
-    KeyedVector< uint32_t*, const char* >   mComments;
-
-
-
-
-    // opcode field of all instructions
-    enum opcode_field {
-        spec_op, regimm_op, j_op, jal_op,           // 00
-        beq_op, bne_op, blez_op, bgtz_op,
-        addi_op, addiu_op, slti_op, sltiu_op,       // 08
-        andi_op, ori_op, xori_op, lui_op,
-        cop0_op, cop1_op, cop2_op, cop1x_op,        // 10
-        beql_op, bnel_op, blezl_op, bgtzl_op,
-        daddi_op, daddiu_op, ldl_op, ldr_op,        // 18
-        spec2_op, jalx_op, mdmx_op, spec3_op,
-        lb_op, lh_op, lwl_op, lw_op,                // 20
-        lbu_op, lhu_op, lwr_op, lwu_op,
-        sb_op, sh_op, swl_op, sw_op,                // 28
-        sdl_op, sdr_op, swr_op, cache_op,
-        ll_op, lwc1_op, lwc2_op, pref_op,           // 30
-        lld_op, ldc1_op, ldc2_op, ld_op,
-        sc_op, swc1_op, swc2_op, rsrv_3b_op,        // 38
-        scd_op, sdc1_op, sdc2_op, sd_op
-    };
-
-
-    // func field for special opcode
-    enum func_spec_op {
-        sll_fn, movc_fn, srl_fn, sra_fn,            // 00
-        sllv_fn, pmon_fn, srlv_fn, srav_fn,
-        jr_fn, jalr_fn, movz_fn, movn_fn,           // 08
-        syscall_fn, break_fn, spim_fn, sync_fn,
-        mfhi_fn, mthi_fn, mflo_fn, mtlo_fn,         // 10
-        dsllv_fn, rsrv_spec_2, dsrlv_fn, dsrav_fn,
-        mult_fn, multu_fn, div_fn, divu_fn,         // 18
-        dmult_fn, dmultu_fn, ddiv_fn, ddivu_fn,
-        add_fn, addu_fn, sub_fn, subu_fn,           // 20
-        and_fn, or_fn, xor_fn, nor_fn,
-        rsrv_spec_3, rsrv_spec_4, slt_fn, sltu_fn,  // 28
-        dadd_fn, daddu_fn, dsub_fn, dsubu_fn,
-        tge_fn, tgeu_fn, tlt_fn, tltu_fn,           // 30
-        teq_fn, rsrv_spec_5, tne_fn, rsrv_spec_6,
-        dsll_fn, rsrv_spec_7, dsrl_fn, dsra_fn,     // 38
-        dsll32_fn, rsrv_spec_8, dsrl32_fn, dsra32_fn
-    };
-
-    // func field for spec2 opcode
-    enum func_spec2_op {
-        madd_fn, maddu_fn, mul_fn, rsrv_spec2_3,
-        msub_fn, msubu_fn,
-        clz_fn = 0x20, clo_fn,
-        dclz_fn = 0x24, dclo_fn,
-        sdbbp_fn = 0x3f
-    };
-
-    // func field for spec3 opcode
-    enum func_spec3_op {
-        ext_fn, dextm_fn, dextu_fn, dext_fn,
-        ins_fn, dinsm_fn, dinsu_fn, dins_fn,
-        bshfl_fn = 0x20,
-        dbshfl_fn = 0x24,
-        rdhwr_fn = 0x3b
-    };
-
-    // sa field for spec3 opcodes, with BSHFL function
-    enum func_spec3_bshfl {
-        wsbh_fn = 0x02,
-        seb_fn = 0x10,
-        seh_fn = 0x18
-    };
-
-    // rt field of regimm opcodes.
-    enum regimm_fn {
-        bltz_fn, bgez_fn, bltzl_fn, bgezl_fn,
-        rsrv_ri_fn4, rsrv_ri_fn5, rsrv_ri_fn6, rsrv_ri_fn7,
-        tgei_fn, tgeiu_fn, tlti_fn, tltiu_fn,
-        teqi_fn, rsrv_ri_fn_0d, tnei_fn, rsrv_ri_fn0f,
-        bltzal_fn, bgezal_fn, bltzall_fn, bgezall_fn,
-        bposge32_fn= 0x1c,
-        synci_fn = 0x1f
-    };
-
-
-    // func field for mad opcodes (MIPS IV).
-    enum mad_func {
-        madd_fp_op      = 0x08, msub_fp_op      = 0x0a,
-        nmadd_fp_op     = 0x0c, nmsub_fp_op     = 0x0e
-    };
-
-
-    enum mips_inst_shifts {
-        OP_SHF       = 26,
-        JTARGET_SHF  = 0,
-        RS_SHF       = 21,
-        RT_SHF       = 16,
-        RD_SHF       = 11,
-        RE_SHF       = 6,
-        SA_SHF       = RE_SHF,  // synonym
-        IMM_SHF      = 0,
-        FUNC_SHF     = 0,
-
-        // mask values
-        MSK_16       = 0xffff,
-
-
-        CACHEOP_SHF  = 18,
-        CACHESEL_SHF = 16,
-    };
-};
-
-enum mips_regnames {
-    R_zero = 0,
-            R_at,   R_v0,   R_v1,   R_a0,   R_a1,   R_a2,   R_a3,
-#if __mips_isa_rev < 6
-    R_t0,   R_t1,   R_t2,   R_t3,   R_t4,   R_t5,   R_t6,   R_t7,
-#else
-    R_a4,   R_a5,   R_a6,   R_a7,   R_t0,   R_t1,   R_t2,   R_t3,
-#endif
-    R_s0,   R_s1,   R_s2,   R_s3,   R_s4,   R_s5,   R_s6,   R_s7,
-    R_t8,   R_t9,   R_k0,   R_k1,   R_gp,   R_sp,   R_s8,   R_ra,
-    R_lr = R_s8,
-
-    // arm regs 0-15 are mips regs 2-17 (meaning s0 & s1 are used)
-    R_at2  = R_s2,    // R_at2 = 18 = s2
-    R_cmp  = R_s3,    // R_cmp = 19 = s3
-    R_cmp2 = R_s4     // R_cmp2 = 20 = s4
-};
-
-
-
-}; // namespace android
-
-#endif //ANDROID_MIPSASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/armreg.h b/libpixelflinger/codeflinger/armreg.h
deleted file mode 100644
index fde81ba..0000000
--- a/libpixelflinger/codeflinger/armreg.h
+++ /dev/null
@@ -1,300 +0,0 @@
-/*	$NetBSD: armreg.h,v 1.28 2003/10/31 16:30:15 scw Exp $	*/
-
-/*-
- * Copyright (c) 1998, 2001 Ben Harris
- * Copyright (c) 1994-1996 Mark Brinicombe.
- * Copyright (c) 1994 Brini.
- * All rights reserved.
- *
- * This code is derived from software written for Brini by Mark Brinicombe
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by Brini.
- * 4. The name of the company nor the name of the author may be used to
- *    endorse or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY BRINI ``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 BRINI 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.
- *
- * $FreeBSD: /repoman/r/ncvs/src/sys/arm/include/armreg.h,v 1.3 2005/11/21 19:06:25 cognet Exp $
- */
-
-#ifndef MACHINE_ARMREG_H
-#define MACHINE_ARMREG_H
-#define INSN_SIZE	4
-#define INSN_COND_MASK	0xf0000000	/* Condition mask */
-#define PSR_MODE        0x0000001f      /* mode mask */
-#define PSR_USR26_MODE  0x00000000
-#define PSR_FIQ26_MODE  0x00000001
-#define PSR_IRQ26_MODE  0x00000002
-#define PSR_SVC26_MODE  0x00000003
-#define PSR_USR32_MODE  0x00000010
-#define PSR_FIQ32_MODE  0x00000011
-#define PSR_IRQ32_MODE  0x00000012
-#define PSR_SVC32_MODE  0x00000013
-#define PSR_ABT32_MODE  0x00000017
-#define PSR_UND32_MODE  0x0000001b
-#define PSR_SYS32_MODE  0x0000001f
-#define PSR_32_MODE     0x00000010
-#define PSR_FLAGS	0xf0000000    /* flags */
-
-#define PSR_C_bit (1 << 29)       /* carry */
-
-/* The high-order byte is always the implementor */
-#define CPU_ID_IMPLEMENTOR_MASK	0xff000000
-#define CPU_ID_ARM_LTD		0x41000000 /* 'A' */
-#define CPU_ID_DEC		0x44000000 /* 'D' */
-#define CPU_ID_INTEL		0x69000000 /* 'i' */
-#define	CPU_ID_TI		0x54000000 /* 'T' */
-
-/* How to decide what format the CPUID is in. */
-#define CPU_ID_ISOLD(x)		(((x) & 0x0000f000) == 0x00000000)
-#define CPU_ID_IS7(x)		(((x) & 0x0000f000) == 0x00007000)
-#define CPU_ID_ISNEW(x)		(!CPU_ID_ISOLD(x) && !CPU_ID_IS7(x))
-
-/* On ARM3 and ARM6, this byte holds the foundry ID. */
-#define CPU_ID_FOUNDRY_MASK	0x00ff0000
-#define CPU_ID_FOUNDRY_VLSI	0x00560000
-
-/* On ARM7 it holds the architecture and variant (sub-model) */
-#define CPU_ID_7ARCH_MASK	0x00800000
-#define CPU_ID_7ARCH_V3		0x00000000
-#define CPU_ID_7ARCH_V4T	0x00800000
-#define CPU_ID_7VARIANT_MASK	0x007f0000
-
-/* On more recent ARMs, it does the same, but in a different format */
-#define CPU_ID_ARCH_MASK	0x000f0000
-#define CPU_ID_ARCH_V3		0x00000000
-#define CPU_ID_ARCH_V4		0x00010000
-#define CPU_ID_ARCH_V4T		0x00020000
-#define CPU_ID_ARCH_V5		0x00030000
-#define CPU_ID_ARCH_V5T		0x00040000
-#define CPU_ID_ARCH_V5TE	0x00050000
-#define CPU_ID_VARIANT_MASK	0x00f00000
-
-/* Next three nybbles are part number */
-#define CPU_ID_PARTNO_MASK	0x0000fff0
-
-/* Intel XScale has sub fields in part number */
-#define CPU_ID_XSCALE_COREGEN_MASK	0x0000e000 /* core generation */
-#define CPU_ID_XSCALE_COREREV_MASK	0x00001c00 /* core revision */
-#define CPU_ID_XSCALE_PRODUCT_MASK	0x000003f0 /* product number */
-
-/* And finally, the revision number. */
-#define CPU_ID_REVISION_MASK	0x0000000f
-
-/* Individual CPUs are probably best IDed by everything but the revision. */
-#define CPU_ID_CPU_MASK		0xfffffff0
-
-/* Fake CPU IDs for ARMs without CP15 */
-#define CPU_ID_ARM2		0x41560200
-#define CPU_ID_ARM250		0x41560250
-
-/* Pre-ARM7 CPUs -- [15:12] == 0 */
-#define CPU_ID_ARM3		0x41560300
-#define CPU_ID_ARM600		0x41560600
-#define CPU_ID_ARM610		0x41560610
-#define CPU_ID_ARM620		0x41560620
-
-/* ARM7 CPUs -- [15:12] == 7 */
-#define CPU_ID_ARM700		0x41007000 /* XXX This is a guess. */
-#define CPU_ID_ARM710		0x41007100
-#define CPU_ID_ARM7500		0x41027100 /* XXX This is a guess. */
-#define CPU_ID_ARM710A		0x41047100 /* inc ARM7100 */
-#define CPU_ID_ARM7500FE	0x41077100
-#define CPU_ID_ARM710T		0x41807100
-#define CPU_ID_ARM720T		0x41807200
-#define CPU_ID_ARM740T8K	0x41807400 /* XXX no MMU, 8KB cache */
-#define CPU_ID_ARM740T4K	0x41817400 /* XXX no MMU, 4KB cache */
-
-/* Post-ARM7 CPUs */
-#define CPU_ID_ARM810		0x41018100
-#define CPU_ID_ARM920T		0x41129200
-#define CPU_ID_ARM920T_ALT	0x41009200
-#define CPU_ID_ARM922T		0x41029220
-#define CPU_ID_ARM940T		0x41029400 /* XXX no MMU */
-#define CPU_ID_ARM946ES		0x41049460 /* XXX no MMU */
-#define	CPU_ID_ARM966ES		0x41049660 /* XXX no MMU */
-#define	CPU_ID_ARM966ESR1	0x41059660 /* XXX no MMU */
-#define CPU_ID_ARM1020E		0x4115a200 /* (AKA arm10 rev 1) */
-#define CPU_ID_ARM1022ES	0x4105a220
-#define CPU_ID_SA110		0x4401a100
-#define CPU_ID_SA1100		0x4401a110
-#define	CPU_ID_TI925T		0x54029250
-#define CPU_ID_SA1110		0x6901b110
-#define CPU_ID_IXP1200		0x6901c120
-#define CPU_ID_80200		0x69052000
-#define CPU_ID_PXA250    	0x69052100 /* sans core revision */
-#define CPU_ID_PXA210    	0x69052120
-#define CPU_ID_PXA250A		0x69052100 /* 1st version Core */
-#define CPU_ID_PXA210A		0x69052120 /* 1st version Core */
-#define CPU_ID_PXA250B		0x69052900 /* 3rd version Core */
-#define CPU_ID_PXA210B		0x69052920 /* 3rd version Core */
-#define CPU_ID_PXA250C		0x69052d00 /* 4th version Core */
-#define CPU_ID_PXA210C		0x69052d20 /* 4th version Core */
-#define	CPU_ID_80321_400	0x69052420
-#define	CPU_ID_80321_600	0x69052430
-#define	CPU_ID_80321_400_B0	0x69052c20
-#define	CPU_ID_80321_600_B0	0x69052c30
-#define	CPU_ID_IXP425_533	0x690541c0
-#define	CPU_ID_IXP425_400	0x690541d0
-#define	CPU_ID_IXP425_266	0x690541f0
-
-/* ARM3-specific coprocessor 15 registers */
-#define ARM3_CP15_FLUSH		1
-#define ARM3_CP15_CONTROL	2
-#define ARM3_CP15_CACHEABLE	3
-#define ARM3_CP15_UPDATEABLE	4
-#define ARM3_CP15_DISRUPTIVE	5	
-
-/* ARM3 Control register bits */
-#define ARM3_CTL_CACHE_ON	0x00000001
-#define ARM3_CTL_SHARED		0x00000002
-#define ARM3_CTL_MONITOR	0x00000004
-
-/*
- * Post-ARM3 CP15 registers:
- *
- *	1	Control register
- *
- *	2	Translation Table Base
- *
- *	3	Domain Access Control
- *
- *	4	Reserved
- *
- *	5	Fault Status
- *
- *	6	Fault Address
- *
- *	7	Cache/write-buffer Control
- *
- *	8	TLB Control
- *
- *	9	Cache Lockdown
- *
- *	10	TLB Lockdown
- *
- *	11	Reserved
- *
- *	12	Reserved
- *
- *	13	Process ID (for FCSE)
- *
- *	14	Reserved
- *
- *	15	Implementation Dependent
- */
-
-/* Some of the definitions below need cleaning up for V3/V4 architectures */
-
-/* CPU control register (CP15 register 1) */
-#define CPU_CONTROL_MMU_ENABLE	0x00000001 /* M: MMU/Protection unit enable */
-#define CPU_CONTROL_AFLT_ENABLE	0x00000002 /* A: Alignment fault enable */
-#define CPU_CONTROL_DC_ENABLE	0x00000004 /* C: IDC/DC enable */
-#define CPU_CONTROL_WBUF_ENABLE 0x00000008 /* W: Write buffer enable */
-#define CPU_CONTROL_32BP_ENABLE 0x00000010 /* P: 32-bit exception handlers */
-#define CPU_CONTROL_32BD_ENABLE 0x00000020 /* D: 32-bit addressing */
-#define CPU_CONTROL_LABT_ENABLE 0x00000040 /* L: Late abort enable */
-#define CPU_CONTROL_BEND_ENABLE 0x00000080 /* B: Big-endian mode */
-#define CPU_CONTROL_SYST_ENABLE 0x00000100 /* S: System protection bit */
-#define CPU_CONTROL_ROM_ENABLE	0x00000200 /* R: ROM protection bit */
-#define CPU_CONTROL_CPCLK	0x00000400 /* F: Implementation defined */
-#define CPU_CONTROL_BPRD_ENABLE 0x00000800 /* Z: Branch prediction enable */
-#define CPU_CONTROL_IC_ENABLE   0x00001000 /* I: IC enable */
-#define CPU_CONTROL_VECRELOC	0x00002000 /* V: Vector relocation */
-#define CPU_CONTROL_ROUNDROBIN	0x00004000 /* RR: Predictable replacement */
-#define CPU_CONTROL_V4COMPAT	0x00008000 /* L4: ARMv4 compat LDR R15 etc */
-
-#define CPU_CONTROL_IDC_ENABLE	CPU_CONTROL_DC_ENABLE
-
-/* XScale Auxillary Control Register (CP15 register 1, opcode2 1) */
-#define	XSCALE_AUXCTL_K		0x00000001 /* dis. write buffer coalescing */
-#define	XSCALE_AUXCTL_P		0x00000002 /* ECC protect page table access */
-#define	XSCALE_AUXCTL_MD_WB_RA	0x00000000 /* mini-D$ wb, read-allocate */
-#define	XSCALE_AUXCTL_MD_WB_RWA	0x00000010 /* mini-D$ wb, read/write-allocate */
-#define	XSCALE_AUXCTL_MD_WT	0x00000020 /* mini-D$ wt, read-allocate */
-#define	XSCALE_AUXCTL_MD_MASK	0x00000030
-
-/* Cache type register definitions */
-#define	CPU_CT_ISIZE(x)		((x) & 0xfff)		/* I$ info */
-#define	CPU_CT_DSIZE(x)		(((x) >> 12) & 0xfff)	/* D$ info */
-#define	CPU_CT_S		(1U << 24)		/* split cache */
-#define	CPU_CT_CTYPE(x)		(((x) >> 25) & 0xf)	/* cache type */
-
-#define	CPU_CT_CTYPE_WT		0	/* write-through */
-#define	CPU_CT_CTYPE_WB1	1	/* write-back, clean w/ read */
-#define	CPU_CT_CTYPE_WB2	2	/* w/b, clean w/ cp15,7 */
-#define	CPU_CT_CTYPE_WB6	6	/* w/b, cp15,7, lockdown fmt A */
-#define	CPU_CT_CTYPE_WB7	7	/* w/b, cp15,7, lockdown fmt B */
-
-#define	CPU_CT_xSIZE_LEN(x)	((x) & 0x3)		/* line size */
-#define	CPU_CT_xSIZE_M		(1U << 2)		/* multiplier */
-#define	CPU_CT_xSIZE_ASSOC(x)	(((x) >> 3) & 0x7)	/* associativity */
-#define	CPU_CT_xSIZE_SIZE(x)	(((x) >> 6) & 0x7)	/* size */
-
-/* Fault status register definitions */
-
-#define FAULT_TYPE_MASK 0x0f
-#define FAULT_USER      0x10
-
-#define FAULT_WRTBUF_0  0x00 /* Vector Exception */
-#define FAULT_WRTBUF_1  0x02 /* Terminal Exception */
-#define FAULT_BUSERR_0  0x04 /* External Abort on Linefetch -- Section */
-#define FAULT_BUSERR_1  0x06 /* External Abort on Linefetch -- Page */
-#define FAULT_BUSERR_2  0x08 /* External Abort on Non-linefetch -- Section */
-#define FAULT_BUSERR_3  0x0a /* External Abort on Non-linefetch -- Page */
-#define FAULT_BUSTRNL1  0x0c /* External abort on Translation -- Level 1 */
-#define FAULT_BUSTRNL2  0x0e /* External abort on Translation -- Level 2 */
-#define FAULT_ALIGN_0   0x01 /* Alignment */
-#define FAULT_ALIGN_1   0x03 /* Alignment */
-#define FAULT_TRANS_S   0x05 /* Translation -- Section */
-#define FAULT_TRANS_P   0x07 /* Translation -- Page */
-#define FAULT_DOMAIN_S  0x09 /* Domain -- Section */
-#define FAULT_DOMAIN_P  0x0b /* Domain -- Page */
-#define FAULT_PERM_S    0x0d /* Permission -- Section */
-#define FAULT_PERM_P    0x0f /* Permission -- Page */
-
-#define	FAULT_IMPRECISE	0x400	/* Imprecise exception (XSCALE) */
-
-/*
- * Address of the vector page, low and high versions.
- */
-#define	ARM_VECTORS_LOW		0x00000000U
-#define	ARM_VECTORS_HIGH	0xffff0000U
-
-/*
- * ARM Instructions
- *
- *       3 3 2 2 2                              
- *       1 0 9 8 7                                                     0
- *      +-------+-------------------------------------------------------+
- *      | cond  |              instruction dependant                    |
- *      |c c c c|                                                       |
- *      +-------+-------------------------------------------------------+
- */
-
-#define INSN_SIZE		4		/* Always 4 bytes */
-#define INSN_COND_MASK		0xf0000000	/* Condition mask */
-#define INSN_COND_AL		0xe0000000	/* Always condition */
-
-#endif /* !MACHINE_ARMREG_H */
diff --git a/libpixelflinger/codeflinger/blending.cpp b/libpixelflinger/codeflinger/blending.cpp
deleted file mode 100644
index 2cbb00f..0000000
--- a/libpixelflinger/codeflinger/blending.cpp
+++ /dev/null
@@ -1,674 +0,0 @@
-/* libs/pixelflinger/codeflinger/blending.cpp
-**
-** Copyright 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.
-*/
-
-#define LOG_TAG "pixelflinger-code"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <android-base/macros.h>
-#include <log/log.h>
-
-#include "GGLAssembler.h"
-
-namespace android {
-
-void GGLAssembler::build_fog(
-                        component_t& temp,      // incomming fragment / output
-                        int component,
-                        Scratch& regs)
-{
-   if (mInfo[component].fog) {
-        Scratch scratches(registerFile());
-        comment("fog");
-
-        integer_t fragment(temp.reg, temp.h, temp.flags);
-        if (!(temp.flags & CORRUPTIBLE)) {
-            temp.reg = regs.obtain();
-            temp.flags |= CORRUPTIBLE;
-        }
-
-        integer_t fogColor(scratches.obtain(), 8, CORRUPTIBLE); 
-        LDRB(AL, fogColor.reg, mBuilderContext.Rctx,
-                immed12_pre(GGL_OFFSETOF(state.fog.color[component])));
-
-        integer_t factor(scratches.obtain(), 16, CORRUPTIBLE);
-        CONTEXT_LOAD(factor.reg, generated_vars.f);
-
-        // clamp fog factor (TODO: see if there is a way to guarantee
-        // we won't overflow, when setting the iterators)
-        BIC(AL, 0, factor.reg, factor.reg, reg_imm(factor.reg, ASR, 31));
-        CMP(AL, factor.reg, imm( 0x10000 ));
-        MOV(HS, 0, factor.reg, imm( 0x10000 ));
-
-        build_blendFOneMinusF(temp, factor, fragment, fogColor);
-    }
-}
-
-void GGLAssembler::build_blending(
-                        component_t& temp,      // incomming fragment / output
-                        const pixel_t& pixel,   // framebuffer
-                        int component,
-                        Scratch& regs)
-{
-   if (!mInfo[component].blend)
-        return;
-        
-    int fs = component==GGLFormat::ALPHA ? mBlendSrcA : mBlendSrc;
-    int fd = component==GGLFormat::ALPHA ? mBlendDstA : mBlendDst;
-    if (fs==GGL_SRC_ALPHA_SATURATE && component==GGLFormat::ALPHA)
-        fs = GGL_ONE;
-    const int blending = blending_codes(fs, fd);
-    if (!temp.size()) {
-        // here, blending will produce something which doesn't depend on
-        // that component (eg: GL_ZERO:GL_*), so the register has not been
-        // allocated yet. Will never be used as a source.
-        temp = component_t(regs.obtain(), CORRUPTIBLE);
-    }
-
-    // we are doing real blending...
-    // fb:          extracted dst
-    // fragment:    extracted src
-    // temp:        component_t(fragment) and result
-
-    // scoped register allocator
-    Scratch scratches(registerFile());
-    comment("blending");
-
-    // we can optimize these cases a bit...
-    // (1) saturation is not needed
-    // (2) we can use only one multiply instead of 2
-    // (3) we can reduce the register pressure
-    //      R = S*f + D*(1-f) = (S-D)*f + D
-    //      R = S*(1-f) + D*f = (D-S)*f + S
-
-    const bool same_factor_opt1 =
-        (fs==GGL_DST_COLOR && fd==GGL_ONE_MINUS_DST_COLOR) ||
-        (fs==GGL_SRC_COLOR && fd==GGL_ONE_MINUS_SRC_COLOR) ||
-        (fs==GGL_DST_ALPHA && fd==GGL_ONE_MINUS_DST_ALPHA) ||
-        (fs==GGL_SRC_ALPHA && fd==GGL_ONE_MINUS_SRC_ALPHA);
-
-    const bool same_factor_opt2 =
-        (fs==GGL_ONE_MINUS_DST_COLOR && fd==GGL_DST_COLOR) ||
-        (fs==GGL_ONE_MINUS_SRC_COLOR && fd==GGL_SRC_COLOR) || 
-        (fs==GGL_ONE_MINUS_DST_ALPHA && fd==GGL_DST_ALPHA) ||
-        (fs==GGL_ONE_MINUS_SRC_ALPHA && fd==GGL_SRC_ALPHA);
-
-
-    // XXX: we could also optimize these cases:
-    // R = S*f + D*f = (S+D)*f
-    // R = S*(1-f) + D*(1-f) = (S+D)*(1-f)
-    // R = S*D + D*S = 2*S*D
-
-
-    // see if we need to extract 'component' from the destination (fb)
-    integer_t fb;
-    if (blending & (BLEND_DST|FACTOR_DST)) { 
-        fb.setTo(scratches.obtain(), 32); 
-        extract(fb, pixel, component);
-        if (mDithering) {
-            // XXX: maybe what we should do instead, is simply
-            // expand fb -or- fragment to the larger of the two
-            if (fb.size() < temp.size()) {
-                // for now we expand 'fb' to min(fragment, 8)
-                int new_size = temp.size() < 8 ? temp.size() : 8;
-                expand(fb, fb, new_size);
-            }
-        }
-    }
-
-
-    // convert input fragment to integer_t
-    if (temp.l && (temp.flags & CORRUPTIBLE)) {
-        MOV(AL, 0, temp.reg, reg_imm(temp.reg, LSR, temp.l));
-        temp.h -= temp.l;
-        temp.l = 0;
-    }
-    integer_t fragment(temp.reg, temp.size(), temp.flags);
-
-    // if not done yet, convert input fragment to integer_t
-    if (temp.l) {
-        // here we know temp is not CORRUPTIBLE
-        fragment.reg = scratches.obtain();
-        MOV(AL, 0, fragment.reg, reg_imm(temp.reg, LSR, temp.l));
-        fragment.flags |= CORRUPTIBLE;
-    }
-
-    if (!(temp.flags & CORRUPTIBLE)) {
-        // temp is not corruptible, but since it's the destination it
-        // will be modified, so we need to allocate a new register.
-        temp.reg = regs.obtain();
-        temp.flags &= ~CORRUPTIBLE;
-        fragment.flags &= ~CORRUPTIBLE;
-    }
-
-    if ((blending & BLEND_SRC) && !same_factor_opt1) {
-        // source (fragment) is needed for the blending stage
-        // so it's not CORRUPTIBLE (unless we're doing same_factor_opt1)
-        fragment.flags &= ~CORRUPTIBLE;
-    }
-
-
-    if (same_factor_opt1) {
-        //  R = S*f + D*(1-f) = (S-D)*f + D
-        integer_t factor;
-        build_blend_factor(factor, fs, 
-                component, pixel, fragment, fb, scratches);
-        // fb is always corruptible from this point
-        fb.flags |= CORRUPTIBLE;
-        build_blendFOneMinusF(temp, factor, fragment, fb);
-    } else if (same_factor_opt2) {
-        //  R = S*(1-f) + D*f = (D-S)*f + S
-        integer_t factor;
-        // fb is always corrruptible here
-        fb.flags |= CORRUPTIBLE;
-        build_blend_factor(factor, fd,
-                component, pixel, fragment, fb, scratches);
-        build_blendOneMinusFF(temp, factor, fragment, fb);
-    } else {
-        integer_t src_factor;
-        integer_t dst_factor;
-
-        // if destination (fb) is not needed for the blending stage, 
-        // then it can be marked as CORRUPTIBLE
-        if (!(blending & BLEND_DST)) {
-            fb.flags |= CORRUPTIBLE;
-        }
-
-        // XXX: try to mark some registers as CORRUPTIBLE
-        // in most case we could make those corruptible
-        // when we're processing the last component
-        // but not always, for instance
-        //    when fragment is constant and not reloaded
-        //    when fb is needed for logic-ops or masking
-        //    when a register is aliased (for instance with mAlphaSource)
-
-        // blend away...
-        if (fs==GGL_ZERO) {
-            if (fd==GGL_ZERO) {         // R = 0
-                // already taken care of
-            } else if (fd==GGL_ONE) {   // R = D
-                // already taken care of
-            } else {                    // R = D*fd
-                // compute fd
-                build_blend_factor(dst_factor, fd,
-                        component, pixel, fragment, fb, scratches);
-                mul_factor(temp, fb, dst_factor);
-            }
-        } else if (fs==GGL_ONE) {
-            if (fd==GGL_ZERO) {         // R = S
-                // NOP, taken care of
-            } else if (fd==GGL_ONE) {   // R = S + D
-                component_add(temp, fb, fragment); // args order matters
-                component_sat(temp);
-            } else {                    // R = S + D*fd
-                // compute fd
-                build_blend_factor(dst_factor, fd,
-                        component, pixel, fragment, fb, scratches);
-                mul_factor_add(temp, fb, dst_factor, component_t(fragment));
-                component_sat(temp);
-            }
-        } else {
-            // compute fs
-            build_blend_factor(src_factor, fs, 
-                    component, pixel, fragment, fb, scratches);
-            if (fd==GGL_ZERO) {         // R = S*fs
-                mul_factor(temp, fragment, src_factor);
-            } else if (fd==GGL_ONE) {   // R = S*fs + D
-                mul_factor_add(temp, fragment, src_factor, component_t(fb));
-                component_sat(temp);
-            } else {                    // R = S*fs + D*fd
-                mul_factor(temp, fragment, src_factor);
-                if (scratches.isUsed(src_factor.reg))
-                    scratches.recycle(src_factor.reg);
-                // compute fd
-                build_blend_factor(dst_factor, fd,
-                        component, pixel, fragment, fb, scratches);
-                mul_factor_add(temp, fb, dst_factor, temp);
-                if (!same_factor_opt1 && !same_factor_opt2) {
-                    component_sat(temp);
-                }
-            }
-        }
-    }
-
-    // now we can be corrupted (it's the dest)
-    temp.flags |= CORRUPTIBLE;
-}
-
-void GGLAssembler::build_blend_factor(
-        integer_t& factor, int f, int component,
-        const pixel_t& dst_pixel,
-        integer_t& fragment,
-        integer_t& fb,
-        Scratch& scratches)
-{
-    integer_t src_alpha(fragment);
-
-    // src_factor/dst_factor won't be used after blending,
-    // so it's fine to mark them as CORRUPTIBLE (if not aliased)
-    factor.flags |= CORRUPTIBLE;
-
-    switch(f) {
-    case GGL_ONE_MINUS_SRC_ALPHA:
-    case GGL_SRC_ALPHA:
-        if (component==GGLFormat::ALPHA && !isAlphaSourceNeeded()) {
-            // we're processing alpha, so we already have
-            // src-alpha in fragment, and we need src-alpha just this time.
-        } else {
-           // alpha-src will be needed for other components
-            if (!mBlendFactorCached || mBlendFactorCached==f) {
-                src_alpha = mAlphaSource;
-                factor = mAlphaSource;
-                factor.flags &= ~CORRUPTIBLE;           
-                // we already computed the blend factor before, nothing to do.
-                if (mBlendFactorCached)
-                    return;
-                // this is the first time, make sure to compute the blend
-                // factor properly.
-                mBlendFactorCached = f;
-                break;
-            } else {
-                // we have a cached alpha blend factor, but we want another one,
-                // this should really not happen because by construction,
-                // we cannot have BOTH source and destination
-                // blend factors use ALPHA *and* ONE_MINUS_ALPHA (because
-                // the blending stage uses the f/(1-f) optimization
-                
-                // for completeness, we handle this case though. Since there
-                // are only 2 choices, this meens we want "the other one"
-                // (1-factor)
-                factor = mAlphaSource;
-                factor.flags &= ~CORRUPTIBLE;           
-                RSB(AL, 0, factor.reg, factor.reg, imm((1<<factor.s)));
-                mBlendFactorCached = f;
-                return;
-            }                
-        }
-        FALLTHROUGH_INTENDED;
-    case GGL_ONE_MINUS_DST_COLOR:
-    case GGL_DST_COLOR:
-    case GGL_ONE_MINUS_SRC_COLOR:
-    case GGL_SRC_COLOR:
-    case GGL_ONE_MINUS_DST_ALPHA:
-    case GGL_DST_ALPHA:
-    case GGL_SRC_ALPHA_SATURATE:
-        // help us find out what register we can use for the blend-factor
-        // CORRUPTIBLE registers are chosen first, or a new one is allocated.
-        if (fragment.flags & CORRUPTIBLE) {
-            factor.setTo(fragment.reg, 32, CORRUPTIBLE);
-            fragment.flags &= ~CORRUPTIBLE;
-        } else if (fb.flags & CORRUPTIBLE) {
-            factor.setTo(fb.reg, 32, CORRUPTIBLE);
-            fb.flags &= ~CORRUPTIBLE;
-        } else {
-            factor.setTo(scratches.obtain(), 32, CORRUPTIBLE);
-        } 
-        break;
-    }
-
-    // XXX: doesn't work if size==1
-
-    switch(f) {
-    case GGL_ONE_MINUS_DST_COLOR:
-    case GGL_DST_COLOR:
-        factor.s = fb.s;
-        ADD(AL, 0, factor.reg, fb.reg, reg_imm(fb.reg, LSR, fb.s-1));
-        break;
-    case GGL_ONE_MINUS_SRC_COLOR:
-    case GGL_SRC_COLOR:
-        factor.s = fragment.s;
-        ADD(AL, 0, factor.reg, fragment.reg,
-            reg_imm(fragment.reg, LSR, fragment.s-1));
-        break;
-    case GGL_ONE_MINUS_SRC_ALPHA:
-    case GGL_SRC_ALPHA:
-        factor.s = src_alpha.s;
-        ADD(AL, 0, factor.reg, src_alpha.reg,
-                reg_imm(src_alpha.reg, LSR, src_alpha.s-1));
-        break;
-    case GGL_ONE_MINUS_DST_ALPHA:
-    case GGL_DST_ALPHA:
-        // XXX: should be precomputed
-        extract(factor, dst_pixel, GGLFormat::ALPHA);
-        ADD(AL, 0, factor.reg, factor.reg,
-                reg_imm(factor.reg, LSR, factor.s-1));
-        break;
-    case GGL_SRC_ALPHA_SATURATE:
-        // XXX: should be precomputed
-        // XXX: f = min(As, 1-Ad)
-        // btw, we're guaranteed that Ad's size is <= 8, because
-        // it's extracted from the framebuffer
-        break;
-    }
-
-    switch(f) {
-    case GGL_ONE_MINUS_DST_COLOR:
-    case GGL_ONE_MINUS_SRC_COLOR:
-    case GGL_ONE_MINUS_DST_ALPHA:
-    case GGL_ONE_MINUS_SRC_ALPHA:
-        RSB(AL, 0, factor.reg, factor.reg, imm((1<<factor.s)));
-    }
-    
-    // don't need more than 8-bits for the blend factor
-    // and this will prevent overflows in the multiplies later
-    if (factor.s > 8) {
-        MOV(AL, 0, factor.reg, reg_imm(factor.reg, LSR, factor.s-8));
-        factor.s = 8;
-    }
-}
-
-int GGLAssembler::blending_codes(int fs, int fd)
-{
-    int blending = 0;
-    switch(fs) {
-    case GGL_ONE:
-        blending |= BLEND_SRC;
-        break;
-
-    case GGL_ONE_MINUS_DST_COLOR:
-    case GGL_DST_COLOR:
-        blending |= FACTOR_DST|BLEND_SRC;
-        break;
-    case GGL_ONE_MINUS_DST_ALPHA:
-    case GGL_DST_ALPHA:
-        // no need to extract 'component' from the destination
-        // for the blend factor, because we need ALPHA only.
-        blending |= BLEND_SRC;
-        break;
-
-    case GGL_ONE_MINUS_SRC_COLOR:
-    case GGL_SRC_COLOR:    
-        blending |= FACTOR_SRC|BLEND_SRC;
-        break;
-    case GGL_ONE_MINUS_SRC_ALPHA:
-    case GGL_SRC_ALPHA:
-    case GGL_SRC_ALPHA_SATURATE:
-        blending |= FACTOR_SRC|BLEND_SRC;
-        break;
-    }
-    switch(fd) {
-    case GGL_ONE:
-        blending |= BLEND_DST;
-        break;
-
-    case GGL_ONE_MINUS_DST_COLOR:
-    case GGL_DST_COLOR:
-        blending |= FACTOR_DST|BLEND_DST;
-        break;
-    case GGL_ONE_MINUS_DST_ALPHA:
-    case GGL_DST_ALPHA:
-        blending |= FACTOR_DST|BLEND_DST;
-        break;
-
-    case GGL_ONE_MINUS_SRC_COLOR:
-    case GGL_SRC_COLOR:    
-        blending |= FACTOR_SRC|BLEND_DST;
-        break;
-    case GGL_ONE_MINUS_SRC_ALPHA:
-    case GGL_SRC_ALPHA:
-        // no need to extract 'component' from the source
-        // for the blend factor, because we need ALPHA only.
-        blending |= BLEND_DST;
-        break;
-    }
-    return blending;
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_blendFOneMinusF(
-        component_t& temp,
-        const integer_t& factor, 
-        const integer_t& fragment,
-        const integer_t& fb)
-{
-    //  R = S*f + D*(1-f) = (S-D)*f + D
-    Scratch scratches(registerFile());
-    // compute S-D
-    integer_t diff(fragment.flags & CORRUPTIBLE ?
-            fragment.reg : scratches.obtain(), fb.size(), CORRUPTIBLE);
-    const int shift = fragment.size() - fb.size();
-    if (shift>0)        RSB(AL, 0, diff.reg, fb.reg, reg_imm(fragment.reg, LSR, shift));
-    else if (shift<0)   RSB(AL, 0, diff.reg, fb.reg, reg_imm(fragment.reg, LSL,-shift));
-    else                RSB(AL, 0, diff.reg, fb.reg, fragment.reg);
-    mul_factor_add(temp, diff, factor, component_t(fb));
-}
-
-void GGLAssembler::build_blendOneMinusFF(
-        component_t& temp,
-        const integer_t& factor, 
-        const integer_t& fragment,
-        const integer_t& fb)
-{
-    //  R = S*f + D*(1-f) = (S-D)*f + D
-    Scratch scratches(registerFile());
-    // compute D-S
-    integer_t diff(fb.flags & CORRUPTIBLE ?
-            fb.reg : scratches.obtain(), fb.size(), CORRUPTIBLE);
-    const int shift = fragment.size() - fb.size();
-    if (shift>0)        SUB(AL, 0, diff.reg, fb.reg, reg_imm(fragment.reg, LSR, shift));
-    else if (shift<0)   SUB(AL, 0, diff.reg, fb.reg, reg_imm(fragment.reg, LSL,-shift));
-    else                SUB(AL, 0, diff.reg, fb.reg, fragment.reg);
-    mul_factor_add(temp, diff, factor, component_t(fragment));
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::mul_factor(  component_t& d,
-                                const integer_t& v,
-                                const integer_t& f)
-{
-    int vs = v.size();
-    int fs = f.size();
-    int ms = vs+fs;
-
-    // XXX: we could have special cases for 1 bit mul
-
-    // all this code below to use the best multiply instruction
-    // wrt the parameters size. We take advantage of the fact
-    // that the 16-bits multiplies allow a 16-bit shift
-    // The trick is that we just make sure that we have at least 8-bits
-    // per component (which is enough for a 8 bits display).
-
-    int xy;
-    int vshift = 0;
-    int fshift = 0;
-    int smulw = 0;
-
-    if (vs<16) {
-        if (fs<16) {
-            xy = xyBB;
-        } else if (GGL_BETWEEN(fs, 24, 31)) {
-            ms -= 16;
-            xy = xyTB;
-        } else {
-            // eg: 15 * 18  ->  15 * 15
-            fshift = fs - 15;
-            ms -= fshift;
-            xy = xyBB;
-        }
-    } else if (GGL_BETWEEN(vs, 24, 31)) {
-        if (fs<16) {
-            ms -= 16;
-            xy = xyTB;
-        } else if (GGL_BETWEEN(fs, 24, 31)) {
-            ms -= 32;
-            xy = xyTT;
-        } else {
-            // eg: 24 * 18  ->  8 * 18
-            fshift = fs - 15;
-            ms -= 16 + fshift;
-            xy = xyTB;
-        }
-    } else {
-        if (fs<16) {
-            // eg: 18 * 15  ->  15 * 15
-            vshift = vs - 15;
-            ms -= vshift;
-            xy = xyBB;
-        } else if (GGL_BETWEEN(fs, 24, 31)) {
-            // eg: 18 * 24  ->  15 * 8
-            vshift = vs - 15;
-            ms -= 16 + vshift;
-            xy = xyBT;
-        } else {
-            // eg: 18 * 18  ->  (15 * 18)>>16
-            fshift = fs - 15;
-            ms -= 16 + fshift;
-            xy = yB;    //XXX SMULWB
-            smulw = 1;
-        }
-    }
-
-    ALOGE_IF(ms>=32, "mul_factor overflow vs=%d, fs=%d", vs, fs);
-
-    int vreg = v.reg;
-    int freg = f.reg;
-    if (vshift) {
-        MOV(AL, 0, d.reg, reg_imm(vreg, LSR, vshift));
-        vreg = d.reg;
-    }
-    if (fshift) {
-        MOV(AL, 0, d.reg, reg_imm(vreg, LSR, fshift));
-        freg = d.reg;
-    }
-    if (smulw)  SMULW(AL, xy, d.reg, vreg, freg);
-    else        SMUL(AL, xy, d.reg, vreg, freg);
-
-
-    d.h = ms;
-    if (mDithering) {
-        d.l = 0; 
-    } else {
-        d.l = fs; 
-        d.flags |= CLEAR_LO;
-    }
-}
-
-void GGLAssembler::mul_factor_add(  component_t& d,
-                                    const integer_t& v,
-                                    const integer_t& f,
-                                    const component_t& a)
-{
-    // XXX: we could have special cases for 1 bit mul
-    Scratch scratches(registerFile());
-
-    int vs = v.size();
-    int fs = f.size();
-    int as = a.h;
-    int ms = vs+fs;
-
-    ALOGE_IF(ms>=32, "mul_factor_add overflow vs=%d, fs=%d, as=%d", vs, fs, as);
-
-    integer_t add(a.reg, a.h, a.flags);
-
-    // 'a' is a component_t but it is guaranteed to have
-    // its high bits set to 0. However in the dithering case,
-    // we can't get away with truncating the potentially bad bits
-    // so extraction is needed.
-
-   if ((mDithering) && (a.size() < ms)) {
-        // we need to expand a
-        if (!(a.flags & CORRUPTIBLE)) {
-            // ... but it's not corruptible, so we need to pick a
-            // temporary register.
-            // Try to uses the destination register first (it's likely
-            // to be usable, unless it aliases an input).
-            if (d.reg!=a.reg && d.reg!=v.reg && d.reg!=f.reg) {
-                add.reg = d.reg;
-            } else {
-                add.reg = scratches.obtain();
-            }
-        }
-        expand(add, a, ms); // extracts and expands
-        as = ms;
-    }
-
-    if (ms == as) {
-        if (vs<16 && fs<16) SMLABB(AL, d.reg, v.reg, f.reg, add.reg);
-        else                MLA(AL, 0, d.reg, v.reg, f.reg, add.reg);
-    } else {
-        int temp = d.reg;
-        if (temp == add.reg) {
-            // the mul will modify add.reg, we need an intermediary reg
-            if (v.flags & CORRUPTIBLE)      temp = v.reg;
-            else if (f.flags & CORRUPTIBLE) temp = f.reg;
-            else                            temp = scratches.obtain();
-        }
-
-        if (vs<16 && fs<16) SMULBB(AL, temp, v.reg, f.reg);
-        else                MUL(AL, 0, temp, v.reg, f.reg);
-
-        if (ms>as) {
-            ADD(AL, 0, d.reg, temp, reg_imm(add.reg, LSL, ms-as));
-        } else if (ms<as) {
-            // not sure if we should expand the mul instead?
-            ADD(AL, 0, d.reg, temp, reg_imm(add.reg, LSR, as-ms));
-        }
-    }
-
-    d.h = ms;
-    if (mDithering) {
-        d.l = a.l; 
-    } else {
-        d.l = fs>a.l ? fs : a.l;
-        d.flags |= CLEAR_LO;
-    }
-}
-
-void GGLAssembler::component_add(component_t& d,
-        const integer_t& dst, const integer_t& src)
-{
-    // here we're guaranteed that fragment.size() >= fb.size()
-    const int shift = src.size() - dst.size();
-    if (!shift) {
-        ADD(AL, 0, d.reg, src.reg, dst.reg);
-    } else {
-        ADD(AL, 0, d.reg, src.reg, reg_imm(dst.reg, LSL, shift));
-    }
-
-    d.h = src.size();
-    if (mDithering) {
-        d.l = 0;
-    } else {
-        d.l = shift;
-        d.flags |= CLEAR_LO;
-    }
-}
-
-void GGLAssembler::component_sat(const component_t& v)
-{
-    const int one = ((1<<v.size())-1)<<v.l;
-    CMP(AL, v.reg, imm( 1<<v.h ));
-    if (isValidImmediate(one)) {
-        MOV(HS, 0, v.reg, imm( one ));
-    } else if (isValidImmediate(~one)) {
-        MVN(HS, 0, v.reg, imm( ~one ));
-    } else {
-        MOV(HS, 0, v.reg, imm( 1<<v.h ));
-        SUB(HS, 0, v.reg, v.reg, imm( 1<<v.l ));
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
diff --git a/libpixelflinger/codeflinger/disassem.c b/libpixelflinger/codeflinger/disassem.c
deleted file mode 100644
index 5cbd63d..0000000
--- a/libpixelflinger/codeflinger/disassem.c
+++ /dev/null
@@ -1,714 +0,0 @@
-/*	$NetBSD: disassem.c,v 1.14 2003/03/27 16:58:36 mycroft Exp $	*/
-
-/*-
- * Copyright (c) 1996 Mark Brinicombe.
- * Copyright (c) 1996 Brini.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by Brini.
- * 4. The name of the company nor the name of the author may be used to
- *    endorse or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY BRINI ``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 BRINI 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.
- *
- * RiscBSD kernel project
- *
- * db_disasm.c
- *
- * Kernel disassembler
- *
- * Created      : 10/02/96
- *
- * Structured after the sparc/sparc/db_disasm.c by David S. Miller &
- * Paul Kranenburg
- *
- * This code is not complete. Not all instructions are disassembled.
- */
-
-#include <sys/cdefs.h>
-//__FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/arm/arm/disassem.c,v 1.2 2005/01/05 21:58:47 imp Exp $");
-#include <sys/param.h>
-#include <stdio.h>
-
-#include "disassem.h"
-#include "armreg.h"
-//#include <ddb/ddb.h>
-
-/*
- * General instruction format
- *
- *	insn[cc][mod]	[operands]
- *
- * Those fields with an uppercase format code indicate that the field
- * follows directly after the instruction before the separator i.e.
- * they modify the instruction rather than just being an operand to
- * the instruction. The only exception is the writeback flag which
- * follows a operand.
- *
- *
- * 2 - print Operand 2 of a data processing instruction
- * d - destination register (bits 12-15)
- * n - n register (bits 16-19)
- * s - s register (bits 8-11)
- * o - indirect register rn (bits 16-19) (used by swap)
- * m - m register (bits 0-3)
- * a - address operand of ldr/str instruction
- * e - address operand of ldrh/strh instruction
- * l - register list for ldm/stm instruction
- * f - 1st fp operand (register) (bits 12-14)
- * g - 2nd fp operand (register) (bits 16-18)
- * h - 3rd fp operand (register/immediate) (bits 0-4)
- * j - xtb rotate literal (bits 10-11)
- * i - bfx lsb literal (bits 7-11)
- * w - bfx width literal (bits 16-20)
- * b - branch address
- * t - thumb branch address (bits 24, 0-23)
- * k - breakpoint comment (bits 0-3, 8-19)
- * X - block transfer type
- * Y - block transfer type (r13 base)
- * c - comment field bits(0-23)
- * p - saved or current status register
- * F - PSR transfer fields
- * D - destination-is-r15 (P) flag on TST, TEQ, CMP, CMN
- * L - co-processor transfer size
- * S - set status flag
- * P - fp precision
- * Q - fp precision (for ldf/stf)
- * R - fp rounding
- * v - co-processor data transfer registers + addressing mode
- * W - writeback flag
- * x - instruction in hex
- * # - co-processor number
- * y - co-processor data processing registers
- * z - co-processor register transfer registers
- */
-
-struct arm32_insn {
-	u_int mask;
-	u_int pattern;
-	char* name;
-	char* format;
-};
-
-static const struct arm32_insn arm32_i[] = {
-    { 0x0fffffff, 0x0ff00000, "imb",	"c" },		/* Before swi */
-    { 0x0fffffff, 0x0ff00001, "imbrange",	"c" },	/* Before swi */
-    { 0x0f000000, 0x0f000000, "swi",	"c" },
-    { 0xfe000000, 0xfa000000, "blx",	"t" },		/* Before b and bl */
-    { 0x0f000000, 0x0a000000, "b",	"b" },
-    { 0x0f000000, 0x0b000000, "bl",	"b" },
-    { 0x0fe000f0, 0x00000090, "mul",	"Snms" },
-    { 0x0fe000f0, 0x00200090, "mla",	"Snmsd" },
-    { 0x0fe000f0, 0x00800090, "umull",	"Sdnms" },
-    { 0x0fe000f0, 0x00c00090, "smull",	"Sdnms" },
-    { 0x0fe000f0, 0x00a00090, "umlal",	"Sdnms" },
-    { 0x0fe000f0, 0x00e00090, "smlal",	"Sdnms" },
-    { 0x0fff03f0, 0x06cf0070, "uxtb16", "dmj" },
-    { 0x0fe00070, 0x07e00050, "ubfx",   "dmiw" },
-    { 0x0d700000, 0x04200000, "strt",	"daW" },
-    { 0x0d700000, 0x04300000, "ldrt",	"daW" },
-    { 0x0d700000, 0x04600000, "strbt",	"daW" },
-    { 0x0d700000, 0x04700000, "ldrbt",	"daW" },
-    { 0x0c500000, 0x04000000, "str",	"daW" },
-    { 0x0c500000, 0x04100000, "ldr",	"daW" },
-    { 0x0c500000, 0x04400000, "strb",	"daW" },
-    { 0x0c500000, 0x04500000, "ldrb",	"daW" },
-    { 0x0e1f0000, 0x080d0000, "stm",	"YnWl" },/* separate out r13 base */
-    { 0x0e1f0000, 0x081d0000, "ldm",	"YnWl" },/* separate out r13 base */    
-    { 0x0e100000, 0x08000000, "stm",	"XnWl" },
-    { 0x0e100000, 0x08100000, "ldm",	"XnWl" },    
-    { 0x0e1000f0, 0x00100090, "ldrb",	"deW" },
-    { 0x0e1000f0, 0x00000090, "strb",	"deW" },
-    { 0x0e1000f0, 0x001000d0, "ldrsb",	"deW" },
-    { 0x0e1000f0, 0x001000b0, "ldrh",	"deW" },
-    { 0x0e1000f0, 0x000000b0, "strh",	"deW" },
-    { 0x0e1000f0, 0x001000f0, "ldrsh",	"deW" },
-    { 0x0f200090, 0x00200090, "und",	"x" },	/* Before data processing */
-    { 0x0e1000d0, 0x000000d0, "und",	"x" },	/* Before data processing */
-    { 0x0ff00ff0, 0x01000090, "swp",	"dmo" },
-    { 0x0ff00ff0, 0x01400090, "swpb",	"dmo" },
-    { 0x0fbf0fff, 0x010f0000, "mrs",	"dp" },	/* Before data processing */
-    { 0x0fb0fff0, 0x0120f000, "msr",	"pFm" },/* Before data processing */
-    { 0x0fb0f000, 0x0320f000, "msr",	"pF2" },/* Before data processing */
-    { 0x0ffffff0, 0x012fff10, "bx",     "m" },
-    { 0x0fff0ff0, 0x016f0f10, "clz",	"dm" },
-    { 0x0ffffff0, 0x012fff30, "blx",	"m" },
-    { 0xfff000f0, 0xe1200070, "bkpt",	"k" },
-    { 0x0de00000, 0x00000000, "and",	"Sdn2" },
-    { 0x0de00000, 0x00200000, "eor",	"Sdn2" },
-    { 0x0de00000, 0x00400000, "sub",	"Sdn2" },
-    { 0x0de00000, 0x00600000, "rsb",	"Sdn2" },
-    { 0x0de00000, 0x00800000, "add",	"Sdn2" },
-    { 0x0de00000, 0x00a00000, "adc",	"Sdn2" },
-    { 0x0de00000, 0x00c00000, "sbc",	"Sdn2" },
-    { 0x0de00000, 0x00e00000, "rsc",	"Sdn2" },
-    { 0x0df00000, 0x01100000, "tst",	"Dn2" },
-    { 0x0df00000, 0x01300000, "teq",	"Dn2" },
-    { 0x0df00000, 0x01500000, "cmp",	"Dn2" },
-    { 0x0df00000, 0x01700000, "cmn",	"Dn2" },
-    { 0x0de00000, 0x01800000, "orr",	"Sdn2" },
-    { 0x0de00000, 0x01a00000, "mov",	"Sd2" },
-    { 0x0de00000, 0x01c00000, "bic",	"Sdn2" },
-    { 0x0de00000, 0x01e00000, "mvn",	"Sd2" },
-    { 0x0ff08f10, 0x0e000100, "adf",	"PRfgh" },
-    { 0x0ff08f10, 0x0e100100, "muf",	"PRfgh" },
-    { 0x0ff08f10, 0x0e200100, "suf",	"PRfgh" },
-    { 0x0ff08f10, 0x0e300100, "rsf",	"PRfgh" },
-    { 0x0ff08f10, 0x0e400100, "dvf",	"PRfgh" },
-    { 0x0ff08f10, 0x0e500100, "rdf",	"PRfgh" },
-    { 0x0ff08f10, 0x0e600100, "pow",	"PRfgh" },
-    { 0x0ff08f10, 0x0e700100, "rpw",	"PRfgh" },
-    { 0x0ff08f10, 0x0e800100, "rmf",	"PRfgh" },
-    { 0x0ff08f10, 0x0e900100, "fml",	"PRfgh" },
-    { 0x0ff08f10, 0x0ea00100, "fdv",	"PRfgh" },
-    { 0x0ff08f10, 0x0eb00100, "frd",	"PRfgh" },
-    { 0x0ff08f10, 0x0ec00100, "pol",	"PRfgh" },
-    { 0x0f008f10, 0x0e000100, "fpbop",	"PRfgh" },
-    { 0x0ff08f10, 0x0e008100, "mvf",	"PRfh" },
-    { 0x0ff08f10, 0x0e108100, "mnf",	"PRfh" },
-    { 0x0ff08f10, 0x0e208100, "abs",	"PRfh" },
-    { 0x0ff08f10, 0x0e308100, "rnd",	"PRfh" },
-    { 0x0ff08f10, 0x0e408100, "sqt",	"PRfh" },
-    { 0x0ff08f10, 0x0e508100, "log",	"PRfh" },
-    { 0x0ff08f10, 0x0e608100, "lgn",	"PRfh" },
-    { 0x0ff08f10, 0x0e708100, "exp",	"PRfh" },
-    { 0x0ff08f10, 0x0e808100, "sin",	"PRfh" },
-    { 0x0ff08f10, 0x0e908100, "cos",	"PRfh" },
-    { 0x0ff08f10, 0x0ea08100, "tan",	"PRfh" },
-    { 0x0ff08f10, 0x0eb08100, "asn",	"PRfh" },
-    { 0x0ff08f10, 0x0ec08100, "acs",	"PRfh" },
-    { 0x0ff08f10, 0x0ed08100, "atn",	"PRfh" },
-    { 0x0f008f10, 0x0e008100, "fpuop",	"PRfh" },
-    { 0x0e100f00, 0x0c000100, "stf",	"QLv" },
-    { 0x0e100f00, 0x0c100100, "ldf",	"QLv" },
-    { 0x0ff00f10, 0x0e000110, "flt",	"PRgd" },
-    { 0x0ff00f10, 0x0e100110, "fix",	"PRdh" },
-    { 0x0ff00f10, 0x0e200110, "wfs",	"d" },
-    { 0x0ff00f10, 0x0e300110, "rfs",	"d" },
-    { 0x0ff00f10, 0x0e400110, "wfc",	"d" },
-    { 0x0ff00f10, 0x0e500110, "rfc",	"d" },
-    { 0x0ff0ff10, 0x0e90f110, "cmf",	"PRgh" },
-    { 0x0ff0ff10, 0x0eb0f110, "cnf",	"PRgh" },
-    { 0x0ff0ff10, 0x0ed0f110, "cmfe",	"PRgh" },
-    { 0x0ff0ff10, 0x0ef0f110, "cnfe",	"PRgh" },
-    { 0xff100010, 0xfe000010, "mcr2",	"#z" },
-    { 0x0f100010, 0x0e000010, "mcr",	"#z" },
-    { 0xff100010, 0xfe100010, "mrc2",	"#z" },
-    { 0x0f100010, 0x0e100010, "mrc",	"#z" },
-    { 0xff000010, 0xfe000000, "cdp2",	"#y" },
-    { 0x0f000010, 0x0e000000, "cdp",	"#y" },
-    { 0xfe100090, 0xfc100000, "ldc2",	"L#v" },
-    { 0x0e100090, 0x0c100000, "ldc",	"L#v" },
-    { 0xfe100090, 0xfc000000, "stc2",	"L#v" },
-    { 0x0e100090, 0x0c000000, "stc",	"L#v" },
-    { 0xf550f000, 0xf550f000, "pld",	"ne" },
-    { 0x0ff00ff0, 0x01000050, "qaad",	"dmn" },
-    { 0x0ff00ff0, 0x01400050, "qdaad",	"dmn" },
-    { 0x0ff00ff0, 0x01600050, "qdsub",	"dmn" },
-    { 0x0ff00ff0, 0x01200050, "dsub",	"dmn" },
-    { 0x0ff000f0, 0x01000080, "smlabb",	"nmsd" },   // d & n inverted!!
-    { 0x0ff000f0, 0x010000a0, "smlatb",	"nmsd" },   // d & n inverted!!
-    { 0x0ff000f0, 0x010000c0, "smlabt",	"nmsd" },   // d & n inverted!!
-    { 0x0ff000f0, 0x010000e0, "smlatt",	"nmsd" },   // d & n inverted!!
-    { 0x0ff000f0, 0x01400080, "smlalbb","ndms" },   // d & n inverted!!
-    { 0x0ff000f0, 0x014000a0, "smlaltb","ndms" },   // d & n inverted!!
-    { 0x0ff000f0, 0x014000c0, "smlalbt","ndms" },   // d & n inverted!!
-    { 0x0ff000f0, 0x014000e0, "smlaltt","ndms" },   // d & n inverted!!
-    { 0x0ff000f0, 0x01200080, "smlawb", "nmsd" },   // d & n inverted!!
-    { 0x0ff0f0f0, 0x012000a0, "smulwb","nms" },   // d & n inverted!!
-    { 0x0ff000f0, 0x012000c0, "smlawt", "nmsd" },   // d & n inverted!!
-    { 0x0ff0f0f0, 0x012000e0, "smulwt","nms" },   // d & n inverted!!
-    { 0x0ff0f0f0, 0x01600080, "smulbb","nms" },   // d & n inverted!!
-    { 0x0ff0f0f0, 0x016000a0, "smultb","nms" },   // d & n inverted!!
-    { 0x0ff0f0f0, 0x016000c0, "smulbt","nms" },   // d & n inverted!!
-    { 0x0ff0f0f0, 0x016000e0, "smultt","nms" },   // d & n inverted!!
-    { 0x00000000, 0x00000000, NULL,	NULL }
-};
-
-static char const arm32_insn_conditions[][4] = {
-	"eq", "ne", "cs", "cc",
-	"mi", "pl", "vs", "vc",
-	"hi", "ls", "ge", "lt",
-	"gt", "le", "",   "nv"
-};
-
-static char const insn_block_transfers[][4] = {
-	"da", "ia", "db", "ib"
-};
-
-static char const insn_stack_block_transfers[][4] = {
-	"ed", "ea", "fd", "fa"
-};
-
-static char const op_shifts[][4] = {
-	"lsl", "lsr", "asr", "ror"
-};
-
-static char const insn_fpa_rounding[][2] = {
-	"", "p", "m", "z"
-};
-
-static char const insn_fpa_precision[][2] = {
-	"s", "d", "e", "p"
-};
-
-static char const insn_fpaconstants[][8] = {
-	"0.0", "1.0", "2.0", "3.0",
-	"4.0", "5.0", "0.5", "10.0"
-};
-
-#define insn_condition(x)	arm32_insn_conditions[((x) >> 28) & 0x0f]
-#define insn_blktrans(x)	insn_block_transfers[((x) >> 23) & 3]
-#define insn_stkblktrans(x)	insn_stack_block_transfers[(3*(((x) >> 20)&1))^(((x) >> 23)&3)]
-#define op2_shift(x)		op_shifts[((x) >> 5) & 3]
-#define insn_fparnd(x)		insn_fpa_rounding[((x) >> 5) & 0x03]
-#define insn_fpaprec(x)		insn_fpa_precision[((((x) >> 18) & 2)|((x) >> 7)) & 1]
-#define insn_fpaprect(x)	insn_fpa_precision[((((x) >> 21) & 2)|((x) >> 15)) & 1]
-#define insn_fpaimm(x)		insn_fpaconstants[(x) & 0x07]
-
-/* Local prototypes */
-static void disasm_register_shift(const disasm_interface_t *di, u_int insn);
-static void disasm_print_reglist(const disasm_interface_t *di, u_int insn);
-static void disasm_insn_ldrstr(const disasm_interface_t *di, u_int insn,
-    u_int loc);
-static void disasm_insn_ldrhstrh(const disasm_interface_t *di, u_int insn,
-    u_int loc);
-static void disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn,
-    u_int loc);
-static u_int disassemble_readword(u_int address);
-static void disassemble_printaddr(u_int address);
-
-u_int
-disasm(const disasm_interface_t *di, u_int loc, int __unused altfmt)
-{
-	const struct arm32_insn *i_ptr = &arm32_i[0];
-	u_int insn = di->di_readword(loc);
-	int matchp = 0;
-	int branch;
-	char* f_ptr;
-	int fmt = 0;
-
-/*	di->di_printf("loc=%08x insn=%08x : ", loc, insn);*/
-
-	while (i_ptr->name) {
-		if ((insn & i_ptr->mask) ==  i_ptr->pattern) {
-			matchp = 1;
-			break;
-		}
-		i_ptr++;
-	}
-
-	if (!matchp) {
-		di->di_printf("und%s\t%08x\n", insn_condition(insn), insn);
-		return(loc + INSN_SIZE);
-	}
-
-	/* If instruction forces condition code, don't print it. */
-	if ((i_ptr->mask & 0xf0000000) == 0xf0000000)
-		di->di_printf("%s", i_ptr->name);
-	else
-		di->di_printf("%s%s", i_ptr->name, insn_condition(insn));
-
-	f_ptr = i_ptr->format;
-
-	/* Insert tab if there are no instruction modifiers */
-
-	if (*(f_ptr) < 'A' || *(f_ptr) > 'Z') {
-		++fmt;
-		di->di_printf("\t");
-	}
-
-	while (*f_ptr) {
-		switch (*f_ptr) {
-		/* 2 - print Operand 2 of a data processing instruction */
-		case '2':
-			if (insn & 0x02000000) {
-				int rotate= ((insn >> 7) & 0x1e);
-
-				di->di_printf("#0x%08x",
-					      (insn & 0xff) << (32 - rotate) |
-					      (insn & 0xff) >> rotate);
-			} else {  
-				disasm_register_shift(di, insn);
-			}
-			break;
-		/* d - destination register (bits 12-15) */
-		case 'd':
-			di->di_printf("r%d", ((insn >> 12) & 0x0f));
-			break;
-		/* D - insert 'p' if Rd is R15 */
-		case 'D':
-			if (((insn >> 12) & 0x0f) == 15)
-				di->di_printf("p");
-			break;
-		/* n - n register (bits 16-19) */
-		case 'n':
-			di->di_printf("r%d", ((insn >> 16) & 0x0f));
-			break;
-		/* s - s register (bits 8-11) */
-		case 's':
-			di->di_printf("r%d", ((insn >> 8) & 0x0f));
-			break;
-		/* o - indirect register rn (bits 16-19) (used by swap) */
-		case 'o':
-			di->di_printf("[r%d]", ((insn >> 16) & 0x0f));
-			break;
-		/* m - m register (bits 0-4) */
-		case 'm':
-			di->di_printf("r%d", ((insn >> 0) & 0x0f));
-			break;
-		/* a - address operand of ldr/str instruction */
-		case 'a':
-			disasm_insn_ldrstr(di, insn, loc);
-			break;
-		/* e - address operand of ldrh/strh instruction */
-		case 'e':
-			disasm_insn_ldrhstrh(di, insn, loc);
-			break;
-		/* l - register list for ldm/stm instruction */
-		case 'l':
-			disasm_print_reglist(di, insn);
-			break;
-		/* f - 1st fp operand (register) (bits 12-14) */
-		case 'f':
-			di->di_printf("f%d", (insn >> 12) & 7);
-			break;
-		/* g - 2nd fp operand (register) (bits 16-18) */
-		case 'g':
-			di->di_printf("f%d", (insn >> 16) & 7);
-			break;
-		/* h - 3rd fp operand (register/immediate) (bits 0-4) */
-		case 'h':
-			if (insn & (1 << 3))
-				di->di_printf("#%s", insn_fpaimm(insn));
-			else
-				di->di_printf("f%d", insn & 7);
-			break;
-		/* j - xtb rotate literal (bits 10-11) */
-		case 'j':
-			di->di_printf("ror #%d", ((insn >> 10) & 3) << 3);
-			break;
-        /* i - bfx lsb literal (bits 7-11) */
-        case 'i':
-            di->di_printf("#%d", (insn >> 7) & 31);
-            break;
-        /* w - bfx width literal (bits 16-20) */
-        case 'w':
-            di->di_printf("#%d", 1 + ((insn >> 16) & 31));
-            break;
-		/* b - branch address */
-		case 'b':
-			branch = ((insn << 2) & 0x03ffffff);
-			if (branch & 0x02000000)
-				branch |= 0xfc000000;
-			di->di_printaddr(loc + 8 + branch);
-			break;
-		/* t - blx address */
-		case 't':
-			branch = ((insn << 2) & 0x03ffffff) |
-			    (insn >> 23 & 0x00000002);
-			if (branch & 0x02000000)
-				branch |= 0xfc000000;
-			di->di_printaddr(loc + 8 + branch);
-			break;
-		/* X - block transfer type */
-		case 'X':
-			di->di_printf("%s", insn_blktrans(insn));
-			break;
-		/* Y - block transfer type (r13 base) */
-		case 'Y':
-			di->di_printf("%s", insn_stkblktrans(insn));
-			break;
-		/* c - comment field bits(0-23) */
-		case 'c':
-			di->di_printf("0x%08x", (insn & 0x00ffffff));
-			break;
-		/* k - breakpoint comment (bits 0-3, 8-19) */
-		case 'k':
-			di->di_printf("0x%04x",
-			    (insn & 0x000fff00) >> 4 | (insn & 0x0000000f));
-			break;
-		/* p - saved or current status register */
-		case 'p':
-			if (insn & 0x00400000)
-				di->di_printf("spsr");
-			else
-				di->di_printf("cpsr");
-			break;
-		/* F - PSR transfer fields */
-		case 'F':
-			di->di_printf("_");
-			if (insn & (1 << 16))
-				di->di_printf("c");
-			if (insn & (1 << 17))
-				di->di_printf("x");
-			if (insn & (1 << 18))
-				di->di_printf("s");
-			if (insn & (1 << 19))
-				di->di_printf("f");
-			break;
-		/* B - byte transfer flag */
-		case 'B':
-			if (insn & 0x00400000)
-				di->di_printf("b");
-			break;
-		/* L - co-processor transfer size */
-		case 'L':
-			if (insn & (1 << 22))
-				di->di_printf("l");
-			break;
-		/* S - set status flag */
-		case 'S':
-			if (insn & 0x00100000)
-				di->di_printf("s");
-			break;
-		/* P - fp precision */
-		case 'P':
-			di->di_printf("%s", insn_fpaprec(insn));
-			break;
-		/* Q - fp precision (for ldf/stf) */
-		case 'Q':
-			break;
-		/* R - fp rounding */
-		case 'R':
-			di->di_printf("%s", insn_fparnd(insn));
-			break;
-		/* W - writeback flag */
-		case 'W':
-			if (insn & (1 << 21))
-				di->di_printf("!");
-			break;
-		/* # - co-processor number */
-		case '#':
-			di->di_printf("p%d", (insn >> 8) & 0x0f);
-			break;
-		/* v - co-processor data transfer registers+addressing mode */
-		case 'v':
-			disasm_insn_ldcstc(di, insn, loc);
-			break;
-		/* x - instruction in hex */
-		case 'x':
-			di->di_printf("0x%08x", insn);
-			break;
-		/* y - co-processor data processing registers */
-		case 'y':
-			di->di_printf("%d, ", (insn >> 20) & 0x0f);
-
-			di->di_printf("c%d, c%d, c%d", (insn >> 12) & 0x0f,
-			    (insn >> 16) & 0x0f, insn & 0x0f);
-
-			di->di_printf(", %d", (insn >> 5) & 0x07);
-			break;
-		/* z - co-processor register transfer registers */
-		case 'z':
-			di->di_printf("%d, ", (insn >> 21) & 0x07);
-			di->di_printf("r%d, c%d, c%d, %d",
-			    (insn >> 12) & 0x0f, (insn >> 16) & 0x0f,
-			    insn & 0x0f, (insn >> 5) & 0x07);
-
-/*			if (((insn >> 5) & 0x07) != 0)
-				di->di_printf(", %d", (insn >> 5) & 0x07);*/
-			break;
-		default:
-			di->di_printf("[%c - unknown]", *f_ptr);
-			break;
-		}
-		if (*(f_ptr+1) >= 'A' && *(f_ptr+1) <= 'Z')
-			++f_ptr;
-		else if (*(++f_ptr)) {
-			++fmt;
-			if (fmt == 1)
-				di->di_printf("\t");
-			else
-				di->di_printf(", ");
-		}
-	};
-
-	di->di_printf("\n");
-
-	return(loc + INSN_SIZE);
-}
-
-
-static void
-disasm_register_shift(const disasm_interface_t *di, u_int insn)
-{
-	di->di_printf("r%d", (insn & 0x0f));
-	if ((insn & 0x00000ff0) == 0)
-		;
-	else if ((insn & 0x00000ff0) == 0x00000060)
-		di->di_printf(", rrx");
-	else {
-		if (insn & 0x10)
-			di->di_printf(", %s r%d", op2_shift(insn),
-			    (insn >> 8) & 0x0f);
-		else
-			di->di_printf(", %s #%d", op2_shift(insn),
-			    (insn >> 7) & 0x1f);
-	}
-}
-
-
-static void
-disasm_print_reglist(const disasm_interface_t *di, u_int insn)
-{
-	int loop;
-	int start;
-	int comma;
-
-	di->di_printf("{");
-	start = -1;
-	comma = 0;
-
-	for (loop = 0; loop < 17; ++loop) {
-		if (start != -1) {
-			if (loop == 16 || !(insn & (1 << loop))) {
-				if (comma)
-					di->di_printf(", ");
-				else
-					comma = 1;
-        			if (start == loop - 1)
-        				di->di_printf("r%d", start);
-        			else
-        				di->di_printf("r%d-r%d", start, loop - 1);
-        			start = -1;
-        		}
-        	} else {
-        		if (insn & (1 << loop))
-        			start = loop;
-        	}
-        }
-	di->di_printf("}");
-
-	if (insn & (1 << 22))
-		di->di_printf("^");
-}
-
-static void
-disasm_insn_ldrstr(const disasm_interface_t *di, u_int insn, u_int loc)
-{
-	int offset;
-
-	offset = insn & 0xfff;
-	if ((insn & 0x032f0000) == 0x010f0000) {
-		/* rA = pc, immediate index */
-		if (insn & 0x00800000)
-			loc += offset;
-		else
-			loc -= offset;
-		di->di_printaddr(loc + 8);
- 	} else {
-		di->di_printf("[r%d", (insn >> 16) & 0x0f);
-		if ((insn & 0x03000fff) != 0x01000000) {
-			di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
-			if (!(insn & 0x00800000))
-				di->di_printf("-");
-			if (insn & (1 << 25))
-				disasm_register_shift(di, insn);
-			else
-				di->di_printf("#0x%03x", offset);
-		}
-		if (insn & (1 << 24))
-			di->di_printf("]");
-	}
-}
-
-static void
-disasm_insn_ldrhstrh(const disasm_interface_t *di, u_int insn, u_int loc)
-{
-	int offset;
-
-	offset = ((insn & 0xf00) >> 4) | (insn & 0xf);
-	if ((insn & 0x004f0000) == 0x004f0000) {
-		/* rA = pc, immediate index */
-		if (insn & 0x00800000)
-			loc += offset;
-		else
-			loc -= offset;
-		di->di_printaddr(loc + 8);
- 	} else {
-		di->di_printf("[r%d", (insn >> 16) & 0x0f);
-		if ((insn & 0x01400f0f) != 0x01400000) {
-			di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
-			if (!(insn & 0x00800000))
-				di->di_printf("-");
-			if (insn & (1 << 22))
-				di->di_printf("#0x%02x", offset);
-			else
-				di->di_printf("r%d", (insn & 0x0f));
-		}
-		if (insn & (1 << 24))
-			di->di_printf("]");
-	}
-}
-
-static void
-disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn, u_int __unused loc)
-{
-	if (((insn >> 8) & 0xf) == 1)
-		di->di_printf("f%d, ", (insn >> 12) & 0x07);
-	else
-		di->di_printf("c%d, ", (insn >> 12) & 0x0f);
-
-	di->di_printf("[r%d", (insn >> 16) & 0x0f);
-
-	di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
-
-	if (!(insn & (1 << 23)))
-		di->di_printf("-");
-
-	di->di_printf("#0x%03x", (insn & 0xff) << 2);
-
-	if (insn & (1 << 24))
-		di->di_printf("]");
-
-	if (insn & (1 << 21))
-		di->di_printf("!");
-}
-
-static u_int
-disassemble_readword(u_int address)
-{
-	return(*((u_int *)address));
-}
-
-static void
-disassemble_printaddr(u_int address)
-{
-	printf("0x%08x", address);
-}
-
-static const disasm_interface_t disassemble_di = {
-	disassemble_readword, disassemble_printaddr, printf
-};
-
-void
-disassemble(u_int address)
-{
-
-	(void)disasm(&disassemble_di, address, 0);
-}
-
-/* End of disassem.c */
diff --git a/libpixelflinger/codeflinger/disassem.h b/libpixelflinger/codeflinger/disassem.h
deleted file mode 100644
index c7c60b6..0000000
--- a/libpixelflinger/codeflinger/disassem.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*	$NetBSD: disassem.h,v 1.4 2001/03/04 04:15:58 matt Exp $	*/
-
-/*-
- * Copyright (c) 1997 Mark Brinicombe.
- * Copyright (c) 1997 Causality Limited.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *	This product includes software developed by Mark Brinicombe.
- * 4. The name of the company nor the name of the author may be used to
- *    endorse or promote products derived from this software without specific
- *    prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 the interface structure required by the disassembler.
- *
- * $FreeBSD: /repoman/r/ncvs/src/sys/arm/include/disassem.h,v 1.2 2005/01/05 21:58:48 imp Exp $
- */
-
-#ifndef ANDROID_MACHINE_DISASSEM_H
-#define ANDROID_MACHINE_DISASSEM_H
-
-#include <sys/types.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
-	u_int	(*di_readword)(u_int);
-	void	(*di_printaddr)(u_int);
-	int	(*di_printf)(const char *, ...);
-} disasm_interface_t;
-
-/* Prototypes for callable functions */
-
-u_int disasm(const disasm_interface_t *, u_int, int);
-void disassemble(u_int);
-
-#if __cplusplus
-}
-#endif
-
-#endif /* !ANDROID_MACHINE_DISASSEM_H */
diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp
deleted file mode 100644
index 4db0a49..0000000
--- a/libpixelflinger/codeflinger/load_store.cpp
+++ /dev/null
@@ -1,384 +0,0 @@
-/* libs/pixelflinger/codeflinger/load_store.cpp
-**
-** Copyright 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.
-*/
-
-#define LOG_TAG "pixelflinger-code"
-
-#include <assert.h>
-#include <stdio.h>
-
-#include <log/log.h>
-
-#include "GGLAssembler.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-void GGLAssembler::store(const pointer_t& addr, const pixel_t& s, uint32_t flags)
-{
-    const int bits = addr.size;
-    const int inc = (flags & WRITE_BACK)?1:0;
-    switch (bits) {
-    case 32:
-        if (inc)    STR(AL, s.reg, addr.reg, immed12_post(4));
-        else        STR(AL, s.reg, addr.reg);
-        break;
-    case 24:
-        // 24 bits formats are a little special and used only for RGB
-        // 0x00BBGGRR is unpacked as R,G,B
-        STRB(AL, s.reg, addr.reg, immed12_pre(0));
-        MOV(AL, 0, s.reg, reg_imm(s.reg, ROR, 8));
-        STRB(AL, s.reg, addr.reg, immed12_pre(1));
-        MOV(AL, 0, s.reg, reg_imm(s.reg, ROR, 8));
-        STRB(AL, s.reg, addr.reg, immed12_pre(2));
-        if (!(s.flags & CORRUPTIBLE)) {
-            MOV(AL, 0, s.reg, reg_imm(s.reg, ROR, 16));
-        }
-        if (inc)
-            ADD(AL, 0, addr.reg, addr.reg, imm(3));
-        break;
-    case 16:
-        if (inc)    STRH(AL, s.reg, addr.reg, immed8_post(2));
-        else        STRH(AL, s.reg, addr.reg);
-        break;
-    case  8:
-        if (inc)    STRB(AL, s.reg, addr.reg, immed12_post(1));
-        else        STRB(AL, s.reg, addr.reg);
-        break;
-    }
-}
-
-void GGLAssembler::load(const pointer_t& addr, const pixel_t& s, uint32_t flags)
-{
-    Scratch scratches(registerFile());
-    int s0;
-
-    const int bits = addr.size;
-    const int inc = (flags & WRITE_BACK)?1:0;
-    switch (bits) {
-    case 32:
-        if (inc)    LDR(AL, s.reg, addr.reg, immed12_post(4));
-        else        LDR(AL, s.reg, addr.reg);
-        break;
-    case 24:
-        // 24 bits formats are a little special and used only for RGB
-        // R,G,B is packed as 0x00BBGGRR
-        s0 = scratches.obtain();
-        if (s.reg != addr.reg) {
-            LDRB(AL, s.reg, addr.reg, immed12_pre(0));      // R
-            LDRB(AL, s0, addr.reg, immed12_pre(1));         // G
-            ORR(AL, 0, s.reg, s.reg, reg_imm(s0, LSL, 8));
-            LDRB(AL, s0, addr.reg, immed12_pre(2));         // B
-            ORR(AL, 0, s.reg, s.reg, reg_imm(s0, LSL, 16));
-        } else {
-            int s1 = scratches.obtain();
-            LDRB(AL, s1, addr.reg, immed12_pre(0));         // R
-            LDRB(AL, s0, addr.reg, immed12_pre(1));         // G
-            ORR(AL, 0, s1, s1, reg_imm(s0, LSL, 8));
-            LDRB(AL, s0, addr.reg, immed12_pre(2));         // B
-            ORR(AL, 0, s.reg, s1, reg_imm(s0, LSL, 16));
-        }
-        if (inc)
-            ADD(AL, 0, addr.reg, addr.reg, imm(3));
-        break;
-    case 16:
-        if (inc)    LDRH(AL, s.reg, addr.reg, immed8_post(2));
-        else        LDRH(AL, s.reg, addr.reg);
-        break;
-    case  8:
-        if (inc)    LDRB(AL, s.reg, addr.reg, immed12_post(1));
-        else        LDRB(AL, s.reg, addr.reg);
-        break;
-    }
-}
-
-void GGLAssembler::extract(integer_t& d, int s, int h, int l, int bits)
-{
-    const int maskLen = h-l;
-
-#ifdef __mips__
-    assert(maskLen<=11);
-#else
-    assert(maskLen<=8);
-#endif
-    assert(h);
-
-    if (h != bits) {
-        const int mask = ((1<<maskLen)-1) << l;
-        if (isValidImmediate(mask)) {
-            AND(AL, 0, d.reg, s, imm(mask));    // component = packed & mask;
-        } else if (isValidImmediate(~mask)) {
-            BIC(AL, 0, d.reg, s, imm(~mask));   // component = packed & mask;
-        } else {
-            MOV(AL, 0, d.reg, reg_imm(s, LSL, 32-h));
-            l += 32-h;
-            h = 32;
-        }
-        s = d.reg;
-    }
-
-    if (l) {
-        MOV(AL, 0, d.reg, reg_imm(s, LSR, l));  // component = packed >> l;
-        s = d.reg;
-    }
-
-    if (s != d.reg) {
-        MOV(AL, 0, d.reg, s);
-    }
-
-    d.s = maskLen;
-}
-
-void GGLAssembler::extract(integer_t& d, const pixel_t& s, int component)
-{
-    extract(d,  s.reg,
-                s.format.c[component].h,
-                s.format.c[component].l,
-                s.size());
-}
-
-void GGLAssembler::extract(component_t& d, const pixel_t& s, int component)
-{
-    integer_t r(d.reg, 32, d.flags);
-    extract(r,  s.reg,
-                s.format.c[component].h,
-                s.format.c[component].l,
-                s.size());
-    d = component_t(r);
-}
-
-
-void GGLAssembler::expand(integer_t& d, const component_t& s, int dbits)
-{
-    if (s.l || (s.flags & CLEAR_HI)) {
-        extract(d, s.reg, s.h, s.l, 32);
-        expand(d, d, dbits);
-    } else {
-        expand(d, integer_t(s.reg, s.size(), s.flags), dbits);
-    }
-}
-
-void GGLAssembler::expand(component_t& d, const component_t& s, int dbits)
-{
-    integer_t r(d.reg, 32, d.flags);
-    expand(r, s, dbits);
-    d = component_t(r);
-}
-
-void GGLAssembler::expand(integer_t& dst, const integer_t& src, int dbits)
-{
-    assert(src.size());
-
-    int sbits = src.size();
-    int s = src.reg;
-    int d = dst.reg;
-
-    // be sure to set 'dst' after we read 'src' as they may be identical
-    dst.s = dbits;
-    dst.flags = 0;
-
-    if (dbits<=sbits) {
-        if (s != d) {
-            MOV(AL, 0, d, s);
-        }
-        return;
-    }
-
-    if (sbits == 1) {
-        RSB(AL, 0, d, s, reg_imm(s, LSL, dbits));
-            // d = (s<<dbits) - s;
-        return;
-    }
-
-    if (dbits % sbits) {
-        MOV(AL, 0, d, reg_imm(s, LSL, dbits-sbits));
-            // d = s << (dbits-sbits);
-        dbits -= sbits;
-        do {
-            ORR(AL, 0, d, d, reg_imm(d, LSR, sbits));
-                // d |= d >> sbits;
-            dbits -= sbits;
-            sbits *= 2;
-        } while(dbits>0);
-        return;
-    }
-
-    dbits -= sbits;
-    do {
-        ORR(AL, 0, d, s, reg_imm(s, LSL, sbits));
-            // d |= d<<sbits;
-        s = d;
-        dbits -= sbits;
-        if (sbits*2 < dbits) {
-            sbits *= 2;
-        }
-    } while(dbits>0);
-}
-
-void GGLAssembler::downshift(
-        pixel_t& d, int component, component_t s, const reg_t& dither)
-{
-    Scratch scratches(registerFile());
-
-    int sh = s.h;
-    int sl = s.l;
-    int maskHiBits = (sh!=32) ? ((s.flags & CLEAR_HI)?1:0) : 0;
-    int maskLoBits = (sl!=0)  ? ((s.flags & CLEAR_LO)?1:0) : 0;
-    int sbits = sh - sl;
-
-    int dh = d.format.c[component].h;
-    int dl = d.format.c[component].l;
-    int dbits = dh - dl;
-    int dithering = 0;
-
-    ALOGE_IF(sbits<dbits, "sbits (%d) < dbits (%d) in downshift", sbits, dbits);
-
-    if (sbits>dbits) {
-        // see if we need to dither
-        dithering = mDithering;
-    }
-
-    int ireg = d.reg;
-    if (!(d.flags & FIRST)) {
-        if (s.flags & CORRUPTIBLE)  {
-            ireg = s.reg;
-        } else {
-            ireg = scratches.obtain();
-        }
-    }
-    d.flags &= ~FIRST;
-
-    if (maskHiBits) {
-        // we need to mask the high bits (and possibly the lowbits too)
-        // and we might be able to use immediate mask.
-        if (!dithering) {
-            // we don't do this if we only have maskLoBits because we can
-            // do it more efficiently below (in the case where dl=0)
-            const int offset = sh - dbits;
-            if (dbits<=8 && offset >= 0) {
-                const uint32_t mask = ((1<<dbits)-1) << offset;
-                if (isValidImmediate(mask) || isValidImmediate(~mask)) {
-                    build_and_immediate(ireg, s.reg, mask, 32);
-                    sl = offset;
-                    s.reg = ireg;
-                    sbits = dbits;
-                    maskLoBits = maskHiBits = 0;
-                }
-            }
-        } else {
-            // in the dithering case though, we need to preserve the lower bits
-            const uint32_t mask = ((1<<sbits)-1) << sl;
-            if (isValidImmediate(mask) || isValidImmediate(~mask)) {
-                build_and_immediate(ireg, s.reg, mask, 32);
-                s.reg = ireg;
-                maskLoBits = maskHiBits = 0;
-            }
-        }
-    }
-
-    // XXX: we could special case (maskHiBits & !maskLoBits)
-    // like we do for maskLoBits below, but it happens very rarely
-    // that we have maskHiBits only and the conditions necessary to lead
-    // to better code (like doing d |= s << 24)
-
-    if (maskHiBits) {
-        MOV(AL, 0, ireg, reg_imm(s.reg, LSL, 32-sh));
-        sl += 32-sh;
-        sh = 32;
-        s.reg = ireg;
-        maskHiBits = 0;
-    }
-
-    //	Downsampling should be performed as follows:
-    //  V * ((1<<dbits)-1) / ((1<<sbits)-1)
-    //	V * [(1<<dbits)/((1<<sbits)-1)	-	1/((1<<sbits)-1)]
-    //	V * [1/((1<<sbits)-1)>>dbits	-	1/((1<<sbits)-1)]
-    //	V/((1<<(sbits-dbits))-(1>>dbits))	-	(V>>sbits)/((1<<sbits)-1)>>sbits
-    //	V/((1<<(sbits-dbits))-(1>>dbits))	-	(V>>sbits)/(1-(1>>sbits))
-    //
-    //	By approximating (1>>dbits) and (1>>sbits) to 0:
-    //
-    //		V>>(sbits-dbits)	-	V>>sbits
-    //
-	//  A good approximation is V>>(sbits-dbits),
-    //  but better one (needed for dithering) is:
-    //
-    //		(V>>(sbits-dbits)<<sbits	-	V)>>sbits
-    //		(V<<dbits	-	V)>>sbits
-    //		(V	-	V>>dbits)>>(sbits-dbits)
-
-    // Dithering is done here
-    if (dithering) {
-        comment("dithering");
-        if (sl) {
-            MOV(AL, 0, ireg, reg_imm(s.reg, LSR, sl));
-            sh -= sl;
-            sl = 0;
-            s.reg = ireg;
-        }
-        // scaling (V-V>>dbits)
-        SUB(AL, 0, ireg, s.reg, reg_imm(s.reg, LSR, dbits));
-        const int shift = (GGL_DITHER_BITS - (sbits-dbits));
-        if (shift>0)        ADD(AL, 0, ireg, ireg, reg_imm(dither.reg, LSR, shift));
-        else if (shift<0)   ADD(AL, 0, ireg, ireg, reg_imm(dither.reg, LSL,-shift));
-        else                ADD(AL, 0, ireg, ireg, dither.reg);
-        s.reg = ireg;
-    }
-
-    if ((maskLoBits|dithering) && (sh > dbits)) {
-        int shift = sh-dbits;
-        if (dl) {
-            MOV(AL, 0, ireg, reg_imm(s.reg, LSR, shift));
-            if (ireg == d.reg) {
-                MOV(AL, 0, d.reg, reg_imm(ireg, LSL, dl));
-            } else {
-                ORR(AL, 0, d.reg, d.reg, reg_imm(ireg, LSL, dl));
-            }
-        } else {
-            if (ireg == d.reg) {
-                MOV(AL, 0, d.reg, reg_imm(s.reg, LSR, shift));
-            } else {
-                ORR(AL, 0, d.reg, d.reg, reg_imm(s.reg, LSR, shift));
-            }
-        }
-    } else {
-        int shift = sh-dh;
-        if (shift>0) {
-            if (ireg == d.reg) {
-                MOV(AL, 0, d.reg, reg_imm(s.reg, LSR, shift));
-            } else {
-                ORR(AL, 0, d.reg, d.reg, reg_imm(s.reg, LSR, shift));
-            }
-        } else if (shift<0) {
-            if (ireg == d.reg) {
-                MOV(AL, 0, d.reg, reg_imm(s.reg, LSL, -shift));
-            } else {
-                ORR(AL, 0, d.reg, d.reg, reg_imm(s.reg, LSL, -shift));
-            }
-        } else {
-            if (ireg == d.reg) {
-                if (s.reg != d.reg) {
-                    MOV(AL, 0, d.reg, s.reg);
-                }
-            } else {
-                ORR(AL, 0, d.reg, d.reg, s.reg);
-            }
-        }
-    }
-}
-
-}; // namespace android
diff --git a/libpixelflinger/codeflinger/mips64_disassem.c b/libpixelflinger/codeflinger/mips64_disassem.c
deleted file mode 100644
index 8528299..0000000
--- a/libpixelflinger/codeflinger/mips64_disassem.c
+++ /dev/null
@@ -1,584 +0,0 @@
-/*  $NetBSD: db_disasm.c,v 1.19 2007/02/28 04:21:53 thorpej Exp $   */
-
-/*-
- * Copyright (c) 1991, 1993
- *  The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ralph Campbell.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- *
- *  from: @(#)kadb.c    8.1 (Berkeley) 6/10/93
- */
-
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-#include <android/log.h>
-
-#include "mips_opcode.h"
-
-#define __unused __attribute__((__unused__))
-
-static char *sprintf_buffer;
-static int sprintf_buf_len;
-
-typedef uint64_t db_addr_t;
-static void db_printf(const char* fmt, ...);
-
-static const char * const op_name[64] = {
-/* 0 */ "spec", "bcond", "j", "jal", "beq", "bne", "blez", "bgtz",
-/* 8 */ "pop10", "addiu", "slti", "sltiu", "andi", "ori", "xori", "aui",
-/*16 */ "cop0", "cop1", "cop2", "?", "?", "?", "pop26", "pop27",
-/*24 */ "pop30", "daddiu", "?", "?", "?", "daui", "msa", "op37",
-/*32 */ "lb", "lh", "?",  "lw", "lbu", "lhu", "?", "lwu",
-/*40 */ "sb", "sh", "?", "sw", "?", "?", "?", "?",
-/*48 */ "?", "lwc1", "bc", "?", "?",  "ldc1", "pop66", "ld",
-/*56 */ "?", "swc1", "balc", "pcrel", "?", "sdc1", "pop76", "sd"
-};
-
-static const char * const spec_name[64] = {
-/* 0 */ "sll", "?", "srl", "sra", "sllv", "?", "srlv", "srav",
-/* 8 */ "?", "jalr", "?", "?", "syscall", "break", "sdbpp", "sync",
-/*16 */ "clz", "clo", "dclz", "dclo", "dsllv", "dlsa", "dsrlv", "dsrav",
-/*24 */ "sop30", "sop31", "sop32", "sop33", "sop34", "sop35", "sop36", "sop37",
-/*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor",
-/*40 */ "?", "?", "slt", "sltu", "dadd", "daddu", "dsub", "dsubu",
-/*48 */ "tge", "tgeu", "tlt", "tltu", "teq", "seleqz", "tne", "selnez",
-/*56 */ "dsll", "?", "dsrl", "dsra", "dsll32", "?", "dsrl32", "dsra32"
-};
-
-static const char * const bcond_name[32] = {
-/* 0 */ "bltz", "bgez", "?", "?", "?", "?", "dahi", "?",
-/* 8 */ "?", "?", "?", "?", "?", "?", "?", "?",
-/*16 */ "nal", "bal", "?", "?", "?", "?", "?", "sigrie",
-/*24 */ "?", "?", "?", "?", "?", "?", "dati", "synci",
-};
-
-static const char * const cop1_name[64] = {
-/* 0 */ "fadd",  "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg",
-/* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f",
-/*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17",
-/*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f",
-/*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27",
-/*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f",
-/*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult",
-    "fcmp.ole","fcmp.ule",
-/*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge",
-    "fcmp.le","fcmp.ngt"
-};
-
-static const char * const fmt_name[16] = {
-    "s",    "d",    "e",    "fmt3",
-    "w",    "fmt5", "fmt6", "fmt7",
-    "fmt8", "fmt9", "fmta", "fmtb",
-    "fmtc", "fmtd", "fmte", "fmtf"
-};
-
-static char * const mips_reg_name[32] = {
-    "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
-    "a4",   "a5",   "a6",   "a7",   "t0",   "t1",   "t2",   "t3",
-    "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
-    "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
-};
-
-static char * alt_arm_reg_name[32] = {  // hacked names for comparison with ARM code
-    "zero", "at",   "r0",   "r1",   "r2",   "r3",   "r4",   "r5",
-    "r6",   "r7",   "r8",   "r9",   "r10",  "r11",  "r12",  "r13",
-    "r14",  "r15",  "at2",  "cmp",  "s4",   "s5",   "s6",   "s7",
-    "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
-};
-
-static char * const * reg_name =  &mips_reg_name[0];
-
-static const char * const c0_opname[64] = {
-    "c0op00","tlbr",  "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07",
-    "tlbp",  "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17",
-    "rfe",   "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27",
-    "eret",  "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37",
-    "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47",
-    "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57",
-    "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67",
-    "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77",
-};
-
-static const char * const c0_reg[32] = {
-    "index",    "random",   "tlblo0",  "tlblo1",
-    "context",  "pagemask", "wired",   "cp0r7",
-    "badvaddr", "count",    "tlbhi",   "compare",
-    "status",   "cause",    "epc",     "prid",
-    "config",   "lladdr",   "watchlo", "watchhi",
-    "xcontext", "cp0r21",   "cp0r22",  "debug",
-    "depc",     "perfcnt",  "ecc",     "cacheerr",
-    "taglo",    "taghi",    "errepc",  "desave"
-};
-
-static void print_addr(db_addr_t);
-db_addr_t mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format);
-
-
-/*
- * Disassemble instruction 'insn' nominally at 'loc'.
- * 'loc' may in fact contain a breakpoint instruction.
- */
-static db_addr_t
-db_disasm_insn(int insn, db_addr_t loc, bool altfmt __unused)
-{
-    bool bdslot = false;
-    InstFmt i;
-
-    i.word = insn;
-
-    switch (i.JType.op) {
-    case OP_SPECIAL:
-        if (i.word == 0) {
-            db_printf("nop");
-            break;
-        }
-        if (i.word == 0x0080) {
-            db_printf("NIY");
-            break;
-        }
-        if (i.word == 0x00c0) {
-            db_printf("NOT IMPL");
-            break;
-        }
-        /* Special cases --------------------------------------------------
-         * "addu" is a "move" only in 32-bit mode.  What's the correct
-         * answer - never decode addu/daddu as "move"?
-         */
-        if ( (i.RType.func == OP_ADDU && i.RType.rt == 0)  ||
-             (i.RType.func == OP_OR   && i.RType.rt == 0) ) {
-            db_printf("move\t%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rs]);
-            break;
-        }
-
-        if (i.RType.func == OP_SRL && (i.RType.rs & 1) == 1) {
-            db_printf("rotr\t%s,%s,%d", reg_name[i.RType.rd],
-                reg_name[i.RType.rt], i.RType.shamt);
-            break;
-        }
-        if (i.RType.func == OP_SRLV && (i.RType.shamt & 1) == 1) {
-            db_printf("rotrv\t%s,%s,%s", reg_name[i.RType.rd],
-                reg_name[i.RType.rt], reg_name[i.RType.rs]);
-            break;
-        }
-
-        if (i.RType.func == OP_SOP30) {
-            if (i.RType.shamt == OP_MUL) {
-                db_printf("mul");
-            } else if (i.RType.shamt == OP_MUH) {
-                db_printf("muh");
-            }
-            db_printf("\t%s,%s,%s", reg_name[i.RType.rd],
-                reg_name[i.RType.rs], reg_name[i.RType.rt]);
-            break;
-        }
-        if (i.RType.func == OP_SOP31) {
-            if (i.RType.shamt == OP_MUL) {
-                db_printf("mulu");
-            } else if (i.RType.shamt == OP_MUH) {
-                db_printf("muhu");
-            }
-            db_printf("\t%s,%s,%s", reg_name[i.RType.rd],
-                reg_name[i.RType.rs], reg_name[i.RType.rt]);
-            break;
-        }
-
-        if (i.RType.func == OP_JALR && i.RType.rd == 0) {
-            db_printf("jr\t%s", reg_name[i.RType.rs]);
-            bdslot = true;
-            break;
-        }
-
-        db_printf("%s", spec_name[i.RType.func]);
-        switch (i.RType.func) {
-        case OP_SLL:
-        case OP_SRL:
-        case OP_SRA:
-        case OP_DSLL:
-
-        case OP_DSRL:
-        case OP_DSRA:
-        case OP_DSLL32:
-        case OP_DSRL32:
-        case OP_DSRA32:
-            db_printf("\t%s,%s,%d",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rt],
-                i.RType.shamt);
-            break;
-
-        case OP_SLLV:
-        case OP_SRLV:
-        case OP_SRAV:
-        case OP_DSLLV:
-        case OP_DSRLV:
-        case OP_DSRAV:
-            db_printf("\t%s,%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rt],
-                reg_name[i.RType.rs]);
-            break;
-
-        case OP_CLZ:
-        case OP_CLO:
-        case OP_DCLZ:
-        case OP_DCLO:
-            db_printf("\t%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rs]);
-            break;
-
-        case OP_JALR:
-            db_printf("\t");
-            if (i.RType.rd != 31) {
-                db_printf("%s,", reg_name[i.RType.rd]);
-            }
-            db_printf("%s", reg_name[i.RType.rs]);
-            bdslot = true;
-            break;
-
-        case OP_SYSCALL:
-        case OP_SYNC:
-            break;
-
-        case OP_BREAK:
-            db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt);
-            break;
-
-        default:
-            db_printf("\t%s,%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rs],
-                reg_name[i.RType.rt]);
-        }
-        break;
-
-    case OP_SPECIAL3:
-        if (i.RType.func == OP_EXT)
-            db_printf("ext\t%s,%s,%d,%d",
-                    reg_name[i.RType.rt],
-                    reg_name[i.RType.rs],
-                    i.RType.shamt,
-                    i.RType.rd+1);
-        else if (i.RType.func == OP_DEXT)
-            db_printf("dext\t%s,%s,%d,%d",
-                    reg_name[i.RType.rt],
-                    reg_name[i.RType.rs],
-                    i.RType.shamt,
-                    i.RType.rd+1);
-        else if (i.RType.func == OP_DEXTM)
-            db_printf("dextm\t%s,%s,%d,%d",
-                    reg_name[i.RType.rt],
-                    reg_name[i.RType.rs],
-                    i.RType.shamt,
-                    i.RType.rd+33);
-        else if (i.RType.func == OP_DEXTU)
-            db_printf("dextu\t%s,%s,%d,%d",
-                    reg_name[i.RType.rt],
-                    reg_name[i.RType.rs],
-                    i.RType.shamt+32,
-                    i.RType.rd+1);
-        else if (i.RType.func == OP_INS)
-            db_printf("ins\t%s,%s,%d,%d",
-                    reg_name[i.RType.rt],
-                    reg_name[i.RType.rs],
-                    i.RType.shamt,
-                    i.RType.rd-i.RType.shamt+1);
-        else if (i.RType.func == OP_DINS)
-            db_printf("dins\t%s,%s,%d,%d",
-                    reg_name[i.RType.rt],
-                    reg_name[i.RType.rs],
-                    i.RType.shamt,
-                    i.RType.rd-i.RType.shamt+1);
-        else if (i.RType.func == OP_DINSM)
-            db_printf("dinsm\t%s,%s,%d,%d",
-                    reg_name[i.RType.rt],
-                    reg_name[i.RType.rs],
-                    i.RType.shamt,
-                    i.RType.rd-i.RType.shamt+33);
-        else if (i.RType.func == OP_DINSU)
-            db_printf("dinsu\t%s,%s,%d,%d",
-                    reg_name[i.RType.rt],
-                    reg_name[i.RType.rs],
-                    i.RType.shamt+32,
-                    i.RType.rd-i.RType.shamt+1);
-        else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_WSBH)
-            db_printf("wsbh\t%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rt]);
-        else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_SEB)
-            db_printf("seb\t%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rt]);
-        else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_SEH)
-            db_printf("seh\t%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rt]);
-        else if (i.RType.func == OP_RDHWR)
-            db_printf("rdhwr\t%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rt]);
-        else
-            db_printf("Unknown");
-        break;
-
-    case OP_BCOND:
-        db_printf("%s\t%s,", bcond_name[i.IType.rt],
-            reg_name[i.IType.rs]);
-        goto pr_displ;
-
-    case OP_BLEZ:
-    case OP_BGTZ:
-        db_printf("%s\t%s,", op_name[i.IType.op],
-            reg_name[i.IType.rs]);
-        goto pr_displ;
-
-    case OP_BEQ:
-        if (i.IType.rs == 0 && i.IType.rt == 0) {
-            db_printf("b\t");
-            goto pr_displ;
-        }
-        /* FALLTHROUGH */
-    case OP_BNE:
-        db_printf("%s\t%s,%s,", op_name[i.IType.op],
-            reg_name[i.IType.rs],
-            reg_name[i.IType.rt]);
-    pr_displ:
-        print_addr(loc + 4 + ((short)i.IType.imm << 2));
-        bdslot = true;
-        break;
-
-    case OP_COP0:
-        switch (i.RType.rs) {
-        case OP_BCx:
-        case OP_BCy:
-
-            db_printf("bc0%c\t",
-                "ft"[i.RType.rt & COPz_BC_TF_MASK]);
-            goto pr_displ;
-
-        case OP_MT:
-            db_printf("mtc0\t%s,%s",
-                reg_name[i.RType.rt],
-                c0_reg[i.RType.rd]);
-            break;
-
-        case OP_DMT:
-            db_printf("dmtc0\t%s,%s",
-                reg_name[i.RType.rt],
-                c0_reg[i.RType.rd]);
-            break;
-
-        case OP_MF:
-            db_printf("mfc0\t%s,%s",
-                reg_name[i.RType.rt],
-                c0_reg[i.RType.rd]);
-            break;
-
-        case OP_DMF:
-            db_printf("dmfc0\t%s,%s",
-                reg_name[i.RType.rt],
-                c0_reg[i.RType.rd]);
-            break;
-
-        default:
-            db_printf("%s", c0_opname[i.FRType.func]);
-        }
-        break;
-
-    case OP_COP1:
-        switch (i.RType.rs) {
-        case OP_BCx:
-        case OP_BCy:
-            db_printf("bc1%c\t",
-                "ft"[i.RType.rt & COPz_BC_TF_MASK]);
-            goto pr_displ;
-
-        case OP_MT:
-            db_printf("mtc1\t%s,f%d",
-                reg_name[i.RType.rt],
-                i.RType.rd);
-            break;
-
-        case OP_MF:
-            db_printf("mfc1\t%s,f%d",
-                reg_name[i.RType.rt],
-                i.RType.rd);
-            break;
-
-        case OP_CT:
-            db_printf("ctc1\t%s,f%d",
-                reg_name[i.RType.rt],
-                i.RType.rd);
-            break;
-
-        case OP_CF:
-            db_printf("cfc1\t%s,f%d",
-                reg_name[i.RType.rt],
-                i.RType.rd);
-            break;
-
-        default:
-            db_printf("%s.%s\tf%d,f%d,f%d",
-                cop1_name[i.FRType.func],
-                fmt_name[i.FRType.fmt],
-                i.FRType.fd, i.FRType.fs, i.FRType.ft);
-        }
-        break;
-
-    case OP_J:
-    case OP_JAL:
-        db_printf("%s\t", op_name[i.JType.op]);
-        print_addr((loc & 0xFFFFFFFFF0000000) | (i.JType.target << 2));
-        bdslot = true;
-        break;
-
-    case OP_LWC1:
-    case OP_SWC1:
-        db_printf("%s\tf%d,", op_name[i.IType.op],
-            i.IType.rt);
-        goto loadstore;
-
-    case OP_LB:
-    case OP_LH:
-    case OP_LW:
-    case OP_LD:
-    case OP_LBU:
-    case OP_LHU:
-    case OP_LWU:
-    case OP_SB:
-    case OP_SH:
-    case OP_SW:
-    case OP_SD:
-        db_printf("%s\t%s,", op_name[i.IType.op],
-            reg_name[i.IType.rt]);
-    loadstore:
-        db_printf("%d(%s)", (short)i.IType.imm,
-            reg_name[i.IType.rs]);
-        break;
-
-    case OP_ORI:
-    case OP_XORI:
-        if (i.IType.rs == 0) {
-            db_printf("li\t%s,0x%x",
-                reg_name[i.IType.rt],
-                i.IType.imm);
-            break;
-        }
-        /* FALLTHROUGH */
-    case OP_ANDI:
-        db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op],
-            reg_name[i.IType.rt],
-            reg_name[i.IType.rs],
-            i.IType.imm);
-        break;
-
-    case OP_AUI:
-        if (i.IType.rs == 0) {
-            db_printf("lui\t%s,0x%x", reg_name[i.IType.rt],
-                i.IType.imm);
-        } else {
-            db_printf("%s\t%s,%s,%d", op_name[i.IType.op],
-            reg_name[i.IType.rt], reg_name[i.IType.rs],
-            (short)i.IType.imm);
-        }
-        break;
-
-    case OP_ADDIU:
-    case OP_DADDIU:
-        if (i.IType.rs == 0) {
-            db_printf("li\t%s,%d",
-                reg_name[i.IType.rt],
-                (short)i.IType.imm);
-            break;
-        }
-        /* FALLTHROUGH */
-    default:
-        db_printf("%s\t%s,%s,%d", op_name[i.IType.op],
-            reg_name[i.IType.rt],
-            reg_name[i.IType.rs],
-            (short)i.IType.imm);
-    }
-    // db_printf("\n");
-    // if (bdslot) {
-    //     db_printf("   bd: ");
-    //     mips_disassem(loc+4);
-    //     return (loc + 8);
-    // }
-    return (loc + 4);
-}
-
-static void
-print_addr(db_addr_t loc)
-{
-    db_printf("0x%08lx", loc);
-}
-
-static void db_printf(const char* fmt, ...)
-{
-    int cnt;
-    va_list argp;
-    va_start(argp, fmt);
-    if (sprintf_buffer) {
-        cnt = vsnprintf(sprintf_buffer, sprintf_buf_len, fmt, argp);
-        sprintf_buffer += cnt;
-        sprintf_buf_len -= cnt;
-    } else {
-        vprintf(fmt, argp);
-    }
-    va_end(argp);
-}
-
-/*
- * Disassemble instruction at 'loc'.
- * Return address of start of next instruction.
- * Since this function is used by 'examine' and by 'step'
- * "next instruction" does NOT mean the next instruction to
- * be executed but the 'linear' next instruction.
- */
-db_addr_t
-mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format)
-{
-    u_int32_t instr;
-
-    if (alt_dis_format) {   // use ARM register names for disassembly
-        reg_name = &alt_arm_reg_name[0];
-    }
-
-    sprintf_buffer = di_buffer;     // quick 'n' dirty printf() vs sprintf()
-    sprintf_buf_len = 39;           // should be passed in
-
-    instr =  *(u_int32_t *)loc;
-    return (db_disasm_insn(instr, loc, false));
-}
diff --git a/libpixelflinger/codeflinger/mips64_disassem.h b/libpixelflinger/codeflinger/mips64_disassem.h
deleted file mode 100644
index c94f04f..0000000
--- a/libpixelflinger/codeflinger/mips64_disassem.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*  $NetBSD: db_disasm.c,v 1.19 2007/02/28 04:21:53 thorpej Exp $   */
-
-/*-
- * Copyright (c) 1991, 1993
- *  The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ralph Campbell.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- *
- *  from: @(#)kadb.c    8.1 (Berkeley) 6/10/93
- */
-
-
-
-#ifndef ANDROID_MIPS_DISASSEM_H
-#define ANDROID_MIPS_DISASSEM_H
-
-#include <sys/types.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-/* Prototypes for callable functions */
-
-void mips_disassem(uint32_t *location, char *di_buffer, int alt_fmt);
-
-#if __cplusplus
-}
-#endif
-
-#endif /* !ANDROID_MIPS_DISASSEM_H */
diff --git a/libpixelflinger/codeflinger/mips_disassem.c b/libpixelflinger/codeflinger/mips_disassem.c
deleted file mode 100644
index 1fe6806..0000000
--- a/libpixelflinger/codeflinger/mips_disassem.c
+++ /dev/null
@@ -1,592 +0,0 @@
-/*  $NetBSD: db_disasm.c,v 1.19 2007/02/28 04:21:53 thorpej Exp $   */
-
-/*-
- * Copyright (c) 1991, 1993
- *  The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ralph Campbell.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- *
- *  from: @(#)kadb.c    8.1 (Berkeley) 6/10/93
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <sys/cdefs.h>
-
-#include <sys/types.h>
-#include "mips_opcode.h"
-
-
-// #include <sys/systm.h>
-// #include <sys/param.h>
-
-// #include <machine/reg.h>
-// #include <machine/cpu.h>
-/*#include <machine/param.h>*/
-// #include <machine/db_machdep.h>
-
-// #include <ddb/db_interface.h>
-// #include <ddb/db_output.h>
-// #include <ddb/db_extern.h>
-// #include <ddb/db_sym.h>
-
-#define __unused __attribute__((__unused__))
-
-static char *sprintf_buffer;
-static int sprintf_buf_len;
-
-
-typedef uint32_t db_addr_t;
-static void db_printf(const char* fmt, ...);
-
-static const char * const op_name[64] = {
-/* 0 */ "spec", "bcond","j  ",    "jal",  "beq",  "bne",  "blez", "bgtz",
-/* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori",  "xori", "lui",
-/*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl",
-/*24 */ "daddi","daddiu","ldl", "ldr",  "op34", "op35", "op36", "op37",
-/*32 */ "lb ",   "lh ",   "lwl",  "lw ",   "lbu",  "lhu",  "lwr",  "lwu",
-/*40 */ "sb ",   "sh ",   "swl",  "sw ",   "sdl",  "sdr",  "swr",  "cache",
-/*48 */ "ll ",   "lwc1", "lwc2", "lwc3", "lld",  "ldc1", "ldc2", "ld ",
-/*56 */ "sc ",   "swc1", "swc2", "swc3", "scd",  "sdc1", "sdc2", "sd "
-};
-
-static const char * const spec_name[64] = {
-/* 0 */ "sll",  "spec01","srl", "sra",  "sllv", "spec05","srlv","srav",
-/* 8 */ "jr",   "jalr", "movz","movn","syscall","break","spec16","sync",
-/*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav",
-/*24 */ "mult", "multu","div",  "divu", "dmult","dmultu","ddiv","ddivu",
-/*32 */ "add",  "addu", "sub",  "subu", "and",  "or ",   "xor",  "nor",
-/*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu",
-/*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67",
-/*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32"
-};
-
-static const char * const spec2_name[64] = {     /* QED RM4650, R5000, etc. */
-/* 0x00 */ "madd", "maddu", "mul", "spec3", "msub", "msubu", "rsrv6", "rsrv7",
-/* 0x08 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
-/* 0x10 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
-/* 0x18 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
-/* 0x20 */ "clz",  "clo",  "rsrv", "rsrv", "dclz", "dclo", "rsrv", "rsrv",
-/* 0x28 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
-/* 0x30 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
-/* 0x38 */ "rsrv", "rsrv", "rsrv", "resv", "rsrv", "rsrv", "rsrv", "sdbbp"
-};
-
-static const char * const bcond_name[32] = {
-/* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?",
-/* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?",
-/*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?",
-/*24 */ "?", "?", "?", "?", "?", "?", "?", "?",
-};
-
-static const char * const cop1_name[64] = {
-/* 0 */ "fadd",  "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg",
-/* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f",
-/*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17",
-/*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f",
-/*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27",
-/*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f",
-/*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult",
-    "fcmp.ole","fcmp.ule",
-/*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge",
-    "fcmp.le","fcmp.ngt"
-};
-
-static const char * const fmt_name[16] = {
-    "s",    "d",    "e",    "fmt3",
-    "w",    "fmt5", "fmt6", "fmt7",
-    "fmt8", "fmt9", "fmta", "fmtb",
-    "fmtc", "fmtd", "fmte", "fmtf"
-};
-
-#if defined(__mips_n32) || defined(__mips_n64)
-static char * const reg_name[32] = {
-    "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
-    "a4",   "a5",   "a6",   "a7",   "t0",   "t1",   "t2",   "t3",
-    "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
-    "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
-};
-#else
-
-static char * alt_arm_reg_name[32] = {  // hacked names for comparison with ARM code
-    "zero", "at",   "r0",   "r1",   "r2",   "r3",   "r4",   "r5",
-    "r6",   "r7",   "r8",   "r9",   "r10",  "r11",  "r12",  "r13",
-    "r14",  "r15",  "at2",  "cmp",  "s4",   "s5",   "s6",   "s7",
-    "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
-};
-
-static char * mips_reg_name[32] = {
-    "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
-    "t0",   "t1",   "t2",   "t3",   "t4",   "t5",   "t6",   "t7",
-    "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
-    "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
-};
-
-static char ** reg_name =  &mips_reg_name[0];
-
-#endif /* __mips_n32 || __mips_n64 */
-
-static const char * const c0_opname[64] = {
-    "c0op00","tlbr",  "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07",
-    "tlbp",  "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17",
-    "rfe",   "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27",
-    "eret",  "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37",
-    "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47",
-    "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57",
-    "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67",
-    "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77",
-};
-
-static const char * const c0_reg[32] = {
-    "index",    "random",   "tlblo0",  "tlblo1",
-    "context",  "pagemask", "wired",   "cp0r7",
-    "badvaddr", "count",    "tlbhi",   "compare",
-    "status",   "cause",    "epc",     "prid",
-    "config",   "lladdr",   "watchlo", "watchhi",
-    "xcontext", "cp0r21",   "cp0r22",  "debug",
-    "depc",     "perfcnt",  "ecc",     "cacheerr",
-    "taglo",    "taghi",    "errepc",  "desave"
-};
-
-static void print_addr(db_addr_t);
-db_addr_t mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format);
-
-
-/*
- * Disassemble instruction 'insn' nominally at 'loc'.
- * 'loc' may in fact contain a breakpoint instruction.
- */
-static db_addr_t
-db_disasm_insn(int insn, db_addr_t loc, bool altfmt __unused)
-{
-    bool bdslot = false;
-    InstFmt i;
-
-    i.word = insn;
-
-    switch (i.JType.op) {
-    case OP_SPECIAL:
-        if (i.word == 0) {
-            db_printf("nop");
-            break;
-        }
-        if (i.word == 0x0080) {
-            db_printf("NIY");
-            break;
-        }
-        if (i.word == 0x00c0) {
-            db_printf("NOT IMPL");
-            break;
-        }
-        /* Special cases --------------------------------------------------
-         * "addu" is a "move" only in 32-bit mode.  What's the correct
-         * answer - never decode addu/daddu as "move"?
-         */
-        if ( (i.RType.func == OP_ADDU && i.RType.rt == 0)  ||
-             (i.RType.func == OP_OR   && i.RType.rt == 0) ) {
-            db_printf("move\t%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rs]);
-            break;
-        }
-        // mips32r2, rotr & rotrv
-        if (i.RType.func == OP_SRL && (i.RType.rs & 1) == 1) {
-            db_printf("rotr\t%s,%s,%d", reg_name[i.RType.rd],
-                reg_name[i.RType.rt], i.RType.shamt);
-            break;
-        }
-        if (i.RType.func == OP_SRLV && (i.RType.shamt & 1) == 1) {
-            db_printf("rotrv\t%s,%s,%s", reg_name[i.RType.rd],
-                reg_name[i.RType.rt], reg_name[i.RType.rs]);
-            break;
-        }
-
-
-        db_printf("%s", spec_name[i.RType.func]);
-        switch (i.RType.func) {
-        case OP_SLL:
-        case OP_SRL:
-        case OP_SRA:
-        case OP_DSLL:
-
-        case OP_DSRL:
-        case OP_DSRA:
-        case OP_DSLL32:
-        case OP_DSRL32:
-        case OP_DSRA32:
-            db_printf("\t%s,%s,%d",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rt],
-                i.RType.shamt);
-            break;
-
-        case OP_SLLV:
-        case OP_SRLV:
-        case OP_SRAV:
-        case OP_DSLLV:
-        case OP_DSRLV:
-        case OP_DSRAV:
-            db_printf("\t%s,%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rt],
-                reg_name[i.RType.rs]);
-            break;
-
-        case OP_MFHI:
-        case OP_MFLO:
-            db_printf("\t%s", reg_name[i.RType.rd]);
-            break;
-
-        case OP_JR:
-        case OP_JALR:
-            db_printf("\t%s", reg_name[i.RType.rs]);
-            bdslot = true;
-            break;
-        case OP_MTLO:
-        case OP_MTHI:
-            db_printf("\t%s", reg_name[i.RType.rs]);
-            break;
-
-        case OP_MULT:
-        case OP_MULTU:
-        case OP_DMULT:
-        case OP_DMULTU:
-        case OP_DIV:
-        case OP_DIVU:
-        case OP_DDIV:
-        case OP_DDIVU:
-            db_printf("\t%s,%s",
-                reg_name[i.RType.rs],
-                reg_name[i.RType.rt]);
-            break;
-
-
-        case OP_SYSCALL:
-        case OP_SYNC:
-            break;
-
-        case OP_BREAK:
-            db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt);
-            break;
-
-        default:
-            db_printf("\t%s,%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rs],
-                reg_name[i.RType.rt]);
-        }
-        break;
-
-    case OP_SPECIAL2:
-        if (i.RType.func == OP_MUL)
-            db_printf("%s\t%s,%s,%s",
-                spec2_name[i.RType.func & 0x3f],
-                    reg_name[i.RType.rd],
-                    reg_name[i.RType.rs],
-                    reg_name[i.RType.rt]);
-        else
-            db_printf("%s\t%s,%s",
-                spec2_name[i.RType.func & 0x3f],
-                    reg_name[i.RType.rs],
-                    reg_name[i.RType.rt]);
-
-        break;
-
-    case OP_SPECIAL3:
-        if (i.RType.func == OP_EXT)
-            db_printf("ext\t%s,%s,%d,%d",
-                    reg_name[i.RType.rt],
-                    reg_name[i.RType.rs],
-                    i.RType.shamt,
-                    i.RType.rd+1);
-        else if (i.RType.func == OP_INS)
-            db_printf("ins\t%s,%s,%d,%d",
-                    reg_name[i.RType.rt],
-                    reg_name[i.RType.rs],
-                    i.RType.shamt,
-                    i.RType.rd-i.RType.shamt+1);
-        else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_WSBH)
-            db_printf("wsbh\t%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rt]);
-        else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_SEB)
-            db_printf("seb\t%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rt]);
-        else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_SEH)
-            db_printf("seh\t%s,%s",
-                reg_name[i.RType.rd],
-                reg_name[i.RType.rt]);
-        else
-            db_printf("Unknown");
-        break;
-
-    case OP_BCOND:
-        db_printf("%s\t%s,", bcond_name[i.IType.rt],
-            reg_name[i.IType.rs]);
-        goto pr_displ;
-
-    case OP_BLEZ:
-    case OP_BLEZL:
-    case OP_BGTZ:
-    case OP_BGTZL:
-        db_printf("%s\t%s,", op_name[i.IType.op],
-            reg_name[i.IType.rs]);
-        goto pr_displ;
-
-    case OP_BEQ:
-    case OP_BEQL:
-        if (i.IType.rs == 0 && i.IType.rt == 0) {
-            db_printf("b  \t");
-            goto pr_displ;
-        }
-        /* FALLTHROUGH */
-    case OP_BNE:
-    case OP_BNEL:
-        db_printf("%s\t%s,%s,", op_name[i.IType.op],
-            reg_name[i.IType.rs],
-            reg_name[i.IType.rt]);
-    pr_displ:
-        print_addr(loc + 4 + ((short)i.IType.imm << 2));
-        bdslot = true;
-        break;
-
-    case OP_COP0:
-        switch (i.RType.rs) {
-        case OP_BCx:
-        case OP_BCy:
-
-            db_printf("bc0%c\t",
-                "ft"[i.RType.rt & COPz_BC_TF_MASK]);
-            goto pr_displ;
-
-        case OP_MT:
-            db_printf("mtc0\t%s,%s",
-                reg_name[i.RType.rt],
-                c0_reg[i.RType.rd]);
-            break;
-
-        case OP_DMT:
-            db_printf("dmtc0\t%s,%s",
-                reg_name[i.RType.rt],
-                c0_reg[i.RType.rd]);
-            break;
-
-        case OP_MF:
-            db_printf("mfc0\t%s,%s",
-                reg_name[i.RType.rt],
-                c0_reg[i.RType.rd]);
-            break;
-
-        case OP_DMF:
-            db_printf("dmfc0\t%s,%s",
-                reg_name[i.RType.rt],
-                c0_reg[i.RType.rd]);
-            break;
-
-        default:
-            db_printf("%s", c0_opname[i.FRType.func]);
-        }
-        break;
-
-    case OP_COP1:
-        switch (i.RType.rs) {
-        case OP_BCx:
-        case OP_BCy:
-            db_printf("bc1%c\t",
-                "ft"[i.RType.rt & COPz_BC_TF_MASK]);
-            goto pr_displ;
-
-        case OP_MT:
-            db_printf("mtc1\t%s,f%d",
-                reg_name[i.RType.rt],
-                i.RType.rd);
-            break;
-
-        case OP_MF:
-            db_printf("mfc1\t%s,f%d",
-                reg_name[i.RType.rt],
-                i.RType.rd);
-            break;
-
-        case OP_CT:
-            db_printf("ctc1\t%s,f%d",
-                reg_name[i.RType.rt],
-                i.RType.rd);
-            break;
-
-        case OP_CF:
-            db_printf("cfc1\t%s,f%d",
-                reg_name[i.RType.rt],
-                i.RType.rd);
-            break;
-
-        default:
-            db_printf("%s.%s\tf%d,f%d,f%d",
-                cop1_name[i.FRType.func],
-                fmt_name[i.FRType.fmt],
-                i.FRType.fd, i.FRType.fs, i.FRType.ft);
-        }
-        break;
-
-    case OP_J:
-    case OP_JAL:
-        db_printf("%s\t", op_name[i.JType.op]);
-        print_addr((loc & 0xF0000000) | (i.JType.target << 2));
-        bdslot = true;
-        break;
-
-    case OP_LWC1:
-    case OP_SWC1:
-        db_printf("%s\tf%d,", op_name[i.IType.op],
-            i.IType.rt);
-        goto loadstore;
-
-    case OP_LB:
-    case OP_LH:
-    case OP_LW:
-    case OP_LD:
-    case OP_LBU:
-    case OP_LHU:
-    case OP_LWU:
-    case OP_SB:
-    case OP_SH:
-    case OP_SW:
-    case OP_SD:
-        db_printf("%s\t%s,", op_name[i.IType.op],
-            reg_name[i.IType.rt]);
-    loadstore:
-        db_printf("%d(%s)", (short)i.IType.imm,
-            reg_name[i.IType.rs]);
-        break;
-
-    case OP_ORI:
-    case OP_XORI:
-        if (i.IType.rs == 0) {
-            db_printf("li\t%s,0x%x",
-                reg_name[i.IType.rt],
-                i.IType.imm);
-            break;
-        }
-        /* FALLTHROUGH */
-    case OP_ANDI:
-        db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op],
-            reg_name[i.IType.rt],
-            reg_name[i.IType.rs],
-            i.IType.imm);
-        break;
-
-    case OP_LUI:
-        db_printf("%s\t%s,0x%x", op_name[i.IType.op],
-            reg_name[i.IType.rt],
-            i.IType.imm);
-        break;
-
-    case OP_CACHE:
-        db_printf("%s\t0x%x,0x%x(%s)",
-            op_name[i.IType.op],
-            i.IType.rt,
-            i.IType.imm,
-            reg_name[i.IType.rs]);
-        break;
-
-    case OP_ADDI:
-    case OP_DADDI:
-    case OP_ADDIU:
-    case OP_DADDIU:
-        if (i.IType.rs == 0) {
-            db_printf("li\t%s,%d",
-                reg_name[i.IType.rt],
-                (short)i.IType.imm);
-            break;
-        }
-        /* FALLTHROUGH */
-    default:
-        db_printf("%s\t%s,%s,%d", op_name[i.IType.op],
-            reg_name[i.IType.rt],
-            reg_name[i.IType.rs],
-            (short)i.IType.imm);
-    }
-    // db_printf("\n");
-    // if (bdslot) {
-    //     db_printf("   bd: ");
-    //     mips_disassem(loc+4);
-    //     return (loc + 8);
-    // }
-    return (loc + 4);
-}
-
-static void
-print_addr(db_addr_t loc)
-{
-    db_printf("0x%08x", loc);
-}
-
-
-
-static void db_printf(const char* fmt, ...)
-{
-    int cnt;
-    va_list argp;
-    va_start(argp, fmt);
-    if (sprintf_buffer) {
-        cnt = vsnprintf(sprintf_buffer, sprintf_buf_len, fmt, argp);
-        sprintf_buffer += cnt;
-        sprintf_buf_len -= cnt;
-    } else {
-        vprintf(fmt, argp);
-    }
-    va_end(argp);
-}
-
-
-/*
- * Disassemble instruction at 'loc'.
- * Return address of start of next instruction.
- * Since this function is used by 'examine' and by 'step'
- * "next instruction" does NOT mean the next instruction to
- * be executed but the 'linear' next instruction.
- */
-db_addr_t
-mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format)
-{
-    u_int32_t instr;
-
-    if (alt_dis_format) {   // use ARM register names for disassembly
-        reg_name = &alt_arm_reg_name[0];
-    }
-
-    sprintf_buffer = di_buffer;     // quick 'n' dirty printf() vs sprintf()
-    sprintf_buf_len = 39;           // should be passed in
-
-    instr =  *(u_int32_t *)loc;
-    return (db_disasm_insn(instr, loc, false));
-}
-
diff --git a/libpixelflinger/codeflinger/mips_disassem.h b/libpixelflinger/codeflinger/mips_disassem.h
deleted file mode 100644
index 2d5b7f5..0000000
--- a/libpixelflinger/codeflinger/mips_disassem.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*  $NetBSD: db_disasm.c,v 1.19 2007/02/28 04:21:53 thorpej Exp $   */
-
-/*-
- * Copyright (c) 1991, 1993
- *  The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ralph Campbell.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- *
- *  from: @(#)kadb.c    8.1 (Berkeley) 6/10/93
- */
-
-
-
-#ifndef ANDROID_MIPS_DISASSEM_H
-#define ANDROID_MIPS_DISASSEM_H
-
-#include <sys/types.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-
-// could add an interface like this, but I have not
-// typedef struct {
-//  u_int   (*di_readword)(u_int);
-//  void    (*di_printaddr)(u_int);
-//  void    (*di_printf)(const char *, ...);
-// } disasm_interface_t;
-
-/* Prototypes for callable functions */
-
-// u_int disasm(const disasm_interface_t *, u_int, int);
-
-void mips_disassem(uint32_t *location, char *di_buffer, int alt_fmt);
-
-#if __cplusplus
-}
-#endif
-
-#endif /* !ANDROID_MIPS_DISASSEM_H */
diff --git a/libpixelflinger/codeflinger/mips_opcode.h b/libpixelflinger/codeflinger/mips_opcode.h
deleted file mode 100644
index 45bb19e..0000000
--- a/libpixelflinger/codeflinger/mips_opcode.h
+++ /dev/null
@@ -1,410 +0,0 @@
-/*  $NetBSD: mips_opcode.h,v 1.12 2005/12/11 12:18:09 christos Exp $    */
-
-/*-
- * Copyright (c) 1992, 1993
- *  The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ralph Campbell.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the University 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 REGENTS 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 REGENTS 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.
- *
- *  @(#)mips_opcode.h   8.1 (Berkeley) 6/10/93
- */
-
-/*
- * Define the instruction formats and opcode values for the
- * MIPS instruction set.
- */
-
-#include <endian.h>
-
-/*
- * Define the instruction formats.
- */
-typedef union {
-    unsigned word;
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-    struct {
-        unsigned imm: 16;
-        unsigned rt: 5;
-        unsigned rs: 5;
-        unsigned op: 6;
-    } IType;
-
-    struct {
-        unsigned target: 26;
-        unsigned op: 6;
-    } JType;
-
-    struct {
-        unsigned func: 6;
-        unsigned shamt: 5;
-        unsigned rd: 5;
-        unsigned rt: 5;
-        unsigned rs: 5;
-        unsigned op: 6;
-    } RType;
-
-    struct {
-        unsigned func: 6;
-        unsigned fd: 5;
-        unsigned fs: 5;
-        unsigned ft: 5;
-        unsigned fmt: 4;
-        unsigned : 1;       /* always '1' */
-        unsigned op: 6;     /* always '0x11' */
-    } FRType;
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
-    struct {
-        unsigned op: 6;
-        unsigned rs: 5;
-        unsigned rt: 5;
-        unsigned imm: 16;
-    } IType;
-
-    struct {
-        unsigned op: 6;
-        unsigned target: 26;
-    } JType;
-
-    struct {
-        unsigned op: 6;
-        unsigned rs: 5;
-        unsigned rt: 5;
-        unsigned rd: 5;
-        unsigned shamt: 5;
-        unsigned func: 6;
-    } RType;
-
-    struct {
-        unsigned op: 6;     /* always '0x11' */
-        unsigned : 1;       /* always '1' */
-        unsigned fmt: 4;
-        unsigned ft: 5;
-        unsigned fs: 5;
-        unsigned fd: 5;
-        unsigned func: 6;
-    } FRType;
-#endif
-} InstFmt;
-
-/*
- * Values for the 'op' field.
- */
-#define OP_SPECIAL  000
-#define OP_BCOND    001
-#define OP_J        002
-#define OP_JAL      003
-#define OP_BEQ      004
-#define OP_BNE      005
-#define OP_BLEZ     006
-#define OP_BGTZ     007
-
-#if __mips_isa_rev < 6
-#define OP_ADDI     010
-#else
-#define OP_POP10    010
-#endif
-
-#define OP_ADDIU    011
-#define OP_SLTI     012
-#define OP_SLTIU    013
-#define OP_ANDI     014
-#define OP_ORI      015
-#define OP_XORI     016
-
-#if __mips_isa_rev < 6
-#define OP_LUI      017
-#else
-#define OP_AUI      017
-#endif
-
-#define OP_COP0     020
-#define OP_COP1     021
-#define OP_COP2     022
-
-#if __mips_isa_rev < 6
-#define OP_COP3     023
-#define OP_BEQL     024
-#define OP_BNEL     025
-#define OP_BLEZL    026
-#define OP_BGTZL    027
-#define OP_DADDI    030
-#else
-#define OP_POP26    026
-#define OP_POP27    027
-#define OP_POP30    030
-#endif
-
-#define OP_DADDIU   031
-
-#if __mips_isa_rev < 6
-#define OP_LDL      032
-#define OP_LDR      033
-#define OP_SPECIAL2 034
-#else
-#define OP_DAUI     035
-#endif
-
-#define OP_SPECIAL3 037
-
-#define OP_LB       040
-#define OP_LH       041
-
-#if __mips_isa_rev < 6
-#define OP_LWL      042
-#endif
-
-#define OP_LW       043
-#define OP_LBU      044
-#define OP_LHU      045
-#define OP_LWR      046
-#define OP_LHU      045
-
-#if __mips_isa_rev < 6
-#define OP_LWR      046
-#endif
-
-#define OP_LWU      047
-
-#define OP_SB       050
-#define OP_SH       051
-
-#if __mips_isa_rev < 6
-#define OP_SWL      052
-#endif
-
-#define OP_SW       053
-
-#if __mips_isa_rev < 6
-#define OP_SDL      054
-#define OP_SDR      055
-#define OP_SWR      056
-#define OP_CACHE    057
-#define OP_LL       060
-#define OP_LWC0     OP_LL
-#define OP_LWC1     061
-#define OP_LWC2     062
-#define OP_LWC3     063
-#define OP_LLD      064
-#else
-#define OP_LWC1     061
-#define OP_BC       062
-#endif
-
-#define OP_LDC1     065
-#define OP_LD       067
-
-#if __mips_isa_rev < 6
-#define OP_SC       070
-#define OP_SWC0     OP_SC
-#endif
-
-#define OP_SWC1     071
-
-#if __mips_isa_rev < 6
-#define OP_SWC2     072
-#define OP_SWC3     073
-#define OP_SCD      074
-#else
-#define OP_BALC     072
-#endif
-
-#define OP_SDC1     075
-#define OP_SD       077
-
-/*
- * Values for the 'func' field when 'op' == OP_SPECIAL.
- */
-#define OP_SLL      000
-#define OP_SRL      002
-#define OP_SRA      003
-#define OP_SLLV     004
-#define OP_SRLV     006
-#define OP_SRAV     007
-
-#if __mips_isa_rev < 6
-#define OP_JR       010
-#endif
-
-#define OP_JALR     011
-#define OP_SYSCALL  014
-#define OP_BREAK    015
-#define OP_SYNC     017
-
-#if __mips_isa_rev < 6
-#define OP_MFHI     020
-#define OP_MTHI     021
-#define OP_MFLO     022
-#define OP_MTLO     023
-#else
-#define OP_CLZ      020
-#define OP_CLO      021
-#define OP_DCLZ     022
-#define OP_DCLO     023
-#endif
-
-#define OP_DSLLV    024
-#define OP_DSRLV    026
-#define OP_DSRAV    027
-
-#if __mips_isa_rev < 6
-#define OP_MULT     030
-#define OP_MULTU    031
-#define OP_DIV      032
-#define OP_DIVU     033
-#define OP_DMULT    034
-#define OP_DMULTU   035
-#define OP_DDIV     036
-#define OP_DDIVU    037
-#else
-#define OP_SOP30    030
-#define OP_SOP31    031
-#define OP_SOP32    032
-#define OP_SOP33    033
-#define OP_SOP34    034
-#define OP_SOP35    035
-#define OP_SOP36    036
-#define OP_SOP37    037
-#endif
-
-#define OP_ADD      040
-#define OP_ADDU     041
-#define OP_SUB      042
-#define OP_SUBU     043
-#define OP_AND      044
-#define OP_OR       045
-#define OP_XOR      046
-#define OP_NOR      047
-
-#define OP_SLT      052
-#define OP_SLTU     053
-#define OP_DADD     054
-#define OP_DADDU    055
-#define OP_DSUB     056
-#define OP_DSUBU    057
-
-#define OP_TGE      060
-#define OP_TGEU     061
-#define OP_TLT      062
-#define OP_TLTU     063
-#define OP_TEQ      064
-#define OP_TNE      066
-
-#define OP_DSLL     070
-#define OP_DSRL     072
-#define OP_DSRA     073
-#define OP_DSLL32   074
-#define OP_DSRL32   076
-#define OP_DSRA32   077
-
-#if __mips_isa_rev < 6
-/*
- * Values for the 'func' field when 'op' == OP_SPECIAL2.
- * OP_SPECIAL2 opcodes are removed in mips32r6
- */
-#define OP_MAD      000     /* QED */
-#define OP_MADU     001     /* QED */
-#define OP_MUL      002     /* QED */
-#endif
-
-/*
- * Values for the 'func' field when 'op' == OP_SPECIAL3.
- */
-#define OP_EXT      000
-#define OP_DEXTM    001
-#define OP_DEXTU    002
-#define OP_DEXT     003
-#define OP_INS      004
-#define OP_DINSM    005
-#define OP_DINSU    006
-#define OP_DINS     007
-#define OP_BSHFL    040
-#define OP_RDHWR    073
-
-/*
- * Values for the 'shamt' field when OP_SPECIAL3 && func OP_BSHFL.
- */
-
-#define OP_WSBH     002
-#define OP_SEB      020
-#define OP_SEH      030
-
-#if __mips_isa_rev == 6
-/*
- * Values for the 'shamt' field when OP_SOP30.
- */
-#define OP_MUL      002
-#define OP_MUH      003
-#endif
-
-/*
- * Values for the 'func' field when 'op' == OP_BCOND.
- */
-#define OP_BLTZ     000
-#define OP_BGEZ     001
-
-#if __mips_isa_rev < 6
-#define OP_BLTZL    002
-#define OP_BGEZL    003
-#define OP_TGEI     010
-#define OP_TGEIU    011
-#define OP_TLTI     012
-#define OP_TLTIU    013
-#define OP_TEQI     014
-#define OP_TNEI     016
-#define OP_BLTZAL   020
-#define OP_BGEZAL   021
-#define OP_BLTZALL  022
-#define OP_BGEZALL  023
-#else
-#define OP_NAL      020
-#define OP_BAL      021
-#endif
-
-/*
- * Values for the 'rs' field when 'op' == OP_COPz.
- */
-#define OP_MF       000
-#define OP_DMF      001
-#define OP_MT       004
-#define OP_DMT      005
-#define OP_BCx      010
-#define OP_BCy      014
-#define OP_CF       002
-#define OP_CT       006
-
-/*
- * Values for the 'rt' field when 'op' == OP_COPz.
- */
-#define COPz_BC_TF_MASK 0x01
-#define COPz_BC_TRUE    0x01
-#define COPz_BC_FALSE   0x00
-#define COPz_BCL_TF_MASK    0x02
-#define COPz_BCL_TRUE   0x02
-#define COPz_BCL_FALSE  0x00
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
deleted file mode 100644
index e6997bd..0000000
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ /dev/null
@@ -1,1261 +0,0 @@
-/* libs/pixelflinger/codeflinger/texturing.cpp
-**
-** Copyright 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.
-*/
-
-#define LOG_TAG "pixelflinger-code"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <log/log.h>
-
-#include "GGLAssembler.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-// iterators are initialized like this:
-// (intToFixedCenter(x) * dx)>>16 + x0
-// ((x<<16 + 0x8000) * dx)>>16 + x0
-// ((x<<16)*dx + (0x8000*dx))>>16 + x0
-// ( (x*dx) + dx>>1 ) + x0
-// (x*dx) + (dx>>1 + x0)
-
-void GGLAssembler::init_iterated_color(fragment_parts_t& parts, const reg_t& x)
-{
-    context_t const* c = mBuilderContext.c;
-
-    if (mSmooth) {
-        // NOTE: we could take this case in the mDithering + !mSmooth case,
-        // but this would use up to 4 more registers for the color components
-        // for only a little added quality.
-        // Currently, this causes the system to run out of registers in
-        // some case (see issue #719496)
-
-        comment("compute initial iterated color (smooth and/or dither case)");
-
-        parts.iterated_packed = 0;
-        parts.packed = 0;
-
-        // 0x1: color component
-        // 0x2: iterators
-        const int optReload = mOptLevel >> 1;
-        if (optReload >= 3)         parts.reload = 0; // reload nothing
-        else if (optReload == 2)    parts.reload = 2; // reload iterators
-        else if (optReload == 1)    parts.reload = 1; // reload colors
-        else if (optReload <= 0)    parts.reload = 3; // reload both
-
-        if (!mSmooth) {
-            // we're not smoothing (just dithering), we never have to 
-            // reload the iterators
-            parts.reload &= ~2;
-        }
-
-        Scratch scratches(registerFile());
-        const int t0 = (parts.reload & 1) ? scratches.obtain() : 0;
-        const int t1 = (parts.reload & 2) ? scratches.obtain() : 0;
-        for (int i=0 ; i<4 ; i++) {
-            if (!mInfo[i].iterated)
-                continue;            
-            
-            // this component exists in the destination and is not replaced
-            // by a texture unit.
-            const int c = (parts.reload & 1) ? t0 : obtainReg();              
-            if (i==0) CONTEXT_LOAD(c, iterators.ydady);
-            if (i==1) CONTEXT_LOAD(c, iterators.ydrdy);
-            if (i==2) CONTEXT_LOAD(c, iterators.ydgdy);
-            if (i==3) CONTEXT_LOAD(c, iterators.ydbdy);
-            parts.argb[i].reg = c;
-
-            if (mInfo[i].smooth) {
-                parts.argb_dx[i].reg = (parts.reload & 2) ? t1 : obtainReg();
-                const int dvdx = parts.argb_dx[i].reg;
-                CONTEXT_LOAD(dvdx, generated_vars.argb[i].dx);
-                MLA(AL, 0, c, x.reg, dvdx, c);
-                
-                // adjust the color iterator to make sure it won't overflow
-                if (!mAA) {
-                    // this is not needed when we're using anti-aliasing
-                    // because we will (have to) clamp the components
-                    // anyway.
-                    int end = scratches.obtain();
-                    MOV(AL, 0, end, reg_imm(parts.count.reg, LSR, 16));
-                    MLA(AL, 1, end, dvdx, end, c);
-                    SUB(MI, 0, c, c, end);
-                    BIC(AL, 0, c, c, reg_imm(c, ASR, 31)); 
-                    scratches.recycle(end);
-                }
-            }
-            
-            if (parts.reload & 1) {
-                CONTEXT_STORE(c, generated_vars.argb[i].c);
-            }
-        }
-    } else {
-        // We're not smoothed, so we can 
-        // just use a packed version of the color and extract the
-        // components as needed (or not at all if we don't blend)
-
-        // figure out if we need the iterated color
-        int load = 0;
-        for (int i=0 ; i<4 ; i++) {
-            component_info_t& info = mInfo[i];
-            if ((info.inDest || info.needed) && !info.replaced)
-                load |= 1;
-        }
-        
-        parts.iterated_packed = 1;
-        parts.packed = (!mTextureMachine.mask && !mBlending
-                && !mFog && !mDithering);
-        parts.reload = 0;
-        if (load || parts.packed) {
-            if (mBlending || mDithering || mInfo[GGLFormat::ALPHA].needed) {
-                comment("load initial iterated color (8888 packed)");
-                parts.iterated.setTo(obtainReg(),
-                        &(c->formats[GGL_PIXEL_FORMAT_RGBA_8888]));
-                CONTEXT_LOAD(parts.iterated.reg, packed8888);
-            } else {
-                comment("load initial iterated color (dest format packed)");
-
-                parts.iterated.setTo(obtainReg(), &mCbFormat);
-
-                // pre-mask the iterated color
-                const int bits = parts.iterated.size();
-                const uint32_t size = ((bits>=32) ? 0 : (1LU << bits)) - 1;
-                uint32_t mask = 0;
-                if (mMasking) {
-                    for (int i=0 ; i<4 ; i++) {
-                        const int component_mask = 1<<i;
-                        const int h = parts.iterated.format.c[i].h;
-                        const int l = parts.iterated.format.c[i].l;
-                        if (h && (!(mMasking & component_mask))) {
-                            mask |= ((1<<(h-l))-1) << l;
-                        }
-                    }
-                }
-
-                if (mMasking && ((mask & size)==0)) {
-                    // none of the components are present in the mask
-                } else {
-                    CONTEXT_LOAD(parts.iterated.reg, packed);
-                    if (mCbFormat.size == 1) {
-                        AND(AL, 0, parts.iterated.reg,
-                                parts.iterated.reg, imm(0xFF));
-                    } else if (mCbFormat.size == 2) {
-                        MOV(AL, 0, parts.iterated.reg,
-                                reg_imm(parts.iterated.reg, LSR, 16));
-                    }
-                }
-
-                // pre-mask the iterated color
-                if (mMasking) {
-                    build_and_immediate(parts.iterated.reg, parts.iterated.reg,
-                            mask, bits);
-                }
-            }
-        }
-    }
-}
-
-void GGLAssembler::build_iterated_color(
-        component_t& fragment,
-        const fragment_parts_t& parts,
-        int component,
-        Scratch& regs)
-{
-    fragment.setTo( regs.obtain(), 0, 32, CORRUPTIBLE); 
-
-    if (!mInfo[component].iterated)
-        return;
-
-    if (parts.iterated_packed) {
-        // iterated colors are packed, extract the one we need
-        extract(fragment, parts.iterated, component);
-    } else {
-        fragment.h = GGL_COLOR_BITS;
-        fragment.l = GGL_COLOR_BITS - 8;
-        fragment.flags |= CLEAR_LO;
-        // iterated colors are held in their own register,
-        // (smooth and/or dithering case)
-        if (parts.reload==3) {
-            // this implies mSmooth
-            Scratch scratches(registerFile());
-            int dx = scratches.obtain();
-            CONTEXT_LOAD(fragment.reg, generated_vars.argb[component].c);
-            CONTEXT_LOAD(dx, generated_vars.argb[component].dx);
-            ADD(AL, 0, dx, fragment.reg, dx);
-            CONTEXT_STORE(dx, generated_vars.argb[component].c);
-        } else if (parts.reload & 1) {
-            CONTEXT_LOAD(fragment.reg, generated_vars.argb[component].c);
-        } else {
-            // we don't reload, so simply rename the register and mark as
-            // non CORRUPTIBLE so that the texture env or blending code
-            // won't modify this (renamed) register
-            regs.recycle(fragment.reg);
-            fragment.reg = parts.argb[component].reg;
-            fragment.flags &= ~CORRUPTIBLE;
-        }
-        if (mInfo[component].smooth && mAA) {
-            // when using smooth shading AND anti-aliasing, we need to clamp
-            // the iterators because there is always an extra pixel on the
-            // edges, which most of the time will cause an overflow
-            // (since technically its outside of the domain).
-            BIC(AL, 0, fragment.reg, fragment.reg,
-                    reg_imm(fragment.reg, ASR, 31));
-            component_sat(fragment);
-        }
-    }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::decodeLogicOpNeeds(const needs_t& needs)
-{
-    // gather some informations about the components we need to process...
-    const int opcode = GGL_READ_NEEDS(LOGIC_OP, needs.n) | GGL_CLEAR;
-    switch(opcode) {
-    case GGL_COPY:
-        mLogicOp = 0;
-        break;
-    case GGL_CLEAR:
-    case GGL_SET:
-        mLogicOp = LOGIC_OP;
-        break;
-    case GGL_AND:
-    case GGL_AND_REVERSE:
-    case GGL_AND_INVERTED:
-    case GGL_XOR:
-    case GGL_OR:
-    case GGL_NOR:
-    case GGL_EQUIV:
-    case GGL_OR_REVERSE:
-    case GGL_OR_INVERTED:
-    case GGL_NAND:
-        mLogicOp = LOGIC_OP|LOGIC_OP_SRC|LOGIC_OP_DST;
-        break;
-    case GGL_NOOP:
-    case GGL_INVERT:
-        mLogicOp = LOGIC_OP|LOGIC_OP_DST;
-        break;        
-    case GGL_COPY_INVERTED:
-        mLogicOp = LOGIC_OP|LOGIC_OP_SRC;
-        break;
-    };        
-}
-
-void GGLAssembler::decodeTMUNeeds(const needs_t& needs, context_t const* c)
-{
-    uint8_t replaced=0;
-    mTextureMachine.mask = 0;
-    mTextureMachine.activeUnits = 0;
-    for (int i=GGL_TEXTURE_UNIT_COUNT-1 ; i>=0 ; i--) {
-        texture_unit_t& tmu = mTextureMachine.tmu[i];
-        if (replaced == 0xF) {
-            // all components are replaced, skip this TMU.
-            tmu.format_idx = 0;
-            tmu.mask = 0;
-            tmu.replaced = replaced;
-            continue;
-        }
-        tmu.format_idx = GGL_READ_NEEDS(T_FORMAT, needs.t[i]);
-        tmu.format = c->formats[tmu.format_idx];
-        tmu.bits = tmu.format.size*8;
-        tmu.swrap = GGL_READ_NEEDS(T_S_WRAP, needs.t[i]);
-        tmu.twrap = GGL_READ_NEEDS(T_T_WRAP, needs.t[i]);
-        tmu.env = ggl_needs_to_env(GGL_READ_NEEDS(T_ENV, needs.t[i]));
-        tmu.pot = GGL_READ_NEEDS(T_POT, needs.t[i]);
-        tmu.linear = GGL_READ_NEEDS(T_LINEAR, needs.t[i])
-                && tmu.format.size!=3; // XXX: only 8, 16 and 32 modes for now
-
-        // 5551 linear filtering is not supported
-        if (tmu.format_idx == GGL_PIXEL_FORMAT_RGBA_5551)
-            tmu.linear = 0;
-        
-        tmu.mask = 0;
-        tmu.replaced = replaced;
-
-        if (tmu.format_idx) {
-            mTextureMachine.activeUnits++;
-            if (tmu.format.c[0].h)    tmu.mask |= 0x1;
-            if (tmu.format.c[1].h)    tmu.mask |= 0x2;
-            if (tmu.format.c[2].h)    tmu.mask |= 0x4;
-            if (tmu.format.c[3].h)    tmu.mask |= 0x8;
-            if (tmu.env == GGL_REPLACE) {
-                replaced |= tmu.mask;
-            } else if (tmu.env == GGL_DECAL) {
-                if (!tmu.format.c[GGLFormat::ALPHA].h) {
-                    // if we don't have alpha, decal does nothing
-                    tmu.mask = 0;
-                } else {
-                    // decal always ignores At
-                    tmu.mask &= ~(1<<GGLFormat::ALPHA);
-                }
-            }
-        }
-        mTextureMachine.mask |= tmu.mask;
-        //printf("%d: mask=%08lx, replaced=%08lx\n",
-        //    i, int(tmu.mask), int(tmu.replaced));
-    }
-    mTextureMachine.replaced = replaced;
-    mTextureMachine.directTexture = 0;
-    //printf("replaced=%08lx\n", mTextureMachine.replaced);
-}
-
-
-void GGLAssembler::init_textures(
-        tex_coord_t* coords,
-        const reg_t& x, const reg_t& y)
-{
-    const needs_t& needs = mBuilderContext.needs;
-    int Rx = x.reg;
-    int Ry = y.reg;
-
-    if (mTextureMachine.mask) {
-        comment("compute texture coordinates");
-    }
-
-    // init texture coordinates for each tmu
-    const int cb_format_idx = GGL_READ_NEEDS(CB_FORMAT, needs.n);
-    const bool multiTexture = mTextureMachine.activeUnits > 1;
-    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
-        const texture_unit_t& tmu = mTextureMachine.tmu[i];
-        if (tmu.format_idx == 0)
-            continue;
-        if ((tmu.swrap == GGL_NEEDS_WRAP_11) &&
-            (tmu.twrap == GGL_NEEDS_WRAP_11)) 
-        {
-            // 1:1 texture
-            pointer_t& txPtr = coords[i].ptr;
-            txPtr.setTo(obtainReg(), tmu.bits);
-            CONTEXT_LOAD(txPtr.reg, state.texture[i].iterators.ydsdy);
-            ADD(AL, 0, Rx, Rx, reg_imm(txPtr.reg, ASR, 16));    // x += (s>>16)
-            CONTEXT_LOAD(txPtr.reg, state.texture[i].iterators.ydtdy);
-            ADD(AL, 0, Ry, Ry, reg_imm(txPtr.reg, ASR, 16));    // y += (t>>16)
-            // merge base & offset
-            CONTEXT_LOAD(txPtr.reg, generated_vars.texture[i].stride);
-            SMLABB(AL, Rx, Ry, txPtr.reg, Rx);               // x+y*stride
-            CONTEXT_ADDR_LOAD(txPtr.reg, generated_vars.texture[i].data);
-            base_offset(txPtr, txPtr, Rx);
-        } else {
-            Scratch scratches(registerFile());
-            reg_t& s = coords[i].s;
-            reg_t& t = coords[i].t;
-            // s = (x * dsdx)>>16 + ydsdy
-            // s = (x * dsdx)>>16 + (y*dsdy)>>16 + s0
-            // t = (x * dtdx)>>16 + ydtdy
-            // t = (x * dtdx)>>16 + (y*dtdy)>>16 + t0
-            s.setTo(obtainReg());
-            t.setTo(obtainReg());
-            const int need_w = GGL_READ_NEEDS(W, needs.n);
-            if (need_w) {
-                CONTEXT_LOAD(s.reg, state.texture[i].iterators.ydsdy);
-                CONTEXT_LOAD(t.reg, state.texture[i].iterators.ydtdy);
-            } else {
-                int ydsdy = scratches.obtain();
-                int ydtdy = scratches.obtain();
-                CONTEXT_LOAD(s.reg, generated_vars.texture[i].dsdx);
-                CONTEXT_LOAD(ydsdy, state.texture[i].iterators.ydsdy);
-                CONTEXT_LOAD(t.reg, generated_vars.texture[i].dtdx);
-                CONTEXT_LOAD(ydtdy, state.texture[i].iterators.ydtdy);
-                MLA(AL, 0, s.reg, Rx, s.reg, ydsdy);
-                MLA(AL, 0, t.reg, Rx, t.reg, ydtdy);
-            }
-            
-            if ((mOptLevel&1)==0) {
-                CONTEXT_STORE(s.reg, generated_vars.texture[i].spill[0]);
-                CONTEXT_STORE(t.reg, generated_vars.texture[i].spill[1]);
-                recycleReg(s.reg);
-                recycleReg(t.reg);
-            }
-        }
-
-        // direct texture?
-        if (!multiTexture && !mBlending && !mDithering && !mFog && 
-            cb_format_idx == tmu.format_idx && !tmu.linear &&
-            mTextureMachine.replaced == tmu.mask) 
-        {
-                mTextureMachine.directTexture = i + 1; 
-        }
-    }
-}
-
-void GGLAssembler::build_textures(  fragment_parts_t& parts,
-                                    Scratch& regs)
-{
-    // We don't have a way to spill registers automatically
-    // spill depth and AA regs, when we know we may have to.
-    // build the spill list...
-    uint32_t spill_list = 0;
-    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
-        const texture_unit_t& tmu = mTextureMachine.tmu[i];
-        if (tmu.format_idx == 0)
-            continue;
-        if (tmu.linear) {
-            // we may run out of register if we have linear filtering
-            // at 1 or 4 bytes / pixel on any texture unit.
-            if (tmu.format.size == 1) {
-                // if depth and AA enabled, we'll run out of 1 register
-                if (parts.z.reg > 0 && parts.covPtr.reg > 0)
-                    spill_list |= 1<<parts.covPtr.reg;
-            }
-            if (tmu.format.size == 4) {
-                // if depth or AA enabled, we'll run out of 1 or 2 registers
-                if (parts.z.reg > 0)
-                    spill_list |= 1<<parts.z.reg;
-                if (parts.covPtr.reg > 0)   
-                    spill_list |= 1<<parts.covPtr.reg;
-            }
-        }
-    }
-
-    Spill spill(registerFile(), *this, spill_list);
-
-    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
-        const texture_unit_t& tmu = mTextureMachine.tmu[i];
-        if (tmu.format_idx == 0)
-            continue;
-
-        pointer_t& txPtr = parts.coords[i].ptr;
-        pixel_t& texel = parts.texel[i];
-
-        // repeat...
-        if ((tmu.swrap == GGL_NEEDS_WRAP_11) &&
-            (tmu.twrap == GGL_NEEDS_WRAP_11))
-        { // 1:1 textures
-            comment("fetch texel");
-            texel.setTo(regs.obtain(), &tmu.format);
-            load(txPtr, texel, WRITE_BACK);
-        } else {
-            Scratch scratches(registerFile());
-            reg_t& s = parts.coords[i].s;
-            reg_t& t = parts.coords[i].t;
-            if ((mOptLevel&1)==0) {
-                comment("reload s/t (multitexture or linear filtering)");
-                s.reg = scratches.obtain();
-                t.reg = scratches.obtain();
-                CONTEXT_LOAD(s.reg, generated_vars.texture[i].spill[0]);
-                CONTEXT_LOAD(t.reg, generated_vars.texture[i].spill[1]);
-            }
-
-            if (registerFile().status() & RegisterFile::OUT_OF_REGISTERS)
-                return;
-
-            comment("compute repeat/clamp");
-            int u       = scratches.obtain();
-            int v       = scratches.obtain();
-            int width   = scratches.obtain();
-            int height  = scratches.obtain();
-            int U = 0;
-            int V = 0;
-
-            if (registerFile().status() & RegisterFile::OUT_OF_REGISTERS)
-                return;
-
-            CONTEXT_LOAD(width,  generated_vars.texture[i].width);
-            CONTEXT_LOAD(height, generated_vars.texture[i].height);
-
-            int FRAC_BITS = 0;
-            if (tmu.linear) {
-                // linear interpolation
-                if (tmu.format.size == 1) {
-                    // for 8-bits textures, we can afford
-                    // 7 bits of fractional precision at no
-                    // additional cost (we can't do 8 bits
-                    // because filter8 uses signed 16 bits muls)
-                    FRAC_BITS = 7;
-                } else if (tmu.format.size == 2) {
-                    // filter16() is internally limited to 4 bits, so:
-                    // FRAC_BITS=2 generates less instructions,
-                    // FRAC_BITS=3,4,5 creates unpleasant artifacts,
-                    // FRAC_BITS=6+ looks good
-                    FRAC_BITS = 6;
-                } else if (tmu.format.size == 4) {
-                    // filter32() is internally limited to 8 bits, so:
-                    // FRAC_BITS=4 looks good
-                    // FRAC_BITS=5+ looks better, but generates 3 extra ipp
-                    FRAC_BITS = 6;
-                } else {
-                    // for all other cases we use 4 bits.
-                    FRAC_BITS = 4;
-                }
-            }
-            wrapping(u, s.reg, width,  tmu.swrap, FRAC_BITS);
-            wrapping(v, t.reg, height, tmu.twrap, FRAC_BITS);
-
-            if (tmu.linear) {
-                comment("compute linear filtering offsets");
-                // pixel size scale
-                const int shift = 31 - gglClz(tmu.format.size);
-                U = scratches.obtain();
-                V = scratches.obtain();
-
-                if (registerFile().status() & RegisterFile::OUT_OF_REGISTERS)
-                    return;
-
-                // sample the texel center
-                SUB(AL, 0, u, u, imm(1<<(FRAC_BITS-1)));
-                SUB(AL, 0, v, v, imm(1<<(FRAC_BITS-1)));
-
-                // get the fractionnal part of U,V
-                AND(AL, 0, U, u, imm((1<<FRAC_BITS)-1));
-                AND(AL, 0, V, v, imm((1<<FRAC_BITS)-1));
-
-                // compute width-1 and height-1
-                SUB(AL, 0, width,  width,  imm(1));
-                SUB(AL, 0, height, height, imm(1));
-
-                // get the integer part of U,V and clamp/wrap
-                // and compute offset to the next texel
-                if (tmu.swrap == GGL_NEEDS_WRAP_REPEAT) {
-                    // u has already been REPEATed
-                    MOV(AL, 1, u, reg_imm(u, ASR, FRAC_BITS));
-                    MOV(MI, 0, u, width);                    
-                    CMP(AL, u, width);
-                    MOV(LT, 0, width, imm(1 << shift));
-                    if (shift)
-                        MOV(GE, 0, width, reg_imm(width, LSL, shift));
-                    RSB(GE, 0, width, width, imm(0));
-                } else {
-                    // u has not been CLAMPed yet
-                    // algorithm:
-                    // if ((u>>4) >= width)
-                    //      u = width<<4
-                    //      width = 0
-                    // else
-                    //      width = 1<<shift
-                    // u = u>>4; // get integer part
-                    // if (u<0)
-                    //      u = 0
-                    //      width = 0
-                    // generated_vars.rt = width
-                    
-                    CMP(AL, width, reg_imm(u, ASR, FRAC_BITS));
-                    MOV(LE, 0, u, reg_imm(width, LSL, FRAC_BITS));
-                    MOV(LE, 0, width, imm(0));
-                    MOV(GT, 0, width, imm(1 << shift));
-                    MOV(AL, 1, u, reg_imm(u, ASR, FRAC_BITS));
-                    MOV(MI, 0, u, imm(0));
-                    MOV(MI, 0, width, imm(0));
-                }
-                CONTEXT_STORE(width, generated_vars.rt);
-
-                const int stride = width;
-                CONTEXT_LOAD(stride, generated_vars.texture[i].stride);
-                if (tmu.twrap == GGL_NEEDS_WRAP_REPEAT) {
-                    // v has already been REPEATed
-                    MOV(AL, 1, v, reg_imm(v, ASR, FRAC_BITS));
-                    MOV(MI, 0, v, height);
-                    CMP(AL, v, height);
-                    MOV(LT, 0, height, imm(1 << shift));
-                    if (shift)
-                        MOV(GE, 0, height, reg_imm(height, LSL, shift));
-                    RSB(GE, 0, height, height, imm(0));
-                    MUL(AL, 0, height, stride, height);
-                } else {
-                    // v has not been CLAMPed yet
-                    CMP(AL, height, reg_imm(v, ASR, FRAC_BITS));
-                    MOV(LE, 0, v, reg_imm(height, LSL, FRAC_BITS));
-                    MOV(LE, 0, height, imm(0));
-                    if (shift) {
-                        MOV(GT, 0, height, reg_imm(stride, LSL, shift));
-                    } else {
-                        MOV(GT, 0, height, stride);
-                    }
-                    MOV(AL, 1, v, reg_imm(v, ASR, FRAC_BITS));
-                    MOV(MI, 0, v, imm(0));
-                    MOV(MI, 0, height, imm(0));
-                }
-                CONTEXT_STORE(height, generated_vars.lb);
-            }
-    
-            scratches.recycle(width);
-            scratches.recycle(height);
-
-            // iterate texture coordinates...
-            comment("iterate s,t");
-            int dsdx = scratches.obtain();
-            int dtdx = scratches.obtain();
-
-            if (registerFile().status() & RegisterFile::OUT_OF_REGISTERS)
-                return;
-
-            CONTEXT_LOAD(dsdx, generated_vars.texture[i].dsdx);
-            CONTEXT_LOAD(dtdx, generated_vars.texture[i].dtdx);
-            ADD(AL, 0, s.reg, s.reg, dsdx);
-            ADD(AL, 0, t.reg, t.reg, dtdx);
-            if ((mOptLevel&1)==0) {
-                CONTEXT_STORE(s.reg, generated_vars.texture[i].spill[0]);
-                CONTEXT_STORE(t.reg, generated_vars.texture[i].spill[1]);
-                scratches.recycle(s.reg);
-                scratches.recycle(t.reg);
-            }
-            scratches.recycle(dsdx);
-            scratches.recycle(dtdx);
-
-            // merge base & offset...
-            comment("merge base & offset");
-            texel.setTo(regs.obtain(), &tmu.format);
-            txPtr.setTo(texel.reg, tmu.bits);
-            int stride = scratches.obtain();
-
-            if (registerFile().status() & RegisterFile::OUT_OF_REGISTERS)
-                return;
-
-            CONTEXT_LOAD(stride,    generated_vars.texture[i].stride);
-            CONTEXT_ADDR_LOAD(txPtr.reg, generated_vars.texture[i].data);
-            SMLABB(AL, u, v, stride, u);    // u+v*stride 
-            base_offset(txPtr, txPtr, u);
-
-            // load texel
-            if (!tmu.linear) {
-                comment("fetch texel");
-                load(txPtr, texel, 0);
-            } else {
-                // recycle registers we don't need anymore
-                scratches.recycle(u);
-                scratches.recycle(v);
-                scratches.recycle(stride);
-
-                comment("fetch texel, bilinear");
-                switch (tmu.format.size) {
-                case 1:  filter8(parts, texel, tmu, U, V, txPtr, FRAC_BITS); break;
-                case 2: filter16(parts, texel, tmu, U, V, txPtr, FRAC_BITS); break;
-                case 3: filter24(parts, texel, tmu, U, V, txPtr, FRAC_BITS); break;
-                case 4: filter32(parts, texel, tmu, U, V, txPtr, FRAC_BITS); break;
-                }
-            }            
-        }
-    }
-}
-
-void GGLAssembler::build_iterate_texture_coordinates(
-    const fragment_parts_t& parts)
-{
-    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
-        const texture_unit_t& tmu = mTextureMachine.tmu[i];
-        if (tmu.format_idx == 0)
-            continue;
-
-        if ((tmu.swrap == GGL_NEEDS_WRAP_11) &&
-            (tmu.twrap == GGL_NEEDS_WRAP_11))
-        { // 1:1 textures
-            const pointer_t& txPtr = parts.coords[i].ptr;
-            ADD(AL, 0, txPtr.reg, txPtr.reg, imm(txPtr.size>>3));
-        } else {
-            Scratch scratches(registerFile());
-            int s = parts.coords[i].s.reg;
-            int t = parts.coords[i].t.reg;
-            if ((mOptLevel&1)==0) {
-                s = scratches.obtain();
-                t = scratches.obtain();
-                CONTEXT_LOAD(s, generated_vars.texture[i].spill[0]);
-                CONTEXT_LOAD(t, generated_vars.texture[i].spill[1]);
-            }
-            int dsdx = scratches.obtain();
-            int dtdx = scratches.obtain();
-            CONTEXT_LOAD(dsdx, generated_vars.texture[i].dsdx);
-            CONTEXT_LOAD(dtdx, generated_vars.texture[i].dtdx);
-            ADD(AL, 0, s, s, dsdx);
-            ADD(AL, 0, t, t, dtdx);
-            if ((mOptLevel&1)==0) {
-                CONTEXT_STORE(s, generated_vars.texture[i].spill[0]);
-                CONTEXT_STORE(t, generated_vars.texture[i].spill[1]);
-            }
-        }
-    }
-}
-
-void GGLAssembler::filter8(
-        const fragment_parts_t& /*parts*/,
-        pixel_t& texel, const texture_unit_t& tmu,
-        int U, int V, pointer_t& txPtr,
-        int FRAC_BITS)
-{
-    if (tmu.format.components != GGL_ALPHA &&
-        tmu.format.components != GGL_LUMINANCE)
-    {
-        // this is a packed format, and we don't support
-        // linear filtering (it's probably RGB 332)
-        // Should not happen with OpenGL|ES
-        LDRB(AL, texel.reg, txPtr.reg);
-        return;
-    }
-
-    // ------------------------
-    // about ~22 cycles / pixel
-    Scratch scratches(registerFile());
-
-    int pixel= scratches.obtain();
-    int d    = scratches.obtain();
-    int u    = scratches.obtain();
-    int k    = scratches.obtain();
-    int rt   = scratches.obtain();
-    int lb   = scratches.obtain();
-
-    // RB -> U * V
-
-    CONTEXT_LOAD(rt, generated_vars.rt);
-    CONTEXT_LOAD(lb, generated_vars.lb);
-
-    int offset = pixel;
-    ADD(AL, 0, offset, lb, rt);
-    LDRB(AL, pixel, txPtr.reg, reg_scale_pre(offset));
-    SMULBB(AL, u, U, V);
-    SMULBB(AL, d, pixel, u);
-    RSB(AL, 0, k, u, imm(1<<(FRAC_BITS*2)));
-    
-    // LB -> (1-U) * V
-    RSB(AL, 0, U, U, imm(1<<FRAC_BITS));
-    LDRB(AL, pixel, txPtr.reg, reg_scale_pre(lb));
-    SMULBB(AL, u, U, V);
-    SMLABB(AL, d, pixel, u, d);
-    SUB(AL, 0, k, k, u);
-    
-    // LT -> (1-U)*(1-V)
-    RSB(AL, 0, V, V, imm(1<<FRAC_BITS));
-    LDRB(AL, pixel, txPtr.reg);
-    SMULBB(AL, u, U, V);
-    SMLABB(AL, d, pixel, u, d);
-
-    // RT -> U*(1-V)
-    LDRB(AL, pixel, txPtr.reg, reg_scale_pre(rt));
-    SUB(AL, 0, u, k, u);
-    SMLABB(AL, texel.reg, pixel, u, d);
-    
-    for (int i=0 ; i<4 ; i++) {
-        if (!texel.format.c[i].h) continue;
-        texel.format.c[i].h = FRAC_BITS*2+8;
-        texel.format.c[i].l = FRAC_BITS*2; // keeping 8 bits in enough
-    }
-    texel.format.size = 4;
-    texel.format.bitsPerPixel = 32;
-    texel.flags |= CLEAR_LO;
-}
-
-void GGLAssembler::filter16(
-        const fragment_parts_t& /*parts*/,
-        pixel_t& texel, const texture_unit_t& tmu,
-        int U, int V, pointer_t& txPtr,
-        int FRAC_BITS)
-{    
-    // compute the mask
-    // XXX: it would be nice if the mask below could be computed
-    // automatically.
-    uint32_t mask = 0;
-    int shift = 0;
-    int prec = 0;
-    switch (tmu.format_idx) {
-        case GGL_PIXEL_FORMAT_RGB_565:
-            // source: 00000ggg.ggg00000 | rrrrr000.000bbbbb
-            // result: gggggggg.gggrrrrr | rrrrr0bb.bbbbbbbb
-            mask = 0x07E0F81F;
-            shift = 16;
-            prec = 5;
-            break;
-        case GGL_PIXEL_FORMAT_RGBA_4444:
-            // 0000,1111,0000,1111 | 0000,1111,0000,1111
-            mask = 0x0F0F0F0F;
-            shift = 12;
-            prec = 4;
-            break;
-        case GGL_PIXEL_FORMAT_LA_88:
-            // 0000,0000,1111,1111 | 0000,0000,1111,1111
-            // AALL -> 00AA | 00LL
-            mask = 0x00FF00FF;
-            shift = 8;
-            prec = 8;
-            break;
-        default:
-            // unsupported format, do something sensical...
-            ALOGE("Unsupported 16-bits texture format (%d)", tmu.format_idx);
-            LDRH(AL, texel.reg, txPtr.reg);
-            return;
-    }
-
-    const int adjust = FRAC_BITS*2 - prec;
-    const int round  = 0;
-
-    // update the texel format
-    texel.format.size = 4;
-    texel.format.bitsPerPixel = 32;
-    texel.flags |= CLEAR_HI|CLEAR_LO;
-    for (int i=0 ; i<4 ; i++) {
-        if (!texel.format.c[i].h) continue;
-        const uint32_t offset = (mask & tmu.format.mask(i)) ? 0 : shift;
-        texel.format.c[i].h = tmu.format.c[i].h + offset + prec;
-        texel.format.c[i].l = texel.format.c[i].h - (tmu.format.bits(i) + prec);
-    }
-
-    // ------------------------
-    // about ~40 cycles / pixel
-    Scratch scratches(registerFile());
-
-    int pixel= scratches.obtain();
-    int d    = scratches.obtain();
-    int u    = scratches.obtain();
-    int k    = scratches.obtain();
-
-    // RB -> U * V
-    int offset = pixel;
-    CONTEXT_LOAD(offset, generated_vars.rt);
-    CONTEXT_LOAD(u, generated_vars.lb);
-    ADD(AL, 0, offset, offset, u);
-
-    LDRH(AL, pixel, txPtr.reg, reg_pre(offset));
-    SMULBB(AL, u, U, V);
-    ORR(AL, 0, pixel, pixel, reg_imm(pixel, LSL, shift));
-    build_and_immediate(pixel, pixel, mask, 32);
-    if (adjust) {
-        if (round)
-            ADD(AL, 0, u, u, imm(1<<(adjust-1)));
-        MOV(AL, 0, u, reg_imm(u, LSR, adjust));
-    }
-    MUL(AL, 0, d, pixel, u);
-    RSB(AL, 0, k, u, imm(1<<prec));
-    
-    // LB -> (1-U) * V
-    CONTEXT_LOAD(offset, generated_vars.lb);
-    RSB(AL, 0, U, U, imm(1<<FRAC_BITS));
-    LDRH(AL, pixel, txPtr.reg, reg_pre(offset));
-    SMULBB(AL, u, U, V);
-    ORR(AL, 0, pixel, pixel, reg_imm(pixel, LSL, shift));
-    build_and_immediate(pixel, pixel, mask, 32);
-    if (adjust) {
-        if (round)
-            ADD(AL, 0, u, u, imm(1<<(adjust-1)));
-        MOV(AL, 0, u, reg_imm(u, LSR, adjust));
-    }
-    MLA(AL, 0, d, pixel, u, d);
-    SUB(AL, 0, k, k, u);
-    
-    // LT -> (1-U)*(1-V)
-    RSB(AL, 0, V, V, imm(1<<FRAC_BITS));
-    LDRH(AL, pixel, txPtr.reg);
-    SMULBB(AL, u, U, V);
-    ORR(AL, 0, pixel, pixel, reg_imm(pixel, LSL, shift));
-    build_and_immediate(pixel, pixel, mask, 32);
-    if (adjust) {
-        if (round)
-            ADD(AL, 0, u, u, imm(1<<(adjust-1)));
-        MOV(AL, 0, u, reg_imm(u, LSR, adjust));
-    }
-    MLA(AL, 0, d, pixel, u, d);
-
-    // RT -> U*(1-V)            
-    CONTEXT_LOAD(offset, generated_vars.rt);
-    LDRH(AL, pixel, txPtr.reg, reg_pre(offset));
-    SUB(AL, 0, u, k, u);
-    ORR(AL, 0, pixel, pixel, reg_imm(pixel, LSL, shift));
-    build_and_immediate(pixel, pixel, mask, 32);
-    MLA(AL, 0, texel.reg, pixel, u, d);
-}
-
-void GGLAssembler::filter24(
-        const fragment_parts_t& /*parts*/,
-        pixel_t& texel, const texture_unit_t& /*tmu*/,
-        int /*U*/, int /*V*/, pointer_t& txPtr,
-        int /*FRAC_BITS*/)
-{
-    // not supported yet (currently disabled)
-    load(txPtr, texel, 0);
-}
-
-void GGLAssembler::filter32(
-        const fragment_parts_t& /*parts*/,
-        pixel_t& texel, const texture_unit_t& /*tmu*/,
-        int U, int V, pointer_t& txPtr,
-        int FRAC_BITS)
-{
-    const int adjust = FRAC_BITS*2 - 8;
-    const int round  = 0;
-
-    // ------------------------
-    // about ~38 cycles / pixel
-    Scratch scratches(registerFile());
-    
-    int pixel= scratches.obtain();
-    int dh   = scratches.obtain();
-    int u    = scratches.obtain();
-    int k    = scratches.obtain();
-
-    int temp = scratches.obtain();
-    int dl   = scratches.obtain();
-    int mask = scratches.obtain();
-
-    MOV(AL, 0, mask, imm(0xFF));
-    ORR(AL, 0, mask, mask, imm(0xFF0000));
-
-    // RB -> U * V
-    int offset = pixel;
-    CONTEXT_LOAD(offset, generated_vars.rt);
-    CONTEXT_LOAD(u, generated_vars.lb);
-    ADD(AL, 0, offset, offset, u);
-
-    LDR(AL, pixel, txPtr.reg, reg_scale_pre(offset));
-    SMULBB(AL, u, U, V);
-    AND(AL, 0, temp, mask, pixel);
-    if (adjust) {
-        if (round)
-            ADD(AL, 0, u, u, imm(1<<(adjust-1)));
-        MOV(AL, 0, u, reg_imm(u, LSR, adjust));
-    }
-    MUL(AL, 0, dh, temp, u);
-    AND(AL, 0, temp, mask, reg_imm(pixel, LSR, 8));
-    MUL(AL, 0, dl, temp, u);
-    RSB(AL, 0, k, u, imm(0x100));
-
-    // LB -> (1-U) * V
-    CONTEXT_LOAD(offset, generated_vars.lb);
-    RSB(AL, 0, U, U, imm(1<<FRAC_BITS));
-    LDR(AL, pixel, txPtr.reg, reg_scale_pre(offset));
-    SMULBB(AL, u, U, V);
-    AND(AL, 0, temp, mask, pixel);
-    if (adjust) {
-        if (round)
-            ADD(AL, 0, u, u, imm(1<<(adjust-1)));
-        MOV(AL, 0, u, reg_imm(u, LSR, adjust));
-    }
-    MLA(AL, 0, dh, temp, u, dh);    
-    AND(AL, 0, temp, mask, reg_imm(pixel, LSR, 8));
-    MLA(AL, 0, dl, temp, u, dl);
-    SUB(AL, 0, k, k, u);
-
-    // LT -> (1-U)*(1-V)
-    RSB(AL, 0, V, V, imm(1<<FRAC_BITS));
-    LDR(AL, pixel, txPtr.reg);
-    SMULBB(AL, u, U, V);
-    AND(AL, 0, temp, mask, pixel);
-    if (adjust) {
-        if (round)
-            ADD(AL, 0, u, u, imm(1<<(adjust-1)));
-        MOV(AL, 0, u, reg_imm(u, LSR, adjust));
-    }
-    MLA(AL, 0, dh, temp, u, dh);    
-    AND(AL, 0, temp, mask, reg_imm(pixel, LSR, 8));
-    MLA(AL, 0, dl, temp, u, dl);
-
-    // RT -> U*(1-V)            
-    CONTEXT_LOAD(offset, generated_vars.rt);
-    LDR(AL, pixel, txPtr.reg, reg_scale_pre(offset));
-    SUB(AL, 0, u, k, u);
-    AND(AL, 0, temp, mask, pixel);
-    MLA(AL, 0, dh, temp, u, dh);    
-    AND(AL, 0, temp, mask, reg_imm(pixel, LSR, 8));
-    MLA(AL, 0, dl, temp, u, dl);
-
-    AND(AL, 0, dh, mask, reg_imm(dh, LSR, 8));
-    AND(AL, 0, dl, dl, reg_imm(mask, LSL, 8));
-    ORR(AL, 0, texel.reg, dh, dl);
-}
-
-void GGLAssembler::build_texture_environment(
-        component_t& fragment,
-        const fragment_parts_t& parts,
-        int component,
-        Scratch& regs)
-{
-    const uint32_t component_mask = 1<<component;
-    const bool multiTexture = mTextureMachine.activeUnits > 1;
-    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
-        texture_unit_t& tmu = mTextureMachine.tmu[i];
-
-        if (tmu.mask & component_mask) {
-            // replace or modulate with this texture
-            if ((tmu.replaced & component_mask) == 0) {
-                // not replaced by a later tmu...
-
-                Scratch scratches(registerFile());
-                pixel_t texel(parts.texel[i]);
-
-                if (multiTexture && 
-                    tmu.swrap == GGL_NEEDS_WRAP_11 &&
-                    tmu.twrap == GGL_NEEDS_WRAP_11)
-                {
-                    texel.reg = scratches.obtain();
-                    texel.flags |= CORRUPTIBLE;
-                    comment("fetch texel (multitexture 1:1)");
-                    load(parts.coords[i].ptr, texel, WRITE_BACK);
-                 }
-
-                component_t incoming(fragment);
-                modify(fragment, regs);
-                
-                switch (tmu.env) {
-                case GGL_REPLACE:
-                    extract(fragment, texel, component);
-                    break;
-                case GGL_MODULATE:
-                    modulate(fragment, incoming, texel, component);
-                    break;
-                case GGL_DECAL:
-                    decal(fragment, incoming, texel, component);
-                    break;
-                case GGL_BLEND:
-                    blend(fragment, incoming, texel, component, i);
-                    break;
-                case GGL_ADD:
-                    add(fragment, incoming, texel, component);
-                    break;
-                }
-            }
-        }
-    }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::wrapping(
-            int d,
-            int coord, int size,
-            int tx_wrap, int tx_linear)
-{
-    // notes:
-    // if tx_linear is set, we need 4 extra bits of precision on the result
-    // SMULL/UMULL is 3 cycles
-    Scratch scratches(registerFile());
-    int c = coord;
-    if (tx_wrap == GGL_NEEDS_WRAP_REPEAT) {
-        // UMULL takes 4 cycles (interlocked), and we can get away with
-        // 2 cycles using SMULWB, but we're loosing 16 bits of precision
-        // out of 32 (this is not a problem because the iterator keeps
-        // its full precision)
-        // UMULL(AL, 0, size, d, c, size);
-        // note: we can't use SMULTB because it's signed.
-        MOV(AL, 0, d, reg_imm(c, LSR, 16-tx_linear));
-        SMULWB(AL, d, d, size);
-    } else if (tx_wrap == GGL_NEEDS_WRAP_CLAMP_TO_EDGE) {
-        if (tx_linear) {
-            // 1 cycle
-            MOV(AL, 0, d, reg_imm(coord, ASR, 16-tx_linear));
-        } else {
-            // 4 cycles (common case)
-            MOV(AL, 0, d, reg_imm(coord, ASR, 16));
-            BIC(AL, 0, d, d, reg_imm(d, ASR, 31));
-            CMP(AL, d, size);
-            SUB(GE, 0, d, size, imm(1));
-        }
-    }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::modulate(
-        component_t& dest, 
-        const component_t& incoming,
-        const pixel_t& incomingTexel, int component)
-{
-    Scratch locals(registerFile());
-    integer_t texel(locals.obtain(), 32, CORRUPTIBLE);            
-    extract(texel, incomingTexel, component);
-
-    const int Nt = texel.size();
-        // Nt should always be less than 10 bits because it comes
-        // from the TMU.
-
-    int Ni = incoming.size();
-        // Ni could be big because it comes from previous MODULATEs
-
-    if (Nt == 1) {
-        // texel acts as a bit-mask
-        // dest = incoming & ((texel << incoming.h)-texel)
-        RSB(AL, 0, dest.reg, texel.reg, reg_imm(texel.reg, LSL, incoming.h));
-        AND(AL, 0, dest.reg, dest.reg, incoming.reg);
-        dest.l = incoming.l;
-        dest.h = incoming.h;
-        dest.flags |= (incoming.flags & CLEAR_LO);
-    } else if (Ni == 1) {
-        MOV(AL, 0, dest.reg, reg_imm(incoming.reg, LSL, 31-incoming.h));
-        AND(AL, 0, dest.reg, texel.reg, reg_imm(dest.reg, ASR, 31));
-        dest.l = 0;
-        dest.h = Nt;
-    } else {
-        int inReg = incoming.reg;
-        int shift = incoming.l;
-        if ((Nt + Ni) > 32) {
-            // we will overflow, reduce the precision of Ni to 8 bits
-            // (Note Nt cannot be more than 10 bits which happens with 
-            // 565 textures and GGL_LINEAR)
-            shift += Ni-8;
-            Ni = 8;
-        }
-
-        // modulate by the component with the lowest precision
-        if (Nt >= Ni) {
-            if (shift) {
-                // XXX: we should be able to avoid this shift
-                // when shift==16 && Nt<16 && Ni<16, in which
-                // we could use SMULBT below.
-                MOV(AL, 0, dest.reg, reg_imm(inReg, LSR, shift));
-                inReg = dest.reg;
-                shift = 0;
-            }
-            // operation:           (Cf*Ct)/((1<<Ni)-1)
-            // approximated with:   Cf*(Ct + Ct>>(Ni-1))>>Ni
-            // this operation doesn't change texel's size
-            ADD(AL, 0, dest.reg, inReg, reg_imm(inReg, LSR, Ni-1));
-            if (Nt<16 && Ni<16) SMULBB(AL, dest.reg, texel.reg, dest.reg);
-            else                MUL(AL, 0, dest.reg, texel.reg, dest.reg);
-            dest.l = Ni;
-            dest.h = Nt + Ni;            
-        } else {
-            if (shift && (shift != 16)) {
-                // if shift==16, we can use 16-bits mul instructions later
-                MOV(AL, 0, dest.reg, reg_imm(inReg, LSR, shift));
-                inReg = dest.reg;
-                shift = 0;
-            }
-            // operation:           (Cf*Ct)/((1<<Nt)-1)
-            // approximated with:   Ct*(Cf + Cf>>(Nt-1))>>Nt
-            // this operation doesn't change incoming's size
-            Scratch scratches(registerFile());
-            int t = (texel.flags & CORRUPTIBLE) ? texel.reg : dest.reg;
-            if (t == inReg)
-                t = scratches.obtain();
-            ADD(AL, 0, t, texel.reg, reg_imm(texel.reg, LSR, Nt-1));
-            if (Nt<16 && Ni<16) {
-                if (shift==16)  SMULBT(AL, dest.reg, t, inReg);
-                else            SMULBB(AL, dest.reg, t, inReg);
-            } else              MUL(AL, 0, dest.reg, t, inReg);
-            dest.l = Nt;
-            dest.h = Nt + Ni;
-        }
-
-        // low bits are not valid
-        dest.flags |= CLEAR_LO;
-
-        // no need to keep more than 8 bits/component
-        if (dest.size() > 8)
-            dest.l = dest.h-8;
-    }
-}
-
-void GGLAssembler::decal(
-        component_t& dest, 
-        const component_t& incoming,
-        const pixel_t& incomingTexel, int component)
-{
-    // RGBA:
-    // Cv = Cf*(1 - At) + Ct*At = Cf + (Ct - Cf)*At
-    // Av = Af
-    Scratch locals(registerFile());
-    integer_t texel(locals.obtain(), 32, CORRUPTIBLE);            
-    integer_t factor(locals.obtain(), 32, CORRUPTIBLE);
-    extract(texel, incomingTexel, component);
-    extract(factor, incomingTexel, GGLFormat::ALPHA);
-
-    // no need to keep more than 8-bits for decal 
-    int Ni = incoming.size();
-    int shift = incoming.l;
-    if (Ni > 8) {
-        shift += Ni-8;
-        Ni = 8;
-    }
-    integer_t incomingNorm(incoming.reg, Ni, incoming.flags);
-    if (shift) {
-        MOV(AL, 0, dest.reg, reg_imm(incomingNorm.reg, LSR, shift));
-        incomingNorm.reg = dest.reg;
-        incomingNorm.flags |= CORRUPTIBLE;
-    }
-    ADD(AL, 0, factor.reg, factor.reg, reg_imm(factor.reg, LSR, factor.s-1));
-    build_blendOneMinusFF(dest, factor, incomingNorm, texel);
-}
-
-void GGLAssembler::blend(
-        component_t& dest, 
-        const component_t& incoming,
-        const pixel_t& incomingTexel, int component, int tmu)
-{
-    // RGBA:
-    // Cv = (1 - Ct)*Cf + Ct*Cc = Cf + (Cc - Cf)*Ct
-    // Av = At*Af
-
-    if (component == GGLFormat::ALPHA) {
-        modulate(dest, incoming, incomingTexel, component);
-        return;
-    }
-    
-    Scratch locals(registerFile());
-    integer_t color(locals.obtain(), 8, CORRUPTIBLE);            
-    integer_t factor(locals.obtain(), 32, CORRUPTIBLE);
-    LDRB(AL, color.reg, mBuilderContext.Rctx,
-            immed12_pre(GGL_OFFSETOF(state.texture[tmu].env_color[component])));
-    extract(factor, incomingTexel, component);
-
-    // no need to keep more than 8-bits for blend 
-    int Ni = incoming.size();
-    int shift = incoming.l;
-    if (Ni > 8) {
-        shift += Ni-8;
-        Ni = 8;
-    }
-    integer_t incomingNorm(incoming.reg, Ni, incoming.flags);
-    if (shift) {
-        MOV(AL, 0, dest.reg, reg_imm(incomingNorm.reg, LSR, shift));
-        incomingNorm.reg = dest.reg;
-        incomingNorm.flags |= CORRUPTIBLE;
-    }
-    ADD(AL, 0, factor.reg, factor.reg, reg_imm(factor.reg, LSR, factor.s-1));
-    build_blendOneMinusFF(dest, factor, incomingNorm, color);
-}
-
-void GGLAssembler::add(
-        component_t& dest, 
-        const component_t& incoming,
-        const pixel_t& incomingTexel, int component)
-{
-    // RGBA:
-    // Cv = Cf + Ct;
-    Scratch locals(registerFile());
-    
-    component_t incomingTemp(incoming);
-
-    // use "dest" as a temporary for extracting the texel, unless "dest"
-    // overlaps "incoming".
-    integer_t texel(dest.reg, 32, CORRUPTIBLE);
-    if (dest.reg == incomingTemp.reg)
-        texel.reg = locals.obtain();
-    extract(texel, incomingTexel, component);
-
-    if (texel.s < incomingTemp.size()) {
-        expand(texel, texel, incomingTemp.size());
-    } else if (texel.s > incomingTemp.size()) {
-        if (incomingTemp.flags & CORRUPTIBLE) {
-            expand(incomingTemp, incomingTemp, texel.s);
-        } else {
-            incomingTemp.reg = locals.obtain();
-            expand(incomingTemp, incoming, texel.s);
-        }
-    }
-
-    if (incomingTemp.l) {
-        ADD(AL, 0, dest.reg, texel.reg,
-                reg_imm(incomingTemp.reg, LSR, incomingTemp.l));
-    } else {
-        ADD(AL, 0, dest.reg, texel.reg, incomingTemp.reg);
-    }
-    dest.l = 0;
-    dest.h = texel.size();
-    component_sat(dest);
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
diff --git a/libpixelflinger/codeflinger/tinyutils/smartpointer.h b/libpixelflinger/codeflinger/tinyutils/smartpointer.h
deleted file mode 100644
index 23a5f7e..0000000
--- a/libpixelflinger/codeflinger/tinyutils/smartpointer.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright 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_PIXELFLINGER_SMART_POINTER_H
-#define ANDROID_PIXELFLINGER_SMART_POINTER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <stdlib.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-namespace tinyutils {
-
-// ---------------------------------------------------------------------------
-
-#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;                                        \
-}
-
-// ---------------------------------------------------------------------------
-
-template <typename T>
-class sp
-{
-public:
-    inline sp() : m_ptr(0) { }
-
-    sp(T* other);  // NOLINT, implicit
-    sp(const sp<T>& other);
-    template<typename U> sp(U* other);  // NOLINT, implicit
-    template<typename U> sp(const sp<U>& other);  // NOLINT, implicit
-
-    ~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);
-    
-    // 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;
-
-    T*              m_ptr;
-};
-
-// ---------------------------------------------------------------------------
-// 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) 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) {
-    if (other.m_ptr) other.m_ptr->incStrong(this);
-    if (m_ptr) m_ptr->decStrong(this);
-    m_ptr = other.m_ptr;
-    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)
-{
-    if (other.m_ptr) other.m_ptr->incStrong(this);
-    if (m_ptr) m_ptr->decStrong(this);
-    m_ptr = other.m_ptr;
-    return *this;
-}
-
-template<typename T> template<typename U>
-sp<T>& sp<T>::operator = (U* other)
-{
-    if (other) other->incStrong(this);
-    if (m_ptr) m_ptr->decStrong(this);
-    m_ptr = other;
-    return *this;
-}
-
-template<typename T>
-void sp<T>::clear()
-{
-    if (m_ptr) {
-        m_ptr->decStrong(this);
-        m_ptr = 0;
-    }
-}
-
-// ---------------------------------------------------------------------------
-
-} // namespace tinyutils
-} // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PIXELFLINGER_SMART_POINTER_H
diff --git a/libpixelflinger/col32cb16blend.S b/libpixelflinger/col32cb16blend.S
deleted file mode 100644
index 39f94e1..0000000
--- a/libpixelflinger/col32cb16blend.S
+++ /dev/null
@@ -1,77 +0,0 @@
-/* libs/pixelflinger/col32cb16blend.S
- *
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-    .text
-    .balign 4
-
-    .global scanline_col32cb16blend_arm
-
-//
-// 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.
-//
-
-// r0 = destination buffer pointer
-// r1 = color value
-// r2 = count
-
-
-scanline_col32cb16blend_arm:
-    push        {r4-r10, lr}                    // stack ARM regs
-
-    mov         r5, r1, lsr #24                 // shift down alpha
-    mov         r9, #0xff                       // create mask
-    add         r5, r5, r5, lsr #7              // add in top bit
-    rsb         r5, r5, #256                    // invert alpha
-    and         r10, r1, #0xff                  // extract red
-    and         r12, r9, r1, lsr #8             // extract green
-    and         r4, r9, r1, lsr #16             // extract blue
-    mov         r10, r10, lsl #5                // prescale red
-    mov         r12, r12, lsl #6                // prescale green
-    mov         r4, r4, lsl #5                  // prescale blue
-    mov         r9, r9, lsr #2                  // create dest green mask
-
-1:
-    ldrh        r8, [r0]                        // load dest pixel
-    subs        r2, r2, #1                      // decrement loop counter
-    mov         r6, r8, lsr #11                 // extract dest red
-    and         r7, r9, r8, lsr #5              // extract dest green
-    and         r8, r8, #0x1f                   // extract dest blue
-
-    smlabb      r6, r6, r5, r10                 // dest red * alpha + src red
-    smlabb      r7, r7, r5, r12                 // dest green * alpha + src green
-    smlabb      r8, r8, r5, r4                  // dest blue * alpha + src blue
-
-    mov         r6, r6, lsr #8                  // shift down red
-    mov         r7, r7, lsr #8                  // shift down green
-    mov         r6, r6, lsl #11                 // shift red into 565
-    orr         r6, r7, lsl #5                  // shift green into 565
-    orr         r6, r8, lsr #8                  // shift blue into 565
-
-    strh        r6, [r0], #2                    // store pixel to dest, update ptr
-    bne         1b                              // if count != 0, loop
-
-    pop         {r4-r10, pc}                    // return
-
-
-
diff --git a/libpixelflinger/col32cb16blend_neon.S b/libpixelflinger/col32cb16blend_neon.S
deleted file mode 100644
index 7ad34b0..0000000
--- a/libpixelflinger/col32cb16blend_neon.S
+++ /dev/null
@@ -1,153 +0,0 @@
-/* libs/pixelflinger/col32cb16blend_neon.S
- *
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-    .text
-    .balign 4
-
-    .global scanline_col32cb16blend_neon
-
-//
-// 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.
-//
-// The NEON implementation processes 16 pixels per iteration. The remaining 0 - 15
-// pixels are processed in ARM code.
-//
-
-// r0 = destination buffer pointer
-// r1 = color pointer
-// r2 = count
-
-
-scanline_col32cb16blend_neon:
-    push        {r4-r11, lr}                    // stack ARM regs
-
-    vmov.u16    q15, #256                       // create alpha constant
-    movs        r3, r2, lsr #4                  // calc. sixteens iterations
-    vmov.u16    q14, #0x1f                      // create blue mask
-
-    beq         2f                              // if r3 == 0, branch to singles
-
-    vld4.8      {d0[], d2[], d4[], d6[]}, [r1]  // load color into four registers
-                                                //  split and duplicate them, such that
-                                                //  d0 = 8 equal red values
-                                                //  d2 = 8 equal green values
-                                                //  d4 = 8 equal blue values
-                                                //  d6 = 8 equal alpha values
-    vshll.u8    q0, d0, #5                      // shift up red and widen
-    vshll.u8    q1, d2, #6                      // shift up green and widen
-    vshll.u8    q2, d4, #5                      // shift up blue and widen
-
-    vshr.u8     d7, d6, #7                      // extract top bit of alpha
-    vaddl.u8    q3, d6, d7                      // add top bit into alpha
-    vsub.u16    q3, q15, q3                     // invert alpha
-
-1:
-    // This loop processes 16 pixels per iteration. In the comments, references to
-    // the first eight pixels are suffixed with "0" (red0, green0, blue0), 
-    // the second eight are suffixed "1".
-                                                // q8  = dst red0
-                                                // q9  = dst green0
-                                                // q10 = dst blue0
-                                                // q13 = dst red1
-                                                // q12 = dst green1
-                                                // q11 = dst blue1
-
-    vld1.16     {d20, d21, d22, d23}, [r0]      // load 16 dest pixels
-    vshr.u16    q8, q10, #11                    // shift dst red0 to low 5 bits
-    pld         [r0, #63]                       // preload next dest pixels
-    vshl.u16    q9, q10, #5                     // shift dst green0 to top 6 bits
-    vand        q10, q10, q14                   // extract dst blue0
-    vshr.u16    q9, q9, #10                     // shift dst green0 to low 6 bits
-    vmul.u16    q8, q8, q3                      // multiply dst red0 by src alpha
-    vshl.u16    q12, q11, #5                    // shift dst green1 to top 6 bits
-    vmul.u16    q9, q9, q3                      // multiply dst green0 by src alpha
-    vshr.u16    q13, q11, #11                   // shift dst red1 to low 5 bits
-    vmul.u16    q10, q10, q3                    // multiply dst blue0 by src alpha
-    vshr.u16    q12, q12, #10                   // shift dst green1 to low 6 bits
-    vand        q11, q11, q14                   // extract dst blue1
-    vadd.u16    q8, q8, q0                      // add src red to dst red0
-    vmul.u16    q13, q13, q3                    // multiply dst red1 by src alpha
-    vadd.u16    q9, q9, q1                      // add src green to dst green0 
-    vmul.u16    q12, q12, q3                    // multiply dst green1 by src alpha
-    vadd.u16    q10, q10, q2                    // add src blue to dst blue0
-    vmul.u16    q11, q11, q3                    // multiply dst blue1 by src alpha
-    vshr.u16    q8, q8, #8                      // shift down red0
-    vadd.u16    q13, q13, q0                    // add src red to dst red1
-    vshr.u16    q9, q9, #8                      // shift down green0
-    vadd.u16    q12, q12, q1                    // add src green to dst green1
-    vshr.u16    q10, q10, #8                    // shift down blue0
-    vadd.u16    q11, q11, q2                    // add src blue to dst blue1
-    vsli.u16    q10, q9, #5                     // shift & insert green0 into blue0
-    vshr.u16    q13, q13, #8                    // shift down red1
-    vsli.u16    q10, q8, #11                    // shift & insert red0 into blue0    
-    vshr.u16    q12, q12, #8                    // shift down green1
-    vshr.u16    q11, q11, #8                    // shift down blue1
-    subs        r3, r3, #1                      // decrement loop counter
-    vsli.u16    q11, q12, #5                    // shift & insert green1 into blue1
-    vsli.u16    q11, q13, #11                   // shift & insert red1 into blue1
-
-    vst1.16     {d20, d21, d22, d23}, [r0]!     // write 16 pixels back to dst
-    bne         1b                              // if count != 0, loop
-
-2:
-    ands        r3, r2, #15                     // calc. single iterations 
-    beq         4f                              // if r3 == 0, exit
-
-    ldr         r4, [r1]                        // load source color
-    mov         r5, r4, lsr #24                 // shift down alpha
-    add         r5, r5, r5, lsr #7              // add in top bit
-    rsb         r5, r5, #256                    // invert alpha
-    and         r11, r4, #0xff                  // extract red
-    ubfx        r12, r4, #8, #8                 // extract green
-    ubfx        r4, r4, #16, #8                 // extract blue
-    mov         r11, r11, lsl #5                // prescale red
-    mov         r12, r12, lsl #6                // prescale green
-    mov         r4, r4, lsl #5                  // prescale blue
-
-3:
-    ldrh        r8, [r0]                        // load dest pixel
-    subs        r3, r3, #1                      // decrement loop counter
-    mov         r6, r8, lsr #11                 // extract dest red
-    ubfx        r7, r8, #5, #6                  // extract dest green
-    and         r8, r8, #0x1f                   // extract dest blue
-
-    smlabb      r6, r6, r5, r11                 // dest red * alpha + src red
-    smlabb      r7, r7, r5, r12                 // dest green * alpha + src green
-    smlabb      r8, r8, r5, r4                  // dest blue * alpha + src blue
-
-    mov         r6, r6, lsr #8                  // shift down red
-    mov         r7, r7, lsr #8                  // shift down green
-    mov         r6, r6, lsl #11                 // shift red into 565
-    orr         r6, r7, lsl #5                  // shift green into 565
-    orr         r6, r8, lsr #8                  // shift blue into 565
-
-    strh        r6, [r0], #2                    // store pixel to dest, update ptr
-    bne         3b                              // if count != 0, loop
-4:
-
-    pop         {r4-r11, pc}                    // return
-
-
-
diff --git a/libpixelflinger/fixed.cpp b/libpixelflinger/fixed.cpp
deleted file mode 100644
index de6b479..0000000
--- a/libpixelflinger/fixed.cpp
+++ /dev/null
@@ -1,329 +0,0 @@
-/* libs/pixelflinger/fixed.cpp
-**
-** Copyright 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.
-*/
-
-#include <stdio.h>
-
-#include <private/pixelflinger/ggl_context.h>
-#include <private/pixelflinger/ggl_fixed.h>
-
-
-// ------------------------------------------------------------------------
-
-int32_t gglRecipQNormalized(int32_t x, int* exponent)
-{
-    const int32_t s = x>>31;
-    uint32_t a = s ? -x : x;
-
-    // the result will overflow, so just set it to the biggest/inf value
-    if (ggl_unlikely(a <= 2LU)) {
-        *exponent = 0;
-        return s ? FIXED_MIN : FIXED_MAX;
-    }
-
-    // Newton-Raphson iteration:
-    // x = r*(2 - a*r)
-
-    const int32_t lz = gglClz(a);
-    a <<= lz;  // 0.32
-    uint32_t r = a;
-    // note: if a == 0x80000000, this means x was a power-of-2, in this
-    // case we don't need to compute anything. We get the reciprocal for
-    // (almost) free.
-    if (a != 0x80000000) {
-        r = (0x2E800 << (30-16)) - (r>>(2-1)); // 2.30, r = 2.90625 - 2*a
-        // 0.32 + 2.30 = 2.62 -> 2.30
-        // 2.30 + 2.30 = 4.60 -> 2.30
-        r = (((2LU<<30) - uint32_t((uint64_t(a)*r) >> 32)) * uint64_t(r)) >> 30;
-        r = (((2LU<<30) - uint32_t((uint64_t(a)*r) >> 32)) * uint64_t(r)) >> 30;
-    }
-
-    // shift right 1-bit to make room for the sign bit
-    *exponent = 30-lz-1;
-    r >>= 1;
-    return s ? -r : r;
-}
-
-int32_t gglRecipQ(GGLfixed x, int q)
-{
-    int shift;
-    x = gglRecipQNormalized(x, &shift);
-    shift += 16-q;
-    if (shift > 0)
-        x += 1L << (shift-1);   // rounding
-    x >>= shift;
-    return x;
-}    
-
-// ------------------------------------------------------------------------
-
-static const GGLfixed ggl_sqrt_reciproc_approx_tab[8] = {
-    // 1/sqrt(x) with x = 1-N/16, N=[8...1]
-    0x16A09, 0x15555, 0x143D1, 0x134BF, 0x1279A, 0x11C01, 0x111AC, 0x10865
-};
-
-GGLfixed gglSqrtRecipx(GGLfixed x)
-{
-    if (x == 0)         return FIXED_MAX;
-    if (x == FIXED_ONE) return x;
-    const GGLfixed a = x;
-    const int32_t lz = gglClz(x);
-    x = ggl_sqrt_reciproc_approx_tab[(a>>(28-lz))&0x7];
-    const int32_t exp = lz - 16;
-    if (exp <= 0)   x >>= -exp>>1;
-    else            x <<= (exp>>1) + (exp & 1);        
-    if (exp & 1) {
-        x = gglMulx(x, ggl_sqrt_reciproc_approx_tab[0])>>1;
-    }
-    // 2 Newton-Raphson iterations: x = x/2*(3-(a*x)*x)
-    x = gglMulx((x>>1),(0x30000 - gglMulx(gglMulx(a,x),x)));
-    x = gglMulx((x>>1),(0x30000 - gglMulx(gglMulx(a,x),x)));
-    return x;
-}
-
-GGLfixed gglSqrtx(GGLfixed a)
-{
-    // Compute a full precision square-root (24 bits accuracy)
-    GGLfixed r = 0;
-    GGLfixed bit = 0x800000;
-    int32_t bshift = 15;
-    do {
-        GGLfixed temp = bit + (r<<1);
-        if (bshift >= 8)    temp <<= (bshift-8);
-        else                temp >>= (8-bshift);
-        if (a >= temp) {
-            r += bit;
-            a -= temp;
-        }
-        bshift--;
-    } while (bit>>=1);
-    return r;
-}
-
-// ------------------------------------------------------------------------
-
-static const GGLfixed ggl_log_approx_tab[] = {
-    // -ln(x)/ln(2) with x = N/16, N=[8...16]
-    0xFFFF, 0xd47f, 0xad96, 0x8a62, 0x6a3f, 0x4caf, 0x3151, 0x17d6, 0x0000
-};
-
-static const GGLfixed ggl_alog_approx_tab[] = { // domain [0 - 1.0]
-	0xffff, 0xeac0, 0xd744, 0xc567, 0xb504, 0xa5fe, 0x9837, 0x8b95, 0x8000
-};
-
-GGLfixed gglPowx(GGLfixed x, GGLfixed y)
-{
-    // prerequisite: 0 <= x <= 1, and y >=0
-
-    // pow(x,y) = 2^(y*log2(x))
-    // =  2^(y*log2(x*(2^exp)*(2^-exp))))
-    // =  2^(y*(log2(X)-exp))
-    // =  2^(log2(X)*y - y*exp)
-    // =  2^( - (-log2(X)*y + y*exp) )
-    
-    int32_t exp = gglClz(x) - 16;
-    GGLfixed f = x << exp;
-    x = (f & 0x0FFF)<<4;
-    f = (f >> 12) & 0x7;
-    GGLfixed p = gglMulAddx(
-            ggl_log_approx_tab[f+1] - ggl_log_approx_tab[f], x,
-            ggl_log_approx_tab[f]);
-    p = gglMulAddx(p, y, y*exp);
-    exp = gglFixedToIntFloor(p);
-    if (exp < 31) {
-        p = gglFracx(p);
-        x = (p & 0x1FFF)<<3;
-        p >>= 13;    
-        p = gglMulAddx(
-                ggl_alog_approx_tab[p+1] - ggl_alog_approx_tab[p], x,
-                ggl_alog_approx_tab[p]);
-        p >>= exp;
-    } else {
-        p = 0;
-    }
-    return p;
-        // ( powf((a*65536.0f), (b*65536.0f)) ) * 65536.0f;
-}
-
-// ------------------------------------------------------------------------
-
-int32_t gglDivQ(GGLfixed n, GGLfixed d, int32_t i)
-{
-    //int32_t r =int32_t((int64_t(n)<<i)/d);
-    const int32_t ds = n^d;
-    if (n<0) n = -n;
-    if (d<0) d = -d;
-    int nd = gglClz(d) - gglClz(n);
-    i += nd + 1;
-    if (nd > 0) d <<= nd;
-    else        n <<= -nd;
-    uint32_t q = 0;
-
-    int j = i & 7;
-    i >>= 3;
-
-    // gcc deals with the code below pretty well.
-    // we get 3.75 cycles per bit in the main loop
-    // and 8 cycles per bit in the termination loop
-    if (ggl_likely(i)) {
-        n -= d;
-        do {
-            q <<= 8;
-            if (n>=0)   q |= 128;
-            else        n += d;
-            n = n*2 - d;
-            if (n>=0)   q |= 64;
-            else        n += d;
-            n = n*2 - d;
-            if (n>=0)   q |= 32;
-            else        n += d;
-            n = n*2 - d;
-            if (n>=0)   q |= 16;
-            else        n += d;
-            n = n*2 - d;
-            if (n>=0)   q |= 8;
-            else        n += d;
-            n = n*2 - d;
-            if (n>=0)   q |= 4;
-            else        n += d;
-            n = n*2 - d;
-            if (n>=0)   q |= 2;
-            else        n += d;
-            n = n*2 - d;
-            if (n>=0)   q |= 1;
-            else        n += d;
-            
-            if (--i == 0)
-                goto finish;
-
-            n = n*2 - d;
-        } while(true);
-        do {
-            q <<= 1;
-            n = n*2 - d;
-            if (n>=0)   q |= 1;
-            else        n += d;
-        finish: ;
-        } while (j--);
-        return (ds<0) ? -q : q;
-    }
-
-    n -= d;
-    if (n>=0)   q |= 1;
-    else        n += d;
-    j--;
-    goto finish;
-}
-
-// ------------------------------------------------------------------------
-
-// assumes that the int32_t values of a, b, and c are all positive
-// use when both a and b are larger than c
-
-template <typename T>
-static inline void swap(T& a, T& b) {
-    T t(a);
-    a = b;
-    b = t;
-}
-
-static __attribute__((noinline))
-int32_t slow_muldiv(uint32_t a, uint32_t b, uint32_t c)
-{
-	// first we compute a*b as a 64-bit integer
-    // (GCC generates umull with the code below)
-    uint64_t ab = uint64_t(a)*b;
-    uint32_t hi = ab>>32;
-    uint32_t lo = ab;
-    uint32_t result;
-
-	// now perform the division
-	if (hi >= c) {
-	overflow:
-		result = 0x7fffffff;  // basic overflow
-	} else if (hi == 0) {
-		result = lo/c;  // note: c can't be 0
-		if ((result >> 31) != 0)  // result must fit in 31 bits
-			goto overflow;
-	} else {
-		uint32_t r = hi;
-		int bits = 31;
-	    result = 0;
-		do {
-			r = (r << 1) | (lo >> 31);
-			lo <<= 1;
-			result <<= 1;
-			if (r >= c) {
-				r -= c;
-				result |= 1;
-			}
-		} while (bits--);
-	}
-	return int32_t(result);
-}
-
-// assumes a >= 0 and c >= b >= 0
-static inline
-int32_t quick_muldiv(int32_t a, int32_t b, int32_t c)
-{
-    int32_t r = 0, q = 0, i;
-    int leading = gglClz(a);
-    i = 32 - leading;
-    a <<= leading;
-    do {
-        r <<= 1;
-        if (a < 0)
-            r += b;
-        a <<= 1;
-        q <<= 1;
-        if (r >= c) {
-            r -= c;
-            q++;
-        }
-        asm(""::); // gcc generates better code this way
-        if (r >= c) {
-            r -= c;
-            q++;
-        }
-    }
-    while (--i);
-    return q;
-}
-
-// this function computes a*b/c with 64-bit intermediate accuracy
-// overflows (e.g. division by 0) are handled and return INT_MAX
-
-int32_t gglMulDivi(int32_t a, int32_t b, int32_t c)
-{
-	int32_t result;
-	int32_t sign = a^b^c;
-
-	if (a < 0) a = -a;
-	if (b < 0) b = -b;
-	if (c < 0) c = -c;
-
-    if (a < b) {
-        swap(a, b);
-    }
-    
-	if (b <= c) result = quick_muldiv(a, b, c);
-	else        result = slow_muldiv((uint32_t)a, (uint32_t)b, (uint32_t)c);
-	
-	if (sign < 0)
-		result = -result;
-	  
-    return result;
-}
diff --git a/libpixelflinger/format.cpp b/libpixelflinger/format.cpp
deleted file mode 100644
index 6546e8c..0000000
--- a/libpixelflinger/format.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/* libs/pixelflinger/format.cpp
-**
-** Copyright 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.
-*/
-
-#include <stdio.h>
-#include <pixelflinger/format.h>
-
-namespace android {
-
-static GGLFormat const gPixelFormatInfos[] =
-{   //          Alpha    Red     Green   Blue
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  4, 32, {{32,24,   8, 0,  16, 8,  24,16 }}, GGL_RGBA },   // PIXEL_FORMAT_RGBA_8888
-    {  4, 24, {{ 0, 0,   8, 0,  16, 8,  24,16 }}, GGL_RGB  },   // PIXEL_FORMAT_RGBX_8888
-    {  3, 24, {{ 0, 0,   8, 0,  16, 8,  24,16 }}, GGL_RGB  },   // PIXEL_FORMAT_RGB_888
-    {  2, 16, {{ 0, 0,  16,11,  11, 5,   5, 0 }}, GGL_RGB  },   // PIXEL_FORMAT_RGB_565
-    {  4, 32, {{32,24,  24,16,  16, 8,   8, 0 }}, GGL_RGBA },   // PIXEL_FORMAT_BGRA_8888
-    {  2, 16, {{ 1, 0,  16,11,  11, 6,   6, 1 }}, GGL_RGBA },   // PIXEL_FORMAT_RGBA_5551
-    {  2, 16, {{ 4, 0,  16,12,  12, 8,   8, 4 }}, GGL_RGBA },   // PIXEL_FORMAT_RGBA_4444
-    {  1,  8, {{ 8, 0,   0, 0,   0, 0,   0, 0 }}, GGL_ALPHA},   // PIXEL_FORMAT_A8
-    {  1,  8, {{ 0, 0,   8, 0,   8, 0,   8, 0 }}, GGL_LUMINANCE},//PIXEL_FORMAT_L8
-    {  2, 16, {{16, 8,   8, 0,   8, 0,   8, 0 }}, GGL_LUMINANCE_ALPHA},// PIXEL_FORMAT_LA_88
-    {  1,  8, {{ 0, 0,   8, 5,   5, 2,   2, 0 }}, GGL_RGB  },   // PIXEL_FORMAT_RGB_332
-    
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    
-    {  2, 16, {{  0, 0, 16, 0,   0, 0,   0, 0 }}, GGL_DEPTH_COMPONENT},
-    {  1,  8, {{  8, 0,  0, 0,   0, 0,   0, 0 }}, GGL_STENCIL_INDEX  },
-    {  4, 24, {{  0, 0, 24, 0,   0, 0,   0, 0 }}, GGL_DEPTH_COMPONENT},
-    {  4,  8, {{ 32,24,  0, 0,   0, 0,   0, 0 }}, GGL_STENCIL_INDEX  },
-
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-    {  0,  0, {{ 0, 0,   0, 0,   0, 0,   0, 0 }},        0 },   // PIXEL_FORMAT_NONE
-
-};
-
-}; // namespace android
-
-
-const GGLFormat* gglGetPixelFormatTable(size_t* numEntries)
-{
-    if (numEntries) {
-        *numEntries = sizeof(android::gPixelFormatInfos)/sizeof(GGLFormat);
-    }
-    return android::gPixelFormatInfos;
-}
diff --git a/libpixelflinger/include/pixelflinger/format.h b/libpixelflinger/include/pixelflinger/format.h
deleted file mode 100644
index d429477..0000000
--- a/libpixelflinger/include/pixelflinger/format.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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_PIXELFLINGER_FORMAT_H
-#define ANDROID_PIXELFLINGER_FORMAT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-enum GGLPixelFormat {
-    // these constants need to match those
-    // in graphics/PixelFormat.java, ui/PixelFormat.h, BlitHardware.h
-    GGL_PIXEL_FORMAT_UNKNOWN    =   0,
-    GGL_PIXEL_FORMAT_NONE       =   0,
-
-    GGL_PIXEL_FORMAT_RGBA_8888   =   1,  // 4x8-bit ARGB
-    GGL_PIXEL_FORMAT_RGBX_8888   =   2,  // 3x8-bit RGB stored in 32-bit chunks
-    GGL_PIXEL_FORMAT_RGB_888     =   3,  // 3x8-bit RGB
-    GGL_PIXEL_FORMAT_RGB_565     =   4,  // 16-bit RGB
-    GGL_PIXEL_FORMAT_BGRA_8888   =   5,  // 4x8-bit BGRA
-    GGL_PIXEL_FORMAT_RGBA_5551   =   6,  // 16-bit RGBA
-    GGL_PIXEL_FORMAT_RGBA_4444   =   7,  // 16-bit RGBA
-
-    GGL_PIXEL_FORMAT_A_8         =   8,  // 8-bit A
-    GGL_PIXEL_FORMAT_L_8         =   9,  // 8-bit L (R=G=B = L)
-    GGL_PIXEL_FORMAT_LA_88       = 0xA,  // 16-bit LA
-    GGL_PIXEL_FORMAT_RGB_332     = 0xB,  // 8-bit RGB (non paletted)
-
-    // reserved range. don't use.
-    GGL_PIXEL_FORMAT_RESERVED_10 = 0x10,
-    GGL_PIXEL_FORMAT_RESERVED_11 = 0x11,
-    GGL_PIXEL_FORMAT_RESERVED_12 = 0x12,
-    GGL_PIXEL_FORMAT_RESERVED_13 = 0x13,
-    GGL_PIXEL_FORMAT_RESERVED_14 = 0x14,
-    GGL_PIXEL_FORMAT_RESERVED_15 = 0x15,
-    GGL_PIXEL_FORMAT_RESERVED_16 = 0x16,
-    GGL_PIXEL_FORMAT_RESERVED_17 = 0x17,
-
-    // reserved/special formats
-    GGL_PIXEL_FORMAT_Z_16       =  0x18,
-    GGL_PIXEL_FORMAT_S_8        =  0x19,
-    GGL_PIXEL_FORMAT_SZ_24      =  0x1A,
-    GGL_PIXEL_FORMAT_SZ_8       =  0x1B,
-
-    // reserved range. don't use.
-    GGL_PIXEL_FORMAT_RESERVED_20 = 0x20,
-    GGL_PIXEL_FORMAT_RESERVED_21 = 0x21,
-};
-
-enum GGLFormatComponents {
-	GGL_STENCIL_INDEX		= 0x1901,
-	GGL_DEPTH_COMPONENT		= 0x1902,
-	GGL_ALPHA				= 0x1906,
-	GGL_RGB					= 0x1907,
-	GGL_RGBA				= 0x1908,
-	GGL_LUMINANCE			= 0x1909,
-	GGL_LUMINANCE_ALPHA		= 0x190A,
-};
-
-enum GGLFormatComponentIndex {
-    GGL_INDEX_ALPHA   = 0,
-    GGL_INDEX_RED     = 1,
-    GGL_INDEX_GREEN   = 2,
-    GGL_INDEX_BLUE    = 3,
-    GGL_INDEX_STENCIL = 0,
-    GGL_INDEX_DEPTH   = 1,
-    GGL_INDEX_Y       = 0,
-    GGL_INDEX_CB      = 1,
-    GGL_INDEX_CR      = 2,
-};
-
-typedef struct GGLFormat {
-#ifdef __cplusplus
-    enum {
-        ALPHA   = GGL_INDEX_ALPHA,
-        RED     = GGL_INDEX_RED,
-        GREEN   = GGL_INDEX_GREEN,
-        BLUE    = GGL_INDEX_BLUE,
-        STENCIL = GGL_INDEX_STENCIL,
-        DEPTH   = GGL_INDEX_DEPTH,
-        LUMA    = GGL_INDEX_Y,
-        CHROMAB = GGL_INDEX_CB,
-        CHROMAR = GGL_INDEX_CR,
-    };
-    inline uint32_t mask(int i) const {
-            return ((1<<(c[i].h-c[i].l))-1)<<c[i].l;
-    }
-    inline uint32_t bits(int i) const {
-            return c[i].h - c[i].l;
-    }
-#endif
-	uint8_t     size;	// bytes per pixel
-    uint8_t     bitsPerPixel;
-    union {    
-        struct {
-            uint8_t     ah;		// alpha high bit position + 1
-            uint8_t     al;		// alpha low bit position
-            uint8_t     rh;		// red high bit position + 1
-            uint8_t     rl;		// red low bit position
-            uint8_t     gh;		// green high bit position + 1
-            uint8_t     gl;		// green low bit position
-            uint8_t     bh;		// blue high bit position + 1
-            uint8_t     bl;		// blue low bit position
-        };
-        struct {
-            uint8_t h;
-            uint8_t l;
-        } __attribute__((__packed__)) c[4];        
-    } __attribute__((__packed__));
-	uint16_t    components;	// GGLFormatComponents
-} GGLFormat;
-
-
-#ifdef __cplusplus
-extern "C" const GGLFormat* gglGetPixelFormatTable(size_t* numEntries = 0);
-#else
-const GGLFormat* gglGetPixelFormatTable(size_t* numEntries);
-#endif
-
-
-// ----------------------------------------------------------------------------
-
-#endif // ANDROID_PIXELFLINGER_FORMAT_H
diff --git a/libpixelflinger/include/pixelflinger/pixelflinger.h b/libpixelflinger/include/pixelflinger/pixelflinger.h
deleted file mode 100644
index 8a2b442..0000000
--- a/libpixelflinger/include/pixelflinger/pixelflinger.h
+++ /dev/null
@@ -1,330 +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.
- */
-
-#ifndef ANDROID_PIXELFLINGER_H
-#define ANDROID_PIXELFLINGER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <pixelflinger/format.h>
-
-// GGL types
-
-typedef int8_t			GGLbyte;		// b
-typedef int16_t			GGLshort;		// s
-typedef int32_t			GGLint;			// i
-typedef ssize_t			GGLsizei;		// i
-typedef int32_t			GGLfixed;		// x
-typedef int32_t			GGLclampx;		// x
-typedef float			GGLfloat;		// f
-typedef float			GGLclampf;		// f
-typedef double			GGLdouble;		// d
-typedef double			GGLclampd;		// d
-typedef uint8_t			GGLubyte;		// ub
-typedef uint8_t			GGLboolean;		// ub
-typedef uint16_t		GGLushort;		// us
-typedef uint32_t		GGLuint;		// ui
-typedef unsigned int	GGLenum;		// ui
-typedef unsigned int	GGLbitfield;	// ui
-typedef void			GGLvoid;
-typedef int32_t         GGLfixed32;
-typedef	int32_t         GGLcolor;
-typedef int32_t         GGLcoord;
-
-// ----------------------------------------------------------------------------
-
-#define GGL_MAX_VIEWPORT_DIMS           4096
-#define GGL_MAX_TEXTURE_SIZE            4096
-#define GGL_MAX_ALIASED_POINT_SIZE      0x7FFFFFF
-#define GGL_MAX_SMOOTH_POINT_SIZE       2048
-#define GGL_MAX_SMOOTH_LINE_WIDTH       2048
-
-// ----------------------------------------------------------------------------
-
-// All these names are compatible with their OpenGL equivalents
-// some of them are listed only for completeness
-enum GGLNames {
-	GGL_FALSE						= 0,
-	GGL_TRUE						= 1,
-
-	// enable/disable
-    GGL_SCISSOR_TEST                = 0x0C11,
-	GGL_TEXTURE_2D					= 0x0DE1,
-	GGL_ALPHA_TEST					= 0x0BC0,
-	GGL_BLEND						= 0x0BE2,
-	GGL_COLOR_LOGIC_OP				= 0x0BF2,
-	GGL_DITHER						= 0x0BD0,
-	GGL_STENCIL_TEST				= 0x0B90,
-	GGL_DEPTH_TEST					= 0x0B71,
-    GGL_AA                          = 0x80000001,
-    GGL_W_LERP                      = 0x80000004,
-    GGL_POINT_SMOOTH_NICE           = 0x80000005,
-
-    // buffers, pixel drawing/reading
-    GGL_COLOR                       = 0x1800,
-    
-    // fog
-    GGL_FOG                         = 0x0B60,
-    
-	// shade model
-	GGL_FLAT						= 0x1D00,
-	GGL_SMOOTH						= 0x1D01,
-
-	// Texture parameter name
-	GGL_TEXTURE_MIN_FILTER			= 0x2801,
-	GGL_TEXTURE_MAG_FILTER			= 0x2800,
-	GGL_TEXTURE_WRAP_S				= 0x2802,
-	GGL_TEXTURE_WRAP_T				= 0x2803,
-	GGL_TEXTURE_WRAP_R				= 0x2804,
-
-	// Texture Filter	
-	GGL_NEAREST						= 0x2600,
-	GGL_LINEAR						= 0x2601,
-	GGL_NEAREST_MIPMAP_NEAREST		= 0x2700,
-	GGL_LINEAR_MIPMAP_NEAREST		= 0x2701,
-	GGL_NEAREST_MIPMAP_LINEAR		= 0x2702,
-	GGL_LINEAR_MIPMAP_LINEAR		= 0x2703,
-
-	// Texture Wrap Mode
-	GGL_CLAMP						= 0x2900,
-	GGL_REPEAT						= 0x2901,
-    GGL_CLAMP_TO_EDGE               = 0x812F,
-
-	// Texture Env Mode
-	GGL_REPLACE						= 0x1E01,
-	GGL_MODULATE					= 0x2100,
-	GGL_DECAL						= 0x2101,
-	GGL_ADD							= 0x0104,
-
-	// Texture Env Parameter
-	GGL_TEXTURE_ENV_MODE			= 0x2200,
-	GGL_TEXTURE_ENV_COLOR			= 0x2201,
-
-	// Texture Env Target
-	GGL_TEXTURE_ENV					= 0x2300,
-
-    // Texture coord generation
-    GGL_TEXTURE_GEN_MODE            = 0x2500,
-    GGL_S                           = 0x2000,
-    GGL_T                           = 0x2001,
-    GGL_R                           = 0x2002,
-    GGL_Q                           = 0x2003,
-    GGL_ONE_TO_ONE                  = 0x80000002,
-    GGL_AUTOMATIC                   = 0x80000003,
-
-    // AlphaFunction
-    GGL_NEVER                       = 0x0200,
-    GGL_LESS                        = 0x0201,
-    GGL_EQUAL                       = 0x0202,
-    GGL_LEQUAL                      = 0x0203,
-    GGL_GREATER                     = 0x0204,
-    GGL_NOTEQUAL                    = 0x0205,
-    GGL_GEQUAL                      = 0x0206,
-    GGL_ALWAYS                      = 0x0207,
-
-    // LogicOp
-    GGL_CLEAR                       = 0x1500,   // 0
-    GGL_AND                         = 0x1501,   // s & d
-    GGL_AND_REVERSE                 = 0x1502,   // s & ~d
-    GGL_COPY                        = 0x1503,   // s
-    GGL_AND_INVERTED                = 0x1504,   // ~s & d
-    GGL_NOOP                        = 0x1505,   // d
-    GGL_XOR                         = 0x1506,   // s ^ d
-    GGL_OR                          = 0x1507,   // s | d
-    GGL_NOR                         = 0x1508,   // ~(s | d)
-    GGL_EQUIV                       = 0x1509,   // ~(s ^ d)
-    GGL_INVERT                      = 0x150A,   // ~d
-    GGL_OR_REVERSE                  = 0x150B,   // s | ~d
-    GGL_COPY_INVERTED               = 0x150C,   // ~s 
-    GGL_OR_INVERTED                 = 0x150D,   // ~s | d
-    GGL_NAND                        = 0x150E,   // ~(s & d)
-    GGL_SET                         = 0x150F,   // 1
-
-	// blending equation & function
-	GGL_ZERO                        = 0,		// SD
-	GGL_ONE                         = 1,		// SD
-	GGL_SRC_COLOR                   = 0x0300,	//  D
-	GGL_ONE_MINUS_SRC_COLOR         = 0x0301,	//	D
-	GGL_SRC_ALPHA                   = 0x0302,	// SD
-	GGL_ONE_MINUS_SRC_ALPHA			= 0x0303,	// SD
-	GGL_DST_ALPHA					= 0x0304,	// SD
-	GGL_ONE_MINUS_DST_ALPHA			= 0x0305,	// SD
-	GGL_DST_COLOR					= 0x0306,	// S
-	GGL_ONE_MINUS_DST_COLOR			= 0x0307,	// S
-	GGL_SRC_ALPHA_SATURATE			= 0x0308,	// S
-    
-    // clear bits
-    GGL_DEPTH_BUFFER_BIT            = 0x00000100,
-    GGL_STENCIL_BUFFER_BIT          = 0x00000400,
-    GGL_COLOR_BUFFER_BIT            = 0x00004000,
-
-    // errors
-    GGL_NO_ERROR                    = 0,
-    GGL_INVALID_ENUM                = 0x0500,
-    GGL_INVALID_VALUE               = 0x0501,
-    GGL_INVALID_OPERATION           = 0x0502,
-    GGL_STACK_OVERFLOW              = 0x0503,
-    GGL_STACK_UNDERFLOW             = 0x0504,
-    GGL_OUT_OF_MEMORY               = 0x0505
-};
-
-// ----------------------------------------------------------------------------
-
-typedef struct {
-    GGLsizei    version;    // always set to sizeof(GGLSurface)
-    GGLuint     width;      // width in pixels
-    GGLuint     height;     // height in pixels
-    GGLint      stride;     // stride in pixels
-    GGLubyte*   data;       // pointer to the bits
-    GGLubyte    format;     // pixel format
-    GGLubyte    rfu[3];     // must be zero
-    // these values are dependent on the used format
-    union {
-        GGLint  compressedFormat;
-        GGLint  vstride;
-    };
-    void*       reserved;
-} GGLSurface;
-
-
-typedef struct {
-    // immediate rendering
-    void (*pointx)(void *con, const GGLcoord* v, GGLcoord r);
-    void (*linex)(void *con, 
-            const GGLcoord* v0, const GGLcoord* v1, GGLcoord width);
-    void (*recti)(void* c, GGLint l, GGLint t, GGLint r, GGLint b); 
-    void (*trianglex)(void* c,
-            GGLcoord const* v0, GGLcoord const* v1, GGLcoord const* v2);
-
-    // scissor
-    void (*scissor)(void* c, GGLint x, GGLint y, GGLsizei width, GGLsizei height);
-
-    // Set the textures and color buffers
-    void (*activeTexture)(void* c, GGLuint tmu);
-    void (*bindTexture)(void* c, const GGLSurface* surface);
-    void (*colorBuffer)(void* c, const GGLSurface* surface);
-    void (*readBuffer)(void* c, const GGLSurface* surface);
-    void (*depthBuffer)(void* c, const GGLSurface* surface);
-    void (*bindTextureLod)(void* c, GGLuint tmu, const GGLSurface* surface);
-
-    // enable/disable features
-    void (*enable)(void* c, GGLenum name);
-    void (*disable)(void* c, GGLenum name);
-    void (*enableDisable)(void* c, GGLenum name, GGLboolean en);
-
-    // specify the fragment's color
-    void (*shadeModel)(void* c, GGLenum mode);
-    void (*color4xv)(void* c, const GGLclampx* color);
-    // specify color iterators (16.16)
-    void (*colorGrad12xv)(void* c, const GGLcolor* grad);
-
-    // specify Z coordinate iterators (0.32)
-    void (*zGrad3xv)(void* c, const GGLfixed32* grad);
-
-    // specify W coordinate iterators (16.16)
-    void (*wGrad3xv)(void* c, const GGLfixed* grad);
-
-    // specify fog iterator & color (16.16)
-    void (*fogGrad3xv)(void* c, const GGLfixed* grad);
-    void (*fogColor3xv)(void* c, const GGLclampx* color);
-
-    // specify blending parameters
-    void (*blendFunc)(void* c, GGLenum src, GGLenum dst);
-    void (*blendFuncSeparate)(void* c,  GGLenum src, GGLenum dst,
-                                        GGLenum srcAlpha, GGLenum dstAplha);
-
-    // texture environnement (REPLACE / MODULATE / DECAL / BLEND)
-    void (*texEnvi)(void* c,    GGLenum target,
-                                GGLenum pname,
-                                GGLint param);
-
-    void (*texEnvxv)(void* c, GGLenum target,
-            GGLenum pname, const GGLfixed* params);
-
-    // texture parameters (Wrapping, filter)
-    void (*texParameteri)(void* c,  GGLenum target,
-                                    GGLenum pname,
-                                    GGLint param);
-
-    // texture iterators (16.16)
-    void (*texCoord2i)(void* c, GGLint s, GGLint t);
-    void (*texCoord2x)(void* c, GGLfixed s, GGLfixed t);
-    
-    // s, dsdx, dsdy, scale, t, dtdx, dtdy, tscale
-    // This api uses block floating-point for S and T texture coordinates.
-    // All values are given in 16.16, scaled by 'scale'. In other words,
-    // set scale to 0, for 16.16 values.
-    void (*texCoordGradScale8xv)(void* c, GGLint tmu, const int32_t* grad8);
-    
-    void (*texGeni)(void* c, GGLenum coord, GGLenum pname, GGLint param);
-
-    // masking
-    void (*colorMask)(void* c,  GGLboolean red,
-                                GGLboolean green,
-                                GGLboolean blue,
-                                GGLboolean alpha);
-
-    void (*depthMask)(void* c, GGLboolean flag);
-
-    void (*stencilMask)(void* c, GGLuint mask);
-
-    // alpha func
-    void (*alphaFuncx)(void* c, GGLenum func, GGLclampx ref);
-
-    // depth func
-    void (*depthFunc)(void* c, GGLenum func);
-
-    // logic op
-    void (*logicOp)(void* c, GGLenum opcode); 
-
-    // clear
-    void (*clear)(void* c, GGLbitfield mask);
-    void (*clearColorx)(void* c,
-            GGLclampx r, GGLclampx g, GGLclampx b, GGLclampx a);
-    void (*clearDepthx)(void* c, GGLclampx depth);
-    void (*clearStencil)(void* c, GGLint s);
-
-    // framebuffer operations
-    void (*copyPixels)(void* c, GGLint x, GGLint y,
-            GGLsizei width, GGLsizei height, GGLenum type);
-    void (*rasterPos2x)(void* c, GGLfixed x, GGLfixed y);
-    void (*rasterPos2i)(void* c, GGLint x, GGLint y);
-} GGLContext;
-
-// ----------------------------------------------------------------------------
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// construct / destroy the context
-ssize_t gglInit(GGLContext** context);
-ssize_t gglUninit(GGLContext* context);
-
-GGLint gglBitBlit(
-        GGLContext* c,
-        int tmu,
-        GGLint crop[4],
-        GGLint where[4]);
-
-#ifdef __cplusplus
-};
-#endif
-
-// ----------------------------------------------------------------------------
-
-#endif // ANDROID_PIXELFLINGER_H
diff --git a/libpixelflinger/include/private/pixelflinger/ggl_context.h b/libpixelflinger/include/private/pixelflinger/ggl_context.h
deleted file mode 100644
index 563b0f1..0000000
--- a/libpixelflinger/include/private/pixelflinger/ggl_context.h
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * 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 ANDROID_GGL_CONTEXT_H
-#define ANDROID_GGL_CONTEXT_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/types.h>
-#include <endian.h>
-
-#include <pixelflinger/pixelflinger.h>
-#include <private/pixelflinger/ggl_fixed.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-
-inline uint32_t GGL_RGBA_TO_HOST(uint32_t v) {
-    return v;
-}
-inline uint32_t GGL_HOST_TO_RGBA(uint32_t v) {
-    return v;
-}
-
-#else
-
-inline uint32_t GGL_RGBA_TO_HOST(uint32_t v) {
-#if defined(__mips__) && __mips_isa_rev>=2
-    uint32_t r;
-    __asm__("wsbh %0, %1;"
-        "rotr %0, %0, 16"
-        : "=r" (r)
-        : "r" (v)
-        );
-    return r;
-#else
-    return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
-#endif
-}
-inline uint32_t GGL_HOST_TO_RGBA(uint32_t v) {
-#if defined(__mips__) && __mips_isa_rev>=2
-    uint32_t r;
-    __asm__("wsbh %0, %1;"
-        "rotr %0, %0, 16"
-        : "=r" (r)
-        : "r" (v)
-        );
-    return r;
-#else
-    return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
-#endif
-}
-
-#endif
-
-// ----------------------------------------------------------------------------
-
-const int GGL_DITHER_BITS = 6;  // dither weights stored on 6 bits
-const int GGL_DITHER_ORDER_SHIFT= 3;
-const int GGL_DITHER_ORDER      = (1<<GGL_DITHER_ORDER_SHIFT);
-const int GGL_DITHER_SIZE       = GGL_DITHER_ORDER * GGL_DITHER_ORDER;
-const int GGL_DITHER_MASK       = GGL_DITHER_ORDER-1;
-
-// ----------------------------------------------------------------------------
-
-const int GGL_SUBPIXEL_BITS = 4;
-
-// TRI_FRACTION_BITS defines the number of bits we want to use
-// for the sub-pixel coordinates during the edge stepping, the
-// value shouldn't be more than 7, or bad things are going to
-// happen when drawing large triangles (8 doesn't work because
-// 32 bit muls will loose the sign bit)
-
-#define  TRI_FRACTION_BITS  (GGL_SUBPIXEL_BITS)
-#define  TRI_ONE            (1 << TRI_FRACTION_BITS)
-#define  TRI_HALF           (1 << (TRI_FRACTION_BITS-1))
-#define  TRI_FROM_INT(x)    ((x) << TRI_FRACTION_BITS)
-#define  TRI_FRAC(x)        ((x)                 &  (TRI_ONE-1))
-#define  TRI_FLOOR(x)       ((x)                 & ~(TRI_ONE-1))
-#define  TRI_CEIL(x)        (((x) + (TRI_ONE-1)) & ~(TRI_ONE-1))
-#define  TRI_ROUND(x)       (((x) +  TRI_HALF  ) & ~(TRI_ONE-1))
-
-#define  TRI_ROUDNING       (1 << (16 - TRI_FRACTION_BITS - 1))
-#define  TRI_FROM_FIXED(x)  (((x)+TRI_ROUDNING) >> (16-TRI_FRACTION_BITS))
-
-#define  TRI_SNAP_NEXT_HALF(x)   (TRI_CEIL((x)+TRI_HALF) - TRI_HALF)
-#define  TRI_SNAP_PREV_HALF(x)   (TRI_CEIL((x)-TRI_HALF) - TRI_HALF)
-
-// ----------------------------------------------------------------------------
-
-const int GGL_COLOR_BITS = 24;
-
-// To maintain 8-bits color chanels, with a maximum GGLSurface
-// size of 4096 and GGL_SUBPIXEL_BITS=4, we need 8 + 12 + 4 = 24 bits
-// for encoding the color iterators
-
-inline GGLcolor gglFixedToIteratedColor(GGLfixed c) {
-    return (c << 8) - c;
-}
-
-// ----------------------------------------------------------------------------
-
-template<bool> struct CTA;
-template<> struct CTA<true> { };
-
-#define GGL_CONTEXT(con, c)         context_t *(con) = static_cast<context_t *>(c) /* NOLINT */
-#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)))
-
-#define ggl_likely(x)	__builtin_expect(!!(x), 1)
-#define ggl_unlikely(x)	__builtin_expect(!!(x), 0)
-
-const int GGL_TEXTURE_UNIT_COUNT    = 2;
-const int GGL_TMU_STATE             = 0x00000001;
-const int GGL_CB_STATE              = 0x00000002;
-const int GGL_PIXEL_PIPELINE_STATE  = 0x00000004;
-
-// ----------------------------------------------------------------------------
-
-#define GGL_RESERVE_NEEDS(name, l, s)                               \
-    const uint32_t  GGL_NEEDS_##name##_MASK = (((1LU<<(s))-1)<<(l));  \
-    const uint32_t  GGL_NEEDS_##name##_SHIFT = (l);
-
-#define GGL_BUILD_NEEDS(val, name)                                  \
-    (((val)<<(GGL_NEEDS_##name##_SHIFT)) & GGL_NEEDS_##name##_MASK)
-
-#define GGL_READ_NEEDS(name, n)                                     \
-    (uint32_t((n) & GGL_NEEDS_##name##_MASK) >> GGL_NEEDS_##name##_SHIFT)
-
-#define GGL_NEED_MASK(name)     (uint32_t(GGL_NEEDS_##name##_MASK))
-#define GGL_NEED(name, val)     GGL_BUILD_NEEDS(val, name)
-
-GGL_RESERVE_NEEDS( CB_FORMAT,       0, 6 )
-GGL_RESERVE_NEEDS( SHADE,           6, 1 )
-GGL_RESERVE_NEEDS( W,               7, 1 )
-GGL_RESERVE_NEEDS( BLEND_SRC,       8, 4 )
-GGL_RESERVE_NEEDS( BLEND_DST,      12, 4 )
-GGL_RESERVE_NEEDS( BLEND_SRCA,     16, 4 )
-GGL_RESERVE_NEEDS( BLEND_DSTA,     20, 4 )
-GGL_RESERVE_NEEDS( LOGIC_OP,       24, 4 )
-GGL_RESERVE_NEEDS( MASK_ARGB,      28, 4 )
-
-GGL_RESERVE_NEEDS( P_ALPHA_TEST,    0, 3 )
-GGL_RESERVE_NEEDS( P_AA,            3, 1 )
-GGL_RESERVE_NEEDS( P_DEPTH_TEST,    4, 3 )
-GGL_RESERVE_NEEDS( P_MASK_Z,        7, 1 )
-GGL_RESERVE_NEEDS( P_DITHER,        8, 1 )
-GGL_RESERVE_NEEDS( P_FOG,           9, 1 )
-GGL_RESERVE_NEEDS( P_RESERVED1,    10,22 )
-
-GGL_RESERVE_NEEDS( T_FORMAT,        0, 6 )
-GGL_RESERVE_NEEDS( T_RESERVED0,     6, 1 )
-GGL_RESERVE_NEEDS( T_POT,           7, 1 )
-GGL_RESERVE_NEEDS( T_S_WRAP,        8, 2 )
-GGL_RESERVE_NEEDS( T_T_WRAP,       10, 2 )
-GGL_RESERVE_NEEDS( T_ENV,          12, 3 )
-GGL_RESERVE_NEEDS( T_LINEAR,       15, 1 )
-
-const int GGL_NEEDS_WRAP_CLAMP_TO_EDGE  = 0;
-const int GGL_NEEDS_WRAP_REPEAT         = 1;
-const int GGL_NEEDS_WRAP_11             = 2;
-
-inline uint32_t ggl_wrap_to_needs(uint32_t e) {
-    switch (e) {
-    case GGL_CLAMP:         return GGL_NEEDS_WRAP_CLAMP_TO_EDGE;
-    case GGL_REPEAT:        return GGL_NEEDS_WRAP_REPEAT;
-    }
-    return 0;
-}
-
-inline uint32_t ggl_blendfactor_to_needs(uint32_t b) {
-    if (b <= 1) return b;
-    return (b & 0xF)+2;
-}
-
-inline uint32_t ggl_needs_to_blendfactor(uint32_t n) {
-    if (n <= 1) return n;
-    return (n - 2) + 0x300;
-}
-
-inline uint32_t ggl_env_to_needs(uint32_t e) {
-    switch (e) {
-    case GGL_REPLACE:   return 0;
-    case GGL_MODULATE:  return 1;
-    case GGL_DECAL:     return 2;
-    case GGL_BLEND:     return 3;
-    case GGL_ADD:       return 4;
-    }
-    return 0;
-}
-
-inline uint32_t ggl_needs_to_env(uint32_t n) {
-    const uint32_t envs[] = { GGL_REPLACE, GGL_MODULATE, 
-            GGL_DECAL, GGL_BLEND, GGL_ADD };
-    return envs[n];
-
-}
-
-// ----------------------------------------------------------------------------
-
-enum {
-    GGL_ENABLE_BLENDING     = 0x00000001,
-    GGL_ENABLE_SMOOTH       = 0x00000002,
-    GGL_ENABLE_AA           = 0x00000004,
-    GGL_ENABLE_LOGIC_OP     = 0x00000008,
-    GGL_ENABLE_ALPHA_TEST   = 0x00000010,
-    GGL_ENABLE_SCISSOR_TEST = 0x00000020,
-    GGL_ENABLE_TMUS         = 0x00000040,
-    GGL_ENABLE_DEPTH_TEST   = 0x00000080,
-    GGL_ENABLE_STENCIL_TEST = 0x00000100,
-    GGL_ENABLE_W            = 0x00000200,
-    GGL_ENABLE_DITHER       = 0x00000400,
-    GGL_ENABLE_FOG          = 0x00000800,
-    GGL_ENABLE_POINT_AA_NICE= 0x00001000
-};
-
-// ----------------------------------------------------------------------------
-
-struct needs_filter_t;
-struct needs_t {
-    inline int match(const needs_filter_t& filter);
-    inline bool operator == (const needs_t& rhs) const {
-        return  (n==rhs.n) &&
-                (p==rhs.p) &&
-                (t[0]==rhs.t[0]) &&
-                (t[1]==rhs.t[1]);
-    }
-    inline bool operator != (const needs_t& rhs) const {
-        return !operator == (rhs);
-    }
-    uint32_t    n;
-    uint32_t    p;
-    uint32_t    t[GGL_TEXTURE_UNIT_COUNT];
-};
-
-inline int compare_type(const needs_t& lhs, const needs_t& rhs) {
-    return memcmp(&lhs, &rhs, sizeof(needs_t));
-}
-
-struct needs_filter_t {
-    needs_t     value;
-    needs_t     mask;
-};
-
-int needs_t::match(const needs_filter_t& filter) {
-    uint32_t result = 
-        ((filter.value.n ^ n)       & filter.mask.n)    |
-        ((filter.value.p ^ p)       & filter.mask.p)    |
-        ((filter.value.t[0] ^ t[0]) & filter.mask.t[0]) |
-        ((filter.value.t[1] ^ t[1]) & filter.mask.t[1]);
-    return (result == 0);
-}
-
-// ----------------------------------------------------------------------------
-
-struct context_t;
-class Assembly;
-
-struct blend_state_t {
-	uint32_t			src;
-	uint32_t			dst;
-	uint32_t			src_alpha;
-	uint32_t			dst_alpha;
-	uint8_t				reserved;
-	uint8_t				alpha_separate;
-	uint8_t				operation;
-	uint8_t				equation;
-};
-
-struct mask_state_t {
-    uint8_t             color;
-    uint8_t             depth;
-    uint32_t            stencil;
-};
-
-struct clear_state_t {
-    GGLclampx           r;
-    GGLclampx           g;
-    GGLclampx           b;
-    GGLclampx           a;
-    GGLclampx           depth;
-    GGLint              stencil;
-    uint32_t            colorPacked;
-    uint32_t            depthPacked;
-    uint32_t            stencilPacked;
-    uint32_t            dirty;
-};
-
-struct fog_state_t {
-    uint8_t     color[4];
-};
-
-struct logic_op_state_t {
-    uint16_t            opcode;
-};
-
-struct alpha_test_state_t {
-    uint16_t            func;
-    GGLcolor            ref;
-};
-
-struct depth_test_state_t {
-    uint16_t            func;
-    GGLclampx           clearValue;
-};
-
-struct scissor_t {
-    uint32_t            user_left;
-    uint32_t            user_right;
-    uint32_t            user_top;
-    uint32_t            user_bottom;
-    uint32_t            left;
-    uint32_t            right;
-    uint32_t            top;
-    uint32_t            bottom;
-};
-
-struct pixel_t {
-    uint32_t    c[4];
-    uint8_t     s[4];
-};
-
-struct surface_t {
-    union {
-        GGLSurface          s;
-        // Keep the following struct field types in line with the corresponding
-        // GGLSurface fields to avoid mismatches leading to errors.
-        struct {
-            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,
-                                uint32_t x, uint32_t y, pixel_t* pixel);
-    void                (*write)(const surface_t* s, context_t* c,
-                                uint32_t x, uint32_t y, const pixel_t* pixel);
-};
-
-// ----------------------------------------------------------------------------
-
-struct texture_shade_t {
-    union {
-        struct {
-            int32_t             is0;
-            int32_t             idsdx;
-            int32_t             idsdy;
-            int                 sscale;
-            int32_t             it0;
-            int32_t             idtdx;
-            int32_t             idtdy;
-            int                 tscale;
-        };
-        struct {
-            int32_t             v;
-            int32_t             dx;
-            int32_t             dy;
-            int                 scale;
-        } st[2];
-    };
-};
-
-struct texture_iterators_t {
-    // these are not encoded in the same way than in the
-    // texture_shade_t structure
-    union {
-        struct {
-            GGLfixed			ydsdy;
-            GGLfixed            dsdx;
-            GGLfixed            dsdy;
-            int                 sscale;
-            GGLfixed			ydtdy;
-            GGLfixed            dtdx;
-            GGLfixed            dtdy;
-            int                 tscale;
-        };
-        struct {
-            GGLfixed			ydvdy;
-            GGLfixed            dvdx;
-            GGLfixed            dvdy;
-            int                 scale;
-        } st[2];
-    };
-};
-
-struct texture_t {
-	surface_t			surface;
-	texture_iterators_t	iterators;
-    texture_shade_t     shade;
-	uint32_t			s_coord;
-	uint32_t            t_coord;
-	uint16_t			s_wrap;
-	uint16_t            t_wrap;
-	uint16_t            min_filter;
-	uint16_t            mag_filter;
-    uint16_t            env;
-    uint8_t             env_color[4];
-	uint8_t				enable;
-	uint8_t				dirty;
-};
-
-struct raster_t {
-    GGLfixed            x;
-    GGLfixed            y;
-};
-
-struct framebuffer_t {
-    surface_t           color;
-    surface_t           read;
-	surface_t			depth;
-	surface_t			stencil;
-    int16_t             *coverage;
-    size_t              coverageBufferSize;
-};
-
-// ----------------------------------------------------------------------------
-
-struct iterators_t {
-	int32_t             xl;
-	int32_t             xr;
-    int32_t             y;
-	GGLcolor			ydady;
-	GGLcolor			ydrdy;
-	GGLcolor			ydgdy;
-	GGLcolor			ydbdy;
-	GGLfixed			ydzdy;
-	GGLfixed			ydwdy;
-	GGLfixed			ydfdy;
-};
-
-struct shade_t {
-	GGLcolor			a0;
-    GGLcolor            dadx;
-    GGLcolor            dady;
-	GGLcolor			r0;
-    GGLcolor            drdx;
-    GGLcolor            drdy;
-	GGLcolor			g0;
-    GGLcolor            dgdx;
-    GGLcolor            dgdy;
-	GGLcolor			b0;
-    GGLcolor            dbdx;
-    GGLcolor            dbdy;
-	uint32_t            z0;
-    GGLfixed32          dzdx;
-    GGLfixed32          dzdy;
-	GGLfixed            w0;
-    GGLfixed            dwdx;
-    GGLfixed            dwdy;
-	uint32_t			f0;
-    GGLfixed            dfdx;
-    GGLfixed            dfdy;
-};
-
-// these are used in the generated code
-// we use this mirror structure to improve
-// data locality in the pixel pipeline
-struct generated_tex_vars_t {
-    uint32_t    width;
-    uint32_t    height;
-    uint32_t    stride;
-    uintptr_t   data;
-    int32_t     dsdx;
-    int32_t     dtdx;
-    int32_t     spill[2];
-};
-
-struct generated_vars_t {
-    struct {
-        int32_t c;
-        int32_t dx;
-    } argb[4];
-    int32_t     aref;
-    int32_t     dzdx;
-    int32_t     zbase;
-    int32_t     f;
-    int32_t     dfdx;
-    int32_t     spill[3];
-    generated_tex_vars_t    texture[GGL_TEXTURE_UNIT_COUNT];
-    int32_t     rt;
-    int32_t     lb;
-};
-
-// ----------------------------------------------------------------------------
-
-struct state_t {
-	framebuffer_t		buffers;
-	texture_t			texture[GGL_TEXTURE_UNIT_COUNT];
-    scissor_t           scissor;
-    raster_t            raster;
-	blend_state_t		blend;
-    alpha_test_state_t  alpha_test;
-    depth_test_state_t  depth_test;
-    mask_state_t        mask;
-    clear_state_t       clear;
-    fog_state_t         fog;
-    logic_op_state_t    logic_op;
-    uint32_t            enables;
-    uint32_t            enabled_tmu;
-    needs_t             needs;
-};
-
-// ----------------------------------------------------------------------------
-
-struct context_t {
-	GGLContext          procs;
-	state_t             state;
-    shade_t             shade;
-	iterators_t         iterators;
-    generated_vars_t    generated_vars                __attribute__((aligned(32)));
-    uint8_t             ditherMatrix[GGL_DITHER_SIZE] __attribute__((aligned(32)));
-    uint32_t            packed;
-    uint32_t            packed8888;
-    const GGLFormat*    formats;
-    uint32_t            dirty;
-    texture_t*          activeTMU;
-    uint32_t            activeTMUIndex;
-
-    void                (*init_y)(context_t* c, int32_t y);
-	void                (*step_y)(context_t* c);
-	void                (*scanline)(context_t* c);
-    void                (*span)(context_t* c);
-    void                (*rect)(context_t* c, size_t yc);
-    
-    void*               base;
-    Assembly*           scanline_as;
-    GGLenum             error;
-};
-
-// ----------------------------------------------------------------------------
-
-void ggl_init_context(context_t* context);
-void ggl_uninit_context(context_t* context);
-void ggl_error(context_t* c, GGLenum error);
-int64_t ggl_system_time();
-
-// ----------------------------------------------------------------------------
-
-};
-
-#endif // ANDROID_GGL_CONTEXT_H
-
diff --git a/libpixelflinger/include/private/pixelflinger/ggl_fixed.h b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
deleted file mode 100644
index 4217a89..0000000
--- a/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
+++ /dev/null
@@ -1,878 +0,0 @@
-/*
- * 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_GGL_FIXED_H
-#define ANDROID_GGL_FIXED_H
-
-#include <math.h>
-#include <pixelflinger/pixelflinger.h>
-
-// ----------------------------------------------------------------------------
-
-#define CONST           __attribute__((const))
-#define ALWAYS_INLINE   __attribute__((always_inline))
-
-const GGLfixed FIXED_BITS = 16;
-const GGLfixed FIXED_EPSILON  = 1;
-const GGLfixed FIXED_ONE  = 1L<<FIXED_BITS;
-const GGLfixed FIXED_HALF = 1L<<(FIXED_BITS-1);
-const GGLfixed FIXED_MIN  = 0x80000000L;
-const GGLfixed FIXED_MAX  = 0x7FFFFFFFL;
-
-inline GGLfixed gglIntToFixed(GGLfixed i)       ALWAYS_INLINE ;
-inline GGLfixed gglFixedToIntRound(GGLfixed f)  ALWAYS_INLINE ;
-inline GGLfixed gglFixedToIntFloor(GGLfixed f)  ALWAYS_INLINE ;
-inline GGLfixed gglFixedToIntCeil(GGLfixed f)   ALWAYS_INLINE ;
-inline GGLfixed gglFracx(GGLfixed v)            ALWAYS_INLINE ;
-inline GGLfixed gglFloorx(GGLfixed v)           ALWAYS_INLINE ;
-inline GGLfixed gglCeilx(GGLfixed v)            ALWAYS_INLINE ;
-inline GGLfixed gglCenterx(GGLfixed v)          ALWAYS_INLINE ;
-inline GGLfixed gglRoundx(GGLfixed v)           ALWAYS_INLINE ;
-
-GGLfixed gglIntToFixed(GGLfixed i) {
-    return i<<FIXED_BITS;
-}
-GGLfixed gglFixedToIntRound(GGLfixed f) {
-    return (f + FIXED_HALF)>>FIXED_BITS;
-}
-GGLfixed gglFixedToIntFloor(GGLfixed f) {
-    return f>>FIXED_BITS;
-}
-GGLfixed gglFixedToIntCeil(GGLfixed f) {
-    return (f + ((1<<FIXED_BITS) - 1))>>FIXED_BITS;
-}
-
-GGLfixed gglFracx(GGLfixed v) {
-    return v & ((1<<FIXED_BITS)-1);
-}
-GGLfixed gglFloorx(GGLfixed v) {
-    return gglFixedToIntFloor(v)<<FIXED_BITS;
-}
-GGLfixed gglCeilx(GGLfixed v) {
-    return gglFixedToIntCeil(v)<<FIXED_BITS;
-}
-GGLfixed gglCenterx(GGLfixed v) {
-    return gglFloorx(v + FIXED_HALF) | FIXED_HALF;
-}
-GGLfixed gglRoundx(GGLfixed v) {
-    return gglFixedToIntRound(v)<<FIXED_BITS;
-}
-
-// conversion from (unsigned) int, short, byte to fixed...
-#define GGL_B_TO_X(_x)      GGLfixed( ((int32_t(_x)+1)>>1)<<10 )
-#define GGL_S_TO_X(_x)      GGLfixed( ((int32_t(_x)+1)>>1)<<2 )
-#define GGL_I_TO_X(_x)      GGLfixed( ((int32_t(_x)>>1)+1)>>14 )
-#define GGL_UB_TO_X(_x)     GGLfixed(   uint32_t(_x) +      \
-                                        (uint32_t(_x)<<8) + \
-                                        (uint32_t(_x)>>7) )
-#define GGL_US_TO_X(_x)     GGLfixed( (_x) + ((_x)>>15) )
-#define GGL_UI_TO_X(_x)     GGLfixed( (((_x)>>1)+1)>>15 )
-
-// ----------------------------------------------------------------------------
-
-GGLfixed gglPowx(GGLfixed x, GGLfixed y) CONST;
-GGLfixed gglSqrtx(GGLfixed a) CONST;
-GGLfixed gglSqrtRecipx(GGLfixed x) CONST;
-int32_t gglMulDivi(int32_t a, int32_t b, int32_t c);
-
-int32_t gglRecipQNormalized(int32_t x, int* exponent);
-int32_t gglRecipQ(GGLfixed x, int q) CONST;
-
-inline GGLfixed gglRecip(GGLfixed x) CONST;
-inline GGLfixed gglRecip(GGLfixed x) {
-    return gglRecipQ(x, 16);
-}
-
-inline GGLfixed gglRecip28(GGLfixed x) CONST;
-int32_t gglRecip28(GGLfixed x) {
-    return gglRecipQ(x, 28);
-}
-
-// ----------------------------------------------------------------------------
-
-#if defined(__arm__) && !defined(__thumb__)
-
-// inline ARM implementations
-inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift) CONST;
-__attribute__((always_inline)) inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift) {
-    GGLfixed result, t;
-    if (__builtin_constant_p(shift)) {
-    asm("smull  %[lo], %[hi], %[x], %[y]            \n"
-        "movs   %[lo], %[lo], lsr %[rshift]         \n"
-        "adc    %[lo], %[lo], %[hi], lsl %[lshift]  \n"
-        : [lo]"=r"(result), [hi]"=r"(t), [x]"=r"(x)
-        : "%[x]"(x), [y]"r"(y), [lshift] "I"(32-shift), [rshift] "I"(shift)
-        : "cc"
-        );
-    } else {
-    asm("smull  %[lo], %[hi], %[x], %[y]            \n"
-        "movs   %[lo], %[lo], lsr %[rshift]         \n"
-        "adc    %[lo], %[lo], %[hi], lsl %[lshift]  \n"
-        : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
-        : "%[x]"(x), [y]"r"(y), [lshift] "r"(32-shift), [rshift] "r"(shift)
-        : "cc"
-        );
-    }
-    return result;
-}
-
-inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST;
-__attribute__((always_inline)) inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a,
-                                                          int shift) {
-    GGLfixed result, t;
-    if (__builtin_constant_p(shift)) {
-    asm("smull  %[lo], %[hi], %[x], %[y]            \n"
-        "add    %[lo], %[a],  %[lo], lsr %[rshift]  \n"
-        "add    %[lo], %[lo], %[hi], lsl %[lshift]  \n"
-        : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
-        : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "I"(32-shift), [rshift] "I"(shift)
-        );
-    } else {
-    asm("smull  %[lo], %[hi], %[x], %[y]            \n"
-        "add    %[lo], %[a],  %[lo], lsr %[rshift]  \n"
-        "add    %[lo], %[lo], %[hi], lsl %[lshift]  \n"
-        : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
-        : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "r"(32-shift), [rshift] "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, t;
-    if (__builtin_constant_p(shift)) {
-    asm("smull  %[lo], %[hi], %[x], %[y]            \n"
-        "rsb    %[lo], %[a],  %[lo], lsr %[rshift]  \n"
-        "add    %[lo], %[lo], %[hi], lsl %[lshift]  \n"
-        : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
-        : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "I"(32-shift), [rshift] "I"(shift)
-        );
-    } else {
-    asm("smull  %[lo], %[hi], %[x], %[y]            \n"
-        "rsb    %[lo], %[a],  %[lo], lsr %[rshift]  \n"
-        "add    %[lo], %[lo], %[hi], lsl %[lshift]  \n"
-        : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
-        : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "r"(32-shift), [rshift] "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)
-{
-    // 64-bits result: r0=low, r1=high
-    union {
-        struct {
-            int32_t lo;
-            int32_t hi;
-        } s;
-        int64_t res;
-    };
-    asm("smull %0, %1, %2, %3   \n"
-        : "=r"(s.lo), "=&r"(s.hi)
-        : "%r"(x), "r"(y)
-        :
-        );
-    return res;
-}
-#elif defined(__mips__) && __mips_isa_rev < 6
-
-/*inline MIPS implementations*/
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST;
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) {
-    GGLfixed result,tmp,tmp1,tmp2;
-
-    if (__builtin_constant_p(shift)) {
-        if (shift == 0) {
-            asm ("mult %[a], %[b] \t\n"
-              "mflo  %[res]   \t\n"
-            : [res]"=&r"(result),[tmp]"=&r"(tmp)
-            : [a]"r"(a),[b]"r"(b)
-            : "%hi","%lo"
-            );
-        } else if (shift == 32)
-        {
-            asm ("mult %[a], %[b] \t\n"
-            "li  %[tmp],1\t\n"
-            "sll  %[tmp],%[tmp],0x1f\t\n"
-            "mflo %[res]   \t\n"
-            "addu %[tmp1],%[tmp],%[res] \t\n"
-            "sltu %[tmp1],%[tmp1],%[tmp]\t\n"   /*obit*/
-            "sra %[tmp],%[tmp],0x1f \t\n"
-            "mfhi  %[res]   \t\n"
-            "addu %[res],%[res],%[tmp]\t\n"
-            "addu %[res],%[res],%[tmp1]\t\n"
-            : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1)
-            : [a]"r"(a),[b]"r"(b),[shift]"I"(shift)
-            : "%hi","%lo"
-            );
-        } else if ((shift >0) && (shift < 32))
-        {
-            asm ("mult %[a], %[b] \t\n"
-            "li  %[tmp],1 \t\n"
-            "sll  %[tmp],%[tmp],%[shiftm1] \t\n"
-            "mflo  %[res]   \t\n"
-            "addu %[tmp1],%[tmp],%[res] \t\n"
-            "sltu %[tmp1],%[tmp1],%[tmp] \t\n"  /*obit?*/
-            "addu  %[res],%[res],%[tmp] \t\n"
-            "mfhi  %[tmp]   \t\n"
-            "addu  %[tmp],%[tmp],%[tmp1] \t\n"
-            "sll   %[tmp],%[tmp],%[lshift] \t\n"
-            "srl   %[res],%[res],%[rshift]    \t\n"
-            "or    %[res],%[res],%[tmp] \t\n"
-            : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-            : [a]"r"(a),[b]"r"(b),[lshift]"I"(32-shift),[rshift]"I"(shift),[shiftm1]"I"(shift-1)
-            : "%hi","%lo"
-            );
-        } else {
-            asm ("mult %[a], %[b] \t\n"
-            "li  %[tmp],1 \t\n"
-            "sll  %[tmp],%[tmp],%[shiftm1] \t\n"
-            "mflo  %[res]   \t\n"
-            "addu %[tmp1],%[tmp],%[res] \t\n"
-            "sltu %[tmp1],%[tmp1],%[tmp] \t\n"  /*obit?*/
-            "sra  %[tmp2],%[tmp],0x1f \t\n"
-            "addu  %[res],%[res],%[tmp] \t\n"
-            "mfhi  %[tmp]   \t\n"
-            "addu  %[tmp],%[tmp],%[tmp2] \t\n"
-            "addu  %[tmp],%[tmp],%[tmp1] \t\n"            /*tmp=hi*/
-            "srl   %[tmp2],%[res],%[rshift]    \t\n"
-            "srav  %[res], %[tmp],%[rshift]\t\n"
-            "sll   %[tmp],%[tmp],1 \t\n"
-            "sll   %[tmp],%[tmp],%[norbits] \t\n"
-            "or    %[tmp],%[tmp],%[tmp2] \t\n"
-            "movz  %[res],%[tmp],%[bit5] \t\n"
-            : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-            : [a]"r"(a),[b]"r"(b),[norbits]"I"(~(shift)),[rshift]"I"(shift),[shiftm1] "I"(shift-1),[bit5]"I"(shift & 0x20)
-            : "%hi","%lo"
-            );
-        }
-    } else {
-        asm ("mult %[a], %[b] \t\n"
-        "li  %[tmp],1 \t\n"
-        "sll  %[tmp],%[tmp],%[shiftm1] \t\n"
-        "mflo  %[res]   \t\n"
-        "addu %[tmp1],%[tmp],%[res] \t\n"
-        "sltu %[tmp1],%[tmp1],%[tmp] \t\n"  /*obit?*/
-        "sra  %[tmp2],%[tmp],0x1f \t\n"
-        "addu  %[res],%[res],%[tmp] \t\n"
-        "mfhi  %[tmp]   \t\n"
-        "addu  %[tmp],%[tmp],%[tmp2] \t\n"
-        "addu  %[tmp],%[tmp],%[tmp1] \t\n"            /*tmp=hi*/
-        "srl   %[tmp2],%[res],%[rshift]    \t\n"
-        "srav  %[res], %[tmp],%[rshift]\t\n"
-        "sll   %[tmp],%[tmp],1 \t\n"
-        "sll   %[tmp],%[tmp],%[norbits] \t\n"
-        "or    %[tmp],%[tmp],%[tmp2] \t\n"
-        "movz  %[res],%[tmp],%[bit5] \t\n"
-         : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-         : [a]"r"(a),[b]"r"(b),[norbits]"r"(~(shift)),[rshift] "r"(shift),[shiftm1]"r"(shift-1),[bit5] "r"(shift & 0x20)
-         : "%hi","%lo"
-         );
-        }
-
-        return result;
-}
-
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
-    GGLfixed result,t,tmp1,tmp2;
-
-    if (__builtin_constant_p(shift)) {
-        if (shift == 0) {
-                 asm ("mult %[a], %[b] \t\n"
-                 "mflo  %[lo]   \t\n"
-                 "addu  %[lo],%[lo],%[c]    \t\n"
-                 : [lo]"=&r"(result)
-                 : [a]"r"(a),[b]"r"(b),[c]"r"(c)
-                 : "%hi","%lo"
-                 );
-                } else if (shift == 32) {
-                    asm ("mult %[a], %[b] \t\n"
-                    "mfhi  %[lo]   \t\n"
-                    "addu  %[lo],%[lo],%[c]    \t\n"
-                    : [lo]"=&r"(result)
-                    : [a]"r"(a),[b]"r"(b),[c]"r"(c)
-                    : "%hi","%lo"
-                    );
-                } else if ((shift>0) && (shift<32)) {
-                    asm ("mult %[a], %[b] \t\n"
-                    "mflo  %[res]   \t\n"
-                    "mfhi  %[t]   \t\n"
-                    "srl   %[res],%[res],%[rshift]    \t\n"
-                    "sll   %[t],%[t],%[lshift]     \t\n"
-                    "or  %[res],%[res],%[t]    \t\n"
-                    "addu  %[res],%[res],%[c]    \t\n"
-                    : [res]"=&r"(result),[t]"=&r"(t)
-                    : [a]"r"(a),[b]"r"(b),[c]"r"(c),[lshift]"I"(32-shift),[rshift]"I"(shift)
-                    : "%hi","%lo"
-                    );
-                } else {
-                    asm ("mult %[a], %[b] \t\n"
-                    "nor %[tmp1],$zero,%[shift]\t\n"
-                    "mflo  %[res]   \t\n"
-                    "mfhi  %[t]   \t\n"
-                    "srl   %[res],%[res],%[shift]    \t\n"
-                    "sll   %[tmp2],%[t],1     \t\n"
-                    "sllv  %[tmp2],%[tmp2],%[tmp1]     \t\n"
-                    "or  %[tmp1],%[tmp2],%[res]    \t\n"
-                    "srav  %[res],%[t],%[shift]     \t\n"
-                    "andi %[tmp2],%[shift],0x20\t\n"
-                    "movz %[res],%[tmp1],%[tmp2]\t\n"
-                    "addu  %[res],%[res],%[c]    \t\n"
-                    : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-                    : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"I"(shift)
-                    : "%hi","%lo"
-                    );
-                }
-            } else {
-                asm ("mult %[a], %[b] \t\n"
-                "nor %[tmp1],$zero,%[shift]\t\n"
-                "mflo  %[res]   \t\n"
-                "mfhi  %[t]   \t\n"
-                "srl   %[res],%[res],%[shift]    \t\n"
-                "sll   %[tmp2],%[t],1     \t\n"
-                "sllv  %[tmp2],%[tmp2],%[tmp1]     \t\n"
-                "or  %[tmp1],%[tmp2],%[res]    \t\n"
-                "srav  %[res],%[t],%[shift]     \t\n"
-                "andi %[tmp2],%[shift],0x20\t\n"
-                "movz %[res],%[tmp1],%[tmp2]\t\n"
-                "addu  %[res],%[res],%[c]    \t\n"
-                : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-                : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"r"(shift)
-                : "%hi","%lo"
-                );
-            }
-            return result;
-}
-
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
-    GGLfixed result,t,tmp1,tmp2;
-
-    if (__builtin_constant_p(shift)) {
-        if (shift == 0) {
-                 asm ("mult %[a], %[b] \t\n"
-                 "mflo  %[lo]   \t\n"
-                 "subu  %[lo],%[lo],%[c]    \t\n"
-                 : [lo]"=&r"(result)
-                 : [a]"r"(a),[b]"r"(b),[c]"r"(c)
-                 : "%hi","%lo"
-                 );
-                } else if (shift == 32) {
-                    asm ("mult %[a], %[b] \t\n"
-                    "mfhi  %[lo]   \t\n"
-                    "subu  %[lo],%[lo],%[c]    \t\n"
-                    : [lo]"=&r"(result)
-                    : [a]"r"(a),[b]"r"(b),[c]"r"(c)
-                    : "%hi","%lo"
-                    );
-                } else if ((shift>0) && (shift<32)) {
-                    asm ("mult %[a], %[b] \t\n"
-                    "mflo  %[res]   \t\n"
-                    "mfhi  %[t]   \t\n"
-                    "srl   %[res],%[res],%[rshift]    \t\n"
-                    "sll   %[t],%[t],%[lshift]     \t\n"
-                    "or  %[res],%[res],%[t]    \t\n"
-                    "subu  %[res],%[res],%[c]    \t\n"
-                    : [res]"=&r"(result),[t]"=&r"(t)
-                    : [a]"r"(a),[b]"r"(b),[c]"r"(c),[lshift]"I"(32-shift),[rshift]"I"(shift)
-                    : "%hi","%lo"
-                    );
-                } else {
-                    asm ("mult %[a], %[b] \t\n"
-                    "nor %[tmp1],$zero,%[shift]\t\n"
-                     "mflo  %[res]   \t\n"
-                     "mfhi  %[t]   \t\n"
-                     "srl   %[res],%[res],%[shift]    \t\n"
-                     "sll   %[tmp2],%[t],1     \t\n"
-                     "sllv  %[tmp2],%[tmp2],%[tmp1]     \t\n"
-                     "or  %[tmp1],%[tmp2],%[res]    \t\n"
-                     "srav  %[res],%[t],%[shift]     \t\n"
-                     "andi %[tmp2],%[shift],0x20\t\n"
-                     "movz %[res],%[tmp1],%[tmp2]\t\n"
-                     "subu  %[res],%[res],%[c]    \t\n"
-                     : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-                     : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"I"(shift)
-                     : "%hi","%lo"
-                     );
-                    }
-                } else {
-                asm ("mult %[a], %[b] \t\n"
-                "nor %[tmp1],$zero,%[shift]\t\n"
-                "mflo  %[res]   \t\n"
-                "mfhi  %[t]   \t\n"
-                "srl   %[res],%[res],%[shift]    \t\n"
-                "sll   %[tmp2],%[t],1     \t\n"
-                "sllv  %[tmp2],%[tmp2],%[tmp1]     \t\n"
-                "or  %[tmp1],%[tmp2],%[res]    \t\n"
-                "srav  %[res],%[t],%[shift]     \t\n"
-                "andi %[tmp2],%[shift],0x20\t\n"
-                "movz %[res],%[tmp1],%[tmp2]\t\n"
-                "subu  %[res],%[res],%[c]    \t\n"
-                : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-                : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"r"(shift)
-                : "%hi","%lo"
-                );
-            }
-    return result;
-}
-
-inline int64_t gglMulii(int32_t x, int32_t y) CONST;
-inline int64_t gglMulii(int32_t x, int32_t y) {
-    union {
-        struct {
-#if defined(__MIPSEL__)
-            int32_t lo;
-            int32_t hi;
-#elif defined(__MIPSEB__)
-            int32_t hi;
-            int32_t lo;
-#endif
-        } s;
-        int64_t res;
-    }u;
-    asm("mult %2, %3 \t\n"
-        "mfhi %1   \t\n"
-        "mflo %0   \t\n"
-        : "=r"(u.s.lo), "=&r"(u.s.hi)
-        : "%r"(x), "r"(y)
-	: "%hi","%lo"
-        );
-    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;
-
-    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;
-}
-
-#elif defined(__mips__) && __mips_isa_rev == 6
-
-/*inline MIPS implementations*/
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST;
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) {
-    GGLfixed result,tmp,tmp1,tmp2;
-
-    if (__builtin_constant_p(shift)) {
-        if (shift == 0) {
-            asm ("mul %[res], %[a], %[b] \t\n"
-            : [res]"=&r"(result)
-            : [a]"r"(a),[b]"r"(b)
-            );
-        } else if (shift == 32)
-        {
-            asm ("mul %[res], %[a], %[b] \t\n"
-            "li  %[tmp],1\t\n"
-            "sll  %[tmp],%[tmp],0x1f\t\n"
-            "addu %[tmp1],%[tmp],%[res] \t\n"
-            "muh %[res], %[a], %[b] \t\n"
-            "sltu %[tmp1],%[tmp1],%[tmp]\t\n"   /*obit*/
-            "sra %[tmp],%[tmp],0x1f \t\n"
-            "addu %[res],%[res],%[tmp]\t\n"
-            "addu %[res],%[res],%[tmp1]\t\n"
-            : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1)
-            : [a]"r"(a),[b]"r"(b),[shift]"I"(shift)
-            );
-        } else if ((shift >0) && (shift < 32))
-        {
-            asm ("mul %[res], %[a], %[b] \t\n"
-            "li  %[tmp],1 \t\n"
-            "sll  %[tmp],%[tmp],%[shiftm1] \t\n"
-            "addu %[tmp1],%[tmp],%[res] \t\n"
-            "sltu %[tmp1],%[tmp1],%[tmp] \t\n"  /*obit?*/
-            "addu  %[res],%[res],%[tmp] \t\n"
-            "muh %[tmp], %[a], %[b] \t\n"
-            "addu  %[tmp],%[tmp],%[tmp1] \t\n"
-            "sll   %[tmp],%[tmp],%[lshift] \t\n"
-            "srl   %[res],%[res],%[rshift]    \t\n"
-            "or    %[res],%[res],%[tmp] \t\n"
-            : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-            : [a]"r"(a),[b]"r"(b),[lshift]"I"(32-shift),[rshift]"I"(shift),[shiftm1]"I"(shift-1)
-            );
-        } else {
-            asm ("mul %[res], %[a], %[b] \t\n"
-            "li  %[tmp],1 \t\n"
-            "sll  %[tmp],%[tmp],%[shiftm1] \t\n"
-            "addu %[tmp1],%[tmp],%[res] \t\n"
-            "sltu %[tmp1],%[tmp1],%[tmp] \t\n"  /*obit?*/
-            "sra  %[tmp2],%[tmp],0x1f \t\n"
-            "addu  %[res],%[res],%[tmp] \t\n"
-            "muh  %[tmp], %[a], %[b]   \t\n"
-            "addu  %[tmp],%[tmp],%[tmp2] \t\n"
-            "addu  %[tmp],%[tmp],%[tmp1] \t\n"            /*tmp=hi*/
-            "srl   %[tmp2],%[res],%[rshift]    \t\n"
-            "srav  %[res], %[tmp],%[rshift]\t\n"
-            "sll   %[tmp],%[tmp],1 \t\n"
-            "sll   %[tmp],%[tmp],%[norbits] \t\n"
-            "or    %[tmp],%[tmp],%[tmp2] \t\n"
-            "seleqz  %[tmp],%[tmp],%[bit5] \t\n"
-            "selnez  %[res],%[res],%[bit5] \t\n"
-            "or    %[res],%[res],%[tmp] \t\n"
-            : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-            : [a]"r"(a),[b]"r"(b),[norbits]"I"(~(shift)),[rshift]"I"(shift),[shiftm1] "I"(shift-1),[bit5]"I"(shift & 0x20)
-            );
-        }
-    } else {
-        asm ("mul %[res], %[a], %[b] \t\n"
-        "li  %[tmp],1 \t\n"
-        "sll  %[tmp],%[tmp],%[shiftm1] \t\n"
-        "addu %[tmp1],%[tmp],%[res] \t\n"
-        "sltu %[tmp1],%[tmp1],%[tmp] \t\n"  /*obit?*/
-        "sra  %[tmp2],%[tmp],0x1f \t\n"
-        "addu  %[res],%[res],%[tmp] \t\n"
-        "muh  %[tmp], %[a], %[b] \t\n"
-        "addu  %[tmp],%[tmp],%[tmp2] \t\n"
-        "addu  %[tmp],%[tmp],%[tmp1] \t\n"            /*tmp=hi*/
-        "srl   %[tmp2],%[res],%[rshift]    \t\n"
-        "srav  %[res], %[tmp],%[rshift]\t\n"
-        "sll   %[tmp],%[tmp],1 \t\n"
-        "sll   %[tmp],%[tmp],%[norbits] \t\n"
-        "or    %[tmp],%[tmp],%[tmp2] \t\n"
-        "seleqz  %[tmp],%[tmp],%[bit5] \t\n"
-        "selnez  %[res],%[res],%[bit5] \t\n"
-        "or    %[res],%[res],%[tmp] \t\n"
-         : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-         : [a]"r"(a),[b]"r"(b),[norbits]"r"(~(shift)),[rshift] "r"(shift),[shiftm1]"r"(shift-1),[bit5] "r"(shift & 0x20)
-         );
-        }
-        return result;
-}
-
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
-    GGLfixed result,t,tmp1,tmp2;
-
-    if (__builtin_constant_p(shift)) {
-        if (shift == 0) {
-                 asm ("mul %[lo], %[a], %[b] \t\n"
-                 "addu  %[lo],%[lo],%[c]    \t\n"
-                 : [lo]"=&r"(result)
-                 : [a]"r"(a),[b]"r"(b),[c]"r"(c)
-                 );
-                } else if (shift == 32) {
-                    asm ("muh %[lo], %[a], %[b] \t\n"
-                    "addu  %[lo],%[lo],%[c]    \t\n"
-                    : [lo]"=&r"(result)
-                    : [a]"r"(a),[b]"r"(b),[c]"r"(c)
-                    );
-                } else if ((shift>0) && (shift<32)) {
-                    asm ("mul %[res], %[a], %[b] \t\n"
-                    "muh  %[t], %[a], %[b] \t\n"
-                    "srl   %[res],%[res],%[rshift]    \t\n"
-                    "sll   %[t],%[t],%[lshift]     \t\n"
-                    "or  %[res],%[res],%[t]    \t\n"
-                    "addu  %[res],%[res],%[c]    \t\n"
-                    : [res]"=&r"(result),[t]"=&r"(t)
-                    : [a]"r"(a),[b]"r"(b),[c]"r"(c),[lshift]"I"(32-shift),[rshift]"I"(shift)
-                    );
-                } else {
-                    asm ("mul %[res], %[a], %[b] \t\n"
-                    "muh %[t], %[a], %[b] \t\n"
-                    "nor %[tmp1],$zero,%[shift]\t\n"
-                    "srl   %[res],%[res],%[shift]    \t\n"
-                    "sll   %[tmp2],%[t],1     \t\n"
-                    "sllv  %[tmp2],%[tmp2],%[tmp1]     \t\n"
-                    "or  %[tmp1],%[tmp2],%[res]    \t\n"
-                    "srav  %[res],%[t],%[shift]     \t\n"
-                    "andi %[tmp2],%[shift],0x20\t\n"
-                    "seleqz %[tmp1],%[tmp1],%[tmp2]\t\n"
-                    "selnez %[res],%[res],%[tmp2]\t\n"
-                    "or %[res],%[res],%[tmp1]\t\n"
-                    "addu  %[res],%[res],%[c]    \t\n"
-                    : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-                    : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"I"(shift)
-                    );
-                }
-            } else {
-                asm ("mul %[res], %[a], %[b] \t\n"
-                "muh %[t], %[a], %[b] \t\n"
-                "nor %[tmp1],$zero,%[shift]\t\n"
-                "srl   %[res],%[res],%[shift]    \t\n"
-                "sll   %[tmp2],%[t],1     \t\n"
-                "sllv  %[tmp2],%[tmp2],%[tmp1]     \t\n"
-                "or  %[tmp1],%[tmp2],%[res]    \t\n"
-                "srav  %[res],%[t],%[shift]     \t\n"
-                "andi %[tmp2],%[shift],0x20\t\n"
-                "seleqz %[tmp1],%[tmp1],%[tmp2]\t\n"
-                "selnez %[res],%[res],%[tmp2]\t\n"
-                "or %[res],%[res],%[tmp1]\t\n"
-                "addu  %[res],%[res],%[c]    \t\n"
-                : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-                : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"r"(shift)
-                );
-            }
-            return result;
-}
-
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
-    GGLfixed result,t,tmp1,tmp2;
-
-    if (__builtin_constant_p(shift)) {
-        if (shift == 0) {
-                 asm ("mul %[lo], %[a], %[b] \t\n"
-                 "subu  %[lo],%[lo],%[c]    \t\n"
-                 : [lo]"=&r"(result)
-                 : [a]"r"(a),[b]"r"(b),[c]"r"(c)
-                 );
-                } else if (shift == 32) {
-                    asm ("muh %[lo], %[a], %[b] \t\n"
-                    "subu  %[lo],%[lo],%[c]    \t\n"
-                    : [lo]"=&r"(result)
-                    : [a]"r"(a),[b]"r"(b),[c]"r"(c)
-                    );
-                } else if ((shift>0) && (shift<32)) {
-                    asm ("mul %[res], %[a], %[b] \t\n"
-                    "muh %[t], %[a], %[b] \t\n"
-                    "srl   %[res],%[res],%[rshift]    \t\n"
-                    "sll   %[t],%[t],%[lshift]     \t\n"
-                    "or  %[res],%[res],%[t]    \t\n"
-                    "subu  %[res],%[res],%[c]    \t\n"
-                    : [res]"=&r"(result),[t]"=&r"(t)
-                    : [a]"r"(a),[b]"r"(b),[c]"r"(c),[lshift]"I"(32-shift),[rshift]"I"(shift)
-                    );
-                } else {
-                    asm ("mul %[res], %[a], %[b] \t\n"
-                    "muh %[t], %[a], %[b] \t\n"
-                    "nor %[tmp1],$zero,%[shift]\t\n"
-                    "srl   %[res],%[res],%[shift]    \t\n"
-                    "sll   %[tmp2],%[t],1     \t\n"
-                    "sllv  %[tmp2],%[tmp2],%[tmp1]     \t\n"
-                    "or  %[tmp1],%[tmp2],%[res]    \t\n"
-                    "srav  %[res],%[t],%[shift]     \t\n"
-                    "andi %[tmp2],%[shift],0x20\t\n"
-                    "seleqz %[tmp1],%[tmp1],%[tmp2]\t\n"
-                    "selnez %[res],%[res],%[tmp2]\t\n"
-                    "or %[res],%[res],%[tmp1]\t\n"
-                    "subu  %[res],%[res],%[c]    \t\n"
-                    : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-                    : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"I"(shift)
-                     );
-                    }
-                } else {
-                asm ("mul %[res], %[a], %[b] \t\n"
-                "muh %[t], %[a], %[b] \t\n"
-                "nor %[tmp1],$zero,%[shift]\t\n"
-                "srl   %[res],%[res],%[shift]    \t\n"
-                "sll   %[tmp2],%[t],1     \t\n"
-                "sllv  %[tmp2],%[tmp2],%[tmp1]     \t\n"
-                "or  %[tmp1],%[tmp2],%[res]    \t\n"
-                "srav  %[res],%[t],%[shift]     \t\n"
-                "andi %[tmp2],%[shift],0x20\t\n"
-                "seleqz %[tmp1],%[tmp1],%[tmp2]\t\n"
-                "selnez %[res],%[res],%[tmp2]\t\n"
-                "or %[res],%[res],%[tmp1]\t\n"
-                "subu  %[res],%[res],%[c]    \t\n"
-                : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
-                : [a]"r"(a),[b]"r"(b),[c]"r"(c),[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) {
-    union {
-        struct {
-#if defined(__MIPSEL__)
-            int32_t lo;
-            int32_t hi;
-#elif defined(__MIPSEB__)
-            int32_t hi;
-            int32_t lo;
-#endif
-        } s;
-        int64_t res;
-    }u;
-    asm("mul %0, %2, %3 \t\n"
-        "muh %1, %2, %3 \t\n"
-        : "=r"(u.s.lo), "=&r"(u.s.hi)
-        : "%r"(x), "r"(y)
-        );
-    return u.res;
-}
-
-#else // ----------------------------------------------------------------------
-
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST;
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) {
-    return GGLfixed((int64_t(a)*b + (1<<(shift-1)))>>shift);
-}
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
-    return GGLfixed((int64_t(a)*b)>>shift) + c;
-}
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
-    return GGLfixed((int64_t(a)*b)>>shift) - c;
-}
-inline int64_t gglMulii(int32_t a, int32_t b) CONST;
-inline int64_t gglMulii(int32_t a, int32_t b) {
-    return int64_t(a)*b;
-}
-
-#endif
-
-// ------------------------------------------------------------------------
-
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b) CONST;
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b) {
-    return gglMulx(a, b, 16);
-}
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c) CONST;
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c) {
-    return gglMulAddx(a, b, c, 16);
-}
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c) CONST;
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c) {
-    return gglMulSubx(a, b, c, 16);
-}
-
-// ------------------------------------------------------------------------
-
-inline int32_t gglClz(int32_t x) CONST;
-inline int32_t gglClz(int32_t x)
-{
-#if (defined(__arm__) && !defined(__thumb__)) || defined(__mips__) || defined(__aarch64__)
-    return __builtin_clz(x);
-#else
-    if (!x) return 32;
-    int32_t exp = 31;
-    if (x & 0xFFFF0000) { exp -=16; x >>= 16; }
-    if (x & 0x0000ff00) { exp -= 8; x >>= 8; }
-    if (x & 0x000000f0) { exp -= 4; x >>= 4; }
-    if (x & 0x0000000c) { exp -= 2; x >>= 2; }
-    if (x & 0x00000002) { exp -= 1; }
-    return exp;
-#endif
-}
-
-// ------------------------------------------------------------------------
-
-int32_t gglDivQ(GGLfixed n, GGLfixed d, int32_t i) CONST;
-
-inline int32_t gglDivQ16(GGLfixed n, GGLfixed d) CONST;
-inline int32_t gglDivQ16(GGLfixed n, GGLfixed d) {
-    return gglDivQ(n, d, 16);
-}
-
-inline int32_t gglDivx(GGLfixed n, GGLfixed d) CONST;
-inline int32_t gglDivx(GGLfixed n, GGLfixed d) {
-    return gglDivQ(n, d, 16);
-}
-
-// ------------------------------------------------------------------------
-
-inline GGLfixed gglRecipFast(GGLfixed x) CONST;
-inline GGLfixed gglRecipFast(GGLfixed x)
-{
-    // This is a really bad approximation of 1/x, but it's also
-    // very fast. x must be strictly positive.
-    // if x between [0.5, 1[ , then 1/x = 3-2*x
-    // (we use 2.30 fixed-point)
-    const int32_t lz = gglClz(x);
-    return (0xC0000000 - (x << (lz - 1))) >> (30-lz);
-}
-
-// ------------------------------------------------------------------------
-
-inline GGLfixed gglClampx(GGLfixed c) CONST;
-inline GGLfixed gglClampx(GGLfixed c)
-{
-#if defined(__thumb__)
-    // clamp without branches
-    c &= ~(c>>31);  c = FIXED_ONE - c;
-    c &= ~(c>>31);  c = FIXED_ONE - c;
-#else
-#if defined(__arm__)
-    // I don't know why gcc thinks its smarter than me! The code below
-    // 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
-    if (c>FIXED_ONE)
-        c = FIXED_ONE;
-#endif
-    return c;
-}
-
-// ------------------------------------------------------------------------
-
-#endif // ANDROID_GGL_FIXED_H
diff --git a/libpixelflinger/picker.cpp b/libpixelflinger/picker.cpp
deleted file mode 100644
index aa55229..0000000
--- a/libpixelflinger/picker.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/* libs/pixelflinger/picker.cpp
-**
-** Copyright 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.
-*/
-
-
-#include <stdio.h>
-
-#include "buffer.h"
-#include "scanline.h"
-#include "picker.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-void ggl_init_picker(context_t* /*c*/)
-{
-}
-
-void ggl_pick(context_t* c)
-{
-    if (ggl_likely(!c->dirty))
-        return;
-        
-    // compute needs, see if they changed...
-    const uint32_t enables = c->state.enables;
-    needs_t new_needs(c->state.needs);
-
-    if (c->dirty & GGL_CB_STATE) {
-        new_needs.n &= ~GGL_NEEDS_CB_FORMAT_MASK;
-        new_needs.n |= GGL_BUILD_NEEDS(c->state.buffers.color.format, CB_FORMAT);
-        if (enables & GGL_ENABLE_BLENDING)
-            c->dirty |= GGL_PIXEL_PIPELINE_STATE;
-    }
-
-    if (c->dirty & GGL_PIXEL_PIPELINE_STATE) {
-        uint32_t n = GGL_BUILD_NEEDS(c->state.buffers.color.format, CB_FORMAT);
-        uint32_t p = 0;
-        if (enables & GGL_ENABLE_BLENDING) {
-            uint32_t src = c->state.blend.src;
-            uint32_t dst = c->state.blend.dst;
-            uint32_t src_alpha = c->state.blend.src_alpha;
-            uint32_t dst_alpha = c->state.blend.dst_alpha;
-            const GGLFormat& cbf = c->formats[ c->state.buffers.color.format ];
-            if (!cbf.c[GGLFormat::ALPHA].h) {
-                if ((src == GGL_ONE_MINUS_DST_ALPHA) ||
-                    (src == GGL_DST_ALPHA)) {
-                    src = GGL_ONE;
-                }
-                if ((src_alpha == GGL_ONE_MINUS_DST_ALPHA) ||
-                    (src_alpha == GGL_DST_ALPHA)) {
-                    src_alpha = GGL_ONE;
-                }
-                if ((dst == GGL_ONE_MINUS_DST_ALPHA) ||
-                    (dst == GGL_DST_ALPHA)) {
-                    dst = GGL_ONE;
-                }
-                if ((dst_alpha == GGL_ONE_MINUS_DST_ALPHA) ||
-                    (dst_alpha == GGL_DST_ALPHA)) {
-                    dst_alpha = GGL_ONE;
-                }
-            }
-
-            src       = ggl_blendfactor_to_needs(src);
-            dst       = ggl_blendfactor_to_needs(dst);
-            src_alpha = ggl_blendfactor_to_needs(src_alpha);
-            dst_alpha = ggl_blendfactor_to_needs(dst_alpha);
-                    
-            n |= GGL_BUILD_NEEDS( src, BLEND_SRC );
-            n |= GGL_BUILD_NEEDS( dst, BLEND_DST );
-            if (c->state.blend.alpha_separate) {
-                n |= GGL_BUILD_NEEDS( src_alpha, BLEND_SRCA );
-                n |= GGL_BUILD_NEEDS( dst_alpha, BLEND_DSTA );
-            } else {
-                n |= GGL_BUILD_NEEDS( src, BLEND_SRCA );
-                n |= GGL_BUILD_NEEDS( dst, BLEND_DSTA );
-            }
-        } else {
-            n |= GGL_BUILD_NEEDS( GGL_ONE,  BLEND_SRC );
-            n |= GGL_BUILD_NEEDS( GGL_ZERO, BLEND_DST );
-            n |= GGL_BUILD_NEEDS( GGL_ONE,  BLEND_SRCA );
-            n |= GGL_BUILD_NEEDS( GGL_ZERO, BLEND_DSTA );
-        }
-
-
-        n |= GGL_BUILD_NEEDS(c->state.mask.color^0xF,               MASK_ARGB);
-        n |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_SMOOTH)  ?1:0,   SHADE);
-        if (enables & GGL_ENABLE_TMUS) {
-            n |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_W)       ?1:0,   W);
-        }
-        p |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_DITHER)  ?1:0,   P_DITHER);
-        p |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_AA)      ?1:0,   P_AA);
-        p |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_FOG)     ?1:0,   P_FOG);
-
-        if (enables & GGL_ENABLE_LOGIC_OP) {
-            n |= GGL_BUILD_NEEDS(c->state.logic_op.opcode, LOGIC_OP);
-        } else {
-            n |= GGL_BUILD_NEEDS(GGL_COPY, LOGIC_OP);
-        }
-
-        if (enables & GGL_ENABLE_ALPHA_TEST) {
-            p |= GGL_BUILD_NEEDS(c->state.alpha_test.func, P_ALPHA_TEST);
-        } else {
-            p |= GGL_BUILD_NEEDS(GGL_ALWAYS, P_ALPHA_TEST);
-        }
-
-        if (enables & GGL_ENABLE_DEPTH_TEST) {
-            p |= GGL_BUILD_NEEDS(c->state.depth_test.func, P_DEPTH_TEST);
-            p |= GGL_BUILD_NEEDS(c->state.mask.depth&1, P_MASK_Z);
-        } else {
-            p |= GGL_BUILD_NEEDS(GGL_ALWAYS, P_DEPTH_TEST);
-            // writing to the z-buffer is always disabled if depth-test
-            // is disabled.
-        }
-        new_needs.n = n;
-        new_needs.p = p;
-    }
-
-    if (c->dirty & GGL_TMU_STATE) {
-        int idx = 0;
-        for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
-            const texture_t& tx = c->state.texture[i];
-            if (tx.enable) {
-                uint32_t t = 0;
-                t |= GGL_BUILD_NEEDS(tx.surface.format, T_FORMAT);
-                t |= GGL_BUILD_NEEDS(ggl_env_to_needs(tx.env), T_ENV);
-                t |= GGL_BUILD_NEEDS(0, T_POT);       // XXX: not used yet
-                if (tx.s_coord==GGL_ONE_TO_ONE && tx.t_coord==GGL_ONE_TO_ONE) {
-                    // we encode 1-to-1 into the wrap mode
-                    t |= GGL_BUILD_NEEDS(GGL_NEEDS_WRAP_11, T_S_WRAP);
-                    t |= GGL_BUILD_NEEDS(GGL_NEEDS_WRAP_11, T_T_WRAP);
-                } else {
-                    t |= GGL_BUILD_NEEDS(ggl_wrap_to_needs(tx.s_wrap), T_S_WRAP);
-                    t |= GGL_BUILD_NEEDS(ggl_wrap_to_needs(tx.t_wrap), T_T_WRAP);
-                }
-                if (tx.mag_filter == GGL_LINEAR) {
-                    t |= GGL_BUILD_NEEDS(1, T_LINEAR);
-                }
-                if (tx.min_filter == GGL_LINEAR) {
-                    t |= GGL_BUILD_NEEDS(1, T_LINEAR);
-                }
-                new_needs.t[idx++] = t;
-            } else {
-                new_needs.t[i] = 0;
-            }
-        }
-    }
-
-    if (new_needs != c->state.needs) {
-        c->state.needs = new_needs;
-        ggl_pick_texture(c);
-        ggl_pick_cb(c);
-        ggl_pick_scanline(c);
-    }
-    c->dirty = 0;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
diff --git a/libpixelflinger/picker.h b/libpixelflinger/picker.h
deleted file mode 100644
index 9cdbc3c..0000000
--- a/libpixelflinger/picker.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* libs/pixelflinger/picker.h
-**
-** Copyright 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 ANDROID_PICKER_H
-#define ANDROID_PICKER_H
-
-#include <private/pixelflinger/ggl_context.h>
-
-namespace android {
-
-void ggl_init_picker(context_t* c);
-void ggl_pick(context_t* c);
-
-}; // namespace android
-
-#endif
diff --git a/libpixelflinger/pixelflinger.cpp b/libpixelflinger/pixelflinger.cpp
deleted file mode 100644
index fd449b2..0000000
--- a/libpixelflinger/pixelflinger.cpp
+++ /dev/null
@@ -1,836 +0,0 @@
-/* libs/pixelflinger/pixelflinger.cpp
-**
-** Copyright 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.
-*/
-
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include <sys/time.h>
-
-#include <pixelflinger/pixelflinger.h>
-#include <private/pixelflinger/ggl_context.h>
-
-#include "buffer.h"
-#include "clear.h"
-#include "picker.h"
-#include "raster.h"
-#include "scanline.h"
-#include "trap.h"
-
-#include "codeflinger/GGLAssembler.h"
-#include "codeflinger/CodeCache.h"
-
-#include <stdio.h> 
-
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-// 8x8 Bayer dither matrix
-static const uint8_t gDitherMatrix[GGL_DITHER_SIZE] = {
-     0, 32,  8, 40,  2, 34, 10, 42,
-    48, 16, 56, 24, 50, 18, 58, 26,
-    12, 44,  4, 36, 14, 46,  6, 38,
-    60, 28, 52, 20, 62, 30, 54, 22,
-     3, 35, 11, 43,  1, 33,  9, 41,
-    51, 19, 59, 27, 49, 17, 57, 25,
-    15, 47,  7, 39, 13, 45,  5, 37,
-    63, 31, 55, 23, 61, 29, 53, 21
-};
-
-static void ggl_init_procs(context_t* c);
-static void ggl_set_scissor(context_t* c);
-
-static void ggl_enable_blending(context_t* c, int enable);
-static void ggl_enable_scissor_test(context_t* c, int enable);
-static void ggl_enable_alpha_test(context_t* c, int enable);
-static void ggl_enable_logic_op(context_t* c, int enable);
-static void ggl_enable_dither(context_t* c, int enable);
-static void ggl_enable_stencil_test(context_t* c, int enable);
-static void ggl_enable_depth_test(context_t* c, int enable);
-static void ggl_enable_aa(context_t* c, int enable);
-static void ggl_enable_point_aa_nice(context_t* c, int enable);
-static void ggl_enable_texture2d(context_t* c, int enable);
-static void ggl_enable_w_lerp(context_t* c, int enable);
-static void ggl_enable_fog(context_t* c, int enable);
-
-static inline int min(int a, int b) CONST;
-static inline int min(int a, int b) {
-    return a < b ? a : b;
-}
-
-static inline int max(int a, int b) CONST;
-static inline int max(int a, int b) {
-    return a < b ? b : a;
-}
-
-// ----------------------------------------------------------------------------
-
-void ggl_error(context_t* c, GGLenum error)
-{
-    if (c->error == GGL_NO_ERROR)
-        c->error = error;
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_bindTexture(void* con, const GGLSurface* surface)
-{
-    GGL_CONTEXT(c, con);
-    if (surface->format != c->activeTMU->surface.format)
-        ggl_state_changed(c, GGL_TMU_STATE);    
-    ggl_set_surface(c, &(c->activeTMU->surface), surface);
-}
-
-
-static void ggl_bindTextureLod(void* con, GGLuint tmu,const GGLSurface* surface)
-{
-    GGL_CONTEXT(c, con);
-    // All LODs must have the same format
-    ggl_set_surface(c, &c->state.texture[tmu].surface, surface);
-}
-
-static void ggl_colorBuffer(void* con, const GGLSurface* surface)
-{
-    GGL_CONTEXT(c, con);
-    if (surface->format != c->state.buffers.color.format)
-        ggl_state_changed(c, GGL_CB_STATE);
-
-    if (surface->width > c->state.buffers.coverageBufferSize) {
-        // allocate the coverage factor buffer
-        free(c->state.buffers.coverage);
-        c->state.buffers.coverage = (int16_t*)malloc(surface->width * 2);
-        c->state.buffers.coverageBufferSize =
-                c->state.buffers.coverage ? surface->width : 0;
-    }
-    ggl_set_surface(c, &(c->state.buffers.color), surface);
-    if (c->state.buffers.read.format == 0) {
-        ggl_set_surface(c, &(c->state.buffers.read), surface);
-    }
-    ggl_set_scissor(c);
-}
-
-static void ggl_readBuffer(void* con, const GGLSurface* surface)
-{
-    GGL_CONTEXT(c, con);
-    ggl_set_surface(c, &(c->state.buffers.read), surface);
-}
-
-static void ggl_depthBuffer(void* con, const GGLSurface* surface)
-{
-    GGL_CONTEXT(c, con);
-    if (surface->format == GGL_PIXEL_FORMAT_Z_16) {
-        ggl_set_surface(c, &(c->state.buffers.depth), surface);
-    } else {
-        c->state.buffers.depth.format = GGL_PIXEL_FORMAT_NONE;
-        ggl_enable_depth_test(c, 0);
-    }
-}
-
-static void ggl_scissor(void* con, GGLint x, GGLint y,
-        GGLsizei width, GGLsizei height)
-{
-    GGL_CONTEXT(c, con);
-    c->state.scissor.user_left = x;
-    c->state.scissor.user_top = y;
-    c->state.scissor.user_right = x + width;
-    c->state.scissor.user_bottom = y + height;
-    ggl_set_scissor(c);
-}
-
-// ----------------------------------------------------------------------------
-
-static void enable_disable(context_t* c, GGLenum name, int en)
-{
-    switch (name) {
-    case GGL_BLEND:             ggl_enable_blending(c, en);      break;
-    case GGL_SCISSOR_TEST:      ggl_enable_scissor_test(c, en);  break;
-    case GGL_ALPHA_TEST:        ggl_enable_alpha_test(c, en);    break;
-    case GGL_COLOR_LOGIC_OP:    ggl_enable_logic_op(c, en);      break;
-    case GGL_DITHER:            ggl_enable_dither(c, en);        break;
-    case GGL_STENCIL_TEST:      ggl_enable_stencil_test(c, en);  break;
-    case GGL_DEPTH_TEST:        ggl_enable_depth_test(c, en);    break;
-    case GGL_AA:                ggl_enable_aa(c, en);            break;
-    case GGL_TEXTURE_2D:        ggl_enable_texture2d(c, en);     break;
-    case GGL_W_LERP:            ggl_enable_w_lerp(c, en);        break;
-    case GGL_FOG:               ggl_enable_fog(c, en);           break;
-    case GGL_POINT_SMOOTH_NICE: ggl_enable_point_aa_nice(c, en); break;
-    }
-}
-
-static void ggl_enable(void* con, GGLenum name)
-{
-    GGL_CONTEXT(c, con);
-    enable_disable(c, name, 1);
-}
-
-static void ggl_disable(void* con, GGLenum name)
-{
-    GGL_CONTEXT(c, con);
-    enable_disable(c, name, 0);
-}
-
-static void ggl_enableDisable(void* con, GGLenum name, GGLboolean en)
-{
-    GGL_CONTEXT(c, con);
-    enable_disable(c, name, en ? 1 : 0);
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_shadeModel(void* con, GGLenum mode)
-{
-    GGL_CONTEXT(c, con);
-    switch (mode) {
-    case GGL_FLAT:
-        if (c->state.enables & GGL_ENABLE_SMOOTH) {
-            c->state.enables &= ~GGL_ENABLE_SMOOTH;
-            ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-        }
-        break;
-    case GGL_SMOOTH:
-        if (!(c->state.enables & GGL_ENABLE_SMOOTH)) {
-            c->state.enables |= GGL_ENABLE_SMOOTH;
-            ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-        }
-        break;
-    default:
-        ggl_error(c, GGL_INVALID_ENUM);
-    }
-}
-
-static void ggl_color4xv(void* con, const GGLclampx* color)
-{
-    GGL_CONTEXT(c, con);
-	c->shade.r0 = gglFixedToIteratedColor(color[0]);
-	c->shade.g0 = gglFixedToIteratedColor(color[1]);
-	c->shade.b0 = gglFixedToIteratedColor(color[2]);
-	c->shade.a0 = gglFixedToIteratedColor(color[3]);
-}
-
-static void ggl_colorGrad12xv(void* con, const GGLcolor* grad)
-{
-    GGL_CONTEXT(c, con);
-    // it is very important to round the iterated value here because
-    // the rasterizer doesn't clamp them, therefore the iterated value
-    //must absolutely be correct.
-    // GGLColor is encoded as 8.16 value
-    const int32_t round = 0x8000;
-	c->shade.r0   = grad[ 0] + round;
-	c->shade.drdx = grad[ 1];
-	c->shade.drdy = grad[ 2];
-	c->shade.g0   = grad[ 3] + round;
-	c->shade.dgdx = grad[ 4];
-	c->shade.dgdy = grad[ 5];
-	c->shade.b0   = grad[ 6] + round;
-	c->shade.dbdx = grad[ 7];
-	c->shade.dbdy = grad[ 8];
-	c->shade.a0   = grad[ 9] + round;
-	c->shade.dadx = grad[10];
-	c->shade.dady = grad[11];
-}
-
-static void ggl_zGrad3xv(void* con, const GGLfixed32* grad)
-{
-    GGL_CONTEXT(c, con);
-    // z iterators are encoded as 0.32 fixed point and the z-buffer
-    // holds 16 bits, the rounding value is 0x8000.
-    const uint32_t round = 0x8000;
-	c->shade.z0   = grad[0] + round;
-	c->shade.dzdx = grad[1];
-	c->shade.dzdy = grad[2];
-}
-
-static void ggl_wGrad3xv(void* con, const GGLfixed* grad)
-{
-    GGL_CONTEXT(c, con);
-	c->shade.w0   = grad[0];
-	c->shade.dwdx = grad[1];
-	c->shade.dwdy = grad[2];
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_fogGrad3xv(void* con, const GGLfixed* grad)
-{
-    GGL_CONTEXT(c, con);
-	c->shade.f0     = grad[0];
-	c->shade.dfdx   = grad[1];
-	c->shade.dfdy   = grad[2];
-}
-
-static void ggl_fogColor3xv(void* con, const GGLclampx* color)
-{
-    GGL_CONTEXT(c, con);
-    const int32_t r = gglClampx(color[0]);
-    const int32_t g = gglClampx(color[1]);
-    const int32_t b = gglClampx(color[2]);
-    c->state.fog.color[GGLFormat::ALPHA]= 0xFF; // unused
-	c->state.fog.color[GGLFormat::RED]  = (r - (r>>8))>>8;
-	c->state.fog.color[GGLFormat::GREEN]= (g - (g>>8))>>8;
-	c->state.fog.color[GGLFormat::BLUE] = (b - (b>>8))>>8;
-}
-
-static void ggl_enable_fog(context_t* c, int enable)
-{
-    const int e = (c->state.enables & GGL_ENABLE_FOG)?1:0;
-    if (e != enable) {
-        if (enable) c->state.enables |= GGL_ENABLE_FOG;
-        else        c->state.enables &= ~GGL_ENABLE_FOG;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_blendFunc(void* con, GGLenum src, GGLenum dst)
-{
-    GGL_CONTEXT(c, con);
-    c->state.blend.src = src;
-    c->state.blend.src_alpha = src;
-    c->state.blend.dst = dst;
-    c->state.blend.dst_alpha = dst;
-    c->state.blend.alpha_separate = 0;
-    if (c->state.enables & GGL_ENABLE_BLENDING) {
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-static void ggl_blendFuncSeparate(void* con,
-        GGLenum src, GGLenum dst,
-        GGLenum srcAlpha, GGLenum dstAplha)
-{
-    GGL_CONTEXT(c, con);
-    c->state.blend.src = src;
-    c->state.blend.src_alpha = srcAlpha;
-    c->state.blend.dst = dst;
-    c->state.blend.dst_alpha = dstAplha;
-    c->state.blend.alpha_separate = 1;
-    if (c->state.enables & GGL_ENABLE_BLENDING) {
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_texEnvi(void* con,	GGLenum target,
-							GGLenum pname,
-							GGLint param)
-{
-    GGL_CONTEXT(c, con);
-    if (target != GGL_TEXTURE_ENV || pname != GGL_TEXTURE_ENV_MODE) {
-        ggl_error(c, GGL_INVALID_ENUM);
-        return;
-    }
-    switch (param) {
-    case GGL_REPLACE:
-    case GGL_MODULATE:
-    case GGL_DECAL:
-    case GGL_BLEND:
-    case GGL_ADD:
-        if (c->activeTMU->env != param) {
-            c->activeTMU->env = param;
-            ggl_state_changed(c, GGL_TMU_STATE);
-        }
-        break;
-    default:
-        ggl_error(c, GGL_INVALID_ENUM);
-    }
-}
-
-static void ggl_texEnvxv(void* con, GGLenum target,
-        GGLenum pname, const GGLfixed* params)
-{
-    GGL_CONTEXT(c, con);
-    if (target != GGL_TEXTURE_ENV) {
-        ggl_error(c, GGL_INVALID_ENUM);
-        return;
-    }
-    switch (pname) {
-    case GGL_TEXTURE_ENV_MODE:
-        ggl_texEnvi(con, target, pname, params[0]);
-        break;
-    case GGL_TEXTURE_ENV_COLOR: {
-        uint8_t* const color = c->activeTMU->env_color;
-        const GGLclampx r = gglClampx(params[0]);
-        const GGLclampx g = gglClampx(params[1]);
-        const GGLclampx b = gglClampx(params[2]);
-        const GGLclampx a = gglClampx(params[3]);
-        color[0] = (a-(a>>8))>>8;
-        color[1] = (r-(r>>8))>>8;
-        color[2] = (g-(g>>8))>>8;
-        color[3] = (b-(b>>8))>>8;
-        break;
-    }
-    default:
-        ggl_error(c, GGL_INVALID_ENUM);
-        return;
-    }
-}
-
-
-static void ggl_texParameteri(void* con,
-        GGLenum target,
-        GGLenum pname,
-        GGLint param)
-{
-    GGL_CONTEXT(c, con);
-    if (target != GGL_TEXTURE_2D) {
-        ggl_error(c, GGL_INVALID_ENUM);
-        return;
-    }
-
-    if (param == GGL_CLAMP_TO_EDGE)
-        param = GGL_CLAMP;
-
-    uint16_t* what = 0;
-    switch (pname) {
-    case GGL_TEXTURE_WRAP_S:
-        if ((param == GGL_CLAMP) ||
-            (param == GGL_REPEAT)) {
-            what = &c->activeTMU->s_wrap;
-        }
-        break;
-    case GGL_TEXTURE_WRAP_T:
-        if ((param == GGL_CLAMP) ||
-            (param == GGL_REPEAT)) {
-            what = &c->activeTMU->t_wrap;
-        }
-        break;
-    case GGL_TEXTURE_MIN_FILTER:
-        if ((param == GGL_NEAREST) ||
-            (param == GGL_NEAREST_MIPMAP_NEAREST) ||
-            (param == GGL_NEAREST_MIPMAP_LINEAR)) {
-            what = &c->activeTMU->min_filter;
-            param = GGL_NEAREST;
-        }
-        if ((param == GGL_LINEAR) ||
-            (param == GGL_LINEAR_MIPMAP_NEAREST) ||
-            (param == GGL_LINEAR_MIPMAP_LINEAR)) {
-            what = &c->activeTMU->min_filter;
-            param = GGL_LINEAR;
-        }
-        break;
-    case GGL_TEXTURE_MAG_FILTER:
-        if ((param == GGL_NEAREST) ||
-            (param == GGL_LINEAR)) {
-            what = &c->activeTMU->mag_filter;
-        }
-        break;
-    }
-    
-    if (!what) {
-        ggl_error(c, GGL_INVALID_ENUM);
-        return;
-    }
-    
-    if (*what != param) {
-        *what = param;
-        ggl_state_changed(c, GGL_TMU_STATE);
-    }
-}
-
-static void ggl_texCoordGradScale8xv(void* con, GGLint tmu, const int32_t* grad)
-{
-    GGL_CONTEXT(c, con);
-    texture_t& u = c->state.texture[tmu];
-	u.shade.is0   = grad[0];
-	u.shade.idsdx = grad[1];
-	u.shade.idsdy = grad[2];
-	u.shade.it0   = grad[3];
-	u.shade.idtdx = grad[4];
-	u.shade.idtdy = grad[5];
-    u.shade.sscale= grad[6];
-    u.shade.tscale= grad[7];
-}
-
-static void ggl_texCoord2x(void* con, GGLfixed s, GGLfixed t)
-{
-    GGL_CONTEXT(c, con);
-	c->activeTMU->shade.is0 = s;
-	c->activeTMU->shade.it0 = t;
-    c->activeTMU->shade.sscale= 0;
-    c->activeTMU->shade.tscale= 0;
-}
-
-static void ggl_texCoord2i(void* con, GGLint s, GGLint t)
-{
-    ggl_texCoord2x(con, s<<16, t<<16);
-}
-
-static void ggl_texGeni(void* con, GGLenum coord, GGLenum pname, GGLint param)
-{
-    GGL_CONTEXT(c, con);
-    if (pname != GGL_TEXTURE_GEN_MODE) {
-        ggl_error(c, GGL_INVALID_ENUM);
-        return;
-    }
-
-    uint32_t* coord_ptr = 0;
-    if (coord == GGL_S)         coord_ptr = &(c->activeTMU->s_coord);
-    else if (coord == GGL_T)    coord_ptr = &(c->activeTMU->t_coord);
-
-    if (coord_ptr) {
-        if (*coord_ptr != uint32_t(param)) {
-            *coord_ptr = uint32_t(param);
-            ggl_state_changed(c, GGL_TMU_STATE);
-        }
-    } else {
-        ggl_error(c, GGL_INVALID_ENUM);
-    }
-}
-
-static void ggl_activeTexture(void* con, GGLuint tmu)
-{
-    GGL_CONTEXT(c, con);
-    if (tmu >= GGLuint(GGL_TEXTURE_UNIT_COUNT)) {
-        ggl_error(c, GGL_INVALID_ENUM);
-        return;
-    }
-    c->activeTMUIndex = tmu;
-    c->activeTMU = &(c->state.texture[tmu]);
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_colorMask(void* con, GGLboolean r,
-                                     GGLboolean g,
-                                     GGLboolean b,
-                                     GGLboolean a)
-{
-    GGL_CONTEXT(c, con);
-    int mask = 0;
-    if (a)  mask |= 1 << GGLFormat::ALPHA;
-    if (r)  mask |= 1 << GGLFormat::RED;
-    if (g)  mask |= 1 << GGLFormat::GREEN;
-    if (b)  mask |= 1 << GGLFormat::BLUE;
-    if (c->state.mask.color != mask) {
-        c->state.mask.color = mask;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-static void ggl_depthMask(void* con, GGLboolean flag)
-{
-    GGL_CONTEXT(c, con);
-    if (c->state.mask.depth != flag?1:0) {
-        c->state.mask.depth = flag?1:0;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-static void ggl_stencilMask(void* con, GGLuint mask)
-{
-    GGL_CONTEXT(c, con);
-    if (c->state.mask.stencil != mask) {
-        c->state.mask.stencil = mask;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_alphaFuncx(void* con, GGLenum func, GGLclampx ref)
-{
-    GGL_CONTEXT(c, con);
-    if ((func < GGL_NEVER) || (func > GGL_ALWAYS)) {
-        ggl_error(c, GGL_INVALID_ENUM);
-        return;
-    }
-    c->state.alpha_test.ref = gglFixedToIteratedColor(gglClampx(ref));
-    if (c->state.alpha_test.func != func) {
-        c->state.alpha_test.func = func;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_depthFunc(void* con, GGLenum func)
-{
-    GGL_CONTEXT(c, con);
-    if ((func < GGL_NEVER) || (func > GGL_ALWAYS)) {
-        ggl_error(c, GGL_INVALID_ENUM);
-        return;
-    }
-    if (c->state.depth_test.func != func) {
-        c->state.depth_test.func = func;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_logicOp(void* con, GGLenum opcode)
-{
-    GGL_CONTEXT(c, con);
-    if ((opcode < GGL_CLEAR) || (opcode > GGL_SET)) {
-        ggl_error(c, GGL_INVALID_ENUM);
-        return;
-    }
-    if (c->state.logic_op.opcode != opcode) {
-        c->state.logic_op.opcode = opcode;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-
-// ----------------------------------------------------------------------------
-
-void ggl_set_scissor(context_t* c)
-{
-    if (c->state.enables & GGL_ENABLE_SCISSOR_TEST) {
-        const int32_t l = c->state.scissor.user_left;
-        const int32_t t = c->state.scissor.user_top;
-        const int32_t r = c->state.scissor.user_right;
-        const int32_t b = c->state.scissor.user_bottom;
-        c->state.scissor.left   = max(0, l);
-        c->state.scissor.right  = min(c->state.buffers.color.width, r);
-        c->state.scissor.top    = max(0, t);
-        c->state.scissor.bottom = min(c->state.buffers.color.height, b);
-    } else {
-        c->state.scissor.left   = 0;
-        c->state.scissor.top    = 0;
-        c->state.scissor.right  = c->state.buffers.color.width;
-        c->state.scissor.bottom = c->state.buffers.color.height;
-    }
-}
-
-void ggl_enable_blending(context_t* c, int enable)
-{
-    const int e = (c->state.enables & GGL_ENABLE_BLENDING)?1:0;
-    if (e != enable) {
-        if (enable) c->state.enables |= GGL_ENABLE_BLENDING;
-        else        c->state.enables &= ~GGL_ENABLE_BLENDING;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-void ggl_enable_scissor_test(context_t* c, int enable)
-{
-    const int e = (c->state.enables & GGL_ENABLE_SCISSOR_TEST)?1:0;
-    if (e != enable) {
-        if (enable) c->state.enables |= GGL_ENABLE_SCISSOR_TEST;
-        else        c->state.enables &= ~GGL_ENABLE_SCISSOR_TEST;
-        ggl_set_scissor(c);
-    }
-}
-
-void ggl_enable_alpha_test(context_t* c, int enable)
-{
-    const int e = (c->state.enables & GGL_ENABLE_ALPHA_TEST)?1:0;
-    if (e != enable) {
-        if (enable) c->state.enables |= GGL_ENABLE_ALPHA_TEST;
-        else        c->state.enables &= ~GGL_ENABLE_ALPHA_TEST;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-void ggl_enable_logic_op(context_t* c, int enable)
-{
-    const int e = (c->state.enables & GGL_ENABLE_LOGIC_OP)?1:0;
-    if (e != enable) {
-        if (enable) c->state.enables |= GGL_ENABLE_LOGIC_OP;
-        else        c->state.enables &= ~GGL_ENABLE_LOGIC_OP;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-void ggl_enable_dither(context_t* c, int enable)
-{
-    const int e = (c->state.enables & GGL_ENABLE_DITHER)?1:0;
-    if (e != enable) {
-        if (enable) c->state.enables |= GGL_ENABLE_DITHER;
-        else        c->state.enables &= ~GGL_ENABLE_DITHER;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-void ggl_enable_stencil_test(context_t* /*c*/, int /*enable*/)
-{
-}
-
-void ggl_enable_depth_test(context_t* c, int enable)
-{
-    if (c->state.buffers.depth.format == 0)
-        enable = 0;
-    const int e = (c->state.enables & GGL_ENABLE_DEPTH_TEST)?1:0;
-    if (e != enable) {
-        if (enable) c->state.enables |= GGL_ENABLE_DEPTH_TEST;
-        else        c->state.enables &= ~GGL_ENABLE_DEPTH_TEST;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-void ggl_enable_aa(context_t* c, int enable)
-{
-    const int e = (c->state.enables & GGL_ENABLE_AA)?1:0;
-    if (e != enable) {
-        if (enable) c->state.enables |= GGL_ENABLE_AA;
-        else        c->state.enables &= ~GGL_ENABLE_AA;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-void ggl_enable_point_aa_nice(context_t* c, int enable)
-{
-    const int e = (c->state.enables & GGL_ENABLE_POINT_AA_NICE)?1:0;
-    if (e != enable) {
-        if (enable) c->state.enables |= GGL_ENABLE_POINT_AA_NICE;
-        else        c->state.enables &= ~GGL_ENABLE_POINT_AA_NICE;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-void ggl_enable_w_lerp(context_t* c, int enable)
-{
-    const int e = (c->state.enables & GGL_ENABLE_W)?1:0;
-    if (e != enable) {
-        if (enable) c->state.enables |= GGL_ENABLE_W;
-        else        c->state.enables &= ~GGL_ENABLE_W;
-        ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
-    }
-}
-
-void ggl_enable_texture2d(context_t* c, int enable)
-{
-    if (c->activeTMU->enable != enable) {
-        const uint32_t tmu = c->activeTMUIndex;
-        c->activeTMU->enable = enable;
-        const uint32_t mask = 1UL << tmu;
-        if (enable)                 c->state.enabled_tmu |= mask;
-        else                        c->state.enabled_tmu &= ~mask;
-        if (c->state.enabled_tmu)   c->state.enables |= GGL_ENABLE_TMUS;
-        else                        c->state.enables &= ~GGL_ENABLE_TMUS;
-        ggl_state_changed(c, GGL_TMU_STATE);
-    }
-}
-
-        
-// ----------------------------------------------------------------------------
-
-int64_t ggl_system_time()
-{
-    struct timespec t;
-    t.tv_sec = t.tv_nsec = 0;
-    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t);
-    return int64_t(t.tv_sec)*1000000000LL + t.tv_nsec;
-}
-
-// ----------------------------------------------------------------------------
-
-void ggl_init_procs(context_t* c)
-{
-    GGLContext& procs = *(GGLContext*)c;
-    GGL_INIT_PROC(procs, scissor);
-    GGL_INIT_PROC(procs, activeTexture);
-    GGL_INIT_PROC(procs, bindTexture);
-    GGL_INIT_PROC(procs, bindTextureLod);
-    GGL_INIT_PROC(procs, colorBuffer);
-    GGL_INIT_PROC(procs, readBuffer);
-    GGL_INIT_PROC(procs, depthBuffer);
-    GGL_INIT_PROC(procs, enable);
-    GGL_INIT_PROC(procs, disable);
-    GGL_INIT_PROC(procs, enableDisable);
-    GGL_INIT_PROC(procs, shadeModel);
-    GGL_INIT_PROC(procs, color4xv);
-    GGL_INIT_PROC(procs, colorGrad12xv);
-    GGL_INIT_PROC(procs, zGrad3xv);
-    GGL_INIT_PROC(procs, wGrad3xv);
-    GGL_INIT_PROC(procs, fogGrad3xv);
-    GGL_INIT_PROC(procs, fogColor3xv);
-    GGL_INIT_PROC(procs, blendFunc);
-    GGL_INIT_PROC(procs, blendFuncSeparate);
-    GGL_INIT_PROC(procs, texEnvi);
-    GGL_INIT_PROC(procs, texEnvxv);
-    GGL_INIT_PROC(procs, texParameteri);
-    GGL_INIT_PROC(procs, texCoord2i);
-    GGL_INIT_PROC(procs, texCoord2x);
-    GGL_INIT_PROC(procs, texCoordGradScale8xv);
-    GGL_INIT_PROC(procs, texGeni);
-    GGL_INIT_PROC(procs, colorMask);
-    GGL_INIT_PROC(procs, depthMask);
-    GGL_INIT_PROC(procs, stencilMask);
-    GGL_INIT_PROC(procs, alphaFuncx);
-    GGL_INIT_PROC(procs, depthFunc);
-    GGL_INIT_PROC(procs, logicOp);
-    ggl_init_clear(c);
-}
-
-void ggl_init_context(context_t* c)
-{
-    memset(c, 0, sizeof(context_t));
-    ggl_init_procs(c);
-    ggl_init_trap(c);
-    ggl_init_scanline(c);
-    ggl_init_texture(c);
-    ggl_init_picker(c);
-    ggl_init_raster(c);
-    c->formats = gglGetPixelFormatTable();
-    c->state.blend.src = GGL_ONE;
-    c->state.blend.dst = GGL_ZERO;
-    c->state.blend.src_alpha = GGL_ONE;
-    c->state.blend.dst_alpha = GGL_ZERO;
-    c->state.mask.color = 0xF;
-    c->state.mask.depth = 0;
-    c->state.mask.stencil = 0xFFFFFFFF;
-    c->state.logic_op.opcode = GGL_COPY;
-    c->state.alpha_test.func = GGL_ALWAYS;
-    c->state.depth_test.func = GGL_LESS;
-    c->state.depth_test.clearValue = FIXED_ONE;
-    c->shade.w0 = FIXED_ONE;
-    memcpy(c->ditherMatrix, gDitherMatrix, sizeof(gDitherMatrix));
-}
-
-void ggl_uninit_context(context_t* c)
-{
-    ggl_uninit_scanline(c);
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
-
-
-
-using namespace android;
-
-ssize_t gglInit(GGLContext** context)
-{
-    void* const base = malloc(sizeof(context_t) + 32);
-	if (base) {
-        // always align the context on cache lines
-        context_t *c = (context_t *)((ptrdiff_t(base)+31) & ~0x1FL);
-        ggl_init_context(c);
-        c->base = base;
-		*context = (GGLContext*)c;
-	} else {
-		return -1;
-	}
-	return 0;
-}
-
-ssize_t gglUninit(GGLContext* con)
-{
-    GGL_CONTEXT(c, (void*)con);
-    ggl_uninit_context(c);
-	free(c->base);
-	return 0;
-}
-
diff --git a/libpixelflinger/raster.cpp b/libpixelflinger/raster.cpp
deleted file mode 100644
index e95c2c8..0000000
--- a/libpixelflinger/raster.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/* libs/pixelflinger/raster.cpp
-**
-** Copyright 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.
-*/
-
-
-
-#include <string.h>
-
-#include "raster.h"
-#include "trap.h"
-
-namespace android {
-
-static void ggl_rasterPos2x(void* con, GGLfixed x, GGLfixed y);
-static void ggl_rasterPos2i(void* con, GGLint x, GGLint y);
-static void ggl_copyPixels(void* con, GGLint xs, GGLint ys,
-        GGLsizei width, GGLsizei height, GGLenum type);
-
-void ggl_init_raster(context_t* c)
-{
-    GGLContext& procs = *(GGLContext*)c;
-    GGL_INIT_PROC(procs, copyPixels);
-    GGL_INIT_PROC(procs, rasterPos2x);
-    GGL_INIT_PROC(procs, rasterPos2i);
-}
-
-void ggl_rasterPos2x(void* con, GGLfixed x, GGLfixed y)
-{
-    GGL_CONTEXT(c, con);
-    // raster pos should be processed just like glVertex
-    c->state.raster.x = x;
-    c->state.raster.y = y;
-}
-
-void ggl_rasterPos2i(void* con, GGLint x, GGLint y)
-{
-    ggl_rasterPos2x(con, gglIntToFixed(x), gglIntToFixed(y));
-}
-
-void ggl_copyPixels(void* con, GGLint xs, GGLint ys,
-        GGLsizei width, GGLsizei height, GGLenum /*type*/)
-{
-    GGL_CONTEXT(c, con);
-
-    // color-buffer
-    surface_t* cb = &(c->state.buffers.color);
-
-    // undefined behaviour if we try to copy from outside the surface
-    if (uint32_t(xs) > cb->width)
-        return;
-    if (uint32_t(ys) > cb->height)
-        return;
-    if (uint32_t(xs + width) > cb->width)
-        return;
-    if (uint32_t(ys + height) > cb->height)
-        return;
-
-    // copy to current raster position
-    GGLint xd = gglFixedToIntRound(c->state.raster.x);
-    GGLint yd = gglFixedToIntRound(c->state.raster.y);
-
-    // clip to scissor
-    if (xd < GGLint(c->state.scissor.left)) {
-        GGLint offset = GGLint(c->state.scissor.left) - xd;
-        xd = GGLint(c->state.scissor.left);
-        xs += offset;
-        width -= offset;
-    }
-    if (yd < GGLint(c->state.scissor.top)) {
-        GGLint offset = GGLint(c->state.scissor.top) - yd;
-        yd = GGLint(c->state.scissor.top);
-        ys += offset;
-        height -= offset;
-    }
-    if ((xd + width) > GGLint(c->state.scissor.right)) {
-        width = GGLint(c->state.scissor.right) - xd;
-    }
-    if ((yd + height) > GGLint(c->state.scissor.bottom)) {
-        height = GGLint(c->state.scissor.bottom) - yd;
-    }
-
-    if (width<=0 || height<=0) {
-        return; // nothing to copy
-    }
-
-    if (xs==xd && ys==yd) {
-        // nothing to do, but be careful, this might not be true when we support
-        // gglPixelTransfer, gglPixelMap and gglPixelZoom
-        return;
-    }
-
-    const GGLFormat* fp = &(c->formats[cb->format]);
-    uint8_t* src = reinterpret_cast<uint8_t*>(cb->data)
-            + (xs + (cb->stride * ys)) * fp->size;
-    uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data)
-            + (xd + (cb->stride * yd)) * fp->size;
-    const size_t bpr = cb->stride * fp->size;
-    const size_t rowsize = width * fp->size;
-    size_t yc = height;
-
-    if (ys < yd) {
-        // bottom to top
-        src += height * bpr;
-        dst += height * bpr;
-        do {
-            dst -= bpr;
-            src -= bpr;
-            memcpy(dst, src, rowsize);
-        } while (--yc);
-    } else {
-        if (ys == yd) {
-            // might be right to left
-            do {
-                memmove(dst, src, rowsize);
-                dst += bpr;
-                src += bpr;
-            } while (--yc);
-        } else {
-            // top to bottom
-            do {
-                memcpy(dst, src, rowsize);
-                dst += bpr;
-                src += bpr;
-            } while (--yc);
-        }
-    }
-}
-
-}; // namespace android
-
-using namespace android;
-
-GGLint gglBitBlit(GGLContext* con, int tmu, GGLint crop[4], GGLint where[4])
-{
-    GGL_CONTEXT(c, (void*)con);
-
-     GGLint x = where[0];
-     GGLint y = where[1];
-     GGLint w = where[2];
-     GGLint h = where[3];
-
-    // exclsively enable this tmu
-    c->procs.activeTexture(c, tmu);
-    c->procs.disable(c, GGL_W_LERP);
-
-    uint32_t tmus = 1UL<<tmu;
-    if (c->state.enabled_tmu != tmus) {
-        c->activeTMU->enable = 1;
-        c->state.enabled_tmu = tmus;
-        c->state.enables |= GGL_ENABLE_TMUS;
-        ggl_state_changed(c, GGL_TMU_STATE);
-    }
-
-    const GGLint Wcr = crop[2];
-    const GGLint Hcr = crop[3];
-    if ((w == Wcr) && (h == Hcr)) {
-        c->procs.texGeni(c, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
-        c->procs.texGeni(c, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
-        const GGLint Ucr = crop[0];
-        const GGLint Vcr = crop[1];
-        const GGLint s0  = Ucr - x;
-        const GGLint t0  = Vcr - y;
-        c->procs.texCoord2i(c, s0, t0);
-        c->procs.recti(c, x, y, x+w, y+h);
-    } else {
-        int32_t texcoords[8];
-        x = gglIntToFixed(x);
-        y = gglIntToFixed(y); 
-    
-        // we CLAMP here, which works with premultiplied (s,t)
-        c->procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP);
-        c->procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
-        c->procs.texGeni(c, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
-        c->procs.texGeni(c, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
-    
-        const GGLint Ucr = crop[0] << 16;
-        const GGLint Vcr = crop[1] << 16;
-        const GGLint Wcr = crop[2] << 16;
-        const GGLint Hcr = crop[3] << 16;
-    
-        // computes texture coordinates (pre-multiplied)
-        int32_t dsdx = Wcr / w;   // dsdx = ((Wcr/w)/Wt)*Wt
-        int32_t dtdy = Hcr / h;   // dtdy = ((Hcr/h)/Ht)*Ht
-        int32_t s0   = Ucr - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx
-        int32_t t0   = Vcr - gglMulx(dtdy, y); // t0 = Vcr - y * dtdy
-        texcoords[0] = s0;
-        texcoords[1] = dsdx;
-        texcoords[2] = 0;
-        texcoords[3] = t0;
-        texcoords[4] = 0;
-        texcoords[5] = dtdy;
-        texcoords[6] = 0;
-        texcoords[7] = 0;
-        c->procs.texCoordGradScale8xv(c, tmu, texcoords);
-        c->procs.recti(c, 
-                gglFixedToIntRound(x),
-                gglFixedToIntRound(y),
-                gglFixedToIntRound(x)+w,
-                gglFixedToIntRound(y)+h);
-    }
-    return 0;
-}
-
diff --git a/libpixelflinger/raster.h b/libpixelflinger/raster.h
deleted file mode 100644
index 9f0f240..0000000
--- a/libpixelflinger/raster.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* libs/pixelflinger/raster.h
-**
-** Copyright 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 ANDROID_GGL_RASTER_H
-#define ANDROID_GGL_RASTER_H
-
-#include <private/pixelflinger/ggl_context.h>
-
-namespace android {
-
-void ggl_init_raster(context_t* c);
-
-void gglCopyPixels(void* c, GGLint x, GGLint y, GGLsizei width, GGLsizei height, GGLenum type);
-void gglRasterPos2d(void* c, GGLint x, GGLint y);
-
-}; // namespace android
-
-#endif // ANDROID_GGL_RASTER_H
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
deleted file mode 100644
index 4cc23c7..0000000
--- a/libpixelflinger/scanline.cpp
+++ /dev/null
@@ -1,2373 +0,0 @@
-/* libs/pixelflinger/scanline.cpp
-**
-** Copyright 2006-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 "pixelflinger"
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <cutils/memory.h>
-#include <log/log.h>
-
-#include "buffer.h"
-#include "scanline.h"
-
-#include "codeflinger/CodeCache.h"
-#include "codeflinger/GGLAssembler.h"
-#if defined(__arm__)
-#include "codeflinger/ARMAssembler.h"
-#elif defined(__aarch64__)
-#include "codeflinger/Arm64Assembler.h"
-#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
-#include "codeflinger/MIPSAssembler.h"
-#elif defined(__mips__) && defined(__LP64__)
-#include "codeflinger/MIPS64Assembler.h"
-#endif
-//#include "codeflinger/ARMAssemblerOptimizer.h"
-
-// ----------------------------------------------------------------------------
-
-#define ANDROID_CODEGEN_GENERIC     0   // force generic pixel pipeline
-#define ANDROID_CODEGEN_C           1   // hand-written C, fallback generic 
-#define ANDROID_CODEGEN_ASM         2   // hand-written asm, fallback generic
-#define ANDROID_CODEGEN_GENERATED   3   // hand-written asm, fallback codegen
-
-#ifdef NDEBUG
-#   define ANDROID_RELEASE
-#   define ANDROID_CODEGEN      ANDROID_CODEGEN_GENERATED
-#else
-#   define ANDROID_DEBUG
-#   define ANDROID_CODEGEN      ANDROID_CODEGEN_GENERATED
-#endif
-
-#if defined(__arm__) || (defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || defined(__LP64__))) || defined(__aarch64__)
-#   define ANDROID_ARM_CODEGEN  1
-#else
-#   define ANDROID_ARM_CODEGEN  0
-#endif
-
-#define DEBUG__CODEGEN_ONLY     0
-
-/* Set to 1 to dump to the log the states that need a new
- * code-generated scanline callback, i.e. those that don't
- * have a corresponding shortcut function.
- */
-#define DEBUG_NEEDS  0
-
-#if defined( __mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || defined(__LP64__))
-#define ASSEMBLY_SCRATCH_SIZE   4096
-#elif defined(__aarch64__)
-#define ASSEMBLY_SCRATCH_SIZE   8192
-#else
-#define ASSEMBLY_SCRATCH_SIZE   2048
-#endif
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-static void init_y(context_t*, int32_t);
-static void init_y_noop(context_t*, int32_t);
-static void init_y_packed(context_t*, int32_t);
-static void init_y_error(context_t*, int32_t);
-
-static void step_y__generic(context_t* c);
-static void step_y__nop(context_t*);
-static void step_y__smooth(context_t* c);
-static void step_y__tmu(context_t* c);
-static void step_y__w(context_t* c);
-
-static void scanline(context_t* c);
-static void scanline_perspective(context_t* c);
-static void scanline_perspective_single(context_t* c);
-static void scanline_t32cb16blend(context_t* c);
-static void scanline_t32cb16blend_dither(context_t* c);
-static void scanline_t32cb16blend_srca(context_t* c);
-static void scanline_t32cb16blend_clamp(context_t* c);
-static void scanline_t32cb16blend_clamp_dither(context_t* c);
-static void scanline_t32cb16blend_clamp_mod(context_t* c);
-static void scanline_x32cb16blend_clamp_mod(context_t* c);
-static void scanline_t32cb16blend_clamp_mod_dither(context_t* c);
-static void scanline_x32cb16blend_clamp_mod_dither(context_t* c);
-static void scanline_t32cb16(context_t* c);
-static void scanline_t32cb16_dither(context_t* c);
-static void scanline_t32cb16_clamp(context_t* c);
-static void scanline_t32cb16_clamp_dither(context_t* c);
-static void scanline_col32cb16blend(context_t* c);
-static void scanline_t16cb16_clamp(context_t* c);
-static void scanline_t16cb16blend_clamp_mod(context_t* c);
-static void scanline_memcpy(context_t* c);
-static void scanline_memset8(context_t* c);
-static void scanline_memset16(context_t* c);
-static void scanline_memset32(context_t* c);
-static void scanline_noop(context_t* c);
-static void scanline_set(context_t* c);
-static void scanline_clear(context_t* c);
-
-static void rect_generic(context_t* c, size_t yc);
-static void rect_memcpy(context_t* c, size_t yc);
-
-#if defined( __arm__)
-extern "C" void scanline_t32cb16blend_arm(uint16_t*, uint32_t*, size_t);
-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_arm64(uint16_t*, uint32_t*, size_t);
-extern "C" void scanline_col32cb16blend_arm64(uint16_t *dst, uint32_t col, size_t ct);
-#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
-extern "C" void scanline_t32cb16blend_mips(uint16_t*, uint32_t*, size_t);
-#elif defined(__mips__) && defined(__LP64__)
-extern "C" void scanline_t32cb16blend_mips64(uint16_t*, uint32_t*, size_t);
-extern "C" void scanline_col32cb16blend_mips64(uint16_t *dst, uint32_t col, size_t ct);
-#endif
-
-// ----------------------------------------------------------------------------
-
-static inline uint16_t  convertAbgr8888ToRgb565(uint32_t  pix)
-{
-    return uint16_t( ((pix << 8) & 0xf800) |
-                      ((pix >> 5) & 0x07e0) |
-                      ((pix >> 19) & 0x001f) );
-}
-
-struct shortcut_t {
-    needs_filter_t  filter;
-    const char*     desc;
-    void            (*scanline)(context_t*);
-    void            (*init_y)(context_t*, int32_t);
-};
-
-// Keep in sync with needs
-
-/* To understand the values here, have a look at:
- *     system/core/include/private/pixelflinger/ggl_context.h
- *
- * Especially the lines defining and using GGL_RESERVE_NEEDS
- *
- * Quick reminders:
- *   - the last nibble of the first value is the destination buffer format.
- *   - the last nibble of the third value is the source texture format
- *   - formats: 4=rgb565 1=abgr8888 2=xbgr8888
- *
- * In the descriptions below:
- *
- *   SRC      means we copy the source pixels to the destination
- *
- *   SRC_OVER means we blend the source pixels to the destination
- *            with dstFactor = 1-srcA, srcFactor=1  (premultiplied source).
- *            This mode is otherwise called 'blend'.
- *
- *   SRCA_OVER means we blend the source pixels to the destination
- *             with dstFactor=srcA*(1-srcA) srcFactor=srcA (non-premul source).
- *             This mode is otherwise called 'blend_srca'
- *
- *   clamp    means we fetch source pixels from a texture with u/v clamping
- *
- *   mod      means the source pixels are modulated (multiplied) by the
- *            a/r/g/b of the current context's color. Typically used for
- *            fade-in / fade-out.
- *
- *   dither   means we dither 32 bit values to 16 bits
- */
-static shortcut_t shortcuts[] = {
-    { { { 0x03515104, 0x00000077, { 0x00000A01, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 8888 tx, blend SRC_OVER", scanline_t32cb16blend, init_y_noop },
-    { { { 0x03010104, 0x00000077, { 0x00000A01, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 8888 tx, SRC", scanline_t32cb16, init_y_noop  },
-    /* same as first entry, but with dithering */
-    { { { 0x03515104, 0x00000177, { 0x00000A01, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 8888 tx, blend SRC_OVER dither", scanline_t32cb16blend_dither, init_y_noop },
-    /* same as second entry, but with dithering */
-    { { { 0x03010104, 0x00000177, { 0x00000A01, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 8888 tx, SRC dither", scanline_t32cb16_dither, init_y_noop  },
-    /* this is used during the boot animation - CHEAT: ignore dithering */
-    { { { 0x03545404, 0x00000077, { 0x00000A01, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFEFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 8888 tx, blend dst:ONE_MINUS_SRCA src:SRCA", scanline_t32cb16blend_srca, init_y_noop },
-    /* special case for arbitrary texture coordinates (think scaling) */
-    { { { 0x03515104, 0x00000077, { 0x00000001, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 8888 tx, SRC_OVER clamp", scanline_t32cb16blend_clamp, init_y },
-    { { { 0x03515104, 0x00000177, { 0x00000001, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 8888 tx, SRC_OVER clamp dither", scanline_t32cb16blend_clamp_dither, init_y },
-    /* another case used during emulation */
-    { { { 0x03515104, 0x00000077, { 0x00001001, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 8888 tx, SRC_OVER clamp modulate", scanline_t32cb16blend_clamp_mod, init_y },
-    /* and this */
-    { { { 0x03515104, 0x00000077, { 0x00001002, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, x888 tx, SRC_OVER clamp modulate", scanline_x32cb16blend_clamp_mod, init_y },
-    { { { 0x03515104, 0x00000177, { 0x00001001, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 8888 tx, SRC_OVER clamp modulate dither", scanline_t32cb16blend_clamp_mod_dither, init_y },
-    { { { 0x03515104, 0x00000177, { 0x00001002, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, x888 tx, SRC_OVER clamp modulate dither", scanline_x32cb16blend_clamp_mod_dither, init_y },
-    { { { 0x03010104, 0x00000077, { 0x00000001, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 8888 tx, SRC clamp", scanline_t32cb16_clamp, init_y  },
-    { { { 0x03010104, 0x00000077, { 0x00000002, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, x888 tx, SRC clamp", scanline_t32cb16_clamp, init_y  },
-    { { { 0x03010104, 0x00000177, { 0x00000001, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 8888 tx, SRC clamp dither", scanline_t32cb16_clamp_dither, init_y  },
-    { { { 0x03010104, 0x00000177, { 0x00000002, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, x888 tx, SRC clamp dither", scanline_t32cb16_clamp_dither, init_y  },
-    { { { 0x03010104, 0x00000077, { 0x00000004, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 565 tx, SRC clamp", scanline_t16cb16_clamp, init_y  },
-    { { { 0x03515104, 0x00000077, { 0x00001004, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
-        "565 fb, 565 tx, SRC_OVER clamp", scanline_t16cb16blend_clamp_mod, init_y  },
-    { { { 0x03515104, 0x00000077, { 0x00000000, 0x00000000 } },
-        { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0xFFFFFFFF } } },
-        "565 fb, 8888 fixed color", scanline_col32cb16blend, init_y_packed  },  
-    { { { 0x00000000, 0x00000000, { 0x00000000, 0x00000000 } },
-        { 0x00000000, 0x00000007, { 0x00000000, 0x00000000 } } },
-        "(nop) alpha test", scanline_noop, init_y_noop },
-    { { { 0x00000000, 0x00000000, { 0x00000000, 0x00000000 } },
-        { 0x00000000, 0x00000070, { 0x00000000, 0x00000000 } } },
-        "(nop) depth test", scanline_noop, init_y_noop },
-    { { { 0x05000000, 0x00000000, { 0x00000000, 0x00000000 } },
-        { 0x0F000000, 0x00000080, { 0x00000000, 0x00000000 } } },
-        "(nop) logic_op", scanline_noop, init_y_noop },
-    { { { 0xF0000000, 0x00000000, { 0x00000000, 0x00000000 } },
-        { 0xF0000000, 0x00000080, { 0x00000000, 0x00000000 } } },
-        "(nop) color mask", scanline_noop, init_y_noop },
-    { { { 0x0F000000, 0x00000077, { 0x00000000, 0x00000000 } },
-        { 0xFF000000, 0x000000F7, { 0x00000000, 0x00000000 } } },
-        "(set) logic_op", scanline_set, init_y_noop },
-    { { { 0x00000000, 0x00000077, { 0x00000000, 0x00000000 } },
-        { 0xFF000000, 0x000000F7, { 0x00000000, 0x00000000 } } },
-        "(clear) logic_op", scanline_clear, init_y_noop },
-    { { { 0x03000000, 0x00000077, { 0x00000000, 0x00000000 } },
-        { 0xFFFFFF00, 0x000000F7, { 0x00000000, 0x00000000 } } },
-        "(clear) blending 0/0", scanline_clear, init_y_noop },
-    { { { 0x00000000, 0x00000000, { 0x00000000, 0x00000000 } },
-        { 0x0000003F, 0x00000000, { 0x00000000, 0x00000000 } } },
-        "(error) invalid color-buffer format", scanline_noop, init_y_error },
-};
-static const needs_filter_t noblend1to1 = {
-        // (disregard dithering, see below)
-        { 0x03010100, 0x00000077, { 0x00000A00, 0x00000000 } },
-        { 0xFFFFFFC0, 0xFFFFFEFF, { 0xFFFFFFC0, 0x0000003F } }
-};
-static  const needs_filter_t fill16noblend = {
-        { 0x03010100, 0x00000077, { 0x00000000, 0x00000000 } },
-        { 0xFFFFFFC0, 0xFFFFFFFF, { 0x0000003F, 0x0000003F } }
-};
-
-// ----------------------------------------------------------------------------
-
-#if ANDROID_ARM_CODEGEN
-
-#if defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || defined(__LP64__))
-static CodeCache gCodeCache(32 * 1024);
-#elif defined(__aarch64__)
-static CodeCache gCodeCache(48 * 1024);
-#else
-static CodeCache gCodeCache(12 * 1024);
-#endif
-
-class ScanlineAssembly : public Assembly {
-    AssemblyKey<needs_t> mKey;
-public:
-    ScanlineAssembly(needs_t needs, size_t size)
-        : Assembly(size), mKey(needs) { }
-    const AssemblyKey<needs_t>& key() const { return mKey; }
-};
-#endif
-
-// ----------------------------------------------------------------------------
-
-void ggl_init_scanline(context_t* c)
-{
-    c->init_y = init_y;
-    c->step_y = step_y__generic;
-    c->scanline = scanline;
-}
-
-void ggl_uninit_scanline(context_t* c)
-{
-    if (c->state.buffers.coverage)
-        free(c->state.buffers.coverage);
-#if ANDROID_ARM_CODEGEN
-    if (c->scanline_as)
-        c->scanline_as->decStrong(c);
-#endif
-}
-
-// ----------------------------------------------------------------------------
-
-static void pick_scanline(context_t* c)
-{
-#if (!defined(DEBUG__CODEGEN_ONLY) || (DEBUG__CODEGEN_ONLY == 0))
-
-#if ANDROID_CODEGEN == ANDROID_CODEGEN_GENERIC
-    c->init_y = init_y;
-    c->step_y = step_y__generic;
-    c->scanline = scanline;
-    return;
-#endif
-
-    //printf("*** needs [%08lx:%08lx:%08lx:%08lx]\n",
-    //    c->state.needs.n, c->state.needs.p,
-    //    c->state.needs.t[0], c->state.needs.t[1]);
-
-    // first handle the special case that we cannot test with a filter
-    const uint32_t cb_format = GGL_READ_NEEDS(CB_FORMAT, c->state.needs.n);
-    if (GGL_READ_NEEDS(T_FORMAT, c->state.needs.t[0]) == cb_format) {
-        if (c->state.needs.match(noblend1to1)) {
-            // this will match regardless of dithering state, since both
-            // src and dest have the same format anyway, there is no dithering
-            // to be done.
-            const GGLFormat* f =
-                &(c->formats[GGL_READ_NEEDS(T_FORMAT, c->state.needs.t[0])]);
-            if ((f->components == GGL_RGB) ||
-                (f->components == GGL_RGBA) ||
-                (f->components == GGL_LUMINANCE) ||
-                (f->components == GGL_LUMINANCE_ALPHA))
-            {
-                // format must have all of RGB components
-                // (so the current color doesn't show through)
-                c->scanline = scanline_memcpy;
-                c->init_y = init_y_noop;
-                return;
-            }
-        }
-    }
-
-    if (c->state.needs.match(fill16noblend)) {
-        c->init_y = init_y_packed;
-        switch (c->formats[cb_format].size) {
-        case 1: c->scanline = scanline_memset8;  return;
-        case 2: c->scanline = scanline_memset16; return;
-        case 4: c->scanline = scanline_memset32; return;
-        }
-    }
-
-    const int numFilters = sizeof(shortcuts)/sizeof(shortcut_t);
-    for (int i=0 ; i<numFilters ; i++) {
-        if (c->state.needs.match(shortcuts[i].filter)) {
-            c->scanline = shortcuts[i].scanline;
-            c->init_y = shortcuts[i].init_y;
-            return;
-        }
-    }
-
-#if DEBUG_NEEDS
-    ALOGI("Needs: n=0x%08x p=0x%08x t0=0x%08x t1=0x%08x",
-         c->state.needs.n, c->state.needs.p,
-         c->state.needs.t[0], c->state.needs.t[1]);
-#endif
-
-#endif // DEBUG__CODEGEN_ONLY
-
-    c->init_y = init_y;
-    c->step_y = step_y__generic;
-
-#if ANDROID_ARM_CODEGEN
-    // we're going to have to generate some code...
-    // here, generate code for our pixel pipeline
-    const AssemblyKey<needs_t> key(c->state.needs);
-    sp<Assembly> assembly = gCodeCache.lookup(key);
-    if (assembly == 0) {
-        // create a new assembly region
-        sp<ScanlineAssembly> a = new ScanlineAssembly(c->state.needs, 
-                ASSEMBLY_SCRATCH_SIZE);
-        // initialize our assembler
-#if defined(__arm__)
-        GGLAssembler assembler( new ARMAssembler(a) );
-        //GGLAssembler assembler(
-        //        new ARMAssemblerOptimizer(new ARMAssembler(a)) );
-#endif
-#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
-        GGLAssembler assembler( new ArmToMipsAssembler(a) );
-#elif defined(__mips__) && defined(__LP64__)
-        GGLAssembler assembler( new ArmToMips64Assembler(a) );
-#elif defined(__aarch64__)
-        GGLAssembler assembler( new ArmToArm64Assembler(a) );
-#endif
-        // generate the scanline code for the given needs
-        bool err = assembler.scanline(c->state.needs, c) != 0;
-        if (ggl_likely(!err)) {
-            // finally, cache this assembly
-            err = gCodeCache.cache(a->key(), a) < 0;
-        }
-        if (ggl_unlikely(err)) {
-            ALOGE("error generating or caching assembly. Reverting to NOP.");
-            c->scanline = scanline_noop;
-            c->init_y = init_y_noop;
-            c->step_y = step_y__nop;
-            return;
-        }
-        assembly = a;
-    }
-
-    // release the previous assembly
-    if (c->scanline_as) {
-        c->scanline_as->decStrong(c);
-    }
-
-    //ALOGI("using generated pixel-pipeline");
-    c->scanline_as = assembly.get();
-    c->scanline_as->incStrong(c); //  hold on to assembly
-    c->scanline = (void(*)(context_t* c))assembly->base();
-#else
-//    ALOGW("using generic (slow) pixel-pipeline");
-    c->scanline = scanline;
-#endif
-}
-
-void ggl_pick_scanline(context_t* c)
-{
-    pick_scanline(c);
-    if ((c->state.enables & GGL_ENABLE_W) &&
-        (c->state.enables & GGL_ENABLE_TMUS))
-    {
-        c->span = c->scanline;
-        c->scanline = scanline_perspective;
-        if (!(c->state.enabled_tmu & (c->state.enabled_tmu - 1))) {
-            // only one TMU enabled
-            c->scanline = scanline_perspective_single;
-        }
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-static void blending(context_t* c, pixel_t* fragment, pixel_t* fb);
-static void blend_factor(context_t* c, pixel_t* r, uint32_t factor,
-        const pixel_t* src, const pixel_t* dst);
-static void rescale(uint32_t& u, uint8_t& su, uint32_t& v, uint8_t& sv);
-
-#if ANDROID_ARM_CODEGEN && (ANDROID_CODEGEN == ANDROID_CODEGEN_GENERATED)
-
-// no need to compile the generic-pipeline, it can't be reached
-void scanline(context_t*)
-{
-}
-
-#else
-
-void rescale(uint32_t& u, uint8_t& su, uint32_t& v, uint8_t& sv)
-{
-    if (su && sv) {
-        if (su > sv) {
-            v = ggl_expand(v, sv, su);
-            sv = su;
-        } else if (su < sv) {
-            u = ggl_expand(u, su, sv);
-            su = sv;
-        }
-    }
-}
-
-void blending(context_t* c, pixel_t* fragment, pixel_t* fb)
-{
-    rescale(fragment->c[0], fragment->s[0], fb->c[0], fb->s[0]);
-    rescale(fragment->c[1], fragment->s[1], fb->c[1], fb->s[1]);
-    rescale(fragment->c[2], fragment->s[2], fb->c[2], fb->s[2]);
-    rescale(fragment->c[3], fragment->s[3], fb->c[3], fb->s[3]);
-
-    pixel_t sf, df;
-    blend_factor(c, &sf, c->state.blend.src, fragment, fb);
-    blend_factor(c, &df, c->state.blend.dst, fragment, fb);
-
-    fragment->c[1] =
-            gglMulAddx(fragment->c[1], sf.c[1], gglMulx(fb->c[1], df.c[1]));
-    fragment->c[2] =
-            gglMulAddx(fragment->c[2], sf.c[2], gglMulx(fb->c[2], df.c[2]));
-    fragment->c[3] =
-            gglMulAddx(fragment->c[3], sf.c[3], gglMulx(fb->c[3], df.c[3]));
-
-    if (c->state.blend.alpha_separate) {
-        blend_factor(c, &sf, c->state.blend.src_alpha, fragment, fb);
-        blend_factor(c, &df, c->state.blend.dst_alpha, fragment, fb);
-    }
-
-    fragment->c[0] =
-            gglMulAddx(fragment->c[0], sf.c[0], gglMulx(fb->c[0], df.c[0]));
-
-    // clamp to 1.0
-    if (fragment->c[0] >= (1LU<<fragment->s[0]))
-        fragment->c[0] = (1<<fragment->s[0])-1;
-    if (fragment->c[1] >= (1LU<<fragment->s[1]))
-        fragment->c[1] = (1<<fragment->s[1])-1;
-    if (fragment->c[2] >= (1LU<<fragment->s[2]))
-        fragment->c[2] = (1<<fragment->s[2])-1;
-    if (fragment->c[3] >= (1LU<<fragment->s[3]))
-        fragment->c[3] = (1<<fragment->s[3])-1;
-}
-
-static inline int blendfactor(uint32_t x, uint32_t size, uint32_t def = 0)
-{
-    if (!size)
-        return def;
-
-    // scale to 16 bits
-    if (size > 16) {
-        x >>= (size - 16);
-    } else if (size < 16) {
-        x = ggl_expand(x, size, 16);
-    }
-    x += x >> 15;
-    return x;
-}
-
-void blend_factor(context_t* /*c*/, pixel_t* r, 
-        uint32_t factor, const pixel_t* src, const pixel_t* dst)
-{
-    switch (factor) {
-        case GGL_ZERO:
-            r->c[1] = 
-            r->c[2] = 
-            r->c[3] = 
-            r->c[0] = 0;
-            break;
-        case GGL_ONE:
-            r->c[1] = 
-            r->c[2] = 
-            r->c[3] = 
-            r->c[0] = FIXED_ONE;
-            break;
-        case GGL_DST_COLOR:
-            r->c[1] = blendfactor(dst->c[1], dst->s[1]);
-            r->c[2] = blendfactor(dst->c[2], dst->s[2]);
-            r->c[3] = blendfactor(dst->c[3], dst->s[3]);
-            r->c[0] = blendfactor(dst->c[0], dst->s[0]);
-            break;
-        case GGL_SRC_COLOR:
-            r->c[1] = blendfactor(src->c[1], src->s[1]);
-            r->c[2] = blendfactor(src->c[2], src->s[2]);
-            r->c[3] = blendfactor(src->c[3], src->s[3]);
-            r->c[0] = blendfactor(src->c[0], src->s[0]);
-            break;
-        case GGL_ONE_MINUS_DST_COLOR:
-            r->c[1] = FIXED_ONE - blendfactor(dst->c[1], dst->s[1]);
-            r->c[2] = FIXED_ONE - blendfactor(dst->c[2], dst->s[2]);
-            r->c[3] = FIXED_ONE - blendfactor(dst->c[3], dst->s[3]);
-            r->c[0] = FIXED_ONE - blendfactor(dst->c[0], dst->s[0]);
-            break;
-        case GGL_ONE_MINUS_SRC_COLOR:
-            r->c[1] = FIXED_ONE - blendfactor(src->c[1], src->s[1]);
-            r->c[2] = FIXED_ONE - blendfactor(src->c[2], src->s[2]);
-            r->c[3] = FIXED_ONE - blendfactor(src->c[3], src->s[3]);
-            r->c[0] = FIXED_ONE - blendfactor(src->c[0], src->s[0]);
-            break;
-        case GGL_SRC_ALPHA:
-            r->c[1] = 
-            r->c[2] = 
-            r->c[3] = 
-            r->c[0] = blendfactor(src->c[0], src->s[0], FIXED_ONE);
-            break;
-        case GGL_ONE_MINUS_SRC_ALPHA:
-            r->c[1] = 
-            r->c[2] = 
-            r->c[3] = 
-            r->c[0] = FIXED_ONE - blendfactor(src->c[0], src->s[0], FIXED_ONE);
-            break;
-        case GGL_DST_ALPHA:
-            r->c[1] = 
-            r->c[2] = 
-            r->c[3] = 
-            r->c[0] = blendfactor(dst->c[0], dst->s[0], FIXED_ONE);
-            break;
-        case GGL_ONE_MINUS_DST_ALPHA:
-            r->c[1] = 
-            r->c[2] = 
-            r->c[3] = 
-            r->c[0] = FIXED_ONE - blendfactor(dst->c[0], dst->s[0], FIXED_ONE);
-            break;
-        case GGL_SRC_ALPHA_SATURATE:
-            // XXX: GGL_SRC_ALPHA_SATURATE
-            break;
-    }
-}
-
-static GGLfixed wrapping(int32_t coord, uint32_t size, int tx_wrap)
-{
-    GGLfixed d;
-    if (tx_wrap == GGL_REPEAT) {
-        d = (uint32_t(coord)>>16) * size;
-    } else if (tx_wrap == GGL_CLAMP) { // CLAMP_TO_EDGE semantics
-        const GGLfixed clamp_min = FIXED_HALF;
-        const GGLfixed clamp_max = (size << 16) - FIXED_HALF;
-        if (coord < clamp_min)     coord = clamp_min;
-        if (coord > clamp_max)     coord = clamp_max;
-        d = coord;
-    } else { // 1:1
-        const GGLfixed clamp_min = 0;
-        const GGLfixed clamp_max = (size << 16);
-        if (coord < clamp_min)     coord = clamp_min;
-        if (coord > clamp_max)     coord = clamp_max;
-        d = coord;
-    }
-    return d;
-}
-
-static inline
-GGLcolor ADJUST_COLOR_ITERATOR(GGLcolor v, GGLcolor dvdx, int len)
-{
-    const int32_t end = dvdx * (len-1) + v;
-    if (end < 0)
-        v -= end;
-    v &= ~(v>>31);
-    return v;
-}
-
-void scanline(context_t* c)
-{
-    const uint32_t enables = c->state.enables;
-    const int xs = c->iterators.xl;
-    const int x1 = c->iterators.xr;
-	int xc = x1 - xs;
-    const int16_t* covPtr = c->state.buffers.coverage + xs;
-
-    // All iterated values are sampled at the pixel center
-
-    // reset iterators for that scanline...
-    GGLcolor r, g, b, a;
-    iterators_t& ci = c->iterators;
-    if (enables & GGL_ENABLE_SMOOTH) {
-        r = (xs * c->shade.drdx) + ci.ydrdy;
-        g = (xs * c->shade.dgdx) + ci.ydgdy;
-        b = (xs * c->shade.dbdx) + ci.ydbdy;
-        a = (xs * c->shade.dadx) + ci.ydady;
-        r = ADJUST_COLOR_ITERATOR(r, c->shade.drdx, xc);
-        g = ADJUST_COLOR_ITERATOR(g, c->shade.dgdx, xc);
-        b = ADJUST_COLOR_ITERATOR(b, c->shade.dbdx, xc);
-        a = ADJUST_COLOR_ITERATOR(a, c->shade.dadx, xc);
-    } else {
-        r = ci.ydrdy;
-        g = ci.ydgdy;
-        b = ci.ydbdy;
-        a = ci.ydady;
-    }
-
-    // z iterators are 1.31
-    GGLfixed z = (xs * c->shade.dzdx) + ci.ydzdy;
-    GGLfixed f = (xs * c->shade.dfdx) + ci.ydfdy;
-
-    struct {
-        GGLfixed s, t;
-    } tc[GGL_TEXTURE_UNIT_COUNT];
-    if (enables & GGL_ENABLE_TMUS) {
-        for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
-            if (c->state.texture[i].enable) {
-                texture_iterators_t& ti = c->state.texture[i].iterators;
-                if (enables & GGL_ENABLE_W) {
-                    tc[i].s = ti.ydsdy;
-                    tc[i].t = ti.ydtdy;
-                } else {
-                    tc[i].s = (xs * ti.dsdx) + ti.ydsdy;
-                    tc[i].t = (xs * ti.dtdx) + ti.ydtdy;
-                }
-            }
-        }
-    }
-
-    pixel_t fragment;
-    pixel_t texel;
-    pixel_t fb;
-
-	uint32_t x = xs;
-	uint32_t y = c->iterators.y;
-
-	while (xc--) {
-    
-        { // just a scope
-
-		// read color (convert to 8 bits by keeping only the integer part)
-        fragment.s[1] = fragment.s[2] =
-        fragment.s[3] = fragment.s[0] = 8;
-        fragment.c[1] = r >> (GGL_COLOR_BITS-8);
-        fragment.c[2] = g >> (GGL_COLOR_BITS-8);
-        fragment.c[3] = b >> (GGL_COLOR_BITS-8);
-        fragment.c[0] = a >> (GGL_COLOR_BITS-8);
-
-		// texturing
-        if (enables & GGL_ENABLE_TMUS) {
-            for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
-                texture_t& tx = c->state.texture[i];
-                if (!tx.enable)
-                    continue;
-                texture_iterators_t& ti = tx.iterators;
-                int32_t u, v;
-
-                // s-coordinate
-                if (tx.s_coord != GGL_ONE_TO_ONE) {
-                    const int w = tx.surface.width;
-                    u = wrapping(tc[i].s, w, tx.s_wrap);
-                    tc[i].s += ti.dsdx;
-                } else {
-                    u = (((tx.shade.is0>>16) + x)<<16) + FIXED_HALF;
-                }
-
-                // t-coordinate
-                if (tx.t_coord != GGL_ONE_TO_ONE) {
-                    const int h = tx.surface.height;
-                    v = wrapping(tc[i].t, h, tx.t_wrap);
-                    tc[i].t += ti.dtdx;
-                } else {
-                    v = (((tx.shade.it0>>16) + y)<<16) + FIXED_HALF;
-                }
-
-                // read texture
-                if (tx.mag_filter == GGL_NEAREST &&
-                    tx.min_filter == GGL_NEAREST)
-                {
-                    u >>= 16;
-                    v >>= 16;
-                    tx.surface.read(&tx.surface, c, u, v, &texel);
-                } else {
-                    const int w = tx.surface.width;
-                    const int h = tx.surface.height;
-                    u -= FIXED_HALF;
-                    v -= FIXED_HALF;
-                    int u0 = u >> 16;
-                    int v0 = v >> 16;
-                    int u1 = u0 + 1;
-                    int v1 = v0 + 1;
-                    if (tx.s_wrap == GGL_REPEAT) {
-                        if (u0<0)  u0 += w;
-                        if (u1<0)  u1 += w;
-                        if (u0>=w) u0 -= w;
-                        if (u1>=w) u1 -= w;
-                    } else {
-                        if (u0<0)  u0 = 0;
-                        if (u1<0)  u1 = 0;
-                        if (u0>=w) u0 = w-1;
-                        if (u1>=w) u1 = w-1;
-                    }
-                    if (tx.t_wrap == GGL_REPEAT) {
-                        if (v0<0)  v0 += h;
-                        if (v1<0)  v1 += h;
-                        if (v0>=h) v0 -= h;
-                        if (v1>=h) v1 -= h;
-                    } else {
-                        if (v0<0)  v0 = 0;
-                        if (v1<0)  v1 = 0;
-                        if (v0>=h) v0 = h-1;
-                        if (v1>=h) v1 = h-1;
-                    }
-                    pixel_t texels[4];
-                    uint32_t mm[4];
-                    tx.surface.read(&tx.surface, c, u0, v0, &texels[0]);
-                    tx.surface.read(&tx.surface, c, u0, v1, &texels[1]);
-                    tx.surface.read(&tx.surface, c, u1, v0, &texels[2]);
-                    tx.surface.read(&tx.surface, c, u1, v1, &texels[3]);
-                    u = (u >> 12) & 0xF; 
-                    v = (v >> 12) & 0xF;
-                    u += u>>3;
-                    v += v>>3;
-                    mm[0] = (0x10 - u) * (0x10 - v);
-                    mm[1] = (0x10 - u) * v;
-                    mm[2] = u * (0x10 - v);
-                    mm[3] = 0x100 - (mm[0] + mm[1] + mm[2]);
-                    for (int j=0 ; j<4 ; j++) {
-                        texel.s[j] = texels[0].s[j];
-                        if (!texel.s[j]) continue;
-                        texel.s[j] += 8;
-                        texel.c[j] =    texels[0].c[j]*mm[0] +
-                                        texels[1].c[j]*mm[1] +
-                                        texels[2].c[j]*mm[2] +
-                                        texels[3].c[j]*mm[3] ;
-                    }
-                }
-
-                // Texture environnement...
-                for (int j=0 ; j<4 ; j++) {
-                    uint32_t& Cf = fragment.c[j];
-                    uint32_t& Ct = texel.c[j];
-                    uint8_t& sf  = fragment.s[j];
-                    uint8_t& st  = texel.s[j];
-                    uint32_t At = texel.c[0];
-                    uint8_t sat = texel.s[0];
-                    switch (tx.env) {
-                    case GGL_REPLACE:
-                        if (st) {
-                            Cf = Ct;
-                            sf = st;
-                        }
-                        break;
-                    case GGL_MODULATE:
-                        if (st) {
-                            uint32_t factor = Ct + (Ct>>(st-1));
-                            Cf = (Cf * factor) >> st;
-                        }
-                        break;
-                    case GGL_DECAL:
-                        if (sat) {
-                            rescale(Cf, sf, Ct, st);
-                            Cf += ((Ct - Cf) * (At + (At>>(sat-1)))) >> sat;
-                        }
-                        break;
-                    case GGL_BLEND:
-                        if (st) {
-                            uint32_t Cc = tx.env_color[i];
-                            if (sf>8)       Cc = (Cc * ((1<<sf)-1))>>8;
-                            else if (sf<8)  Cc = (Cc - (Cc>>(8-sf)))>>(8-sf);
-                            uint32_t factor = Ct + (Ct>>(st-1));
-                            Cf = ((((1<<st) - factor) * Cf) + Ct*Cc)>>st;
-                        }
-                        break;
-                    case GGL_ADD:
-                        if (st) {
-                            rescale(Cf, sf, Ct, st);
-                            Cf += Ct;
-                        }
-                        break;
-                    }
-                }
-            }
-		}
-    
-        // coverage application
-        if (enables & GGL_ENABLE_AA) {
-            int16_t cf = *covPtr++;
-            fragment.c[0] = (int64_t(fragment.c[0]) * cf) >> 15;
-        }
-        
-        // alpha-test
-        if (enables & GGL_ENABLE_ALPHA_TEST) {
-            GGLcolor ref = c->state.alpha_test.ref;
-            GGLcolor alpha = (uint64_t(fragment.c[0]) *
-                    ((1<<GGL_COLOR_BITS)-1)) / ((1<<fragment.s[0])-1);
-            switch (c->state.alpha_test.func) {
-            case GGL_NEVER:     goto discard;
-            case GGL_LESS:      if (alpha<ref)  break; goto discard;
-            case GGL_EQUAL:     if (alpha==ref) break; goto discard;
-            case GGL_LEQUAL:    if (alpha<=ref) break; goto discard;
-            case GGL_GREATER:   if (alpha>ref)  break; goto discard;
-            case GGL_NOTEQUAL:  if (alpha!=ref) break; goto discard;
-            case GGL_GEQUAL:    if (alpha>=ref) break; goto discard;
-            }
-        }
-        
-        // depth test
-        if (c->state.buffers.depth.format) {
-            if (enables & GGL_ENABLE_DEPTH_TEST) {
-                surface_t* cb = &(c->state.buffers.depth);
-                uint16_t* p = (uint16_t*)(cb->data)+(x+(cb->stride*y));
-                uint16_t zz = uint32_t(z)>>(16);
-                uint16_t depth = *p;
-                switch (c->state.depth_test.func) {
-                case GGL_NEVER:     goto discard;
-                case GGL_LESS:      if (zz<depth)    break; goto discard;
-                case GGL_EQUAL:     if (zz==depth)   break; goto discard;
-                case GGL_LEQUAL:    if (zz<=depth)   break; goto discard;
-                case GGL_GREATER:   if (zz>depth)    break; goto discard;
-                case GGL_NOTEQUAL:  if (zz!=depth)   break; goto discard;
-                case GGL_GEQUAL:    if (zz>=depth)   break; goto discard;
-                }
-                // depth buffer is not enabled, if depth-test is not enabled
-/*
-        fragment.s[1] = fragment.s[2] =
-        fragment.s[3] = fragment.s[0] = 8;
-        fragment.c[1] = 
-        fragment.c[2] = 
-        fragment.c[3] = 
-        fragment.c[0] = 255 - (zz>>8);
-*/
-                if (c->state.mask.depth) {
-                    *p = zz;
-                }
-            }
-        }
-
-        // fog
-        if (enables & GGL_ENABLE_FOG) {
-            for (int i=1 ; i<=3 ; i++) {
-                GGLfixed fc = (c->state.fog.color[i] * 0x10000) / 0xFF;
-                uint32_t& c = fragment.c[i];
-                uint8_t& s  = fragment.s[i];
-                c = (c * 0x10000) / ((1<<s)-1);
-                c = gglMulAddx(c, f, gglMulx(fc, 0x10000 - f));
-                s = 16;
-            }
-        }
-
-        // blending
-        if (enables & GGL_ENABLE_BLENDING) {
-            fb.c[1] = fb.c[2] = fb.c[3] = fb.c[0] = 0; // placate valgrind
-            fb.s[1] = fb.s[2] = fb.s[3] = fb.s[0] = 0;
-            c->state.buffers.color.read(
-                    &(c->state.buffers.color), c, x, y, &fb);
-            blending( c, &fragment, &fb );
-        }
-
-		// write
-        c->state.buffers.color.write(
-                &(c->state.buffers.color), c, x, y, &fragment);
-        }
-
-discard:
-		// iterate...
-        x += 1;
-        if (enables & GGL_ENABLE_SMOOTH) {
-            r += c->shade.drdx;
-            g += c->shade.dgdx;
-            b += c->shade.dbdx;
-            a += c->shade.dadx;
-        }
-        z += c->shade.dzdx;
-        f += c->shade.dfdx;
-	}
-}
-
-#endif // ANDROID_ARM_CODEGEN && (ANDROID_CODEGEN == ANDROID_CODEGEN_GENERATED)
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Scanline
-#endif
-
-/* Used to parse a 32-bit source texture linearly. Usage is:
- *
- * horz_iterator32  hi(context);
- * while (...) {
- *    uint32_t  src_pixel = hi.get_pixel32();
- *    ...
- * }
- *
- * Use only for one-to-one texture mapping.
- */
-struct horz_iterator32 {
-    explicit horz_iterator32(context_t* c) {
-        const int x = c->iterators.xl;
-        const int y = c->iterators.y;
-        texture_t& tx = c->state.texture[0];
-        const int32_t u = (tx.shade.is0>>16) + x;
-        const int32_t v = (tx.shade.it0>>16) + y;
-        m_src = reinterpret_cast<uint32_t*>(tx.surface.data)+(u+(tx.surface.stride*v));
-    }
-    uint32_t  get_pixel32() {
-        return *m_src++;
-    }
-protected:
-    uint32_t* m_src;
-};
-
-/* A variant for 16-bit source textures. */
-struct horz_iterator16 {
-    explicit horz_iterator16(context_t* c) {
-        const int x = c->iterators.xl;
-        const int y = c->iterators.y;
-        texture_t& tx = c->state.texture[0];
-        const int32_t u = (tx.shade.is0>>16) + x;
-        const int32_t v = (tx.shade.it0>>16) + y;
-        m_src = reinterpret_cast<uint16_t*>(tx.surface.data)+(u+(tx.surface.stride*v));
-    }
-    uint16_t  get_pixel16() {
-        return *m_src++;
-    }
-protected:
-    uint16_t* m_src;
-};
-
-/* A clamp iterator is used to iterate inside a texture with GGL_CLAMP.
- * After initialization, call get_src16() or get_src32() to get the current
- * texture pixel value.
- */
-struct clamp_iterator {
-    explicit clamp_iterator(context_t* c) {
-        const int xs = c->iterators.xl;
-        texture_t& tx = c->state.texture[0];
-        texture_iterators_t& ti = tx.iterators;
-        m_s = (xs * ti.dsdx) + ti.ydsdy;
-        m_t = (xs * ti.dtdx) + ti.ydtdy;
-        m_ds = ti.dsdx;
-        m_dt = ti.dtdx;
-        m_width_m1 = tx.surface.width - 1;
-        m_height_m1 = tx.surface.height - 1;
-        m_data = tx.surface.data;
-        m_stride = tx.surface.stride;
-    }
-    uint16_t get_pixel16() {
-        int  u, v;
-        get_uv(u, v);
-        uint16_t* src = reinterpret_cast<uint16_t*>(m_data) + (u + (m_stride*v));
-        return src[0];
-    }
-    uint32_t get_pixel32() {
-        int  u, v;
-        get_uv(u, v);
-        uint32_t* src = reinterpret_cast<uint32_t*>(m_data) + (u + (m_stride*v));
-        return src[0];
-    }
-private:
-    void   get_uv(int& u, int& v) {
-        int  uu = m_s >> 16;
-        int  vv = m_t >> 16;
-        if (uu < 0)
-            uu = 0;
-        if (uu > m_width_m1)
-            uu = m_width_m1;
-        if (vv < 0)
-            vv = 0;
-        if (vv > m_height_m1)
-            vv = m_height_m1;
-        u = uu;
-        v = vv;
-        m_s += m_ds;
-        m_t += m_dt;
-    }
-
-    GGLfixed  m_s, m_t;
-    GGLfixed  m_ds, m_dt;
-    int       m_width_m1, m_height_m1;
-    uint8_t*  m_data;
-    int       m_stride;
-};
-
-/*
- * The 'horizontal clamp iterator' variant corresponds to the case where
- * the 'v' coordinate doesn't change. This is useful to avoid one mult and
- * extra adds / checks per pixels, if the blending/processing operation after
- * this is very fast.
- */
-static int is_context_horizontal(const context_t* c) {
-    return (c->state.texture[0].iterators.dtdx == 0);
-}
-
-struct horz_clamp_iterator {
-    uint16_t  get_pixel16() {
-        int  u = m_s >> 16;
-        m_s += m_ds;
-        if (u < 0)
-            u = 0;
-        if (u > m_width_m1)
-            u = m_width_m1;
-        const uint16_t* src = reinterpret_cast<const uint16_t*>(m_data);
-        return src[u];
-    }
-    uint32_t  get_pixel32() {
-        int  u = m_s >> 16;
-        m_s += m_ds;
-        if (u < 0)
-            u = 0;
-        if (u > m_width_m1)
-            u = m_width_m1;
-        const uint32_t* src = reinterpret_cast<const uint32_t*>(m_data);
-        return src[u];
-    }
-protected:
-    void init(const context_t* c, int shift);
-    GGLfixed       m_s;
-    GGLfixed       m_ds;
-    int            m_width_m1;
-    const uint8_t* m_data;
-};
-
-void horz_clamp_iterator::init(const context_t* c, int shift)
-{
-    const int xs = c->iterators.xl;
-    const texture_t& tx = c->state.texture[0];
-    const texture_iterators_t& ti = tx.iterators;
-    m_s = (xs * ti.dsdx) + ti.ydsdy;
-    m_ds = ti.dsdx;
-    m_width_m1 = tx.surface.width-1;
-    m_data = tx.surface.data;
-
-    GGLfixed t = (xs * ti.dtdx) + ti.ydtdy;
-    int      v = t >> 16;
-    if (v < 0)
-        v = 0;
-    else if (v >= (int)tx.surface.height)
-        v = (int)tx.surface.height-1;
-
-    m_data += (tx.surface.stride*v) << shift;
-}
-
-struct horz_clamp_iterator16 : horz_clamp_iterator {
-    explicit horz_clamp_iterator16(const context_t* c) {
-        init(c,1);
-    };
-};
-
-struct horz_clamp_iterator32 : horz_clamp_iterator {
-    explicit horz_clamp_iterator32(context_t* c) {
-        init(c,2);
-    };
-};
-
-/* This is used to perform dithering operations.
- */
-struct ditherer {
-    explicit ditherer(const context_t* c) {
-        const int x = c->iterators.xl;
-        const int y = c->iterators.y;
-        m_line = &c->ditherMatrix[ ((y & GGL_DITHER_MASK)<<GGL_DITHER_ORDER_SHIFT) ];
-        m_index = x & GGL_DITHER_MASK;
-    }
-    void step(void) {
-        m_index++;
-    }
-    int  get_value(void) {
-        int ret = m_line[m_index & GGL_DITHER_MASK];
-        m_index++;
-        return ret;
-    }
-    uint16_t abgr8888ToRgb565(uint32_t s) {
-        uint32_t r = s & 0xff;
-        uint32_t g = (s >> 8) & 0xff;
-        uint32_t b = (s >> 16) & 0xff;
-        return rgb888ToRgb565(r,g,b);
-    }
-    /* The following assumes that r/g/b are in the 0..255 range each */
-    uint16_t rgb888ToRgb565(uint32_t& r, uint32_t& g, uint32_t &b) {
-        int threshold = get_value();
-        /* dither in on GGL_DITHER_BITS, and each of r, g, b is on 8 bits */
-        r += (threshold >> (GGL_DITHER_BITS-8 +5));
-        g += (threshold >> (GGL_DITHER_BITS-8 +6));
-        b += (threshold >> (GGL_DITHER_BITS-8 +5));
-        if (r > 0xff)
-            r = 0xff;
-        if (g > 0xff)
-            g = 0xff;
-        if (b > 0xff)
-            b = 0xff;
-        return uint16_t(((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3));
-    }
-protected:
-    const uint8_t* m_line;
-    int            m_index;
-};
-
-/* This structure is used to blend (SRC_OVER) 32-bit source pixels
- * onto 16-bit destination ones. Usage is simply:
- *
- *   blender.blend(<32-bit-src-pixel-value>,<ptr-to-16-bit-dest-pixel>)
- */
-struct blender_32to16 {
-    explicit blender_32to16(context_t* /*c*/) { }
-    void write(uint32_t s, uint16_t* dst) {
-        if (s == 0)
-            return;
-        s = GGL_RGBA_TO_HOST(s);
-        int sA = (s>>24);
-        if (sA == 0xff) {
-            *dst = convertAbgr8888ToRgb565(s);
-        } else {
-            int f = 0x100 - (sA + (sA>>7));
-            int sR = (s >> (   3))&0x1F;
-            int sG = (s >> ( 8+2))&0x3F;
-            int sB = (s >> (16+3))&0x1F;
-            uint16_t d = *dst;
-            int dR = (d>>11)&0x1f;
-            int dG = (d>>5)&0x3f;
-            int dB = (d)&0x1f;
-            sR += (f*dR)>>8;
-            sG += (f*dG)>>8;
-            sB += (f*dB)>>8;
-            *dst = uint16_t((sR<<11)|(sG<<5)|sB);
-        }
-    }
-    void write(uint32_t s, uint16_t* dst, ditherer& di) {
-        if (s == 0) {
-            di.step();
-            return;
-        }
-        s = GGL_RGBA_TO_HOST(s);
-        int sA = (s>>24);
-        if (sA == 0xff) {
-            *dst = di.abgr8888ToRgb565(s);
-        } else {
-            int threshold = di.get_value() << (8 - GGL_DITHER_BITS);
-            int f = 0x100 - (sA + (sA>>7));
-            int sR = (s >> (   3))&0x1F;
-            int sG = (s >> ( 8+2))&0x3F;
-            int sB = (s >> (16+3))&0x1F;
-            uint16_t d = *dst;
-            int dR = (d>>11)&0x1f;
-            int dG = (d>>5)&0x3f;
-            int dB = (d)&0x1f;
-            sR = ((sR << 8) + f*dR + threshold)>>8;
-            sG = ((sG << 8) + f*dG + threshold)>>8;
-            sB = ((sB << 8) + f*dB + threshold)>>8;
-            if (sR > 0x1f) sR = 0x1f;
-            if (sG > 0x3f) sG = 0x3f;
-            if (sB > 0x1f) sB = 0x1f;
-            *dst = uint16_t((sR<<11)|(sG<<5)|sB);
-        }
-    }
-};
-
-/* This blender does the same for the 'blend_srca' operation.
- * where dstFactor=srcA*(1-srcA) srcFactor=srcA
- */
-struct blender_32to16_srcA {
-    explicit blender_32to16_srcA(const context_t* /*c*/) { }
-    void write(uint32_t s, uint16_t* dst) {
-        if (!s) {
-            return;
-        }
-        uint16_t d = *dst;
-        s = GGL_RGBA_TO_HOST(s);
-        int sR = (s >> (   3))&0x1F;
-        int sG = (s >> ( 8+2))&0x3F;
-        int sB = (s >> (16+3))&0x1F;
-        int sA = (s>>24);
-        int f1 = (sA + (sA>>7));
-        int f2 = 0x100-f1;
-        int dR = (d>>11)&0x1f;
-        int dG = (d>>5)&0x3f;
-        int dB = (d)&0x1f;
-        sR = (f1*sR + f2*dR)>>8;
-        sG = (f1*sG + f2*dG)>>8;
-        sB = (f1*sB + f2*dB)>>8;
-        *dst = uint16_t((sR<<11)|(sG<<5)|sB);
-    }
-};
-
-/* Common init code the modulating blenders */
-struct blender_modulate {
-    void init(const context_t* c) {
-        const int r = c->iterators.ydrdy >> (GGL_COLOR_BITS-8);
-        const int g = c->iterators.ydgdy >> (GGL_COLOR_BITS-8);
-        const int b = c->iterators.ydbdy >> (GGL_COLOR_BITS-8);
-        const int a = c->iterators.ydady >> (GGL_COLOR_BITS-8);
-        m_r = r + (r >> 7);
-        m_g = g + (g >> 7);
-        m_b = b + (b >> 7);
-        m_a = a + (a >> 7);
-    }
-protected:
-    int m_r, m_g, m_b, m_a;
-};
-
-/* This blender does a normal blend after modulation.
- */
-struct blender_32to16_modulate : blender_modulate {
-    explicit blender_32to16_modulate(const context_t* c) {
-        init(c);
-    }
-    void write(uint32_t s, uint16_t* dst) {
-        // blend source and destination
-        if (!s) {
-            return;
-        }
-        s = GGL_RGBA_TO_HOST(s);
-
-        /* We need to modulate s */
-        uint32_t  sA = (s >> 24);
-        uint32_t  sB = (s >> 16) & 0xff;
-        uint32_t  sG = (s >> 8) & 0xff;
-        uint32_t  sR = s & 0xff;
-
-        sA = (sA*m_a) >> 8;
-        /* Keep R/G/B scaled to 5.8 or 6.8 fixed float format */
-        sR = (sR*m_r) >> (8 - 5);
-        sG = (sG*m_g) >> (8 - 6);
-        sB = (sB*m_b) >> (8 - 5);
-
-        /* Now do a normal blend */
-        int f = 0x100 - (sA + (sA>>7));
-        uint16_t d = *dst;
-        int dR = (d>>11)&0x1f;
-        int dG = (d>>5)&0x3f;
-        int dB = (d)&0x1f;
-        sR = (sR + f*dR)>>8;
-        sG = (sG + f*dG)>>8;
-        sB = (sB + f*dB)>>8;
-        *dst = uint16_t((sR<<11)|(sG<<5)|sB);
-    }
-    void write(uint32_t s, uint16_t* dst, ditherer& di) {
-        // blend source and destination
-        if (!s) {
-            di.step();
-            return;
-        }
-        s = GGL_RGBA_TO_HOST(s);
-
-        /* We need to modulate s */
-        uint32_t  sA = (s >> 24);
-        uint32_t  sB = (s >> 16) & 0xff;
-        uint32_t  sG = (s >> 8) & 0xff;
-        uint32_t  sR = s & 0xff;
-
-        sA = (sA*m_a) >> 8;
-        /* keep R/G/B scaled to 5.8 or 6.8 fixed float format */
-        sR = (sR*m_r) >> (8 - 5);
-        sG = (sG*m_g) >> (8 - 6);
-        sB = (sB*m_b) >> (8 - 5);
-
-        /* Scale threshold to 0.8 fixed float format */
-        int threshold = di.get_value() << (8 - GGL_DITHER_BITS);
-        int f = 0x100 - (sA + (sA>>7));
-        uint16_t d = *dst;
-        int dR = (d>>11)&0x1f;
-        int dG = (d>>5)&0x3f;
-        int dB = (d)&0x1f;
-        sR = (sR + f*dR + threshold)>>8;
-        sG = (sG + f*dG + threshold)>>8;
-        sB = (sB + f*dB + threshold)>>8;
-        if (sR > 0x1f) sR = 0x1f;
-        if (sG > 0x3f) sG = 0x3f;
-        if (sB > 0x1f) sB = 0x1f;
-        *dst = uint16_t((sR<<11)|(sG<<5)|sB);
-    }
-};
-
-/* same as 32to16_modulate, except that the input is xRGB, instead of ARGB */
-struct blender_x32to16_modulate : blender_modulate {
-    explicit blender_x32to16_modulate(const context_t* c) {
-        init(c);
-    }
-    void write(uint32_t s, uint16_t* dst) {
-        s = GGL_RGBA_TO_HOST(s);
-
-        uint32_t  sB = (s >> 16) & 0xff;
-        uint32_t  sG = (s >> 8) & 0xff;
-        uint32_t  sR = s & 0xff;
-
-        /* Keep R/G/B in 5.8 or 6.8 format */
-        sR = (sR*m_r) >> (8 - 5);
-        sG = (sG*m_g) >> (8 - 6);
-        sB = (sB*m_b) >> (8 - 5);
-
-        int f = 0x100 - m_a;
-        uint16_t d = *dst;
-        int dR = (d>>11)&0x1f;
-        int dG = (d>>5)&0x3f;
-        int dB = (d)&0x1f;
-        sR = (sR + f*dR)>>8;
-        sG = (sG + f*dG)>>8;
-        sB = (sB + f*dB)>>8;
-        *dst = uint16_t((sR<<11)|(sG<<5)|sB);
-    }
-    void write(uint32_t s, uint16_t* dst, ditherer& di) {
-        s = GGL_RGBA_TO_HOST(s);
-
-        uint32_t  sB = (s >> 16) & 0xff;
-        uint32_t  sG = (s >> 8) & 0xff;
-        uint32_t  sR = s & 0xff;
-
-        sR = (sR*m_r) >> (8 - 5);
-        sG = (sG*m_g) >> (8 - 6);
-        sB = (sB*m_b) >> (8 - 5);
-
-        /* Now do a normal blend */
-        int threshold = di.get_value() << (8 - GGL_DITHER_BITS);
-        int f = 0x100 - m_a;
-        uint16_t d = *dst;
-        int dR = (d>>11)&0x1f;
-        int dG = (d>>5)&0x3f;
-        int dB = (d)&0x1f;
-        sR = (sR + f*dR + threshold)>>8;
-        sG = (sG + f*dG + threshold)>>8;
-        sB = (sB + f*dB + threshold)>>8;
-        if (sR > 0x1f) sR = 0x1f;
-        if (sG > 0x3f) sG = 0x3f;
-        if (sB > 0x1f) sB = 0x1f;
-        *dst = uint16_t((sR<<11)|(sG<<5)|sB);
-    }
-};
-
-/* Same as above, but source is 16bit rgb565 */
-struct blender_16to16_modulate : blender_modulate {
-    explicit blender_16to16_modulate(const context_t* c) {
-        init(c);
-    }
-    void write(uint16_t s16, uint16_t* dst) {
-        uint32_t  s = s16;
-
-        uint32_t  sR = s >> 11;
-        uint32_t  sG = (s >> 5) & 0x3f;
-        uint32_t  sB = s & 0x1f;
-
-        sR = (sR*m_r);
-        sG = (sG*m_g);
-        sB = (sB*m_b);
-
-        int f = 0x100 - m_a;
-        uint16_t d = *dst;
-        int dR = (d>>11)&0x1f;
-        int dG = (d>>5)&0x3f;
-        int dB = (d)&0x1f;
-        sR = (sR + f*dR)>>8;
-        sG = (sG + f*dG)>>8;
-        sB = (sB + f*dB)>>8;
-        *dst = uint16_t((sR<<11)|(sG<<5)|sB);
-    }
-};
-
-/* This is used to iterate over a 16-bit destination color buffer.
- * Usage is:
- *
- *   dst_iterator16  di(context);
- *   while (di.count--) {
- *       <do stuff with dest pixel at di.dst>
- *       di.dst++;
- *   }
- */
-struct dst_iterator16 {
-    explicit dst_iterator16(const context_t* c) {
-        const int x = c->iterators.xl;
-        const int width = c->iterators.xr - x;
-        const int32_t y = c->iterators.y;
-        const surface_t* cb = &(c->state.buffers.color);
-        count = width;
-        dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
-    }
-    int        count;
-    uint16_t*  dst;
-};
-
-
-static void scanline_t32cb16_clamp(context_t* c)
-{
-    dst_iterator16  di(c);
-
-    if (is_context_horizontal(c)) {
-        /* Special case for simple horizontal scaling */
-        horz_clamp_iterator32 ci(c);
-        while (di.count--) {
-            uint32_t s = ci.get_pixel32();
-            *di.dst++ = convertAbgr8888ToRgb565(s);
-        }
-    } else {
-        /* General case */
-        clamp_iterator ci(c);
-        while (di.count--) {
-            uint32_t s = ci.get_pixel32();
-            *di.dst++ = convertAbgr8888ToRgb565(s);
-        }
-    }
-}
-
-static void scanline_t32cb16_dither(context_t* c)
-{
-    horz_iterator32 si(c);
-    dst_iterator16  di(c);
-    ditherer        dither(c);
-
-    while (di.count--) {
-        uint32_t s = si.get_pixel32();
-        *di.dst++ = dither.abgr8888ToRgb565(s);
-    }
-}
-
-static void scanline_t32cb16_clamp_dither(context_t* c)
-{
-    dst_iterator16  di(c);
-    ditherer        dither(c);
-
-    if (is_context_horizontal(c)) {
-        /* Special case for simple horizontal scaling */
-        horz_clamp_iterator32 ci(c);
-        while (di.count--) {
-            uint32_t s = ci.get_pixel32();
-            *di.dst++ = dither.abgr8888ToRgb565(s);
-        }
-    } else {
-        /* General case */
-        clamp_iterator ci(c);
-        while (di.count--) {
-            uint32_t s = ci.get_pixel32();
-            *di.dst++ = dither.abgr8888ToRgb565(s);
-        }
-    }
-}
-
-static void scanline_t32cb16blend_dither(context_t* c)
-{
-    dst_iterator16 di(c);
-    ditherer       dither(c);
-    blender_32to16 bl(c);
-    horz_iterator32  hi(c);
-    while (di.count--) {
-        uint32_t s = hi.get_pixel32();
-        bl.write(s, di.dst, dither);
-        di.dst++;
-    }
-}
-
-static void scanline_t32cb16blend_clamp(context_t* c)
-{
-    dst_iterator16  di(c);
-    blender_32to16  bl(c);
-
-    if (is_context_horizontal(c)) {
-        horz_clamp_iterator32 ci(c);
-        while (di.count--) {
-            uint32_t s = ci.get_pixel32();
-            bl.write(s, di.dst);
-            di.dst++;
-        }
-    } else {
-        clamp_iterator ci(c);
-        while (di.count--) {
-            uint32_t s = ci.get_pixel32();
-            bl.write(s, di.dst);
-            di.dst++;
-        }
-    }
-}
-
-static void scanline_t32cb16blend_clamp_dither(context_t* c)
-{
-    dst_iterator16 di(c);
-    ditherer       dither(c);
-    blender_32to16 bl(c);
-
-    clamp_iterator ci(c);
-    while (di.count--) {
-        uint32_t s = ci.get_pixel32();
-        bl.write(s, di.dst, dither);
-        di.dst++;
-    }
-}
-
-void scanline_t32cb16blend_clamp_mod(context_t* c)
-{
-    dst_iterator16 di(c);
-    blender_32to16_modulate bl(c);
-
-    clamp_iterator ci(c);
-    while (di.count--) {
-        uint32_t s = ci.get_pixel32();
-        bl.write(s, di.dst);
-        di.dst++;
-    }
-}
-
-void scanline_t32cb16blend_clamp_mod_dither(context_t* c)
-{
-    dst_iterator16 di(c);
-    blender_32to16_modulate bl(c);
-    ditherer dither(c);
-
-    clamp_iterator ci(c);
-    while (di.count--) {
-        uint32_t s = ci.get_pixel32();
-        bl.write(s, di.dst, dither);
-        di.dst++;
-    }
-}
-
-/* Variant of scanline_t32cb16blend_clamp_mod with a xRGB texture */
-void scanline_x32cb16blend_clamp_mod(context_t* c)
-{
-    dst_iterator16 di(c);
-    blender_x32to16_modulate  bl(c);
-
-    clamp_iterator ci(c);
-    while (di.count--) {
-        uint32_t s = ci.get_pixel32();
-        bl.write(s, di.dst);
-        di.dst++;
-    }
-}
-
-void scanline_x32cb16blend_clamp_mod_dither(context_t* c)
-{
-    dst_iterator16 di(c);
-    blender_x32to16_modulate  bl(c);
-    ditherer dither(c);
-
-    clamp_iterator ci(c);
-    while (di.count--) {
-        uint32_t s = ci.get_pixel32();
-        bl.write(s, di.dst, dither);
-        di.dst++;
-    }
-}
-
-void scanline_t16cb16_clamp(context_t* c)
-{
-    dst_iterator16  di(c);
-
-    /* Special case for simple horizontal scaling */
-    if (is_context_horizontal(c)) {
-        horz_clamp_iterator16 ci(c);
-        while (di.count--) {
-            *di.dst++ = ci.get_pixel16();
-        }
-    } else {
-        clamp_iterator ci(c);
-        while (di.count--) {
-            *di.dst++ = ci.get_pixel16();
-        }
-    }
-}
-
-
-
-template <typename T, typename U>
-static inline __attribute__((const))
-T interpolate(int y, T v0, U dvdx, U dvdy) {
-    // interpolates in pixel's centers
-    // v = v0 + (y + 0.5) * dvdy + (0.5 * dvdx)
-    return (y * dvdy) + (v0 + ((dvdy + dvdx) >> 1));
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-void init_y(context_t* c, int32_t ys)
-{
-    const uint32_t enables = c->state.enables;
-
-    // compute iterators...
-    iterators_t& ci = c->iterators;
-    
-    // sample in the center
-    ci.y = ys;
-
-    if (enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_W|GGL_ENABLE_FOG)) {
-        ci.ydzdy = interpolate(ys, c->shade.z0, c->shade.dzdx, c->shade.dzdy);
-        ci.ydwdy = interpolate(ys, c->shade.w0, c->shade.dwdx, c->shade.dwdy);
-        ci.ydfdy = interpolate(ys, c->shade.f0, c->shade.dfdx, c->shade.dfdy);
-    }
-
-    if (ggl_unlikely(enables & GGL_ENABLE_SMOOTH)) {
-        ci.ydrdy = interpolate(ys, c->shade.r0, c->shade.drdx, c->shade.drdy);
-        ci.ydgdy = interpolate(ys, c->shade.g0, c->shade.dgdx, c->shade.dgdy);
-        ci.ydbdy = interpolate(ys, c->shade.b0, c->shade.dbdx, c->shade.dbdy);
-        ci.ydady = interpolate(ys, c->shade.a0, c->shade.dadx, c->shade.dady);
-        c->step_y = step_y__smooth;
-    } else {
-        ci.ydrdy = c->shade.r0;
-        ci.ydgdy = c->shade.g0;
-        ci.ydbdy = c->shade.b0;
-        ci.ydady = c->shade.a0;
-        // XXX: do only if needed, or make sure this is fast
-        c->packed = ggl_pack_color(c, c->state.buffers.color.format,
-                ci.ydrdy, ci.ydgdy, ci.ydbdy, ci.ydady);
-        c->packed8888 = ggl_pack_color(c, GGL_PIXEL_FORMAT_RGBA_8888, 
-                ci.ydrdy, ci.ydgdy, ci.ydbdy, ci.ydady);
-    }
-
-    // initialize the variables we need in the shader
-    generated_vars_t& gen = c->generated_vars;
-    gen.argb[GGLFormat::ALPHA].c  = ci.ydady;
-    gen.argb[GGLFormat::ALPHA].dx = c->shade.dadx;
-    gen.argb[GGLFormat::RED  ].c  = ci.ydrdy;
-    gen.argb[GGLFormat::RED  ].dx = c->shade.drdx;
-    gen.argb[GGLFormat::GREEN].c  = ci.ydgdy;
-    gen.argb[GGLFormat::GREEN].dx = c->shade.dgdx;
-    gen.argb[GGLFormat::BLUE ].c  = ci.ydbdy;
-    gen.argb[GGLFormat::BLUE ].dx = c->shade.dbdx;
-    gen.dzdx = c->shade.dzdx;
-    gen.f    = ci.ydfdy;
-    gen.dfdx = c->shade.dfdx;
-
-    if (enables & GGL_ENABLE_TMUS) {
-        for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
-            texture_t& t = c->state.texture[i];
-            if (!t.enable) continue;
-
-            texture_iterators_t& ti = t.iterators;
-            if (t.s_coord == GGL_ONE_TO_ONE && t.t_coord == GGL_ONE_TO_ONE) {
-                // we need to set all of these to 0 because in some cases
-                // step_y__generic() or step_y__tmu() will be used and
-                // therefore will update dtdy, however, in 1:1 mode
-                // this is always done by the scanline rasterizer.
-                ti.dsdx = ti.dsdy = ti.dtdx = ti.dtdy = 0;
-                ti.ydsdy = t.shade.is0;
-                ti.ydtdy = t.shade.it0;
-            } else {
-                const int adjustSWrap = ((t.s_wrap==GGL_CLAMP)?0:16);
-                const int adjustTWrap = ((t.t_wrap==GGL_CLAMP)?0:16);
-                ti.sscale = t.shade.sscale + adjustSWrap;
-                ti.tscale = t.shade.tscale + adjustTWrap;
-                if (!(enables & GGL_ENABLE_W)) {
-                    // S coordinate
-                    const int32_t sscale = ti.sscale;
-                    const int32_t sy = interpolate(ys,
-                            t.shade.is0, t.shade.idsdx, t.shade.idsdy);
-                    if (sscale>=0) {
-                        ti.ydsdy= sy            << sscale;
-                        ti.dsdx = t.shade.idsdx << sscale; 
-                        ti.dsdy = t.shade.idsdy << sscale;
-                    } else {
-                        ti.ydsdy= sy            >> -sscale;
-                        ti.dsdx = t.shade.idsdx >> -sscale; 
-                        ti.dsdy = t.shade.idsdy >> -sscale;
-                    }
-                    // T coordinate
-                    const int32_t tscale = ti.tscale;
-                    const int32_t ty = interpolate(ys,
-                            t.shade.it0, t.shade.idtdx, t.shade.idtdy);
-                    if (tscale>=0) {
-                        ti.ydtdy= ty            << tscale;
-                        ti.dtdx = t.shade.idtdx << tscale; 
-                        ti.dtdy = t.shade.idtdy << tscale;
-                    } else {
-                        ti.ydtdy= ty            >> -tscale;
-                        ti.dtdx = t.shade.idtdx >> -tscale; 
-                        ti.dtdy = t.shade.idtdy >> -tscale;
-                    }
-                }
-            }
-            // mirror for generated code...
-            generated_tex_vars_t& gen = c->generated_vars.texture[i];
-            gen.width   = t.surface.width;
-            gen.height  = t.surface.height;
-            gen.stride  = t.surface.stride;
-            gen.data    = uintptr_t(t.surface.data);
-            gen.dsdx = ti.dsdx;
-            gen.dtdx = ti.dtdx;
-        }
-    }
-
-    // choose the y-stepper
-    c->step_y = step_y__nop;
-    if (enables & GGL_ENABLE_FOG) {
-        c->step_y = step_y__generic;
-    } else if (enables & GGL_ENABLE_TMUS) {
-        if (enables & GGL_ENABLE_SMOOTH) {
-            c->step_y = step_y__generic;
-        } else if (enables & GGL_ENABLE_W) {
-            c->step_y = step_y__w;
-        } else {
-            c->step_y = step_y__tmu;
-        }
-    } else {
-        if (enables & GGL_ENABLE_SMOOTH) {
-            c->step_y = step_y__smooth;
-        }
-    }
-    
-    // choose the rectangle blitter
-    c->rect = rect_generic;
-    if ((c->step_y == step_y__nop) &&
-        (c->scanline == scanline_memcpy))
-    {
-        c->rect = rect_memcpy;
-    }
-}
-
-void init_y_packed(context_t* c, int32_t y0)
-{
-    uint8_t f = c->state.buffers.color.format;
-    c->packed = ggl_pack_color(c, f,
-            c->shade.r0, c->shade.g0, c->shade.b0, c->shade.a0);
-    c->packed8888 = ggl_pack_color(c, GGL_PIXEL_FORMAT_RGBA_8888,
-            c->shade.r0, c->shade.g0, c->shade.b0, c->shade.a0);
-    c->iterators.y = y0;
-    c->step_y = step_y__nop;
-    // choose the rectangle blitter
-    c->rect = rect_generic;
-    if (c->scanline == scanline_memcpy) {
-        c->rect = rect_memcpy;
-    }
-}
-
-void init_y_noop(context_t* c, int32_t y0)
-{
-    c->iterators.y = y0;
-    c->step_y = step_y__nop;
-    // choose the rectangle blitter
-    c->rect = rect_generic;
-    if (c->scanline == scanline_memcpy) {
-        c->rect = rect_memcpy;
-    }
-}
-
-void init_y_error(context_t* c, int32_t y0)
-{
-    // woooops, shoud never happen,
-    // fail gracefully (don't display anything)
-    init_y_noop(c, y0);
-    ALOGE("color-buffer has an invalid format!");
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-void step_y__generic(context_t* c)
-{
-    const uint32_t enables = c->state.enables;
-
-    // iterate...
-    iterators_t& ci = c->iterators;
-    ci.y += 1;
-                
-    if (enables & GGL_ENABLE_SMOOTH) {
-        ci.ydrdy += c->shade.drdy;
-        ci.ydgdy += c->shade.dgdy;
-        ci.ydbdy += c->shade.dbdy;
-        ci.ydady += c->shade.dady;
-    }
-
-    const uint32_t mask =
-            GGL_ENABLE_DEPTH_TEST |
-            GGL_ENABLE_W |
-            GGL_ENABLE_FOG;
-    if (enables & mask) {
-        ci.ydzdy += c->shade.dzdy;
-        ci.ydwdy += c->shade.dwdy;
-        ci.ydfdy += c->shade.dfdy;
-    }
-
-    if ((enables & GGL_ENABLE_TMUS) && (!(enables & GGL_ENABLE_W))) {
-        for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
-            if (c->state.texture[i].enable) {
-                texture_iterators_t& ti = c->state.texture[i].iterators;
-                ti.ydsdy += ti.dsdy;
-                ti.ydtdy += ti.dtdy;
-            }
-        }
-    }
-}
-
-void step_y__nop(context_t* c)
-{
-    c->iterators.y += 1;
-    c->iterators.ydzdy += c->shade.dzdy;
-}
-
-void step_y__smooth(context_t* c)
-{
-    iterators_t& ci = c->iterators;
-    ci.y += 1;
-    ci.ydrdy += c->shade.drdy;
-    ci.ydgdy += c->shade.dgdy;
-    ci.ydbdy += c->shade.dbdy;
-    ci.ydady += c->shade.dady;
-    ci.ydzdy += c->shade.dzdy;
-}
-
-void step_y__w(context_t* c)
-{
-    iterators_t& ci = c->iterators;
-    ci.y += 1;
-    ci.ydzdy += c->shade.dzdy;
-    ci.ydwdy += c->shade.dwdy;
-}
-
-void step_y__tmu(context_t* c)
-{
-    iterators_t& ci = c->iterators;
-    ci.y += 1;
-    ci.ydzdy += c->shade.dzdy;
-    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
-        if (c->state.texture[i].enable) {
-            texture_iterators_t& ti = c->state.texture[i].iterators;
-            ti.ydsdy += ti.dsdy;
-            ti.ydtdy += ti.dtdy;
-        }
-    }
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-void scanline_perspective(context_t* c)
-{
-    struct {
-        union {
-            struct {
-                int32_t s, sq;
-                int32_t t, tq;
-            } sqtq;
-            struct {
-                int32_t v, q;
-            } st[2];
-        };
-    } tc[GGL_TEXTURE_UNIT_COUNT] __attribute__((aligned(16)));
-
-    // XXX: we should have a special case when dwdx = 0
-
-    // 32 pixels spans works okay. 16 is a lot better,
-    // but hey, it's a software renderer...
-    const uint32_t SPAN_BITS = 5; 
-    const uint32_t ys = c->iterators.y;
-    const uint32_t xs = c->iterators.xl;
-    const uint32_t x1 = c->iterators.xr;
-	const uint32_t xc = x1 - xs;
-    uint32_t remainder = xc & ((1<<SPAN_BITS)-1);
-    uint32_t numSpans = xc >> SPAN_BITS;
-
-    const iterators_t& ci = c->iterators;
-    int32_t w0 = (xs * c->shade.dwdx) + ci.ydwdy;
-    int32_t q0 = gglRecipQ(w0, 30);
-    const int iwscale = 32 - gglClz(q0);
-
-    const int32_t dwdx = c->shade.dwdx << SPAN_BITS;
-    int32_t xl = c->iterators.xl;
-
-    // We process s & t with a loop to reduce the code size
-    // (and i-cache pressure).
-
-    for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
-        const texture_t& tmu = c->state.texture[i];
-        if (!tmu.enable) continue;
-        int32_t s =   tmu.shade.is0 +
-                     (tmu.shade.idsdy * ys) + (tmu.shade.idsdx * xs) +
-                     ((tmu.shade.idsdx + tmu.shade.idsdy)>>1);
-        int32_t t =   tmu.shade.it0 +
-                     (tmu.shade.idtdy * ys) + (tmu.shade.idtdx * xs) +
-                     ((tmu.shade.idtdx + tmu.shade.idtdy)>>1);
-        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;
-    do {
-        int32_t w1;
-        if (ggl_likely(numSpans)) {
-            w1 = w0 + dwdx;
-        } else {
-            if (remainder) {
-                // finish off the scanline...
-                span = remainder;
-                w1 = (c->shade.dwdx * span) + w0;
-            } else {
-                break;
-            }
-        }
-        int32_t q1 = gglRecipQ(w1, 30);
-        for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
-            texture_t& tmu = c->state.texture[i];
-            if (!tmu.enable) continue;
-            texture_iterators_t& ti = tmu.iterators;
-
-            for (int j=0 ; j<2 ; j++) {
-                int32_t v = tc[i].st[j].v;
-                if (span)   v += (tmu.shade.st[j].dx)*span;
-                else        v += (tmu.shade.st[j].dx)<<SPAN_BITS;
-                const int32_t v0 = tc[i].st[j].q;
-                const int32_t v1 = gglMulx(v, q1, iwscale);
-                int32_t dvdx = v1 - v0;
-                if (span)   dvdx /= span;
-                else        dvdx >>= SPAN_BITS;
-                tc[i].st[j].v = v;
-                tc[i].st[j].q = v1;
-
-                const int scale = ti.st[j].scale + (iwscale - 30);
-                if (scale >= 0) {
-                    ti.st[j].ydvdy = v0   << scale;
-                    ti.st[j].dvdx  = dvdx << scale;
-                } else {
-                    ti.st[j].ydvdy = v0   >> -scale;
-                    ti.st[j].dvdx  = dvdx >> -scale;
-                }
-            }
-            generated_tex_vars_t& gen = c->generated_vars.texture[i];
-            gen.dsdx = ti.st[0].dvdx;
-            gen.dtdx = ti.st[1].dvdx;
-        }
-        c->iterators.xl = xl;
-        c->iterators.xr = xl = xl + (span ? span : (1<<SPAN_BITS));
-        w0 = w1;
-        q0 = q1;
-        c->span(c);
-    } while(numSpans--);
-}
-
-void scanline_perspective_single(context_t* c)
-{
-    // 32 pixels spans works okay. 16 is a lot better,
-    // but hey, it's a software renderer...
-    const uint32_t SPAN_BITS = 5; 
-    const uint32_t ys = c->iterators.y;
-    const uint32_t xs = c->iterators.xl;
-    const uint32_t x1 = c->iterators.xr;
-	const uint32_t xc = x1 - xs;
-
-    const iterators_t& ci = c->iterators;
-    int32_t w = (xs * c->shade.dwdx) + ci.ydwdy;
-    int32_t iw = gglRecipQ(w, 30);
-    const int iwscale = 32 - gglClz(iw);
-
-    const int i = 31 - gglClz(c->state.enabled_tmu);
-    generated_tex_vars_t& gen = c->generated_vars.texture[i];
-    texture_t& tmu = c->state.texture[i];
-    texture_iterators_t& ti = tmu.iterators;
-    const int sscale = ti.sscale + (iwscale - 30);
-    const int tscale = ti.tscale + (iwscale - 30);
-    int32_t s =   tmu.shade.is0 +
-                 (tmu.shade.idsdy * ys) + (tmu.shade.idsdx * xs) +
-                 ((tmu.shade.idsdx + tmu.shade.idsdy)>>1);
-    int32_t t =   tmu.shade.it0 +
-                 (tmu.shade.idtdy * ys) + (tmu.shade.idtdx * xs) +
-                 ((tmu.shade.idtdx + tmu.shade.idtdy)>>1);
-    int32_t s0 = gglMulx(s, iw, iwscale);
-    int32_t t0 = gglMulx(t, iw, iwscale);
-    int32_t xl = c->iterators.xl;
-
-    int32_t sq, tq, dsdx, dtdx;
-    int32_t premainder = xc & ((1<<SPAN_BITS)-1);
-    uint32_t numSpans = xc >> SPAN_BITS;
-    if (c->shade.dwdx == 0) {
-        // XXX: we could choose to do this if the error is small enough
-        numSpans = 0;
-        premainder = xc;
-        goto no_perspective;
-    }
-
-    if (premainder) {
-        w += c->shade.dwdx   * premainder;
-        iw = gglRecipQ(w, 30);
-no_perspective:        
-        s += tmu.shade.idsdx * premainder;
-        t += tmu.shade.idtdx * premainder;
-        sq = gglMulx(s, iw, iwscale);
-        tq = gglMulx(t, iw, iwscale);
-        dsdx = (sq - s0) / premainder;
-        dtdx = (tq - t0) / premainder;
-        c->iterators.xl = xl;
-        c->iterators.xr = xl = xl + premainder;
-        goto finish;
-    }
-
-    while (numSpans--) {
-        w += c->shade.dwdx   << SPAN_BITS;
-        s += tmu.shade.idsdx << SPAN_BITS;
-        t += tmu.shade.idtdx << SPAN_BITS;
-        iw = gglRecipQ(w, 30);
-        sq = gglMulx(s, iw, iwscale);
-        tq = gglMulx(t, iw, iwscale);
-        dsdx = (sq - s0) >> SPAN_BITS;
-        dtdx = (tq - t0) >> SPAN_BITS;
-        c->iterators.xl = xl;
-        c->iterators.xr = xl = xl + (1<<SPAN_BITS);
-finish:
-        if (sscale >= 0) {
-            ti.ydsdy = s0   << sscale;
-            ti.dsdx  = dsdx << sscale;
-        } else {
-            ti.ydsdy = s0   >>-sscale;
-            ti.dsdx  = dsdx >>-sscale;
-        }
-        if (tscale >= 0) {
-            ti.ydtdy = t0   << tscale;
-            ti.dtdx  = dtdx << tscale;
-        } else {
-            ti.ydtdy = t0   >>-tscale;
-            ti.dtdx  = dtdx >>-tscale;
-        }
-        s0 = sq;
-        t0 = tq;
-        gen.dsdx = ti.dsdx;
-        gen.dtdx = ti.dtdx;
-        c->span(c);
-    }
-}
-
-// ----------------------------------------------------------------------------
-
-void scanline_col32cb16blend(context_t* c)
-{
-    int32_t x = c->iterators.xl;
-    size_t ct = c->iterators.xr - x;
-    int32_t y = c->iterators.y;
-    surface_t* cb = &(c->state.buffers.color);
-    union {
-        uint16_t* dst;
-        uint32_t* dst32;
-    };
-    dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
-
-#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && defined(__arm__))
-#if defined(__ARM_HAVE_NEON) && BYTE_ORDER == LITTLE_ENDIAN
-    scanline_col32cb16blend_neon(dst, &(c->packed8888), ct);
-#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_arm64(dst, GGL_RGBA_TO_HOST(c->packed8888), ct);
-#elif ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__mips__) && defined(__LP64__)))
-    scanline_col32cb16blend_mips64(dst, GGL_RGBA_TO_HOST(c->packed8888), ct);
-#else
-    uint32_t s = GGL_RGBA_TO_HOST(c->packed8888);
-    int sA = (s>>24);
-    int f = 0x100 - (sA + (sA>>7));
-    while (ct--) {
-        uint16_t d = *dst;
-        int dR = (d>>11)&0x1f;
-        int dG = (d>>5)&0x3f;
-        int dB = (d)&0x1f;
-        int sR = (s >> (   3))&0x1F;
-        int sG = (s >> ( 8+2))&0x3F;
-        int sB = (s >> (16+3))&0x1F;
-        sR += (f*dR)>>8;
-        sG += (f*dG)>>8;
-        sB += (f*dB)>>8;
-        *dst++ = uint16_t((sR<<11)|(sG<<5)|sB);
-    }
-#endif
-
-}
-
-void scanline_t32cb16(context_t* c)
-{
-    int32_t x = c->iterators.xl;
-    size_t ct = c->iterators.xr - x;    
-    int32_t y = c->iterators.y;
-    surface_t* cb = &(c->state.buffers.color);
-    union {
-        uint16_t* dst;
-        uint32_t* dst32;
-    };
-    dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
-
-    surface_t* tex = &(c->state.texture[0].surface);
-    const int32_t u = (c->state.texture[0].shade.is0>>16) + x;
-    const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
-    uint32_t *src = reinterpret_cast<uint32_t*>(tex->data)+(u+(tex->stride*v));
-    uint32_t s, d;
-
-    if (ct==1 || uintptr_t(dst)&2) {
-last_one:
-        s = GGL_RGBA_TO_HOST( *src++ );
-        *dst++ = convertAbgr8888ToRgb565(s);
-        ct--;
-    }
-
-    while (ct >= 2) {
-#if BYTE_ORDER == BIG_ENDIAN
-        s = GGL_RGBA_TO_HOST( *src++ );
-        d = convertAbgr8888ToRgb565_hi16(s);
-
-        s = GGL_RGBA_TO_HOST( *src++ );
-        d |= convertAbgr8888ToRgb565(s);
-#else
-        s = GGL_RGBA_TO_HOST( *src++ );
-        d = convertAbgr8888ToRgb565(s);
-
-        s = GGL_RGBA_TO_HOST( *src++ );
-        d |= convertAbgr8888ToRgb565(s) << 16;
-#endif
-        *dst32++ = d;
-        ct -= 2;
-    }
-    
-    if (ct > 0) {
-        goto last_one;
-    }
-}
-
-void scanline_t32cb16blend(context_t* c)
-{
-#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || defined(__aarch64__) || \
-    (defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || defined(__LP64__)))))
-    int32_t x = c->iterators.xl;
-    size_t ct = c->iterators.xr - x;
-    int32_t y = c->iterators.y;
-    surface_t* cb = &(c->state.buffers.color);
-    uint16_t* dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
-
-    surface_t* tex = &(c->state.texture[0].surface);
-    const int32_t u = (c->state.texture[0].shade.is0>>16) + x;
-    const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
-    uint32_t *src = reinterpret_cast<uint32_t*>(tex->data)+(u+(tex->stride*v));
-
-#ifdef __arm__
-    scanline_t32cb16blend_arm(dst, src, ct);
-#elif defined(__aarch64__)
-    scanline_t32cb16blend_arm64(dst, src, ct);
-#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
-    scanline_t32cb16blend_mips(dst, src, ct);
-#elif defined(__mips__) && defined(__LP64__)
-    scanline_t32cb16blend_mips64(dst, src, ct);
-#endif
-#else
-    dst_iterator16  di(c);
-    horz_iterator32  hi(c);
-    blender_32to16  bl(c);
-    while (di.count--) {
-        uint32_t s = hi.get_pixel32();
-        bl.write(s, di.dst);
-        di.dst++;
-    }
-#endif
-}
-
-void scanline_t32cb16blend_srca(context_t* c)
-{
-    dst_iterator16  di(c);
-    horz_iterator32  hi(c);
-    blender_32to16_srcA  blender(c);
-
-    while (di.count--) {
-        uint32_t s = hi.get_pixel32();
-        blender.write(s,di.dst);
-        di.dst++;
-    }
-}
-
-void scanline_t16cb16blend_clamp_mod(context_t* c)
-{
-    const int a = c->iterators.ydady >> (GGL_COLOR_BITS-8);
-    if (a == 0) {
-        return;
-    }
-
-    if (a == 255) {
-        scanline_t16cb16_clamp(c);
-        return;
-    }
-
-    dst_iterator16  di(c);
-    blender_16to16_modulate  blender(c);
-    clamp_iterator  ci(c);
-
-    while (di.count--) {
-        uint16_t s = ci.get_pixel16();
-        blender.write(s, di.dst);
-        di.dst++;
-    }
-}
-
-void scanline_memcpy(context_t* c)
-{
-    int32_t x = c->iterators.xl;
-    size_t ct = c->iterators.xr - x;
-    int32_t y = c->iterators.y;
-    surface_t* cb = &(c->state.buffers.color);
-    const GGLFormat* fp = &(c->formats[cb->format]);
-    uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
-                            (x + (cb->stride * y)) * fp->size;
-
-    surface_t* tex = &(c->state.texture[0].surface);
-    const int32_t u = (c->state.texture[0].shade.is0>>16) + x;
-    const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
-    uint8_t *src = reinterpret_cast<uint8_t*>(tex->data) +
-                            (u + (tex->stride * v)) * fp->size;
-
-    const size_t size = ct * fp->size;
-    memcpy(dst, src, size);
-}
-
-void scanline_memset8(context_t* c)
-{
-    int32_t x = c->iterators.xl;
-    size_t ct = c->iterators.xr - x;
-    int32_t y = c->iterators.y;
-    surface_t* cb = &(c->state.buffers.color);
-    uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) + (x+(cb->stride*y));
-    uint32_t packed = c->packed;
-    memset(dst, packed, ct);
-}
-
-void scanline_memset16(context_t* c)
-{
-    int32_t x = c->iterators.xl;
-    size_t ct = c->iterators.xr - x;
-    int32_t y = c->iterators.y;
-    surface_t* cb = &(c->state.buffers.color);
-    uint16_t* dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
-    uint32_t packed = c->packed;
-    android_memset16(dst, packed, ct*2);
-}
-
-void scanline_memset32(context_t* c)
-{
-    int32_t x = c->iterators.xl;
-    size_t ct = c->iterators.xr - x;
-    int32_t y = c->iterators.y;
-    surface_t* cb = &(c->state.buffers.color);
-    uint32_t* dst = reinterpret_cast<uint32_t*>(cb->data) + (x+(cb->stride*y));
-    uint32_t packed = GGL_HOST_TO_RGBA(c->packed);
-    android_memset32(dst, packed, ct*4);
-}
-
-void scanline_clear(context_t* c)
-{
-    int32_t x = c->iterators.xl;
-    size_t ct = c->iterators.xr - x;
-    int32_t y = c->iterators.y;
-    surface_t* cb = &(c->state.buffers.color);
-    const GGLFormat* fp = &(c->formats[cb->format]);
-    uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
-                            (x + (cb->stride * y)) * fp->size;
-    const size_t size = ct * fp->size;
-    memset(dst, 0, size);
-}
-
-void scanline_set(context_t* c)
-{
-    int32_t x = c->iterators.xl;
-    size_t ct = c->iterators.xr - x;
-    int32_t y = c->iterators.y;
-    surface_t* cb = &(c->state.buffers.color);
-    const GGLFormat* fp = &(c->formats[cb->format]);
-    uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
-                            (x + (cb->stride * y)) * fp->size;
-    const size_t size = ct * fp->size;
-    memset(dst, 0xFF, size);
-}
-
-void scanline_noop(context_t* /*c*/)
-{
-}
-
-void rect_generic(context_t* c, size_t yc)
-{
-    do {
-        c->scanline(c);
-        c->step_y(c);
-    } while (--yc);
-}
-
-void rect_memcpy(context_t* c, size_t yc)
-{
-    int32_t x = c->iterators.xl;
-    size_t ct = c->iterators.xr - x;
-    int32_t y = c->iterators.y;
-    surface_t* cb = &(c->state.buffers.color);
-    const GGLFormat* fp = &(c->formats[cb->format]);
-    uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
-                            (x + (cb->stride * y)) * fp->size;
-
-    surface_t* tex = &(c->state.texture[0].surface);
-    const int32_t u = (c->state.texture[0].shade.is0>>16) + x;
-    const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
-    uint8_t *src = reinterpret_cast<uint8_t*>(tex->data) +
-                            (u + (tex->stride * v)) * fp->size;
-
-    if (cb->stride == tex->stride && ct == size_t(cb->stride)) {
-        memcpy(dst, src, ct * fp->size * yc);
-    } else {
-        const size_t size = ct * fp->size;
-        const size_t dbpr = cb->stride  * fp->size;
-        const size_t sbpr = tex->stride * fp->size;
-        do {
-            memcpy(dst, src, size);
-            dst += dbpr;
-            src += sbpr;        
-        } while (--yc);
-    }
-}
-// ----------------------------------------------------------------------------
-}; // namespace android
-
diff --git a/libpixelflinger/scanline.h b/libpixelflinger/scanline.h
deleted file mode 100644
index b6f4d37..0000000
--- a/libpixelflinger/scanline.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* libs/pixelflinger/scanline.h
-**
-** Copyright 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 ANDROID_SCANLINE_H
-#define ANDROID_SCANLINE_H
-
-#include <private/pixelflinger/ggl_context.h>
-
-namespace android {
-
-void ggl_init_scanline(context_t* c);
-void ggl_uninit_scanline(context_t* c);
-void ggl_pick_scanline(context_t* c);
-
-}; // namespace android
-
-#endif
diff --git a/libpixelflinger/t32cb16blend.S b/libpixelflinger/t32cb16blend.S
deleted file mode 100644
index 5e4995a..0000000
--- a/libpixelflinger/t32cb16blend.S
+++ /dev/null
@@ -1,203 +0,0 @@
-/* libs/pixelflinger/t32cb16blend.S
-**
-** Copyright 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.
-*/
-
-
-	.text
-	.syntax unified
-	.balign 4
-	
-	.global scanline_t32cb16blend_arm
-
-
-/*
- * .macro pixel
- *
- * \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: r6, r7, lr
- *
- */
-
-.macro pixel,   DREG, SRC, FB, ODD
-
-    // SRC = 0xAABBGGRR
-    mov     r7, \SRC, lsr #24           // sA
-    add     r7, r7, r7, lsr #7          // sA + (sA >> 7)
-    rsb     r7, r7, #0x100              // sA = 0x100 - (sA+(sA>>7))
-
-1:
-
-.if \ODD
-
-    // red
-    mov     lr, \DREG, lsr #(16 + 11)
-    smulbb  lr, r7, lr
-    mov     r6, \SRC, lsr #3
-    and     r6, r6, #0x1F
-    add     lr, r6, lr, lsr #8
-    cmp     lr, #0x1F
-    orrhs   \FB, \FB, #(0x1F<<(16 + 11))
-    orrlo   \FB, \FB, lr, lsl #(16 + 11)
-
-        // green
-        and     r6, \DREG, #(0x3F<<(16 + 5))
-        smulbt  r6, r7, r6
-        mov     lr, \SRC, lsr #(8+2)
-        and     lr, lr, #0x3F
-        add     r6, lr, r6, lsr #(5+8)
-        cmp     r6, #0x3F
-        orrhs   \FB, \FB, #(0x3F<<(16 + 5))
-        orrlo   \FB, \FB, r6, lsl #(16 + 5)
-
-            // blue
-            and     lr, \DREG, #(0x1F << 16)
-            smulbt  lr, r7, lr
-            mov     r6, \SRC, lsr #(8+8+3)
-            and     r6, r6, #0x1F
-            add     lr, r6, lr, lsr #8
-            cmp     lr, #0x1F
-            orrhs   \FB, \FB, #(0x1F << 16)
-            orrlo   \FB, \FB, lr, lsl #16
-
-.else
-
-    // red
-    mov     lr, \DREG, lsr #11
-    and     lr, lr, #0x1F
-    smulbb  lr, r7, lr
-    mov     r6, \SRC, lsr #3
-    and     r6, r6, #0x1F
-    add     lr, r6, lr, lsr #8
-    cmp     lr, #0x1F
-    movhs   \FB, #(0x1F<<11)
-    movlo   \FB, lr, lsl #11
-
-
-        // green
-        and     r6, \DREG, #(0x3F<<5)
-        smulbb  r6, r7, r6
-        mov     lr, \SRC, lsr #(8+2)
-        and     lr, lr, #0x3F
-        add     r6, lr, r6, lsr #(5+8)
-        cmp     r6, #0x3F
-        orrhs   \FB, \FB, #(0x3F<<5)
-        orrlo   \FB, \FB, r6, lsl #5
-
-            // blue
-            and     lr, \DREG, #0x1F
-            smulbb  lr, r7, lr
-            mov     r6, \SRC, lsr #(8+8+3)
-            and     r6, r6, #0x1F
-            add     lr, r6, lr, lsr #8
-            cmp     lr, #0x1F
-            orrhs   \FB, \FB, #0x1F
-            orrlo   \FB, \FB, lr
-
-.endif
-
-    .endm
-    
-
-// r0:  dst ptr
-// r1:  src ptr
-// r2:  count
-// r3:  d
-// r4:  s0
-// r5:  s1
-// r6:  pixel
-// r7:  pixel
-// r8:  free
-// r9:  free
-// r10: free
-// r11: free
-// r12: scratch
-// r14: pixel
-
-scanline_t32cb16blend_arm:
-    stmfd	sp!, {r4-r7, lr}
-
-    pld     [r0]
-    pld     [r1]
-
-    // align DST to 32 bits
-    tst     r0, #0x3
-    beq     aligned
-    subs    r2, r2, #1
-    ldmfdlo sp!, {r4-r7, lr}        // return
-    bxlo    lr
-
-last:
-    ldr     r4, [r1], #4
-    ldrh    r3, [r0]
-    pixel   r3, r4, r12, 0
-    strh    r12, [r0], #2
-
-aligned:
-    subs    r2, r2, #2
-    blo     9f
-
-    // The main loop is unrolled twice and processes 4 pixels
-8:  ldmia   r1!, {r4, r5}
-    // stream the source
-    pld     [r1, #32]
-    add     r0, r0, #4
-    // it's all zero, skip this pixel
-    orrs    r3, r4, r5
-    beq     7f
-    
-    // load the destination
-    ldr     r3, [r0, #-4]
-    // stream the destination
-    pld     [r0, #32]
-    pixel   r3, r4, r12, 0
-    pixel   r3, r5, r12, 1
-    // effectively, we're getting write-combining by virtue of the
-    // cpu's write-back cache.
-    str     r12, [r0, #-4]
-
-    // 2nd iterration of the loop, don't stream anything
-    subs    r2, r2, #2
-    movlt   r4, r5
-    blt     9f
-    ldmia   r1!, {r4, r5}
-    add     r0, r0, #4
-    orrs    r3, r4, r5
-    beq     7f
-    ldr     r3, [r0, #-4]
-    pixel   r3, r4, r12, 0
-    pixel   r3, r5, r12, 16
-    str     r12, [r0, #-4]
-
-    
-7:  subs    r2, r2, #2
-    bhs     8b
-    mov     r4, r5
-
-9:  adds    r2, r2, #1
-    ldmfdlo sp!, {r4-r7, lr}        // return
-    bxlo    lr
-    b       last
diff --git a/libpixelflinger/tests/Android.bp b/libpixelflinger/tests/Android.bp
deleted file mode 100644
index e20dd93..0000000
--- a/libpixelflinger/tests/Android.bp
+++ /dev/null
@@ -1,17 +0,0 @@
-cc_defaults {
-    name: "pixelflinger-tests",
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-
-    header_libs: ["libpixelflinger_internal"],
-    static_libs: [
-        "libbase",
-        "libcutils",
-        "liblog",
-        "libpixelflinger",
-        "libutils",
-    ],
-}
diff --git a/libpixelflinger/tests/arch-arm64/Android.bp b/libpixelflinger/tests/arch-arm64/Android.bp
deleted file mode 100644
index 2f5586a..0000000
--- a/libpixelflinger/tests/arch-arm64/Android.bp
+++ /dev/null
@@ -1,11 +0,0 @@
-cc_defaults {
-    name: "pixelflinger-tests-arm64",
-    defaults: ["pixelflinger-tests"],
-
-    enabled: false,
-    arch: {
-        arm64: {
-            enabled: true,
-        },
-    },
-}
diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.bp b/libpixelflinger/tests/arch-arm64/assembler/Android.bp
deleted file mode 100644
index 003f485..0000000
--- a/libpixelflinger/tests/arch-arm64/assembler/Android.bp
+++ /dev/null
@@ -1,9 +0,0 @@
-cc_test {
-    name: "test-pixelflinger-arm64-assembler-test",
-    defaults: ["pixelflinger-tests-arm64"],
-
-    srcs: [
-        "arm64_assembler_test.cpp",
-        "asm_test_jacket.S",
-    ],
-}
diff --git a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
deleted file mode 100644
index 63642c4..0000000
--- a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
+++ /dev/null
@@ -1,782 +0,0 @@
-/*
- * 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>
-
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-
-#include "codeflinger/ARMAssemblerInterface.h"
-#include "codeflinger/Arm64Assembler.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},
-};
-
-
-void flushcache()
-{
-    const long base = long(instrMem);
-    const long curr = base + long(instrMemSize);
-    __builtin___clear_cache((char*)base, (char*)curr);
-}
-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 ArmToArm64Assembler */
-    {
-        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);
-    }
-
-    ArmToArm64Assembler 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-arm64/assembler/asm_test_jacket.S b/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
deleted file mode 100644
index 3f900f8..0000000
--- a/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * 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
-    .balign 0
-
-    .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-arm64/col32cb16blend/Android.bp b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.bp
deleted file mode 100644
index e640aeb..0000000
--- a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-cc_test {
-    name: "test-pixelflinger-arm64-col32cb16blend",
-    defaults: ["pixelflinger-tests-arm64"],
-
-    srcs: ["col32cb16blend_test.c"],
-}
diff --git a/libpixelflinger/tests/arch-arm64/col32cb16blend/col32cb16blend_test.c b/libpixelflinger/tests/arch-arm64/col32cb16blend/col32cb16blend_test.c
deleted file mode 100644
index c6a3017..0000000
--- a/libpixelflinger/tests/arch-arm64/col32cb16blend/col32cb16blend_test.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * 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_arm64(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_arm64(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-arm64/disassembler/Android.bp b/libpixelflinger/tests/arch-arm64/disassembler/Android.bp
deleted file mode 100644
index 38dc99a..0000000
--- a/libpixelflinger/tests/arch-arm64/disassembler/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-cc_test {
-    name: "test-pixelflinger-arm64-disassembler-test",
-    defaults: ["pixelflinger-tests-arm64"],
-
-    srcs: ["arm64_diassembler_test.cpp"],
-}
diff --git a/libpixelflinger/tests/arch-arm64/disassembler/arm64_diassembler_test.cpp b/libpixelflinger/tests/arch-arm64/disassembler/arm64_diassembler_test.cpp
deleted file mode 100644
index af3183b..0000000
--- a/libpixelflinger/tests/arch-arm64/disassembler/arm64_diassembler_test.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * 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 arm64_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];
-        arm64_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-arm64/t32cb16blend/Android.bp b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.bp
deleted file mode 100644
index 9d060d1..0000000
--- a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-cc_test {
-    name: "test-pixelflinger-arm64-t32cb16blend",
-    defaults: ["pixelflinger-tests-arm64"],
-
-    srcs: ["t32cb16blend_test.c"],
-}
diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/t32cb16blend_test.c b/libpixelflinger/tests/arch-arm64/t32cb16blend/t32cb16blend_test.c
deleted file mode 100644
index afb36fb..0000000
--- a/libpixelflinger/tests/arch-arm64/t32cb16blend/t32cb16blend_test.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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_arm64(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_arm64(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/Android.bp b/libpixelflinger/tests/codegen/Android.bp
deleted file mode 100644
index 7e4bcfb..0000000
--- a/libpixelflinger/tests/codegen/Android.bp
+++ /dev/null
@@ -1,12 +0,0 @@
-cc_test {
-    name: "test-opengl-codegen",
-    defaults: ["pixelflinger-tests"],
-
-    srcs: ["codegen.cpp"],
-
-    arch: {
-        arm: {
-            instruction_set: "arm",
-        },
-    },
-}
diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp
deleted file mode 100644
index dce4ed7..0000000
--- a/libpixelflinger/tests/codegen/codegen.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-#include <stdio.h>
-#include <stdint.h>
-
-#include "private/pixelflinger/ggl_context.h"
-
-#include "buffer.h"
-#include "scanline.h"
-
-#include "codeflinger/CodeCache.h"
-#include "codeflinger/GGLAssembler.h"
-#include "codeflinger/ARMAssembler.h"
-#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
-#include "codeflinger/MIPSAssembler.h"
-#elif defined(__mips__) && defined(__LP64__) && __mips_isa_rev == 6
-#include "codeflinger/MIPS64Assembler.h"
-#endif
-#include "codeflinger/Arm64Assembler.h"
-
-#if defined(__arm__) || (defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || (defined(__LP64__) && __mips_isa_rev == 6))) || defined(__aarch64__)
-#   define ANDROID_ARM_CODEGEN  1
-#else
-#   define ANDROID_ARM_CODEGEN  0
-#endif
-
-#if defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || (defined(__LP64__) && __mips_isa_rev == 6))
-#define ASSEMBLY_SCRATCH_SIZE   4096
-#elif defined(__aarch64__)
-#define ASSEMBLY_SCRATCH_SIZE   8192
-#else
-#define ASSEMBLY_SCRATCH_SIZE   2048
-#endif
-
-using namespace android;
-
-class ScanlineAssembly : public Assembly {
-    AssemblyKey<needs_t> mKey;
-public:
-    ScanlineAssembly(needs_t needs, size_t size)
-        : Assembly(size), mKey(needs) { }
-    const AssemblyKey<needs_t>& key() const { return mKey; }
-};
-
-#if ANDROID_ARM_CODEGEN
-static void ggl_test_codegen(uint32_t n, uint32_t p, uint32_t t0, uint32_t t1)
-{
-    GGLContext* c;
-    gglInit(&c);
-    needs_t needs;
-    needs.n = n;
-    needs.p = p;
-    needs.t[0] = t0;
-    needs.t[1] = t1;
-    sp<ScanlineAssembly> a(new ScanlineAssembly(needs, ASSEMBLY_SCRATCH_SIZE));
-
-#if defined(__arm__)
-    GGLAssembler assembler( new ARMAssembler(a) );
-#endif
-
-#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
-    GGLAssembler assembler( new ArmToMipsAssembler(a) );
-#endif
-
-#if defined(__mips__) && defined(__LP64__) && __mips_isa_rev == 6
-    GGLAssembler assembler( new ArmToMips64Assembler(a) );
-#endif
-
-#if defined(__aarch64__)
-    GGLAssembler assembler( new ArmToArm64Assembler(a) );
-#endif
-
-    int err = assembler.scanline(needs, (context_t*)c);
-    if (err != 0) {
-        printf("error %08x (%s)\n", err, strerror(-err));
-    }
-    gglUninit(c);
-}
-#else
-static void ggl_test_codegen(uint32_t, uint32_t, uint32_t, uint32_t) {
-    printf("This test runs only on ARM, Arm64 or MIPS\n");
-}
-#endif
-
-int main(int argc, char** argv)
-{
-    if (argc != 2) {
-        printf("usage: %s 00000117:03454504_00001501_00000000\n", argv[0]);
-        return 0;
-    }
-    uint32_t n;
-    uint32_t p;
-    uint32_t t0;
-    uint32_t t1;
-    sscanf(argv[1], "%08x:%08x_%08x_%08x", &p, &n, &t0, &t1);
-    ggl_test_codegen(n, p,  t0, t1);
-    return 0;
-}
diff --git a/libpixelflinger/tests/gglmul/Android.bp b/libpixelflinger/tests/gglmul/Android.bp
deleted file mode 100644
index 288337b..0000000
--- a/libpixelflinger/tests/gglmul/Android.bp
+++ /dev/null
@@ -1,12 +0,0 @@
-cc_test {
-    name: "test-pixelflinger-gglmul",
-
-    srcs: ["gglmul_test.cpp"],
-
-    header_libs: ["libpixelflinger_internal"],
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-}
diff --git a/libpixelflinger/tests/gglmul/gglmul_test.cpp b/libpixelflinger/tests/gglmul/gglmul_test.cpp
deleted file mode 100644
index 5d460d6..0000000
--- a/libpixelflinger/tests/gglmul/gglmul_test.cpp
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * 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 <inttypes.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
-
-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(%" PRId64 ") Expected(%" PRId64 ")\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/libpixelflinger/trap.cpp b/libpixelflinger/trap.cpp
deleted file mode 100644
index 06ad237..0000000
--- a/libpixelflinger/trap.cpp
+++ /dev/null
@@ -1,1173 +0,0 @@
-/* libs/pixelflinger/trap.cpp
-**
-** Copyright 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.
-*/
-
-#define LOG_TAG "pixelflinger-trap"
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <cutils/memory.h>
-#include <log/log.h>
-
-#include "trap.h"
-#include "picker.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-// enable to see triangles edges
-#define DEBUG_TRANGLES  0
-
-// ----------------------------------------------------------------------------
-
-static void pointx_validate(void *con, const GGLcoord* c, GGLcoord r);
-static void pointx(void *con, const GGLcoord* c, GGLcoord r);
-static void aa_pointx(void *con, const GGLcoord* c, GGLcoord r);
-static void aa_nice_pointx(void *con, const GGLcoord* c, GGLcoord r);
-
-static void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
-static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
-static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
-
-static void recti_validate(void* c, GGLint l, GGLint t, GGLint r, GGLint b); 
-static void recti(void* c, GGLint l, GGLint t, GGLint r, GGLint b); 
-
-static void trianglex_validate(void*,
-        const GGLcoord*, const GGLcoord*, const GGLcoord*);
-static void trianglex_small(void*,
-        const GGLcoord*, const GGLcoord*, const GGLcoord*);
-static void trianglex_big(void*,
-        const GGLcoord*, const GGLcoord*, const GGLcoord*);
-static void aa_trianglex(void*,
-        const GGLcoord*, const GGLcoord*, const GGLcoord*);
-static void trianglex_debug(void* con,
-        const GGLcoord*, const GGLcoord*, const GGLcoord*);
-
-static void aapolyx(void* con,
-        const GGLcoord* pts, int count);
-
-static inline int min(int a, int b) CONST;
-static inline int max(int a, int b) CONST;
-static inline int min(int a, int b, int c) CONST;
-static inline int max(int a, int b, int c) CONST;
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Tools
-#endif
-
-inline int min(int a, int b) {
-    return a<b ? a : b;
-}
-inline int max(int a, int b) {
-    return a<b ? b : a;
-}
-inline int min(int a, int b, int c) {
-    return min(a,min(b,c));
-}
-inline int max(int a, int b, int c) {
-    return max(a,max(b,c));
-}
-
-template <typename T>
-static inline void swap(T& a, T& b) {
-    T t(a);
-    a = b;
-    b = t;
-}
-
-static void
-triangle_dump_points( const GGLcoord*  v0,
-                      const GGLcoord*  v1,
-                      const GGLcoord*  v2 )
-{
-    float tri = 1.0f / TRI_ONE;
-    ALOGD("  P0=(%.3f, %.3f)  [%08x, %08x]\n"
-          "  P1=(%.3f, %.3f)  [%08x, %08x]\n"
-          "  P2=(%.3f, %.3f)  [%08x, %08x]\n",
-          v0[0]*tri, v0[1]*tri, v0[0], v0[1],
-          v1[0]*tri, v1[1]*tri, v1[0], v1[1],
-          v2[0]*tri, v2[1]*tri, v2[0], v2[1] );
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Misc
-#endif
-
-void ggl_init_trap(context_t* c)
-{
-    ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE|GGL_TMU_STATE|GGL_CB_STATE);
-}
-
-void ggl_state_changed(context_t* c, int flags)
-{
-    if (ggl_likely(!c->dirty)) {
-        c->procs.pointx     = pointx_validate;
-        c->procs.linex      = linex_validate;
-        c->procs.recti      = recti_validate;
-        c->procs.trianglex  = trianglex_validate;
-    }
-    c->dirty |= uint32_t(flags);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Point
-#endif
-
-void pointx_validate(void *con, const GGLcoord* v, GGLcoord rad)
-{
-    GGL_CONTEXT(c, con);
-    ggl_pick(c);
-    if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
-        if (c->state.enables & GGL_ENABLE_POINT_AA_NICE) {
-            c->procs.pointx = aa_nice_pointx;
-        } else {
-            c->procs.pointx = aa_pointx;
-        }
-    } else {
-        c->procs.pointx = pointx;
-    }
-    c->procs.pointx(con, v, rad);
-}
-
-void pointx(void *con, const GGLcoord* v, GGLcoord rad)
-{
-    GGL_CONTEXT(c, con);
-    GGLcoord halfSize = TRI_ROUND(rad) >> 1;
-    if (halfSize == 0)
-        halfSize = TRI_HALF;
-    GGLcoord xc = v[0]; 
-    GGLcoord yc = v[1];
-    if (halfSize & TRI_HALF) { // size odd
-        xc = TRI_FLOOR(xc) + TRI_HALF;
-        yc = TRI_FLOOR(yc) + TRI_HALF;
-    } else { // size even
-        xc = TRI_ROUND(xc);
-        yc = TRI_ROUND(yc);
-    }
-    GGLint l = (xc - halfSize) >> TRI_FRACTION_BITS;
-    GGLint t = (yc - halfSize) >> TRI_FRACTION_BITS;
-    GGLint r = (xc + halfSize) >> TRI_FRACTION_BITS;
-    GGLint b = (yc + halfSize) >> TRI_FRACTION_BITS;
-    recti(c, l, t, r, b);
-}
-
-// This way of computing the coverage factor, is more accurate and gives
-// better results for small circles, but it is also a lot slower.
-// Here we use super-sampling.
-static int32_t coverageNice(GGLcoord x, GGLcoord y, 
-        GGLcoord rmin, GGLcoord rmax, GGLcoord rr)
-{
-    const GGLcoord d2 = x*x + y*y;
-    if (d2 >= rmax) return 0;
-    if (d2 < rmin)  return 0x7FFF;
-
-    const int kSamples              =  4;
-    const int kInc                  =  4;    // 1/4 = 0.25
-    const int kCoverageUnit         =  1;    // 1/(4^2) = 0.0625
-    const GGLcoord kCoordOffset     = -6;    // -0.375
-
-    int hits = 0;
-    int x_sample = x + kCoordOffset;
-    for (int i=0 ; i<kSamples ; i++, x_sample += kInc) {
-        const int xval = rr - (x_sample * x_sample);
-        int y_sample = y + kCoordOffset;
-        for (int j=0 ; j<kSamples ; j++, y_sample += kInc) {
-            if (xval - (y_sample * y_sample) > 0)
-                hits += kCoverageUnit;
-        }
-    }
-    return min(0x7FFF, hits << (15 - kSamples));
-}
-
-
-void aa_nice_pointx(void *con, const GGLcoord* v, GGLcoord size)
-{
-    GGL_CONTEXT(c, con);
-
-    GGLcoord rad = ((size + 1)>>1);
-    GGLint l = (v[0] - rad) >> TRI_FRACTION_BITS;
-    GGLint t = (v[1] - rad) >> TRI_FRACTION_BITS;
-    GGLint r = (v[0] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
-    GGLint b = (v[1] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
-    GGLcoord xstart = TRI_FROM_INT(l) - v[0] + TRI_HALF; 
-    GGLcoord ystart = TRI_FROM_INT(t) - v[1] + TRI_HALF; 
-
-    // scissor...
-    if (l < GGLint(c->state.scissor.left)) {
-        xstart += TRI_FROM_INT(c->state.scissor.left-l);
-        l = GGLint(c->state.scissor.left);
-    }
-    if (t < GGLint(c->state.scissor.top)) {
-        ystart += TRI_FROM_INT(c->state.scissor.top-t);
-        t = GGLint(c->state.scissor.top);
-    }
-    if (r > GGLint(c->state.scissor.right)) {
-        r = GGLint(c->state.scissor.right);
-    }
-    if (b > GGLint(c->state.scissor.bottom)) {
-        b = GGLint(c->state.scissor.bottom);
-    }
-
-    int xc = r - l;
-    int yc = b - t;
-    if (xc>0 && yc>0) {
-        int16_t* covPtr = c->state.buffers.coverage;
-        const int32_t sqr2Over2 = 0xC; // rounded up
-        GGLcoord rr = rad*rad;
-        GGLcoord rmin = (rad - sqr2Over2)*(rad - sqr2Over2);
-        GGLcoord rmax = (rad + sqr2Over2)*(rad + sqr2Over2);
-        GGLcoord y = ystart;
-        c->iterators.xl = l;
-        c->iterators.xr = r;
-        c->init_y(c, t);
-        do {
-            // compute coverage factors for each pixel
-            GGLcoord x = xstart;
-            for (int i=l ; i<r ; i++) {
-                covPtr[i] = coverageNice(x, y, rmin, rmax, rr);
-                x += TRI_ONE;
-            }
-            y += TRI_ONE;
-            c->scanline(c);
-            c->step_y(c);
-        } while (--yc);
-    }
-}
-
-// This is a cheap way of computing the coverage factor for a circle.
-// We just lerp between the circles of radii r-sqrt(2)/2 and r+sqrt(2)/2
-static inline int32_t coverageFast(GGLcoord x, GGLcoord y,
-        GGLcoord rmin, GGLcoord rmax, GGLcoord scale)
-{
-    const GGLcoord d2 = x*x + y*y;
-    if (d2 >= rmax) return 0;
-    if (d2 < rmin)  return 0x7FFF;
-    return 0x7FFF - (d2-rmin)*scale;
-}
-
-void aa_pointx(void *con, const GGLcoord* v, GGLcoord size)
-{
-    GGL_CONTEXT(c, con);
-
-    GGLcoord rad = ((size + 1)>>1);
-    GGLint l = (v[0] - rad) >> TRI_FRACTION_BITS;
-    GGLint t = (v[1] - rad) >> TRI_FRACTION_BITS;
-    GGLint r = (v[0] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
-    GGLint b = (v[1] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
-    GGLcoord xstart = TRI_FROM_INT(l) - v[0] + TRI_HALF; 
-    GGLcoord ystart = TRI_FROM_INT(t) - v[1] + TRI_HALF; 
-
-    // scissor...
-    if (l < GGLint(c->state.scissor.left)) {
-        xstart += TRI_FROM_INT(c->state.scissor.left-l);
-        l = GGLint(c->state.scissor.left);
-    }
-    if (t < GGLint(c->state.scissor.top)) {
-        ystart += TRI_FROM_INT(c->state.scissor.top-t);
-        t = GGLint(c->state.scissor.top);
-    }
-    if (r > GGLint(c->state.scissor.right)) {
-        r = GGLint(c->state.scissor.right);
-    }
-    if (b > GGLint(c->state.scissor.bottom)) {
-        b = GGLint(c->state.scissor.bottom);
-    }
-
-    int xc = r - l;
-    int yc = b - t;
-    if (xc>0 && yc>0) {
-        int16_t* covPtr = c->state.buffers.coverage;
-        rad <<= 4;
-        const int32_t sqr2Over2 = 0xB5;    // fixed-point 24.8
-        GGLcoord rmin = rad - sqr2Over2;
-        GGLcoord rmax = rad + sqr2Over2;
-        GGLcoord scale;
-        rmin *= rmin;
-        rmax *= rmax;
-        scale = 0x800000 / (rmax - rmin);
-        rmin >>= 8;
-        rmax >>= 8;
-
-        GGLcoord y = ystart;
-        c->iterators.xl = l;
-        c->iterators.xr = r;
-        c->init_y(c, t);
-
-        do {
-            // compute coverage factors for each pixel
-            GGLcoord x = xstart;
-            for (int i=l ; i<r ; i++) {
-                covPtr[i] = coverageFast(x, y, rmin, rmax, scale);
-                x += TRI_ONE;
-            }
-            y += TRI_ONE;
-            c->scanline(c);
-            c->step_y(c);
-        } while (--yc);
-    }
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Line
-#endif
-
-void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w)
-{
-    GGL_CONTEXT(c, con);
-    ggl_pick(c);
-    if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
-        c->procs.linex = aa_linex;
-    } else {
-        c->procs.linex = linex;
-    }
-    c->procs.linex(con, v0, v1, w);
-}
-
-static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
-{
-    GGLcoord v[4][2];
-    v[0][0] = v0[0];    v[0][1] = v0[1];
-    v[1][0] = v1[0];    v[1][1] = v1[1];
-    v0 = v[0];
-    v1 = v[1];
-    const GGLcoord dx = abs(v0[0] - v1[0]);
-    const GGLcoord dy = abs(v0[1] - v1[1]);
-    GGLcoord nx, ny;
-    nx = ny = 0;
-
-    GGLcoord halfWidth = TRI_ROUND(width) >> 1;
-    if (halfWidth == 0)
-        halfWidth = TRI_HALF;
-
-    ((dx > dy) ? ny : nx) = halfWidth;
-    v[2][0] = v1[0];    v[2][1] = v1[1];
-    v[3][0] = v0[0];    v[3][1] = v0[1];
-    v[0][0] += nx;      v[0][1] += ny;
-    v[1][0] += nx;      v[1][1] += ny;
-    v[2][0] -= nx;      v[2][1] -= ny;
-    v[3][0] -= nx;      v[3][1] -= ny;
-    trianglex_big(con, v[0], v[1], v[2]);
-    trianglex_big(con, v[0], v[2], v[3]);
-}
-
-static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
-{
-    GGLcoord v[4][2];
-    v[0][0] = v0[0];    v[0][1] = v0[1];
-    v[1][0] = v1[0];    v[1][1] = v1[1];
-    v0 = v[0];
-    v1 = v[1];
-    
-    const GGLcoord dx = v0[0] - v1[0];
-    const GGLcoord dy = v0[1] - v1[1];
-    GGLcoord nx = -dy;
-    GGLcoord ny =  dx;
-
-    // generally, this will be well below 1.0
-    const GGLfixed norm = gglMulx(width, gglSqrtRecipx(nx*nx+ny*ny), 4);
-    nx = gglMulx(nx, norm, 21);
-    ny = gglMulx(ny, norm, 21);
-    
-    v[2][0] = v1[0];    v[2][1] = v1[1];
-    v[3][0] = v0[0];    v[3][1] = v0[1];
-    v[0][0] += nx;      v[0][1] += ny;
-    v[1][0] += nx;      v[1][1] += ny;
-    v[2][0] -= nx;      v[2][1] -= ny;
-    v[3][0] -= nx;      v[3][1] -= ny;
-    aapolyx(con, v[0], 4);        
-}
-
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Rect
-#endif
-
-void recti_validate(void *con, GGLint l, GGLint t, GGLint r, GGLint b)
-{
-    GGL_CONTEXT(c, con);
-    ggl_pick(c);
-    c->procs.recti = recti;
-    c->procs.recti(con, l, t, r, b);
-}
-
-void recti(void* con, GGLint l, GGLint t, GGLint r, GGLint b)
-{
-    GGL_CONTEXT(c, con);
-
-    // scissor...
-    if (l < GGLint(c->state.scissor.left))
-        l = GGLint(c->state.scissor.left);
-    if (t < GGLint(c->state.scissor.top))
-        t = GGLint(c->state.scissor.top);
-    if (r > GGLint(c->state.scissor.right))
-        r = GGLint(c->state.scissor.right);
-    if (b > GGLint(c->state.scissor.bottom))
-        b = GGLint(c->state.scissor.bottom);
-
-    int xc = r - l;
-    int yc = b - t;
-    if (xc>0 && yc>0) {
-        c->iterators.xl = l;
-        c->iterators.xr = r;
-        c->init_y(c, t);
-        c->rect(c, yc);
-    }
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Triangle / Debugging
-#endif
-
-static void scanline_set(context_t* c)
-{
-    int32_t x = c->iterators.xl;
-    size_t ct = c->iterators.xr - x;
-    int32_t y = c->iterators.y;
-    surface_t* cb = &(c->state.buffers.color);
-    const GGLFormat* fp = &(c->formats[cb->format]);
-    uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
-                            (x + (cb->stride * y)) * fp->size;
-    const size_t size = ct * fp->size;
-    memset(dst, 0xFF, size);
-}
-
-static void trianglex_debug(void* con,
-        const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
-    GGL_CONTEXT(c, con);
-    if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
-        aa_trianglex(con,v0,v1,v2);
-    } else {
-        trianglex_big(con,v0,v1,v2);
-    }
-	void (*save_scanline)(context_t*)  = c->scanline;
-    c->scanline = scanline_set;
-    linex(con, v0, v1, TRI_ONE);
-    linex(con, v1, v2, TRI_ONE);
-    linex(con, v2, v0, TRI_ONE);
-    c->scanline = save_scanline;
-}
-
-static void trianglex_xor(void* con,
-        const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
-    trianglex_big(con,v0,v1,v2);
-    trianglex_small(con,v0,v1,v2);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Triangle
-#endif
-
-void trianglex_validate(void *con,
-        const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
-    GGL_CONTEXT(c, con);
-    ggl_pick(c);
-    if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
-        c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : aa_trianglex;
-    } else {
-        c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : trianglex_big;
-    }
-    c->procs.trianglex(con, v0, v1, v2);
-}
-
-// ----------------------------------------------------------------------------
-
-void trianglex_small(void* con,
-        const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
-    GGL_CONTEXT(c, con);
-
-    // vertices are in 28.4 fixed point, which allows
-    // us to use 32 bits multiplies below.
-    int32_t x0 = v0[0];
-    int32_t y0 = v0[1];
-    int32_t x1 = v1[0];
-    int32_t y1 = v1[1];
-    int32_t x2 = v2[0];
-    int32_t y2 = v2[1];
-
-    int32_t dx01 = x0 - x1;
-    int32_t dy20 = y2 - y0;
-    int32_t dy01 = y0 - y1;
-    int32_t dx20 = x2 - x0;
-
-    // The code below works only with CCW triangles
-    // so if we get a CW triangle, we need to swap two of its vertices
-    if (dx01*dy20 < dy01*dx20) {
-        swap(x0, x1);
-        swap(y0, y1);
-        dx01 = x0 - x1;
-        dy01 = y0 - y1;
-        dx20 = x2 - x0;
-        dy20 = y2 - y0;
-    }
-    int32_t dx12 = x1 - x2;
-    int32_t dy12 = y1 - y2;
-
-    // bounding box & scissor
-    const int32_t bminx = TRI_FLOOR(min(x0, x1, x2)) >> TRI_FRACTION_BITS;
-    const int32_t bminy = TRI_FLOOR(min(y0, y1, y2)) >> TRI_FRACTION_BITS;
-    const int32_t bmaxx = TRI_CEIL( max(x0, x1, x2)) >> TRI_FRACTION_BITS;
-    const int32_t bmaxy = TRI_CEIL( max(y0, y1, y2)) >> TRI_FRACTION_BITS;
-    const int32_t minx = max(bminx, c->state.scissor.left);
-    const int32_t miny = max(bminy, c->state.scissor.top);
-    const int32_t maxx = min(bmaxx, c->state.scissor.right);
-    const int32_t maxy = min(bmaxy, c->state.scissor.bottom);
-    if ((minx >= maxx) || (miny >= maxy))
-        return; // too small or clipped out...
-
-    // step equations to the bounding box and snap to pixel center
-    const int32_t my = (miny << TRI_FRACTION_BITS) + TRI_HALF;
-    const int32_t mx = (minx << TRI_FRACTION_BITS) + TRI_HALF;
-    int32_t ey0 = dy01 * (x0 - mx) - dx01 * (y0 - my);
-    int32_t ey1 = dy12 * (x1 - mx) - dx12 * (y1 - my);
-    int32_t ey2 = dy20 * (x2 - mx) - dx20 * (y2 - my);
-
-    // right-exclusive fill rule, to avoid rare cases
-    // of over drawing
-    if (dy01<0 || (dy01 == 0 && dx01>0)) ey0++;
-    if (dy12<0 || (dy12 == 0 && dx12>0)) ey1++;
-    if (dy20<0 || (dy20 == 0 && dx20>0)) ey2++;
-    
-    c->init_y(c, miny);
-    for (int32_t y = miny; y < maxy; y++) {
-        int32_t ex0 = ey0;
-        int32_t ex1 = ey1;
-        int32_t ex2 = ey2;    
-        int32_t xl, xr;
-        for (xl=minx ; xl<maxx ; xl++) {
-            if (ex0>0 && ex1>0 && ex2>0)
-                break; // all strictly positive
-            ex0 -= dy01 << TRI_FRACTION_BITS;
-            ex1 -= dy12 << TRI_FRACTION_BITS;
-            ex2 -= dy20 << TRI_FRACTION_BITS;
-        }
-        xr = xl;
-        for ( ; xr<maxx ; xr++) {
-            if (!(ex0>0 && ex1>0 && ex2>0))
-                break; // not all strictly positive
-            ex0 -= dy01 << TRI_FRACTION_BITS;
-            ex1 -= dy12 << TRI_FRACTION_BITS;
-            ex2 -= dy20 << TRI_FRACTION_BITS;
-        }
-
-        if (xl < xr) {
-            c->iterators.xl = xl;
-            c->iterators.xr = xr;
-            c->scanline(c);
-        }
-        c->step_y(c);
-
-        ey0 += dx01 << TRI_FRACTION_BITS;
-        ey1 += dx12 << TRI_FRACTION_BITS;
-        ey2 += dx20 << TRI_FRACTION_BITS;
-    }
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-// the following routine fills a triangle via edge stepping, which
-// unfortunately requires divisions in the setup phase to get right,
-// it should probably only be used for relatively large trianges
-
-
-// x = y*DX/DY    (ou DX and DY are constants, DY > 0, et y >= 0)
-// 
-// for an equation of the type:
-//      x' = y*K/2^p     (with K and p constants "carefully chosen")
-// 
-// We can now do a DDA without precision loss. We define 'e' by:
-//      x' - x = y*(DX/DY - K/2^p) = y*e
-// 
-// If we choose K = round(DX*2^p/DY) then,
-//      abs(e) <= 1/2^(p+1) by construction
-// 
-// therefore abs(x'-x) = y*abs(e) <= y/2^(p+1) <= DY/2^(p+1) <= DMAX/2^(p+1)
-// 
-// which means that if DMAX <= 2^p, therefore abs(x-x') <= 1/2, including
-// at the last line. In fact, it's even a strict inequality except in one
-// extrem case (DY == DMAX et e = +/- 1/2)
-// 
-// Applying that to our coordinates, we need 2^p >= 4096*16 = 65536
-// so p = 16 is enough, we're so lucky!
-
-const int TRI_ITERATORS_BITS = 16;
-
-struct Edge
-{
-  int32_t  x;      // edge position in 16.16 coordinates
-  int32_t  x_incr; // on each step, increment x by that amount
-  int32_t  y_top;  // starting scanline, 16.4 format
-  int32_t  y_bot;
-};
-
-static void
-edge_dump( Edge*  edge )
-{
-  ALOGI( "  top=%d (%.3f)  bot=%d (%.3f)  x=%d (%.3f)  ix=%d (%.3f)",
-        edge->y_top, edge->y_top/float(TRI_ONE),
-		edge->y_bot, edge->y_bot/float(TRI_ONE),
-		edge->x, edge->x/float(FIXED_ONE),
-		edge->x_incr, edge->x_incr/float(FIXED_ONE) );
-}
-
-static void
-triangle_dump_edges( Edge*  edges,
-                     int            count )
-{ 
-    ALOGI( "%d edge%s:\n", count, count == 1 ? "" : "s" );
-	for ( ; count > 0; count--, edges++ )
-	  edge_dump( edges );
-}
-
-// the following function sets up an edge, it assumes
-// that ymin and ymax are in already in the 'reduced'
-// format
-static __attribute__((noinline))
-void edge_setup(
-        Edge*           edges,
-        int*            pcount,
-        const GGLcoord* p1,
-        const GGLcoord* p2,
-        int32_t         ymin,
-        int32_t         ymax )
-{
-	const GGLfixed*  top = p1;
-	const GGLfixed*  bot = p2;
-	Edge*    edge = edges + *pcount;
-
-	if (top[1] > bot[1]) {
-        swap(top, bot);
-	}
-
-	int  y1 = top[1] | 1;
-	int  y2 = bot[1] | 1;
-	int  dy = y2 - y1;
-
-	if ( dy == 0 || y1 > ymax || y2 < ymin )
-		return;
-
-	if ( y1 > ymin )
-		ymin = TRI_SNAP_NEXT_HALF(y1);
-	
-	if ( y2 < ymax )
-		ymax = TRI_SNAP_PREV_HALF(y2);
-
-	if ( ymin > ymax )  // when the edge doesn't cross any scanline
-	  return;
-
-	const int x1 = top[0];
-	const int dx = bot[0] - x1;
-    const int shift = TRI_ITERATORS_BITS - TRI_FRACTION_BITS;
-
-	// setup edge fields
-    // We add 0.5 to edge->x here because it simplifies the rounding
-    // in triangle_sweep_edges() -- this doesn't change the ordering of 'x'
-	edge->x      = (x1 << shift) + (1LU << (TRI_ITERATORS_BITS-1));
-	edge->x_incr = 0;
-	edge->y_top  = ymin;
-	edge->y_bot  = ymax;
-
-	if (ggl_likely(ymin <= ymax && dx)) {
-        edge->x_incr = gglDivQ16(dx, dy);
-    }
-    if (ggl_likely(y1 < ymin)) {
-        int32_t xadjust = (edge->x_incr * (ymin-y1)) >> TRI_FRACTION_BITS;
-        edge->x += xadjust;
-    }
-  
-	++*pcount;
-}
-
-
-static void
-triangle_sweep_edges( Edge*  left,
-                      Edge*  right,
-					  int            ytop,
-					  int            ybot,
-					  context_t*     c )
-{
-    int count = ((ybot - ytop)>>TRI_FRACTION_BITS) + 1;
-    if (count<=0) return;
-
-    // sort the edges horizontally
-    if ((left->x > right->x) || 
-        ((left->x == right->x) && (left->x_incr > right->x_incr))) {
-        swap(left, right);
-    }
-
-    int left_x = left->x;
-    int right_x = right->x;
-    const int left_xi = left->x_incr;
-    const int right_xi  = right->x_incr;
-    left->x  += left_xi * count;
-    right->x += right_xi * count;
-
-	const int xmin = c->state.scissor.left;
-	const int xmax = c->state.scissor.right;
-    do {
-        // horizontal scissoring
-        const int32_t xl = max(left_x  >> TRI_ITERATORS_BITS, xmin);
-        const int32_t xr = min(right_x >> TRI_ITERATORS_BITS, xmax);
-        left_x  += left_xi;
-        right_x += right_xi;
-        // invoke the scanline rasterizer
-        if (ggl_likely(xl < xr)) {
-            c->iterators.xl = xl;
-            c->iterators.xr = xr;
-            c->scanline(c);
-        }
-		c->step_y(c);
-	} while (--count);
-}
-
-
-void trianglex_big(void* con,
-        const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
-    GGL_CONTEXT(c, con);
-
-    Edge edges[3];
-	int num_edges = 0;
-	int32_t ymin = TRI_FROM_INT(c->state.scissor.top)    + TRI_HALF;
-	int32_t ymax = TRI_FROM_INT(c->state.scissor.bottom) - TRI_HALF;
-	    
-	edge_setup( edges, &num_edges, v0, v1, ymin, ymax );
-	edge_setup( edges, &num_edges, v0, v2, ymin, ymax );
-	edge_setup( edges, &num_edges, v1, v2, ymin, ymax );
-
-    if (ggl_unlikely(num_edges<2))  // for really tiny triangles that don't
-		return;                     // cross any scanline centers
-
-    Edge* left  = &edges[0];
-    Edge* right = &edges[1];
-    Edge* other = &edges[2];
-    int32_t y_top = min(left->y_top, right->y_top);
-    int32_t y_bot = max(left->y_bot, right->y_bot);
-
-	if (ggl_likely(num_edges==3)) {
-        y_top = min(y_top, edges[2].y_top);
-        y_bot = max(y_bot, edges[2].y_bot);
-		if (edges[0].y_top > y_top) {
-            other = &edges[0];
-            left  = &edges[2];
-		} else if (edges[1].y_top > y_top) {
-            other = &edges[1];
-            right = &edges[2];
-		}
-    }
-
-    c->init_y(c, y_top >> TRI_FRACTION_BITS);
-
-    int32_t y_mid = min(left->y_bot, right->y_bot);
-    triangle_sweep_edges( left, right, y_top, y_mid, c );
-
-    // second scanline sweep loop, if necessary
-    y_mid += TRI_ONE;
-    if (y_mid <= y_bot) {
-        ((left->y_bot == y_bot) ? right : left) = other;
-        if (other->y_top < y_mid) {
-            other->x += other->x_incr;
-        }
-        triangle_sweep_edges( left, right, y_mid, y_bot, c );
-    }
-}
-
-void aa_trianglex(void* con,
-        const GGLcoord* a, const GGLcoord* b, const GGLcoord* c)
-{
-    GGLcoord pts[6] = { a[0], a[1], b[0], b[1], c[0], c[1] };
-    aapolyx(con, pts, 3);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-struct AAEdge
-{
-    GGLfixed x;         // edge position in 12.16 coordinates
-    GGLfixed x_incr;    // on each y step, increment x by that amount
-    GGLfixed y_incr;    // on each x step, increment y by that amount
-    int16_t y_top;      // starting scanline, 12.4 format
-    int16_t y_bot;      // starting scanline, 12.4 format
-    void dump();
-};
-
-void AAEdge::dump()
-{
-    float tri  = 1.0f / TRI_ONE;
-    float iter = 1.0f / (1<<TRI_ITERATORS_BITS);
-    float fix  = 1.0f / FIXED_ONE;
-    ALOGD(   "x=%08x (%.3f), "
-            "x_incr=%08x (%.3f), y_incr=%08x (%.3f), "
-            "y_top=%08x (%.3f), y_bot=%08x (%.3f) ",
-        x, x*fix,
-        x_incr, x_incr*iter,
-        y_incr, y_incr*iter,
-        y_top, y_top*tri,
-        y_bot, y_bot*tri );
-}
-
-// the following function sets up an edge, it assumes
-// that ymin and ymax are in already in the 'reduced'
-// format
-static __attribute__((noinline))
-void aa_edge_setup(
-        AAEdge*         edges,
-        int*            pcount,
-        const GGLcoord* p1,
-        const GGLcoord* p2,
-        int32_t         ymin,
-        int32_t         ymax )
-{
-    const GGLfixed*  top = p1;
-    const GGLfixed*  bot = p2;
-    AAEdge* edge = edges + *pcount;
-
-    if (top[1] > bot[1])
-        swap(top, bot);
-
-    int  y1 = top[1];
-    int  y2 = bot[1];
-    int  dy = y2 - y1;
-
-    if (dy==0 || y1>ymax || y2<ymin)
-        return;
-
-    if (y1 > ymin)
-        ymin = y1;
-    
-    if (y2 < ymax)
-        ymax = y2;
-
-    const int x1 = top[0];
-    const int dx = bot[0] - x1;
-    const int shift = FIXED_BITS - TRI_FRACTION_BITS;
-
-    // setup edge fields
-    edge->x      = x1 << shift;
-    edge->x_incr = 0;
-    edge->y_top  = ymin;
-    edge->y_bot  = ymax;
-    edge->y_incr = 0x7FFFFFFF;
-
-    if (ggl_likely(ymin <= ymax && dx)) {
-        edge->x_incr = gglDivQ16(dx, dy);
-        if (dx != 0) {
-            edge->y_incr = abs(gglDivQ16(dy, dx));
-        }
-    }
-    if (ggl_likely(y1 < ymin)) {
-        int32_t xadjust = (edge->x_incr * (ymin-y1))
-                >> (TRI_FRACTION_BITS + TRI_ITERATORS_BITS - FIXED_BITS);
-        edge->x += xadjust;
-    }
-  
-    ++*pcount;
-}
-
-
-typedef int (*compar_t)(const void*, const void*);
-static int compare_edges(const AAEdge *e0, const AAEdge *e1) {
-    if (e0->y_top > e1->y_top)      return 1;
-    if (e0->y_top < e1->y_top)      return -1;
-    if (e0->x > e1->x)              return 1;
-    if (e0->x < e1->x)              return -1;
-    if (e0->x_incr > e1->x_incr)    return 1;
-    if (e0->x_incr < e1->x_incr)    return -1;
-    return 0; // same edges, should never happen
-}
-
-static inline 
-void SET_COVERAGE(int16_t*& p, int32_t value, ssize_t n)
-{
-    android_memset16((uint16_t*)p, value, n*2);
-    p += n;
-}
-
-static inline 
-void ADD_COVERAGE(int16_t*& p, int32_t value)
-{
-    value = *p + value;
-    if (value >= 0x8000)
-        value = 0x7FFF;
-    *p++ = value;
-}
-
-static inline
-void SUB_COVERAGE(int16_t*& p, int32_t value)
-{
-    value = *p - value;
-    value &= ~(value>>31);
-    *p++ = value;
-}
-
-void aapolyx(void* con,
-        const GGLcoord* pts, int count)
-{
-    /*
-     * NOTE: This routine assumes that the polygon has been clipped to the
-     * viewport already, that is, no vertex lies outside of the framebuffer.
-     * If this happens, the code below won't corrupt memory but the 
-     * coverage values may not be correct.
-     */
-    
-    GGL_CONTEXT(c, con);
-
-    // we do only quads for now (it's used for thick lines)
-    if ((count>4) || (count<2)) return;
-
-    // take scissor into account
-    const int xmin = c->state.scissor.left;
-    const int xmax = c->state.scissor.right;
-    if (xmin >= xmax) return;
-
-    // generate edges from the vertices
-    int32_t ymin = TRI_FROM_INT(c->state.scissor.top);
-    int32_t ymax = TRI_FROM_INT(c->state.scissor.bottom);
-    if (ymin >= ymax) return;
-
-    AAEdge edges[4];
-    int num_edges = 0;
-    GGLcoord const * p = pts;
-    for (int i=0 ; i<count-1 ; i++, p+=2) {
-        aa_edge_setup(edges, &num_edges, p, p+2, ymin, ymax);
-    }
-    aa_edge_setup(edges, &num_edges, p, pts, ymin, ymax );
-    if (ggl_unlikely(num_edges<2))
-        return;
-
-    // sort the edge list top to bottom, left to right.
-    qsort(edges, num_edges, sizeof(AAEdge), (compar_t)compare_edges);
-
-    int16_t* const covPtr = c->state.buffers.coverage;
-    memset(covPtr+xmin, 0, (xmax-xmin)*sizeof(*covPtr));
-
-    // now, sweep all edges in order
-    // start with the 2 first edges. We know that they share their top
-    // vertex, by construction.
-    int i = 2;
-    AAEdge* left  = &edges[0];
-    AAEdge* right = &edges[1];
-    int32_t yt = left->y_top;
-    GGLfixed l = left->x;
-    GGLfixed r = right->x;
-    int retire = 0;
-    int16_t* coverage;
-
-    // at this point we can initialize the rasterizer    
-    c->init_y(c, yt>>TRI_FRACTION_BITS);
-    c->iterators.xl = xmax;
-    c->iterators.xr = xmin;
-
-    do {
-        int32_t y = min(min(left->y_bot, right->y_bot), TRI_FLOOR(yt + TRI_ONE));
-        const int32_t shift = TRI_FRACTION_BITS + TRI_ITERATORS_BITS - FIXED_BITS;
-        const int cf_shift = (1 + TRI_FRACTION_BITS*2 + TRI_ITERATORS_BITS - 15);
-
-        // compute xmin and xmax for the left edge
-        GGLfixed l_min = gglMulAddx(left->x_incr, y - left->y_top, left->x, shift);
-        GGLfixed l_max = l;
-        l = l_min;
-        if (l_min > l_max)
-            swap(l_min, l_max);
-
-        // compute xmin and xmax for the right edge
-        GGLfixed r_min = gglMulAddx(right->x_incr, y - right->y_top, right->x, shift);
-        GGLfixed r_max = r;
-        r = r_min;
-        if (r_min > r_max)
-            swap(r_min, r_max);
-
-        // make sure we're not touching coverage values outside of the
-        // framebuffer
-        l_min &= ~(l_min>>31);
-        r_min &= ~(r_min>>31);
-        l_max &= ~(l_max>>31);
-        r_max &= ~(r_max>>31);
-        if (gglFixedToIntFloor(l_min) >= xmax) l_min = gglIntToFixed(xmax)-1;
-        if (gglFixedToIntFloor(r_min) >= xmax) r_min = gglIntToFixed(xmax)-1;
-        if (gglFixedToIntCeil(l_max) >= xmax)  l_max = gglIntToFixed(xmax)-1;
-        if (gglFixedToIntCeil(r_max) >= xmax)  r_max = gglIntToFixed(xmax)-1;
-
-        // compute the integer versions of the above
-        const GGLfixed l_min_i = gglFloorx(l_min);
-        const GGLfixed l_max_i = gglCeilx (l_max);
-        const GGLfixed r_min_i = gglFloorx(r_min);
-        const GGLfixed r_max_i = gglCeilx (r_max);
-
-        // clip horizontally using the scissor
-        const int xml = max(xmin, gglFixedToIntFloor(l_min_i));
-        const int xmr = min(xmax, gglFixedToIntFloor(r_max_i));
-
-        // if we just stepped to a new scanline, render the previous one.
-        // and clear the coverage buffer
-        if (retire) {
-            if (c->iterators.xl < c->iterators.xr)
-                c->scanline(c);
-            c->step_y(c);
-            memset(covPtr+xmin, 0, (xmax-xmin)*sizeof(*covPtr));
-            c->iterators.xl = xml;
-            c->iterators.xr = xmr;
-        } else {
-            // update the horizontal range of this scanline
-            c->iterators.xl = min(c->iterators.xl, xml);
-            c->iterators.xr = max(c->iterators.xr, xmr);
-        }
-
-        coverage = covPtr + gglFixedToIntFloor(l_min_i);
-        if (l_min_i == gglFloorx(l_max)) {
-            
-            /*
-             *  fully traverse this pixel vertically
-             *       l_max
-             *  +-----/--+  yt
-             *  |    /   |  
-             *  |   /    |
-             *  |  /     |
-             *  +-/------+  y
-             *   l_min  (l_min_i + TRI_ONE)
-             */
-              
-            GGLfixed dx = l_max - l_min;
-            int32_t dy = y - yt;
-            int cf = gglMulx((dx >> 1) + (l_min_i + FIXED_ONE - l_max), dy,
-                FIXED_BITS + TRI_FRACTION_BITS - 15);
-            ADD_COVERAGE(coverage, cf);
-            // all pixels on the right have cf = 1.0
-        } else {
-            /*
-             *  spans several pixels in one scanline
-             *            l_max
-             *  +--------+--/-----+  yt
-             *  |        |/       |
-             *  |       /|        |
-             *  |     /  |        |
-             *  +---/----+--------+  y
-             *   l_min (l_min_i + TRI_ONE)
-             */
-
-            // handle the first pixel separately...
-            const int32_t y_incr = left->y_incr;
-            int32_t dx = TRI_FROM_FIXED(l_min_i - l_min) + TRI_ONE;
-            int32_t cf = (dx * dx * y_incr) >> cf_shift;
-            ADD_COVERAGE(coverage, cf);
-
-            // following pixels get covered by y_incr, but we need
-            // to fix-up the cf to account for previous partial pixel
-            dx = TRI_FROM_FIXED(l_min - l_min_i);
-            cf -= (dx * dx * y_incr) >> cf_shift;
-            for (int x = l_min_i+FIXED_ONE ; x < l_max_i-FIXED_ONE ; x += FIXED_ONE) {
-                cf += y_incr >> (TRI_ITERATORS_BITS-15);
-                ADD_COVERAGE(coverage, cf);
-            }
-            
-            // and the last pixel
-            dx = TRI_FROM_FIXED(l_max - l_max_i) - TRI_ONE;
-            cf += (dx * dx * y_incr) >> cf_shift;
-            ADD_COVERAGE(coverage, cf);
-        }
-        
-        // now, fill up all fully covered pixels
-        coverage = covPtr + gglFixedToIntFloor(l_max_i);
-        int cf = ((y - yt) << (15 - TRI_FRACTION_BITS));
-        if (ggl_likely(cf >= 0x8000)) {
-            SET_COVERAGE(coverage, 0x7FFF, ((r_max - l_max_i)>>FIXED_BITS)+1);
-        } else {
-            for (int x=l_max_i ; x<r_max ; x+=FIXED_ONE) {
-                ADD_COVERAGE(coverage, cf);
-            }
-        }
-        
-        // subtract the coverage of the right edge
-        coverage = covPtr + gglFixedToIntFloor(r_min_i); 
-        if (r_min_i == gglFloorx(r_max)) {
-            GGLfixed dx = r_max - r_min;
-            int32_t dy = y - yt;
-            int cf = gglMulx((dx >> 1) + (r_min_i + FIXED_ONE - r_max), dy,
-                FIXED_BITS + TRI_FRACTION_BITS - 15);
-            SUB_COVERAGE(coverage, cf);
-            // all pixels on the right have cf = 1.0
-        } else {
-            // handle the first pixel separately...
-            const int32_t y_incr = right->y_incr;
-            int32_t dx = TRI_FROM_FIXED(r_min_i - r_min) + TRI_ONE;
-            int32_t cf = (dx * dx * y_incr) >> cf_shift;
-            SUB_COVERAGE(coverage, cf);
-            
-            // following pixels get covered by y_incr, but we need
-            // to fix-up the cf to account for previous partial pixel
-            dx = TRI_FROM_FIXED(r_min - r_min_i);
-            cf -= (dx * dx * y_incr) >> cf_shift;
-            for (int x = r_min_i+FIXED_ONE ; x < r_max_i-FIXED_ONE ; x += FIXED_ONE) {
-                cf += y_incr >> (TRI_ITERATORS_BITS-15);
-                SUB_COVERAGE(coverage, cf);
-            }
-            
-            // and the last pixel
-            dx = TRI_FROM_FIXED(r_max - r_max_i) - TRI_ONE;
-            cf += (dx * dx * y_incr) >> cf_shift;
-            SUB_COVERAGE(coverage, cf);
-        }
-
-        // did we reach the end of an edge? if so, get a new one.
-        if (y == left->y_bot || y == right->y_bot) {
-            // bail out if we're done
-            if (i>=num_edges)
-                break;
-            if (y == left->y_bot)
-                left = &edges[i++];
-            if (y == right->y_bot)
-                right = &edges[i++];
-        }
-
-        // next scanline
-        yt = y;
-        
-        // did we just finish a scanline?        
-        retire = (y << (32-TRI_FRACTION_BITS)) == 0;
-    } while (true);
-
-    // render the last scanline
-    if (c->iterators.xl < c->iterators.xr)
-        c->scanline(c);
-}
-
-}; // namespace android
diff --git a/libpixelflinger/trap.h b/libpixelflinger/trap.h
deleted file mode 100644
index 7cce7b3..0000000
--- a/libpixelflinger/trap.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* libs/pixelflinger/trap.h
-**
-** Copyright 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 ANDROID_TRAP_H
-#define ANDROID_TRAP_H
-
-#include <private/pixelflinger/ggl_context.h>
-
-namespace android {
-
-void ggl_init_trap(context_t* c);
-void ggl_state_changed(context_t* c, int flags);
-
-}; // namespace android
-
-#endif
diff --git a/libprocessgroup/profiles/cgroups.json b/libprocessgroup/profiles/cgroups.json
index 0341902..4518487 100644
--- a/libprocessgroup/profiles/cgroups.json
+++ b/libprocessgroup/profiles/cgroups.json
@@ -39,19 +39,21 @@
       "Mode": "0755",
       "UID": "system",
       "GID": "system"
-    },
-    {
-      "Controller": "freezer",
-      "Path": "/dev/freezer",
-      "Mode": "0755",
-      "UID": "system",
-      "GID": "system"
     }
   ],
   "Cgroups2": {
-    "Path": "/dev/cg2_bpf",
-    "Mode": "0600",
-    "UID": "root",
-    "GID": "root"
+    "Path": "/sys/fs/cgroup",
+    "Mode": "0755",
+    "UID": "system",
+    "GID": "system",
+    "Controllers": [
+      {
+        "Controller": "freezer",
+        "Path": "freezer",
+        "Mode": "0755",
+        "UID": "system",
+        "GID": "system"
+      }
+    ]
   }
 }
diff --git a/libprocessgroup/profiles/cgroups.proto b/libprocessgroup/profiles/cgroups.proto
index f4070c5..13adcae 100644
--- a/libprocessgroup/profiles/cgroups.proto
+++ b/libprocessgroup/profiles/cgroups.proto
@@ -24,19 +24,24 @@
     Cgroups2 cgroups2 = 2 [json_name = "Cgroups2"];
 }
 
-// Next: 6
+// Next: 7
 message Cgroup {
     string controller = 1 [json_name = "Controller"];
     string path = 2 [json_name = "Path"];
     string mode = 3 [json_name = "Mode"];
     string uid = 4 [json_name = "UID"];
     string gid = 5 [json_name = "GID"];
+// Booleans default to false when not specified. File reconstruction fails
+// when a boolean is specified as false, so leave unspecified in that case
+// https://developers.google.com/protocol-buffers/docs/proto3#default
+    bool needs_activation = 6 [json_name = "NeedsActivation"];
 }
 
-// Next: 5
+// Next: 6
 message Cgroups2 {
     string path = 1 [json_name = "Path"];
     string mode = 2 [json_name = "Mode"];
     string uid = 3 [json_name = "UID"];
     string gid = 4 [json_name = "GID"];
+    repeated Cgroup controllers = 5 [json_name = "Controllers"];
 }
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index a515e58..c4dbf8e 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -49,6 +49,11 @@
       "Name": "UClampMax",
       "Controller": "cpu",
       "File": "cpu.uclamp.max"
+    },
+    {
+      "Name": "FreezerState",
+      "Controller": "freezer",
+      "File": "cgroup.freeze"
     }
   ],
 
@@ -74,7 +79,7 @@
           "Params":
           {
             "Controller": "freezer",
-            "Path": "frozen"
+            "Path": ""
           }
         }
       ]
@@ -87,7 +92,7 @@
           "Params":
           {
             "Controller": "freezer",
-            "Path": ""
+            "Path": "../"
           }
         }
       ]
@@ -531,6 +536,32 @@
           }
         }
       ]
+    },
+    {
+      "Name": "FreezerDisabled",
+      "Actions": [
+        {
+          "Name": "SetAttribute",
+          "Params":
+          {
+            "Name": "FreezerState",
+            "Value": "0"
+          }
+        }
+      ]
+    },
+    {
+      "Name": "FreezerEnabled",
+      "Actions": [
+        {
+          "Name": "SetAttribute",
+          "Params":
+          {
+            "Name": "FreezerState",
+            "Value": "1"
+          }
+        }
+      ]
     }
   ],
 
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
index 135904b..bf06bbc 100644
--- a/libsparse/Android.bp
+++ b/libsparse/Android.bp
@@ -6,6 +6,7 @@
     ramdisk_available: true,
     recovery_available: true,
     unique_host_soname: true,
+    vendor_available: true,
     srcs: [
         "backed_block.cpp",
         "output_file.cpp",
diff --git a/libsparse/backed_block.cpp b/libsparse/backed_block.cpp
index f3d8022..6229e7c 100644
--- a/libsparse/backed_block.cpp
+++ b/libsparse/backed_block.cpp
@@ -25,7 +25,7 @@
 
 struct backed_block {
   unsigned int block;
-  unsigned int len;
+  uint64_t len;
   enum backed_block_type type;
   union {
     struct {
@@ -60,7 +60,7 @@
   return bb->next;
 }
 
-unsigned int backed_block_len(struct backed_block* bb) {
+uint64_t backed_block_len(struct backed_block* bb) {
   return bb->len;
 }
 
@@ -270,7 +270,7 @@
 }
 
 /* Queues a fill block of memory to be written to the specified data blocks */
-int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, unsigned int len,
+int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, uint64_t len,
                           unsigned int block) {
   struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
   if (bb == nullptr) {
@@ -287,7 +287,7 @@
 }
 
 /* Queues a block of memory to be written to the specified data blocks */
-int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned int len,
+int backed_block_add_data(struct backed_block_list* bbl, void* data, uint64_t len,
                           unsigned int block) {
   struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
   if (bb == nullptr) {
@@ -305,7 +305,7 @@
 
 /* Queues a chunk of a file on disk to be written to the specified data blocks */
 int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
-                          unsigned int len, unsigned int block) {
+                          uint64_t len, unsigned int block) {
   struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
   if (bb == nullptr) {
     return -ENOMEM;
@@ -322,7 +322,7 @@
 }
 
 /* Queues a chunk of a fd to be written to the specified data blocks */
-int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, unsigned int len,
+int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, uint64_t len,
                         unsigned int block) {
   struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
   if (bb == nullptr) {
diff --git a/libsparse/backed_block.h b/libsparse/backed_block.h
index 3a75460..71a8969 100644
--- a/libsparse/backed_block.h
+++ b/libsparse/backed_block.h
@@ -29,18 +29,18 @@
   BACKED_BLOCK_FILL,
 };
 
-int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned int len,
+int backed_block_add_data(struct backed_block_list* bbl, void* data, uint64_t len,
                           unsigned int block);
-int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, unsigned int len,
+int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, uint64_t len,
                           unsigned int block);
 int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
-                          unsigned int len, unsigned int block);
-int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, unsigned int len,
+                          uint64_t len, unsigned int block);
+int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, uint64_t len,
                         unsigned int block);
 
 struct backed_block* backed_block_iter_new(struct backed_block_list* bbl);
 struct backed_block* backed_block_iter_next(struct backed_block* bb);
-unsigned int backed_block_len(struct backed_block* bb);
+uint64_t backed_block_len(struct backed_block* bb);
 unsigned int backed_block_block(struct backed_block* bb);
 void* backed_block_data(struct backed_block* bb);
 const char* backed_block_filename(struct backed_block* bb);
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 3d5fb0c..2f75349 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -75,8 +75,7 @@
  *
  * Returns 0 on success, negative errno on error.
  */
-int sparse_file_add_data(struct sparse_file *s,
-		void *data, unsigned int len, unsigned int block);
+int sparse_file_add_data(struct sparse_file* s, void* data, uint64_t len, unsigned int block);
 
 /**
  * sparse_file_add_fill - associate a fill chunk with a sparse file
@@ -93,8 +92,8 @@
  *
  * Returns 0 on success, negative errno on error.
  */
-int sparse_file_add_fill(struct sparse_file *s,
-		uint32_t fill_val, unsigned int len, unsigned int block);
+int sparse_file_add_fill(struct sparse_file* s, uint32_t fill_val, uint64_t len,
+                         unsigned int block);
 
 /**
  * sparse_file_add_file - associate a chunk of a file with a sparse file
@@ -116,9 +115,8 @@
  *
  * Returns 0 on success, negative errno on error.
  */
-int sparse_file_add_file(struct sparse_file *s,
-		const char *filename, int64_t file_offset, unsigned int len,
-		unsigned int block);
+int sparse_file_add_file(struct sparse_file* s, const char* filename, int64_t file_offset,
+                         uint64_t len, unsigned int block);
 
 /**
  * sparse_file_add_file - associate a chunk of a file with a sparse file
@@ -143,8 +141,8 @@
  *
  * Returns 0 on success, negative errno on error.
  */
-int sparse_file_add_fd(struct sparse_file *s,
-		int fd, int64_t file_offset, unsigned int len, unsigned int block);
+int sparse_file_add_fd(struct sparse_file* s, int fd, int64_t file_offset, uint64_t len,
+                       unsigned int block);
 
 /**
  * sparse_file_write - write a sparse file to a file
diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp
index b883c13..b2c5407 100644
--- a/libsparse/output_file.cpp
+++ b/libsparse/output_file.cpp
@@ -65,9 +65,9 @@
 };
 
 struct sparse_file_ops {
-  int (*write_data_chunk)(struct output_file* out, unsigned int len, void* data);
-  int (*write_fill_chunk)(struct output_file* out, unsigned int len, uint32_t fill_val);
-  int (*write_skip_chunk)(struct output_file* out, int64_t len);
+  int (*write_data_chunk)(struct output_file* out, uint64_t len, void* data);
+  int (*write_fill_chunk)(struct output_file* out, uint64_t len, uint32_t fill_val);
+  int (*write_skip_chunk)(struct output_file* out, uint64_t len);
   int (*write_end_chunk)(struct output_file* out);
 };
 
@@ -316,7 +316,7 @@
   return 0;
 }
 
-static int write_sparse_skip_chunk(struct output_file* out, int64_t skip_len) {
+static int write_sparse_skip_chunk(struct output_file* out, uint64_t skip_len) {
   chunk_header_t chunk_header;
   int ret;
 
@@ -340,9 +340,10 @@
   return 0;
 }
 
-static int write_sparse_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
+static int write_sparse_fill_chunk(struct output_file* out, uint64_t len, uint32_t fill_val) {
   chunk_header_t chunk_header;
-  int rnd_up_len, count;
+  uint64_t rnd_up_len;
+  int count;
   int ret;
 
   /* Round up the fill length to a multiple of the block size */
@@ -370,9 +371,9 @@
   return 0;
 }
 
-static int write_sparse_data_chunk(struct output_file* out, unsigned int len, void* data) {
+static int write_sparse_data_chunk(struct output_file* out, uint64_t len, void* data) {
   chunk_header_t chunk_header;
-  int rnd_up_len, zero_len;
+  uint64_t rnd_up_len, zero_len;
   int ret;
 
   /* Round up the data length to a multiple of the block size */
@@ -437,9 +438,9 @@
     .write_end_chunk = write_sparse_end_chunk,
 };
 
-static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data) {
+static int write_normal_data_chunk(struct output_file* out, uint64_t len, void* data) {
   int ret;
-  unsigned int rnd_up_len = ALIGN(len, out->block_size);
+  uint64_t rnd_up_len = ALIGN(len, out->block_size);
 
   ret = out->ops->write(out, data, len);
   if (ret < 0) {
@@ -453,10 +454,10 @@
   return ret;
 }
 
-static int write_normal_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
+static int write_normal_fill_chunk(struct output_file* out, uint64_t len, uint32_t fill_val) {
   int ret;
   unsigned int i;
-  unsigned int write_len;
+  uint64_t write_len;
 
   /* Initialize fill_buf with the fill_val */
   for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
@@ -464,7 +465,7 @@
   }
 
   while (len) {
-    write_len = std::min(len, out->block_size);
+    write_len = std::min(len, (uint64_t)out->block_size);
     ret = out->ops->write(out, out->fill_buf, write_len);
     if (ret < 0) {
       return ret;
@@ -476,7 +477,7 @@
   return 0;
 }
 
-static int write_normal_skip_chunk(struct output_file* out, int64_t len) {
+static int write_normal_skip_chunk(struct output_file* out, uint64_t len) {
   return out->ops->skip(out, len);
 }
 
@@ -639,16 +640,16 @@
 }
 
 /* Write a contiguous region of data blocks from a memory buffer */
-int write_data_chunk(struct output_file* out, unsigned int len, void* data) {
+int write_data_chunk(struct output_file* out, uint64_t len, void* data) {
   return out->sparse_ops->write_data_chunk(out, len, data);
 }
 
 /* Write a contiguous region of data blocks with a fill value */
-int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
+int write_fill_chunk(struct output_file* out, uint64_t len, uint32_t fill_val) {
   return out->sparse_ops->write_fill_chunk(out, len, fill_val);
 }
 
-int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset) {
+int write_fd_chunk(struct output_file* out, uint64_t len, int fd, int64_t offset) {
   auto m = android::base::MappedFile::FromFd(fd, offset, len, PROT_READ);
   if (!m) return -errno;
 
@@ -656,7 +657,7 @@
 }
 
 /* Write a contiguous region of data blocks from a file */
-int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset) {
+int write_file_chunk(struct output_file* out, uint64_t len, const char* file, int64_t offset) {
   int ret;
 
   int file_fd = open(file, O_RDONLY | O_BINARY);
@@ -671,6 +672,6 @@
   return ret;
 }
 
-int write_skip_chunk(struct output_file* out, int64_t len) {
+int write_skip_chunk(struct output_file* out, uint64_t len) {
   return out->sparse_ops->write_skip_chunk(out, len);
 }
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
index 278430b..ecbcdf3 100644
--- a/libsparse/output_file.h
+++ b/libsparse/output_file.h
@@ -30,11 +30,11 @@
 struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv,
                                               unsigned int block_size, int64_t len, int gz,
                                               int sparse, int chunks, int crc);
-int write_data_chunk(struct output_file* out, unsigned int len, void* data);
-int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val);
-int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset);
-int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset);
-int write_skip_chunk(struct output_file* out, int64_t len);
+int write_data_chunk(struct output_file* out, uint64_t len, void* data);
+int write_fill_chunk(struct output_file* out, uint64_t len, uint32_t fill_val);
+int write_file_chunk(struct output_file* out, uint64_t len, const char* file, int64_t offset);
+int write_fd_chunk(struct output_file* out, uint64_t len, int fd, int64_t offset);
+int write_skip_chunk(struct output_file* out, uint64_t len);
 void output_file_close(struct output_file* out);
 
 int read_all(int fd, void* buf, size_t len);
diff --git a/libsparse/sparse.cpp b/libsparse/sparse.cpp
index 8622b4c..396e7eb 100644
--- a/libsparse/sparse.cpp
+++ b/libsparse/sparse.cpp
@@ -50,21 +50,21 @@
   free(s);
 }
 
-int sparse_file_add_data(struct sparse_file* s, void* data, unsigned int len, unsigned int block) {
+int sparse_file_add_data(struct sparse_file* s, void* data, uint64_t len, unsigned int block) {
   return backed_block_add_data(s->backed_block_list, data, len, block);
 }
 
-int sparse_file_add_fill(struct sparse_file* s, uint32_t fill_val, unsigned int len,
+int sparse_file_add_fill(struct sparse_file* s, uint32_t fill_val, uint64_t len,
                          unsigned int block) {
   return backed_block_add_fill(s->backed_block_list, fill_val, len, block);
 }
 
 int sparse_file_add_file(struct sparse_file* s, const char* filename, int64_t file_offset,
-                         unsigned int len, unsigned int block) {
+                         uint64_t len, unsigned int block) {
   return backed_block_add_file(s->backed_block_list, filename, file_offset, len, block);
 }
 
-int sparse_file_add_fd(struct sparse_file* s, int fd, int64_t file_offset, unsigned int len,
+int sparse_file_add_fd(struct sparse_file* s, int fd, int64_t file_offset, uint64_t len,
                        unsigned int block) {
   return backed_block_add_fd(s->backed_block_list, fd, file_offset, len, block);
 }
diff --git a/libstats/pull/Android.bp b/libstats/pull/Android.bp
new file mode 100644
index 0000000..a8b4a4f
--- /dev/null
+++ b/libstats/pull/Android.bp
@@ -0,0 +1,110 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+// ==========================================================
+// Native library to register a pull atom callback with statsd
+// ==========================================================
+cc_defaults {
+    name: "libstatspull_defaults",
+    srcs: [
+        "stats_pull_atom_callback.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "libbinder_ndk",
+        "liblog",
+        "libstatssocket",
+    ],
+    static_libs: [
+        "libutils",
+        "statsd-aidl-ndk_platform",
+    ],
+}
+cc_library_shared {
+    name: "libstatspull",
+    defaults: [
+        "libstatspull_defaults"
+    ],
+    // enumerate stable entry points for APEX use
+    stubs: {
+        symbol_file: "libstatspull.map.txt",
+        versions: [
+            "30",
+        ],
+    },
+    apex_available: [
+        "com.android.os.statsd",
+        "test_com.android.os.statsd",
+    ],
+
+    stl: "libc++_static",
+
+    // TODO(b/151102177): Enable it when the build error is fixed.
+    header_abi_checker: {
+        enabled: false,
+    },
+}
+
+// ONLY USE IN TESTS.
+cc_library_static {
+    name: "libstatspull_private",
+    defaults: [
+        "libstatspull_defaults",
+    ],
+    visibility: [
+        "//frameworks/base/apex/statsd/tests/libstatspull",
+    ],
+}
+
+// Note: These unit tests only test PullAtomMetadata.
+// For full E2E tests of libstatspull, use LibStatsPullTests
+cc_test {
+    name: "libstatspull_test",
+    srcs: [
+        "tests/pull_atom_metadata_test.cpp",
+    ],
+    shared_libs: [
+        "libstatspull",
+        "libstatssocket",
+    ],
+    test_suites: ["general-tests", "mts"],
+    test_config: "libstatspull_test.xml",
+
+    //TODO(b/153588990): Remove when the build system properly separates 
+    //32bit and 64bit architectures.
+    compile_multilib: "both",
+    multilib: {
+        lib64: {
+            suffix: "64",
+        },
+        lib32: {
+            suffix: "32",
+        },
+    },
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-variable",
+        "-Wno-unused-function",
+        "-Wno-unused-parameter",
+    ],
+    require_root: true,
+}
diff --git a/libstats/pull/OWNERS b/libstats/pull/OWNERS
new file mode 100644
index 0000000..7855774
--- /dev/null
+++ b/libstats/pull/OWNERS
@@ -0,0 +1,7 @@
+joeo@google.com
+muhammadq@google.com
+ruchirr@google.com
+singhtejinder@google.com
+tsaichristine@google.com
+yaochen@google.com
+yro@google.com
diff --git a/libstats/pull/TEST_MAPPING b/libstats/pull/TEST_MAPPING
new file mode 100644
index 0000000..76f4f02
--- /dev/null
+++ b/libstats/pull/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit" : [
+    {
+      "name" : "libstatspull_test"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/libstats/pull/include/stats_pull_atom_callback.h b/libstats/pull/include/stats_pull_atom_callback.h
new file mode 100644
index 0000000..17df584
--- /dev/null
+++ b/libstats/pull/include/stats_pull_atom_callback.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <stats_event.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Opaque struct representing the metadata for registering an AStatsManager_PullAtomCallback.
+ */
+struct AStatsManager_PullAtomMetadata;
+typedef struct AStatsManager_PullAtomMetadata AStatsManager_PullAtomMetadata;
+
+/**
+ * Allocate and initialize new PullAtomMetadata.
+ *
+ * Must call AStatsManager_PullAtomMetadata_release to free the memory.
+ */
+AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain();
+
+/**
+ * Frees the memory held by this PullAtomMetadata
+ *
+ * After calling this, the PullAtomMetadata must not be used or modified in any way.
+ */
+void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata);
+
+/**
+ * Set the cool down time of the pull in milliseconds. If two successive pulls are issued
+ * within the cool down, a cached version of the first will be used for the second. The minimum
+ * allowed cool down is one second.
+ */
+void AStatsManager_PullAtomMetadata_setCoolDownMillis(AStatsManager_PullAtomMetadata* metadata,
+                                                      int64_t cool_down_millis);
+
+/**
+ * Get the cool down time of the pull in milliseconds.
+ */
+int64_t AStatsManager_PullAtomMetadata_getCoolDownMillis(AStatsManager_PullAtomMetadata* metadata);
+
+/**
+ * Set the maximum time the pull can take in milliseconds.
+ * The maximum allowed timeout is 10 seconds.
+ */
+void AStatsManager_PullAtomMetadata_setTimeoutMillis(AStatsManager_PullAtomMetadata* metadata,
+                                                     int64_t timeout_millis);
+
+/**
+ * Get the maximum time the pull can take in milliseconds.
+ */
+int64_t AStatsManager_PullAtomMetadata_getTimeoutMillis(AStatsManager_PullAtomMetadata* metadata);
+
+/**
+ * Set the additive fields of this pulled atom.
+ *
+ * This is only applicable for atoms which have a uid field. When tasks are run in
+ * isolated processes, the data will be attributed to the host uid. Additive fields
+ * will be combined when the non-additive fields are the same.
+ */
+void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
+                                                      int32_t* additive_fields, int32_t num_fields);
+
+/**
+ * Get the number of additive fields for this pulled atom. This is intended to be called before
+ * AStatsManager_PullAtomMetadata_getAdditiveFields to determine the size of the array.
+ */
+int32_t AStatsManager_PullAtomMetadata_getNumAdditiveFields(
+        AStatsManager_PullAtomMetadata* metadata);
+
+/**
+ * Get the additive fields of this pulled atom.
+ *
+ * \param fields an output parameter containing the additive fields for this PullAtomMetadata.
+ *               Fields is an array and it is assumed that it is at least as large as the number of
+ *               additive fields, which can be obtained by calling
+ *               AStatsManager_PullAtomMetadata_getNumAdditiveFields.
+ */
+void AStatsManager_PullAtomMetadata_getAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
+                                                      int32_t* fields);
+
+/**
+ * Return codes for the result of a pull.
+ */
+typedef int32_t AStatsManager_PullAtomCallbackReturn;
+enum {
+    // Value indicating that this pull was successful and that the result should be used.
+    AStatsManager_PULL_SUCCESS = 0,
+    // Value indicating that this pull was unsuccessful and that the result should not be used.
+    AStatsManager_PULL_SKIP = 1,
+};
+
+/**
+ * Opaque struct representing a list of AStatsEvent objects.
+ */
+struct AStatsEventList;
+typedef struct AStatsEventList AStatsEventList;
+
+/**
+ * Appends and returns an AStatsEvent to the end of the AStatsEventList.
+ *
+ * If an AStatsEvent is obtained in this manner, the memory is internally managed and
+ * AStatsEvent_release does not need to be called. The lifetime of the AStatsEvent is that of the
+ * AStatsEventList.
+ *
+ * The AStatsEvent does still need to be built by calling AStatsEvent_build.
+ */
+AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data);
+
+/**
+ * Callback interface for pulling atoms requested by the stats service.
+ *
+ * \param atom_tag the tag of the atom to pull.
+ * \param data an output parameter in which the caller should fill the results of the pull. This
+ *             param cannot be NULL and it's lifetime is as long as the execution of the callback.
+ *             It must not be accessed or modified after returning from the callback.
+ * \param cookie the opaque pointer passed in AStatsManager_registerPullAtomCallback.
+ * \return AStatsManager_PULL_SUCCESS if the pull was successful, or AStatsManager_PULL_SKIP if not.
+ */
+typedef AStatsManager_PullAtomCallbackReturn (*AStatsManager_PullAtomCallback)(
+        int32_t atom_tag, AStatsEventList* data, void* cookie);
+/**
+ * Sets a callback for an atom when that atom is to be pulled. The stats service will
+ * invoke the callback when the stats service determines that this atom needs to be
+ * pulled.
+ *
+ * Requires the REGISTER_STATS_PULL_ATOM permission.
+ *
+ * \param atom_tag          The tag of the atom for this pull atom callback.
+ * \param metadata          Optional metadata specifying the timeout, cool down time, and
+ *                          additive fields for mapping isolated to host uids.
+ *                          This param is nullable, in which case defaults will be used.
+ * \param callback          The callback to be invoked when the stats service pulls the atom.
+ * \param cookie            A pointer that will be passed back to the callback.
+ *                          It has no meaning to statsd.
+ */
+void AStatsManager_setPullAtomCallback(int32_t atom_tag, AStatsManager_PullAtomMetadata* metadata,
+                                       AStatsManager_PullAtomCallback callback, void* cookie);
+
+/**
+ * Clears a callback for an atom when that atom is to be pulled. Note that any ongoing
+ * pulls will still occur.
+ *
+ * Requires the REGISTER_STATS_PULL_ATOM permission.
+ *
+ * \param atomTag           The tag of the atom of which to unregister
+ */
+void AStatsManager_clearPullAtomCallback(int32_t atom_tag);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libstats/pull/libstatspull.map.txt b/libstats/pull/libstatspull.map.txt
new file mode 100644
index 0000000..e0e851a
--- /dev/null
+++ b/libstats/pull/libstatspull.map.txt
@@ -0,0 +1,17 @@
+LIBSTATSPULL {
+    global:
+        AStatsManager_PullAtomMetadata_obtain; # apex # introduced=30
+        AStatsManager_PullAtomMetadata_release; # apex # introduced=30
+        AStatsManager_PullAtomMetadata_setCoolDownMillis; # apex # introduced=30
+        AStatsManager_PullAtomMetadata_getCoolDownMillis; # apex # introduced=30
+        AStatsManager_PullAtomMetadata_setTimeoutMillis; # apex # introduced=30
+        AStatsManager_PullAtomMetadata_getTimeoutMillis; # apex # introduced=30
+        AStatsManager_PullAtomMetadata_setAdditiveFields; # apex # introduced=30
+        AStatsManager_PullAtomMetadata_getNumAdditiveFields; # apex # introduced=30
+        AStatsManager_PullAtomMetadata_getAdditiveFields; # apex # introduced=30
+        AStatsEventList_addStatsEvent; # apex # introduced=30
+        AStatsManager_setPullAtomCallback; # apex # introduced=30
+        AStatsManager_clearPullAtomCallback; # apex # introduced=30
+    local:
+        *;
+};
diff --git a/libstats/pull/libstatspull_test.xml b/libstats/pull/libstatspull_test.xml
new file mode 100644
index 0000000..233fc1f
--- /dev/null
+++ b/libstats/pull/libstatspull_test.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs libstatspull_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+    <option name="test-suite-tag" value="mts" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+       <option name="cleanup" value="true" />
+       <option name="push" value="libstatspull_test->/data/local/tmp/libstatspull_test" />
+       <option name="append-bitness" value="true" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="libstatspull_test" />
+    </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.os.statsd" />
+    </object>
+</configuration>
diff --git a/libstats/pull/stats_pull_atom_callback.cpp b/libstats/pull/stats_pull_atom_callback.cpp
new file mode 100644
index 0000000..478cae7
--- /dev/null
+++ b/libstats/pull/stats_pull_atom_callback.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <map>
+#include <thread>
+#include <vector>
+
+#include <stats_event.h>
+#include <stats_pull_atom_callback.h>
+
+#include <aidl/android/os/BnPullAtomCallback.h>
+#include <aidl/android/os/IPullAtomResultReceiver.h>
+#include <aidl/android/os/IStatsd.h>
+#include <aidl/android/util/StatsEventParcel.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+
+using Status = ::ndk::ScopedAStatus;
+using aidl::android::os::BnPullAtomCallback;
+using aidl::android::os::IPullAtomResultReceiver;
+using aidl::android::os::IStatsd;
+using aidl::android::util::StatsEventParcel;
+using ::ndk::SharedRefBase;
+
+struct AStatsEventList {
+    std::vector<AStatsEvent*> data;
+};
+
+AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data) {
+    AStatsEvent* event = AStatsEvent_obtain();
+    pull_data->data.push_back(event);
+    return event;
+}
+
+static const int64_t DEFAULT_COOL_DOWN_MILLIS = 1000LL;  // 1 second.
+static const int64_t DEFAULT_TIMEOUT_MILLIS = 2000LL;    // 2 seconds.
+
+struct AStatsManager_PullAtomMetadata {
+    int64_t cool_down_millis;
+    int64_t timeout_millis;
+    std::vector<int32_t> additive_fields;
+};
+
+AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain() {
+    AStatsManager_PullAtomMetadata* metadata = new AStatsManager_PullAtomMetadata();
+    metadata->cool_down_millis = DEFAULT_COOL_DOWN_MILLIS;
+    metadata->timeout_millis = DEFAULT_TIMEOUT_MILLIS;
+    metadata->additive_fields = std::vector<int32_t>();
+    return metadata;
+}
+
+void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata) {
+    delete metadata;
+}
+
+void AStatsManager_PullAtomMetadata_setCoolDownMillis(AStatsManager_PullAtomMetadata* metadata,
+                                                      int64_t cool_down_millis) {
+    metadata->cool_down_millis = cool_down_millis;
+}
+
+int64_t AStatsManager_PullAtomMetadata_getCoolDownMillis(AStatsManager_PullAtomMetadata* metadata) {
+    return metadata->cool_down_millis;
+}
+
+void AStatsManager_PullAtomMetadata_setTimeoutMillis(AStatsManager_PullAtomMetadata* metadata,
+                                                     int64_t timeout_millis) {
+    metadata->timeout_millis = timeout_millis;
+}
+
+int64_t AStatsManager_PullAtomMetadata_getTimeoutMillis(AStatsManager_PullAtomMetadata* metadata) {
+    return metadata->timeout_millis;
+}
+
+void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
+                                                      int32_t* additive_fields,
+                                                      int32_t num_fields) {
+    metadata->additive_fields.assign(additive_fields, additive_fields + num_fields);
+}
+
+int32_t AStatsManager_PullAtomMetadata_getNumAdditiveFields(
+        AStatsManager_PullAtomMetadata* metadata) {
+    return metadata->additive_fields.size();
+}
+
+void AStatsManager_PullAtomMetadata_getAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
+                                                      int32_t* fields) {
+    std::copy(metadata->additive_fields.begin(), metadata->additive_fields.end(), fields);
+}
+
+class StatsPullAtomCallbackInternal : public BnPullAtomCallback {
+  public:
+    StatsPullAtomCallbackInternal(const AStatsManager_PullAtomCallback callback, void* cookie,
+                                  const int64_t coolDownMillis, const int64_t timeoutMillis,
+                                  const std::vector<int32_t> additiveFields)
+        : mCallback(callback),
+          mCookie(cookie),
+          mCoolDownMillis(coolDownMillis),
+          mTimeoutMillis(timeoutMillis),
+          mAdditiveFields(additiveFields) {}
+
+    Status onPullAtom(int32_t atomTag,
+                      const std::shared_ptr<IPullAtomResultReceiver>& resultReceiver) override {
+        AStatsEventList statsEventList;
+        int successInt = mCallback(atomTag, &statsEventList, mCookie);
+        bool success = successInt == AStatsManager_PULL_SUCCESS;
+
+        // Convert stats_events into StatsEventParcels.
+        std::vector<StatsEventParcel> parcels;
+        for (int i = 0; i < statsEventList.data.size(); i++) {
+            size_t size;
+            uint8_t* buffer = AStatsEvent_getBuffer(statsEventList.data[i], &size);
+
+            StatsEventParcel p;
+            // vector.assign() creates a copy, but this is inevitable unless
+            // stats_event.h/c uses a vector as opposed to a buffer.
+            p.buffer.assign(buffer, buffer + size);
+            parcels.push_back(std::move(p));
+        }
+
+        Status status = resultReceiver->pullFinished(atomTag, success, parcels);
+        if (!status.isOk()) {
+            std::vector<StatsEventParcel> emptyParcels;
+            resultReceiver->pullFinished(atomTag, /*success=*/false, emptyParcels);
+        }
+        for (int i = 0; i < statsEventList.data.size(); i++) {
+            AStatsEvent_release(statsEventList.data[i]);
+        }
+        return Status::ok();
+    }
+
+    int64_t getCoolDownMillis() const { return mCoolDownMillis; }
+    int64_t getTimeoutMillis() const { return mTimeoutMillis; }
+    const std::vector<int32_t>& getAdditiveFields() const { return mAdditiveFields; }
+
+  private:
+    const AStatsManager_PullAtomCallback mCallback;
+    void* mCookie;
+    const int64_t mCoolDownMillis;
+    const int64_t mTimeoutMillis;
+    const std::vector<int32_t> mAdditiveFields;
+};
+
+static std::mutex pullAtomMutex;
+static std::shared_ptr<IStatsd> sStatsd = nullptr;
+
+static std::map<int32_t, std::shared_ptr<StatsPullAtomCallbackInternal>> mPullers;
+static std::shared_ptr<IStatsd> getStatsService();
+
+static void binderDied(void* /*cookie*/) {
+    {
+        std::lock_guard<std::mutex> lock(pullAtomMutex);
+        sStatsd = nullptr;
+    }
+
+    std::shared_ptr<IStatsd> statsService = getStatsService();
+    if (statsService == nullptr) {
+        return;
+    }
+
+    // Since we do not want to make an IPC with the lock held, we first create a
+    // copy of the data with the lock held before iterating through the map.
+    std::map<int32_t, std::shared_ptr<StatsPullAtomCallbackInternal>> pullersCopy;
+    {
+        std::lock_guard<std::mutex> lock(pullAtomMutex);
+        pullersCopy = mPullers;
+    }
+    for (const auto& it : pullersCopy) {
+        statsService->registerNativePullAtomCallback(it.first, it.second->getCoolDownMillis(),
+                                                     it.second->getTimeoutMillis(),
+                                                     it.second->getAdditiveFields(), it.second);
+    }
+}
+
+static ::ndk::ScopedAIBinder_DeathRecipient sDeathRecipient(
+        AIBinder_DeathRecipient_new(binderDied));
+
+static std::shared_ptr<IStatsd> getStatsService() {
+    std::lock_guard<std::mutex> lock(pullAtomMutex);
+    if (!sStatsd) {
+        // Fetch statsd
+        ::ndk::SpAIBinder binder(AServiceManager_getService("stats"));
+        sStatsd = IStatsd::fromBinder(binder);
+        if (sStatsd) {
+            AIBinder_linkToDeath(binder.get(), sDeathRecipient.get(), /*cookie=*/nullptr);
+        }
+    }
+    return sStatsd;
+}
+
+void registerStatsPullAtomCallbackBlocking(int32_t atomTag,
+                                           std::shared_ptr<StatsPullAtomCallbackInternal> cb) {
+    const std::shared_ptr<IStatsd> statsService = getStatsService();
+    if (statsService == nullptr) {
+        // Statsd not available
+        return;
+    }
+
+    statsService->registerNativePullAtomCallback(
+            atomTag, cb->getCoolDownMillis(), cb->getTimeoutMillis(), cb->getAdditiveFields(), cb);
+}
+
+void unregisterStatsPullAtomCallbackBlocking(int32_t atomTag) {
+    const std::shared_ptr<IStatsd> statsService = getStatsService();
+    if (statsService == nullptr) {
+        // Statsd not available
+        return;
+    }
+
+    statsService->unregisterNativePullAtomCallback(atomTag);
+}
+
+void AStatsManager_setPullAtomCallback(int32_t atom_tag, AStatsManager_PullAtomMetadata* metadata,
+                                       AStatsManager_PullAtomCallback callback, void* cookie) {
+    int64_t coolDownMillis =
+            metadata == nullptr ? DEFAULT_COOL_DOWN_MILLIS : metadata->cool_down_millis;
+    int64_t timeoutMillis = metadata == nullptr ? DEFAULT_TIMEOUT_MILLIS : metadata->timeout_millis;
+
+    std::vector<int32_t> additiveFields;
+    if (metadata != nullptr) {
+        additiveFields = metadata->additive_fields;
+    }
+
+    std::shared_ptr<StatsPullAtomCallbackInternal> callbackBinder =
+            SharedRefBase::make<StatsPullAtomCallbackInternal>(callback, cookie, coolDownMillis,
+                                                               timeoutMillis, additiveFields);
+
+    {
+        std::lock_guard<std::mutex> lg(pullAtomMutex);
+        // Always add to the map. If statsd is dead, we will add them when it comes back.
+        mPullers[atom_tag] = callbackBinder;
+    }
+
+    std::thread registerThread(registerStatsPullAtomCallbackBlocking, atom_tag, callbackBinder);
+    registerThread.detach();
+}
+
+void AStatsManager_clearPullAtomCallback(int32_t atom_tag) {
+    {
+        std::lock_guard<std::mutex> lg(pullAtomMutex);
+        // Always remove the puller from our map.
+        // If statsd is down, we will not register it when it comes back.
+        mPullers.erase(atom_tag);
+    }
+    std::thread unregisterThread(unregisterStatsPullAtomCallbackBlocking, atom_tag);
+    unregisterThread.detach();
+}
diff --git a/libstats/pull/tests/pull_atom_metadata_test.cpp b/libstats/pull/tests/pull_atom_metadata_test.cpp
new file mode 100644
index 0000000..abc8e47
--- /dev/null
+++ b/libstats/pull/tests/pull_atom_metadata_test.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <stats_pull_atom_callback.h>
+
+namespace {
+
+static const int64_t DEFAULT_COOL_DOWN_MILLIS = 1000LL;  // 1 second.
+static const int64_t DEFAULT_TIMEOUT_MILLIS = 2000LL;    // 2 seconds.
+
+}  // anonymous namespace
+
+TEST(AStatsManager_PullAtomMetadataTest, TestEmpty) {
+    AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), DEFAULT_COOL_DOWN_MILLIS);
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), DEFAULT_TIMEOUT_MILLIS);
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), 0);
+    AStatsManager_PullAtomMetadata_release(metadata);
+}
+
+TEST(AStatsManager_PullAtomMetadataTest, TestSetTimeoutMillis) {
+    int64_t timeoutMillis = 500;
+    AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
+    AStatsManager_PullAtomMetadata_setTimeoutMillis(metadata, timeoutMillis);
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), DEFAULT_COOL_DOWN_MILLIS);
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), timeoutMillis);
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), 0);
+    AStatsManager_PullAtomMetadata_release(metadata);
+}
+
+TEST(AStatsManager_PullAtomMetadataTest, TestSetCoolDownMillis) {
+    int64_t coolDownMillis = 10000;
+    AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
+    AStatsManager_PullAtomMetadata_setCoolDownMillis(metadata, coolDownMillis);
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), coolDownMillis);
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), DEFAULT_TIMEOUT_MILLIS);
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), 0);
+    AStatsManager_PullAtomMetadata_release(metadata);
+}
+
+TEST(AStatsManager_PullAtomMetadataTest, TestSetAdditiveFields) {
+    const int numFields = 3;
+    int inputFields[numFields] = {2, 4, 6};
+    AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
+    AStatsManager_PullAtomMetadata_setAdditiveFields(metadata, inputFields, numFields);
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), DEFAULT_COOL_DOWN_MILLIS);
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), DEFAULT_TIMEOUT_MILLIS);
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), numFields);
+    int outputFields[numFields];
+    AStatsManager_PullAtomMetadata_getAdditiveFields(metadata, outputFields);
+    for (int i = 0; i < numFields; i++) {
+        EXPECT_EQ(inputFields[i], outputFields[i]);
+    }
+    AStatsManager_PullAtomMetadata_release(metadata);
+}
+
+TEST(AStatsManager_PullAtomMetadataTest, TestSetAllElements) {
+    int64_t timeoutMillis = 500;
+    int64_t coolDownMillis = 10000;
+    const int numFields = 3;
+    int inputFields[numFields] = {2, 4, 6};
+
+    AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
+    AStatsManager_PullAtomMetadata_setTimeoutMillis(metadata, timeoutMillis);
+    AStatsManager_PullAtomMetadata_setCoolDownMillis(metadata, coolDownMillis);
+    AStatsManager_PullAtomMetadata_setAdditiveFields(metadata, inputFields, numFields);
+
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), coolDownMillis);
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), timeoutMillis);
+    EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), numFields);
+    int outputFields[numFields];
+    AStatsManager_PullAtomMetadata_getAdditiveFields(metadata, outputFields);
+    for (int i = 0; i < numFields; i++) {
+        EXPECT_EQ(inputFields[i], outputFields[i]);
+    }
+    AStatsManager_PullAtomMetadata_release(metadata);
+}
diff --git a/libstats/push_compat/Android.bp b/libstats/push_compat/Android.bp
index cbc65ff..43ae69d 100644
--- a/libstats/push_compat/Android.bp
+++ b/libstats/push_compat/Android.bp
@@ -32,13 +32,15 @@
         "-DWRITE_TO_STATSD=1",
         "-DWRITE_TO_LOGD=0",
     ],
-    header_libs: ["libstatssocket_headers"],
+    header_libs: [
+        "libcutils_headers",
+        "libstatssocket_headers",
+    ],
     static_libs: [
         "libbase",
     ],
     shared_libs: [
         "liblog",
-        "libutils",
     ],
 }
 
@@ -46,6 +48,9 @@
     name: "libstatspush_compat",
     defaults: ["libstatspush_compat_defaults"],
     export_include_dirs: ["include"],
+    export_header_lib_headers: [
+        "libstatssocket_headers",
+    ],
     static_libs: ["libgtest_prod"],
     apex_available: ["com.android.resolv"],
     min_sdk_version: "29",
diff --git a/libstats/push_compat/StatsEventCompat.cpp b/libstats/push_compat/StatsEventCompat.cpp
index edfa070..12a5dd4 100644
--- a/libstats/push_compat/StatsEventCompat.cpp
+++ b/libstats/push_compat/StatsEventCompat.cpp
@@ -15,41 +15,42 @@
  */
 
 #include "include/StatsEventCompat.h"
+
+#include <chrono>
+
+#include <android-base/chrono_utils.h>
 #include <android-base/properties.h>
 #include <android/api-level.h>
 #include <android/log.h>
 #include <dlfcn.h>
-#include <utils/SystemClock.h>
 
+using android::base::boot_clock;
 using android::base::GetProperty;
 
 const static int kStatsEventTag = 1937006964;
-
-/* Checking ro.build.version.release is fragile, as the release field is
- * an opaque string without structural guarantees. However, testing confirms
- * that on Q devices, the property is "10," and on R, it is "R." Until
- * android_get_device_api_level() is updated, this is the only solution.
- *
- * TODO(b/146019024): migrate to android_get_device_api_level()
- */
 const bool StatsEventCompat::mPlatformAtLeastR =
-        GetProperty("ro.build.version.codename", "") == "R" ||
-        android_get_device_api_level() > __ANDROID_API_Q__;
+        android_get_device_api_level() >= __ANDROID_API_R__;
 
-// definitions of static class variables
+// initializations of static class variables
 bool StatsEventCompat::mAttemptedLoad = false;
-struct stats_event_api_table* StatsEventCompat::mStatsEventApi = nullptr;
 std::mutex StatsEventCompat::mLoadLock;
+AStatsEventApi StatsEventCompat::mAStatsEventApi;
+
+static int64_t elapsedRealtimeNano() {
+    return std::chrono::time_point_cast<std::chrono::nanoseconds>(boot_clock::now())
+            .time_since_epoch()
+            .count();
+}
 
 StatsEventCompat::StatsEventCompat() : mEventQ(kStatsEventTag) {
     // guard loading because StatsEventCompat might be called from multithreaded
     // environment
     {
         std::lock_guard<std::mutex> lg(mLoadLock);
-        if (!mAttemptedLoad) {
+        if (!mAttemptedLoad && mPlatformAtLeastR) {
             void* handle = dlopen("libstatssocket.so", RTLD_NOW);
             if (handle) {
-                mStatsEventApi = (struct stats_event_api_table*)dlsym(handle, "table");
+                initializeApiTableLocked(handle);
             } else {
                 ALOGE("dlopen failed: %s\n", dlerror());
             }
@@ -57,61 +58,93 @@
         mAttemptedLoad = true;
     }
 
-    if (mStatsEventApi) {
-        mEventR = mStatsEventApi->obtain();
-    } else if (!mPlatformAtLeastR) {
-        mEventQ << android::elapsedRealtimeNano();
+    if (useRSchema()) {
+        mEventR = mAStatsEventApi.obtain();
+    } else if (useQSchema()) {
+        mEventQ << elapsedRealtimeNano();
     }
 }
 
 StatsEventCompat::~StatsEventCompat() {
-    if (mStatsEventApi) mStatsEventApi->release(mEventR);
+    if (useRSchema()) mAStatsEventApi.release(mEventR);
+}
+
+// Populates the AStatsEventApi struct by calling dlsym to find the address of
+// each API function.
+void StatsEventCompat::initializeApiTableLocked(void* handle) {
+    mAStatsEventApi.obtain = (AStatsEvent* (*)())dlsym(handle, "AStatsEvent_obtain");
+    mAStatsEventApi.build = (void (*)(AStatsEvent*))dlsym(handle, "AStatsEvent_build");
+    mAStatsEventApi.write = (int (*)(AStatsEvent*))dlsym(handle, "AStatsEvent_write");
+    mAStatsEventApi.release = (void (*)(AStatsEvent*))dlsym(handle, "AStatsEvent_release");
+    mAStatsEventApi.setAtomId =
+            (void (*)(AStatsEvent*, uint32_t))dlsym(handle, "AStatsEvent_setAtomId");
+    mAStatsEventApi.writeInt32 =
+            (void (*)(AStatsEvent*, int32_t))dlsym(handle, "AStatsEvent_writeInt32");
+    mAStatsEventApi.writeInt64 =
+            (void (*)(AStatsEvent*, int64_t))dlsym(handle, "AStatsEvent_writeInt64");
+    mAStatsEventApi.writeFloat =
+            (void (*)(AStatsEvent*, float))dlsym(handle, "AStatsEvent_writeFloat");
+    mAStatsEventApi.writeBool =
+            (void (*)(AStatsEvent*, bool))dlsym(handle, "AStatsEvent_writeBool");
+    mAStatsEventApi.writeByteArray = (void (*)(AStatsEvent*, const uint8_t*, size_t))dlsym(
+            handle, "AStatsEvent_writeByteArray");
+    mAStatsEventApi.writeString =
+            (void (*)(AStatsEvent*, const char*))dlsym(handle, "AStatsEvent_writeString");
+    mAStatsEventApi.writeAttributionChain =
+            (void (*)(AStatsEvent*, const uint32_t*, const char* const*, uint8_t))dlsym(
+                    handle, "AStatsEvent_writeAttributionChain");
+    mAStatsEventApi.addBoolAnnotation =
+            (void (*)(AStatsEvent*, uint8_t, bool))dlsym(handle, "AStatsEvent_addBoolAnnotation");
+    mAStatsEventApi.addInt32Annotation = (void (*)(AStatsEvent*, uint8_t, int32_t))dlsym(
+            handle, "AStatsEvent_addInt32Annotation");
+
+    mAStatsEventApi.initialized = true;
 }
 
 void StatsEventCompat::setAtomId(int32_t atomId) {
-    if (mStatsEventApi) {
-        mStatsEventApi->set_atom_id(mEventR, (uint32_t)atomId);
-    } else if (!mPlatformAtLeastR) {
+    if (useRSchema()) {
+        mAStatsEventApi.setAtomId(mEventR, (uint32_t)atomId);
+    } else if (useQSchema()) {
         mEventQ << atomId;
     }
 }
 
 void StatsEventCompat::writeInt32(int32_t value) {
-    if (mStatsEventApi) {
-        mStatsEventApi->write_int32(mEventR, value);
-    } else if (!mPlatformAtLeastR) {
+    if (useRSchema()) {
+        mAStatsEventApi.writeInt32(mEventR, value);
+    } else if (useQSchema()) {
         mEventQ << value;
     }
 }
 
 void StatsEventCompat::writeInt64(int64_t value) {
-    if (mStatsEventApi) {
-        mStatsEventApi->write_int64(mEventR, value);
-    } else if (!mPlatformAtLeastR) {
+    if (useRSchema()) {
+        mAStatsEventApi.writeInt64(mEventR, value);
+    } else if (useQSchema()) {
         mEventQ << value;
     }
 }
 
 void StatsEventCompat::writeFloat(float value) {
-    if (mStatsEventApi) {
-        mStatsEventApi->write_float(mEventR, value);
-    } else if (!mPlatformAtLeastR) {
+    if (useRSchema()) {
+        mAStatsEventApi.writeFloat(mEventR, value);
+    } else if (useQSchema()) {
         mEventQ << value;
     }
 }
 
 void StatsEventCompat::writeBool(bool value) {
-    if (mStatsEventApi) {
-        mStatsEventApi->write_bool(mEventR, value);
-    } else if (!mPlatformAtLeastR) {
+    if (useRSchema()) {
+        mAStatsEventApi.writeBool(mEventR, value);
+    } else if (useQSchema()) {
         mEventQ << value;
     }
 }
 
 void StatsEventCompat::writeByteArray(const char* buffer, size_t length) {
-    if (mStatsEventApi) {
-        mStatsEventApi->write_byte_array(mEventR, (const uint8_t*)buffer, length);
-    } else if (!mPlatformAtLeastR) {
+    if (useRSchema()) {
+        mAStatsEventApi.writeByteArray(mEventR, reinterpret_cast<const uint8_t*>(buffer), length);
+    } else if (useQSchema()) {
         mEventQ.AppendCharArray(buffer, length);
     }
 }
@@ -119,19 +152,19 @@
 void StatsEventCompat::writeString(const char* value) {
     if (value == nullptr) value = "";
 
-    if (mStatsEventApi) {
-        mStatsEventApi->write_string8(mEventR, value);
-    } else if (!mPlatformAtLeastR) {
+    if (useRSchema()) {
+        mAStatsEventApi.writeString(mEventR, value);
+    } else if (useQSchema()) {
         mEventQ << value;
     }
 }
 
 void StatsEventCompat::writeAttributionChain(const int32_t* uids, size_t numUids,
                                              const vector<const char*>& tags) {
-    if (mStatsEventApi) {
-        mStatsEventApi->write_attribution_chain(mEventR, (const uint32_t*)uids, tags.data(),
-                                                (uint8_t)numUids);
-    } else if (!mPlatformAtLeastR) {
+    if (useRSchema()) {
+        mAStatsEventApi.writeAttributionChain(mEventR, (const uint32_t*)uids, tags.data(),
+                                              (uint8_t)numUids);
+    } else if (useQSchema()) {
         mEventQ.begin();
         for (size_t i = 0; i < numUids; i++) {
             mEventQ.begin();
@@ -148,26 +181,8 @@
                                           const map<int, int64_t>& int64Map,
                                           const map<int, const char*>& stringMap,
                                           const map<int, float>& floatMap) {
-    if (mStatsEventApi) {
-        vector<struct key_value_pair> pairs;
-
-        for (const auto& it : int32Map) {
-            pairs.push_back({.key = it.first, .valueType = INT32_TYPE, .int32Value = it.second});
-        }
-        for (const auto& it : int64Map) {
-            pairs.push_back({.key = it.first, .valueType = INT64_TYPE, .int64Value = it.second});
-        }
-        for (const auto& it : stringMap) {
-            pairs.push_back({.key = it.first, .valueType = STRING_TYPE, .stringValue = it.second});
-        }
-        for (const auto& it : floatMap) {
-            pairs.push_back({.key = it.first, .valueType = FLOAT_TYPE, .floatValue = it.second});
-        }
-
-        mStatsEventApi->write_key_value_pairs(mEventR, pairs.data(), (uint8_t)pairs.size());
-    }
-
-    else if (!mPlatformAtLeastR) {
+    // AStatsEvent does not support key value pairs.
+    if (useQSchema()) {
         mEventQ.begin();
         writeKeyValuePairMap(int32Map);
         writeKeyValuePairMap(int64Map);
@@ -194,28 +209,35 @@
 template void StatsEventCompat::writeKeyValuePairMap<const char*>(const map<int, const char*>&);
 
 void StatsEventCompat::addBoolAnnotation(uint8_t annotationId, bool value) {
-    if (mStatsEventApi) mStatsEventApi->add_bool_annotation(mEventR, annotationId, value);
+    if (useRSchema()) {
+        mAStatsEventApi.addBoolAnnotation(mEventR, annotationId, value);
+    }
     // Don't do anything if on Q.
 }
 
 void StatsEventCompat::addInt32Annotation(uint8_t annotationId, int32_t value) {
-    if (mStatsEventApi) mStatsEventApi->add_int32_annotation(mEventR, annotationId, value);
+    if (useRSchema()) {
+        mAStatsEventApi.addInt32Annotation(mEventR, annotationId, value);
+    }
     // Don't do anything if on Q.
 }
 
 int StatsEventCompat::writeToSocket() {
-    if (mStatsEventApi) {
-        mStatsEventApi->build(mEventR);
-        return mStatsEventApi->write(mEventR);
+    if (useRSchema()) {
+        return mAStatsEventApi.write(mEventR);
     }
 
-    if (!mPlatformAtLeastR) return mEventQ.write(LOG_ID_STATS);
+    if (useQSchema()) return mEventQ.write(LOG_ID_STATS);
 
-    // We reach here only if we're on R, but libstatspush_compat was unable to
+    // We reach here only if we're on R, but libstatssocket was unable to
     // be loaded using dlopen.
     return -ENOLINK;
 }
 
-bool StatsEventCompat::usesNewSchema() {
-    return mStatsEventApi != nullptr;
+bool StatsEventCompat::useRSchema() {
+    return mPlatformAtLeastR && mAStatsEventApi.initialized;
+}
+
+bool StatsEventCompat::useQSchema() {
+    return !mPlatformAtLeastR;
 }
diff --git a/libstats/push_compat/include/StatsEventCompat.h b/libstats/push_compat/include/StatsEventCompat.h
index a8cde68..00bf48b 100644
--- a/libstats/push_compat/include/StatsEventCompat.h
+++ b/libstats/push_compat/include/StatsEventCompat.h
@@ -26,6 +26,26 @@
 using std::map;
 using std::vector;
 
+struct AStatsEventApi {
+    // Indicates whether the below function pointers have been set using dlsym.
+    bool initialized = false;
+
+    AStatsEvent* (*obtain)(void);
+    void (*build)(AStatsEvent*);
+    int (*write)(AStatsEvent*);
+    void (*release)(AStatsEvent*);
+    void (*setAtomId)(AStatsEvent*, uint32_t);
+    void (*writeInt32)(AStatsEvent*, int32_t);
+    void (*writeInt64)(AStatsEvent*, int64_t);
+    void (*writeFloat)(AStatsEvent*, float);
+    void (*writeBool)(AStatsEvent*, bool);
+    void (*writeByteArray)(AStatsEvent*, const uint8_t*, size_t);
+    void (*writeString)(AStatsEvent*, const char*);
+    void (*writeAttributionChain)(AStatsEvent*, const uint32_t*, const char* const*, uint8_t);
+    void (*addBoolAnnotation)(AStatsEvent*, uint8_t, bool);
+    void (*addInt32Annotation)(AStatsEvent*, uint8_t, int32_t);
+};
+
 class StatsEventCompat {
   public:
     StatsEventCompat();
@@ -57,15 +77,18 @@
     const static bool mPlatformAtLeastR;
     static bool mAttemptedLoad;
     static std::mutex mLoadLock;
-    static struct stats_event_api_table* mStatsEventApi;
+    static AStatsEventApi mAStatsEventApi;
 
     // non-static member variables
-    struct stats_event* mEventR = nullptr;
+    AStatsEvent* mEventR = nullptr;
     stats_event_list mEventQ;
 
     template <class T>
     void writeKeyValuePairMap(const map<int, T>& keyValuePairMap);
 
-    bool usesNewSchema();
+    void initializeApiTableLocked(void* handle);
+    bool useRSchema();
+    bool useQSchema();
+
     FRIEND_TEST(StatsEventCompatTest, TestDynamicLoading);
 };
diff --git a/libstats/push_compat/tests/StatsEventCompat_test.cpp b/libstats/push_compat/tests/StatsEventCompat_test.cpp
index 2be24ec..2a70db5 100644
--- a/libstats/push_compat/tests/StatsEventCompat_test.cpp
+++ b/libstats/push_compat/tests/StatsEventCompat_test.cpp
@@ -21,18 +21,9 @@
 
 using android::base::GetProperty;
 
-/* Checking ro.build.version.release is fragile, as the release field is
- * an opaque string without structural guarantees. However, testing confirms
- * that on Q devices, the property is "10," and on R, it is "R." Until
- * android_get_device_api_level() is updated, this is the only solution.
- *
- *
- * TODO(b/146019024): migrate to android_get_device_api_level()
- */
-const static bool mPlatformAtLeastR = GetProperty("ro.build.version.release", "") == "R" ||
-                                      android_get_device_api_level() > __ANDROID_API_Q__;
+const static bool mPlatformAtLeastR = android_get_device_api_level() >= __ANDROID_API_R__;
 
 TEST(StatsEventCompatTest, TestDynamicLoading) {
     StatsEventCompat event;
-    EXPECT_EQ(mPlatformAtLeastR, event.usesNewSchema());
+    EXPECT_EQ(mPlatformAtLeastR, event.useRSchema());
 }
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index 6882ab2..89cdfe5 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -17,37 +17,69 @@
 // =========================================================================
 // Native library to write stats log to statsd socket on Android R and later
 // =========================================================================
-cc_library {
-    name: "libstatssocket",
+cc_defaults {
+    name: "libstatssocket_defaults",
     srcs: [
         "stats_buffer_writer.c",
         "stats_event.c",
-        // TODO(b/145573568): Remove stats_event_list once stats_event
-        // migration is complete.
-        "stats_event_list.c",
+        "stats_socket.c",
         "statsd_writer.c",
     ],
-    host_supported: true,
+    export_include_dirs: ["include"],
+    static_libs: [
+        "libcutils", // does not expose a stable C API
+    ],
+    header_libs: ["liblog_headers"],
     cflags: [
         "-Wall",
         "-Werror",
-        "-DLIBLOG_LOG_TAG=1006",
-        "-DWRITE_TO_STATSD=1",
-        "-DWRITE_TO_LOGD=0",
     ],
-    export_include_dirs: ["include"],
-    shared_libs: [
-        "libcutils",
-        "liblog",
+}
+
+cc_library {
+    name: "libstatssocket",
+    defaults: [
+        "libstatssocket_defaults",
     ],
+    host_supported: true,
+    target: {
+        // On android, libstatssocket should only be linked as a shared lib
+        android: {
+            static: {
+                enabled: false,
+            },
+        },
+        host: {
+            shared: {
+                enabled: false,
+            },
+        },
+    },
+    stl: "libc++_static",
 
     // enumerate stable entry points for APEX use
     stubs: {
         symbol_file: "libstatssocket.map.txt",
         versions: [
-            "1",
+            "30",
         ],
-    }
+    },
+    apex_available: [
+        "com.android.os.statsd",
+        "test_com.android.os.statsd",
+    ],
+}
+
+//TODO (b/149842105): Figure out if there is a better solution for this.
+cc_test_library {
+    name: "libstatssocket_private",
+    defaults: [
+        "libstatssocket_defaults",
+    ],
+    visibility: [
+        "//frameworks/base/apex/statsd/tests/libstatspull",
+        "//frameworks/base/cmds/statsd",
+    ],
 }
 
 cc_library_headers {
@@ -58,41 +90,36 @@
     min_sdk_version: "29",
 }
 
-cc_benchmark {
-    name: "libstatssocket_benchmark",
-    srcs: [
-        "benchmark/main.cpp",
-        "benchmark/stats_event_benchmark.cpp",
-    ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
-    static_libs: [
-        "libstatssocket",
-    ],
-    shared_libs: [
-        "libcutils",
-        "liblog",
-        "libgtest_prod",
-    ],
-}
-
 cc_test {
     name: "libstatssocket_test",
-    srcs: ["tests/stats_event_test.cpp"],
+    srcs: [
+        "tests/stats_event_test.cpp",
+        "tests/stats_writer_test.cpp",
+    ],
     cflags: [
         "-Wall",
         "-Werror",
     ],
     static_libs: [
         "libgmock",
-        "libstatssocket",
+        "libstatssocket_private",
     ],
     shared_libs: [
         "libcutils",
-        "liblog",
         "libutils",
     ],
-    test_suites: ["device_tests"],
+    test_suites: ["device-tests", "mts"],
+    test_config: "libstatssocket_test.xml",
+    //TODO(b/153588990): Remove when the build system properly separates.
+    //32bit and 64bit architectures.
+    compile_multilib: "both",
+    multilib: {
+        lib64: {
+            suffix: "64",
+        },
+        lib32: {
+            suffix: "32",
+        },
+    },
+    require_root: true,
 }
diff --git a/libstats/socket/TEST_MAPPING b/libstats/socket/TEST_MAPPING
new file mode 100644
index 0000000..0224998
--- /dev/null
+++ b/libstats/socket/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit" : [
+    {
+      "name" : "libstatssocket_test"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/libstats/socket/benchmark/stats_event_benchmark.cpp b/libstats/socket/benchmark/stats_event_benchmark.cpp
deleted file mode 100644
index 9488168..0000000
--- a/libstats/socket/benchmark/stats_event_benchmark.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "benchmark/benchmark.h"
-#include "stats_event.h"
-
-static struct stats_event* constructStatsEvent() {
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, 100);
-
-    // randomly sample atom size
-    int numElements = rand() % 800;
-    for (int i = 0; i < numElements; i++) {
-        stats_event_write_int32(event, i);
-    }
-
-    return event;
-}
-
-static void BM_stats_event_truncate_buffer(benchmark::State& state) {
-    while (state.KeepRunning()) {
-        struct stats_event* event = constructStatsEvent();
-        stats_event_build(event);
-        stats_event_write(event);
-        stats_event_release(event);
-    }
-}
-
-BENCHMARK(BM_stats_event_truncate_buffer);
-
-static void BM_stats_event_full_buffer(benchmark::State& state) {
-    while (state.KeepRunning()) {
-        struct stats_event* event = constructStatsEvent();
-        stats_event_truncate_buffer(event, false);
-        stats_event_build(event);
-        stats_event_write(event);
-        stats_event_release(event);
-    }
-}
-
-BENCHMARK(BM_stats_event_full_buffer);
diff --git a/libstats/socket/include/stats_buffer_writer.h b/libstats/socket/include/stats_buffer_writer.h
index de4a5e2..5b41f0e 100644
--- a/libstats/socket/include/stats_buffer_writer.h
+++ b/libstats/socket/include/stats_buffer_writer.h
@@ -23,6 +23,7 @@
 extern "C" {
 #endif  // __CPLUSPLUS
 void stats_log_close();
+int stats_log_is_closed();
 int write_buffer_to_statsd(void* buffer, size_t size, uint32_t atomId);
 #ifdef __cplusplus
 }
diff --git a/libstats/socket/include/stats_event.h b/libstats/socket/include/stats_event.h
index 080e957..3d3baf9 100644
--- a/libstats/socket/include/stats_event.h
+++ b/libstats/socket/include/stats_event.h
@@ -26,136 +26,136 @@
  * This code defines and encapsulates the socket protocol.
  *
  * Usage:
- *      struct stats_event* event = stats_event_obtain();
+ *      AStatsEvent* event = AStatsEvent_obtain();
  *
- *      stats_event_set_atom_id(event, atomId);
- *      stats_event_write_int32(event, 24);
- *      stats_event_add_bool_annotation(event, 1, true); // annotations apply to the previous field
- *      stats_event_add_int32_annotation(event, 2, 128);
- *      stats_event_write_float(event, 2.0);
+ *      AStatsEvent_setAtomId(event, atomId);
+ *      AStatsEvent_addBoolAnnotation(event, 5, false); // atom-level annotation
+ *      AStatsEvent_writeInt32(event, 24);
+ *      AStatsEvent_addBoolAnnotation(event, 1, true); // annotation for preceding atom field
+ *      AStatsEvent_addInt32Annotation(event, 2, 128);
+ *      AStatsEvent_writeFloat(event, 2.0);
  *
- *      stats_event_build(event);
- *      stats_event_write(event);
- *      stats_event_release(event);
+ *      AStatsEvent_write(event);
+ *      AStatsEvent_release(event);
  *
- * Notes:
- *    (a) write_<type>() and add_<type>_annotation() should be called in the order that fields
- *        and annotations are defined in the atom.
- *    (b) set_atom_id() can be called anytime before stats_event_write().
- *    (c) add_<type>_annotation() calls apply to the previous field.
- *    (d) If errors occur, stats_event_write() will write a bitmask of the errors to the socket.
- *    (e) All strings should be encoded using UTF8.
+ * Note that calls to add atom fields and annotations should be made in the
+ * order that they are defined in the atom.
  */
 
-/* ERRORS */
-#define ERROR_NO_TIMESTAMP 0x1
-#define ERROR_NO_ATOM_ID 0x2
-#define ERROR_OVERFLOW 0x4
-#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
-#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
-#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
-#define ERROR_INVALID_ANNOTATION_ID 0x40
-#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
-#define ERROR_TOO_MANY_ANNOTATIONS 0x100
-#define ERROR_TOO_MANY_FIELDS 0x200
-#define ERROR_INVALID_VALUE_TYPE 0x400
-#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
-
-/* TYPE IDS */
-#define INT32_TYPE 0x00
-#define INT64_TYPE 0x01
-#define STRING_TYPE 0x02
-#define LIST_TYPE 0x03
-#define FLOAT_TYPE 0x04
-#define BOOL_TYPE 0x05
-#define BYTE_ARRAY_TYPE 0x06
-#define OBJECT_TYPE 0x07
-#define KEY_VALUE_PAIRS_TYPE 0x08
-#define ATTRIBUTION_CHAIN_TYPE 0x09
-#define ERROR_TYPE 0x0F
-
 #ifdef __cplusplus
 extern "C" {
 #endif  // __CPLUSPLUS
 
-struct stats_event;
-
-/* SYSTEM API */
-struct stats_event* stats_event_obtain();
-// The build function can be called multiple times without error. If the event
-// has been built before, this function is a no-op.
-void stats_event_build(struct stats_event* event);
-int stats_event_write(struct stats_event* event);
-void stats_event_release(struct stats_event* event);
-
-void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId);
-
-void stats_event_write_int32(struct stats_event* event, int32_t value);
-void stats_event_write_int64(struct stats_event* event, int64_t value);
-void stats_event_write_float(struct stats_event* event, float value);
-void stats_event_write_bool(struct stats_event* event, bool value);
-
-void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes);
-
-// Buf must be null-terminated.
-void stats_event_write_string8(struct stats_event* event, const char* value);
-
-// Tags must be null-terminated.
-void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
-                                         const char* const* tags, uint8_t numNodes);
-
-/* key_value_pair struct can be constructed as follows:
- *    struct key_value_pair pair = {.key = key, .valueType = STRING_TYPE,
- *                                  .stringValue = buf};
+/**
+ * Opaque struct use to represent a StatsEvent. It builds and stores the data that is sent to
+ * statsd.
  */
-struct key_value_pair {
-    int32_t key;
-    uint8_t valueType;  // expected to be INT32_TYPE, INT64_TYPE, FLOAT_TYPE, or STRING_TYPE
-    union {
-        int32_t int32Value;
-        int64_t int64Value;
-        float floatValue;
-        const char* stringValue;  // must be null terminated
-    };
-};
+struct AStatsEvent;
+typedef struct AStatsEvent AStatsEvent;
 
-void stats_event_write_key_value_pairs(struct stats_event* event, struct key_value_pair* pairs,
-                                       uint8_t numPairs);
+/**
+ * Returns a new AStatsEvent. If you call this function, you must call AStatsEvent_release to free
+ * the allocated memory.
+ */
+AStatsEvent* AStatsEvent_obtain();
 
-void stats_event_add_bool_annotation(struct stats_event* event, uint8_t annotationId, bool value);
-void stats_event_add_int32_annotation(struct stats_event* event, uint8_t annotationId,
-                                      int32_t value);
+/**
+ * Builds and finalizes the AStatsEvent for a pulled event.
+ * This should only be called for pulled AStatsEvents.
+ *
+ * After this function, the StatsEvent must not be modified in any way other than calling release or
+ * write.
+ *
+ * Build can be called multiple times without error.
+ * If the event has been built before, this function is a no-op.
+ */
+void AStatsEvent_build(AStatsEvent* event);
 
-uint32_t stats_event_get_atom_id(struct stats_event* event);
+/**
+ * Writes the StatsEvent to the stats log.
+ *
+ * After calling this, AStatsEvent_release must be called,
+ * and is the only function that can be safely called.
+ */
+int AStatsEvent_write(AStatsEvent* event);
+
+/**
+ * Frees the memory held by this StatsEvent.
+ *
+ * After calling this, the StatsEvent must not be used or modified in any way.
+ */
+void AStatsEvent_release(AStatsEvent* event);
+
+/**
+ * Sets the atom id for this StatsEvent.
+ *
+ * This function should be called immediately after AStatsEvent_obtain. It may
+ * be called additional times as well, but subsequent calls will have no effect.
+ **/
+void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId);
+
+/**
+ * Writes an int32_t field to this StatsEvent.
+ **/
+void AStatsEvent_writeInt32(AStatsEvent* event, int32_t value);
+
+/**
+ * Writes an int64_t field to this StatsEvent.
+ **/
+void AStatsEvent_writeInt64(AStatsEvent* event, int64_t value);
+
+/**
+ * Writes a float field to this StatsEvent.
+ **/
+void AStatsEvent_writeFloat(AStatsEvent* event, float value);
+
+/**
+ * Write a bool field to this StatsEvent.
+ **/
+void AStatsEvent_writeBool(AStatsEvent* event, bool value);
+
+/**
+ * Write a byte array field to this StatsEvent.
+ **/
+void AStatsEvent_writeByteArray(AStatsEvent* event, const uint8_t* buf, size_t numBytes);
+
+/**
+ * Write a string field to this StatsEvent.
+ *
+ * The string must be null-terminated.
+ **/
+void AStatsEvent_writeString(AStatsEvent* event, const char* value);
+
+/**
+ * Write an attribution chain field to this StatsEvent.
+ *
+ * The sizes of uids and tags must be equal. The AttributionNode at position i is
+ * made up of uids[i] and tags[i].
+ *
+ * \param uids array of uids in the attribution chain.
+ * \param tags array of tags in the attribution chain. Each tag must be null-terminated.
+ * \param numNodes the number of AttributionNodes in the attribution chain. This is the length of
+ *                 the uids and the tags.
+ **/
+void AStatsEvent_writeAttributionChain(AStatsEvent* event, const uint32_t* uids,
+                                       const char* const* tags, uint8_t numNodes);
+
+/**
+ * Write a bool annotation for the previous field written.
+ **/
+void AStatsEvent_addBoolAnnotation(AStatsEvent* event, uint8_t annotationId, bool value);
+
+/**
+ * Write an integer annotation for the previous field written.
+ **/
+void AStatsEvent_addInt32Annotation(AStatsEvent* event, uint8_t annotationId, int32_t value);
+
+// Internal/test APIs. Should not be exposed outside of the APEX.
+void AStatsEvent_overwriteTimestamp(AStatsEvent* event, uint64_t timestampNs);
+uint32_t AStatsEvent_getAtomId(AStatsEvent* event);
 // Size is an output parameter.
-uint8_t* stats_event_get_buffer(struct stats_event* event, size_t* size);
-uint32_t stats_event_get_errors(struct stats_event* event);
-
-// This table is used by StatsEventCompat to access the stats_event API.
-struct stats_event_api_table {
-    struct stats_event* (*obtain)(void);
-    void (*build)(struct stats_event*);
-    int (*write)(struct stats_event*);
-    void (*release)(struct stats_event*);
-    void (*set_atom_id)(struct stats_event*, uint32_t);
-    void (*write_int32)(struct stats_event*, int32_t);
-    void (*write_int64)(struct stats_event*, int64_t);
-    void (*write_float)(struct stats_event*, float);
-    void (*write_bool)(struct stats_event*, bool);
-    void (*write_byte_array)(struct stats_event*, const uint8_t*, size_t);
-    void (*write_string8)(struct stats_event*, const char*);
-    void (*write_attribution_chain)(struct stats_event*, const uint32_t*, const char* const*,
-                                    uint8_t);
-    void (*write_key_value_pairs)(struct stats_event*, struct key_value_pair*, uint8_t);
-    void (*add_bool_annotation)(struct stats_event*, uint8_t, bool);
-    void (*add_int32_annotation)(struct stats_event*, uint8_t, int32_t);
-    uint32_t (*get_atom_id)(struct stats_event*);
-    uint8_t* (*get_buffer)(struct stats_event*, size_t*);
-    uint32_t (*get_errors)(struct stats_event*);
-};
-
-// exposed for benchmarking only
-void stats_event_truncate_buffer(struct stats_event* event, bool truncate);
+uint8_t* AStatsEvent_getBuffer(AStatsEvent* event, size_t* size);
+uint32_t AStatsEvent_getErrors(AStatsEvent* event);
 
 #ifdef __cplusplus
 }
diff --git a/libstats/socket/include/stats_event_list.h b/libstats/socket/include/stats_event_list.h
deleted file mode 100644
index 7a26536..0000000
--- a/libstats/socket/include/stats_event_list.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <log/log_event_list.h>
-#include <sys/uio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-void reset_log_context(android_log_context ctx);
-int write_to_logger(android_log_context context, log_id_t id);
-void note_log_drop(int error, int atomId);
-void stats_log_close();
-int android_log_write_char_array(android_log_context ctx, const char* value, size_t len);
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef __cplusplus
-/**
- * A copy of android_log_event_list class.
- *
- * android_log_event_list is going to be deprecated soon, so copy it here to
- * avoid creating dependency on upstream code. TODO(b/78304629): Rewrite this
- * code.
- */
-class stats_event_list {
-  private:
-    android_log_context ctx;
-    int ret;
-
-    stats_event_list(const stats_event_list&) = delete;
-    void operator=(const stats_event_list&) = delete;
-
-  public:
-    explicit stats_event_list(int tag) : ret(0) {
-        ctx = create_android_logger(static_cast<uint32_t>(tag));
-    }
-    ~stats_event_list() { android_log_destroy(&ctx); }
-
-    int close() {
-        int retval = android_log_destroy(&ctx);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return retval;
-    }
-
-    /* To allow above C calls to use this class as parameter */
-    operator android_log_context() const { return ctx; }
-
-    /* return errors or transmit status */
-    int status() const { return ret; }
-
-    int begin() {
-        int retval = android_log_write_list_begin(ctx);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret;
-    }
-    int end() {
-        int retval = android_log_write_list_end(ctx);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret;
-    }
-
-    stats_event_list& operator<<(int32_t value) {
-        int retval = android_log_write_int32(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    stats_event_list& operator<<(uint32_t value) {
-        int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    stats_event_list& operator<<(bool value) {
-        int retval = android_log_write_int32(ctx, value ? 1 : 0);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    stats_event_list& operator<<(int64_t value) {
-        int retval = android_log_write_int64(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    stats_event_list& operator<<(uint64_t value) {
-        int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    stats_event_list& operator<<(const char* value) {
-        int retval = android_log_write_string8(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    stats_event_list& operator<<(const std::string& value) {
-        int retval = android_log_write_string8_len(ctx, value.data(), value.length());
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    stats_event_list& operator<<(float value) {
-        int retval = android_log_write_float32(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return *this;
-    }
-
-    int write(log_id_t id = LOG_ID_EVENTS) {
-        /* facilitate -EBUSY retry */
-        if ((ret == -EBUSY) || (ret > 0)) {
-            ret = 0;
-        }
-        int retval = write_to_logger(ctx, id);
-        /* existing errors trump transmission errors */
-        if (!ret) {
-            ret = retval;
-        }
-        return ret;
-    }
-
-    /*
-     * Append<Type> methods removes any integer promotion
-     * confusion, and adds access to string with length.
-     * Append methods are also added for all types for
-     * convenience.
-     */
-
-    bool AppendInt(int32_t value) {
-        int retval = android_log_write_int32(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret >= 0;
-    }
-
-    bool AppendLong(int64_t value) {
-        int retval = android_log_write_int64(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret >= 0;
-    }
-
-    bool AppendString(const char* value) {
-        int retval = android_log_write_string8(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret >= 0;
-    }
-
-    bool AppendString(const char* value, size_t len) {
-        int retval = android_log_write_string8_len(ctx, value, len);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret >= 0;
-    }
-
-    bool AppendString(const std::string& value) {
-        int retval = android_log_write_string8_len(ctx, value.data(), value.length());
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret;
-    }
-
-    bool Append(const std::string& value) {
-        int retval = android_log_write_string8_len(ctx, value.data(), value.length());
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret;
-    }
-
-    bool AppendFloat(float value) {
-        int retval = android_log_write_float32(ctx, value);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret >= 0;
-    }
-
-    template <typename Tvalue>
-    bool Append(Tvalue value) {
-        *this << value;
-        return ret >= 0;
-    }
-
-    bool Append(const char* value, size_t len) {
-        int retval = android_log_write_string8_len(ctx, value, len);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret >= 0;
-    }
-
-    bool AppendCharArray(const char* value, size_t len) {
-        int retval = android_log_write_char_array(ctx, value, len);
-        if (retval < 0) {
-            ret = retval;
-        }
-        return ret >= 0;
-    }
-};
-
-#endif
diff --git a/libstats/socket/benchmark/main.cpp b/libstats/socket/include/stats_socket.h
similarity index 65%
copy from libstats/socket/benchmark/main.cpp
copy to libstats/socket/include/stats_socket.h
index 5ebdf6e..5a75fc0 100644
--- a/libstats/socket/benchmark/main.cpp
+++ b/libstats/socket/include/stats_socket.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open 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,6 +14,20 @@
  * limitations under the License.
  */
 
-#include <benchmark/benchmark.h>
+#pragma once
 
-BENCHMARK_MAIN();
+/**
+ * Helpers to manage the statsd socket.
+ **/
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __CPLUSPLUS
+
+/**
+ * Closes the statsd socket file descriptor.
+ **/
+void AStatsSocket_close();
+#ifdef __cplusplus
+}
+#endif  // __CPLUSPLUS
diff --git a/libstats/socket/libstatssocket.map.txt b/libstats/socket/libstatssocket.map.txt
index 55bfbda..5c13904 100644
--- a/libstats/socket/libstatssocket.map.txt
+++ b/libstats/socket/libstatssocket.map.txt
@@ -1,23 +1,20 @@
 LIBSTATSSOCKET {
     global:
-        stats_event_obtain; # apex # introduced=1
-        stats_event_build; # apex # introduced=1
-        stats_event_write; # apex # introduced=1
-        stats_event_release; # apex # introduced=1
-        stats_event_set_atom_id; # apex # introduced=1
-        stats_event_write_int32; # apex # introduced=1
-        stats_event_write_int64; # apex # introduced=1
-        stats_event_write_float; # apex # introduced=1
-        stats_event_write_bool; # apex # introduced=1
-        stats_event_write_byte_array; # apex # introduced=1
-        stats_event_write_string8; # apex # introduced=1
-        stats_event_write_attribution_chain; # apex # introduced=1
-        stats_event_write_key_value_pairs; # apex # introduced=1
-        stats_event_add_bool_annotation; # apex # introduced=1
-        stats_event_add_int32_annotation; # apex # introduced=1
-        stats_event_get_atom_id; # apex # introduced=1
-        stats_event_get_buffer; # apex # introduced=1
-        stats_event_get_errors; # apex # introduced=1
+        AStatsEvent_obtain; # apex # introduced=30
+        AStatsEvent_build; # apex # introduced=30
+        AStatsEvent_write; # apex # introduced=30
+        AStatsEvent_release; # apex # introduced=30
+        AStatsEvent_setAtomId; # apex # introduced=30
+        AStatsEvent_writeInt32; # apex # introduced=30
+        AStatsEvent_writeInt64; # apex # introduced=30
+        AStatsEvent_writeFloat; # apex # introduced=30
+        AStatsEvent_writeBool; # apex # introduced=30
+        AStatsEvent_writeByteArray; # apex # introduced=30
+        AStatsEvent_writeString; # apex # introduced=30
+        AStatsEvent_writeAttributionChain; # apex # introduced=30
+        AStatsEvent_addBoolAnnotation; # apex # introduced=30
+        AStatsEvent_addInt32Annotation; # apex # introduced=30
+        AStatsSocket_close; # apex # introduced=30
     local:
         *;
 };
diff --git a/libstats/socket/libstatssocket_test.xml b/libstats/socket/libstatssocket_test.xml
new file mode 100644
index 0000000..d2694d1
--- /dev/null
+++ b/libstats/socket/libstatssocket_test.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs libstatssocket_test.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+    <option name="test-suite-tag" value="mts" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+       <option name="cleanup" value="true" />
+       <option name="push" value="libstatssocket_test->/data/local/tmp/libstatssocket_test" />
+       <option name="append-bitness" value="true" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="libstatssocket_test" />
+    </test>
+
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.os.statsd" />
+    </object>
+</configuration>
+
diff --git a/libstats/socket/stats_buffer_writer.c b/libstats/socket/stats_buffer_writer.c
index c5c591d..549acdc 100644
--- a/libstats/socket/stats_buffer_writer.c
+++ b/libstats/socket/stats_buffer_writer.c
@@ -43,27 +43,23 @@
     statsd_writer_init_unlock();
 }
 
+int stats_log_is_closed() {
+    return statsdLoggerWrite.isClosed && (*statsdLoggerWrite.isClosed)();
+}
+
 int write_buffer_to_statsd(void* buffer, size_t size, uint32_t atomId) {
     int ret = 1;
 
-#ifdef __ANDROID__
-    bool statsdEnabled = property_get_bool("ro.statsd.enable", true);
-#else
-    bool statsdEnabled = false;
-#endif
+    struct iovec vecs[2];
+    vecs[0].iov_base = (void*)&kStatsEventTag;
+    vecs[0].iov_len = sizeof(kStatsEventTag);
+    vecs[1].iov_base = buffer;
+    vecs[1].iov_len = size;
 
-    if (statsdEnabled) {
-        struct iovec vecs[2];
-        vecs[0].iov_base = (void*)&kStatsEventTag;
-        vecs[0].iov_len = sizeof(kStatsEventTag);
-        vecs[1].iov_base = buffer;
-        vecs[1].iov_len = size;
+    ret = __write_to_statsd(vecs, 2);
 
-        ret = __write_to_statsd(vecs, 2);
-
-        if (ret < 0) {
-            note_log_drop(ret, atomId);
-        }
+    if (ret < 0) {
+        note_log_drop(ret, atomId);
     }
 
     return ret;
diff --git a/libstats/socket/stats_event.c b/libstats/socket/stats_event.c
index 15039c6..f3e8087 100644
--- a/libstats/socket/stats_event.c
+++ b/libstats/socket/stats_event.c
@@ -23,29 +23,61 @@
 #define LOGGER_ENTRY_MAX_PAYLOAD 4068
 // Max payload size is 4 bytes less as 4 bytes are reserved for stats_eventTag.
 // See android_util_Stats_Log.cpp
-#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - 4)
+#define MAX_PUSH_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - 4)
+
+#define MAX_PULL_EVENT_PAYLOAD (50 * 1024)  // 50 KB
 
 /* POSITIONS */
 #define POS_NUM_ELEMENTS 1
 #define POS_TIMESTAMP (POS_NUM_ELEMENTS + sizeof(uint8_t))
 #define POS_ATOM_ID (POS_TIMESTAMP + sizeof(uint8_t) + sizeof(uint64_t))
-#define POS_FIRST_FIELD (POS_ATOM_ID + sizeof(uint8_t) + sizeof(uint32_t))
 
 /* LIMITS */
 #define MAX_ANNOTATION_COUNT 15
 #define MAX_BYTE_VALUE 127  // parsing side requires that lengths fit in 7 bits
 
-// The stats_event struct holds the serialized encoding of an event
+/* ERRORS */
+#define ERROR_NO_TIMESTAMP 0x1
+#define ERROR_NO_ATOM_ID 0x2
+#define ERROR_OVERFLOW 0x4
+#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
+#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
+#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
+#define ERROR_INVALID_ANNOTATION_ID 0x40
+#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
+#define ERROR_TOO_MANY_ANNOTATIONS 0x100
+#define ERROR_TOO_MANY_FIELDS 0x200
+#define ERROR_INVALID_VALUE_TYPE 0x400
+#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
+#define ERROR_ATOM_ID_INVALID_POSITION 0x2000
+
+/* TYPE IDS */
+#define INT32_TYPE 0x00
+#define INT64_TYPE 0x01
+#define STRING_TYPE 0x02
+#define LIST_TYPE 0x03
+#define FLOAT_TYPE 0x04
+#define BOOL_TYPE 0x05
+#define BYTE_ARRAY_TYPE 0x06
+#define OBJECT_TYPE 0x07
+#define KEY_VALUE_PAIRS_TYPE 0x08
+#define ATTRIBUTION_CHAIN_TYPE 0x09
+#define ERROR_TYPE 0x0F
+
+// The AStatsEvent struct holds the serialized encoding of an event
 // within a buf. Also includes other required fields.
-struct stats_event {
+struct AStatsEvent {
     uint8_t* buf;
-    size_t lastFieldPos;  // location of last field within the buf
-    size_t size;          // number of valid bytes within buffer
+    // Location of last field within the buf. Here, field denotes either a
+    // metadata field (e.g. timestamp) or an atom field.
+    size_t lastFieldPos;
+    // Number of valid bytes within the buffer.
+    size_t numBytesWritten;
     uint32_t numElements;
     uint32_t atomId;
     uint32_t errors;
-    bool truncate;
     bool built;
+    size_t bufSize;
 };
 
 static int64_t get_elapsed_realtime_ns() {
@@ -55,93 +87,115 @@
     return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;
 }
 
-struct stats_event* stats_event_obtain() {
-    struct stats_event* event = malloc(sizeof(struct stats_event));
-    event->buf = (uint8_t*)calloc(MAX_EVENT_PAYLOAD, 1);
-    event->buf[0] = OBJECT_TYPE;
+AStatsEvent* AStatsEvent_obtain() {
+    AStatsEvent* event = malloc(sizeof(AStatsEvent));
+    event->lastFieldPos = 0;
+    event->numBytesWritten = 2;  // reserve first 2 bytes for root event type and number of elements
+    event->numElements = 0;
     event->atomId = 0;
     event->errors = 0;
-    event->truncate = true;  // truncate for both pulled and pushed atoms
     event->built = false;
+    event->bufSize = MAX_PUSH_EVENT_PAYLOAD;
+    event->buf = (uint8_t*)calloc(event->bufSize, 1);
 
-    // place the timestamp
-    uint64_t timestampNs = get_elapsed_realtime_ns();
-    event->buf[POS_TIMESTAMP] = INT64_TYPE;
-    memcpy(&event->buf[POS_TIMESTAMP + sizeof(uint8_t)], &timestampNs, sizeof(timestampNs));
-
-    event->numElements = 1;
-    event->lastFieldPos = 0;  // 0 since we haven't written a field yet
-    event->size = POS_FIRST_FIELD;
+    event->buf[0] = OBJECT_TYPE;
+    AStatsEvent_writeInt64(event, get_elapsed_realtime_ns());  // write the timestamp
 
     return event;
 }
 
-void stats_event_release(struct stats_event* event) {
+void AStatsEvent_release(AStatsEvent* event) {
     free(event->buf);
     free(event);
 }
 
-void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId) {
+void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId) {
+    if (event->atomId != 0) return;
+    if (event->numElements != 1) {
+        event->errors |= ERROR_ATOM_ID_INVALID_POSITION;
+        return;
+    }
+
     event->atomId = atomId;
-    event->buf[POS_ATOM_ID] = INT32_TYPE;
-    memcpy(&event->buf[POS_ATOM_ID + sizeof(uint8_t)], &atomId, sizeof(atomId));
-    event->numElements++;
+    AStatsEvent_writeInt32(event, atomId);
+}
+
+// Overwrites the timestamp populated in AStatsEvent_obtain with a custom
+// timestamp. Should only be called from test code.
+void AStatsEvent_overwriteTimestamp(AStatsEvent* event, uint64_t timestampNs) {
+    memcpy(&event->buf[POS_TIMESTAMP + sizeof(uint8_t)], &timestampNs, sizeof(timestampNs));
+    // Do not increment numElements because we already accounted for the timestamp
+    // within AStatsEvent_obtain.
 }
 
 // Side-effect: modifies event->errors if the buffer would overflow
-static bool overflows(struct stats_event* event, size_t size) {
-    if (event->size + size > MAX_EVENT_PAYLOAD) {
+static bool overflows(AStatsEvent* event, size_t size) {
+    const size_t totalBytesNeeded = event->numBytesWritten + size;
+    if (totalBytesNeeded > MAX_PULL_EVENT_PAYLOAD) {
         event->errors |= ERROR_OVERFLOW;
         return true;
     }
+
+    // Expand buffer if needed.
+    if (event->bufSize < MAX_PULL_EVENT_PAYLOAD && totalBytesNeeded > event->bufSize) {
+        do {
+            event->bufSize *= 2;
+        } while (event->bufSize <= totalBytesNeeded);
+
+        if (event->bufSize > MAX_PULL_EVENT_PAYLOAD) {
+            event->bufSize = MAX_PULL_EVENT_PAYLOAD;
+        }
+
+        event->buf = (uint8_t*)realloc(event->buf, event->bufSize);
+    }
     return false;
 }
 
-// Side-effect: all append functions increment event->size if there is
+// Side-effect: all append functions increment event->numBytesWritten if there is
 // sufficient space within the buffer to place the value
-static void append_byte(struct stats_event* event, uint8_t value) {
+static void append_byte(AStatsEvent* event, uint8_t value) {
     if (!overflows(event, sizeof(value))) {
-        event->buf[event->size] = value;
-        event->size += sizeof(value);
+        event->buf[event->numBytesWritten] = value;
+        event->numBytesWritten += sizeof(value);
     }
 }
 
-static void append_bool(struct stats_event* event, bool value) {
+static void append_bool(AStatsEvent* event, bool value) {
     append_byte(event, (uint8_t)value);
 }
 
-static void append_int32(struct stats_event* event, int32_t value) {
+static void append_int32(AStatsEvent* event, int32_t value) {
     if (!overflows(event, sizeof(value))) {
-        memcpy(&event->buf[event->size], &value, sizeof(value));
-        event->size += sizeof(value);
+        memcpy(&event->buf[event->numBytesWritten], &value, sizeof(value));
+        event->numBytesWritten += sizeof(value);
     }
 }
 
-static void append_int64(struct stats_event* event, int64_t value) {
+static void append_int64(AStatsEvent* event, int64_t value) {
     if (!overflows(event, sizeof(value))) {
-        memcpy(&event->buf[event->size], &value, sizeof(value));
-        event->size += sizeof(value);
+        memcpy(&event->buf[event->numBytesWritten], &value, sizeof(value));
+        event->numBytesWritten += sizeof(value);
     }
 }
 
-static void append_float(struct stats_event* event, float value) {
+static void append_float(AStatsEvent* event, float value) {
     if (!overflows(event, sizeof(value))) {
-        memcpy(&event->buf[event->size], &value, sizeof(value));
-        event->size += sizeof(float);
+        memcpy(&event->buf[event->numBytesWritten], &value, sizeof(value));
+        event->numBytesWritten += sizeof(float);
     }
 }
 
-static void append_byte_array(struct stats_event* event, const uint8_t* buf, size_t size) {
+static void append_byte_array(AStatsEvent* event, const uint8_t* buf, size_t size) {
     if (!overflows(event, size)) {
-        memcpy(&event->buf[event->size], buf, size);
-        event->size += size;
+        memcpy(&event->buf[event->numBytesWritten], buf, size);
+        event->numBytesWritten += size;
     }
 }
 
 // Side-effect: modifies event->errors if buf is not properly null-terminated
-static void append_string(struct stats_event* event, const char* buf) {
-    size_t size = strnlen(buf, MAX_EVENT_PAYLOAD);
-    if (size == MAX_EVENT_PAYLOAD) {
+static void append_string(AStatsEvent* event, const char* buf) {
+    size_t size = strnlen(buf, MAX_PULL_EVENT_PAYLOAD);
+    if (size == MAX_PULL_EVENT_PAYLOAD) {
         event->errors |= ERROR_STRING_NOT_NULL_TERMINATED;
         return;
     }
@@ -150,61 +204,51 @@
     append_byte_array(event, (uint8_t*)buf, size);
 }
 
-static void start_field(struct stats_event* event, uint8_t typeId) {
-    event->lastFieldPos = event->size;
+static void start_field(AStatsEvent* event, uint8_t typeId) {
+    event->lastFieldPos = event->numBytesWritten;
     append_byte(event, typeId);
     event->numElements++;
 }
 
-void stats_event_write_int32(struct stats_event* event, int32_t value) {
-    if (event->errors) return;
-
+void AStatsEvent_writeInt32(AStatsEvent* event, int32_t value) {
     start_field(event, INT32_TYPE);
     append_int32(event, value);
 }
 
-void stats_event_write_int64(struct stats_event* event, int64_t value) {
-    if (event->errors) return;
-
+void AStatsEvent_writeInt64(AStatsEvent* event, int64_t value) {
     start_field(event, INT64_TYPE);
     append_int64(event, value);
 }
 
-void stats_event_write_float(struct stats_event* event, float value) {
-    if (event->errors) return;
-
+void AStatsEvent_writeFloat(AStatsEvent* event, float value) {
     start_field(event, FLOAT_TYPE);
     append_float(event, value);
 }
 
-void stats_event_write_bool(struct stats_event* event, bool value) {
-    if (event->errors) return;
-
+void AStatsEvent_writeBool(AStatsEvent* event, bool value) {
     start_field(event, BOOL_TYPE);
     append_bool(event, value);
 }
 
-void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes) {
-    if (event->errors) return;
-
+void AStatsEvent_writeByteArray(AStatsEvent* event, const uint8_t* buf, size_t numBytes) {
     start_field(event, BYTE_ARRAY_TYPE);
     append_int32(event, numBytes);
     append_byte_array(event, buf, numBytes);
 }
 
 // Value is assumed to be encoded using UTF8
-void stats_event_write_string8(struct stats_event* event, const char* value) {
-    if (event->errors) return;
-
+void AStatsEvent_writeString(AStatsEvent* event, const char* value) {
     start_field(event, STRING_TYPE);
     append_string(event, value);
 }
 
 // Tags are assumed to be encoded using UTF8
-void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
-                                         const char* const* tags, uint8_t numNodes) {
-    if (numNodes > MAX_BYTE_VALUE) event->errors |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG;
-    if (event->errors) return;
+void AStatsEvent_writeAttributionChain(AStatsEvent* event, const uint32_t* uids,
+                                       const char* const* tags, uint8_t numNodes) {
+    if (numNodes > MAX_BYTE_VALUE) {
+        event->errors |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG;
+        return;
+    }
 
     start_field(event, ATTRIBUTION_CHAIN_TYPE);
     append_byte(event, numNodes);
@@ -215,39 +259,8 @@
     }
 }
 
-void stats_event_write_key_value_pairs(struct stats_event* event, struct key_value_pair* pairs,
-                                       uint8_t numPairs) {
-    if (numPairs > MAX_BYTE_VALUE) event->errors |= ERROR_TOO_MANY_KEY_VALUE_PAIRS;
-    if (event->errors) return;
-
-    start_field(event, KEY_VALUE_PAIRS_TYPE);
-    append_byte(event, numPairs);
-
-    for (uint8_t i = 0; i < numPairs; i++) {
-        append_int32(event, pairs[i].key);
-        append_byte(event, pairs[i].valueType);
-        switch (pairs[i].valueType) {
-            case INT32_TYPE:
-                append_int32(event, pairs[i].int32Value);
-                break;
-            case INT64_TYPE:
-                append_int64(event, pairs[i].int64Value);
-                break;
-            case FLOAT_TYPE:
-                append_float(event, pairs[i].floatValue);
-                break;
-            case STRING_TYPE:
-                append_string(event, pairs[i].stringValue);
-                break;
-            default:
-                event->errors |= ERROR_INVALID_VALUE_TYPE;
-                return;
-        }
-    }
-}
-
 // Side-effect: modifies event->errors if field has too many annotations
-static void increment_annotation_count(struct stats_event* event) {
+static void increment_annotation_count(AStatsEvent* event) {
     uint8_t fieldType = event->buf[event->lastFieldPos] & 0x0F;
     uint32_t oldAnnotationCount = (event->buf[event->lastFieldPos] & 0xF0) >> 4;
     uint32_t newAnnotationCount = oldAnnotationCount + 1;
@@ -260,10 +273,14 @@
     event->buf[event->lastFieldPos] = (((uint8_t)newAnnotationCount << 4) & 0xF0) | fieldType;
 }
 
-void stats_event_add_bool_annotation(struct stats_event* event, uint8_t annotationId, bool value) {
-    if (event->lastFieldPos == 0) event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
-    if (annotationId > MAX_BYTE_VALUE) event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
-    if (event->errors) return;
+void AStatsEvent_addBoolAnnotation(AStatsEvent* event, uint8_t annotationId, bool value) {
+    if (event->numElements < 2) {
+        event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
+        return;
+    } else if (annotationId > MAX_BYTE_VALUE) {
+        event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
+        return;
+    }
 
     append_byte(event, annotationId);
     append_byte(event, BOOL_TYPE);
@@ -271,11 +288,14 @@
     increment_annotation_count(event);
 }
 
-void stats_event_add_int32_annotation(struct stats_event* event, uint8_t annotationId,
-                                      int32_t value) {
-    if (event->lastFieldPos == 0) event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
-    if (annotationId > MAX_BYTE_VALUE) event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
-    if (event->errors) return;
+void AStatsEvent_addInt32Annotation(AStatsEvent* event, uint8_t annotationId, int32_t value) {
+    if (event->numElements < 2) {
+        event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
+        return;
+    } else if (annotationId > MAX_BYTE_VALUE) {
+        event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
+        return;
+    }
 
     append_byte(event, annotationId);
     append_byte(event, INT32_TYPE);
@@ -283,72 +303,49 @@
     increment_annotation_count(event);
 }
 
-uint32_t stats_event_get_atom_id(struct stats_event* event) {
+uint32_t AStatsEvent_getAtomId(AStatsEvent* event) {
     return event->atomId;
 }
 
-uint8_t* stats_event_get_buffer(struct stats_event* event, size_t* size) {
-    if (size) *size = event->size;
+uint8_t* AStatsEvent_getBuffer(AStatsEvent* event, size_t* size) {
+    if (size) *size = event->numBytesWritten;
     return event->buf;
 }
 
-uint32_t stats_event_get_errors(struct stats_event* event) {
+uint32_t AStatsEvent_getErrors(AStatsEvent* event) {
     return event->errors;
 }
 
-void stats_event_truncate_buffer(struct stats_event* event, bool truncate) {
-    event->truncate = truncate;
-}
-
-void stats_event_build(struct stats_event* event) {
-    if (event->built) return;
-
-    if (event->atomId == 0) event->errors |= ERROR_NO_ATOM_ID;
-
-    if (event->numElements > MAX_BYTE_VALUE) {
-        event->errors |= ERROR_TOO_MANY_FIELDS;
-    } else {
-        event->buf[POS_NUM_ELEMENTS] = event->numElements;
-    }
+static void build_internal(AStatsEvent* event, const bool push) {
+    if (event->numElements > MAX_BYTE_VALUE) event->errors |= ERROR_TOO_MANY_FIELDS;
+    if (0 == event->atomId) event->errors |= ERROR_NO_ATOM_ID;
+    if (push && event->numBytesWritten > MAX_PUSH_EVENT_PAYLOAD) event->errors |= ERROR_OVERFLOW;
 
     // If there are errors, rewrite buffer.
     if (event->errors) {
-        event->buf[POS_NUM_ELEMENTS] = 3;
-        event->buf[POS_FIRST_FIELD] = ERROR_TYPE;
-        memcpy(&event->buf[POS_FIRST_FIELD + sizeof(uint8_t)], &event->errors,
-               sizeof(event->errors));
-        event->size = POS_FIRST_FIELD + sizeof(uint8_t) + sizeof(uint32_t);
+        // Discard everything after the atom id (including atom-level
+        // annotations). This leaves only two elements (timestamp and atom id).
+        event->numElements = 2;
+        // Reset number of atom-level annotations to 0.
+        event->buf[POS_ATOM_ID] = INT32_TYPE;
+        // Now, write errors to the buffer immediately after the atom id.
+        event->numBytesWritten = POS_ATOM_ID + sizeof(uint8_t) + sizeof(uint32_t);
+        start_field(event, ERROR_TYPE);
+        append_int32(event, event->errors);
     }
 
-    // Truncate the buffer to the appropriate length in order to limit our
-    // memory usage.
-    if (event->truncate) event->buf = (uint8_t*)realloc(event->buf, event->size);
+    event->buf[POS_NUM_ELEMENTS] = event->numElements;
+}
+
+void AStatsEvent_build(AStatsEvent* event) {
+    if (event->built) return;
+
+    build_internal(event, false /* push */);
 
     event->built = true;
 }
 
-int stats_event_write(struct stats_event* event) {
-    stats_event_build(event);
-    return write_buffer_to_statsd(&event->buf, event->size, event->atomId);
+int AStatsEvent_write(AStatsEvent* event) {
+    build_internal(event, true /* push */);
+    return write_buffer_to_statsd(event->buf, event->numBytesWritten, event->atomId);
 }
-
-struct stats_event_api_table table = {
-        stats_event_obtain,
-        stats_event_build,
-        stats_event_write,
-        stats_event_release,
-        stats_event_set_atom_id,
-        stats_event_write_int32,
-        stats_event_write_int64,
-        stats_event_write_float,
-        stats_event_write_bool,
-        stats_event_write_byte_array,
-        stats_event_write_string8,
-        stats_event_write_attribution_chain,
-        stats_event_write_key_value_pairs,
-        stats_event_add_bool_annotation,
-        stats_event_add_int32_annotation,
-        stats_event_get_atom_id,
-        stats_event_get_buffer,
-        stats_event_get_errors,
-};
diff --git a/libstats/socket/stats_event_list.c b/libstats/socket/stats_event_list.c
deleted file mode 100644
index 661a223..0000000
--- a/libstats/socket/stats_event_list.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "include/stats_event_list.h"
-
-#include <string.h>
-#include <sys/time.h>
-#include "stats_buffer_writer.h"
-
-#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
-
-typedef struct {
-    uint32_t tag;
-    unsigned pos;                                    /* Read/write position into buffer */
-    unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements   */
-    unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1];  /* pos for list counter */
-    unsigned list_nest_depth;
-    unsigned len; /* Length or raw buffer. */
-    bool overflow;
-    bool list_stop; /* next call decrement list_nest_depth and issue a stop */
-    enum {
-        kAndroidLoggerRead = 1,
-        kAndroidLoggerWrite = 2,
-    } read_write_flag;
-    uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
-} android_log_context_internal;
-
-// Similar to create_android_logger(), but instead of allocation a new buffer,
-// this function resets the buffer for resuse.
-void reset_log_context(android_log_context ctx) {
-    if (!ctx) {
-        return;
-    }
-    android_log_context_internal* context = (android_log_context_internal*)(ctx);
-    uint32_t tag = context->tag;
-    memset(context, 0, sizeof(android_log_context_internal));
-
-    context->tag = tag;
-    context->read_write_flag = kAndroidLoggerWrite;
-    size_t needed = sizeof(uint8_t) + sizeof(uint8_t);
-    if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
-        context->overflow = true;
-    }
-    /* Everything is a list */
-    context->storage[context->pos + 0] = EVENT_TYPE_LIST;
-    context->list[0] = context->pos + 1;
-    context->pos += needed;
-}
-
-int stats_write_list(android_log_context ctx) {
-    android_log_context_internal* context;
-    const char* msg;
-    ssize_t len;
-
-    context = (android_log_context_internal*)(ctx);
-    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
-        return -EBADF;
-    }
-
-    if (context->list_nest_depth) {
-        return -EIO;
-    }
-
-    /* NB: if there was overflow, then log is truncated. Nothing reported */
-    context->storage[1] = context->count[0];
-    len = context->len = context->pos;
-    msg = (const char*)context->storage;
-    /* it's not a list */
-    if (context->count[0] <= 1) {
-        len -= sizeof(uint8_t) + sizeof(uint8_t);
-        if (len < 0) {
-            len = 0;
-        }
-        msg += sizeof(uint8_t) + sizeof(uint8_t);
-    }
-
-    return write_buffer_to_statsd((void*)msg, len, 0);
-}
-
-int write_to_logger(android_log_context ctx, log_id_t id) {
-    int retValue = 0;
-
-    if (WRITE_TO_LOGD) {
-        retValue = android_log_write_list(ctx, id);
-    }
-
-    if (WRITE_TO_STATSD) {
-        // log_event_list's cast operator is overloaded.
-        int ret = stats_write_list(ctx);
-        // In debugging phase, we may write to both logd and statsd. Prefer to
-        // return statsd socket write error code here.
-        if (ret < 0) {
-            retValue = ret;
-        }
-    }
-
-    return retValue;
-}
-
-static inline void copy4LE(uint8_t* buf, uint32_t val) {
-    buf[0] = val & 0xFF;
-    buf[1] = (val >> 8) & 0xFF;
-    buf[2] = (val >> 16) & 0xFF;
-    buf[3] = (val >> 24) & 0xFF;
-}
-
-// Note: this function differs from android_log_write_string8_len in that the length passed in
-// should be treated as actual length and not max length.
-int android_log_write_char_array(android_log_context ctx, const char* value, size_t actual_len) {
-    size_t needed;
-    ssize_t len = actual_len;
-    android_log_context_internal* context;
-
-    context = (android_log_context_internal*)ctx;
-    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
-        return -EBADF;
-    }
-    if (context->overflow) {
-        return -EIO;
-    }
-    if (!value) {
-        value = "";
-        len = 0;
-    }
-    needed = sizeof(uint8_t) + sizeof(int32_t) + len;
-    if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
-        /* Truncate string for delivery */
-        len = MAX_EVENT_PAYLOAD - context->pos - 1 - sizeof(int32_t);
-        if (len <= 0) {
-            context->overflow = true;
-            return -EIO;
-        }
-    }
-    context->count[context->list_nest_depth]++;
-    context->storage[context->pos + 0] = EVENT_TYPE_STRING;
-    copy4LE(&context->storage[context->pos + 1], len);
-    if (len) {
-        memcpy(&context->storage[context->pos + 5], value, len);
-    }
-    context->pos += needed;
-    return len;
-}
diff --git a/libstats/socket/benchmark/main.cpp b/libstats/socket/stats_socket.c
similarity index 75%
rename from libstats/socket/benchmark/main.cpp
rename to libstats/socket/stats_socket.c
index 5ebdf6e..09f8967 100644
--- a/libstats/socket/benchmark/main.cpp
+++ b/libstats/socket/stats_socket.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open 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,6 +14,9 @@
  * limitations under the License.
  */
 
-#include <benchmark/benchmark.h>
+#include "include/stats_socket.h"
+#include "stats_buffer_writer.h"
 
-BENCHMARK_MAIN();
+void AStatsSocket_close() {
+    stats_log_close();
+}
diff --git a/libstats/socket/statsd_writer.c b/libstats/socket/statsd_writer.c
index 04d3b46..73b7a7e 100644
--- a/libstats/socket/statsd_writer.c
+++ b/libstats/socket/statsd_writer.c
@@ -62,6 +62,7 @@
 static void statsdClose();
 static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr);
 static void statsdNoteDrop();
+static int statsdIsClosed();
 
 struct android_log_transport_write statsdLoggerWrite = {
         .name = "statsd",
@@ -71,6 +72,7 @@
         .close = statsdClose,
         .write = statsdWrite,
         .noteDrop = statsdNoteDrop,
+        .isClosed = statsdIsClosed,
 };
 
 /* log_init_lock assumed */
@@ -153,6 +155,13 @@
     atomic_exchange_explicit(&atom_tag, tag, memory_order_relaxed);
 }
 
+static int statsdIsClosed() {
+    if (atomic_load(&statsdLoggerWrite.sock) < 0) {
+        return 1;
+    }
+    return 0;
+}
+
 static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) {
     ssize_t ret;
     int sock;
diff --git a/libstats/socket/statsd_writer.h b/libstats/socket/statsd_writer.h
index fe2d37c..562bda5 100644
--- a/libstats/socket/statsd_writer.h
+++ b/libstats/socket/statsd_writer.h
@@ -40,6 +40,8 @@
     int (*write)(struct timespec* ts, struct iovec* vec, size_t nr);
     /* note one log drop */
     void (*noteDrop)(int error, int tag);
+    /* checks if the socket is closed */
+    int (*isClosed)();
 };
 
 #endif  // ANDROID_STATS_LOG_STATS_WRITER_H
diff --git a/libstats/socket/tests/stats_event_test.cpp b/libstats/socket/tests/stats_event_test.cpp
index cf0592c..9a1fac8 100644
--- a/libstats/socket/tests/stats_event_test.cpp
+++ b/libstats/socket/tests/stats_event_test.cpp
@@ -18,13 +18,47 @@
 #include <gtest/gtest.h>
 #include <utils/SystemClock.h>
 
+// Keep in sync with stats_event.c. Consider moving to separate header file to avoid duplication.
+/* ERRORS */
+#define ERROR_NO_TIMESTAMP 0x1
+#define ERROR_NO_ATOM_ID 0x2
+#define ERROR_OVERFLOW 0x4
+#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
+#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
+#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
+#define ERROR_INVALID_ANNOTATION_ID 0x40
+#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
+#define ERROR_TOO_MANY_ANNOTATIONS 0x100
+#define ERROR_TOO_MANY_FIELDS 0x200
+#define ERROR_INVALID_VALUE_TYPE 0x400
+#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
+#define ERROR_ATOM_ID_INVALID_POSITION 0x2000
+
+/* TYPE IDS */
+#define INT32_TYPE 0x00
+#define INT64_TYPE 0x01
+#define STRING_TYPE 0x02
+#define LIST_TYPE 0x03
+#define FLOAT_TYPE 0x04
+#define BOOL_TYPE 0x05
+#define BYTE_ARRAY_TYPE 0x06
+#define OBJECT_TYPE 0x07
+#define KEY_VALUE_PAIRS_TYPE 0x08
+#define ATTRIBUTION_CHAIN_TYPE 0x09
+#define ERROR_TYPE 0x0F
+
 using std::string;
 using std::vector;
 
 // Side-effect: this function moves the start of the buffer past the read value
 template <class T>
 T readNext(uint8_t** buffer) {
-    T value = *(T*)(*buffer);
+    T value;
+    if ((reinterpret_cast<uintptr_t>(*buffer) % alignof(T)) == 0) {
+        value = *(T*)(*buffer);
+    } else {
+        memcpy(&value, *buffer, sizeof(T));
+    }
     *buffer += sizeof(T);
     return value;
 }
@@ -61,7 +95,7 @@
 }
 
 void checkMetadata(uint8_t** buffer, uint8_t numElements, int64_t startTime, int64_t endTime,
-                   uint32_t atomId) {
+                   uint32_t atomId, uint8_t numAtomLevelAnnotations = 0) {
     // All events start with OBJECT_TYPE id.
     checkTypeHeader(buffer, OBJECT_TYPE);
 
@@ -76,7 +110,7 @@
     EXPECT_LE(timestamp, endTime);
 
     // Check atom id
-    checkTypeHeader(buffer, INT32_TYPE);
+    checkTypeHeader(buffer, INT32_TYPE, numAtomLevelAnnotations);
     checkScalar(buffer, atomId);
 }
 
@@ -88,17 +122,17 @@
     bool boolValue = false;
 
     int64_t startTime = android::elapsedRealtimeNano();
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, atomId);
-    stats_event_write_int32(event, int32Value);
-    stats_event_write_int64(event, int64Value);
-    stats_event_write_float(event, floatValue);
-    stats_event_write_bool(event, boolValue);
-    stats_event_build(event);
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+    AStatsEvent_writeInt32(event, int32Value);
+    AStatsEvent_writeInt64(event, int64Value);
+    AStatsEvent_writeFloat(event, floatValue);
+    AStatsEvent_writeBool(event, boolValue);
+    AStatsEvent_build(event);
     int64_t endTime = android::elapsedRealtimeNano();
 
     size_t bufferSize;
-    uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+    uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
     uint8_t* bufferEnd = buffer + bufferSize;
 
     checkMetadata(&buffer, /*numElements=*/4, startTime, endTime, atomId);
@@ -120,8 +154,8 @@
     checkScalar(&buffer, boolValue);
 
     EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
-    EXPECT_EQ(stats_event_get_errors(event), 0);
-    stats_event_release(event);
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
 }
 
 TEST(StatsEventTest, TestStrings) {
@@ -129,14 +163,14 @@
     string str = "test_string";
 
     int64_t startTime = android::elapsedRealtimeNano();
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, atomId);
-    stats_event_write_string8(event, str.c_str());
-    stats_event_build(event);
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+    AStatsEvent_writeString(event, str.c_str());
+    AStatsEvent_build(event);
     int64_t endTime = android::elapsedRealtimeNano();
 
     size_t bufferSize;
-    uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+    uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
     uint8_t* bufferEnd = buffer + bufferSize;
 
     checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -145,8 +179,8 @@
     checkString(&buffer, str);
 
     EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
-    EXPECT_EQ(stats_event_get_errors(event), 0);
-    stats_event_release(event);
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
 }
 
 TEST(StatsEventTest, TestByteArrays) {
@@ -154,14 +188,14 @@
     vector<uint8_t> message = {'b', 'y', 't', '\0', 'e', 's'};
 
     int64_t startTime = android::elapsedRealtimeNano();
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, atomId);
-    stats_event_write_byte_array(event, message.data(), message.size());
-    stats_event_build(event);
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+    AStatsEvent_writeByteArray(event, message.data(), message.size());
+    AStatsEvent_build(event);
     int64_t endTime = android::elapsedRealtimeNano();
 
     size_t bufferSize;
-    uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+    uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
     uint8_t* bufferEnd = buffer + bufferSize;
 
     checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -170,8 +204,8 @@
     checkByteArray(&buffer, message);
 
     EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
-    EXPECT_EQ(stats_event_get_errors(event), 0);
-    stats_event_release(event);
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
 }
 
 TEST(StatsEventTest, TestAttributionChains) {
@@ -188,14 +222,14 @@
     }
 
     int64_t startTime = android::elapsedRealtimeNano();
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, atomId);
-    stats_event_write_attribution_chain(event, uids, cTags, numNodes);
-    stats_event_build(event);
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+    AStatsEvent_writeAttributionChain(event, uids, cTags, numNodes);
+    AStatsEvent_build(event);
     int64_t endTime = android::elapsedRealtimeNano();
 
     size_t bufferSize;
-    uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+    uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
     uint8_t* bufferEnd = buffer + bufferSize;
 
     checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -208,63 +242,11 @@
     }
 
     EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
-    EXPECT_EQ(stats_event_get_errors(event), 0);
-    stats_event_release(event);
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
 }
 
-TEST(StatsEventTest, TestKeyValuePairs) {
-    uint32_t atomId = 100;
-
-    uint8_t numPairs = 4;
-    struct key_value_pair pairs[numPairs];
-    pairs[0] = {.key = 0, .valueType = INT32_TYPE, .int32Value = -1};
-    pairs[1] = {.key = 1, .valueType = INT64_TYPE, .int64Value = 0x123456789};
-    pairs[2] = {.key = 2, .valueType = FLOAT_TYPE, .floatValue = 5.5};
-    string str = "test_key_value_pair_string";
-    pairs[3] = {.key = 3, .valueType = STRING_TYPE, .stringValue = str.c_str()};
-
-    int64_t startTime = android::elapsedRealtimeNano();
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, atomId);
-    stats_event_write_key_value_pairs(event, pairs, numPairs);
-    stats_event_build(event);
-    int64_t endTime = android::elapsedRealtimeNano();
-
-    size_t bufferSize;
-    uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
-    uint8_t* bufferEnd = buffer + bufferSize;
-
-    checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
-
-    checkTypeHeader(&buffer, KEY_VALUE_PAIRS_TYPE);
-    checkScalar(&buffer, numPairs);
-
-    // first pair
-    checkScalar(&buffer, pairs[0].key);
-    checkTypeHeader(&buffer, pairs[0].valueType);
-    checkScalar(&buffer, pairs[0].int32Value);
-
-    // second pair
-    checkScalar(&buffer, pairs[1].key);
-    checkTypeHeader(&buffer, pairs[1].valueType);
-    checkScalar(&buffer, pairs[1].int64Value);
-
-    // third pair
-    checkScalar(&buffer, pairs[2].key);
-    checkTypeHeader(&buffer, pairs[2].valueType);
-    checkScalar(&buffer, pairs[2].floatValue);
-
-    // fourth pair
-    checkScalar(&buffer, pairs[3].key);
-    checkTypeHeader(&buffer, pairs[3].valueType);
-    checkString(&buffer, str);
-
-    EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
-    EXPECT_EQ(stats_event_get_errors(event), 0);
-    stats_event_release(event);
-}
-
-TEST(StatsEventTest, TestAnnotations) {
+TEST(StatsEventTest, TestFieldAnnotations) {
     uint32_t atomId = 100;
 
     // first element information
@@ -282,19 +264,19 @@
     bool floatAnnotation2Value = false;
 
     int64_t startTime = android::elapsedRealtimeNano();
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, 100);
-    stats_event_write_bool(event, boolValue);
-    stats_event_add_bool_annotation(event, boolAnnotation1Id, boolAnnotation1Value);
-    stats_event_add_int32_annotation(event, boolAnnotation2Id, boolAnnotation2Value);
-    stats_event_write_float(event, floatValue);
-    stats_event_add_int32_annotation(event, floatAnnotation1Id, floatAnnotation1Value);
-    stats_event_add_bool_annotation(event, floatAnnotation2Id, floatAnnotation2Value);
-    stats_event_build(event);
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+    AStatsEvent_writeBool(event, boolValue);
+    AStatsEvent_addBoolAnnotation(event, boolAnnotation1Id, boolAnnotation1Value);
+    AStatsEvent_addInt32Annotation(event, boolAnnotation2Id, boolAnnotation2Value);
+    AStatsEvent_writeFloat(event, floatValue);
+    AStatsEvent_addInt32Annotation(event, floatAnnotation1Id, floatAnnotation1Value);
+    AStatsEvent_addBoolAnnotation(event, floatAnnotation2Id, floatAnnotation2Value);
+    AStatsEvent_build(event);
     int64_t endTime = android::elapsedRealtimeNano();
 
     size_t bufferSize;
-    uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+    uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
     uint8_t* bufferEnd = buffer + bufferSize;
 
     checkMetadata(&buffer, /*numElements=*/2, startTime, endTime, atomId);
@@ -312,33 +294,167 @@
     checkAnnotation(&buffer, floatAnnotation2Id, BOOL_TYPE, floatAnnotation2Value);
 
     EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
-    EXPECT_EQ(stats_event_get_errors(event), 0);
-    stats_event_release(event);
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
+}
+
+TEST(StatsEventTest, TestAtomLevelAnnotations) {
+    uint32_t atomId = 100;
+    // atom-level annotation information
+    uint8_t boolAnnotationId = 1;
+    uint8_t int32AnnotationId = 2;
+    bool boolAnnotationValue = false;
+    int32_t int32AnnotationValue = 5;
+
+    float fieldValue = -3.5;
+
+    int64_t startTime = android::elapsedRealtimeNano();
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+    AStatsEvent_addBoolAnnotation(event, boolAnnotationId, boolAnnotationValue);
+    AStatsEvent_addInt32Annotation(event, int32AnnotationId, int32AnnotationValue);
+    AStatsEvent_writeFloat(event, fieldValue);
+    AStatsEvent_build(event);
+    int64_t endTime = android::elapsedRealtimeNano();
+
+    size_t bufferSize;
+    uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
+    uint8_t* bufferEnd = buffer + bufferSize;
+
+    checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId,
+                  /*numAtomLevelAnnotations=*/2);
+
+    // check atom-level annotations
+    checkAnnotation(&buffer, boolAnnotationId, BOOL_TYPE, boolAnnotationValue);
+    checkAnnotation(&buffer, int32AnnotationId, INT32_TYPE, int32AnnotationValue);
+
+    // check first element
+    checkTypeHeader(&buffer, FLOAT_TYPE);
+    checkScalar(&buffer, fieldValue);
+
+    EXPECT_EQ(buffer, bufferEnd);  // ensure that we have read the entire buffer
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
 }
 
 TEST(StatsEventTest, TestNoAtomIdError) {
-    struct stats_event* event = stats_event_obtain();
+    AStatsEvent* event = AStatsEvent_obtain();
     // Don't set the atom id in order to trigger the error.
-    stats_event_build(event);
+    AStatsEvent_build(event);
 
-    uint32_t errors = stats_event_get_errors(event);
-    EXPECT_NE(errors | ERROR_NO_ATOM_ID, 0);
+    uint32_t errors = AStatsEvent_getErrors(event);
+    EXPECT_EQ(errors & ERROR_NO_ATOM_ID, ERROR_NO_ATOM_ID);
 
-    stats_event_release(event);
+    AStatsEvent_release(event);
 }
 
-TEST(StatsEventTest, TestOverflowError) {
-    struct stats_event* event = stats_event_obtain();
-    stats_event_set_atom_id(event, 100);
-    // Add 1000 int32s to the event. Each int32 takes 5 bytes so this will
+TEST(StatsEventTest, TestPushOverflowError) {
+    const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    const int writeCount = 120;  // Number of times to write str in the event.
+
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
+
+    // Add str to the event 120 times. Each str takes >35 bytes so this will
     // overflow the 4068 byte buffer.
-    for (int i = 0; i < 1000; i++) {
-        stats_event_write_int32(event, 0);
+    // We want to keep writeCount less than 127 to avoid hitting
+    // ERROR_TOO_MANY_FIELDS.
+    for (int i = 0; i < writeCount; i++) {
+        AStatsEvent_writeString(event, str);
     }
-    stats_event_build(event);
+    AStatsEvent_write(event);
 
-    uint32_t errors = stats_event_get_errors(event);
-    EXPECT_NE(errors | ERROR_OVERFLOW, 0);
+    uint32_t errors = AStatsEvent_getErrors(event);
+    EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
 
-    stats_event_release(event);
+    AStatsEvent_release(event);
+}
+
+TEST(StatsEventTest, TestPullOverflowError) {
+    const uint32_t atomId = 10100;
+    const vector<uint8_t> bytes(430 /* number of elements */, 1 /* value of each element */);
+    const int writeCount = 120;  // Number of times to write bytes in the event.
+
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+
+    // Add bytes to the event 120 times. Size of bytes is 430 so this will
+    // overflow the 50 KB pulled event buffer.
+    // We want to keep writeCount less than 127 to avoid hitting
+    // ERROR_TOO_MANY_FIELDS.
+    for (int i = 0; i < writeCount; i++) {
+        AStatsEvent_writeByteArray(event, bytes.data(), bytes.size());
+    }
+    AStatsEvent_build(event);
+
+    uint32_t errors = AStatsEvent_getErrors(event);
+    EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
+
+    AStatsEvent_release(event);
+}
+
+TEST(StatsEventTest, TestLargePull) {
+    const uint32_t atomId = 100;
+    const string str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    const int writeCount = 120;  // Number of times to write str in the event.
+    const int64_t startTime = android::elapsedRealtimeNano();
+
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+
+    // Add str to the event 120 times.
+    // We want to keep writeCount less than 127 to avoid hitting
+    // ERROR_TOO_MANY_FIELDS.
+    for (int i = 0; i < writeCount; i++) {
+        AStatsEvent_writeString(event, str.c_str());
+    }
+    AStatsEvent_build(event);
+    int64_t endTime = android::elapsedRealtimeNano();
+
+    size_t bufferSize;
+    uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
+    uint8_t* bufferEnd = buffer + bufferSize;
+
+    checkMetadata(&buffer, writeCount, startTime, endTime, atomId);
+
+    // Check all instances of str have been written.
+    for (int i = 0; i < writeCount; i++) {
+        checkTypeHeader(&buffer, STRING_TYPE);
+        checkString(&buffer, str);
+    }
+
+    EXPECT_EQ(buffer, bufferEnd);  // Ensure that we have read the entire buffer.
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
+}
+
+TEST(StatsEventTest, TestAtomIdInvalidPositionError) {
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_writeInt32(event, 0);
+    AStatsEvent_setAtomId(event, 100);
+    AStatsEvent_writeBool(event, true);
+    AStatsEvent_build(event);
+
+    uint32_t errors = AStatsEvent_getErrors(event);
+    EXPECT_EQ(errors & ERROR_ATOM_ID_INVALID_POSITION, ERROR_ATOM_ID_INVALID_POSITION);
+
+    AStatsEvent_release(event);
+}
+
+TEST(StatsEventTest, TestOverwriteTimestamp) {
+    uint32_t atomId = 100;
+    int64_t expectedTimestamp = 0x123456789;
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, atomId);
+    AStatsEvent_overwriteTimestamp(event, expectedTimestamp);
+    AStatsEvent_build(event);
+
+    uint8_t* buffer = AStatsEvent_getBuffer(event, NULL);
+
+    // Make sure that the timestamp is being overwritten.
+    checkMetadata(&buffer, /*numElements=*/0, /*startTime=*/expectedTimestamp,
+                  /*endTime=*/expectedTimestamp, atomId);
+
+    EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+    AStatsEvent_release(event);
 }
diff --git a/libstats/socket/tests/stats_writer_test.cpp b/libstats/socket/tests/stats_writer_test.cpp
new file mode 100644
index 0000000..749599f
--- /dev/null
+++ b/libstats/socket/tests/stats_writer_test.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "stats_buffer_writer.h"
+#include "stats_event.h"
+#include "stats_socket.h"
+
+TEST(StatsWriterTest, TestSocketClose) {
+    AStatsEvent* event = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(event, 100);
+    AStatsEvent_writeInt32(event, 5);
+    int successResult = AStatsEvent_write(event);
+    AStatsEvent_release(event);
+
+    // In the case of a successful write, we return the number of bytes written.
+    EXPECT_GT(successResult, 0);
+    EXPECT_FALSE(stats_log_is_closed());
+
+    AStatsSocket_close();
+
+    EXPECT_TRUE(stats_log_is_closed());
+}
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 9c1621b..3b6cfd8 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -185,7 +185,6 @@
     if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
         return false;
 
-    // Sanity check.
     int type = nh->nlmsg_type;
     if (type != RTM_NEWADDR && type != RTM_DELADDR) {
         SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type);
@@ -349,7 +348,6 @@
     uint8_t type = nh->nlmsg_type;
     const char *msgname = rtMessageName(type);
 
-    // Sanity check.
     if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
         SLOGE("%s: incorrect message type %d (%s)\n", __func__, type, msgname);
         return false;
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index fe2f3d6..e90afcd 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -201,50 +201,31 @@
         return 0;
     }
 
-    int ret = 0;
-    int e = 0; // SLOGW and sigaction are not inert regarding errno
     int current = 0;
 
-    struct sigaction new_action, old_action;
-    memset(&new_action, 0, sizeof(new_action));
-    new_action.sa_handler = SIG_IGN;
-    sigaction(SIGPIPE, &new_action, &old_action);
-
     for (;;) {
-        ssize_t rc = TEMP_FAILURE_RETRY(
-            writev(mSocket, iov + current, iovcnt - current));
-
-        if (rc > 0) {
-            size_t written = rc;
-            while ((current < iovcnt) && (written >= iov[current].iov_len)) {
-                written -= iov[current].iov_len;
-                current++;
-            }
-            if (current == iovcnt) {
-                break;
-            }
-            iov[current].iov_base = (char *)iov[current].iov_base + written;
-            iov[current].iov_len -= written;
-            continue;
-        }
+        ssize_t rc = TEMP_FAILURE_RETRY(writev(mSocket, iov + current, iovcnt - current));
 
         if (rc == 0) {
-            e = EIO;
+            errno = EIO;
             SLOGW("0 length write :(");
-        } else {
-            e = errno;
-            SLOGW("write error (%s)", strerror(e));
+            return -1;
+        } else if (rc < 0) {
+            SLOGW("write error (%s)", strerror(errno));
+            return -1;
         }
-        ret = -1;
-        break;
-    }
 
-    sigaction(SIGPIPE, &old_action, &new_action);
-
-    if (e != 0) {
-        errno = e;
+        size_t written = rc;
+        while (current < iovcnt && written >= iov[current].iov_len) {
+            written -= iov[current].iov_len;
+            current++;
+        }
+        if (current == iovcnt) {
+            return 0;
+        }
+        iov[current].iov_base = (char*)iov[current].iov_base + written;
+        iov[current].iov_len -= written;
     }
-    return ret;
 }
 
 void SocketClient::incRef() {
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 8cc780a..75a419c 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -131,7 +131,6 @@
         support_system_process: true,
     },
     defaults: ["libunwindstack_defaults"],
-
     srcs: ["DexFile.cpp"],
     cflags: ["-DDEXFILE_SUPPORT"],
     shared_libs: ["libdexfile_support"],
@@ -168,6 +167,7 @@
     defaults: ["libunwindstack_defaults"],
 
     visibility: [
+        "//external/gwp_asan",
         "//system/core/debuggerd",
         "//system/core/init",
         "//system/core/libbacktrace",
diff --git a/libunwindstack/DwarfCfa.cpp b/libunwindstack/DwarfCfa.cpp
index c128b9b..c6db209 100644
--- a/libunwindstack/DwarfCfa.cpp
+++ b/libunwindstack/DwarfCfa.cpp
@@ -26,7 +26,9 @@
 
 #include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfLocation.h>
+#include <unwindstack/Elf.h>
 #include <unwindstack/Log.h>
+#include <unwindstack/MachineArm64.h>
 
 #include "DwarfCfa.h"
 #include "DwarfEncoding.h"
@@ -204,8 +206,12 @@
 bool DwarfCfa<AddressType>::LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op,
                                            uint64_t* cur_pc) {
   const auto* cfa = &DwarfCfaInfo::kTable[op];
-  if (cfa->name[0] == '\0') {
-    log(indent, "Illegal");
+  if (cfa->name[0] == '\0' || (arch_ != ARCH_ARM64 && op == 0x2d)) {
+    if (op == 0x2d) {
+      log(indent, "Illegal (Only valid on aarch64)");
+    } else {
+      log(indent, "Illegal");
+    }
     log(indent, "Raw Data: 0x%02x", op);
     return true;
   }
@@ -514,6 +520,24 @@
   return true;
 }
 
+template <typename AddressType>
+bool DwarfCfa<AddressType>::cfa_aarch64_negate_ra_state(dwarf_loc_regs_t* loc_regs) {
+  // Only supported on aarch64.
+  if (arch_ != ARCH_ARM64) {
+    last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+    return false;
+  }
+
+  auto cfa_location = loc_regs->find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE);
+  if (cfa_location == loc_regs->end()) {
+    (*loc_regs)[Arm64Reg::ARM64_PREG_RA_SIGN_STATE] = {.type = DWARF_LOCATION_PSEUDO_REGISTER,
+                                                       .values = {1}};
+  } else {
+    cfa_location->second.values[0] ^= 1;
+  }
+  return true;
+}
+
 const DwarfCfaInfo::Info DwarfCfaInfo::kTable[64] = {
     {
         // 0x00 DW_CFA_nop
@@ -699,7 +723,13 @@
     {"", 0, 0, {}, {}},  // 0x2a illegal cfa
     {"", 0, 0, {}, {}},  // 0x2b illegal cfa
     {"", 0, 0, {}, {}},  // 0x2c illegal cfa
-    {"", 0, 0, {}, {}},  // 0x2d DW_CFA_GNU_window_save (Treat as illegal)
+    {
+        "DW_CFA_AARCH64_negate_ra_state",  // 0x2d DW_CFA_AARCH64_negate_ra_state
+        3,
+        0,
+        {},
+        {},
+    },
     {
         "DW_CFA_GNU_args_size",  // 0x2e DW_CFA_GNU_args_size
         2,
diff --git a/libunwindstack/DwarfCfa.h b/libunwindstack/DwarfCfa.h
index 569c17c..d627e15 100644
--- a/libunwindstack/DwarfCfa.h
+++ b/libunwindstack/DwarfCfa.h
@@ -31,6 +31,9 @@
 
 namespace unwindstack {
 
+// Forward declarations.
+enum ArchEnum : uint8_t;
+
 // DWARF Standard home: http://dwarfstd.org/
 // This code is based on DWARF 4: http://http://dwarfstd.org/doc/DWARF4.pdf
 // See section 6.4.2.1 for a description of the DW_CFA_xxx values.
@@ -72,7 +75,8 @@
   typedef typename std::make_signed<AddressType>::type SignedType;
 
  public:
-  DwarfCfa(DwarfMemory* memory, const DwarfFde* fde) : memory_(memory), fde_(fde) {}
+  DwarfCfa(DwarfMemory* memory, const DwarfFde* fde, ArchEnum arch)
+      : memory_(memory), fde_(fde), arch_(arch) {}
   virtual ~DwarfCfa() = default;
 
   bool GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset,
@@ -99,6 +103,7 @@
   DwarfErrorData last_error_;
   DwarfMemory* memory_;
   const DwarfFde* fde_;
+  ArchEnum arch_;
 
   AddressType cur_pc_;
   const dwarf_loc_regs_t* cie_loc_regs_ = nullptr;
@@ -128,6 +133,7 @@
   bool cfa_val_offset_sf(dwarf_loc_regs_t*);
   bool cfa_val_expression(dwarf_loc_regs_t*);
   bool cfa_gnu_negative_offset_extended(dwarf_loc_regs_t*);
+  bool cfa_aarch64_negate_ra_state(dwarf_loc_regs_t*);
 
   using process_func = bool (DwarfCfa::*)(dwarf_loc_regs_t*);
   constexpr static process_func kCallbackTable[64] = {
@@ -221,8 +227,9 @@
       nullptr,
       // 0x2c illegal cfa
       nullptr,
-      // 0x2d DW_CFA_GNU_window_save (Treat this as illegal)
-      nullptr,
+      // 0x2d DW_CFA_AARCH64_negate_ra_state (aarch64 only)
+      // DW_CFA_GNU_window_save on other architectures.
+      &DwarfCfa::cfa_aarch64_negate_ra_state,
       // 0x2e DW_CFA_GNU_args_size
       &DwarfCfa::cfa_nop,
       // 0x2f DW_CFA_GNU_negative_offset_extended
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 18bd490..bf86e6e 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -21,6 +21,7 @@
 #include <unwindstack/DwarfMemory.h>
 #include <unwindstack/DwarfSection.h>
 #include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Elf.h>
 #include <unwindstack/Log.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
@@ -49,7 +50,7 @@
 
     // Now get the location information for this pc.
     dwarf_loc_regs_t loc_regs;
-    if (!GetCfaLocationInfo(pc, fde, &loc_regs)) {
+    if (!GetCfaLocationInfo(pc, fde, &loc_regs, regs->Arch())) {
       return false;
     }
     loc_regs.cie = fde->cie;
@@ -464,6 +465,9 @@
         eval_info->return_address_undefined = true;
       }
       break;
+    case DWARF_LOCATION_PSEUDO_REGISTER:
+      last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+      return false;
     default:
       break;
   }
@@ -491,6 +495,10 @@
   // Always set the dex pc to zero when evaluating.
   cur_regs->set_dex_pc(0);
 
+  // Reset necessary pseudo registers before evaluation.
+  // This is needed for ARM64, for example.
+  regs->ResetPseudoRegisters();
+
   EvalInfo<AddressType> eval_info{.loc_regs = &loc_regs,
                                   .cie = cie,
                                   .regular_memory = regular_memory,
@@ -527,13 +535,19 @@
 
     AddressType* reg_ptr;
     if (reg >= cur_regs->total_regs()) {
-      // Skip this unknown register.
-      continue;
-    }
-
-    reg_ptr = eval_info.regs_info.Save(reg);
-    if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
-      return false;
+      if (entry.second.type != DWARF_LOCATION_PSEUDO_REGISTER) {
+        // Skip this unknown register.
+        continue;
+      }
+      if (!eval_info.regs_info.regs->SetPseudoRegister(reg, entry.second.values[0])) {
+        last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+        return false;
+      }
+    } else {
+      reg_ptr = eval_info.regs_info.Save(reg);
+      if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
+        return false;
+      }
     }
   }
 
@@ -554,8 +568,8 @@
 
 template <typename AddressType>
 bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde,
-                                                       dwarf_loc_regs_t* loc_regs) {
-  DwarfCfa<AddressType> cfa(&memory_, fde);
+                                                       dwarf_loc_regs_t* loc_regs, ArchEnum arch) {
+  DwarfCfa<AddressType> cfa(&memory_, fde, arch);
 
   // Look for the cached copy of the cie data.
   auto reg_entry = cie_loc_regs_.find(fde->cie_offset);
@@ -576,8 +590,9 @@
 }
 
 template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) {
-  DwarfCfa<AddressType> cfa(&memory_, fde);
+bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const DwarfFde* fde,
+                                        ArchEnum arch) {
+  DwarfCfa<AddressType> cfa(&memory_, fde, arch);
 
   // Always print the cie information.
   const DwarfCie* cie = fde->cie;
diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp
index 5b7431a..b496187 100644
--- a/libunwindstack/RegsArm64.cpp
+++ b/libunwindstack/RegsArm64.cpp
@@ -30,7 +30,10 @@
 namespace unwindstack {
 
 RegsArm64::RegsArm64()
-    : RegsImpl<uint64_t>(ARM64_REG_LAST, Location(LOCATION_REGISTER, ARM64_REG_LR)) {}
+    : RegsImpl<uint64_t>(ARM64_REG_LAST, Location(LOCATION_REGISTER, ARM64_REG_LR)) {
+  ResetPseudoRegisters();
+  pac_mask_ = 0;
+}
 
 ArchEnum RegsArm64::Arch() {
   return ARCH_ARM64;
@@ -45,6 +48,23 @@
 }
 
 void RegsArm64::set_pc(uint64_t pc) {
+  // If the target is aarch64 then the return address may have been
+  // signed using the Armv8.3-A Pointer Authentication extension. The
+  // original return address can be restored by stripping out the
+  // authentication code using a mask or xpaclri. xpaclri is a NOP on
+  // pre-Armv8.3-A architectures.
+  if ((0 != pc) && IsRASigned()) {
+    if (pac_mask_) {
+      pc &= ~pac_mask_;
+#if defined(__aarch64__)
+    } else {
+      register uint64_t x30 __asm("x30") = pc;
+      // This is XPACLRI.
+      asm("hint 0x7" : "+r"(x30));
+      pc = x30;
+#endif
+    }
+  }
   regs_[ARM64_REG_PC] = pc;
 }
 
@@ -144,6 +164,37 @@
   return true;
 }
 
+void RegsArm64::ResetPseudoRegisters(void) {
+  // DWARF for AArch64 says RA_SIGN_STATE should be initialized to 0.
+  this->SetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, 0);
+}
+
+bool RegsArm64::SetPseudoRegister(uint16_t id, uint64_t value) {
+  if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) {
+    pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST] = value;
+    return true;
+  }
+  return false;
+}
+
+bool RegsArm64::GetPseudoRegister(uint16_t id, uint64_t* value) {
+  if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) {
+    *value = pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST];
+    return true;
+  }
+  return false;
+}
+
+bool RegsArm64::IsRASigned() {
+  uint64_t value;
+  auto result = this->GetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, &value);
+  return (result && (value != 0));
+}
+
+void RegsArm64::SetPACMask(uint64_t mask) {
+  pac_mask_ = mask;
+}
+
 Regs* RegsArm64::Clone() {
   return new RegsArm64(*this);
 }
diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp
index c9e245d..26d9f65 100644
--- a/libunwindstack/RegsX86_64.cpp
+++ b/libunwindstack/RegsX86_64.cpp
@@ -141,15 +141,14 @@
     return false;
   }
 
-  uint16_t data2;
-  if (!elf_memory->ReadFully(elf_offset + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
+  uint8_t data2;
+  if (!elf_memory->ReadFully(elf_offset + 8, &data2, sizeof(data2)) || data2 != 0x05) {
     return false;
   }
 
   // __restore_rt:
   // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00   mov $0xf,%rax
   // 0x0f 0x05                            syscall
-  // 0x0f                                 nopl 0x0($rax)
 
   // Read the mcontext data from the stack.
   // sp points to the ucontext data structure, read only the mcontext part.
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 2d867cd..bcdbde8 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -27,6 +27,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
+#include <unwindstack/DexFiles.h>
 #include <unwindstack/Elf.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/MapInfo.h>
@@ -34,7 +35,7 @@
 #include <unwindstack/Memory.h>
 #include <unwindstack/Unwinder.h>
 
-#include <unwindstack/DexFiles.h>
+#include "Check.h"
 
 // Use the demangler from libc++.
 extern "C" char* __cxa_demangle(const char*, char*, size_t*, int* status);
@@ -75,6 +76,7 @@
     frame->rel_pc = dex_pc - info->start;
   } else {
     frame->rel_pc = dex_pc;
+    warnings_ |= WARNING_DEX_PC_NOT_IN_MAP;
     return;
   }
 
@@ -141,12 +143,11 @@
 
 void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
                       const std::vector<std::string>* map_suffixes_to_ignore) {
-  frames_.clear();
-  last_error_.code = ERROR_NONE;
-  last_error_.address = 0;
-  elf_from_memory_not_file_ = false;
+  CHECK(arch_ != ARCH_UNKNOWN);
+  ClearErrors();
 
-  ArchEnum arch = regs_->Arch();
+  frames_.clear();
+  elf_from_memory_not_file_ = false;
 
   bool return_address_attempt = false;
   bool adjust_pc = false;
@@ -167,7 +168,7 @@
       if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
         break;
       }
-      elf = map_info->GetElf(process_memory_, arch);
+      elf = map_info->GetElf(process_memory_, arch_);
       // If this elf is memory backed, and there is a valid file, then set
       // an indicator that we couldn't open the file.
       if (!elf_from_memory_not_file_ && map_info->memory_backed_elf && !map_info->name.empty() &&
@@ -181,7 +182,7 @@
         step_pc = rel_pc;
       }
       if (adjust_pc) {
-        pc_adjustment = GetPcAdjustment(rel_pc, elf, arch);
+        pc_adjustment = GetPcAdjustment(rel_pc, elf, arch_);
       } else {
         pc_adjustment = 0;
       }
@@ -309,7 +310,7 @@
 
 std::string Unwinder::FormatFrame(const FrameData& frame) const {
   std::string data;
-  if (regs_->Is32Bit()) {
+  if (ArchIs32Bit(arch_)) {
     data += android::base::StringPrintf("  #%02zu pc %08" PRIx64, frame.num, frame.rel_pc);
   } else {
     data += android::base::StringPrintf("  #%02zu pc %016" PRIx64, frame.num, frame.rel_pc);
@@ -360,23 +361,33 @@
   return FormatFrame(frames_[frame_num]);
 }
 
-void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) {
-  jit_debug->SetArch(arch);
+void Unwinder::SetJitDebug(JitDebug* jit_debug) {
+  CHECK(arch_ != ARCH_UNKNOWN);
+  jit_debug->SetArch(arch_);
   jit_debug_ = jit_debug;
 }
 
-void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) {
-  dex_files->SetArch(arch);
+void Unwinder::SetDexFiles(DexFiles* dex_files) {
+  CHECK(arch_ != ARCH_UNKNOWN);
+  dex_files->SetArch(arch_);
   dex_files_ = dex_files;
 }
 
-bool UnwinderFromPid::Init(ArchEnum arch) {
+bool UnwinderFromPid::Init() {
+  CHECK(arch_ != ARCH_UNKNOWN);
+  if (initted_) {
+    return true;
+  }
+  initted_ = true;
+
   if (pid_ == getpid()) {
     maps_ptr_.reset(new LocalMaps());
   } else {
     maps_ptr_.reset(new RemoteMaps(pid_));
   }
   if (!maps_ptr_->Parse()) {
+    ClearErrors();
+    last_error_.code = ERROR_INVALID_MAP;
     return false;
   }
   maps_ = maps_ptr_.get();
@@ -385,28 +396,38 @@
 
   jit_debug_ptr_.reset(new JitDebug(process_memory_));
   jit_debug_ = jit_debug_ptr_.get();
-  SetJitDebug(jit_debug_, arch);
+  SetJitDebug(jit_debug_);
 #if defined(DEXFILE_SUPPORT)
   dex_files_ptr_.reset(new DexFiles(process_memory_));
   dex_files_ = dex_files_ptr_.get();
-  SetDexFiles(dex_files_, arch);
+  SetDexFiles(dex_files_);
 #endif
 
   return true;
 }
 
-FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc) {
+void UnwinderFromPid::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
+                             const std::vector<std::string>* map_suffixes_to_ignore) {
+  if (!Init()) {
+    return;
+  }
+  Unwinder::Unwind(initial_map_names_to_skip, map_suffixes_to_ignore);
+}
+
+FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc, ArchEnum arch, Maps* maps,
+                                         JitDebug* jit_debug,
+                                         std::shared_ptr<Memory> process_memory,
+                                         bool resolve_names) {
   FrameData frame;
 
-  Maps* maps = GetMaps();
   MapInfo* map_info = maps->Find(pc);
-  if (!map_info) {
+  if (map_info == nullptr || arch == ARCH_UNKNOWN) {
+    frame.pc = pc;
     frame.rel_pc = pc;
     return frame;
   }
 
-  ArchEnum arch = Regs::CurrentArch();
-  Elf* elf = map_info->GetElf(GetProcessMemory(), arch);
+  Elf* elf = map_info->GetElf(process_memory, arch);
 
   uint64_t relative_pc = elf->GetRelPc(pc, map_info);
 
@@ -416,10 +437,9 @@
   uint64_t debug_pc = relative_pc;
 
   // If we don't have a valid ELF file, check the JIT.
-  if (!elf->valid()) {
-    JitDebug jit_debug(GetProcessMemory());
+  if (!elf->valid() && jit_debug != nullptr) {
     uint64_t jit_pc = pc - pc_adjustment;
-    Elf* jit_elf = jit_debug.GetElf(maps, jit_pc);
+    Elf* jit_elf = jit_debug->GetElf(maps, jit_pc);
     if (jit_elf != nullptr) {
       debug_pc = jit_pc;
       elf = jit_elf;
@@ -437,12 +457,16 @@
   frame.map_flags = map_info->flags;
   frame.map_load_bias = elf->GetLoadBias();
 
-  if (!resolve_names_ ||
-      !elf->GetFunctionName(relative_pc, &frame.function_name, &frame.function_offset)) {
+  if (!resolve_names ||
+      !elf->GetFunctionName(debug_pc, &frame.function_name, &frame.function_offset)) {
     frame.function_name = "";
     frame.function_offset = 0;
   }
   return frame;
 }
 
+FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc) {
+  return BuildFrameFromPcOnly(pc, arch_, maps_, jit_debug_, process_memory_, resolve_names_);
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Arch.h b/libunwindstack/include/unwindstack/Arch.h
new file mode 100644
index 0000000..7060004
--- /dev/null
+++ b/libunwindstack/include/unwindstack/Arch.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 _LIBUNWINDSTACK_ARCH_H
+#define _LIBUNWINDSTACK_ARCH_H
+
+#include <stddef.h>
+
+namespace unwindstack {
+
+enum ArchEnum : uint8_t {
+  ARCH_UNKNOWN = 0,
+  ARCH_ARM,
+  ARCH_ARM64,
+  ARCH_X86,
+  ARCH_X86_64,
+  ARCH_MIPS,
+  ARCH_MIPS64,
+};
+
+static inline bool ArchIs32Bit(ArchEnum arch) {
+  switch (arch) {
+    case ARCH_ARM:
+    case ARCH_X86:
+    case ARCH_MIPS:
+      return true;
+    default:
+      return false;
+  }
+}
+
+}  // namespace unwindstack
+
+#endif  // _LIBUNWINDSTACK_ARCH_H
diff --git a/libunwindstack/include/unwindstack/DwarfLocation.h b/libunwindstack/include/unwindstack/DwarfLocation.h
index 3d50ccf..bf45bc7 100644
--- a/libunwindstack/include/unwindstack/DwarfLocation.h
+++ b/libunwindstack/include/unwindstack/DwarfLocation.h
@@ -33,6 +33,7 @@
   DWARF_LOCATION_REGISTER,
   DWARF_LOCATION_EXPRESSION,
   DWARF_LOCATION_VAL_EXPRESSION,
+  DWARF_LOCATION_PSEUDO_REGISTER,
 };
 
 struct DwarfLocation {
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index c244749..af823da 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -31,6 +31,7 @@
 namespace unwindstack {
 
 // Forward declarations.
+enum ArchEnum : uint8_t;
 class Memory;
 class Regs;
 template <typename AddressType>
@@ -90,13 +91,14 @@
 
   virtual bool Eval(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*) = 0;
 
-  virtual bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) = 0;
+  virtual bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde, ArchEnum arch) = 0;
 
   virtual void GetFdes(std::vector<const DwarfFde*>* fdes) = 0;
 
   virtual const DwarfFde* GetFdeFromPc(uint64_t pc) = 0;
 
-  virtual bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) = 0;
+  virtual bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs,
+                                  ArchEnum arch) = 0;
 
   virtual uint64_t GetCieOffsetFromFde32(uint32_t pointer) = 0;
 
@@ -140,9 +142,10 @@
   bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs,
             Regs* regs, bool* finished) override;
 
-  bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) override;
+  bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs,
+                          ArchEnum arch) override;
 
-  bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) override;
+  bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde, ArchEnum arch) override;
 
  protected:
   bool GetNextCieOrFde(const DwarfFde** fde_entry);
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 472ed92..97614b1 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -25,6 +25,7 @@
 #include <unordered_map>
 #include <utility>
 
+#include <unwindstack/Arch.h>
 #include <unwindstack/ElfInterface.h>
 #include <unwindstack/Memory.h>
 
@@ -38,16 +39,6 @@
 struct MapInfo;
 class Regs;
 
-enum ArchEnum : uint8_t {
-  ARCH_UNKNOWN = 0,
-  ARCH_ARM,
-  ARCH_ARM64,
-  ARCH_X86,
-  ARCH_X86_64,
-  ARCH_MIPS,
-  ARCH_MIPS64,
-};
-
 class Elf {
  public:
   Elf(Memory* memory) : memory_(memory) {}
diff --git a/libunwindstack/include/unwindstack/Error.h b/libunwindstack/include/unwindstack/Error.h
index 72ec454..0be4572 100644
--- a/libunwindstack/include/unwindstack/Error.h
+++ b/libunwindstack/include/unwindstack/Error.h
@@ -21,6 +21,13 @@
 
 namespace unwindstack {
 
+// A bit map of warnings, multiple warnings can be set at the same time.
+enum WarningCode : uint64_t {
+  WARNING_NONE = 0,
+  WARNING_DEX_PC_NOT_IN_MAP = 0x1,  // A dex pc was found, but it doesn't exist
+                                    // in any valid map.
+};
+
 enum ErrorCode : uint8_t {
   ERROR_NONE,                 // No error.
   ERROR_MEMORY_INVALID,       // Memory read failed.
@@ -32,6 +39,27 @@
   ERROR_INVALID_ELF,          // Unwind in an invalid elf.
 };
 
+static inline const char* GetErrorCodeString(ErrorCode error) {
+  switch (error) {
+    case ERROR_NONE:
+      return "None";
+    case ERROR_MEMORY_INVALID:
+      return "Memory Invalid";
+    case ERROR_UNWIND_INFO:
+      return "Unwind Info";
+    case ERROR_UNSUPPORTED:
+      return "Unsupported";
+    case ERROR_INVALID_MAP:
+      return "Invalid Map";
+    case ERROR_MAX_FRAMES_EXCEEDED:
+      return "Maximum Frames Exceeded";
+    case ERROR_REPEATED_FRAME:
+      return "Repeated Frame";
+    case ERROR_INVALID_ELF:
+      return "Invalid Elf";
+  }
+}
+
 struct ErrorData {
   ErrorCode code;
   uint64_t address;  // Only valid when code is ERROR_MEMORY_INVALID.
diff --git a/libunwindstack/include/unwindstack/MachineArm64.h b/libunwindstack/include/unwindstack/MachineArm64.h
index e953335..358e3d9 100644
--- a/libunwindstack/include/unwindstack/MachineArm64.h
+++ b/libunwindstack/include/unwindstack/MachineArm64.h
@@ -60,6 +60,13 @@
 
   ARM64_REG_SP = ARM64_REG_R31,
   ARM64_REG_LR = ARM64_REG_R30,
+
+  // Pseudo registers. These are not machine registers.
+
+  // AARCH64 Return address signed state pseudo-register
+  ARM64_PREG_RA_SIGN_STATE = 34,
+  ARM64_PREG_FIRST = ARM64_PREG_RA_SIGN_STATE,
+  ARM64_PREG_LAST,
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
index a367e6c..1a2a704 100644
--- a/libunwindstack/include/unwindstack/Regs.h
+++ b/libunwindstack/include/unwindstack/Regs.h
@@ -24,11 +24,12 @@
 #include <string>
 #include <vector>
 
+#include <unwindstack/Arch.h>
+
 namespace unwindstack {
 
 // Forward declarations.
 class Elf;
-enum ArchEnum : uint8_t;
 class Memory;
 
 class Regs {
@@ -52,7 +53,7 @@
 
   virtual ArchEnum Arch() = 0;
 
-  virtual bool Is32Bit() = 0;
+  bool Is32Bit() { return ArchIs32Bit(Arch()); }
 
   virtual void* RawData() = 0;
   virtual uint64_t pc() = 0;
@@ -64,6 +65,10 @@
   uint64_t dex_pc() { return dex_pc_; }
   void set_dex_pc(uint64_t dex_pc) { dex_pc_ = dex_pc; }
 
+  virtual void ResetPseudoRegisters() {}
+  virtual bool SetPseudoRegister(uint16_t, uint64_t) { return false; }
+  virtual bool GetPseudoRegister(uint16_t, uint64_t*) { return false; }
+
   virtual bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) = 0;
 
   virtual bool SetPcFromReturnAddress(Memory* process_memory) = 0;
@@ -92,8 +97,6 @@
       : Regs(total_regs, return_loc), regs_(total_regs) {}
   virtual ~RegsImpl() = default;
 
-  bool Is32Bit() override { return sizeof(AddressType) == sizeof(uint32_t); }
-
   inline AddressType& operator[](size_t reg) { return regs_[reg]; }
 
   void* RawData() override { return regs_.data(); }
diff --git a/libunwindstack/include/unwindstack/RegsArm64.h b/libunwindstack/include/unwindstack/RegsArm64.h
index 2b3ddeb..bf7ab15 100644
--- a/libunwindstack/include/unwindstack/RegsArm64.h
+++ b/libunwindstack/include/unwindstack/RegsArm64.h
@@ -22,6 +22,7 @@
 #include <functional>
 
 #include <unwindstack/Elf.h>
+#include <unwindstack/MachineArm64.h>
 #include <unwindstack/Regs.h>
 
 namespace unwindstack {
@@ -48,11 +49,25 @@
   void set_pc(uint64_t pc) override;
   void set_sp(uint64_t sp) override;
 
+  void ResetPseudoRegisters() override;
+
+  bool SetPseudoRegister(uint16_t id, uint64_t value) override;
+
+  bool GetPseudoRegister(uint16_t id, uint64_t* value) override;
+
+  bool IsRASigned();
+
+  void SetPACMask(uint64_t mask);
+
   Regs* Clone() override final;
 
   static Regs* Read(void* data);
 
   static Regs* CreateFromUcontext(void* ucontext);
+
+ protected:
+  uint64_t pseudo_regs_[Arm64Reg::ARM64_PREG_LAST - Arm64Reg::ARM64_PREG_FIRST];
+  uint64_t pac_mask_;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 4d49f23..b274c4c 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -24,6 +24,7 @@
 #include <string>
 #include <vector>
 
+#include <unwindstack/Arch.h>
 #include <unwindstack/DexFiles.h>
 #include <unwindstack/Error.h>
 #include <unwindstack/JitDebug.h>
@@ -35,7 +36,6 @@
 
 // Forward declarations.
 class Elf;
-enum ArchEnum : uint8_t;
 
 struct FrameData {
   size_t num;
@@ -64,7 +64,11 @@
 class Unwinder {
  public:
   Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr<Memory> process_memory)
-      : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) {
+      : max_frames_(max_frames),
+        maps_(maps),
+        regs_(regs),
+        process_memory_(process_memory),
+        arch_(regs->Arch()) {
     frames_.reserve(max_frames);
   }
   Unwinder(size_t max_frames, Maps* maps, std::shared_ptr<Memory> process_memory)
@@ -74,8 +78,8 @@
 
   virtual ~Unwinder() = default;
 
-  void Unwind(const std::vector<std::string>* initial_map_names_to_skip = nullptr,
-              const std::vector<std::string>* map_suffixes_to_ignore = nullptr);
+  virtual void Unwind(const std::vector<std::string>* initial_map_names_to_skip = nullptr,
+                      const std::vector<std::string>* map_suffixes_to_ignore = nullptr);
 
   size_t NumFrames() const { return frames_.size(); }
 
@@ -90,9 +94,14 @@
   std::string FormatFrame(size_t frame_num) const;
   std::string FormatFrame(const FrameData& frame) const;
 
-  void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
+  void SetArch(ArchEnum arch) { arch_ = arch; };
 
-  void SetRegs(Regs* regs) { regs_ = regs; }
+  void SetJitDebug(JitDebug* jit_debug);
+
+  void SetRegs(Regs* regs) {
+    regs_ = regs;
+    arch_ = regs_ != nullptr ? regs->Arch() : ARCH_UNKNOWN;
+  }
   Maps* GetMaps() { return maps_; }
   std::shared_ptr<Memory>& GetProcessMemory() { return process_memory_; }
 
@@ -107,22 +116,35 @@
 
   void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; }
 
-  void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
+  void SetDexFiles(DexFiles* dex_files);
 
   bool elf_from_memory_not_file() { return elf_from_memory_not_file_; }
 
   ErrorCode LastErrorCode() { return last_error_.code; }
+  const char* LastErrorCodeString() { return GetErrorCodeString(last_error_.code); }
   uint64_t LastErrorAddress() { return last_error_.address; }
+  uint64_t warnings() { return warnings_; }
 
   // Builds a frame for symbolization using the maps from this unwinder. The
   // constructed frame contains just enough information to be used to symbolize
   // frames collected by frame-pointer unwinding that's done outside of
   // libunwindstack. This is used by tombstoned to symbolize frame pointer-based
   // stack traces that are collected by tools such as GWP-ASan and MTE.
+  static FrameData BuildFrameFromPcOnly(uint64_t pc, ArchEnum arch, Maps* maps, JitDebug* jit_debug,
+                                        std::shared_ptr<Memory> process_memory, bool resolve_names);
   FrameData BuildFrameFromPcOnly(uint64_t pc);
 
  protected:
   Unwinder(size_t max_frames) : max_frames_(max_frames) { frames_.reserve(max_frames); }
+  Unwinder(size_t max_frames, ArchEnum arch) : max_frames_(max_frames), arch_(arch) {
+    frames_.reserve(max_frames);
+  }
+
+  void ClearErrors() {
+    warnings_ = WARNING_NONE;
+    last_error_.code = ERROR_NONE;
+    last_error_.address = 0;
+  }
 
   void FillInDexFrame();
   FrameData* FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t pc_adjustment);
@@ -141,20 +163,28 @@
   // file. This is only true if there is an actual file backing up the elf.
   bool elf_from_memory_not_file_ = false;
   ErrorData last_error_;
+  uint64_t warnings_;
+  ArchEnum arch_ = ARCH_UNKNOWN;
 };
 
 class UnwinderFromPid : public Unwinder {
  public:
   UnwinderFromPid(size_t max_frames, pid_t pid) : Unwinder(max_frames), pid_(pid) {}
+  UnwinderFromPid(size_t max_frames, pid_t pid, ArchEnum arch)
+      : Unwinder(max_frames, arch), pid_(pid) {}
   virtual ~UnwinderFromPid() = default;
 
-  bool Init(ArchEnum arch);
+  bool Init();
+
+  void Unwind(const std::vector<std::string>* initial_map_names_to_skip = nullptr,
+              const std::vector<std::string>* map_suffixes_to_ignore = nullptr) override;
 
  private:
   pid_t pid_;
   std::unique_ptr<Maps> maps_ptr_;
   std::unique_ptr<JitDebug> jit_debug_ptr_;
   std::unique_ptr<DexFiles> dex_files_ptr_;
+  bool initted_ = false;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfCfaLogTest.cpp b/libunwindstack/tests/DwarfCfaLogTest.cpp
index def4088..2b5a8dc 100644
--- a/libunwindstack/tests/DwarfCfaLogTest.cpp
+++ b/libunwindstack/tests/DwarfCfaLogTest.cpp
@@ -26,6 +26,7 @@
 #include <unwindstack/DwarfLocation.h>
 #include <unwindstack/DwarfMemory.h>
 #include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Elf.h>
 #include <unwindstack/Log.h>
 
 #include "DwarfCfa.h"
@@ -57,7 +58,7 @@
     fde_.pc_end = 0x2000;
     fde_.pc_end = 0x10000;
     fde_.cie = &cie_;
-    cfa_.reset(new DwarfCfa<TypeParam>(dmem_.get(), &fde_));
+    cfa_.reset(new DwarfCfa<TypeParam>(dmem_.get(), &fde_, ARCH_UNKNOWN));
   }
 
   MemoryFake memory_;
@@ -72,8 +73,8 @@
 
 TYPED_TEST_P(DwarfCfaLogTest, cfa_illegal) {
   for (uint8_t i = 0x17; i < 0x3f; i++) {
-    if (i == 0x2e || i == 0x2f) {
-      // Skip gnu extension ops.
+    if (i == 0x2d || i == 0x2e || i == 0x2f) {
+      // Skip gnu extension ops and aarch64 specialized op.
       continue;
     }
     this->memory_.SetMemory(0x2000, std::vector<uint8_t>{i});
@@ -763,6 +764,26 @@
   ASSERT_EQ("", GetFakeLogBuf());
 }
 
+TYPED_TEST_P(DwarfCfaLogTest, cfa_aarch64_negate_ra_state) {
+  // Verify that if the cfa op is handled properly depending on aarch.
+  this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x2d});
+
+  ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2001));
+  std::string expected = "4 unwind Illegal (Only valid on aarch64)\n";
+  expected += "4 unwind Raw Data: 0x2d\n";
+  ASSERT_EQ(expected, GetFakeLogPrint());
+  ASSERT_EQ("", GetFakeLogBuf());
+
+  ResetLogs();
+  this->cfa_.reset(new DwarfCfa<TypeParam>(this->dmem_.get(), &this->fde_, ARCH_ARM64));
+
+  ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2001));
+  expected = "4 unwind DW_CFA_AARCH64_negate_ra_state\n";
+  expected += "4 unwind Raw Data: 0x2d\n";
+  ASSERT_EQ(expected, GetFakeLogPrint());
+  ASSERT_EQ("", GetFakeLogBuf());
+}
+
 REGISTER_TYPED_TEST_SUITE_P(DwarfCfaLogTest, cfa_illegal, cfa_nop, cfa_offset, cfa_offset_extended,
                             cfa_offset_extended_sf, cfa_restore, cfa_restore_extended, cfa_set_loc,
                             cfa_advance_loc, cfa_advance_loc1, cfa_advance_loc2, cfa_advance_loc4,
@@ -771,7 +792,8 @@
                             cfa_def_cfa_register, cfa_def_cfa_offset, cfa_def_cfa_offset_sf,
                             cfa_def_cfa_expression, cfa_expression, cfa_val_offset,
                             cfa_val_offset_sf, cfa_val_expression, cfa_gnu_args_size,
-                            cfa_gnu_negative_offset_extended, cfa_register_override);
+                            cfa_gnu_negative_offset_extended, cfa_register_override,
+                            cfa_aarch64_negate_ra_state);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaLogTestTypes;
 INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfCfaLogTest, DwarfCfaLogTestTypes);
diff --git a/libunwindstack/tests/DwarfCfaTest.cpp b/libunwindstack/tests/DwarfCfaTest.cpp
index 9c6ab05..ea7e708 100644
--- a/libunwindstack/tests/DwarfCfaTest.cpp
+++ b/libunwindstack/tests/DwarfCfaTest.cpp
@@ -25,7 +25,9 @@
 #include <unwindstack/DwarfLocation.h>
 #include <unwindstack/DwarfMemory.h>
 #include <unwindstack/DwarfStructs.h>
+#include <unwindstack/Elf.h>
 #include <unwindstack/Log.h>
+#include <unwindstack/MachineArm64.h>
 
 #include "DwarfCfa.h"
 
@@ -55,7 +57,7 @@
     fde_.pc_start = 0x2000;
     fde_.cie = &cie_;
 
-    cfa_.reset(new DwarfCfa<TypeParam>(dmem_.get(), &fde_));
+    cfa_.reset(new DwarfCfa<TypeParam>(dmem_.get(), &fde_, ARCH_UNKNOWN));
   }
 
   MemoryFake memory_;
@@ -70,8 +72,8 @@
 
 TYPED_TEST_P(DwarfCfaTest, cfa_illegal) {
   for (uint8_t i = 0x17; i < 0x3f; i++) {
-    if (i == 0x2e || i == 0x2f) {
-      // Skip gnu extension ops.
+    if (i == 0x2d || i == 0x2e || i == 0x2f) {
+      // Skip gnu extension ops and aarch64 specialized op.
       continue;
     }
     this->memory_.SetMemory(0x2000, std::vector<uint8_t>{i});
@@ -952,6 +954,57 @@
   ASSERT_EQ("", GetFakeLogBuf());
 }
 
+TYPED_TEST_P(DwarfCfaTest, cfa_aarch64_negate_ra_state) {
+  this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x2d});
+  dwarf_loc_regs_t loc_regs;
+
+  ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
+  ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->cfa_->LastErrorCode());
+  ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
+
+  ASSERT_EQ("", GetFakeLogPrint());
+  ASSERT_EQ("", GetFakeLogBuf());
+
+  ResetLogs();
+  this->cfa_.reset(new DwarfCfa<TypeParam>(this->dmem_.get(), &this->fde_, ARCH_ARM64));
+  ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
+  ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
+
+  auto location = loc_regs.find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE);
+  ASSERT_NE(loc_regs.end(), location);
+  ASSERT_EQ(DWARF_LOCATION_PSEUDO_REGISTER, location->second.type);
+  ASSERT_EQ(1U, location->second.values[0]);
+
+  ASSERT_EQ("", GetFakeLogPrint());
+  ASSERT_EQ("", GetFakeLogBuf());
+
+  // Verify that the value is set to 0 after another evaluation.
+  ResetLogs();
+  ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
+  ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
+
+  location = loc_regs.find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE);
+  ASSERT_NE(loc_regs.end(), location);
+  ASSERT_EQ(DWARF_LOCATION_PSEUDO_REGISTER, location->second.type);
+  ASSERT_EQ(0U, location->second.values[0]);
+
+  ASSERT_EQ("", GetFakeLogPrint());
+  ASSERT_EQ("", GetFakeLogBuf());
+
+  // Verify that the value is set to 1 again after a third op.
+  ResetLogs();
+  ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
+  ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
+
+  location = loc_regs.find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE);
+  ASSERT_NE(loc_regs.end(), location);
+  ASSERT_EQ(DWARF_LOCATION_PSEUDO_REGISTER, location->second.type);
+  ASSERT_EQ(1U, location->second.values[0]);
+
+  ASSERT_EQ("", GetFakeLogPrint());
+  ASSERT_EQ("", GetFakeLogBuf());
+}
+
 REGISTER_TYPED_TEST_SUITE_P(DwarfCfaTest, cfa_illegal, cfa_nop, cfa_offset, cfa_offset_extended,
                             cfa_offset_extended_sf, cfa_restore, cfa_restore_extended, cfa_set_loc,
                             cfa_advance_loc1, cfa_advance_loc2, cfa_advance_loc4, cfa_undefined,
@@ -960,7 +1013,7 @@
                             cfa_def_cfa_offset_sf, cfa_def_cfa_expression, cfa_expression,
                             cfa_val_offset, cfa_val_offset_sf, cfa_val_expression,
                             cfa_gnu_args_size, cfa_gnu_negative_offset_extended,
-                            cfa_register_override);
+                            cfa_register_override, cfa_aarch64_negate_ra_state);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaTestTypes;
 INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfCfaTest, DwarfCfaTestTypes);
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index cac59b7..a08a8d0 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -20,6 +20,7 @@
 
 #include <unwindstack/DwarfError.h>
 #include <unwindstack/DwarfSection.h>
+#include <unwindstack/Elf.h>
 
 #include "DwarfEncoding.h"
 
@@ -491,6 +492,40 @@
   EXPECT_EQ(0x80000000U, regs.pc());
 }
 
+TYPED_TEST_P(DwarfSectionImplTest, Eval_pseudo_register_invalid) {
+  DwarfCie cie{.return_address_register = 5};
+  RegsImplFake<TypeParam> regs(10);
+  regs.set_pseudo_reg(11);
+  dwarf_loc_regs_t loc_regs;
+
+  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+  loc_regs[1] = DwarfLocation{DWARF_LOCATION_PSEUDO_REGISTER, {20, 0}};
+  bool finished;
+  ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
+
+  loc_regs.clear();
+  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+  loc_regs[12] = DwarfLocation{DWARF_LOCATION_PSEUDO_REGISTER, {20, 0}};
+  ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+  EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
+}
+
+TYPED_TEST_P(DwarfSectionImplTest, Eval_pseudo_register) {
+  DwarfCie cie{.return_address_register = 5};
+  RegsImplFake<TypeParam> regs(10);
+  regs.set_pseudo_reg(11);
+  dwarf_loc_regs_t loc_regs;
+
+  loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
+  loc_regs[11] = DwarfLocation{DWARF_LOCATION_PSEUDO_REGISTER, {20, 0}};
+  bool finished;
+  ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, &regs, &finished));
+  uint64_t pseudo_value = 0;
+  ASSERT_TRUE(regs.GetPseudoRegister(11, &pseudo_value));
+  EXPECT_EQ(20U, pseudo_value);
+}
+
 TYPED_TEST_P(DwarfSectionImplTest, GetCfaLocationInfo_cie_not_cached) {
   DwarfCie cie{};
   cie.cfa_instructions_offset = 0x3000;
@@ -505,7 +540,7 @@
   this->memory_.SetMemory(0x6000, std::vector<uint8_t>{0x09, 0x04, 0x03});
 
   dwarf_loc_regs_t loc_regs;
-  ASSERT_TRUE(this->section_->GetCfaLocationInfo(0x100, &fde, &loc_regs));
+  ASSERT_TRUE(this->section_->GetCfaLocationInfo(0x100, &fde, &loc_regs, ARCH_UNKNOWN));
   ASSERT_EQ(2U, loc_regs.size());
 
   auto entry = loc_regs.find(2);
@@ -535,7 +570,7 @@
   this->memory_.SetMemory(0x6000, std::vector<uint8_t>{0x09, 0x04, 0x03});
 
   dwarf_loc_regs_t loc_regs;
-  ASSERT_TRUE(this->section_->GetCfaLocationInfo(0x100, &fde, &loc_regs));
+  ASSERT_TRUE(this->section_->GetCfaLocationInfo(0x100, &fde, &loc_regs, ARCH_UNKNOWN));
   ASSERT_EQ(2U, loc_regs.size());
 
   auto entry = loc_regs.find(6);
@@ -560,7 +595,7 @@
 
   this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x00});
   this->memory_.SetMemory(0x6000, std::vector<uint8_t>{0xc2});
-  ASSERT_TRUE(this->section_->Log(2, 0x1000, &fde));
+  ASSERT_TRUE(this->section_->Log(2, 0x1000, &fde, ARCH_UNKNOWN));
 
   ASSERT_EQ(
       "4 unwind     DW_CFA_nop\n"
@@ -580,6 +615,7 @@
                             Eval_invalid_register, Eval_different_reg_locations,
                             Eval_return_address_undefined, Eval_pc_zero, Eval_return_address,
                             Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
+                            Eval_pseudo_register_invalid, Eval_pseudo_register,
                             GetCfaLocationInfo_cie_not_cached, GetCfaLocationInfo_cie_cached, Log);
 
 typedef ::testing::Types<uint32_t, uint64_t> DwarfSectionImplTestTypes;
diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp
index 953dc75..febd6d3 100644
--- a/libunwindstack/tests/DwarfSectionTest.cpp
+++ b/libunwindstack/tests/DwarfSectionTest.cpp
@@ -20,8 +20,10 @@
 #include <gtest/gtest.h>
 
 #include <unwindstack/DwarfSection.h>
+#include <unwindstack/Elf.h>
 
 #include "MemoryFake.h"
+#include "RegsFake.h"
 
 namespace unwindstack {
 
@@ -35,13 +37,14 @@
   MOCK_METHOD(bool, Eval, (const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*),
               (override));
 
-  MOCK_METHOD(bool, Log, (uint8_t, uint64_t, const DwarfFde*), (override));
+  MOCK_METHOD(bool, Log, (uint8_t, uint64_t, const DwarfFde*, ArchEnum arch), (override));
 
   MOCK_METHOD(void, GetFdes, (std::vector<const DwarfFde*>*), (override));
 
   MOCK_METHOD(const DwarfFde*, GetFdeFromPc, (uint64_t), (override));
 
-  MOCK_METHOD(bool, GetCfaLocationInfo, (uint64_t, const DwarfFde*, dwarf_loc_regs_t*), (override));
+  MOCK_METHOD(bool, GetCfaLocationInfo,
+              (uint64_t, const DwarfFde*, dwarf_loc_regs_t*, ArchEnum arch), (override));
 
   MOCK_METHOD(uint64_t, GetCieOffsetFromFde32, (uint32_t), (override));
 
@@ -56,8 +59,11 @@
 
   MemoryFake memory_;
   std::unique_ptr<MockDwarfSection> section_;
+  static RegsFake regs_;
 };
 
+RegsFake DwarfSectionTest::regs_(10);
+
 TEST_F(DwarfSectionTest, Step_fail_fde) {
   EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(nullptr));
 
@@ -73,7 +79,7 @@
   EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
 
   bool finished;
-  ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished));
+  ASSERT_FALSE(section_->Step(0x1000, &regs_, nullptr, &finished));
 }
 
 TEST_F(DwarfSectionTest, Step_fail_cfa_location) {
@@ -83,11 +89,11 @@
   fde.cie = &cie;
 
   EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
-  EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
+  EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_, ::testing::_))
       .WillOnce(::testing::Return(false));
 
   bool finished;
-  ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished));
+  ASSERT_FALSE(section_->Step(0x1000, &regs_, nullptr, &finished));
 }
 
 TEST_F(DwarfSectionTest, Step_pass) {
@@ -97,19 +103,19 @@
   fde.cie = &cie;
 
   EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
-  EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
+  EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_, ::testing::_))
       .WillOnce(::testing::Return(true));
 
   MemoryFake process;
-  EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
+  EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, &regs_, ::testing::_))
       .WillOnce(::testing::Return(true));
 
   bool finished;
-  ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x1000, &regs_, &process, &finished));
 }
 
 static bool MockGetCfaLocationInfo(::testing::Unused, const DwarfFde* fde,
-                                   dwarf_loc_regs_t* loc_regs) {
+                                   dwarf_loc_regs_t* loc_regs, ArchEnum) {
   loc_regs->pc_start = fde->pc_start;
   loc_regs->pc_end = fde->pc_end;
   return true;
@@ -123,17 +129,17 @@
   fde.cie = &cie;
 
   EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
-  EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
+  EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_, ::testing::_))
       .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
 
   MemoryFake process;
-  EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
+  EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, &regs_, ::testing::_))
       .WillRepeatedly(::testing::Return(true));
 
   bool finished;
-  ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
-  ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
-  ASSERT_TRUE(section_->Step(0x1500, nullptr, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x1000, &regs_, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x1000, &regs_, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x1500, &regs_, &process, &finished));
 }
 
 TEST_F(DwarfSectionTest, Step_cache_not_in_pc) {
@@ -143,26 +149,26 @@
   fde0.pc_end = 0x2000;
   fde0.cie = &cie;
   EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde0));
-  EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde0, ::testing::_))
+  EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde0, ::testing::_, ::testing::_))
       .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
 
   MemoryFake process;
-  EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
+  EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, &regs_, ::testing::_))
       .WillRepeatedly(::testing::Return(true));
 
   bool finished;
-  ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x1000, &regs_, &process, &finished));
 
   DwarfFde fde1{};
   fde1.pc_start = 0x500;
   fde1.pc_end = 0x800;
   fde1.cie = &cie;
   EXPECT_CALL(*section_, GetFdeFromPc(0x600)).WillOnce(::testing::Return(&fde1));
-  EXPECT_CALL(*section_, GetCfaLocationInfo(0x600, &fde1, ::testing::_))
+  EXPECT_CALL(*section_, GetCfaLocationInfo(0x600, &fde1, ::testing::_, ::testing::_))
       .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
 
-  ASSERT_TRUE(section_->Step(0x600, nullptr, &process, &finished));
-  ASSERT_TRUE(section_->Step(0x700, nullptr, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x600, &regs_, &process, &finished));
+  ASSERT_TRUE(section_->Step(0x700, &regs_, &process, &finished));
 }
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index 75fc9d0..f67d7dc 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -83,15 +83,33 @@
   uint64_t sp() override { return fake_sp_; }
   void set_pc(uint64_t pc) override { fake_pc_ = pc; }
   void set_sp(uint64_t sp) override { fake_sp_ = sp; }
+  void set_pseudo_reg(uint64_t reg) { fake_pseudo_reg_ = reg; }
 
   bool SetPcFromReturnAddress(Memory*) override { return false; }
   bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
 
+  bool SetPseudoRegister(uint16_t reg, uint64_t value) override {
+    if (fake_pseudo_reg_ != reg) {
+      return false;
+    }
+    fake_pseudo_reg_value_ = value;
+    return true;
+  }
+  bool GetPseudoRegister(uint16_t reg, uint64_t* value) override {
+    if (fake_pseudo_reg_ != reg) {
+      return false;
+    }
+    *value = fake_pseudo_reg_value_;
+    return true;
+  }
+
   Regs* Clone() override { return nullptr; }
 
  private:
   uint64_t fake_pc_ = 0;
   uint64_t fake_sp_ = 0;
+  uint16_t fake_pseudo_reg_ = 0;
+  uint64_t fake_pseudo_reg_value_ = 0;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index e4fc6f0..acf72de 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -247,6 +247,14 @@
   EXPECT_EQ(0xc200000000U, mips64.pc());
 }
 
+TEST_F(RegsTest, arm64_strip_pac_mask) {
+  RegsArm64 arm64;
+  arm64.SetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, 1);
+  arm64.SetPACMask(0x007fff8000000000ULL);
+  arm64.set_pc(0x0020007214bb3a04ULL);
+  EXPECT_EQ(0x0000007214bb3a04ULL, arm64.pc());
+}
+
 TEST_F(RegsTest, machine_type) {
   RegsArm arm_regs;
   EXPECT_EQ(ARCH_ARM, arm_regs.Arch());
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index c2bd836..0c6f9f8 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -314,7 +314,7 @@
 
   JitDebug jit_debug(process_memory_);
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
-  unwinder.SetJitDebug(&jit_debug, regs_->Arch());
+  unwinder.SetJitDebug(&jit_debug);
   unwinder.Unwind();
 
   std::string frame_info(DumpFrames(unwinder));
@@ -616,7 +616,7 @@
 
   JitDebug jit_debug(process_memory_);
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
-  unwinder.SetJitDebug(&jit_debug, regs_->Arch());
+  unwinder.SetJitDebug(&jit_debug);
   unwinder.Unwind();
 
   std::string frame_info(DumpFrames(unwinder));
@@ -939,7 +939,7 @@
   std::unique_ptr<Regs> regs_copy(leak_data->regs->Clone());
   JitDebug jit_debug(leak_data->process_memory);
   Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory);
-  unwinder.SetJitDebug(&jit_debug, regs_copy->Arch());
+  unwinder.SetJitDebug(&jit_debug);
   unwinder.Unwind();
   ASSERT_EQ(76U, unwinder.NumFrames());
 }
@@ -1062,7 +1062,7 @@
 
   JitDebug jit_debug(process_memory_);
   Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
-  unwinder.SetJitDebug(&jit_debug, regs_->Arch());
+  unwinder.SetJitDebug(&jit_debug);
   unwinder.Unwind();
 
   std::string frame_info(DumpFrames(unwinder));
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index f76a101..b11d213 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -170,7 +170,6 @@
     unwinder.reset(new Unwinder(512, maps.get(), regs.get(), process_memory));
   } else {
     UnwinderFromPid* unwinder_from_pid = new UnwinderFromPid(512, getpid());
-    ASSERT_TRUE(unwinder_from_pid->Init(regs->Arch()));
     unwinder_from_pid->SetRegs(regs.get());
     unwinder.reset(unwinder_from_pid);
   }
@@ -283,7 +282,6 @@
   ASSERT_TRUE(regs.get() != nullptr);
 
   UnwinderFromPid unwinder(512, pid);
-  ASSERT_TRUE(unwinder.Init(regs->Arch()));
   unwinder.SetRegs(regs.get());
 
   VerifyUnwind(&unwinder, kFunctionOrder);
@@ -335,7 +333,6 @@
   ASSERT_TRUE(regs.get() != nullptr);
 
   UnwinderFromPid unwinder(512, *pid);
-  ASSERT_TRUE(unwinder.Init(regs->Arch()));
   unwinder.SetRegs(regs.get());
 
   VerifyUnwind(&unwinder, kFunctionOrder);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index dd33aa9..8bae242 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -37,6 +37,7 @@
 #include <unwindstack/Unwinder.h>
 
 #include "ElfFake.h"
+#include "ElfTestUtils.h"
 #include "MemoryFake.h"
 #include "RegsFake.h"
 
@@ -44,23 +45,31 @@
 
 class UnwinderTest : public ::testing::Test {
  protected:
-  static void AddMapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
-                         const char* name, Elf* elf = nullptr) {
+  static MapInfo* AddMapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
+                             const char* name, Elf* elf = nullptr) {
     std::string str_name(name);
     maps_->Add(start, end, offset, flags, name, static_cast<uint64_t>(-1));
+    MapInfo* map_info = maps_->Find(start);
     if (elf != nullptr) {
-      const auto& map_info = *--maps_->end();
       map_info->elf.reset(elf);
     }
+    return map_info;
   }
 
   static void SetUpTestSuite() {
     maps_.reset(new Maps);
 
-    ElfFake* elf = new ElfFake(new MemoryFake);
-    ElfInterfaceFake* interface_fake = new ElfInterfaceFake(nullptr);
-    interface_fake->FakeSetBuildID("FAKE");
-    elf->FakeSetInterface(interface_fake);
+    memory_ = new MemoryFake;
+    process_memory_.reset(memory_);
+
+    ElfFake* elf;
+    ElfInterfaceFake* interface;
+    MapInfo* map_info;
+
+    elf = new ElfFake(new MemoryFake);
+    interface = new ElfInterfaceFake(nullptr);
+    interface->FakeSetBuildID("FAKE");
+    elf->FakeSetInterface(interface);
     AddMapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so", elf);
 
     AddMapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
@@ -81,19 +90,17 @@
     AddMapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so", elf);
 
     elf = new ElfFake(new MemoryFake);
-    ElfInterfaceFake* interface = new ElfInterfaceFake(nullptr);
+    interface = new ElfInterfaceFake(nullptr);
     interface->FakeSetSoname("lib_fake.so");
     elf->FakeSetInterface(interface);
-    AddMapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk", elf);
-    MapInfo* map_info = maps_->Find(0x43000);
-    ASSERT_TRUE(map_info != nullptr);
+    map_info = AddMapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk", elf);
     map_info->elf_start_offset = 0x1d000;
 
     AddMapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
 
-    AddMapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
-    const auto& info = *--maps_->end();
-    info->load_bias = 0;
+    map_info =
+        AddMapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
+    map_info->load_bias = 0;
 
     elf = new ElfFake(new MemoryFake);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
@@ -103,40 +110,76 @@
 
     elf = new ElfFake(new MemoryFake);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
-    AddMapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_offset.oat",
-               elf);
-    const auto& info2 = *--maps_->end();
-    info2->elf_offset = 0x8000;
+    map_info = AddMapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                          "/fake/fake_offset.oat", elf);
+    map_info->elf_offset = 0x8000;
 
     elf = new ElfFake(new MemoryFake);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
-    AddMapInfo(0xc0000, 0xc1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/unreadable.so", elf);
-    const auto& info3 = *--maps_->end();
-    info3->memory_backed_elf = true;
+    map_info = AddMapInfo(0xc0000, 0xc1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                          "/fake/unreadable.so", elf);
+    map_info->memory_backed_elf = true;
 
     elf = new ElfFake(new MemoryFake);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
-    AddMapInfo(0xc1000, 0xc2000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "[vdso]", elf);
-    const auto& info4 = *--maps_->end();
-    info4->memory_backed_elf = true;
+    map_info = AddMapInfo(0xc1000, 0xc2000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "[vdso]", elf);
+    map_info->memory_backed_elf = true;
 
     elf = new ElfFake(new MemoryFake);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
-    AddMapInfo(0xc2000, 0xc3000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "", elf);
-    const auto& info5 = *--maps_->end();
-    info5->memory_backed_elf = true;
+    map_info = AddMapInfo(0xc2000, 0xc3000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "", elf);
+    map_info->memory_backed_elf = true;
 
     elf = new ElfFake(new MemoryFake);
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
-    AddMapInfo(0xc3000, 0xc4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/memfd:/jit-cache", elf);
-    const auto& info6 = *--maps_->end();
-    info6->memory_backed_elf = true;
+    map_info = AddMapInfo(0xc3000, 0xc4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                          "/memfd:/jit-cache", elf);
+    map_info->memory_backed_elf = true;
 
-    AddMapInfo(0xd0000, 0xd1000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.apk");
-    const auto& info7 = *--maps_->end();
-    info7->load_bias = 0;
+    map_info =
+        AddMapInfo(0xd0000, 0xd1000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.apk");
+    map_info->load_bias = 0;
 
-    process_memory_.reset(new MemoryFake);
+    elf = new ElfFake(new MemoryFake);
+    interface = new ElfInterfaceFake(nullptr);
+    elf->FakeSetInterface(interface);
+    interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x1800);
+    interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x1900);
+    interface->FakeSetDataOffset(0x1000);
+    interface->FakeSetDataVaddrStart(0x1000);
+    interface->FakeSetDataVaddrEnd(0x8000);
+    AddMapInfo(0xf0000, 0xf1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/global.so", elf);
+    AddMapInfo(0xf1000, 0xf9000, 0x1000, PROT_READ | PROT_WRITE, "/fake/global.so");
+    // dex debug data
+    memory_->SetData32(0xf180c, 0xf3000);
+    memory_->SetData32(0xf3000, 0xf4000);
+    memory_->SetData32(0xf3004, 0xf4000);
+    memory_->SetData32(0xf3008, 0xf5000);
+    // jit debug data
+    memory_->SetData32(0xf1900, 1);
+    memory_->SetData32(0xf1904, 0);
+    memory_->SetData32(0xf1908, 0xf6000);
+    memory_->SetData32(0xf190c, 0xf6000);
+    memory_->SetData32(0xf6000, 0);
+    memory_->SetData32(0xf6004, 0);
+    memory_->SetData32(0xf6008, 0xf7000);
+    memory_->SetData32(0xf600c, 0);
+    memory_->SetData64(0xf6010, 0x1000);
+
+    elf = new ElfFake(new MemoryFake);
+    elf->FakeSetValid(false);
+    elf->FakeSetLoadBias(0x300);
+    map_info = AddMapInfo(0x100000, 0x101000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
+                          "/fake/jit.so", elf);
+    map_info->elf_start_offset = 0x100;
+    map_info->offset = 0x200;
+
+#if 0
+    elf = new ElfFake(new MemoryFake);
+    interface = new ElfInterfaceFake(nullptr);
+    interface->FakePushFunctionData(FunctionData("Fake0", 10));
+    AddMapInfo(0x110000, 0x111000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/elf.so", elf);
+#endif
   }
 
   void SetUp() override {
@@ -147,11 +190,13 @@
 
   static std::unique_ptr<Maps> maps_;
   static RegsFake regs_;
+  static MemoryFake* memory_;
   static std::shared_ptr<Memory> process_memory_;
 };
 
 std::unique_ptr<Maps> UnwinderTest::maps_;
 RegsFake UnwinderTest::regs_(5);
+MemoryFake* UnwinderTest::memory_;
 std::shared_ptr<Memory> UnwinderTest::process_memory_(nullptr);
 
 TEST_F(UnwinderTest, multiple_frames) {
@@ -168,6 +213,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
@@ -233,6 +279,7 @@
   unwinder.SetResolveNames(false);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
@@ -293,6 +340,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
@@ -323,6 +371,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
@@ -353,6 +402,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
@@ -384,6 +434,7 @@
   unwinder.SetEmbeddedSoname(false);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
@@ -421,6 +472,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
@@ -454,6 +506,7 @@
   Unwinder unwinder(20, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(20U, unwinder.NumFrames());
@@ -497,6 +550,7 @@
   std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
   unwinder.Unwind(&skip_libs);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
@@ -559,6 +613,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
@@ -607,6 +662,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
@@ -627,6 +683,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
@@ -642,6 +699,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
@@ -679,6 +737,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
@@ -745,6 +804,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
@@ -795,6 +855,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
@@ -843,6 +904,7 @@
   std::vector<std::string> skip_names{"libanother.so"};
   unwinder.Unwind(&skip_names);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(0U, unwinder.NumFrames());
@@ -866,6 +928,7 @@
   std::vector<std::string> suffixes{"oat"};
   unwinder.Unwind(nullptr, &suffixes);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
@@ -925,6 +988,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
@@ -984,6 +1048,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
@@ -1028,6 +1093,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
@@ -1072,6 +1138,54 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_DEX_PC_NOT_IN_MAP, unwinder.warnings());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+  ASSERT_EQ(2U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x50000U, frame->rel_pc);
+  EXPECT_EQ(0x50000U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("", frame->map_name);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
+  EXPECT_EQ(0U, frame->map_start);
+  EXPECT_EQ(0U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(0, frame->map_flags);
+
+  frame = &unwinder.frames()[1];
+  EXPECT_EQ(1U, frame->num);
+  EXPECT_EQ(0U, frame->rel_pc);
+  EXPECT_EQ(0x1000U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
+  EXPECT_EQ(0x1000U, frame->map_start);
+  EXPECT_EQ(0x8000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, dex_pc_not_in_map_valid_dex_files) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+  regs_.set_pc(0x1000);
+  regs_.set_sp(0x10000);
+  regs_.FakeSetDexPc(0x50000);
+
+  DexFiles dex_files(process_memory_);
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+  unwinder.SetDexFiles(&dex_files);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_DEX_PC_NOT_IN_MAP, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
@@ -1119,6 +1233,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
@@ -1178,6 +1293,7 @@
   Unwinder unwinder(1, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1208,6 +1324,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_TRUE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1238,6 +1355,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1268,6 +1386,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1298,6 +1417,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
   EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
@@ -1474,4 +1594,178 @@
   }
 }
 
+TEST_F(UnwinderTest, build_frame_pc_only_errors) {
+  RegsFake regs(10);
+  regs.FakeSetArch(ARCH_ARM);
+  Unwinder unwinder(10, maps_.get(), &regs, process_memory_);
+
+  FrameData frame;
+
+  // Pc not in map
+  frame = unwinder.BuildFrameFromPcOnly(0x10);
+  EXPECT_EQ(0x10U, frame.pc);
+  EXPECT_EQ(0x10U, frame.rel_pc);
+
+  // No regs set
+  unwinder.SetRegs(nullptr);
+  frame = unwinder.BuildFrameFromPcOnly(0x100310);
+  EXPECT_EQ(0x100310U, frame.pc);
+  EXPECT_EQ(0x100310U, frame.rel_pc);
+  unwinder.SetRegs(&regs);
+
+  // Invalid elf
+  frame = unwinder.BuildFrameFromPcOnly(0x100310);
+  EXPECT_EQ(0x10030eU, frame.pc);
+  EXPECT_EQ(0x60eU, frame.rel_pc);
+  EXPECT_EQ("/fake/jit.so", frame.map_name);
+  EXPECT_EQ(0x100U, frame.map_elf_start_offset);
+  EXPECT_EQ(0x200U, frame.map_exact_offset);
+  EXPECT_EQ(0x100000U, frame.map_start);
+  EXPECT_EQ(0x101000U, frame.map_end);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame.map_flags);
+  EXPECT_EQ(0x300U, frame.map_load_bias);
+  EXPECT_EQ("", frame.function_name);
+  EXPECT_EQ(0U, frame.function_offset);
+}
+
+TEST_F(UnwinderTest, build_frame_pc_valid_elf) {
+  RegsFake regs(10);
+  regs.FakeSetArch(ARCH_ARM);
+  Unwinder unwinder(10, maps_.get(), &regs, process_memory_);
+
+  FrameData frame;
+
+  // Valid elf, no function data.
+  frame = unwinder.BuildFrameFromPcOnly(0x1010);
+  EXPECT_EQ(0x100cU, frame.pc);
+  EXPECT_EQ(0xcU, frame.rel_pc);
+  EXPECT_EQ("/system/fake/libc.so", frame.map_name);
+  EXPECT_EQ(0U, frame.map_elf_start_offset);
+  EXPECT_EQ(0U, frame.map_exact_offset);
+  EXPECT_EQ(0x1000U, frame.map_start);
+  EXPECT_EQ(0x8000U, frame.map_end);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, frame.map_flags);
+  EXPECT_EQ(0U, frame.map_load_bias);
+  EXPECT_EQ("", frame.function_name);
+  EXPECT_EQ(0U, frame.function_offset);
+
+  // Valid elf, function data present, but do not resolve.
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
+  unwinder.SetResolveNames(false);
+
+  frame = unwinder.BuildFrameFromPcOnly(0x1010);
+  EXPECT_EQ(0x100cU, frame.pc);
+  EXPECT_EQ(0xcU, frame.rel_pc);
+  EXPECT_EQ("/system/fake/libc.so", frame.map_name);
+  EXPECT_EQ(0U, frame.map_elf_start_offset);
+  EXPECT_EQ(0U, frame.map_exact_offset);
+  EXPECT_EQ(0x1000U, frame.map_start);
+  EXPECT_EQ(0x8000U, frame.map_end);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, frame.map_flags);
+  EXPECT_EQ(0U, frame.map_load_bias);
+  EXPECT_EQ("", frame.function_name);
+  EXPECT_EQ(0U, frame.function_offset);
+
+  // Valid elf, function data present.
+  unwinder.SetResolveNames(true);
+
+  frame = unwinder.BuildFrameFromPcOnly(0x1010);
+  EXPECT_EQ(0x100cU, frame.pc);
+  EXPECT_EQ(0xcU, frame.rel_pc);
+  EXPECT_EQ("/system/fake/libc.so", frame.map_name);
+  EXPECT_EQ(0U, frame.map_elf_start_offset);
+  EXPECT_EQ(0U, frame.map_exact_offset);
+  EXPECT_EQ(0x1000U, frame.map_start);
+  EXPECT_EQ(0x8000U, frame.map_end);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, frame.map_flags);
+  EXPECT_EQ(0U, frame.map_load_bias);
+  EXPECT_EQ("Frame0", frame.function_name);
+  EXPECT_EQ(10U, frame.function_offset);
+}
+
+TEST_F(UnwinderTest, build_frame_pc_in_jit) {
+  // Create the elf data for the jit debug information.
+  Elf32_Ehdr ehdr = {};
+  TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
+  ehdr.e_phoff = 0x50;
+  ehdr.e_phnum = 1;
+  ehdr.e_phentsize = sizeof(Elf32_Phdr);
+  ehdr.e_shoff = 0x100;
+  ehdr.e_shstrndx = 1;
+  ehdr.e_shentsize = sizeof(Elf32_Shdr);
+  ehdr.e_shnum = 3;
+  memory_->SetMemory(0xf7000, &ehdr, sizeof(ehdr));
+
+  Elf32_Phdr phdr = {};
+  phdr.p_flags = PF_X;
+  phdr.p_type = PT_LOAD;
+  phdr.p_offset = 0x100000;
+  phdr.p_vaddr = 0x100000;
+  phdr.p_memsz = 0x1000;
+  memory_->SetMemory(0xf7050, &phdr, sizeof(phdr));
+
+  Elf32_Shdr shdr = {};
+  shdr.sh_type = SHT_NULL;
+  memory_->SetMemory(0xf7100, &shdr, sizeof(shdr));
+
+  shdr.sh_type = SHT_SYMTAB;
+  shdr.sh_link = 2;
+  shdr.sh_addr = 0x300;
+  shdr.sh_offset = 0x300;
+  shdr.sh_entsize = sizeof(Elf32_Sym);
+  shdr.sh_size = shdr.sh_entsize;
+  memory_->SetMemory(0xf7100 + sizeof(shdr), &shdr, sizeof(shdr));
+
+  memset(&shdr, 0, sizeof(shdr));
+  shdr.sh_type = SHT_STRTAB;
+  shdr.sh_name = 0x500;
+  shdr.sh_offset = 0x400;
+  shdr.sh_size = 0x100;
+  memory_->SetMemory(0xf7100 + 2 * sizeof(shdr), &shdr, sizeof(shdr));
+
+  Elf32_Sym sym = {};
+  sym.st_shndx = 2;
+  sym.st_info = STT_FUNC;
+  sym.st_value = 0x100300;
+  sym.st_size = 0x100;
+  memory_->SetMemory(0xf7300, &sym, sizeof(sym));
+  memory_->SetMemory(0xf7400, "FakeJitFunction");
+
+  RegsFake regs(10);
+  regs.FakeSetArch(ARCH_ARM);
+  JitDebug jit_debug(process_memory_);
+  Unwinder unwinder(10, maps_.get(), &regs, process_memory_);
+  unwinder.SetJitDebug(&jit_debug);
+
+  FrameData frame = unwinder.BuildFrameFromPcOnly(0x100310);
+  EXPECT_EQ(0x10030eU, frame.pc);
+  EXPECT_EQ(0x60eU, frame.rel_pc);
+  EXPECT_EQ("/fake/jit.so", frame.map_name);
+  EXPECT_EQ(0x100U, frame.map_elf_start_offset);
+  EXPECT_EQ(0x200U, frame.map_exact_offset);
+  EXPECT_EQ(0x100000U, frame.map_start);
+  EXPECT_EQ(0x101000U, frame.map_end);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame.map_flags);
+  EXPECT_EQ(0U, frame.map_load_bias);
+  EXPECT_EQ("FakeJitFunction", frame.function_name);
+  EXPECT_EQ(0xeU, frame.function_offset);
+}
+
+TEST_F(UnwinderTest, unwinder_from_pid_init_error) {
+  UnwinderFromPid unwinder(10, getpid());
+  ASSERT_DEATH(unwinder.Init(), "");
+}
+
+TEST_F(UnwinderTest, set_jit_debug_error) {
+  Unwinder unwinder(10, maps_.get(), process_memory_);
+  JitDebug jit_debug(process_memory_);
+  ASSERT_DEATH(unwinder.SetJitDebug(&jit_debug), "");
+}
+
+TEST_F(UnwinderTest, set_dex_files_error) {
+  Unwinder unwinder(10, maps_.get(), process_memory_);
+  DexFiles dex_files(process_memory_);
+  ASSERT_DEATH(unwinder.SetDexFiles(&dex_files), "");
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/VerifyBionicTerminationTest.cpp b/libunwindstack/tests/VerifyBionicTerminationTest.cpp
index 6a3e91a..3e67dc9 100644
--- a/libunwindstack/tests/VerifyBionicTerminationTest.cpp
+++ b/libunwindstack/tests/VerifyBionicTerminationTest.cpp
@@ -55,7 +55,7 @@
     return DWARF_LOCATION_INVALID;
   }
   dwarf_loc_regs_t regs;
-  if (!section->GetCfaLocationInfo(rel_pc, fde, &regs)) {
+  if (!section->GetCfaLocationInfo(rel_pc, fde, &regs, ARCH_UNKNOWN)) {
     return DWARF_LOCATION_INVALID;
   }
 
@@ -94,7 +94,6 @@
   std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
 
   UnwinderFromPid unwinder(512, getpid());
-  ASSERT_TRUE(unwinder.Init(regs->Arch()));
   unwinder.SetRegs(regs.get());
 
   RegsGetLocal(regs.get());
diff --git a/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp b/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
index 94f5a73..9c5374a 100644
--- a/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
+++ b/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
@@ -16,6 +16,11 @@
 
 #include "UnwinderComponentCreator.h"
 
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
 std::unique_ptr<Regs> GetRegisters(ArchEnum arch) {
   switch (arch) {
     case unwindstack::ARCH_ARM: {
@@ -109,13 +114,35 @@
   return elf;
 }
 
+static constexpr size_t kPageSize = 4096;
+
+static constexpr uint64_t AlignToPage(uint64_t address) {
+  return (address + kPageSize - 1) & ~(kPageSize - 1);
+}
+
 std::unique_ptr<Maps> GetMaps(FuzzedDataProvider* data_provider) {
   std::unique_ptr<Maps> maps = std::make_unique<Maps>();
+  std::map<uint64_t, uint64_t> map_ends;
   uint8_t entry_count = data_provider->ConsumeIntegralInRange<uint8_t>(0, kMaxMapEntryCount);
   for (uint8_t i = 0; i < entry_count; i++) {
-    uint64_t start = data_provider->ConsumeIntegral<uint64_t>();
-    uint64_t end = data_provider->ConsumeIntegralInRange<uint64_t>(start, UINT64_MAX);
-    uint64_t offset = data_provider->ConsumeIntegral<uint64_t>();
+    uint64_t start = AlignToPage(data_provider->ConsumeIntegral<uint64_t>());
+    uint64_t end = AlignToPage(data_provider->ConsumeIntegralInRange<uint64_t>(start, UINT64_MAX));
+    if (start == end) {
+      // It's impossible to see start == end in the real world, so
+      // make sure the map contains at least one page of data.
+      if (__builtin_add_overflow(end, 0x1000, &end)) {
+        continue;
+      }
+    }
+    // Make sure not to add overlapping maps, that is not something that can
+    // happen in the real world.
+    auto entry = map_ends.upper_bound(start);
+    if (entry != map_ends.end() && end > entry->second) {
+      continue;
+    }
+    map_ends[end] = start;
+
+    uint64_t offset = AlignToPage(data_provider->ConsumeIntegral<uint64_t>());
     std::string map_info_name = data_provider->ConsumeRandomLengthString(kMaxMapInfoNameLen);
     uint8_t flags = PROT_READ | PROT_WRITE;
 
diff --git a/libunwindstack/tests/fuzz/UnwinderFuzz.cpp b/libunwindstack/tests/fuzz/UnwinderFuzz.cpp
index 2f4986a..1600547 100644
--- a/libunwindstack/tests/fuzz/UnwinderFuzz.cpp
+++ b/libunwindstack/tests/fuzz/UnwinderFuzz.cpp
@@ -85,7 +85,7 @@
 
   // Create instance
   Unwinder unwinder(max_frames, maps.get(), regs.get(), memory);
-  unwinder.SetJitDebug(jit_debug_ptr.get(), arch);
+  unwinder.SetJitDebug(jit_debug_ptr.get());
   unwinder.SetResolveNames(data_provider.ConsumeBool());
   // Call unwind
   PerformUnwind(&data_provider, &unwinder);
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 1812e50..ae45f06 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -90,11 +90,6 @@
   printf("\n");
 
   unwindstack::UnwinderFromPid unwinder(1024, pid);
-  if (!unwinder.Init(regs->Arch())) {
-    printf("Failed to init unwinder object.\n");
-    return;
-  }
-
   unwinder.SetRegs(regs);
   unwinder.Unwind();
 
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
index 64b58a8..c44a121 100644
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -248,10 +248,6 @@
   // Do an unwind so we know how much of the stack to save, and what
   // elf files are involved.
   unwindstack::UnwinderFromPid unwinder(1024, pid);
-  if (!unwinder.Init(regs->Arch())) {
-    printf("Unable to init unwinder object.\n");
-    return 1;
-  }
   unwinder.SetRegs(regs);
   uint64_t sp = regs->sp();
   unwinder.Unwind();
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index 7a6d8ba..a5002f2 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -96,7 +96,7 @@
       printf(" <%s>", name.c_str());
     }
     printf("\n");
-    if (!section->Log(2, UINT64_MAX, fde)) {
+    if (!section->Log(2, UINT64_MAX, fde, elf->arch())) {
       printf("Failed to process cfa information for entry at 0x%" PRIx64 "\n", fde->pc_start);
     }
   }
diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp
index 0cbcac5..68e0273 100644
--- a/libunwindstack/tools/unwind_reg_info.cpp
+++ b/libunwindstack/tools/unwind_reg_info.cpp
@@ -64,7 +64,8 @@
   }
 }
 
-void PrintRegInformation(DwarfSection* section, Memory* memory, uint64_t pc, uint8_t class_type) {
+void PrintRegInformation(DwarfSection* section, Memory* memory, uint64_t pc, uint8_t class_type,
+                         ArchEnum arch) {
   const DwarfFde* fde = section->GetFdeFromPc(pc);
   if (fde == nullptr) {
     printf("  No fde found.\n");
@@ -72,7 +73,7 @@
   }
 
   dwarf_loc_regs_t regs;
-  if (!section->GetCfaLocationInfo(pc, fde, &regs)) {
+  if (!section->GetCfaLocationInfo(pc, fde, &regs, arch)) {
     printf("  Cannot get location information.\n");
     return;
   }
@@ -128,6 +129,11 @@
         break;
       }
 
+      case DWARF_LOCATION_PSEUDO_REGISTER: {
+        printf("%" PRId64 " (pseudo)\n", loc->values[0]);
+        break;
+      }
+
       case DWARF_LOCATION_UNDEFINED:
         printf("undefine\n");
         break;
@@ -199,7 +205,7 @@
   DwarfSection* section = interface->eh_frame();
   if (section != nullptr) {
     printf("\neh_frame:\n");
-    PrintRegInformation(section, elf.memory(), pc, elf.class_type());
+    PrintRegInformation(section, elf.memory(), pc, elf.class_type(), elf.arch());
   } else {
     printf("\nno eh_frame information\n");
   }
@@ -207,7 +213,7 @@
   section = interface->debug_frame();
   if (section != nullptr) {
     printf("\ndebug_frame:\n");
-    PrintRegInformation(section, elf.memory(), pc, elf.class_type());
+    PrintRegInformation(section, elf.memory(), pc, elf.class_type(), elf.arch());
     printf("\n");
   } else {
     printf("\nno debug_frame information\n");
@@ -219,7 +225,8 @@
     section = gnu_debugdata_interface->eh_frame();
     if (section != nullptr) {
       printf("\ngnu_debugdata (eh_frame):\n");
-      PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type());
+      PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type(),
+                          elf.arch());
       printf("\n");
     } else {
       printf("\nno gnu_debugdata (eh_frame)\n");
@@ -228,7 +235,8 @@
     section = gnu_debugdata_interface->debug_frame();
     if (section != nullptr) {
       printf("\ngnu_debugdata (debug_frame):\n");
-      PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type());
+      PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type(),
+                          elf.arch());
       printf("\n");
     } else {
       printf("\nno gnu_debugdata (debug_frame)\n");
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 022dedf..dd9fea0 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -132,7 +132,6 @@
         "JenkinsHash.cpp",
         "NativeHandle.cpp",
         "Printer.cpp",
-        "PropertyMap.cpp",
         "RefBase.cpp",
         "SharedBuffer.cpp",
         "StopWatch.cpp",
@@ -205,6 +204,7 @@
     shared_libs: [
         "libutils",
         "libbase",
+        "liblog",
     ],
 }
 
@@ -238,6 +238,54 @@
     srcs: ["Vector_fuzz.cpp"],
 }
 
+cc_fuzz {
+    name: "libutils_fuzz_printer",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["Printer_fuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_callstack",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["CallStack_fuzz.cpp"],
+    shared_libs: [
+        "libutilscallstack",
+    ],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_process_callstack",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["ProcessCallStack_fuzz.cpp"],
+    shared_libs: [
+        "libutilscallstack",
+    ],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_stopwatch",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["StopWatch_fuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_refbase",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["RefBase_fuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_lrucache",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["LruCache_fuzz.cpp"],
+}
+
+cc_fuzz {
+    name: "libutils_fuzz_looper",
+    defaults: ["libutils_fuzz_defaults"],
+    srcs: ["Looper_fuzz.cpp"],
+}
+
 cc_test {
     name: "libutils_test",
     host_supported: true,
diff --git a/libutils/CallStack_fuzz.cpp b/libutils/CallStack_fuzz.cpp
new file mode 100644
index 0000000..e89b5b7
--- /dev/null
+++ b/libutils/CallStack_fuzz.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <memory.h>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/CallStack.h"
+
+static constexpr int MAX_STRING_SIZE = 500;
+static constexpr int MAX_IGNORE_DEPTH = 200;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    size_t ignoreDepth = dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_IGNORE_DEPTH);
+    int logPriority = dataProvider.ConsumeIntegral<int>();
+    pid_t tid = dataProvider.ConsumeIntegral<pid_t>();
+    std::string logTag = dataProvider.ConsumeRandomLengthString(MAX_STRING_SIZE);
+    std::string prefix = dataProvider.ConsumeRandomLengthString(MAX_STRING_SIZE);
+
+    const char* logTagChars = logTag.c_str();
+    const char* prefixChars = prefix.c_str();
+
+    android::CallStack::CallStackUPtr callStack = android::CallStack::getCurrent(ignoreDepth);
+    android::CallStack* callstackPtr = callStack.get();
+    android::CallStack::logStack(logTagChars, callstackPtr,
+                                 static_cast<android_LogPriority>(logPriority));
+    android::CallStack::stackToString(prefixChars);
+
+    callstackPtr->log(logTagChars, static_cast<android_LogPriority>(logPriority), prefixChars);
+    callstackPtr->clear();
+    callstackPtr->getCurrent(ignoreDepth);
+    callstackPtr->log(logTagChars, static_cast<android_LogPriority>(logPriority), prefixChars);
+    callstackPtr->update(ignoreDepth, tid);
+    callstackPtr->log(logTagChars, static_cast<android_LogPriority>(logPriority), prefixChars);
+
+    return 0;
+}
diff --git a/libutils/FuzzFormatTypes.h b/libutils/FuzzFormatTypes.h
new file mode 100644
index 0000000..5d58a1a
--- /dev/null
+++ b/libutils/FuzzFormatTypes.h
@@ -0,0 +1,45 @@
+#pragma once
+#include <string>
+
+static const std::string kFormatChars = std::string("duoxXfFeEgGaAcsp");
+static constexpr int32_t kMaxFormatFlagValue = INT16_MAX;
+enum FormatChar : uint8_t {
+    SIGNED_DECIMAL = 0,
+    UNSIGNED_DECIMAL = 1,
+    UNSIGNED_OCTAL = 2,
+    UNSIGNED_HEX_LOWER = 3,
+    UNSIGNED_HEX_UPPER = 4,
+    // Uppercase/lowercase floating point impacts 'inf', 'infinity', and 'nan'
+    FLOAT_LOWER = 5,
+    FLOAT_UPPER = 6,
+    // Upper/lower impacts the "e" in exponents.
+    EXPONENT_LOWER = 7,
+    EXPONENT_UPPER = 8,
+    // %g will use %e or %f, whichever is shortest
+    SHORT_EXP_LOWER = 9,
+    // %G will use %E or %F, whichever is shortest
+    SHORT_EXP_UPPER = 10,
+    HEX_FLOAT_LOWER = 11,
+    HEX_FLOAT_UPPER = 12,
+    CHAR = 13,
+    STRING = 14,
+    POINTER = 15,
+    // Used by libfuzzer
+    kMaxValue = POINTER
+};
+
+bool canApplyFlag(FormatChar formatChar, char modifier) {
+    if (modifier == '#') {
+        return formatChar == UNSIGNED_OCTAL || formatChar == UNSIGNED_HEX_LOWER ||
+               formatChar == UNSIGNED_HEX_UPPER || formatChar == FLOAT_LOWER ||
+               formatChar == FLOAT_UPPER || formatChar == SHORT_EXP_LOWER ||
+               formatChar == SHORT_EXP_UPPER;
+    } else if (modifier == '.') {
+        return formatChar == SIGNED_DECIMAL || formatChar == UNSIGNED_DECIMAL ||
+               formatChar == UNSIGNED_OCTAL || formatChar == UNSIGNED_HEX_LOWER ||
+               formatChar == UNSIGNED_HEX_UPPER || formatChar == FLOAT_LOWER ||
+               formatChar == FLOAT_UPPER || formatChar == SHORT_EXP_LOWER ||
+               formatChar == SHORT_EXP_UPPER || formatChar == STRING;
+    }
+    return true;
+}
diff --git a/libutils/Looper_fuzz.cpp b/libutils/Looper_fuzz.cpp
new file mode 100644
index 0000000..c3ae54e
--- /dev/null
+++ b/libutils/Looper_fuzz.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/select.h>
+
+#include <iostream>
+
+#include <utils/Looper.h>
+
+#include "Looper_test_pipe.h"
+#include "fuzzer/FuzzedDataProvider.h"
+
+using android::Looper;
+using android::sp;
+
+// We don't want this to bog down fuzzing
+static constexpr int MAX_POLL_DELAY = 50;
+static constexpr int MAX_OPERATIONS = 500;
+
+void doNothing() {}
+void* doNothingPointer = reinterpret_cast<void*>(doNothing);
+
+static int noopCallback(int, int, void*) {
+    return 0;
+}
+
+std::vector<std::function<void(FuzzedDataProvider*, sp<Looper>, Pipe)>> operations = {
+        [](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe) -> void {
+            looper->pollOnce(dataProvider->ConsumeIntegralInRange<int>(0, MAX_POLL_DELAY));
+        },
+        [](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe) -> void {
+            looper->pollAll(dataProvider->ConsumeIntegralInRange<int>(0, MAX_POLL_DELAY));
+        },
+        // events and callback are nullptr
+        [](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe pipeObj) -> void {
+            looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral<int>(),
+                          dataProvider->ConsumeIntegral<int>(), nullptr, nullptr);
+        },
+        // Events is nullptr
+        [](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe pipeObj) -> void {
+            looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral<int>(),
+                          dataProvider->ConsumeIntegral<int>(), noopCallback, nullptr);
+        },
+        // callback is nullptr
+        [](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe pipeObj) -> void {
+            looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral<int>(),
+                          dataProvider->ConsumeIntegral<int>(), nullptr, doNothingPointer);
+        },
+        // callback and events both set
+        [](FuzzedDataProvider* dataProvider, sp<Looper> looper, Pipe pipeObj) -> void {
+            looper->addFd(pipeObj.receiveFd, dataProvider->ConsumeIntegral<int>(),
+                          dataProvider->ConsumeIntegral<int>(), noopCallback, doNothingPointer);
+        },
+
+        [](FuzzedDataProvider*, sp<Looper> looper, Pipe) -> void { looper->wake(); },
+        [](FuzzedDataProvider*, sp<Looper>, Pipe pipeObj) -> void { pipeObj.writeSignal(); }};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    Pipe pipeObj;
+    FuzzedDataProvider dataProvider(data, size);
+    sp<Looper> looper = new Looper(dataProvider.ConsumeBool());
+
+    size_t opsRun = 0;
+    while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
+        uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
+        operations[op](&dataProvider, looper, pipeObj);
+    }
+    // Clear our pointer
+    looper.clear();
+    return 0;
+}
diff --git a/libutils/Looper_test.cpp b/libutils/Looper_test.cpp
index 37bdf05..34f424b 100644
--- a/libutils/Looper_test.cpp
+++ b/libutils/Looper_test.cpp
@@ -2,12 +2,13 @@
 // 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 <unistd.h>
+#include <utils/Looper.h>
+#include <utils/StopWatch.h>
+#include <utils/Timers.h>
+#include "Looper_test_pipe.h"
 
 #include <utils/threads.h>
 
@@ -24,41 +25,6 @@
     MSG_TEST4 = 4,
 };
 
-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;
 
diff --git a/libutils/Looper_test_pipe.h b/libutils/Looper_test_pipe.h
new file mode 100644
index 0000000..77b7b8b
--- /dev/null
+++ b/libutils/Looper_test_pipe.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <unistd.h>
+/**
+ * A pipe class for use when testing or fuzzing Looper
+ */
+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);
+        }
+    }
+
+    android::status_t writeSignal() {
+        ssize_t nWritten = ::write(sendFd, "*", 1);
+        return nWritten == 1 ? 0 : -errno;
+    }
+
+    android::status_t readSignal() {
+        char buf[1];
+        ssize_t nRead = ::read(receiveFd, buf, 1);
+        return nRead == 1 ? 0 : nRead == 0 ? -EPIPE : -errno;
+    }
+};
diff --git a/libutils/LruCache_fuzz.cpp b/libutils/LruCache_fuzz.cpp
new file mode 100644
index 0000000..f8bacfc
--- /dev/null
+++ b/libutils/LruCache_fuzz.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <functional>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/LruCache.h"
+#include "utils/StrongPointer.h"
+
+typedef android::LruCache<size_t, size_t> FuzzCache;
+
+static constexpr uint32_t MAX_CACHE_ENTRIES = 800;
+
+class NoopRemovedCallback : public android::OnEntryRemoved<size_t, size_t> {
+  public:
+    void operator()(size_t&, size_t&) {
+        // noop
+    }
+};
+
+static NoopRemovedCallback callback;
+
+static const std::vector<std::function<void(FuzzedDataProvider*, FuzzCache*)>> operations = {
+        [](FuzzedDataProvider*, FuzzCache* cache) -> void { cache->removeOldest(); },
+        [](FuzzedDataProvider*, FuzzCache* cache) -> void { cache->peekOldestValue(); },
+        [](FuzzedDataProvider*, FuzzCache* cache) -> void { cache->clear(); },
+        [](FuzzedDataProvider*, FuzzCache* cache) -> void { cache->size(); },
+        [](FuzzedDataProvider*, FuzzCache* cache) -> void {
+            android::LruCache<size_t, size_t>::Iterator iter(*cache);
+            while (iter.next()) {
+                iter.key();
+                iter.value();
+            }
+        },
+        [](FuzzedDataProvider* dataProvider, FuzzCache* cache) -> void {
+            size_t key = dataProvider->ConsumeIntegral<size_t>();
+            size_t val = dataProvider->ConsumeIntegral<size_t>();
+            cache->put(key, val);
+        },
+        [](FuzzedDataProvider* dataProvider, FuzzCache* cache) -> void {
+            size_t key = dataProvider->ConsumeIntegral<size_t>();
+            cache->get(key);
+        },
+        [](FuzzedDataProvider* dataProvider, FuzzCache* cache) -> void {
+            size_t key = dataProvider->ConsumeIntegral<size_t>();
+            cache->remove(key);
+        },
+        [](FuzzedDataProvider*, FuzzCache* cache) -> void {
+            cache->setOnEntryRemovedListener(&callback);
+        }};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    FuzzCache cache(MAX_CACHE_ENTRIES);
+    while (dataProvider.remaining_bytes() > 0) {
+        uint8_t op = dataProvider.ConsumeIntegral<uint8_t>() % operations.size();
+        operations[op](&dataProvider, &cache);
+    }
+
+    return 0;
+}
diff --git a/libutils/Printer_fuzz.cpp b/libutils/Printer_fuzz.cpp
new file mode 100755
index 0000000..0180d41
--- /dev/null
+++ b/libutils/Printer_fuzz.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "android-base/file.h"
+#include "android/log.h"
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/Printer.h"
+#include "utils/String8.h"
+static constexpr int MAX_STR_SIZE = 1000;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    android::String8 outStr = android::String8();
+    // Line indent/formatting
+    uint indent = dataProvider.ConsumeIntegral<uint>();
+    std::string prefix = dataProvider.ConsumeRandomLengthString(MAX_STR_SIZE);
+    std::string line = dataProvider.ConsumeRandomLengthString(MAX_STR_SIZE);
+
+    // Misc properties
+    std::string logTag = dataProvider.ConsumeRandomLengthString(MAX_STR_SIZE);
+    android_LogPriority priority =
+            static_cast<android_LogPriority>(dataProvider.ConsumeIntegral<int>());
+    bool ignoreBlankLines = dataProvider.ConsumeBool();
+
+    TemporaryFile tf;
+    android::FdPrinter filePrinter = android::FdPrinter(tf.fd, indent, prefix.c_str());
+    android::String8Printer stringPrinter = android::String8Printer(&outStr);
+    android::PrefixPrinter printer = android::PrefixPrinter(stringPrinter, prefix.c_str());
+    android::LogPrinter logPrinter =
+            android::LogPrinter(logTag.c_str(), priority, prefix.c_str(), ignoreBlankLines);
+
+    printer.printLine(line.c_str());
+    printer.printFormatLine("%s", line.c_str());
+    logPrinter.printLine(line.c_str());
+    logPrinter.printFormatLine("%s", line.c_str());
+    filePrinter.printLine(line.c_str());
+    filePrinter.printFormatLine("%s", line.c_str());
+    return 0;
+}
diff --git a/libutils/ProcessCallStack_fuzz.cpp b/libutils/ProcessCallStack_fuzz.cpp
new file mode 100644
index 0000000..30136cd
--- /dev/null
+++ b/libutils/ProcessCallStack_fuzz.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <atomic>
+#include <thread>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/ProcessCallStack.h"
+using android::ProcessCallStack;
+
+static constexpr int MAX_NAME_SIZE = 1000;
+static constexpr int MAX_LOG_META_SIZE = 1000;
+static constexpr uint8_t MAX_THREADS = 10;
+
+std::atomic_bool ranCallStackUpdate(false);
+void loop() {
+    while (!ranCallStackUpdate.load()) {
+        std::this_thread::sleep_for(std::chrono::milliseconds(50));
+    }
+}
+
+void spawnThreads(FuzzedDataProvider* dataProvider) {
+    std::vector<std::thread> threads = std::vector<std::thread>();
+
+    // Get the number of threads to generate
+    uint8_t count = dataProvider->ConsumeIntegralInRange<uint8_t>(1, MAX_THREADS);
+
+    // Generate threads
+    for (uint8_t i = 0; i < count; i++) {
+        std::string threadName =
+                dataProvider->ConsumeRandomLengthString(MAX_NAME_SIZE).append(std::to_string(i));
+        std::thread th = std::thread(loop);
+        pthread_setname_np(th.native_handle(), threadName.c_str());
+        threads.push_back(move(th));
+    }
+
+    // Collect thread information
+    ProcessCallStack callStack = ProcessCallStack();
+    callStack.update();
+
+    // Tell our patiently waiting threads they can be done now.
+    ranCallStackUpdate.store(true);
+
+    std::string logTag = dataProvider->ConsumeRandomLengthString(MAX_LOG_META_SIZE);
+    std::string prefix = dataProvider->ConsumeRandomLengthString(MAX_LOG_META_SIZE);
+    // Both of these, along with dump, all call print() under the hood,
+    // Which is covered by the Printer fuzzer.
+    callStack.log(logTag.c_str());
+    callStack.toString(prefix.c_str());
+
+    // Check size
+    callStack.size();
+
+    // wait for any remaining threads
+    for (auto& thread : threads) {
+        thread.join();
+    }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    spawnThreads(&dataProvider);
+    return 0;
+}
diff --git a/libutils/PropertyMap.cpp b/libutils/PropertyMap.cpp
deleted file mode 100644
index f00272a..0000000
--- a/libutils/PropertyMap.cpp
+++ /dev/null
@@ -1,214 +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.
- */
-
-#define LOG_TAG "PropertyMap"
-
-#include <utils/PropertyMap.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 = nullptr;
-
-    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 OK;
-}
-
-} // namespace android
diff --git a/libutils/RefBase_fuzz.cpp b/libutils/RefBase_fuzz.cpp
new file mode 100755
index 0000000..2a92531
--- /dev/null
+++ b/libutils/RefBase_fuzz.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <atomic>
+#include <thread>
+
+#include "fuzzer/FuzzedDataProvider.h"
+#include "utils/RefBase.h"
+#include "utils/StrongPointer.h"
+using android::RefBase;
+using android::sp;
+using android::wp;
+
+static constexpr int REFBASE_INITIAL_STRONG_VALUE = (1 << 28);
+static constexpr int REFBASE_MAX_COUNT = 0xfffff;
+
+static constexpr int MAX_OPERATIONS = 100;
+static constexpr int MAX_THREADS = 10;
+
+bool canDecrementStrong(RefBase* ref) {
+    // There's an assert around decrementing the strong count too much that causes an artificial
+    // crash This is just running BAD_STRONG from RefBase
+    const int32_t count = ref->getStrongCount() - 1;
+    return !(count == 0 || ((count) & (~(REFBASE_MAX_COUNT | REFBASE_INITIAL_STRONG_VALUE))) != 0);
+}
+bool canDecrementWeak(RefBase* ref) {
+    const int32_t count = ref->getWeakRefs()->getWeakCount() - 1;
+    return !((count) == 0 || ((count) & (~REFBASE_MAX_COUNT)) != 0);
+}
+
+struct RefBaseSubclass : public RefBase {
+    RefBaseSubclass() {}
+    virtual ~RefBaseSubclass() {}
+};
+
+std::vector<std::function<void(RefBaseSubclass*)>> operations = {
+        [](RefBaseSubclass* ref) -> void { ref->getStrongCount(); },
+        [](RefBaseSubclass* ref) -> void { ref->printRefs(); },
+        [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->printRefs(); },
+        [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->getWeakCount(); },
+        [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->refBase(); },
+        [](RefBaseSubclass* ref) -> void { ref->incStrong(nullptr); },
+        [](RefBaseSubclass* ref) -> void {
+            if (canDecrementStrong(ref)) {
+                ref->decStrong(nullptr);
+            }
+        },
+        [](RefBaseSubclass* ref) -> void { ref->forceIncStrong(nullptr); },
+        [](RefBaseSubclass* ref) -> void { ref->createWeak(nullptr); },
+        [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->attemptIncStrong(nullptr); },
+        [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->attemptIncWeak(nullptr); },
+        [](RefBaseSubclass* ref) -> void {
+            if (canDecrementWeak(ref)) {
+                ref->getWeakRefs()->decWeak(nullptr);
+            }
+        },
+        [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->incWeak(nullptr); },
+        [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->printRefs(); },
+};
+
+void loop(RefBaseSubclass* loopRef, const std::vector<uint8_t>& fuzzOps) {
+    for (auto op : fuzzOps) {
+        operations[op % operations.size()](loopRef);
+    }
+}
+
+void spawnThreads(FuzzedDataProvider* dataProvider) {
+    std::vector<std::thread> threads = std::vector<std::thread>();
+
+    // Get the number of threads to generate
+    uint8_t count = dataProvider->ConsumeIntegralInRange<uint8_t>(1, MAX_THREADS);
+
+    // Generate threads
+    for (uint8_t i = 0; i < count; i++) {
+        RefBaseSubclass* threadRef = new RefBaseSubclass();
+        uint8_t opCount = dataProvider->ConsumeIntegralInRange<uint8_t>(1, MAX_OPERATIONS);
+        std::vector<uint8_t> threadOperations = dataProvider->ConsumeBytes<uint8_t>(opCount);
+        std::thread tmp = std::thread(loop, threadRef, threadOperations);
+        threads.push_back(move(tmp));
+    }
+
+    for (auto& th : threads) {
+        th.join();
+    }
+}
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    spawnThreads(&dataProvider);
+    return 0;
+}
diff --git a/libutils/StopWatch_fuzz.cpp b/libutils/StopWatch_fuzz.cpp
new file mode 100644
index 0000000..63d8a28
--- /dev/null
+++ b/libutils/StopWatch_fuzz.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "fuzzer/FuzzedDataProvider.h"
+#include "utils/StopWatch.h"
+
+static constexpr int MAX_OPERATIONS = 100;
+static constexpr int MAX_NAME_LEN = 2048;
+
+static const std::vector<std::function<void(android::StopWatch)>> operations = {
+        [](android::StopWatch stopWatch) -> void { stopWatch.reset(); },
+        [](android::StopWatch stopWatch) -> void { stopWatch.lap(); },
+        [](android::StopWatch stopWatch) -> void { stopWatch.elapsedTime(); },
+        [](android::StopWatch stopWatch) -> void { stopWatch.name(); },
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider dataProvider(data, size);
+    std::string nameStr = dataProvider.ConsumeRandomLengthString(MAX_NAME_LEN);
+    int clockVal = dataProvider.ConsumeIntegral<int>();
+    android::StopWatch stopWatch = android::StopWatch(nameStr.c_str(), clockVal);
+    std::vector<uint8_t> opsToRun = dataProvider.ConsumeRemainingBytes<uint8_t>();
+    int opsRun = 0;
+    for (auto it : opsToRun) {
+        if (opsRun++ >= MAX_OPERATIONS) {
+            break;
+        }
+        it = it % operations.size();
+        operations[it](stopWatch);
+    }
+    return 0;
+}
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index d514f29..70bf5a0 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -441,7 +441,7 @@
         mString = getEmptyString();
         return OK;
     }
-    if ((begin+len) > N) len = N-begin;
+    if (len > N || len > N - begin) len = N - begin;
     if (begin == 0 && len == N) {
         return OK;
     }
diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp
index 2adfe98..b02683c 100644
--- a/libutils/String8_fuzz.cpp
+++ b/libutils/String8_fuzz.cpp
@@ -15,97 +15,199 @@
  */
 #include <functional>
 #include <iostream>
+#include <memory>
 
+#include "FuzzFormatTypes.h"
 #include "fuzzer/FuzzedDataProvider.h"
 #include "utils/String8.h"
 
 static constexpr int MAX_STRING_BYTES = 256;
 static constexpr uint8_t MAX_OPERATIONS = 50;
+// Interestingly, 2147483614 (INT32_MAX - 33) seems to be the max value that is handled for format
+// flags. Unfortunately we need to use a smaller value so we avoid consuming too much memory.
 
-std::vector<std::function<void(FuzzedDataProvider&, android::String8, android::String8)>>
+void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend);
+std::vector<std::function<void(FuzzedDataProvider*, android::String8*, android::String8*)>>
         operations = {
-
                 // Bytes and size
-                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
-                    str1.bytes();
+                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+                    str1->bytes();
                 },
-                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
-                    str1.isEmpty();
+                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+                    str1->isEmpty();
                 },
-                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
-                    str1.length();
-                },
-                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
-                    str1.size();
+                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+                    str1->length();
                 },
 
                 // Casing
-                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
-                    str1.toUpper();
+                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+                    str1->toUpper();
                 },
-                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
-                    str1.toLower();
+                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+                    str1->toLower();
                 },
-
-                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
-                    str1.removeAll(str2.c_str());
+                [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+                    str1->removeAll(str2->c_str());
                 },
-                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
-                    str1.compare(str2);
+                [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+                    const android::String8& constRef(*str2);
+                    str1->compare(constRef);
                 },
 
                 // Append and format
-                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
-                    str1.append(str2);
+                [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+                    str1->append(str2->c_str());
                 },
-                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
-                    str1.appendFormat(str1.c_str(), str2.c_str());
-                },
-                [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
-                    str1.format(str1.c_str(), str2.c_str());
-                },
+                [](FuzzedDataProvider* dataProvider, android::String8* str1, android::String8*)
+                        -> void { fuzzFormat(dataProvider, str1, dataProvider->ConsumeBool()); },
 
                 // Find operation
-                [](FuzzedDataProvider& dataProvider, android::String8 str1,
-                   android::String8) -> void {
+                [](FuzzedDataProvider* dataProvider, android::String8* str1,
+                   android::String8* str2) -> void {
                     // We need to get a value from our fuzzer here.
-                    int start_index = dataProvider.ConsumeIntegralInRange<int>(0, str1.size());
-                    str1.find(str1.c_str(), start_index);
+                    int start_index = dataProvider->ConsumeIntegralInRange<int>(0, str1->size());
+                    str1->find(str2->c_str(), start_index);
                 },
 
                 // Path handling
-                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
-                    str1.getBasePath();
+                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+                    str1->getBasePath();
                 },
-                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
-                    str1.getPathExtension();
+                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+                    str1->getPathExtension();
                 },
-                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
-                    str1.getPathLeaf();
+                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+                    str1->getPathLeaf();
                 },
-                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
-                    str1.getPathDir();
+                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+                    str1->getPathDir();
                 },
-                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
-                    str1.convertToResPath();
+                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+                    str1->convertToResPath();
                 },
-                [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
-                    android::String8 path_out_str = android::String8();
-                    str1.walkPath(&path_out_str);
-                    path_out_str.clear();
+                [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+                    std::shared_ptr<android::String8> path_out_str =
+                            std::make_shared<android::String8>();
+                    str1->walkPath(path_out_str.get());
+                    path_out_str->clear();
                 },
-                [](FuzzedDataProvider& dataProvider, android::String8 str1,
-                   android::String8) -> void {
-                    str1.setPathName(dataProvider.ConsumeBytesWithTerminator<char>(5).data());
+                [](FuzzedDataProvider* dataProvider, android::String8* str1,
+                   android::String8*) -> void {
+                    str1->setPathName(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
                 },
-                [](FuzzedDataProvider& dataProvider, android::String8 str1,
-                   android::String8) -> void {
-                    str1.appendPath(dataProvider.ConsumeBytesWithTerminator<char>(5).data());
+                [](FuzzedDataProvider* dataProvider, android::String8* str1,
+                   android::String8*) -> void {
+                    str1->appendPath(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
                 },
 };
 
-void callFunc(uint8_t index, FuzzedDataProvider& dataProvider, android::String8 str1,
-              android::String8 str2) {
+void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) {
+    FormatChar formatType = dataProvider->ConsumeEnum<FormatChar>();
+
+    std::string formatString("%");
+    // Width specifier
+    if (dataProvider->ConsumeBool()) {
+        // Left pad with zeroes
+        if (dataProvider->ConsumeBool()) {
+            formatString.push_back('0');
+        }
+        // Right justify (or left justify if negative)
+        int32_t justify = dataProvider->ConsumeIntegralInRange<int32_t>(-kMaxFormatFlagValue,
+                                                                        kMaxFormatFlagValue);
+        formatString += std::to_string(justify);
+    }
+
+    // The # specifier only works with o, x, X, a, A, e, E, f, F, g, and G
+    if (canApplyFlag(formatType, '#') && dataProvider->ConsumeBool()) {
+        formatString.push_back('#');
+    }
+
+    // Precision specifier
+    if (canApplyFlag(formatType, '.') && dataProvider->ConsumeBool()) {
+        formatString.push_back('.');
+        formatString +=
+                std::to_string(dataProvider->ConsumeIntegralInRange<int>(0, kMaxFormatFlagValue));
+    }
+
+    formatString.push_back(kFormatChars.at(static_cast<uint8_t>(formatType)));
+
+    switch (formatType) {
+        case SIGNED_DECIMAL: {
+            int val = dataProvider->ConsumeIntegral<int>();
+            if (shouldAppend) {
+                str1->appendFormat(formatString.c_str(), val);
+            } else {
+                str1->format(formatString.c_str(), dataProvider->ConsumeIntegral<int>());
+            }
+            break;
+        }
+
+        case UNSIGNED_DECIMAL:
+        case UNSIGNED_OCTAL:
+        case UNSIGNED_HEX_LOWER:
+        case UNSIGNED_HEX_UPPER: {
+            // Unsigned integers for u, o, x, and X
+            uint val = dataProvider->ConsumeIntegral<uint>();
+            if (shouldAppend) {
+                str1->appendFormat(formatString.c_str(), val);
+            } else {
+                str1->format(formatString.c_str(), val);
+            }
+            break;
+        }
+
+        case FLOAT_LOWER:
+        case FLOAT_UPPER:
+        case EXPONENT_LOWER:
+        case EXPONENT_UPPER:
+        case SHORT_EXP_LOWER:
+        case SHORT_EXP_UPPER:
+        case HEX_FLOAT_LOWER:
+        case HEX_FLOAT_UPPER: {
+            // Floating points for f, F, e, E, g, G, a, and A
+            float val = dataProvider->ConsumeFloatingPoint<float>();
+            if (shouldAppend) {
+                str1->appendFormat(formatString.c_str(), val);
+            } else {
+                str1->format(formatString.c_str(), val);
+            }
+            break;
+        }
+
+        case CHAR: {
+            char val = dataProvider->ConsumeIntegral<char>();
+            if (shouldAppend) {
+                str1->appendFormat(formatString.c_str(), val);
+            } else {
+                str1->format(formatString.c_str(), val);
+            }
+            break;
+        }
+
+        case STRING: {
+            std::string val = dataProvider->ConsumeRandomLengthString(MAX_STRING_BYTES);
+            if (shouldAppend) {
+                str1->appendFormat(formatString.c_str(), val.c_str());
+            } else {
+                str1->format(formatString.c_str(), val.c_str());
+            }
+            break;
+        }
+        case POINTER: {
+            uintptr_t val = dataProvider->ConsumeIntegral<uintptr_t>();
+            if (shouldAppend) {
+                str1->appendFormat(formatString.c_str(), val);
+            } else {
+                str1->format(formatString.c_str(), val);
+            }
+            break;
+        }
+    }
+}
+
+void callFunc(uint8_t index, FuzzedDataProvider* dataProvider, android::String8* str1,
+              android::String8* str2) {
     operations[index](dataProvider, str1, str2);
 }
 
@@ -120,14 +222,12 @@
     // Create UTF-8 pointers
     android::String8 str_one_utf8 = android::String8(vec.data());
     android::String8 str_two_utf8 = android::String8(vec_two.data());
-
     // Run operations against strings
     int opsRun = 0;
     while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
         uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
-        callFunc(op, dataProvider, str_one_utf8, str_two_utf8);
+        operations[op](&dataProvider, &str_one_utf8, &str_two_utf8);
     }
-
     // Just to be extra sure these can be freed, we're going to explicitly clear
     // them
     str_one_utf8.clear();
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index 73ec1be..9c71141 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -39,8 +39,15 @@
  */
 int64_t uptimeMillis()
 {
-    int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
-    return (int64_t) nanoseconds_to_milliseconds(when);
+    return nanoseconds_to_milliseconds(uptimeNanos());
+}
+
+/*
+ * public static native long uptimeNanos();
+ */
+int64_t uptimeNanos()
+{
+    return systemTime(SYSTEM_TIME_MONOTONIC);
 }
 
 /*
diff --git a/libutils/SystemClock_test.cpp b/libutils/SystemClock_test.cpp
index 5ad060b..7449dad 100644
--- a/libutils/SystemClock_test.cpp
+++ b/libutils/SystemClock_test.cpp
@@ -29,16 +29,24 @@
 
 TEST(SystemClock, SystemClock) {
     auto startUptimeMs = android::uptimeMillis();
+    auto startUptimeNs = android::uptimeNanos();
     auto startRealtimeMs = android::elapsedRealtime();
     auto startRealtimeNs = android::elapsedRealtimeNano();
 
     ASSERT_GT(startUptimeMs, 0)
             << "uptimeMillis() reported an impossible uptime";
+    ASSERT_GT(startUptimeNs, 0)
+            << "uptimeNanos() reported an impossible uptime";
     ASSERT_GE(startRealtimeMs, startUptimeMs)
             << "elapsedRealtime() thinks we've suspended for negative time";
-    ASSERT_GE(startRealtimeNs, startUptimeMs * MS_IN_NS)
+    ASSERT_GE(startRealtimeNs, startUptimeNs)
             << "elapsedRealtimeNano() thinks we've suspended for negative time";
 
+    ASSERT_GE(startUptimeNs, startUptimeMs * MS_IN_NS)
+            << "uptimeMillis() and uptimeNanos() are inconsistent";
+    ASSERT_LT(startUptimeNs, (startUptimeMs + SLACK_MS) * MS_IN_NS)
+            << "uptimeMillis() and uptimeNanos() are inconsistent";
+
     ASSERT_GE(startRealtimeNs, startRealtimeMs * MS_IN_NS)
             << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent";
     ASSERT_LT(startRealtimeNs, (startRealtimeMs + SLACK_MS) * MS_IN_NS)
@@ -51,6 +59,7 @@
     ASSERT_EQ(nanosleepErr, 0) << "nanosleep() failed: " << strerror(errno);
 
     auto endUptimeMs = android::uptimeMillis();
+    auto endUptimeNs = android::uptimeNanos();
     auto endRealtimeMs = android::elapsedRealtime();
     auto endRealtimeNs = android::elapsedRealtimeNano();
 
@@ -58,6 +67,10 @@
             << "uptimeMillis() advanced too little after nanosleep()";
     EXPECT_LT(endUptimeMs - startUptimeMs, SLEEP_MS + SLACK_MS)
             << "uptimeMillis() advanced too much after nanosleep()";
+    EXPECT_GE(endUptimeNs - startUptimeNs, SLEEP_NS)
+            << "uptimeNanos() advanced too little after nanosleep()";
+    EXPECT_LT(endUptimeNs - startUptimeNs, SLEEP_NS + SLACK_NS)
+            << "uptimeNanos() advanced too much after nanosleep()";
     EXPECT_GE(endRealtimeMs - startRealtimeMs, SLEEP_MS)
             << "elapsedRealtime() advanced too little after nanosleep()";
     EXPECT_LT(endRealtimeMs - startRealtimeMs, SLEEP_MS + SLACK_MS)
@@ -67,6 +80,11 @@
     EXPECT_LT(endRealtimeNs - startRealtimeNs, SLEEP_NS + SLACK_NS)
             << "elapsedRealtimeNano() advanced too much after nanosleep()";
 
+    EXPECT_GE(endUptimeNs, endUptimeMs * MS_IN_NS)
+            << "uptimeMillis() and uptimeNanos() are inconsistent after nanosleep()";
+    EXPECT_LT(endUptimeNs, (endUptimeMs + SLACK_MS) * MS_IN_NS)
+            << "uptimeMillis() and uptimeNanos() are inconsistent after nanosleep()";
+
     EXPECT_GE(endRealtimeNs, endRealtimeMs * MS_IN_NS)
             << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent after nanosleep()";
     EXPECT_LT(endRealtimeNs, (endRealtimeMs + SLACK_MS) * MS_IN_NS)
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 147db54..540dcf4 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -302,7 +302,8 @@
 }
 
 #if defined(__ANDROID__)
-int androidSetThreadPriority(pid_t tid, int pri, bool change_policy) {
+int androidSetThreadPriority(pid_t tid, int pri)
+{
     int rc = 0;
     int lasterr = 0;
     int curr_pri = getpriority(PRIO_PROCESS, tid);
@@ -311,19 +312,17 @@
         return rc;
     }
 
-    if (change_policy) {
-        if (pri >= ANDROID_PRIORITY_BACKGROUND) {
-            rc = SetTaskProfiles(tid, {"SCHED_SP_BACKGROUND"}, true) ? 0 : -1;
-        } else if (curr_pri >= ANDROID_PRIORITY_BACKGROUND) {
-            SchedPolicy policy = SP_FOREGROUND;
-            // Change to the sched policy group of the process.
-            get_sched_policy(getpid(), &policy);
-            rc = SetTaskProfiles(tid, {get_sched_policy_profile_name(policy)}, true) ? 0 : -1;
-        }
+    if (pri >= ANDROID_PRIORITY_BACKGROUND) {
+        rc = SetTaskProfiles(tid, {"SCHED_SP_BACKGROUND"}, true) ? 0 : -1;
+    } else if (curr_pri >= ANDROID_PRIORITY_BACKGROUND) {
+        SchedPolicy policy = SP_FOREGROUND;
+        // Change to the sched policy group of the process.
+        get_sched_policy(getpid(), &policy);
+        rc = SetTaskProfiles(tid, {get_sched_policy_profile_name(policy)}, true) ? 0 : -1;
+    }
 
-        if (rc) {
-            lasterr = errno;
-        }
+    if (rc) {
+        lasterr = errno;
     }
 
     if (setpriority(PRIO_PROCESS, tid, pri) < 0) {
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index b08e061..b6e457b 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -162,9 +162,9 @@
     if (index >= src_len) {
         return -1;
     }
-    size_t dummy_index;
+    size_t unused_index;
     if (next_index == nullptr) {
-        next_index = &dummy_index;
+        next_index = &unused_index;
     }
     size_t num_read;
     int32_t ret = utf32_at_internal(src + index, &num_read);
diff --git a/libutils/include/utils/AndroidThreads.h b/libutils/include/utils/AndroidThreads.h
index 3c30a2a..a8d7851 100644
--- a/libutils/include/utils/AndroidThreads.h
+++ b/libutils/include/utils/AndroidThreads.h
@@ -78,9 +78,7 @@
 // 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.
-// Parameter "change_policy" indicates if sched policy should be changed. It needs
-// not be checked again if the change is done elsewhere like activity manager.
-extern int androidSetThreadPriority(pid_t tid, int prio, bool change_policy = true);
+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.
diff --git a/libutils/include/utils/Debug.h b/libutils/include/utils/Debug.h
index 96bd70e..c3b9026 100644
--- a/libutils/include/utils/Debug.h
+++ b/libutils/include/utils/Debug.h
@@ -14,27 +14,9 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UTILS_DEBUG_H
-#define ANDROID_UTILS_DEBUG_H
+#pragma once
 
-#include <stdint.h>
-#include <sys/types.h>
+// Note: new code should use static_assert directly.
 
-namespace android {
-// ---------------------------------------------------------------------------
-
-#ifdef __cplusplus
-template<bool> struct CompileTimeAssert;
-template<> struct CompileTimeAssert<true> {};
-#define COMPILE_TIME_ASSERT(_exp) \
-    template class CompileTimeAssert< (_exp) >;
-#endif
-
-// DO NOT USE: Please use static_assert instead
-#define COMPILE_TIME_ASSERT_FUNCTION_SCOPE(_exp) \
-    CompileTimeAssert<( _exp )>();
-
-// ---------------------------------------------------------------------------
-}  // namespace android
-
-#endif // ANDROID_UTILS_DEBUG_H
+#define COMPILE_TIME_ASSERT static_assert
+#define COMPILE_TIME_ASSERT_FUNCTION_SCOPE static_assert
diff --git a/libutils/include/utils/Flattenable.h b/libutils/include/utils/Flattenable.h
index 17c5e10..8aa381a 100644
--- a/libutils/include/utils/Flattenable.h
+++ b/libutils/include/utils/Flattenable.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_UTILS_FLATTENABLE_H
-#define ANDROID_UTILS_FLATTENABLE_H
+#pragma once
 
 // DO NOT USE: please use parcelable instead
 // This code is deprecated and will not be supported via AIDL code gen. For data
@@ -25,7 +24,6 @@
 #include <string.h>
 #include <sys/types.h>
 #include <utils/Errors.h>
-#include <utils/Debug.h>
 
 #include <type_traits>
 
@@ -217,5 +215,3 @@
 };
 
 }  // namespace android
-
-#endif /* ANDROID_UTILS_FLATTENABLE_H */
diff --git a/libutils/include/utils/PropertyMap.h b/libutils/include/utils/PropertyMap.h
deleted file mode 100644
index a9e674f..0000000
--- a/libutils/include/utils/PropertyMap.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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/libutils/include/utils/SystemClock.h b/libutils/include/utils/SystemClock.h
index f816fba..892104c 100644
--- a/libutils/include/utils/SystemClock.h
+++ b/libutils/include/utils/SystemClock.h
@@ -23,6 +23,7 @@
 namespace android {
 
 int64_t uptimeMillis();
+int64_t uptimeNanos();
 int64_t elapsedRealtime();
 int64_t elapsedRealtimeNano();
 
diff --git a/libutils/include/utils/Vector.h b/libutils/include/utils/Vector.h
index ddf71de..be35ea2 100644
--- a/libutils/include/utils/Vector.h
+++ b/libutils/include/utils/Vector.h
@@ -23,15 +23,13 @@
 #include <log/log.h>
 #include <utils/TypeHelpers.h>
 #include <utils/VectorImpl.h>
-
-/*
- * Used to blacklist some functions from CFI.
- *
- */
 #ifndef __has_attribute
 #define __has_attribute(x) 0
 #endif
 
+/*
+ * Used to exclude some functions from CFI.
+ */
 #if __has_attribute(no_sanitize)
 #define UTILS_VECTOR_NO_CFI __attribute__((no_sanitize("cfi")))
 #else
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index d15fa2b..6b7e016 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -64,6 +64,7 @@
 using android::base::ParseUint;
 using android::base::Split;
 using android::base::StringPrintf;
+using android::base::WriteFully;
 
 class Logcat {
   public:
@@ -616,15 +617,15 @@
                 if (long_options[option_index].name == wrap_str) {
                     mode |= ANDROID_LOG_WRAP | ANDROID_LOG_NONBLOCK;
                     // ToDo: implement API that supports setting a wrap timeout
-                    size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
-                    if (optarg && (!ParseUint(optarg, &dummy) || dummy < 1)) {
+                    size_t timeout = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
+                    if (optarg && (!ParseUint(optarg, &timeout) || timeout < 1)) {
                         error(EXIT_FAILURE, 0, "%s %s out of range.",
                               long_options[option_index].name, optarg);
                     }
-                    if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
+                    if (timeout != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
                         fprintf(stderr, "WARNING: %s %u seconds, ignoring %zu\n",
                                 long_options[option_index].name, ANDROID_LOG_WRAP_DEFAULT_TIMEOUT,
-                                dummy);
+                                timeout);
                     }
                     break;
                 }
@@ -864,8 +865,7 @@
 
                     if (consolePipe) {
                         // need the trailing '\0'
-                        if (!android::base::WriteFully(fd, pipePurpose.c_str(),
-                                                       pipePurpose.size() + 1)) {
+                        if (!WriteFully(fd, pipePurpose.c_str(), pipePurpose.size() + 1)) {
                             close(fd);
                             return EXIT_FAILURE;
                         }
@@ -1064,19 +1064,23 @@
         if (getLogSize) {
             long size = android_logger_get_log_size(logger);
             long readable = android_logger_get_log_readable_size(logger);
+            long consumed = android_logger_get_log_consumed_size(logger);
 
             if (size < 0 || readable < 0) {
                 ReportErrorName(buffer_name, security_buffer_selected, &get_size_failures);
             } else {
                 auto size_format = format_of_size(size);
                 auto readable_format = format_of_size(readable);
+                auto consumed_format = format_of_size(consumed);
                 std::string str = android::base::StringPrintf(
-                        "%s: ring buffer is %lu %sB (%lu %sB consumed),"
+                        "%s: ring buffer is %lu %sB (%lu %sB consumed, %lu %sB readable),"
                         " max entry is %d B, max payload is %d B\n",
-                        buffer_name, size_format.first, size_format.second, readable_format.first,
-                        readable_format.second, (int)LOGGER_ENTRY_MAX_LEN,
-                        (int)LOGGER_ENTRY_MAX_PAYLOAD);
-                TEMP_FAILURE_RETRY(write(output_fd_.get(), str.data(), str.length()));
+                        buffer_name, size_format.first, size_format.second, consumed_format.first,
+                        consumed_format.second, readable_format.first, readable_format.second,
+                        (int)LOGGER_ENTRY_MAX_LEN, (int)LOGGER_ENTRY_MAX_PAYLOAD);
+                if (!WriteFully(output_fd_, str.data(), str.length())) {
+                    error(EXIT_FAILURE, errno, "Failed to write to output fd");
+                }
             }
         }
     }
@@ -1146,7 +1150,9 @@
         if (*cp == '\n') ++cp;
 
         size_t len = strlen(cp);
-        TEMP_FAILURE_RETRY(write(output_fd_.get(), cp, len));
+        if (!WriteFully(output_fd_, cp, len)) {
+            error(EXIT_FAILURE, errno, "Failed to write to output fd");
+        }
         return EXIT_SUCCESS;
     }
 
@@ -1190,7 +1196,9 @@
         PrintDividers(log_msg.id(), printDividers);
 
         if (print_binary_) {
-            TEMP_FAILURE_RETRY(write(output_fd_.get(), &log_msg, log_msg.len()));
+            if (!WriteFully(output_fd_, &log_msg, log_msg.len())) {
+                error(EXIT_FAILURE, errno, "Failed to write to output fd");
+            }
         } else {
             ProcessBuffer(&log_msg);
         }
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 61aa938..735fd94 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -539,7 +539,6 @@
 static int get_groups(const char* cmd) {
     FILE* fp;
 
-    // NB: crash log only available in user space
     EXPECT_TRUE(NULL != (fp = popen(cmd, "r")));
 
     if (fp == NULL) {
@@ -551,17 +550,18 @@
     int count = 0;
 
     while (fgets(buffer, sizeof(buffer), fp)) {
-        int size, consumed, max, payload;
-        char size_mult[4], consumed_mult[4];
+        int size, consumed, readable, max, payload;
+        char size_mult[4], consumed_mult[4], readable_mult[4];
         long full_size, full_consumed;
 
         size = consumed = max = payload = 0;
         // NB: crash log can be very small, not hit a Kb of consumed space
         //     doubly lucky we are not including it.
-        EXPECT_EQ(6, sscanf(buffer,
-                            "%*s ring buffer is %d %3s (%d %3s consumed),"
+        EXPECT_EQ(8, sscanf(buffer,
+                            "%*s ring buffer is %d %3s (%d %3s consumed, %d %3s readable),"
                             " max entry is %d B, max payload is %d B",
-                            &size, size_mult, &consumed, consumed_mult, &max, &payload))
+                            &size, size_mult, &consumed, consumed_mult, &readable, readable_mult,
+                            &max, &payload))
                 << "Parse error on: " << buffer;
         full_size = size;
         switch (size_mult[0]) {
@@ -1224,13 +1224,14 @@
             break;
         }
 
-        int size, consumed, max, payload;
-        char size_mult[4], consumed_mult[4];
+        int size, consumed, readable, max, payload;
+        char size_mult[4], consumed_mult[4], readable_mult[4];
         size = consumed = max = payload = 0;
-        if (6 == sscanf(buffer,
-                        "events: ring buffer is %d %3s (%d %3s consumed),"
+        if (8 == sscanf(buffer,
+                        "events: ring buffer is %d %3s (%d %3s consumed, %d %3s readable),"
                         " max entry is %d B, max payload is %d B",
-                        &size, size_mult, &consumed, consumed_mult, &max, &payload)) {
+                        &size, size_mult, &consumed, consumed_mult, &readable, readable_mult, &max,
+                        &payload)) {
             long full_size = size, full_consumed = consumed;
 
             switch (size_mult[0]) {
@@ -1654,68 +1655,6 @@
         EXPECT_GE(ret, 0);
         EXPECT_TRUE(End_to_End(sync.tagStr, ""));
     }
-
-    {
-        // Invent new entries because existing can not serve
-        EventTagMap* map = android_openEventTagMap(nullptr);
-        ASSERT_TRUE(nullptr != map);
-        static const char name[] = logcat_executable ".descriptive-monotonic";
-        int myTag = android_lookupEventTagNum(map, name, "(new|1|s)",
-                                              ANDROID_LOG_UNKNOWN);
-        android_closeEventTagMap(map);
-        ASSERT_NE(-1, myTag);
-
-        const struct tag sync = { (uint32_t)myTag, name };
-
-        {
-            android_log_event_list ctx(sync.tagNo);
-            ctx << (uint32_t)7;
-            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
-            EXPECT_GE(ret, 0);
-            EXPECT_TRUE(End_to_End(sync.tagStr, "new=7s"));
-        }
-        {
-            android_log_event_list ctx(sync.tagNo);
-            ctx << (uint32_t)62;
-            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
-            EXPECT_GE(ret, 0);
-            EXPECT_TRUE(End_to_End(sync.tagStr, "new=1:02"));
-        }
-        {
-            android_log_event_list ctx(sync.tagNo);
-            ctx << (uint32_t)3673;
-            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
-            EXPECT_GE(ret, 0);
-            EXPECT_TRUE(End_to_End(sync.tagStr, "new=1:01:13"));
-        }
-        {
-            android_log_event_list ctx(sync.tagNo);
-            ctx << (uint32_t)(86400 + 7200 + 180 + 58);
-            for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
-            EXPECT_GE(ret, 0);
-            EXPECT_TRUE(End_to_End(sync.tagStr, "new=1d 2:03:58"));
-        }
-    }
-}
-
-static bool reportedSecurity(const char* command) {
-    FILE* fp = popen(command, "r");
-    if (!fp) return true;
-
-    std::string ret;
-    bool val = android::base::ReadFdToString(fileno(fp), &ret);
-    pclose(fp);
-
-    if (!val) return true;
-    return std::string::npos != ret.find("'security'");
-}
-
-TEST(logcat, security) {
-    EXPECT_FALSE(reportedSecurity(logcat_executable " -b all -g 2>&1"));
-    EXPECT_TRUE(reportedSecurity(logcat_executable " -b security -g 2>&1"));
-    EXPECT_TRUE(reportedSecurity(logcat_executable " -b security -c 2>&1"));
-    EXPECT_TRUE(
-        reportedSecurity(logcat_executable " -b security -G 256K 2>&1"));
 }
 
 static size_t commandOutputSize(const char* command) {
@@ -1749,7 +1688,7 @@
   ASSERT_TRUE(android::base::ReadFdToString(fileno(fp), &output));
   pclose(fp);
 
-  ASSERT_TRUE(android::base::StartsWith(output, "unknown buffer foo\n"));
+  EXPECT_NE(std::string::npos, output.find("Unknown buffer 'foo'"));
 }
 
 static void SniffUid(const std::string& line, uid_t& uid) {
diff --git a/logd/Android.bp b/logd/Android.bp
index 036cb7e..335a174 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -36,6 +36,7 @@
         "libz",
     ],
     static_libs: ["libzstd"],
+    header_libs: ["libcutils_headers"],
     cflags: [
         "-Wextra",
         "-Wthread-safety",
@@ -44,6 +45,9 @@
     lto: {
         thin: true,
     },
+    sanitize: {
+        cfi: true,
+    },
     cpp_std: "experimental",
 }
 
@@ -57,6 +61,7 @@
         "LogReaderList.cpp",
         "LogReaderThread.cpp",
         "LogBufferElement.cpp",
+        "LogSize.cpp",
         "LogStatistics.cpp",
         "LogTags.cpp",
         "PruneList.cpp",
@@ -65,6 +70,7 @@
         "SerializedLogChunk.cpp",
         "SimpleLogBuffer.cpp",
     ],
+    static_libs: ["liblog"],
     logtags: ["event.logtags"],
 
     export_include_dirs: ["."],
@@ -144,7 +150,9 @@
         "SerializedLogChunkTest.cpp",
         "SerializedFlushToStateTest.cpp",
     ],
-
+    sanitize: {
+        cfi: true,
+    },
     static_libs: [
         "libbase",
         "libcutils",
@@ -177,6 +185,27 @@
     },
     test_suites: [
         "cts",
+        "device-tests",
         "vts10",
     ],
 }
+
+cc_binary {
+    name: "replay_messages",
+    defaults: ["logd_defaults"],
+    host_supported: true,
+
+    srcs: [
+        "ReplayMessages.cpp",
+    ],
+
+    static_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "liblogd",
+        "libselinux",
+        "libz",
+        "libzstd",
+    ],
+}
diff --git a/logd/ChattyLogBuffer.h b/logd/ChattyLogBuffer.h
index ce3dc7b..b4d3a2f 100644
--- a/logd/ChattyLogBuffer.h
+++ b/logd/ChattyLogBuffer.h
@@ -25,7 +25,6 @@
 #include <android-base/thread_annotations.h>
 #include <android/log.h>
 #include <private/android_filesystem_config.h>
-#include <sysutils/SocketClient.h>
 
 #include "LogBuffer.h"
 #include "LogBufferElement.h"
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 2eeb0d9..0ba1621 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -32,6 +32,7 @@
 #include <string>
 
 #include <android-base/logging.h>
+#include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <cutils/sockets.h>
 #include <log/log_properties.h>
@@ -46,6 +47,7 @@
     registerCmd(new ClearCmd(this));
     registerCmd(new GetBufSizeCmd(this));
     registerCmd(new SetBufSizeCmd(this));
+    registerCmd(new GetBufSizeReadableCmd(this));
     registerCmd(new GetBufSizeUsedCmd(this));
     registerCmd(new GetStatisticsCmd(this));
     registerCmd(new SetPruneListCmd(this));
@@ -63,53 +65,58 @@
     }
 }
 
-int CommandListener::ClearCmd::runCommand(SocketClient* cli, int argc,
-                                          char** argv) {
+template <typename F>
+static int LogIdCommand(SocketClient* cli, int argc, char** argv, F&& function) {
     setname();
+    if (argc < 2) {
+        cli->sendMsg("Missing Argument");
+        return 0;
+    }
+
+    int log_id;
+    if (!android::base::ParseInt(argv[1], &log_id, static_cast<int>(LOG_ID_MAIN),
+                                 static_cast<int>(LOG_ID_KERNEL))) {
+        cli->sendMsg("Range Error");
+        return 0;
+    }
+
+    function(static_cast<log_id_t>(log_id));
+    return 0;
+}
+
+int CommandListener::ClearCmd::runCommand(SocketClient* cli, int argc, char** argv) {
     uid_t uid = cli->getUid();
     if (clientHasLogCredentials(cli)) {
         uid = AID_ROOT;
     }
 
-    if (argc < 2) {
-        cli->sendMsg("Missing Argument");
-        return 0;
-    }
-
-    int id = atoi(argv[1]);
-    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
-        cli->sendMsg("Range Error");
-        return 0;
-    }
-
-    cli->sendMsg(buf()->Clear((log_id_t)id, uid) ? "success" : "busy");
-    return 0;
+    return LogIdCommand(cli, argc, argv, [&](log_id_t id) {
+        cli->sendMsg(buf()->Clear(id, uid) ? "success" : "busy");
+    });
 }
 
-int CommandListener::GetBufSizeCmd::runCommand(SocketClient* cli, int argc,
-                                               char** argv) {
-    setname();
-    if (argc < 2) {
-        cli->sendMsg("Missing Argument");
-        return 0;
-    }
+template <typename F>
+static int LogSizeCommand(SocketClient* cli, int argc, char** argv, F&& size_function) {
+    return LogIdCommand(cli, argc, argv, [&](log_id_t log_id) {
+        cli->sendMsg(std::to_string(size_function(log_id)).c_str());
+    });
+}
 
-    int id = atoi(argv[1]);
-    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
-        cli->sendMsg("Range Error");
-        return 0;
-    }
+int CommandListener::GetBufSizeCmd::runCommand(SocketClient* cli, int argc, char** argv) {
+    return LogSizeCommand(cli, argc, argv, [this](log_id_t id) { return buf()->GetSize(id); });
+}
 
-    unsigned long size = buf()->GetSize((log_id_t)id);
-    char buf[512];
-    snprintf(buf, sizeof(buf), "%lu", size);
-    cli->sendMsg(buf);
-    return 0;
+int CommandListener::GetBufSizeReadableCmd::runCommand(SocketClient* cli, int argc, char** argv) {
+    return LogSizeCommand(cli, argc, argv,
+                          [this](log_id_t id) { return stats()->SizeReadable(id); });
+}
+
+int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient* cli, int argc, char** argv) {
+    return LogSizeCommand(cli, argc, argv, [this](log_id_t id) { return stats()->Sizes(id); });
 }
 
 int CommandListener::SetBufSizeCmd::runCommand(SocketClient* cli, int argc,
                                                char** argv) {
-    setname();
     if (!clientHasLogCredentials(cli)) {
         cli->sendMsg("Permission Denied");
         return 0;
@@ -119,42 +126,11 @@
         cli->sendMsg("Missing Argument");
         return 0;
     }
+    size_t size = atol(argv[2]);
 
-    int id = atoi(argv[1]);
-    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
-        cli->sendMsg("Range Error");
-        return 0;
-    }
-
-    unsigned long size = atol(argv[2]);
-    if (buf()->SetSize((log_id_t)id, size)) {
-        cli->sendMsg("Range Error");
-        return 0;
-    }
-
-    cli->sendMsg("success");
-    return 0;
-}
-
-int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient* cli, int argc,
-                                                   char** argv) {
-    setname();
-    if (argc < 2) {
-        cli->sendMsg("Missing Argument");
-        return 0;
-    }
-
-    int id = atoi(argv[1]);
-    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
-        cli->sendMsg("Range Error");
-        return 0;
-    }
-
-    unsigned long size = stats()->Sizes((log_id_t)id);
-    char buf[512];
-    snprintf(buf, sizeof(buf), "%lu", size);
-    cli->sendMsg(buf);
-    return 0;
+    return LogIdCommand(cli, argc, argv, [&](log_id_t log_id) {
+        cli->sendMsg(buf()->SetSize(log_id, size) ? "success" : "busy");
+    });
 }
 
 // This returns a string with a length prefix with the format <length>\n<data>\n\f.  The length
@@ -179,8 +155,7 @@
     return android::base::StringPrintf("%zu\n%s\n\f", total_size, str.c_str());
 }
 
-int CommandListener::GetStatisticsCmd::runCommand(SocketClient* cli, int argc,
-                                                  char** argv) {
+int CommandListener::GetStatisticsCmd::runCommand(SocketClient* cli, int argc, char** argv) {
     setname();
     uid_t uid = cli->getUid();
     if (clientHasLogCredentials(cli)) {
@@ -245,8 +220,7 @@
     return 0;
 }
 
-int CommandListener::GetEventTagCmd::runCommand(SocketClient* cli, int argc,
-                                                char** argv) {
+int CommandListener::GetEventTagCmd::runCommand(SocketClient* cli, int argc, char** argv) {
     setname();
     uid_t uid = cli->getUid();
     if (clientHasLogCredentials(cli)) {
@@ -290,8 +264,7 @@
     return 0;
 }
 
-int CommandListener::ReinitCmd::runCommand(SocketClient* cli, int /*argc*/,
-                                           char** /*argv*/) {
+int CommandListener::ReinitCmd::runCommand(SocketClient* cli, int, char**) {
     setname();
 
     LOG(INFO) << "logd reinit";
@@ -314,8 +287,7 @@
     return 0;
 }
 
-int CommandListener::ExitCmd::runCommand(SocketClient* cli, int /*argc*/,
-                                         char** /*argv*/) {
+int CommandListener::ExitCmd::runCommand(SocketClient* cli, int, char**) {
     setname();
 
     cli->sendMsg("success");
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index c3080ab..8e12634 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -57,6 +57,7 @@
     LogCmd(Clear, clear);
     LogCmd(GetBufSize, getLogSize);
     LogCmd(SetBufSize, setLogSize);
+    LogCmd(GetBufSizeReadable, getLogSizeReadable);
     LogCmd(GetBufSizeUsed, getLogSizeUsed);
     LogCmd(GetStatistics, getStatistics);
     LogCmd(GetPruneList, getPruneList);
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 0ce9796..0e17476 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -32,7 +32,7 @@
 #include <sstream>
 
 #include <android-base/macros.h>
-#include <log/log_properties.h>
+#include <android-base/properties.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -40,6 +40,8 @@
 #include "LogUtils.h"
 #include "libaudit.h"
 
+using android::base::GetBoolProperty;
+
 #define KMSG_PRIORITY(PRI)                               \
     '<', '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \
         '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, '>'
@@ -48,8 +50,8 @@
     : SocketListener(getLogSocket(), false),
       logbuf(buf),
       fdDmesg(fdDmesg),
-      main(__android_logger_property_get_bool("ro.logd.auditd.main", BOOL_DEFAULT_TRUE)),
-      events(__android_logger_property_get_bool("ro.logd.auditd.events", BOOL_DEFAULT_TRUE)),
+      main(GetBoolProperty("ro.logd.auditd.main", true)),
+      events(GetBoolProperty("ro.logd.auditd.events", true)),
       initialized(false),
       stats_(stats) {
     static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index c5d333a..a98c4b9 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -68,8 +68,8 @@
                                              log_time realtime)>& filter) = 0;
 
     virtual bool Clear(log_id_t id, uid_t uid) = 0;
-    virtual unsigned long GetSize(log_id_t id) = 0;
-    virtual int SetSize(log_id_t id, unsigned long size) = 0;
+    virtual size_t GetSize(log_id_t id) = 0;
+    virtual bool SetSize(log_id_t id, size_t size) = 0;
 
     virtual uint64_t sequence() const = 0;
 };
diff --git a/logd/LogBufferTest.cpp b/logd/LogBufferTest.cpp
index 47d2a2f..1911105 100644
--- a/logd/LogBufferTest.cpp
+++ b/logd/LogBufferTest.cpp
@@ -34,16 +34,6 @@
 using android::base::Split;
 using android::base::StringPrintf;
 
-#ifndef __ANDROID__
-unsigned long __android_logger_get_buffer_size(log_id_t) {
-    return 1024 * 1024;
-}
-
-bool __android_logger_valid_buffer_size(unsigned long) {
-    return true;
-}
-#endif
-
 char* android::uidToName(uid_t) {
     return nullptr;
 }
diff --git a/logd/LogBufferTest.h b/logd/LogBufferTest.h
index 1fd22c2..eeeb980 100644
--- a/logd/LogBufferTest.h
+++ b/logd/LogBufferTest.h
@@ -75,6 +75,8 @@
         } else {
             FAIL() << "Unknown buffer type selected for test";
         }
+
+        log_id_for_each(i) { log_buffer_->SetSize(i, 1024 * 1024); }
     }
 
     void LogMessages(const std::vector<LogMessage>& messages) {
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index dbdf7fd..d6c7d25 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -381,8 +381,8 @@
         }
         if ((i == 9) && (cp[i] == ' ')) {
             int pid = 0;
-            char dummy;
-            if (sscanf(cp + 4, "%d%c", &pid, &dummy) == 2) {
+            char placeholder;
+            if (sscanf(cp + 4, "%d%c", &pid, &placeholder) == 2) {
                 buf = cp + 10;  // skip-it-all
                 return pid;
             }
@@ -392,8 +392,8 @@
         // Mediatek kernels with modified printk
         if (*cp == '[') {
             int pid = 0;
-            char dummy;
-            if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &dummy) == 2) {
+            char placeholder;
+            if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &placeholder) == 2) {
                 return pid;
             }
             break;  // Only the first one
@@ -703,7 +703,7 @@
         p = " ";
         b = 1;
     }
-    // paranoid sanity check, can not happen ...
+    // This shouldn't happen, but clamp the size if it does.
     if (b > LOGGER_ENTRY_MAX_PAYLOAD) {
         b = LOGGER_ENTRY_MAX_PAYLOAD;
     }
@@ -712,7 +712,7 @@
     }
     // calculate buffer copy requirements
     ssize_t n = 1 + taglen + 1 + b + 1;
-    // paranoid sanity check, first two just can not happen ...
+    // Extra checks for likely impossible cases.
     if ((taglen > n) || (b > n) || (n > (ssize_t)USHRT_MAX) || (n <= 0)) {
         return -EINVAL;
     }
@@ -722,7 +722,7 @@
     // If we malloc'd this buffer, we could get away without n's USHRT_MAX
     // test above, but we would then required a max(n, USHRT_MAX) as
     // truncating length argument to logbuf->log() below. Gain is protection
-    // of stack sanity and speedup, loss is truncated long-line content.
+    // against stack corruption and speedup, loss is truncated long-line content.
     char newstr[n];
     char* np = newstr;
 
diff --git a/logd/LogReader.h b/logd/LogReader.h
index b85a584..a4e52c4 100644
--- a/logd/LogReader.h
+++ b/logd/LogReader.h
@@ -22,8 +22,6 @@
 #include "LogReaderList.h"
 #include "LogReaderThread.h"
 
-#define LOGD_SNDTIMEO 32
-
 class LogReader : public SocketListener {
   public:
     explicit LogReader(LogBuffer* logbuf, LogReaderList* reader_list);
diff --git a/logd/LogReaderThread.h b/logd/LogReaderThread.h
index 1855c0e..20624f2 100644
--- a/logd/LogReaderThread.h
+++ b/logd/LogReaderThread.h
@@ -27,7 +27,6 @@
 #include <memory>
 
 #include <log/log.h>
-#include <sysutils/SocketClient.h>
 
 #include "LogBuffer.h"
 #include "LogWriter.h"
diff --git a/logd/LogSize.cpp b/logd/LogSize.cpp
new file mode 100644
index 0000000..fe829ba
--- /dev/null
+++ b/logd/LogSize.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <LogSize.h>
+
+#include <array>
+#include <optional>
+#include <string>
+
+#include <android-base/parseint.h>
+#include <android-base/properties.h>
+
+bool IsValidBufferSize(size_t value) {
+    return kLogBufferMinSize <= value && value <= kLogBufferMaxSize;
+}
+
+static std::optional<size_t> GetBufferSizeProperty(const std::string& key) {
+    std::string value = android::base::GetProperty(key, "");
+    if (value.empty()) {
+        return {};
+    }
+
+    uint32_t size;
+    if (!android::base::ParseByteCount(value, &size)) {
+        return {};
+    }
+
+    if (!IsValidBufferSize(size)) {
+        return {};
+    }
+
+    return size;
+}
+
+size_t GetBufferSizeFromProperties(log_id_t log_id) {
+    std::string buffer_name = android_log_id_to_name(log_id);
+    std::array<std::string, 4> properties = {
+            "persist.logd.size." + buffer_name,
+            "ro.logd.size." + buffer_name,
+            "persist.logd.size",
+            "ro.logd.size",
+    };
+
+    for (const auto& property : properties) {
+        if (auto size = GetBufferSizeProperty(property)) {
+            return *size;
+        }
+    }
+
+    if (android::base::GetBoolProperty("ro.config.low_ram", false)) {
+        return kLogBufferMinSize;
+    }
+
+    return kDefaultLogBufferSize;
+}
diff --git a/logd/LogSize.h b/logd/LogSize.h
new file mode 100644
index 0000000..d5716ff
--- /dev/null
+++ b/logd/LogSize.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stddef.h>
+
+#include <log/log.h>
+
+static constexpr size_t kDefaultLogBufferSize = 256 * 1024;
+static constexpr size_t kLogBufferMinSize = 64 * 1024;
+static constexpr size_t kLogBufferMaxSize = 256 * 1024 * 1024;
+
+bool IsValidBufferSize(size_t value);
+
+// This returns the buffer size as set in system properties for use in LogBuffer::Init().
+// Note that `logcat -G` calls LogBuffer::SetSize(), which configures log buffer sizes without
+// setting these properties, so this function should never be used except for LogBuffer::Init().
+// LogBuffer::GetSize() should be used instead within logd.  Other processes can use
+// android_logger_get_log_size() or `logcat -g` to query the actual allotted buffer size.
+size_t GetBufferSizeFromProperties(log_id_t log_id);
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 1705d48..87069b3 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -26,8 +26,10 @@
 #include <unistd.h>
 
 #include <list>
+#include <vector>
 
 #include <android-base/logging.h>
+#include <android-base/strings.h>
 #include <private/android_logger.h>
 
 #include "LogBufferElement.h"
@@ -61,7 +63,8 @@
     return std::string(msg, len);
 }
 
-LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size)
+LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size,
+                             std::optional<log_time> start_time)
     : enable(enable_statistics), track_total_size_(track_total_size) {
     log_time now(CLOCK_REALTIME);
     log_id_for_each(id) {
@@ -70,8 +73,13 @@
         mDroppedElements[id] = 0;
         mSizesTotal[id] = 0;
         mElementsTotal[id] = 0;
-        mOldest[id] = now;
-        mNewest[id] = now;
+        if (start_time) {
+            mOldest[id] = *start_time;
+            mNewest[id] = *start_time;
+        } else {
+            mOldest[id] = now;
+            mNewest[id] = now;
+        }
         mNewestDropped[id] = now;
     }
 }
@@ -784,6 +792,31 @@
     return output;
 }
 
+std::string LogStatistics::ReportInteresting() const {
+    auto lock = std::lock_guard{lock_};
+
+    std::vector<std::string> items;
+
+    log_id_for_each(i) { items.emplace_back(std::to_string(mElements[i])); }
+
+    log_id_for_each(i) { items.emplace_back(std::to_string(mSizes[i])); }
+
+    log_id_for_each(i) {
+        items.emplace_back(std::to_string(overhead_[i] ? *overhead_[i] : mSizes[i]));
+    }
+
+    log_id_for_each(i) {
+        uint64_t oldest = mOldest[i].msec() / 1000;
+        uint64_t newest = mNewest[i].msec() / 1000;
+
+        int span = newest - oldest;
+
+        items.emplace_back(std::to_string(span));
+    }
+
+    return android::base::Join(items, ",");
+}
+
 std::string LogStatistics::Format(uid_t uid, pid_t pid, unsigned int logMask) const {
     auto lock = std::lock_guard{lock_};
 
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index d440a8c..faf9283 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -515,7 +515,8 @@
     }
 
   public:
-    LogStatistics(bool enable_statistics, bool track_total_size);
+    LogStatistics(bool enable_statistics, bool track_total_size,
+                  std::optional<log_time> start_time = {});
 
     void AddTotal(log_id_t log_id, uint16_t size) EXCLUDES(lock_);
 
@@ -543,7 +544,7 @@
     bool ShouldPrune(log_id id, unsigned long max_size, unsigned long* prune_rows) const
             EXCLUDES(lock_);
 
-    // Snapshot of the sizes for a given log buffer.
+    // Return the consumed size of the given buffer.
     size_t Sizes(log_id_t id) const EXCLUDES(lock_) {
         auto lock = std::lock_guard{lock_};
         if (overhead_[id]) {
@@ -551,11 +552,19 @@
         }
         return mSizes[id];
     }
+
+    // Return the uncompressed size of the contents of the given buffer.
+    size_t SizeReadable(log_id_t id) const EXCLUDES(lock_) {
+        auto lock = std::lock_guard{lock_};
+        return mSizes[id];
+    }
+
     // TODO: Get rid of this entirely.
     static size_t sizesTotal() {
         return SizesTotal;
     }
 
+    std::string ReportInteresting() const EXCLUDES(lock_);
     std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_);
 
     const char* PidToName(pid_t pid) const EXCLUDES(lock_);
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
index 1b7107f..6ab3b48 100644
--- a/logd/LogTags.cpp
+++ b/logd/LogTags.cpp
@@ -24,6 +24,7 @@
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <sys/uio.h>
 #include <unistd.h>
 
 #include <string>
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index df78a50..c0f62d3 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -20,12 +20,13 @@
 #include <sys/types.h>
 
 #include <private/android_logger.h>
-#include <sysutils/SocketClient.h>
 #include <utils/FastStrcmp.h>
 
 // Hijack this header as a common include file used by most all sources
 // to report some utilities defined here and there.
 
+#define LOGD_SNDTIMEO 32
+
 namespace android {
 
 // Furnished in main.cpp. Caller must own and free returned value
diff --git a/logd/README.compression.md b/logd/README.compression.md
new file mode 100644
index 0000000..4ba634a
--- /dev/null
+++ b/logd/README.compression.md
@@ -0,0 +1,81 @@
+# Log Compression instead of Chatty in Android S
+
+## The problem
+
+* Log buffer space is precious, but suffers from the tragedy of the commons
+* Log spam fills the buffers making them less useful in logcat/bugreports
+* “Spam” is often in the eye of the beholder: which messages are important depends on what you’re trying to debug
+
+## The idea
+
+* Chatty isn’t helping as much as we’d hoped, and is surprisingly expensive
+* Compress logs to make more efficient use of the buffer
+* Address the root cause of log spam at its source:
+    * Do not hide log spam at runtime, which de-incentivize fixes
+    * Add presubmit coverage similar to SELinux violations to keep log spam down
+
+---
+
+## Chatty in Theory
+
+* Delete messages classified as spam to extend the range of logs from other sources
+* “Spam” defined as:
+    * Logs from UIDs whose logs consume over 12.5% of a log buffer
+    * Back-to-back exact duplicate messages
+
+## Chatty in Practice
+
+* Developer confusion about missing and de-duplicated logs
+* Lowered incentive to fix the root cause of bad logging behavior
+* High CPU overhead
+* Memory usage greatly exceeds configured buffer size
+* Only marginal increase in log range
+
+---
+
+## Log Compression in Theory
+
+* Store many more logs in the same log buffer size => better for diagnosis
+* Memory usage stays below configured log size => better system health
+* No gaps in logs, no de-duplicated logs => no developer confusion
+* No hiding bad behavior => increased accountability/incentive to fix root causes
+
+## Log Compression Preliminary Results
+
+* Captured 2, 5 day periods of full time personal usage of Pixel 4 and replayed the logs offline
+* Compression vs Chatty:
+    * **3.5x more log messages on average**
+    * **50% less CPU usage**
+    * **50% less memory usage**
+
+---
+
+## Log Messages in 1MB
+
+* The number of log messages still available in logcat after ‘Message Count’ messages have been logged to a 1MB log buffer
+* Note: ‘Simple’ is the Chatty code without log spam detection and without de-duplication.
+
+![Total Log Count](doc_images/total_log_count.png)
+
+---
+
+## CPU Time
+
+* Total CPU time on ARM64 (Walleye) and 32bit x86 (Cuttlefish)
+* X axis represents different log buffer size configurations.
+    * Chatty uses significantly more CPU time at 1MB (the default Pixel configuration)
+    * Chatty scales poorly with increased log buffer sizes
+* Note: “simple” isn’t “compression without actually compressing”, it’s “chatty without doing the chatty elimination”, which is why “simple” is more expensive than “compression” on walleye.
+
+![CPU Time Walleye](doc_images/cpu_walleye.png)
+![CPU Time Cuttlefish](doc_images/cpu_cuttlefish.png)
+
+---
+
+## Memory Usage
+
+* The memory used by ‘Message Count’ messages, on both Walleye and Cuttlefish
+* Note: Chatty does not consider the metadata (UID, PID, timestamp, etc) in its calculation of log buffer size, so a 1MB log buffer will consume more than 1MB.  Note that there are 8 log buffers, 5 of which are typically filled.
+
+![Memory Usage](doc_images/memory_usage.png)
+
diff --git a/logd/README.property b/logd/README.property
index 1d7d990..8fd7f48 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -7,8 +7,8 @@
 ro.logd.auditd.events      bool   true   selinux audit messages sent to events.
 persist.logd.security      bool   false  Enable security buffer.
 ro.organization_owned      bool   false  Override persist.logd.security to false
-ro.logd.kernel             bool+ svelte+ Enable klogd daemon
-ro.logd.statistics         bool+ svelte+ Enable logcat -S statistics.
+ro.logd.kernel             bool  svelte+ Enable klogd daemon
+logd.statistics            bool  svelte+ Enable logcat -S statistics.
 ro.debuggable              number        if not "1", logd.statistics &
                                          ro.logd.kernel default false.
 logd.logpersistd.enable    bool   auto   Safe to start logpersist daemon service
@@ -57,11 +57,8 @@
 
 NB:
 - auto - managed by /init
-- bool+ - "true", "false" and comma separated list of "eng" (forced false if
-  ro.debuggable is not "1") or "svelte" (forced false if ro.config.low_ram is
-  true).
 - svelte - see ro.config.low_ram for details.
-- svelte+ - see ro.config.low_ram and ro.debuggable for details.
+- svelte+ - If empty, default to true if `ro.config.low_ram == false && ro.debuggable == true`
 - ro - <base property> temporary override, ro.<base property> platform default.
 - persist - <base property> override, persist.<base property> platform default.
 - build - VERBOSE for native, DEBUG for jvm isLoggable, or developer option.
diff --git a/logd/README.replay.md b/logd/README.replay.md
new file mode 100644
index 0000000..5f7ec9e
--- /dev/null
+++ b/logd/README.replay.md
@@ -0,0 +1,46 @@
+logd can record and replay log messages for offline analysis.
+
+Recording Messages
+------------------
+
+logd has a `RecordingLogBuffer` buffer that records messages to /data/misc/logd/recorded-messages.
+It stores messages in memory until that file is accessible, in order to capture all messages since
+the beginning of boot.  It is only meant for logging developers to use and must be manually enabled
+in by adding `RecordingLogBuffer.cpp` to `Android.bp` and setting
+`log_buffer = new SimpleLogBuffer(&reader_list, &log_tags, &log_statistics);` in `main.cpp`.
+
+Recording messages may delay the Log() function from completing and it is highly recommended to make
+the logd socket in `liblog` blocking, by removing `SOCK_NONBLOCK` from the `socket()` call in
+`liblog/logd_writer.cpp`.
+
+Replaying Messages
+------------------
+
+Recorded messages can be replayed offline with the `replay_messages` tool.  It runs on host and
+device and supports the following options:
+
+1. `interesting` - this prints 'interesting' statistics for each of the log buffer types (simple,
+   chatty, serialized).  The statistics are:
+    1. Log Entry Count
+    2. Size (the uncompressed size of the log messages in bytes)
+    3. Overhead (the total cost of the log messages in memory in bytes)
+    4. Range (the range of time that the logs cover in seconds)
+2. `memory_usage BUFFER_TYPE` - this prints the memory usage (sum of private dirty pages of the
+  `replay_messages` process).  Note that the input file is mmap()'ed as RO/Shared so it does not
+  appear in these dirty pages, and a baseline is taken before allocating the log buffers, so only
+  their contributions are measured.  The tool outputs the memory usage every 100,000 messages.
+3. `latency BUFFER_TYPE` - this prints statistics of the latency of the Log() function for the given
+  buffer type.  It specifically prints the 1st, 2nd, and 3rd quartiles; the 95th, 99th, and 99.99th
+  percentiles; and the maximum latency.
+4. `print_logs BUFFER_TYPE [buffers] [print_point]` - this prints the logs as processed by the given
+  buffer_type from the buffers specified by `buffers` starting after the number of logs specified by
+  `print_point` have been logged.  This acts as if a user called `logcat` immediately after the
+  specified logs have been logged, which is particularly useful since it will show the chatty
+  pruning messages at that point.  It additionally prints the statistics from `logcat -S` after the
+  logs.
+  `buffers` is a comma separated list of the numeric buffer id values from `<android/log.h>`.  For
+  example, `0,1,3` represents the main, radio, and system buffers.  It can can also be `all`.
+  `print_point` is an positive integer.  If it is unspecified, logs are printed after the entire
+  input file is consumed.
+5. `nothing BUFFER_TYPE` - this does nothing other than read the input file and call Log() for the
+  given buffer type.  This is used for profiling CPU usage of strictly the log buffer.
diff --git a/libstats/socket/benchmark/main.cpp b/logd/RecordedLogMessage.h
similarity index 65%
copy from libstats/socket/benchmark/main.cpp
copy to logd/RecordedLogMessage.h
index 5ebdf6e..f18c422 100644
--- a/libstats/socket/benchmark/main.cpp
+++ b/logd/RecordedLogMessage.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open 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,6 +14,17 @@
  * limitations under the License.
  */
 
-#include <benchmark/benchmark.h>
+#pragma once
 
-BENCHMARK_MAIN();
+#include <inttypes.h>
+
+#include <log/log_time.h>
+
+struct __attribute__((packed)) RecordedLogMessage {
+    uint32_t uid;
+    uint32_t pid;
+    uint32_t tid;
+    log_time realtime;
+    uint16_t msg_len;
+    uint8_t log_id;
+};
diff --git a/logd/RecordingLogBuffer.cpp b/logd/RecordingLogBuffer.cpp
new file mode 100644
index 0000000..f5991f3
--- /dev/null
+++ b/logd/RecordingLogBuffer.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "RecordingLogBuffer.h"
+
+#include <android-base/file.h>
+
+static void WriteLogMessage(int fd, const RecordedLogMessage& meta, const std::string& msg) {
+    android::base::WriteFully(fd, &meta, sizeof(meta));
+    android::base::WriteFully(fd, msg.c_str(), meta.msg_len);
+}
+
+void RecordingLogBuffer::RecordLogMessage(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
+                                          pid_t tid, const char* msg, uint16_t len) {
+    auto lock = std::lock_guard{lock_};
+    if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
+        len = LOGGER_ENTRY_MAX_PAYLOAD;
+    }
+
+    RecordedLogMessage recorded_log_message = {
+            .uid = uid,
+            .pid = static_cast<uint32_t>(pid),
+            .tid = static_cast<uint32_t>(tid),
+            .realtime = realtime,
+            .msg_len = len,
+            .log_id = static_cast<uint8_t>(log_id),
+    };
+
+    if (!fd_.ok()) {
+        fd_.reset(open("/data/misc/logd/recorded-messages",
+                       O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, 0666));
+        if (!fd_.ok()) {
+            since_boot_messages_.emplace_back(recorded_log_message, std::string(msg, len));
+            return;
+        } else {
+            for (const auto& [meta, msg] : since_boot_messages_) {
+                WriteLogMessage(fd_.get(), meta, msg);
+            }
+        }
+    }
+
+    WriteLogMessage(fd_.get(), recorded_log_message, std::string(msg, len));
+}
+
+int RecordingLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
+                            const char* msg, uint16_t len) {
+    RecordLogMessage(log_id, realtime, uid, pid, tid, msg, len);
+    return SimpleLogBuffer::Log(log_id, realtime, uid, pid, tid, msg, len);
+}
\ No newline at end of file
diff --git a/logd/RecordingLogBuffer.h b/logd/RecordingLogBuffer.h
new file mode 100644
index 0000000..49a0aba
--- /dev/null
+++ b/logd/RecordingLogBuffer.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "SimpleLogBuffer.h"
+
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+
+#include "RecordedLogMessage.h"
+
+class RecordingLogBuffer : public SimpleLogBuffer {
+  public:
+    RecordingLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats)
+        : SimpleLogBuffer(reader_list, tags, stats) {}
+
+    int Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char* msg,
+            uint16_t len) override;
+
+  private:
+    void RecordLogMessage(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
+                          const char* msg, uint16_t len);
+
+    std::vector<std::pair<RecordedLogMessage, std::string>> since_boot_messages_;
+    android::base::unique_fd fd_;
+};
diff --git a/logd/ReplayMessages.cpp b/logd/ReplayMessages.cpp
new file mode 100644
index 0000000..56509ec
--- /dev/null
+++ b/logd/ReplayMessages.cpp
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <inttypes.h>
+
+#include <chrono>
+#include <map>
+
+#include <android-base/file.h>
+#include <android-base/mapped_file.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <android/log.h>
+#include <log/log_time.h>
+#include <log/logprint.h>
+
+#include "ChattyLogBuffer.h"
+#include "LogBuffer.h"
+#include "LogStatistics.h"
+#include "RecordedLogMessage.h"
+#include "SerializedLogBuffer.h"
+#include "SimpleLogBuffer.h"
+
+using android::base::MappedFile;
+using android::base::ParseInt;
+using android::base::ParseUint;
+using android::base::Split;
+
+char* android::uidToName(uid_t) {
+    return nullptr;
+}
+
+static size_t GetPrivateDirty() {
+    // Allocate once and hope that we don't need to reallocate >40000, to prevent heap fragmentation
+    static std::string smaps(40000, '\0');
+    android::base::ReadFileToString("/proc/self/smaps", &smaps);
+
+    size_t result = 0;
+    size_t base = 0;
+    size_t found;
+    while (true) {
+        found = smaps.find("Private_Dirty:", base);
+        if (found == smaps.npos) break;
+
+        found += sizeof("Private_Dirty:");
+
+        result += atoi(&smaps[found]);
+
+        base = found + 1;
+    }
+
+    return result;
+}
+
+static AndroidLogFormat* GetLogFormat() {
+    static AndroidLogFormat* format = [] {
+        auto* format = android_log_format_new();
+        android_log_setPrintFormat(format, android_log_formatFromString("threadtime"));
+        android_log_setPrintFormat(format, android_log_formatFromString("uid"));
+        return format;
+    }();
+    return format;
+}
+
+static void PrintMessage(struct log_msg* buf) {
+    bool is_binary =
+            buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
+
+    AndroidLogEntry entry;
+    int err;
+    if (is_binary) {
+        char binaryMsgBuf[1024];
+        err = android_log_processBinaryLogBuffer(&buf->entry, &entry, nullptr, binaryMsgBuf,
+                                                 sizeof(binaryMsgBuf));
+    } else {
+        err = android_log_processLogBuffer(&buf->entry, &entry);
+    }
+    if (err < 0) {
+        fprintf(stderr, "Error parsing log message\n");
+    }
+
+    android_log_printLogLine(GetLogFormat(), STDOUT_FILENO, &entry);
+}
+
+static log_time GetFirstTimeStamp(const MappedFile& recorded_messages) {
+    if (sizeof(RecordedLogMessage) >= recorded_messages.size()) {
+        fprintf(stderr, "At least one log message must be present in the input\n");
+        exit(1);
+    }
+
+    auto* meta = reinterpret_cast<RecordedLogMessage*>(recorded_messages.data());
+    return meta->realtime;
+}
+
+static LogMask BuffersToLogMask(const char* buffers) {
+    if (buffers == nullptr || !strcmp(buffers, "all")) {
+        return kLogMaskAll;
+    }
+    auto string_ids = Split(buffers, ",");
+    LogMask log_mask = 0;
+    for (const auto& string_id : string_ids) {
+        int buffer_id;
+        if (!ParseInt(string_id, &buffer_id, 0, 7)) {
+            fprintf(stderr, "Could not parse buffer_id '%s'\n", string_id.c_str());
+            exit(1);
+        }
+        log_mask |= 1 << buffer_id;
+    }
+    return log_mask;
+}
+
+class StdoutWriter : public LogWriter {
+  public:
+    StdoutWriter() : LogWriter(0, true) {}
+    bool Write(const logger_entry& entry, const char* message) override {
+        struct log_msg log_msg;
+        log_msg.entry = entry;
+        if (log_msg.entry.len > LOGGER_ENTRY_MAX_PAYLOAD) {
+            fprintf(stderr, "payload too large %" PRIu16, log_msg.entry.len);
+            exit(1);
+        }
+        memcpy(log_msg.msg(), message, log_msg.entry.len);
+
+        PrintMessage(&log_msg);
+
+        return true;
+    }
+
+    void Shutdown() override {
+        fprintf(stderr, "LogWriter::Shutdown() called\n");
+        exit(1);
+    }
+
+    std::string name() const override { return "stdout writer"; }
+};
+
+class Operation {
+  public:
+    virtual ~Operation() {}
+
+    virtual void Begin() {}
+    virtual void Log(const RecordedLogMessage& meta, const char* msg) = 0;
+    virtual void End() {}
+};
+
+class PrintInteresting : public Operation {
+  public:
+    PrintInteresting(log_time first_log_timestamp)
+        : stats_simple_{false, false, first_log_timestamp},
+          stats_chatty_{false, false, first_log_timestamp},
+          stats_serialized_{false, true, first_log_timestamp} {}
+
+    void Begin() override {
+        printf("message_count,simple_main_lines,simple_radio_lines,simple_events_lines,simple_"
+               "system_lines,simple_crash_lines,simple_stats_lines,simple_security_lines,simple_"
+               "kernel_lines,simple_main_size,simple_radio_size,simple_events_size,simple_system_"
+               "size,simple_crash_size,simple_stats_size,simple_security_size,simple_kernel_size,"
+               "simple_main_overhead,simple_radio_overhead,simple_events_overhead,simple_system_"
+               "overhead,simple_crash_overhead,simple_stats_overhead,simple_security_overhead,"
+               "simple_kernel_overhead,simple_main_range,simple_radio_range,simple_events_range,"
+               "simple_system_range,simple_crash_range,simple_stats_range,simple_security_range,"
+               "simple_kernel_range,chatty_main_lines,chatty_radio_lines,chatty_events_lines,"
+               "chatty_system_lines,chatty_crash_lines,chatty_stats_lines,chatty_security_lines,"
+               "chatty_"
+               "kernel_lines,chatty_main_size,chatty_radio_size,chatty_events_size,chatty_system_"
+               "size,chatty_crash_size,chatty_stats_size,chatty_security_size,chatty_kernel_size,"
+               "chatty_main_overhead,chatty_radio_overhead,chatty_events_overhead,chatty_system_"
+               "overhead,chatty_crash_overhead,chatty_stats_overhead,chatty_security_overhead,"
+               "chatty_kernel_overhead,chatty_main_range,chatty_radio_range,chatty_events_range,"
+               "chatty_system_range,chatty_crash_range,chatty_stats_range,chatty_security_range,"
+               "chatty_kernel_range,serialized_main_lines,serialized_radio_lines,serialized_events_"
+               "lines,serialized_"
+               "system_lines,serialized_crash_lines,serialized_stats_lines,serialized_security_"
+               "lines,serialized_"
+               "kernel_lines,serialized_main_size,serialized_radio_size,serialized_events_size,"
+               "serialized_system_"
+               "size,serialized_crash_size,serialized_stats_size,serialized_security_size,"
+               "serialized_kernel_size,"
+               "serialized_main_overhead,serialized_radio_overhead,serialized_events_overhead,"
+               "serialized_system_"
+               "overhead,serialized_crash_overhead,serialized_stats_overhead,serialized_security_"
+               "overhead,"
+               "serialized_kernel_overhead,serialized_main_range,serialized_radio_range,serialized_"
+               "events_range,"
+               "serialized_system_range,serialized_crash_range,serialized_stats_range,serialized_"
+               "security_range,"
+               "serialized_kernel_range\n");
+    }
+
+    void Log(const RecordedLogMessage& meta, const char* msg) override {
+        simple_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid,
+                               meta.pid, meta.tid, msg, meta.msg_len);
+
+        chatty_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid,
+                               meta.pid, meta.tid, msg, meta.msg_len);
+
+        serialized_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid,
+                                   meta.pid, meta.tid, msg, meta.msg_len);
+
+        if (num_message_ % 10000 == 0) {
+            printf("%" PRIu64 ",%s,%s,%s\n", num_message_,
+                   stats_simple_.ReportInteresting().c_str(),
+                   stats_chatty_.ReportInteresting().c_str(),
+                   stats_serialized_.ReportInteresting().c_str());
+        }
+
+        num_message_++;
+    }
+
+  private:
+    uint64_t num_message_ = 1;
+
+    LogReaderList reader_list_;
+    LogTags tags_;
+    PruneList prune_list_;
+
+    LogStatistics stats_simple_;
+    SimpleLogBuffer simple_log_buffer_{&reader_list_, &tags_, &stats_simple_};
+
+    LogStatistics stats_chatty_;
+    ChattyLogBuffer chatty_log_buffer_{&reader_list_, &tags_, &prune_list_, &stats_chatty_};
+
+    LogStatistics stats_serialized_;
+    SerializedLogBuffer serialized_log_buffer_{&reader_list_, &tags_, &stats_serialized_};
+};
+
+class SingleBufferOperation : public Operation {
+  public:
+    SingleBufferOperation(log_time first_log_timestamp, const char* buffer) {
+        if (!strcmp(buffer, "simple")) {
+            stats_.reset(new LogStatistics{false, false, first_log_timestamp});
+            log_buffer_.reset(new SimpleLogBuffer(&reader_list_, &tags_, stats_.get()));
+        } else if (!strcmp(buffer, "chatty")) {
+            stats_.reset(new LogStatistics{false, false, first_log_timestamp});
+            log_buffer_.reset(
+                    new ChattyLogBuffer(&reader_list_, &tags_, &prune_list_, stats_.get()));
+        } else if (!strcmp(buffer, "serialized")) {
+            stats_.reset(new LogStatistics{false, true, first_log_timestamp});
+            log_buffer_.reset(new SerializedLogBuffer(&reader_list_, &tags_, stats_.get()));
+        } else {
+            fprintf(stderr, "invalid log buffer type '%s'\n", buffer);
+            abort();
+        }
+    }
+
+    void Log(const RecordedLogMessage& meta, const char* msg) override {
+        PreOperation();
+        log_buffer_->Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid, meta.pid,
+                         meta.tid, msg, meta.msg_len);
+
+        Operation();
+
+        num_message_++;
+    }
+
+    virtual void PreOperation() {}
+    virtual void Operation() {}
+
+  protected:
+    uint64_t num_message_ = 1;
+
+    LogReaderList reader_list_;
+    LogTags tags_;
+    PruneList prune_list_;
+
+    std::unique_ptr<LogStatistics> stats_;
+    std::unique_ptr<LogBuffer> log_buffer_;
+};
+
+class PrintMemory : public SingleBufferOperation {
+  public:
+    PrintMemory(log_time first_log_timestamp, const char* buffer)
+        : SingleBufferOperation(first_log_timestamp, buffer) {}
+
+    void Operation() override {
+        if (num_message_ % 100000 == 0) {
+            printf("%" PRIu64 ",%s\n", num_message_,
+                   std::to_string(GetPrivateDirty() - baseline_memory_).c_str());
+        }
+    }
+
+  private:
+    size_t baseline_memory_ = GetPrivateDirty();
+};
+
+class PrintLogs : public SingleBufferOperation {
+  public:
+    PrintLogs(log_time first_log_timestamp, const char* buffer, const char* buffers,
+              const char* print_point)
+        : SingleBufferOperation(first_log_timestamp, buffer) {
+        mask_ = BuffersToLogMask(buffers);
+        if (print_point != nullptr) {
+            uint64_t result = 0;
+            if (!ParseUint(print_point, &result)) {
+                fprintf(stderr, "Could not parse print point '%s'\n", print_point);
+                exit(1);
+            }
+            print_point_ = result;
+        }
+    }
+
+    void Operation() override {
+        if (print_point_ && num_message_ >= *print_point_) {
+            End();
+            exit(0);
+        }
+    }
+
+    void End() override {
+        std::unique_ptr<LogWriter> test_writer(new StdoutWriter());
+        std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, mask_);
+        log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr);
+
+        auto stats_string = stats_->Format(0, 0, mask_);
+        printf("%s\n", stats_string.c_str());
+    }
+
+  private:
+    LogMask mask_ = kLogMaskAll;
+    std::optional<uint64_t> print_point_;
+};
+
+class PrintLatency : public SingleBufferOperation {
+  public:
+    PrintLatency(log_time first_log_timestamp, const char* buffer)
+        : SingleBufferOperation(first_log_timestamp, buffer) {}
+
+    void PreOperation() override { operation_start_ = std::chrono::steady_clock::now(); }
+
+    void Operation() override {
+        auto end = std::chrono::steady_clock::now();
+        auto duration = (end - operation_start_).count();
+        durations_.emplace_back(duration);
+    }
+
+    void End() override {
+        std::sort(durations_.begin(), durations_.end());
+        auto q1 = durations_.size() / 4;
+        auto q2 = durations_.size() / 2;
+        auto q3 = 3 * durations_.size() / 4;
+
+        auto p95 = 95 * durations_.size() / 100;
+        auto p99 = 99 * durations_.size() / 100;
+        auto p9999 = 9999 * durations_.size() / 10000;
+
+        printf("q1: %lld q2: %lld q3: %lld  p95: %lld p99: %lld p99.99: %lld  max: %lld\n",
+               durations_[q1], durations_[q2], durations_[q3], durations_[p95], durations_[p99],
+               durations_[p9999], durations_.back());
+    }
+
+  private:
+    std::chrono::steady_clock::time_point operation_start_;
+    std::vector<long long> durations_;
+};
+
+class PrintAllLogs : public SingleBufferOperation {
+  public:
+    PrintAllLogs(log_time first_log_timestamp, const char* buffer, const char* buffers)
+        : SingleBufferOperation(first_log_timestamp, buffer) {
+        LogMask mask = BuffersToLogMask(buffers);
+        auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
+        std::unique_ptr<LogWriter> stdout_writer(new StdoutWriter());
+        std::unique_ptr<LogReaderThread> log_reader(
+                new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(stdout_writer),
+                                    false, 0, mask, 0, {}, 1, {}));
+        reader_list_.reader_threads().emplace_back(std::move(log_reader));
+    }
+
+    void Operation() override {
+        // If the rate of reading logs is slower than the rate of incoming logs, then the reader
+        // thread is disconnected to not overflow log buffers, therefore we artificially slow down
+        // the incoming log rate.
+        usleep(100);
+    }
+};
+
+int main(int argc, char** argv) {
+    if (argc < 3) {
+        fprintf(stderr, "Usage: %s FILE OPERATION [BUFFER] [OPTIONS]\n", argv[0]);
+        return 1;
+    }
+
+    if (strcmp(argv[2], "interesting") != 0 && argc < 4) {
+        fprintf(stderr, "Operations other than 'interesting' require a BUFFER argument\n");
+        return 1;
+    }
+
+    int recorded_messages_fd = open(argv[1], O_RDONLY);
+    if (recorded_messages_fd == -1) {
+        fprintf(stderr, "Couldn't open input file\n");
+        return 1;
+    }
+    struct stat fd_stat;
+    if (fstat(recorded_messages_fd, &fd_stat) != 0) {
+        fprintf(stderr, "Couldn't fstat input file\n");
+        return 1;
+    }
+    auto recorded_messages = MappedFile::FromFd(recorded_messages_fd, 0,
+                                                static_cast<size_t>(fd_stat.st_size), PROT_READ);
+    if (recorded_messages == nullptr) {
+        fprintf(stderr, "Couldn't mmap input file\n");
+        return 1;
+    }
+
+    // LogStatistics typically uses 'now()' to initialize its log range state, but this doesn't work
+    // when replaying older logs, so we instead give it the timestamp from the first log.
+    log_time first_log_timestamp = GetFirstTimeStamp(*recorded_messages);
+
+    std::unique_ptr<Operation> operation;
+    if (!strcmp(argv[2], "interesting")) {
+        operation.reset(new PrintInteresting(first_log_timestamp));
+    } else if (!strcmp(argv[2], "memory_usage")) {
+        operation.reset(new PrintMemory(first_log_timestamp, argv[3]));
+    } else if (!strcmp(argv[2], "latency")) {
+        operation.reset(new PrintLatency(first_log_timestamp, argv[3]));
+    } else if (!strcmp(argv[2], "print_logs")) {
+        operation.reset(new PrintLogs(first_log_timestamp, argv[3], argc > 4 ? argv[4] : nullptr,
+                                      argc > 5 ? argv[5] : nullptr));
+    } else if (!strcmp(argv[2], "print_all_logs")) {
+        operation.reset(
+                new PrintAllLogs(first_log_timestamp, argv[3], argc > 4 ? argv[4] : nullptr));
+    } else if (!strcmp(argv[2], "nothing")) {
+        operation.reset(new SingleBufferOperation(first_log_timestamp, argv[3]));
+    } else {
+        fprintf(stderr, "unknown operation '%s'\n", argv[2]);
+        return 1;
+    }
+
+    // LogBuffer::Log() won't log without this on host.
+    __android_log_set_minimum_priority(ANDROID_LOG_VERBOSE);
+    // But we still want to suppress messages <= error to not interrupt the rest of the output.
+    __android_log_set_logger([](const struct __android_log_message* log_message) {
+        if (log_message->priority < ANDROID_LOG_ERROR) {
+            return;
+        }
+        __android_log_stderr_logger(log_message);
+    });
+
+    operation->Begin();
+
+    uint64_t read_position = 0;
+    while (read_position + sizeof(RecordedLogMessage) < recorded_messages->size()) {
+        auto* meta =
+                reinterpret_cast<RecordedLogMessage*>(recorded_messages->data() + read_position);
+        if (read_position + sizeof(RecordedLogMessage) + meta->msg_len >=
+            recorded_messages->size()) {
+            break;
+        }
+        char* msg = recorded_messages->data() + read_position + sizeof(RecordedLogMessage);
+        read_position += sizeof(RecordedLogMessage) + meta->msg_len;
+
+        operation->Log(*meta, msg);
+    }
+
+    operation->End();
+
+    return 0;
+}
diff --git a/logd/SerializedFlushToState.cpp b/logd/SerializedFlushToState.cpp
index 2633348..fdf1dd3 100644
--- a/logd/SerializedFlushToState.cpp
+++ b/logd/SerializedFlushToState.cpp
@@ -16,6 +16,8 @@
 
 #include "SerializedFlushToState.h"
 
+#include <limits>
+
 #include <android-base/logging.h>
 
 SerializedFlushToState::SerializedFlushToState(uint64_t start, LogMask log_mask)
@@ -31,7 +33,7 @@
 SerializedFlushToState::~SerializedFlushToState() {
     log_id_for_each(i) {
         if (log_positions_[i]) {
-            log_positions_[i]->buffer_it->DecReaderRefCount(true);
+            log_positions_[i]->buffer_it->DecReaderRefCount();
         }
     }
 }
@@ -63,14 +65,13 @@
     log_positions_[log_id].emplace(log_position);
 }
 
-void SerializedFlushToState::AddMinHeapEntry(log_id_t log_id) {
+void SerializedFlushToState::UpdateLogsNeeded(log_id_t log_id) {
     auto& buffer_it = log_positions_[log_id]->buffer_it;
     auto read_offset = log_positions_[log_id]->read_offset;
 
-    // If there is another log to read in this buffer, add it to the min heap.
+    // If there is another log to read in this buffer, let it be read.
     if (read_offset < buffer_it->write_offset()) {
-        auto* entry = buffer_it->log_entry(read_offset);
-        min_heap_.emplace(log_id, entry);
+        logs_needed_from_next_position_[log_id] = false;
     } else if (read_offset == buffer_it->write_offset()) {
         // If there are no more logs to read in this buffer and it's the last buffer, then
         // set logs_needed_from_next_position_ to wait until more logs get logged.
@@ -78,20 +79,20 @@
             logs_needed_from_next_position_[log_id] = true;
         } else {
             // Otherwise, if there is another buffer piece, move to that and do the same check.
-            buffer_it->DecReaderRefCount(true);
+            buffer_it->DecReaderRefCount();
             ++buffer_it;
             buffer_it->IncReaderRefCount();
             log_positions_[log_id]->read_offset = 0;
             if (buffer_it->write_offset() == 0) {
                 logs_needed_from_next_position_[log_id] = true;
             } else {
-                auto* entry = buffer_it->log_entry(0);
-                min_heap_.emplace(log_id, entry);
+                logs_needed_from_next_position_[log_id] = false;
             }
         }
     } else {
         // read_offset > buffer_it->write_offset() should never happen.
-        CHECK(false);
+        LOG(FATAL) << "read_offset (" << read_offset << ") > buffer_it->write_offset() ("
+                   << buffer_it->write_offset() << ")";
     }
 }
 
@@ -106,24 +107,41 @@
             }
             CreateLogPosition(i);
         }
-        logs_needed_from_next_position_[i] = false;
-        // If it wasn't possible to insert, logs_needed_from_next_position will be set back to true.
-        AddMinHeapEntry(i);
+        UpdateLogsNeeded(i);
     }
 }
 
-MinHeapElement SerializedFlushToState::PopNextUnreadLog() {
-    auto top = min_heap_.top();
-    min_heap_.pop();
+bool SerializedFlushToState::HasUnreadLogs() {
+    CheckForNewLogs();
+    log_id_for_each(i) {
+        if (log_positions_[i] && !logs_needed_from_next_position_[i]) {
+            return true;
+        }
+    }
+    return false;
+}
 
-    auto* entry = top.entry;
-    auto log_id = top.log_id;
+LogWithId SerializedFlushToState::PopNextUnreadLog() {
+    uint64_t min_sequence = std::numeric_limits<uint64_t>::max();
+    log_id_t log_id;
+    const SerializedLogEntry* entry = nullptr;
+    log_id_for_each(i) {
+        if (!log_positions_[i] || logs_needed_from_next_position_[i]) {
+            continue;
+        }
+        if (log_positions_[i]->log_entry()->sequence() < min_sequence) {
+            log_id = i;
+            entry = log_positions_[i]->log_entry();
+            min_sequence = entry->sequence();
+        }
+    }
+    CHECK_NE(nullptr, entry);
 
     log_positions_[log_id]->read_offset += entry->total_len();
 
     logs_needed_from_next_position_[log_id] = true;
 
-    return top;
+    return {log_id, entry};
 }
 
 void SerializedFlushToState::Prune(log_id_t log_id,
@@ -133,25 +151,12 @@
         return;
     }
 
-    // // Decrease the ref count since we're deleting our reference.
-    buffer_it->DecReaderRefCount(false);
+    // Decrease the ref count since we're deleting our reference.
+    buffer_it->DecReaderRefCount();
 
     // Delete in the reference.
     log_positions_[log_id].reset();
 
-    // Remove the MinHeapElement referencing log_id, if it exists, but retain the others.
-    std::vector<MinHeapElement> old_elements;
-    while (!min_heap_.empty()) {
-        auto& element = min_heap_.top();
-        if (element.log_id != log_id) {
-            old_elements.emplace_back(element);
-        }
-        min_heap_.pop();
-    }
-    for (auto&& element : old_elements) {
-        min_heap_.emplace(element);
-    }
-
     // Finally set logs_needed_from_next_position_, so CheckForNewLogs() will re-create the
     // log_position_ object during the next read.
     logs_needed_from_next_position_[log_id] = true;
diff --git a/logd/SerializedFlushToState.h b/logd/SerializedFlushToState.h
index 0b20822..c953a16 100644
--- a/logd/SerializedFlushToState.h
+++ b/logd/SerializedFlushToState.h
@@ -27,26 +27,19 @@
 struct LogPosition {
     std::list<SerializedLogChunk>::iterator buffer_it;
     int read_offset;
+
+    const SerializedLogEntry* log_entry() const { return buffer_it->log_entry(read_offset); }
 };
 
-struct MinHeapElement {
-    MinHeapElement(log_id_t log_id, const SerializedLogEntry* entry)
-        : log_id(log_id), entry(entry) {}
+struct LogWithId {
     log_id_t log_id;
     const SerializedLogEntry* entry;
-    // The change of comparison operators is intentional, std::priority_queue uses operator<() to
-    // compare but creates a max heap.  Since we want a min heap, we return the opposite result.
-    bool operator<(const MinHeapElement& rhs) const {
-        return entry->sequence() > rhs.entry->sequence();
-    }
 };
 
 // This class tracks the specific point where a FlushTo client has read through the logs.  It
 // directly references the std::list<> iterators from the parent SerializedLogBuffer and the offset
 // into each log chunk where it has last read.  All interactions with this class, except for its
-// construction, must be done with SerializedLogBuffer::lock_ held.  No log chunks that it
-// references may be pruned, which is handled by ensuring prune does not touch any log chunk with
-// highest sequence number greater or equal to start().
+// construction, must be done with SerializedLogBuffer::lock_ held.
 class SerializedFlushToState : public FlushToState {
   public:
     // Initializes this state object.  For each log buffer set in log_mask, this sets
@@ -61,31 +54,29 @@
         if (logs_ == nullptr) logs_ = logs;
     }
 
-    bool HasUnreadLogs() {
-        CheckForNewLogs();
-        return !min_heap_.empty();
-    }
+    // Updates the state of log_positions_ and logs_needed_from_next_position_ then returns true if
+    // there are any unread logs, false otherwise.
+    bool HasUnreadLogs();
 
-    // Pops the next unread log from the min heap and sets logs_needed_from_next_position_ to
-    // indicate that we're waiting for more logs from the associated log buffer.
-    MinHeapElement PopNextUnreadLog();
+    // Returns the next unread log and sets logs_needed_from_next_position_ to indicate that we're
+    // waiting for more logs from the associated log buffer.
+    LogWithId PopNextUnreadLog();
 
     // If the parent log buffer prunes logs, the reference that this class contains may become
     // invalid, so this must be called first to drop the reference to buffer_it, if any.
     void Prune(log_id_t log_id, const std::list<SerializedLogChunk>::iterator& buffer_it);
 
   private:
-    // If there is a log in the serialized log buffer for `log_id` at the read_offset, add it to the
-    // min heap for reading, otherwise set logs_needed_from_next_position_ to indicate that we're
-    // waiting for the next log.
-    void AddMinHeapEntry(log_id_t log_id);
+    // Set logs_needed_from_next_position_[i] to indicate if log_positions_[i] points to an unread
+    // log or to the point at which the next log will appear.
+    void UpdateLogsNeeded(log_id_t log_id);
 
     // Create a LogPosition object for the given log_id by searching through the log chunks for the
     // first chunk and then first log entry within that chunk that is greater or equal to start().
     void CreateLogPosition(log_id_t log_id);
 
     // Checks to see if any log buffers set in logs_needed_from_next_position_ have new logs and
-    // calls AddMinHeapEntry() if so.
+    // calls UpdateLogsNeeded() if so.
     void CheckForNewLogs();
 
     std::list<SerializedLogChunk>* logs_ = nullptr;
@@ -97,7 +88,4 @@
     // next_log_position == logs_write_position_)`.  These will be re-checked in each
     // loop in case new logs came in.
     std::bitset<LOG_ID_MAX> logs_needed_from_next_position_ = {};
-    // A min heap that has up to one entry per log buffer, sorted by sequence number, of the next
-    // element that this reader should read.
-    std::priority_queue<MinHeapElement> min_heap_;
 };
diff --git a/logd/SerializedFlushToStateTest.cpp b/logd/SerializedFlushToStateTest.cpp
index f4515c8..88f4052 100644
--- a/logd/SerializedFlushToStateTest.cpp
+++ b/logd/SerializedFlushToStateTest.cpp
@@ -287,4 +287,21 @@
     EXPECT_EQ(second_chunk->reader_ref_count(), 1U);
 
     EXPECT_FALSE(state.HasUnreadLogs());
-}
\ No newline at end of file
+}
+
+TEST(SerializedFlushToState, Prune) {
+    auto chunk = SerializedLogChunk{kChunkSize};
+    chunk.Log(1, log_time(), 0, 1, 1, "abc", 3);
+    chunk.Log(2, log_time(), 0, 1, 1, "abc", 3);
+    chunk.Log(3, log_time(), 0, 1, 1, "abc", 3);
+    chunk.FinishWriting();
+
+    std::list<SerializedLogChunk> log_chunks[LOG_ID_MAX];
+    log_chunks[LOG_ID_MAIN].emplace_back(std::move(chunk));
+
+    auto state = SerializedFlushToState{1, kLogMaskAll};
+    state.InitializeLogs(log_chunks);
+    ASSERT_TRUE(state.HasUnreadLogs());
+
+    state.Prune(LOG_ID_MAIN, log_chunks[LOG_ID_MAIN].begin());
+}
diff --git a/logd/SerializedLogBuffer.cpp b/logd/SerializedLogBuffer.cpp
index a626d30..fa90878 100644
--- a/logd/SerializedLogBuffer.cpp
+++ b/logd/SerializedLogBuffer.cpp
@@ -23,6 +23,7 @@
 #include <android-base/logging.h>
 #include <android-base/scopeguard.h>
 
+#include "LogSize.h"
 #include "LogStatistics.h"
 #include "SerializedFlushToState.h"
 
@@ -34,8 +35,8 @@
 
 void SerializedLogBuffer::Init() {
     log_id_for_each(i) {
-        if (SetSize(i, __android_logger_get_buffer_size(i))) {
-            SetSize(i, LOG_BUFFER_MIN_SIZE);
+        if (!SetSize(i, GetBufferSizeFromProperties(i))) {
+            SetSize(i, kLogBufferMinSize);
         }
     }
 
@@ -74,6 +75,10 @@
         return -EINVAL;
     }
 
+    if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
+        len = LOGGER_ENTRY_MAX_PAYLOAD;
+    }
+
     if (!ShouldLog(log_id, msg, len)) {
         stats_->AddTotal(log_id, len);
         return -EACCES;
@@ -108,8 +113,8 @@
     if (total_size > max_size_[log_id]) {
         Prune(log_id, total_size - max_size_[log_id], 0);
         after_size = GetSizeUsed(log_id);
-        LOG(INFO) << "Pruned Logs from log_id: " << log_id << ", previous size: " << total_size
-                  << " after size: " << after_size;
+        LOG(VERBOSE) << "Pruned Logs from log_id: " << log_id << ", previous size: " << total_size
+                     << " after size: " << after_size;
     }
 
     stats_->set_overhead(log_id, after_size);
@@ -123,7 +128,7 @@
         stats_->Subtract(entry->ToLogStatisticsElement(log_id));
         read_offset += entry->total_len();
     }
-    chunk.DecReaderRefCount(false);
+    chunk.DecReaderRefCount();
 }
 
 void SerializedLogBuffer::NotifyReadersOfPrune(
@@ -134,33 +139,42 @@
     }
 }
 
-bool SerializedLogBuffer::Prune(log_id_t log_id, size_t bytes_to_free, uid_t uid) {
-    // Don't prune logs that are newer than the point at which any reader threads are reading from.
-    LogReaderThread* oldest = nullptr;
+void SerializedLogBuffer::Prune(log_id_t log_id, size_t bytes_to_free, uid_t uid) {
     auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
-    for (const auto& reader_thread : reader_list_->reader_threads()) {
-        if (!reader_thread->IsWatching(log_id)) {
-            continue;
-        }
-        if (!oldest || oldest->start() > reader_thread->start() ||
-            (oldest->start() == reader_thread->start() &&
-             reader_thread->deadline().time_since_epoch().count() != 0)) {
-            oldest = reader_thread.get();
-        }
-    }
 
     auto& log_buffer = logs_[log_id];
     auto it = log_buffer.begin();
     while (it != log_buffer.end()) {
-        if (oldest != nullptr && it->highest_sequence_number() >= oldest->start()) {
-            break;
+        for (const auto& reader_thread : reader_list_->reader_threads()) {
+            if (!reader_thread->IsWatching(log_id)) {
+                continue;
+            }
+
+            if (reader_thread->deadline().time_since_epoch().count() != 0) {
+                // Always wake up wrapped readers when pruning.  'Wrapped' readers are an
+                // optimization that allows the reader to wait until logs starting at a specified
+                // time stamp are about to be pruned.  This is error-prone however, since if that
+                // timestamp is about to be pruned, the reader is not likely to read the messages
+                // fast enough to not back-up logd.  Instead, we can achieve an nearly-as-efficient
+                // but not error-prune batching effect by waking the reader whenever any chunk is
+                // about to be pruned.
+                reader_thread->triggerReader_Locked();
+            }
+
+            // Some readers may be still reading from this log chunk, log a warning that they are
+            // about to lose logs.
+            // TODO: We should forcefully disconnect the reader instead, such that the reader itself
+            // has an indication that they've lost logs.
+            if (reader_thread->start() <= it->highest_sequence_number()) {
+                LOG(WARNING) << "Skipping entries from slow reader, " << reader_thread->name()
+                             << ", from LogBuffer::Prune()";
+            }
         }
 
         // Increment ahead of time since we're going to erase this iterator from the list.
         auto it_to_prune = it++;
 
-        // The sequence number check ensures that all readers have read all logs in this chunk, but
-        // they may still hold a reference to the chunk to track their last read log_position.
+        // Readers may have a reference to the chunk to track their last read log_position.
         // Notify them to delete the reference.
         NotifyReadersOfPrune(log_id, it_to_prune);
 
@@ -175,42 +189,11 @@
             RemoveChunkFromStats(log_id, *it_to_prune);
             log_buffer.erase(it_to_prune);
             if (buffer_size >= bytes_to_free) {
-                return true;
+                return;
             }
             bytes_to_free -= buffer_size;
         }
     }
-
-    // If we've deleted all buffers without bytes_to_free hitting 0, then we're called by Clear()
-    // and should return true.
-    if (it == log_buffer.end()) {
-        return true;
-    }
-
-    // Otherwise we are stuck due to a reader, so mitigate it.
-    CHECK(oldest != nullptr);
-    KickReader(oldest, log_id, bytes_to_free);
-    return false;
-}
-
-// If the selected reader is blocking our pruning progress, decide on
-// what kind of mitigation is necessary to unblock the situation.
-void SerializedLogBuffer::KickReader(LogReaderThread* reader, log_id_t id, size_t bytes_to_free) {
-    if (bytes_to_free >= max_size_[id]) {  // +100%
-        // A misbehaving or slow reader is dropped if we hit too much memory pressure.
-        LOG(WARNING) << "Kicking blocked reader, " << reader->name()
-                     << ", from LogBuffer::kickMe()";
-        reader->release_Locked();
-    } else if (reader->deadline().time_since_epoch().count() != 0) {
-        // Allow a blocked WRAP deadline reader to trigger and start reporting the log data.
-        reader->triggerReader_Locked();
-    } else {
-        // Tell slow reader to skip entries to catch up.
-        unsigned long prune_rows = bytes_to_free / 300;
-        LOG(WARNING) << "Skipping " << prune_rows << " entries from slow reader, " << reader->name()
-                     << ", from LogBuffer::kickMe()";
-        reader->triggerSkip_Locked(id, prune_rows);
-    }
 }
 
 std::unique_ptr<FlushToState> SerializedLogBuffer::CreateFlushToState(uint64_t start,
@@ -228,7 +211,7 @@
     state.InitializeLogs(logs_);
 
     while (state.HasUnreadLogs()) {
-        MinHeapElement top = state.PopNextUnreadLog();
+        LogWithId top = state.PopNextUnreadLog();
         auto* entry = top.entry;
         auto log_id = top.log_id;
 
@@ -251,12 +234,18 @@
             }
         }
 
+        // We copy the log entry such that we can flush it without the lock.  We never block pruning
+        // waiting for this Flush() to complete.
+        constexpr size_t kMaxEntrySize = sizeof(*entry) + LOGGER_ENTRY_MAX_PAYLOAD + 1;
+        unsigned char entry_copy[kMaxEntrySize] __attribute__((uninitialized));
+        CHECK_LT(entry->msg_len(), LOGGER_ENTRY_MAX_PAYLOAD + 1);
+        memcpy(entry_copy, entry, sizeof(*entry) + entry->msg_len());
         lock.unlock();
-        // We never prune logs equal to or newer than any LogReaderThreads' `start` value, so the
-        // `entry` pointer is safe here without the lock
-        if (!entry->Flush(writer, log_id)) {
+
+        if (!reinterpret_cast<SerializedLogEntry*>(entry_copy)->Flush(writer, log_id)) {
             return false;
         }
+
         lock.lock();
     }
 
@@ -265,41 +254,14 @@
 }
 
 bool SerializedLogBuffer::Clear(log_id_t id, uid_t uid) {
-    // Try three times to clear, then disconnect the readers and try one final time.
-    for (int retry = 0; retry < 3; ++retry) {
-        {
-            auto lock = std::lock_guard{lock_};
-            bool prune_success = Prune(id, ULONG_MAX, uid);
-            if (prune_success) {
-                return true;
-            }
-        }
-        sleep(1);
-    }
-    // Check if it is still busy after the sleep, we try to prune one entry, not another clear run,
-    // so we are looking for the quick side effect of the return value to tell us if we have a
-    // _blocked_ reader.
-    bool busy = false;
-    {
-        auto lock = std::lock_guard{lock_};
-        busy = !Prune(id, 1, uid);
-    }
-    // It is still busy, disconnect all readers.
-    if (busy) {
-        auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
-        for (const auto& reader_thread : reader_list_->reader_threads()) {
-            if (reader_thread->IsWatching(id)) {
-                LOG(WARNING) << "Kicking blocked reader, " << reader_thread->name()
-                             << ", from LogBuffer::clear()";
-                reader_thread->release_Locked();
-            }
-        }
-    }
     auto lock = std::lock_guard{lock_};
-    return Prune(id, ULONG_MAX, uid);
+    Prune(id, ULONG_MAX, uid);
+
+    // Clearing SerializedLogBuffer never waits for readers and therefore is always successful.
+    return true;
 }
 
-unsigned long SerializedLogBuffer::GetSizeUsed(log_id_t id) {
+size_t SerializedLogBuffer::GetSizeUsed(log_id_t id) {
     size_t total_size = 0;
     for (const auto& chunk : logs_[id]) {
         total_size += chunk.PruneSize();
@@ -307,7 +269,7 @@
     return total_size;
 }
 
-unsigned long SerializedLogBuffer::GetSize(log_id_t id) {
+size_t SerializedLogBuffer::GetSize(log_id_t id) {
     auto lock = std::lock_guard{lock_};
     return max_size_[id];
 }
@@ -315,10 +277,10 @@
 // New SerializedLogChunk objects will be allocated according to the new size, but older one are
 // unchanged.  MaybePrune() is called on the log buffer to reduce it to an appropriate size if the
 // new size is lower.
-int SerializedLogBuffer::SetSize(log_id_t id, unsigned long size) {
+bool SerializedLogBuffer::SetSize(log_id_t id, size_t size) {
     // Reasonable limits ...
-    if (!__android_logger_valid_buffer_size(size)) {
-        return -1;
+    if (!IsValidBufferSize(size)) {
+        return false;
     }
 
     auto lock = std::lock_guard{lock_};
@@ -326,5 +288,5 @@
 
     MaybePrune(id);
 
-    return 0;
+    return true;
 }
diff --git a/logd/SerializedLogBuffer.h b/logd/SerializedLogBuffer.h
index a03050e..294cfe6 100644
--- a/logd/SerializedLogBuffer.h
+++ b/logd/SerializedLogBuffer.h
@@ -47,27 +47,25 @@
                                                   log_time realtime)>& filter) override;
 
     bool Clear(log_id_t id, uid_t uid) override;
-    unsigned long GetSize(log_id_t id) override;
-    int SetSize(log_id_t id, unsigned long size) override;
+    size_t GetSize(log_id_t id) override;
+    bool SetSize(log_id_t id, size_t size) override;
 
     uint64_t sequence() const override { return sequence_.load(std::memory_order_relaxed); }
 
   private:
     bool ShouldLog(log_id_t log_id, const char* msg, uint16_t len);
     void MaybePrune(log_id_t log_id) REQUIRES(lock_);
-    bool Prune(log_id_t log_id, size_t bytes_to_free, uid_t uid) REQUIRES(lock_);
-    void KickReader(LogReaderThread* reader, log_id_t id, size_t bytes_to_free)
-            REQUIRES_SHARED(lock_);
+    void Prune(log_id_t log_id, size_t bytes_to_free, uid_t uid) REQUIRES(lock_);
     void NotifyReadersOfPrune(log_id_t log_id, const std::list<SerializedLogChunk>::iterator& chunk)
             REQUIRES(reader_list_->reader_threads_lock());
     void RemoveChunkFromStats(log_id_t log_id, SerializedLogChunk& chunk);
-    unsigned long GetSizeUsed(log_id_t id) REQUIRES(lock_);
+    size_t GetSizeUsed(log_id_t id) REQUIRES(lock_);
 
     LogReaderList* reader_list_;
     LogTags* tags_;
     LogStatistics* stats_;
 
-    unsigned long max_size_[LOG_ID_MAX] GUARDED_BY(lock_) = {};
+    size_t max_size_[LOG_ID_MAX] GUARDED_BY(lock_) = {};
     std::list<SerializedLogChunk> logs_[LOG_ID_MAX] GUARDED_BY(lock_);
     RwLock lock_;
 
diff --git a/logd/SerializedLogChunk.cpp b/logd/SerializedLogChunk.cpp
index e444856..1ffe7a8 100644
--- a/logd/SerializedLogChunk.cpp
+++ b/logd/SerializedLogChunk.cpp
@@ -25,13 +25,11 @@
 }
 
 void SerializedLogChunk::Compress() {
-    if (compressed_log_.size() == 0) {
-        CompressionEngine::GetInstance().Compress(contents_, write_offset_, compressed_log_);
-        LOG(INFO) << "Compressed Log, buffer max size: " << contents_.size()
-                  << " size used: " << write_offset_
-                  << " compressed size: " << compressed_log_.size();
-    }
-    contents_.Resize(0);
+    CHECK_EQ(compressed_log_.size(), 0U);
+    CompressionEngine::GetInstance().Compress(contents_, write_offset_, compressed_log_);
+    LOG(VERBOSE) << "Compressed Log, buffer max size: " << contents_.size()
+                 << " size used: " << write_offset_
+                 << " compressed size: " << compressed_log_.size();
 }
 
 // TODO: Develop a better reference counting strategy to guard against the case where the writer is
@@ -44,13 +42,13 @@
     CompressionEngine::GetInstance().Decompress(compressed_log_, contents_);
 }
 
-void SerializedLogChunk::DecReaderRefCount(bool compress) {
+void SerializedLogChunk::DecReaderRefCount() {
     CHECK_NE(reader_ref_count_, 0U);
     if (--reader_ref_count_ != 0) {
         return;
     }
-    if (compress && !writer_active_) {
-        Compress();
+    if (!writer_active_) {
+        contents_.Resize(0);
     }
 }
 
@@ -83,18 +81,21 @@
     }
 
     if (new_write_offset == 0) {
-        DecReaderRefCount(false);
+        DecReaderRefCount();
         return true;
     }
 
-    // Clear the old compressed logs and set write_offset_ appropriately for DecReaderRefCount()
-    // to compress the new partially cleared log.
+    // Clear the old compressed logs and set write_offset_ appropriately to compress the new
+    // partially cleared log.
     if (new_write_offset != write_offset_) {
-        compressed_log_.Resize(0);
         write_offset_ = new_write_offset;
+        if (!writer_active_) {
+            compressed_log_.Resize(0);
+            Compress();
+        }
     }
 
-    DecReaderRefCount(true);
+    DecReaderRefCount();
 
     return false;
 }
@@ -111,4 +112,4 @@
     write_offset_ += entry->total_len();
     highest_sequence_number_ = sequence;
     return entry;
-}
\ No newline at end of file
+}
diff --git a/logd/SerializedLogChunk.h b/logd/SerializedLogChunk.h
index 50bae63..645433d 100644
--- a/logd/SerializedLogChunk.h
+++ b/logd/SerializedLogChunk.h
@@ -18,6 +18,8 @@
 
 #include <sys/types.h>
 
+#include <android-base/logging.h>
+
 #include "LogWriter.h"
 #include "SerializedData.h"
 #include "SerializedLogEntry.h"
@@ -30,9 +32,7 @@
 
     void Compress();
     void IncReaderRefCount();
-    // Decrease the reader ref count and compress the log if appropriate.  `compress` should only be
-    // set to false in the case that the log buffer will be deleted afterwards.
-    void DecReaderRefCount(bool compress);
+    void DecReaderRefCount();
 
     // Must have no readers referencing this.  Return true if there are no logs left in this chunk.
     bool ClearUidLogs(uid_t uid, log_id_t log_id, LogStatistics* stats);
@@ -50,12 +50,14 @@
 
     void FinishWriting() {
         writer_active_ = false;
+        Compress();
         if (reader_ref_count_ == 0) {
-            Compress();
+            contents_.Resize(0);
         }
     }
 
     const SerializedLogEntry* log_entry(int offset) const {
+        CHECK(writer_active_ || reader_ref_count_ > 0);
         return reinterpret_cast<const SerializedLogEntry*>(data() + offset);
     }
     const uint8_t* data() const { return contents_.data(); }
diff --git a/logd/SerializedLogChunkTest.cpp b/logd/SerializedLogChunkTest.cpp
index 2b478a3..3b45125 100644
--- a/logd/SerializedLogChunkTest.cpp
+++ b/logd/SerializedLogChunkTest.cpp
@@ -113,8 +113,7 @@
 TEST(SerializedLogChunk, catch_DecCompressedRef_CHECK) {
     size_t chunk_size = 10 * 4096;
     auto chunk = SerializedLogChunk{chunk_size};
-    EXPECT_DEATH({ chunk.DecReaderRefCount(true); }, "");
-    EXPECT_DEATH({ chunk.DecReaderRefCount(false); }, "");
+    EXPECT_DEATH({ chunk.DecReaderRefCount(); }, "");
 }
 
 // Check that the CHECK() in ClearUidLogs() if the ref count is greater than 0 is caught.
@@ -123,7 +122,7 @@
     auto chunk = SerializedLogChunk{chunk_size};
     chunk.IncReaderRefCount();
     EXPECT_DEATH({ chunk.ClearUidLogs(1000, LOG_ID_MAIN, nullptr); }, "");
-    chunk.DecReaderRefCount(false);
+    chunk.DecReaderRefCount();
 }
 
 class UidClearTest : public testing::TestWithParam<bool> {
@@ -144,7 +143,7 @@
         check(chunk_);
 
         if (finish_writing) {
-            chunk_.DecReaderRefCount(false);
+            chunk_.DecReaderRefCount();
         }
     }
 
@@ -282,3 +281,27 @@
 }
 
 INSTANTIATE_TEST_CASE_P(UidClearTests, UidClearTest, testing::Values(true, false));
+
+// b/166187079: ClearUidLogs() should not compress the log if writer_active_ is true
+TEST(SerializedLogChunk, ClearUidLogs_then_FinishWriting) {
+    static constexpr size_t kChunkSize = 10 * 4096;
+    static constexpr uid_t kUidToClear = 1000;
+    static constexpr uid_t kOtherUid = 1234;
+
+    SerializedLogChunk chunk{kChunkSize};
+    static const char msg1[] = "saved first message";
+    static const char msg2[] = "cleared interior message";
+    static const char msg3[] = "last message stays";
+    ASSERT_NE(nullptr, chunk.Log(1, log_time(), kOtherUid, 1, 2, msg1, sizeof(msg1)));
+    ASSERT_NE(nullptr, chunk.Log(2, log_time(), kUidToClear, 1, 2, msg2, sizeof(msg2)));
+    ASSERT_NE(nullptr, chunk.Log(3, log_time(), kOtherUid, 1, 2, msg3, sizeof(msg3)));
+
+    chunk.ClearUidLogs(kUidToClear, LOG_ID_MAIN, nullptr);
+
+    ASSERT_NE(nullptr, chunk.Log(4, log_time(), kOtherUid, 1, 2, msg3, sizeof(msg3)));
+
+    chunk.FinishWriting();
+    // The next line would violate a CHECK() during decompression with the faulty code.
+    chunk.IncReaderRefCount();
+    chunk.DecReaderRefCount();
+}
diff --git a/logd/SimpleLogBuffer.cpp b/logd/SimpleLogBuffer.cpp
index ec08d54..b00dd25 100644
--- a/logd/SimpleLogBuffer.cpp
+++ b/logd/SimpleLogBuffer.cpp
@@ -19,6 +19,7 @@
 #include <android-base/logging.h>
 
 #include "LogBufferElement.h"
+#include "LogSize.h"
 
 SimpleLogBuffer::SimpleLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats)
     : reader_list_(reader_list), tags_(tags), stats_(stats) {
@@ -29,8 +30,8 @@
 
 void SimpleLogBuffer::Init() {
     log_id_for_each(i) {
-        if (SetSize(i, __android_logger_get_buffer_size(i))) {
-            SetSize(i, LOG_BUFFER_MIN_SIZE);
+        if (!SetSize(i, GetBufferSizeFromProperties(i))) {
+            SetSize(i, kLogBufferMinSize);
         }
     }
 
@@ -247,22 +248,22 @@
 }
 
 // get the total space allocated to "id"
-unsigned long SimpleLogBuffer::GetSize(log_id_t id) {
+size_t SimpleLogBuffer::GetSize(log_id_t id) {
     auto lock = SharedLock{lock_};
     size_t retval = max_size_[id];
     return retval;
 }
 
 // set the total space allocated to "id"
-int SimpleLogBuffer::SetSize(log_id_t id, unsigned long size) {
+bool SimpleLogBuffer::SetSize(log_id_t id, size_t size) {
     // Reasonable limits ...
-    if (!__android_logger_valid_buffer_size(size)) {
-        return -1;
+    if (!IsValidBufferSize(size)) {
+        return false;
     }
 
     auto lock = std::lock_guard{lock_};
     max_size_[id] = size;
-    return 0;
+    return true;
 }
 
 void SimpleLogBuffer::MaybePrune(log_id_t id) {
diff --git a/logd/SimpleLogBuffer.h b/logd/SimpleLogBuffer.h
index 9f7d699..8e5b50e 100644
--- a/logd/SimpleLogBuffer.h
+++ b/logd/SimpleLogBuffer.h
@@ -41,8 +41,8 @@
                                                   log_time realtime)>& filter) override;
 
     bool Clear(log_id_t id, uid_t uid) override;
-    unsigned long GetSize(log_id_t id) override;
-    int SetSize(log_id_t id, unsigned long size) override final;
+    size_t GetSize(log_id_t id) override;
+    bool SetSize(log_id_t id, size_t size) override final;
 
     uint64_t sequence() const override { return sequence_.load(std::memory_order_relaxed); }
 
@@ -60,7 +60,7 @@
 
     LogStatistics* stats() { return stats_; }
     LogReaderList* reader_list() { return reader_list_; }
-    unsigned long max_size(log_id_t id) REQUIRES_SHARED(lock_) { return max_size_[id]; }
+    size_t max_size(log_id_t id) REQUIRES_SHARED(lock_) { return max_size_[id]; }
     std::list<LogBufferElement>& logs() { return logs_; }
 
     RwLock lock_;
@@ -75,7 +75,7 @@
 
     std::atomic<uint64_t> sequence_ = 1;
 
-    unsigned long max_size_[LOG_ID_MAX] GUARDED_BY(lock_);
+    size_t max_size_[LOG_ID_MAX] GUARDED_BY(lock_);
     std::list<LogBufferElement> logs_ GUARDED_BY(lock_);
     // Keeps track of the iterator to the oldest log message of a given log type, as an
     // optimization when pruning logs.  Use GetOldest() to retrieve.
diff --git a/logd/doc_images/cpu_cuttlefish.png b/logd/doc_images/cpu_cuttlefish.png
new file mode 100644
index 0000000..8d809ca
--- /dev/null
+++ b/logd/doc_images/cpu_cuttlefish.png
Binary files differ
diff --git a/logd/doc_images/cpu_walleye.png b/logd/doc_images/cpu_walleye.png
new file mode 100644
index 0000000..39c951b
--- /dev/null
+++ b/logd/doc_images/cpu_walleye.png
Binary files differ
diff --git a/logd/doc_images/memory_usage.png b/logd/doc_images/memory_usage.png
new file mode 100644
index 0000000..434d6d3
--- /dev/null
+++ b/logd/doc_images/memory_usage.png
Binary files differ
diff --git a/logd/doc_images/total_log_count.png b/logd/doc_images/total_log_count.png
new file mode 100644
index 0000000..e73c2c1
--- /dev/null
+++ b/logd/doc_images/total_log_count.png
Binary files differ
diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp
index 8309f95..d71a2f9 100644
--- a/logd/fuzz/log_buffer_log_fuzzer.cpp
+++ b/logd/fuzz/log_buffer_log_fuzzer.cpp
@@ -30,16 +30,6 @@
 #define MIN_TAG_ID 1000
 #define TAG_MOD 10
 
-#ifndef __ANDROID__
-unsigned long __android_logger_get_buffer_size(log_id_t) {
-    return 1024 * 1024;
-}
-
-bool __android_logger_valid_buffer_size(unsigned long) {
-    return true;
-}
-#endif
-
 char* android::uidToName(uid_t) {
     return strdup("fake");
 }
diff --git a/logd/logd_test.cpp b/logd/logd_test.cpp
index ed34ea4..828f580 100644
--- a/logd/logd_test.cpp
+++ b/logd/logd_test.cpp
@@ -30,6 +30,7 @@
 #include <android-base/file.h>
 #include <android-base/macros.h>
 #include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
 #include <cutils/sockets.h>
 #include <gtest/gtest.h>
 #include <log/log_read.h>
@@ -39,7 +40,9 @@
 #include <selinux/selinux.h>
 #endif
 
-#include "LogReader.h"  // pickup LOGD_SNDTIMEO
+#include "LogUtils.h"  // For LOGD_SNDTIMEO.
+
+using android::base::unique_fd;
 
 #ifdef __ANDROID__
 static void send_to_control(char* buf, size_t len) {
@@ -162,6 +165,7 @@
 }
 #endif
 
+#ifdef LOGD_ENABLE_FLAKY_TESTS
 TEST(logd, statistics) {
 #ifdef __ANDROID__
     size_t len;
@@ -237,6 +241,7 @@
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
+#endif
 
 #ifdef __ANDROID__
 static void caught_signal(int /* signum */) {
@@ -720,6 +725,7 @@
 }
 #endif
 
+#ifdef LOGD_ENABLE_FLAKY_TESTS
 // b/27242723 confirmed fixed
 TEST(logd, SNDTIMEO) {
 #ifdef __ANDROID__
@@ -777,6 +783,7 @@
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
+#endif
 
 TEST(logd, getEventTag_list) {
 #ifdef __ANDROID__
@@ -833,126 +840,33 @@
 #endif
 }
 
+TEST(logd, no_epipe) {
 #ifdef __ANDROID__
-static inline uint32_t get4LE(const uint8_t* src) {
-  return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
-}
+    // Actually generating SIGPIPE in logd is racy, since we need to close the socket quicker than
+    // logd finishes writing the data to it, so we try 10 times, which should be enough to trigger
+    // SIGPIPE if logd isn't ignoring SIGPIPE
+    for (int i = 0; i < 10; ++i) {
+        unique_fd sock1(
+                socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
+        ASSERT_GT(sock1, 0);
+        unique_fd sock2(
+                socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
+        ASSERT_GT(sock2, 0);
 
-static inline uint32_t get4LE(const char* src) {
-  return get4LE(reinterpret_cast<const uint8_t*>(src));
-}
-#endif
+        std::string message = "getStatistics 0 1 2 3 4 5 6 7";
 
-void __android_log_btwrite_multiple__helper(int count) {
-#ifdef __ANDROID__
-    log_time ts(CLOCK_MONOTONIC);
-    usleep(100);
-    log_time ts1(CLOCK_MONOTONIC);
+        ASSERT_GT(write(sock1, message.c_str(), message.length()), 0);
+        sock1.reset();
+        ASSERT_GT(write(sock2, message.c_str(), message.length()), 0);
 
-    // We fork to create a unique pid for the submitted log messages
-    // so that we do not collide with the other _multiple_ tests.
+        struct pollfd p = {.fd = sock2, .events = POLLIN, .revents = 0};
 
-    pid_t pid = fork();
-
-    if (pid == 0) {
-        // child
-        for (int i = count; i; --i) {
-            ASSERT_LT(
-                0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
-            usleep(100);
-        }
-        ASSERT_LT(0,
-                  __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
-        usleep(1000000);
-
-        _exit(0);
+        int ret = poll(&p, 1, 20);
+        EXPECT_EQ(ret, 1);
+        EXPECT_TRUE(p.revents & POLLIN);
+        EXPECT_FALSE(p.revents & POLL_ERR);
     }
-
-    siginfo_t info = {};
-    ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED)));
-    ASSERT_EQ(0, info.si_status);
-
-    struct logger_list* logger_list;
-    ASSERT_TRUE(nullptr != (logger_list = android_logger_list_open(LOG_ID_EVENTS,
-                                                                   ANDROID_LOG_NONBLOCK, 0, pid)));
-
-    int expected_count = (count < 2) ? count : 2;
-    int expected_chatty_count = (count <= 2) ? 0 : 1;
-    int expected_identical_count = (count < 2) ? 0 : (count - 2);
-    static const int expected_expire_count = 0;
-
-    count = 0;
-    int second_count = 0;
-    int chatty_count = 0;
-    int identical_count = 0;
-    int expire_count = 0;
-
-    for (;;) {
-        log_msg log_msg;
-        if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
-
-        if ((log_msg.entry.pid != pid) || (log_msg.entry.len < (4 + 1 + 8)) ||
-            (log_msg.id() != LOG_ID_EVENTS))
-            continue;
-
-        char* eventData = log_msg.msg();
-        if (!eventData) continue;
-
-        uint32_t tag = get4LE(eventData);
-
-        if ((eventData[4] == EVENT_TYPE_LONG) &&
-            (log_msg.entry.len == (4 + 1 + 8))) {
-            if (tag != 0) continue;
-
-            log_time* tx = reinterpret_cast<log_time*>(eventData + 4 + 1);
-            if (ts == *tx) {
-                ++count;
-            } else if (ts1 == *tx) {
-                ++second_count;
-            }
-        } else if (eventData[4] == EVENT_TYPE_STRING) {
-            if (tag != CHATTY_LOG_TAG) continue;
-            ++chatty_count;
-            // int len = get4LE(eventData + 4 + 1);
-            log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
-            const char* cp;
-            if ((cp = strstr(eventData + 4 + 1 + 4, " identical "))) {
-                unsigned val = 0;
-                sscanf(cp, " identical %u lines", &val);
-                identical_count += val;
-            } else if ((cp = strstr(eventData + 4 + 1 + 4, " expire "))) {
-                unsigned val = 0;
-                sscanf(cp, " expire %u lines", &val);
-                expire_count += val;
-            }
-        }
-    }
-
-    android_logger_list_close(logger_list);
-
-    EXPECT_EQ(expected_count, count);
-    EXPECT_EQ(1, second_count);
-    EXPECT_EQ(expected_chatty_count, chatty_count);
-    EXPECT_EQ(expected_identical_count, identical_count);
-    EXPECT_EQ(expected_expire_count, expire_count);
 #else
-    count = 0;
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
-
-TEST(logd, multiple_test_1) {
-    __android_log_btwrite_multiple__helper(1);
-}
-
-TEST(logd, multiple_test_2) {
-    __android_log_btwrite_multiple__helper(2);
-}
-
-TEST(logd, multiple_test_3) {
-    __android_log_btwrite_multiple__helper(3);
-}
-
-TEST(logd, multiple_test_10) {
-    __android_log_btwrite_multiple__helper(10);
-}
diff --git a/logd/main.cpp b/logd/main.cpp
index 897e11e..c92c5b7 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -62,7 +62,9 @@
 #include "SerializedLogBuffer.h"
 #include "SimpleLogBuffer.h"
 
+using android::base::GetBoolProperty;
 using android::base::GetProperty;
+using android::base::SetProperty;
 
 #define KMSG_PRIORITY(PRI)                                 \
     '<', '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \
@@ -82,9 +84,10 @@
         PLOG(FATAL) << "failed to set batch scheduler";
     }
 
-    if (!__android_logger_property_get_bool("ro.debuggable", BOOL_DEFAULT_FALSE) &&
-        prctl(PR_SET_DUMPABLE, 0) == -1) {
-        PLOG(FATAL) << "failed to clear PR_SET_DUMPABLE";
+    if (!GetBoolProperty("ro.debuggable", false)) {
+        if (prctl(PR_SET_DUMPABLE, 0) == -1) {
+            PLOG(FATAL) << "failed to clear PR_SET_DUMPABLE";
+        }
     }
 
     std::unique_ptr<struct _cap_struct, int (*)(void*)> caps(cap_init(), cap_free);
@@ -110,6 +113,14 @@
     }
 }
 
+// GetBoolProperty that defaults to true if `ro.debuggable == true && ro.config.low_rawm == false`.
+static bool GetBoolPropertyEngSvelteDefault(const std::string& name) {
+    bool default_value =
+            GetBoolProperty("ro.debuggable", false) && !GetBoolProperty("ro.config.low_ram", false);
+
+    return GetBoolProperty(name, default_value);
+}
+
 char* android::uidToName(uid_t u) {
     struct Userdata {
         uid_t uid;
@@ -207,6 +218,8 @@
 // logging plugins like auditd and restart control. Additional
 // transitory per-client threads are created for each reader.
 int main(int argc, char* argv[]) {
+    // We want EPIPE when a reader disconnects, not to terminate logd.
+    signal(SIGPIPE, SIG_IGN);
     // logd is written under the assumption that the timezone is UTC.
     // If TZ is not set, persist.sys.timezone is looked up in some time utility
     // libc functions, including mktime. It confuses the logd time handling,
@@ -236,10 +249,9 @@
     }
 
     int fdPmesg = -1;
-    bool klogd = __android_logger_property_get_bool(
-        "ro.logd.kernel",
-        BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE);
+    bool klogd = GetBoolPropertyEngSvelteDefault("ro.logd.kernel");
     if (klogd) {
+        SetProperty("ro.logd.kernel", "true");
         static const char proc_kmsg[] = "/proc/kmsg";
         fdPmesg = android_get_control_file(proc_kmsg);
         if (fdPmesg < 0) {
@@ -249,7 +261,7 @@
         if (fdPmesg < 0) PLOG(ERROR) << "Failed to open " << proc_kmsg;
     }
 
-    bool auditd = __android_logger_property_get_bool("ro.logd.auditd", BOOL_DEFAULT_TRUE);
+    bool auditd = GetBoolProperty("ro.logd.auditd", true);
     DropPrivs(klogd, auditd);
 
     // A cache of event log tags
@@ -258,13 +270,11 @@
     // Pruning configuration.
     PruneList prune_list;
 
-    std::string buffer_type = GetProperty("logd.buffer_type", "chatty");
+    std::string buffer_type = GetProperty("logd.buffer_type", "serialized");
 
     // Partial (required for chatty) or full logging statistics.
-    bool enable_full_log_statistics = __android_logger_property_get_bool(
-            "logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
-                                       BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE);
-    LogStatistics log_statistics(enable_full_log_statistics, buffer_type == "serialized");
+    LogStatistics log_statistics(GetBoolPropertyEngSvelteDefault("logd.statistics"),
+                                 buffer_type == "serialized");
 
     // Serves the purpose of managing the last logs times read on a socket connection, and as a
     // reader lock on a range of log entries.
@@ -309,9 +319,7 @@
     // and LogReader is notified to send updates to connected clients.
     LogAudit* al = nullptr;
     if (auditd) {
-        int dmesg_fd = __android_logger_property_get_bool("ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)
-                               ? fdDmesg
-                               : -1;
+        int dmesg_fd = GetBoolProperty("ro.logd.auditd.dmesg", true) ? fdDmesg : -1;
         al = new LogAudit(log_buffer, dmesg_fd, &log_statistics);
     }
 
diff --git a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
index a643062..3907413 100644
--- a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
+++ b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
@@ -139,7 +139,7 @@
 
   auto property_info_area = reinterpret_cast<const PropertyInfoArea*>(serialized_trie.data());
 
-  // Sanity check
+  // Smoke test
   auto root_node = property_info_area->root_node();
   EXPECT_STREQ("root", root_node.name());
   EXPECT_STREQ("default", property_info_area->context(root_node.context_index()));
diff --git a/qemu_pipe/qemu_pipe.cpp b/qemu_pipe/qemu_pipe.cpp
index beeccb0..03afb21 100644
--- a/qemu_pipe/qemu_pipe.cpp
+++ b/qemu_pipe/qemu_pipe.cpp
@@ -35,7 +35,6 @@
 #endif
 
 int qemu_pipe_open(const char* pipeName) {
-    // Sanity check.
     if (!pipeName) {
         errno = EINVAL;
         return -1;
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index ac8e847..77fa94e 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -131,6 +131,16 @@
 # via /vendor/lib/modules directly.
 LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/vendor_dlkm/etc $(TARGET_ROOT_OUT)/vendor_dlkm/etc
 
+# For /odm_dlkm partition.
+LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/odm_dlkm
+# For Treble Generic System Image (GSI), system-as-root GSI needs to work on
+# both devices with and without /odm_dlkm partition. Those symlinks are for
+# devices without /odm_dlkm partition. For devices with /odm_dlkm
+# partition, mount odm_dlkm.img under /odm_dlkm will hide those symlinks.
+# Note that /odm_dlkm/lib is omitted because odm DLKMs should be accessed
+# via /odm/lib/modules directly.
+LOCAL_POST_INSTALL_CMD += ; ln -sf /odm/odm_dlkm/etc $(TARGET_ROOT_OUT)/odm_dlkm/etc
+
 ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
   LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
 else
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index 5de422f..967205f 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -10,6 +10,7 @@
 libGLESv1_CM.so
 libGLESv2.so
 libGLESv3.so
+libicu.so
 libicui18n.so
 libicuuc.so
 libjnigraphics.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index fb6f1be..91f2c57 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -81,6 +81,11 @@
     # Mount tracefs
     mount tracefs tracefs /sys/kernel/tracing
 
+    # create sys dirctory
+    mkdir /dev/sys 0755 system system
+    mkdir /dev/sys/fs 0755 system system
+    mkdir /dev/sys/block 0755 system system
+
 # Run boringssl self test for each ABI so that later processes can skip it. http://b/139348610
 on early-init && property:ro.product.cpu.abilist32=*
     exec_start boringssl_self_test32
@@ -177,6 +182,9 @@
     mount binder binder /dev/binderfs stats=global
     chmod 0755 /dev/binderfs
 
+    # Mount fusectl
+    mount fusectl none /sys/fs/fuse/connections
+
     symlink /dev/binderfs/binder /dev/binder
     symlink /dev/binderfs/hwbinder /dev/hwbinder
     symlink /dev/binderfs/vndbinder /dev/vndbinder
@@ -319,16 +327,6 @@
     chmod 0664 /dev/cpuset/restricted/tasks
     chmod 0664 /dev/cpuset/tasks
 
-    # freezer cgroup entries
-    mkdir /dev/freezer/frozen
-    write /dev/freezer/frozen/freezer.state FROZEN
-    chown system system /dev/freezer/cgroup.procs
-    chown system system /dev/freezer/frozen
-    chown system system /dev/freezer/frozen/freezer.state
-    chown system system /dev/freezer/frozen/cgroup.procs
-
-    chmod 0444 /dev/freezer/frozen/freezer.state
-
     # make the PSI monitor accessible to others
     chown system system /proc/pressure/memory
     chmod 0664 /proc/pressure/memory
@@ -343,8 +341,6 @@
     # This is needed by any process that uses socket tagging.
     chmod 0644 /dev/xt_qtaguid
 
-    chown root root /dev/cg2_bpf
-    chmod 0600 /dev/cg2_bpf
     mount bpf bpf /sys/fs/bpf nodev noexec nosuid
 
     # Create location for fs_mgr to store abbreviated output from filesystem
@@ -468,6 +464,10 @@
     # The bind+remount combination allows this to work in containers.
     mount rootfs rootfs / remount bind ro nodev
 
+    # Mount default storage into root namespace
+    mount none /mnt/user/0 /storage bind rec
+    mount none none /storage slave rec
+
     # Make sure /sys/kernel/debug (if present) is labeled properly
     # Note that tracefs may be mounted under debug, so we need to cross filesystems
     restorecon --recursive --cross-filesystems /sys/kernel/debug
@@ -517,6 +517,7 @@
     mkdir /metadata/bootstat 0750 system log
     mkdir /metadata/ota 0700 root system
     mkdir /metadata/ota/snapshots 0700 root system
+    mkdir /metadata/userspacereboot 0770 root system
 
     mkdir /metadata/apex 0700 root system
     mkdir /metadata/apex/sessions 0700 root system
@@ -527,6 +528,7 @@
     # no-op.
     restorecon_recursive /metadata/apex
 
+    mkdir /metadata/staged-install 0770 root system
 on late-fs
     # Ensure that tracefs has the correct permissions.
     # This does not work correctly if it is called in post-fs.
@@ -663,6 +665,15 @@
     mkdir /data/vendor/tombstones 0771 root root
     mkdir /data/vendor/tombstones/wifi 0771 wifi wifi
 
+    # Create directories to push tests to for each linker namespace.
+    # Create the subdirectories in case the first test is run as root
+    # so it doesn't end up owned by root.
+    mkdir /data/local/tests 0700 shell shell
+    mkdir /data/local/tests/product 0700 shell shell
+    mkdir /data/local/tests/system 0700 shell shell
+    mkdir /data/local/tests/unrestricted 0700 shell shell
+    mkdir /data/local/tests/vendor 0700 shell shell
+
     # create dalvik-cache, so as to enforce our permissions
     mkdir /data/dalvik-cache 0771 root root encryption=Require
     # create the A/B OTA directory, so as to enforce our permissions
@@ -795,34 +806,19 @@
     # IOCTLs on ashmem fds any more.
     setprop sys.use_memfd false
 
-    # Explicitly disable FUSE
-    setprop persist.sys.fuse false
-
     # Set fscklog permission
     chown root system /dev/fscklogs/log
     chmod 0770 /dev/fscklogs/log
 
-# Switch between sdcardfs and FUSE depending on persist property
-# TODO: Move this to ro property before launch because FDE devices
-# interact with persistent properties differently during boot
-on zygote-start && property:persist.sys.fuse=true
-  # Mount default storage into root namespace
-  mount none /mnt/user/0 /storage bind rec
-  mount none none /storage slave rec
-on zygote-start && property:persist.sys.fuse=false
-  # Mount default storage into root namespace
-  mount none /mnt/runtime/default /storage bind rec
-  mount none none /storage slave rec
-on zygote-start && property:persist.sys.fuse=""
-  # Mount default storage into root namespace
-  mount none /mnt/runtime/default /storage bind rec
-  mount none none /storage slave rec
+    # Enable FUSE by default
+    setprop persist.sys.fuse true
 
 # It is recommended to put unnecessary data/ initialization from post-fs-data
 # to start-zygote in device's init.rc to unblock zygote start.
 on zygote-start && property:ro.crypto.state=unencrypted
     # A/B update verifier that marks a successful boot.
     exec_start update_verifier_nonencrypted
+    start statsd
     start netd
     start zygote
     start zygote_secondary
@@ -830,6 +826,7 @@
 on zygote-start && property:ro.crypto.state=unsupported
     # A/B update verifier that marks a successful boot.
     exec_start update_verifier_nonencrypted
+    start statsd
     start netd
     start zygote
     start zygote_secondary
@@ -837,6 +834,7 @@
 on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
     # A/B update verifier that marks a successful boot.
     exec_start update_verifier_nonencrypted
+    start statsd
     start netd
     start zygote
     start zygote_secondary
@@ -867,17 +865,26 @@
     chown root system /sys/block/zram0/writeback
     chmod 0664 /sys/block/zram0/writeback
 
+    # to access F2FS sysfs on dm-<num> directly
+    mkdir /dev/sys/fs/by-name 0755 system system
+    symlink /sys/fs/f2fs/${dev.mnt.blk.data} /dev/sys/fs/by-name/userdata
+
+    # to access dm-<num> sysfs
+    mkdir /dev/sys/block/by-name 0755 system system
+    symlink /sys/devices/virtual/block/${dev.mnt.blk.data} /dev/sys/block/by-name/userdata
+
     # F2FS tuning. Set cp_interval larger than dirty_expire_centisecs, 30 secs,
     # to avoid power consumption when system becomes mostly idle. Be careful
     # to make it too large, since it may bring userdata loss, if they
     # are not aware of using fsync()/sync() to prepare sudden power-cut.
-    write /sys/fs/f2fs/${dev.mnt.blk.data}/cp_interval 200
-    write /sys/fs/f2fs/${dev.mnt.blk.data}/gc_urgent_sleep_time 50
+    write /dev/sys/fs/by-name/userdata/cp_interval 200
+    write /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time 50
+    write /dev/sys/fs/by-name/userdata/iostat_enable 1
 
     # limit discard size to 128MB in order to avoid long IO latency
     # for filesystem tuning first (dm or sda)
     # Note that, if dm-<num> is used, sda/mmcblk0 should be tuned in vendor/init.rc
-    write /sys/devices/virtual/block/${dev.mnt.blk.data}/queue/discard_max_bytes 134217728
+    write /dev/sys/block/by-name/userdata/queue/discard_max_bytes 134217728
 
     # Permissions for System Server and daemons.
     chown system system /sys/power/autosleep
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 9adbcba..e827cf5 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -5,6 +5,7 @@
     group root readproc reserved_disk
     socket zygote stream 660 root system
     socket usap_pool_primary stream 660 root system
+    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
     onrestart write /sys/power/state on
     onrestart restart audioserver
     onrestart restart cameraserver
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 0e69b16..adc7031 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -5,6 +5,7 @@
     group root readproc reserved_disk
     socket zygote stream 660 root system
     socket usap_pool_primary stream 660 root system
+    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
     onrestart write /sys/power/state on
     onrestart restart audioserver
     onrestart restart cameraserver
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 3e80168..fb9e99b 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -5,13 +5,14 @@
     group root readproc reserved_disk
     socket zygote stream 660 root system
     socket usap_pool_primary stream 660 root system
+    onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
     onrestart write /sys/power/state on
     onrestart restart audioserver
     onrestart restart cameraserver
     onrestart restart media
     onrestart restart netd
     onrestart restart wificond
-    writepid /dev/cpuset/foreground/tasks
+    task_profiles ProcessCapacityHigh MaxPerformance
 
 service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
     class main
@@ -21,4 +22,4 @@
     socket zygote_secondary stream 660 root system
     socket usap_pool_secondary stream 660 root system
     onrestart restart zygote
-    writepid /dev/cpuset/foreground/tasks
+    task_profiles ProcessCapacityHigh MaxPerformance
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 9c2cdf2..1994bdb 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -17,6 +17,9 @@
     devname uevent_devpath
     dirname /dev/snd
 
+subsystem dma_heap
+   devname uevent_devpath
+   dirname /dev/dma_heap
 # ueventd can only set permissions on device nodes and their associated
 # sysfs attributes, not on arbitrary paths.
 #
@@ -39,6 +42,7 @@
 /dev/vndbinder            0666   root       root
 
 /dev/pmsg0                0222   root       log
+/dev/dma_heap/system      0666   system     system
 
 # kms driver for drm based gpu
 /dev/dri/*                0666   root       graphics
diff --git a/run-as/Android.bp b/run-as/Android.bp
index 840a43c..accd07d 100644
--- a/run-as/Android.bp
+++ b/run-as/Android.bp
@@ -25,4 +25,5 @@
         "libpackagelistparser",
         "libminijail",
     ],
+    header_libs: ["libcutils_headers"],
 }
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index 3bee875..4510dc7 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -98,7 +98,7 @@
 toolbox: df getevent iftop ioctl ionice log ls lsof mount nandread
 newfs\_msdos ps prlimit renice sendevent start stop top uptime watchprops
 
-toybox: acpi basename blockdev bzcat cal cat chcon chgrp chmod chown
+toybox (0.5.2-ish): acpi basename blockdev bzcat cal cat chcon chgrp chmod chown
 chroot cksum clear comm cmp cp cpio cut date dirname dmesg dos2unix echo
 env expand expr fallocate false find free getenforce getprop groups
 head hostname hwclock id ifconfig inotifyd insmod kill load\_policy ln
@@ -118,7 +118,7 @@
 toolbox: getevent iftop ioctl log nandread newfs\_msdos ps prlimit
 sendevent start stop top
 
-toybox: acpi base64 basename blockdev bzcat cal cat chcon chgrp chmod
+toybox (0.7.0-ish): acpi base64 basename blockdev bzcat cal cat chcon chgrp chmod
 chown chroot cksum clear comm cmp cp cpio cut date df dirname dmesg
 dos2unix du echo env expand expr fallocate false find flock free
 getenforce getprop groups head hostname hwclock id ifconfig inotifyd
@@ -140,7 +140,7 @@
 
 toolbox: getevent newfs\_msdos
 
-toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown
+toybox (0.7.3-ish): acpi base64 basename blockdev cal cat chcon chgrp chmod chown
 chroot chrt cksum clear cmp comm cp cpio cut date df diff dirname dmesg
 dos2unix du echo env expand expr fallocate false file find flock free
 getenforce getprop groups gunzip gzip head hostname hwclock id ifconfig
@@ -166,7 +166,7 @@
 
 toolbox: getevent getprop newfs\_msdos
 
-toybox: acpi base64 basename blockdev cal cat chcon chgrp chmod chown
+toybox (0.7.6-ish): acpi base64 basename blockdev cal cat chcon chgrp chmod chown
 chroot chrt cksum clear cmp comm cp cpio cut date df diff dirname dmesg
 dos2unix du echo env expand expr fallocate false file find flock fmt free
 getenforce groups gunzip gzip head hostname hwclock id ifconfig inotifyd
@@ -192,7 +192,7 @@
 
 toolbox: getevent getprop
 
-toybox: acpi base64 basename bc blkid blockdev cal cat chattr chcon chgrp
+toybox (0.8.0-ish): acpi base64 basename bc blkid blockdev cal cat chattr chcon chgrp
 chmod chown chroot chrt cksum clear cmp comm cp cpio cut date dd df
 diff dirname dmesg dos2unix du echo egrep env expand expr fallocate
 false fgrep file find flock fmt free freeramdisk fsfreeze getconf
@@ -224,7 +224,7 @@
 
 toolbox: getevent getprop setprop start stop
 
-toybox: acpi base64 basename blkid blockdev cal cat chattr chcon chgrp chmod
+toybox (0.8.3-ish): acpi base64 basename blkid blockdev cal cat chattr chcon chgrp chmod
 chown chroot chrt cksum clear cmp comm cp cpio cut date dd devmem
 df diff dirname dmesg dos2unix du echo egrep env expand expr fallocate
 false fgrep file find flock fmt free freeramdisk fsfreeze fsync getconf
diff --git a/toolbox/start.cpp b/toolbox/start.cpp
index 46314cf..cffb89c 100644
--- a/toolbox/start.cpp
+++ b/toolbox/start.cpp
@@ -37,6 +37,7 @@
 
 static void ControlDefaultServices(bool start) {
     std::vector<std::string> services = {
+        "iorapd",
         "netd",
         "surfaceflinger",
         "audioserver",
@@ -91,4 +92,4 @@
 
 extern "C" int stop_main(int argc, char** argv) {
     return StartStop(argc, argv, false);
-}
+}
\ No newline at end of file
diff --git a/trusty/confirmationui/NotSoSecureInput.cpp b/trusty/confirmationui/NotSoSecureInput.cpp
index 3d9a2d6..18e45cd 100644
--- a/trusty/confirmationui/NotSoSecureInput.cpp
+++ b/trusty/confirmationui/NotSoSecureInput.cpp
@@ -82,7 +82,7 @@
 
 /**
  * This is an implementation of the SecureInput protocol in unserspace. This is
- * just an example and should not be used as is. The protocol implemented her
+ * just an example and should not be used as is. The protocol implemented here
  * should be used by a trusted input device that can assert user events with
  * high assurance even if the HLOS kernel is compromised. A confirmationui HAL
  * that links directly against this implementation is not secure and shal not be
diff --git a/trusty/gatekeeper/trusty_gatekeeper.cpp b/trusty/gatekeeper/trusty_gatekeeper.cpp
index d149664..e416fb2 100644
--- a/trusty/gatekeeper/trusty_gatekeeper.cpp
+++ b/trusty/gatekeeper/trusty_gatekeeper.cpp
@@ -56,9 +56,9 @@
 
 SizedBuffer hidl_vec2sized_buffer(const hidl_vec<uint8_t>& vec) {
     if (vec.size() == 0 || vec.size() > std::numeric_limits<uint32_t>::max()) return {};
-    auto dummy = new uint8_t[vec.size()];
-    std::copy(vec.begin(), vec.end(), dummy);
-    return {dummy, static_cast<uint32_t>(vec.size())};
+    auto buffer = new uint8_t[vec.size()];
+    std::copy(vec.begin(), vec.end(), buffer);
+    return {buffer, static_cast<uint32_t>(vec.size())};
 }
 
 Return<void> TrustyGateKeeperDevice::enroll(uint32_t uid,
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 6840baa..27e1a3f 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -75,3 +75,36 @@
 
     vintf_fragments: ["4.0/android.hardware.keymaster@4.0-service.trusty.xml"],
 }
+
+prebuilt_etc {
+    name: "keymaster_soft_attestation_keys.xml",
+    vendor: true,
+    src: "set_attestation_key/keymaster_soft_attestation_keys.xml",
+}
+
+cc_binary {
+    name: "trusty_keymaster_set_attestation_key",
+    vendor: true,
+
+    srcs: [
+        "set_attestation_key/set_attestation_key.cpp",
+        "ipc/trusty_keymaster_ipc.cpp",
+    ],
+
+    local_include_dirs: ["include"],
+
+    shared_libs: [
+        "libc",
+        "libcrypto",
+        "liblog",
+        "libtrusty",
+        "libhardware",
+        "libkeymaster_messages",
+        "libxml2",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
+
diff --git a/trusty/keymaster/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp
index f3ef747..750a9d7 100644
--- a/trusty/keymaster/TrustyKeymaster.cpp
+++ b/trusty/keymaster/TrustyKeymaster.cpp
@@ -173,7 +173,7 @@
 }
 
 GetHmacSharingParametersResponse TrustyKeymaster::GetHmacSharingParameters() {
-    // Dummy empty buffer to allow ForwardCommand to have something to serialize
+    // Empty buffer to allow ForwardCommand to have something to serialize
     Buffer request;
     GetHmacSharingParametersResponse response;
     ForwardCommand(KM_GET_HMAC_SHARING_PARAMETERS, request, &response);
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index 13e6725..ce2cc2e 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -53,6 +53,19 @@
     KM_DELETE_ALL_KEYS              = (23 << KEYMASTER_REQ_SHIFT),
     KM_DESTROY_ATTESTATION_IDS      = (24 << KEYMASTER_REQ_SHIFT),
     KM_IMPORT_WRAPPED_KEY           = (25 << KEYMASTER_REQ_SHIFT),
+
+    // Bootloader/provisioning calls.
+    KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT),
+    KM_SET_ATTESTATION_KEY = (0x2000 << KEYMASTER_REQ_SHIFT),
+    KM_APPEND_ATTESTATION_CERT_CHAIN = (0x3000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_GET_CA_REQUEST = (0x4000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_SET_CA_RESPONSE_BEGIN = (0x5000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_SET_CA_RESPONSE_UPDATE = (0x6000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_SET_CA_RESPONSE_FINISH = (0x7000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_READ_UUID = (0x8000 << KEYMASTER_REQ_SHIFT),
+    KM_SET_PRODUCT_ID = (0x9000 << KEYMASTER_REQ_SHIFT),
+    KM_CLEAR_ATTESTATION_CERT_CHAIN = (0xa000 << KEYMASTER_REQ_SHIFT),
+    KM_SET_WRAPPED_ATTESTATION_KEY = (0xb000 << KEYMASTER_REQ_SHIFT),
 };
 
 #ifdef __ANDROID__
diff --git a/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml b/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml
new file mode 100644
index 0000000..fce2ac2
--- /dev/null
+++ b/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0"?>
+<AndroidAttestation>
+  <NumberOfKeyboxes>10</NumberOfKeyboxes>
+  <Keybox DeviceID="dev1">
+    <Key algorithm="rsa">
+      <PrivateKey format="pem">
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDAgyPcVogbuDAgafWwhWHG7r5/BeL1qEIEir6LR752/q7yXPKb
+KvoyABQWAUKZiaFfz8aBXrNjWDwv0vIL5Jgyg92BSxbX4YVBeuVKvClqOm21wAQI
+O2jFVsHwIzmRZBmGTVC3TUCuykhMdzVsiVoMJ1q/rEmdXX0jYvKcXgLocQIDAQAB
+AoGBAL6GCwuZqAKm+xpZQ4p7txUGWwmjbcbpysxr88AsNNfXnpTGYGQo2Ix7f2V3
+wc3qZAdKvo5yht8fCBHclygmCGjeldMu/Ja20IT/JxpfYN78xwPno45uKbqaPF/C
+woB2tqiWrx0014gozpvdsfNPnJQEQweBKY4gExZyW728mTpBAkEA4cbZJ2RsCRbs
+NoJtWUmDdAwh8bB0xKGlmGfGaXlchdPcRkxbkp6Uv7NODcxQFLEPEzQat/3V9gQU
+0qMmytQcxQJBANpIWZd4XNVjD7D9jFJU+Y5TjhiYOq6ea35qWntdNDdVuSGOvUAy
+DSg4fXifdvohi8wti2il9kGPu+ylF5qzr70CQFD+/DJklVlhbtZTThVFCTKdk6PY
+ENvlvbmCKSz3i9i624Agro1X9LcdBThv/p6dsnHKNHejSZnbdvjl7OnA1J0CQBW3
+TPJ8zv+Ls2vwTZ2DRrCaL3DS9EObDyasfgP36dH3fUuRX9KbKCPwOstdUgDghX/y
+qAPpPu6W1iNc6VRCvCECQQCQp0XaiXCyzWSWYDJCKMX4KFb/1mW6moXI1g8bi+5x
+fs0scurgHa2GunZU1M9FrbXx8rMdn4Eiz6XxpVcPmy0l
+-----END RSA PRIVATE KEY-----
+      </PrivateKey>
+      <CertificateChain>
+        <NumberOfCertificates>2</NumberOfCertificates>
+        <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICtjCCAh+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT
+BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDAeFw0xNjAxMDQx
+MjQwNTNaFw0zNTEyMzAxMjQwNTNaMHYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD
+YWxpZm9ybmlhMRUwEwYDVQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJv
+aWQxKTAnBgNVBAMMIEFuZHJvaWQgU29mdHdhcmUgQXR0ZXN0YXRpb24gS2V5MIGf
+MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAgyPcVogbuDAgafWwhWHG7r5/BeL1
+qEIEir6LR752/q7yXPKbKvoyABQWAUKZiaFfz8aBXrNjWDwv0vIL5Jgyg92BSxbX
+4YVBeuVKvClqOm21wAQIO2jFVsHwIzmRZBmGTVC3TUCuykhMdzVsiVoMJ1q/rEmd
+XX0jYvKcXgLocQIDAQABo2YwZDAdBgNVHQ4EFgQU1AwQG/jNY7n3OVK1DhNcpteZ
+k4YwHwYDVR0jBBgwFoAUKfrxrMxN0kyWQCd1trDpMuUH/i4wEgYDVR0TAQH/BAgw
+BgEB/wIBADAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADgYEAni1IX4xn
+M9waha2Z11Aj6hTsQ7DhnerCI0YecrUZ3GAi5KVoMWwLVcTmnKItnzpPk2sxixZ4
+Fg2Iy9mLzICdhPDCJ+NrOPH90ecXcjFZNX2W88V/q52PlmEmT7K+gbsNSQQiis6f
+9/VCLiVE+iEHElqDtVWtGIL4QBSbnCBjBH8=
+-----END CERTIFICATE-----
+        </Certificate>
+        <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICpzCCAhCgAwIBAgIJAP+U2d2fB8gMMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW
+aWV3MRUwEwYDVQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQwHhcN
+MTYwMTA0MTIzMTA4WhcNMzUxMjMwMTIzMTA4WjBjMQswCQYDVQQGEwJVUzETMBEG
+A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEVMBMGA1UE
+CgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCia63rbi5EYe/VDoLmt5TRdSMfd5tjkWP/96r/C3JHTsAs
+Q+wzfNes7UA+jCigZtX3hwszl94OuE4TQKuvpSe/lWmgMdsGUmX4RFlXYfC78hdL
+t0GAZMAoDo9Sd47b0ke2RekZyOmLw9vCkT/X11DEHTVm+Vfkl5YLCazOkjWFmwID
+AQABo2MwYTAdBgNVHQ4EFgQUKfrxrMxN0kyWQCd1trDpMuUH/i4wHwYDVR0jBBgw
+FoAUKfrxrMxN0kyWQCd1trDpMuUH/i4wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
+Af8EBAMCAoQwDQYJKoZIhvcNAQELBQADgYEAT3LzNlmNDsG5dFsxWfbwjSVJMJ6j
+HBwp0kUtILlNX2S06IDHeHqcOd6os/W/L3BfRxBcxebrTQaZYdKumgf/93y4q+uc
+DyQHXrF/unlx/U1bnt8Uqf7f7XzAiF343ZtkMlbVNZriE/mPzsF83O+kqrJVw4Op
+Lvtc9mL1J1IXvmM=
+-----END CERTIFICATE-----
+        </Certificate>
+      </CertificateChain>
+    </Key>
+  </Keybox>
+  <Keybox DeviceID="dev1">
+    <Key algorithm="ecdsa">
+      <PrivateKey format="pem">
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEICHghkMqFRmEWc82OlD8FMnarfk19SfC39ceTW28QuVEoAoGCCqGSM49
+AwEHoUQDQgAE6555+EJjWazLKpFMiYbMcK2QZpOCqXMmE/6sy/ghJ0whdJdKKv6l
+uU1/ZtTgZRBmNbxTt6CjpnFYPts+Ea4QFA==
+-----END EC PRIVATE KEY-----
+      </PrivateKey>
+      <CertificateChain>
+        <NumberOfCertificates>2</NumberOfCertificates>
+        <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICeDCCAh6gAwIBAgICEAEwCgYIKoZIzj0EAwIwgZgxCzAJBgNVBAYTAlVTMRMw
+EQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRUwEwYD
+VQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQxMzAxBgNVBAMMKkFu
+ZHJvaWQgS2V5c3RvcmUgU29mdHdhcmUgQXR0ZXN0YXRpb24gUm9vdDAeFw0xNjAx
+MTEwMDQ2MDlaFw0yNjAxMDgwMDQ2MDlaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdB
+bmRyb2lkMTswOQYDVQQDDDJBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVz
+dGF0aW9uIEludGVybWVkaWF0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOue
+efhCY1msyyqRTImGzHCtkGaTgqlzJhP+rMv4ISdMIXSXSir+pblNf2bU4GUQZjW8
+U7ego6ZxWD7bPhGuEBSjZjBkMB0GA1UdDgQWBBQ//KzWGrE6noEguNUlHMVlux6R
+qTAfBgNVHSMEGDAWgBTIrel3TEXDo88NFhDkeUM6IVowzzASBgNVHRMBAf8ECDAG
+AQH/AgEAMA4GA1UdDwEB/wQEAwIChDAKBggqhkjOPQQDAgNIADBFAiBLipt77oK8
+wDOHri/AiZi03cONqycqRZ9pDMfDktQPjgIhAO7aAV229DLp1IQ7YkyUBO86fMy9
+Xvsiu+f+uXc/WT/7
+-----END CERTIFICATE-----
+        </Certificate>
+        <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICizCCAjKgAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMIGYMQswCQYDVQQG
+EwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmll
+dzEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMTMwMQYD
+VQQDDCpBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVzdGF0aW9uIFJvb3Qw
+HhcNMTYwMTExMDA0MzUwWhcNMzYwMTA2MDA0MzUwWjCBmDELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT
+BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEzMDEGA1UEAwwq
+QW5kcm9pZCBLZXlzdG9yZSBTb2Z0d2FyZSBBdHRlc3RhdGlvbiBSb290MFkwEwYH
+KoZIzj0CAQYIKoZIzj0DAQcDQgAE7l1ex+HA220Dpn7mthvsTWpdamguD/9/SQ59
+dx9EIm29sa/6FsvHrcV30lacqrewLVQBXT5DKyqO107sSHVBpKNjMGEwHQYDVR0O
+BBYEFMit6XdMRcOjzw0WEOR5QzohWjDPMB8GA1UdIwQYMBaAFMit6XdMRcOjzw0W
+EOR5QzohWjDPMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKEMAoGCCqG
+SM49BAMCA0cAMEQCIDUho++LNEYenNVg8x1YiSBq3KNlQfYNns6KGYxmSGB7AiBN
+C/NR2TB8fVvaNTQdqEcbY6WFZTytTySn502vQX3xvw==
+-----END CERTIFICATE-----
+        </Certificate>
+      </CertificateChain>
+    </Key>
+  </Keybox>
+</AndroidAttestation>
diff --git a/trusty/keymaster/set_attestation_key/set_attestation_key.cpp b/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
new file mode 100644
index 0000000..a89a4a8
--- /dev/null
+++ b/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <getopt.h>
+#include <libxml/xmlreader.h>
+#include <openssl/pem.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <string>
+
+using std::string;
+
+#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
+
+static const char* _sopts = "h";
+static const struct option _lopts[] = {
+        {"help", no_argument, 0, 'h'},
+        {0, 0, 0, 0},
+};
+
+static const char* usage =
+        "Usage: %s [options] xml-file\n"
+        "\n"
+        "options:\n"
+        "  -h, --help            prints this message and exit\n"
+        "\n";
+
+static void print_usage_and_exit(const char* prog, int code) {
+    fprintf(stderr, usage, prog);
+    exit(code);
+}
+
+static void parse_options(int argc, char** argv) {
+    int c;
+    int oidx = 0;
+
+    while (1) {
+        c = getopt_long(argc, argv, _sopts, _lopts, &oidx);
+        if (c == -1) {
+            break; /* done */
+        }
+
+        switch (c) {
+            case 'h':
+                print_usage_and_exit(argv[0], EXIT_SUCCESS);
+                break;
+
+            default:
+                print_usage_and_exit(argv[0], EXIT_FAILURE);
+        }
+    }
+}
+
+struct SetAttestationKeyRequest : public keymaster::KeymasterMessage {
+    explicit SetAttestationKeyRequest(int32_t ver = keymaster::MAX_MESSAGE_VERSION)
+        : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return sizeof(uint32_t) + key_data.SerializedSize(); }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        buf = keymaster::append_uint32_to_buf(buf, end, algorithm);
+        return key_data.Serialize(buf, end);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return keymaster::copy_uint32_from_buf(buf_ptr, end, &algorithm) &&
+               key_data.Deserialize(buf_ptr, end);
+    }
+
+    keymaster_algorithm_t algorithm;
+    keymaster::Buffer key_data;
+};
+
+struct KeymasterNoResponse : public keymaster::KeymasterResponse {
+    explicit KeymasterNoResponse(int32_t ver = keymaster::MAX_MESSAGE_VERSION)
+        : keymaster::KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override { return 0; }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
+};
+
+struct SetAttestationKeyResponse : public KeymasterNoResponse {};
+
+struct ClearAttestationCertChainRequest : public keymaster::KeymasterMessage {
+    explicit ClearAttestationCertChainRequest(int32_t ver = keymaster::MAX_MESSAGE_VERSION)
+        : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return sizeof(uint32_t); }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        return keymaster::append_uint32_to_buf(buf, end, algorithm);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return keymaster::copy_uint32_from_buf(buf_ptr, end, &algorithm);
+    }
+
+    keymaster_algorithm_t algorithm;
+};
+
+struct ClearAttestationCertChainResponse : public KeymasterNoResponse {};
+
+static int set_attestation_key_or_cert_bin(uint32_t cmd, keymaster_algorithm_t algorithm,
+                                           const void* key_data, size_t key_data_size) {
+    int ret;
+
+    SetAttestationKeyRequest req;
+    req.algorithm = algorithm;
+    req.key_data.Reinitialize(key_data, key_data_size);
+    SetAttestationKeyResponse rsp;
+
+    ret = trusty_keymaster_send(cmd, req, &rsp);
+    if (ret) {
+        fprintf(stderr, "trusty_keymaster_send cmd 0x%x failed %d\n", cmd, ret);
+        return ret;
+    }
+
+    return 0;
+}
+
+static int set_attestation_key_or_cert_pem(uint32_t cmd, keymaster_algorithm_t algorithm,
+                                           const xmlChar* pemkey) {
+    int ret;
+    int sslret;
+
+    /* Convert from pem to binary */
+    BIO* bio = BIO_new_mem_buf(pemkey, xmlStrlen(pemkey));
+    if (!bio) {
+        fprintf(stderr, "BIO_new_mem_buf failed\n");
+        ERR_print_errors_fp(stderr);
+        return -1;
+    }
+
+    char* key_name;
+    char* key_header;
+    uint8_t* key;
+    long keylen;
+    sslret = PEM_read_bio(bio, &key_name, &key_header, &key, &keylen);
+    BIO_free(bio);
+
+    if (!sslret) {
+        fprintf(stderr, "PEM_read_bio failed\n");
+        ERR_print_errors_fp(stderr);
+        return -1;
+    }
+
+    /* Send key in binary format to trusty */
+    ret = set_attestation_key_or_cert_bin(cmd, algorithm, key, keylen);
+
+    OPENSSL_free(key_name);
+    OPENSSL_free(key_header);
+    OPENSSL_free(key);
+
+    return ret;
+}
+
+static int set_attestation_key_or_cert_iecs(uint32_t cmd, keymaster_algorithm_t algorithm,
+                                            const xmlChar* key_base64) {
+    int ret;
+    int sslret;
+
+    /* Remove all whitespace. EVP_DecodeBase64 does not support whitespace. */
+    string key_base64_str((const char*)key_base64);
+    key_base64_str.erase(remove_if(key_base64_str.begin(), key_base64_str.end(), isspace),
+                         key_base64_str.end());
+
+    /* Convert from base64 to binary */
+    uint8_t* key;
+    size_t keylen;
+    size_t key_base64_len = key_base64_str.length();
+
+    sslret = EVP_DecodedLength(&keylen, key_base64_len);
+    if (!sslret) {
+        fprintf(stderr, "invalid input length, %zu\n", key_base64_len);
+        return -1;
+    }
+    key = (uint8_t*)malloc(keylen);
+    if (!key) {
+        fprintf(stderr, "failed to allocate key, size %zu\n", key_base64_len);
+        return -1;
+    }
+    sslret = EVP_DecodeBase64(key, &keylen, keylen, (const uint8_t*)key_base64_str.data(),
+                              key_base64_len);
+    if (!sslret) {
+        fprintf(stderr, "EVP_DecodeBase64 failed\n");
+        ERR_print_errors_fp(stderr);
+        free(key);
+        return -1;
+    }
+
+    /* Send key in binary format to trusty */
+    ret = set_attestation_key_or_cert_bin(cmd, algorithm, key, keylen);
+
+    free(key);
+
+    return ret;
+}
+
+static int str_to_algorithm(keymaster_algorithm_t* algorithm, const xmlChar* algorithm_str) {
+    if (xmlStrEqual(algorithm_str, BAD_CAST "rsa")) {
+        *algorithm = KM_ALGORITHM_RSA;
+    } else if (xmlStrEqual(algorithm_str, BAD_CAST "ecdsa")) {
+        *algorithm = KM_ALGORITHM_EC;
+    } else {
+        printf("unsupported algorithm: %s\n", algorithm_str);
+        return -1;
+    }
+    return 0;
+}
+
+static int set_attestation_key_or_cert(uint32_t cmd, const xmlChar* algorithm_str,
+                                       const xmlChar* format, const xmlChar* str) {
+    int ret;
+    keymaster_algorithm_t algorithm;
+
+    ret = str_to_algorithm(&algorithm, algorithm_str);
+    if (ret) {
+        return ret;
+    }
+
+    if (xmlStrEqual(format, BAD_CAST "pem")) {
+        ret = set_attestation_key_or_cert_pem(cmd, algorithm, str);
+    } else if (xmlStrEqual(format, BAD_CAST "iecs")) {
+        ret = set_attestation_key_or_cert_iecs(cmd, algorithm, str);
+    } else {
+        printf("unsupported key/cert format: %s\n", format);
+        return -1;
+    }
+    return ret;
+}
+
+static int clear_cert_chain(const xmlChar* algorithm_str) {
+    int ret;
+    ClearAttestationCertChainRequest req;
+    ClearAttestationCertChainResponse rsp;
+
+    ret = str_to_algorithm(&req.algorithm, algorithm_str);
+    if (ret) {
+        return ret;
+    }
+
+    ret = trusty_keymaster_send(KM_CLEAR_ATTESTATION_CERT_CHAIN, req, &rsp);
+    if (ret) {
+        fprintf(stderr, "%s: trusty_keymaster_send failed %d\n", __func__, ret);
+        return ret;
+    }
+    return 0;
+}
+
+static int process_xml(xmlTextReaderPtr xml) {
+    int ret;
+    const xmlChar* algorithm = NULL;
+    const xmlChar* element = NULL;
+    const xmlChar* element_format = NULL;
+
+    while ((ret = xmlTextReaderRead(xml)) == 1) {
+        int nodetype = xmlTextReaderNodeType(xml);
+        const xmlChar *name, *value;
+        name = xmlTextReaderConstName(xml);
+        switch (nodetype) {
+            case XML_READER_TYPE_ELEMENT:
+                element = name;
+                element_format = xmlTextReaderGetAttribute(xml, BAD_CAST "format");
+                if (xmlStrEqual(name, BAD_CAST "Key")) {
+                    algorithm = xmlTextReaderGetAttribute(xml, BAD_CAST "algorithm");
+                } else if (xmlStrEqual(name, BAD_CAST "CertificateChain")) {
+                    ret = clear_cert_chain(algorithm);
+                    if (ret) {
+                        fprintf(stderr, "%s, algorithm %s: Clear cert chain cmd failed, %d\n",
+                                element, algorithm, ret);
+                        return ret;
+                    }
+                    printf("%s, algorithm %s: Clear cert chain cmd done\n", element, algorithm);
+                }
+                break;
+            case XML_READER_TYPE_TEXT:
+                value = xmlTextReaderConstValue(xml);
+                uint32_t cmd;
+                if (xmlStrEqual(element, BAD_CAST "PrivateKey")) {
+                    cmd = KM_SET_ATTESTATION_KEY;
+                } else if (xmlStrEqual(element, BAD_CAST "WrappedPrivateKey")) {
+                    cmd = KM_SET_WRAPPED_ATTESTATION_KEY;
+                } else if (xmlStrEqual(element, BAD_CAST "Certificate")) {
+                    cmd = KM_APPEND_ATTESTATION_CERT_CHAIN;
+                } else {
+                    break;
+                }
+
+                ret = set_attestation_key_or_cert(cmd, algorithm, element_format, value);
+                if (ret) {
+                    fprintf(stderr, "%s, algorithm %s, format %s: Cmd 0x%x failed, %d\n", element,
+                            algorithm, element_format, cmd, ret);
+                    return ret;
+                }
+                printf("%s, algorithm %s, format %s: Cmd 0x%x done\n", element, algorithm,
+                       element_format, cmd);
+                break;
+            case XML_READER_TYPE_END_ELEMENT:
+                element = NULL;
+                break;
+        }
+    }
+    return ret;
+}
+
+static int parse_xml_file(const char* filename) {
+    int ret;
+    xmlTextReaderPtr xml = xmlReaderForFile(filename, NULL, 0);
+    if (!xml) {
+        fprintf(stderr, "failed to open %s\n", filename);
+        return -1;
+    }
+
+    ret = process_xml(xml);
+
+    xmlFreeTextReader(xml);
+    if (ret != 0) {
+        fprintf(stderr, "Failed to parse or process %s\n", filename);
+        return -1;
+    }
+
+    return 0;
+}
+
+int main(int argc, char** argv) {
+    int ret = 0;
+
+    parse_options(argc, argv);
+    if (optind + 1 != argc) {
+        print_usage_and_exit(argv[0], EXIT_FAILURE);
+    }
+
+    ret = trusty_keymaster_connect();
+    if (ret) {
+        fprintf(stderr, "trusty_keymaster_connect failed %d\n", ret);
+    } else {
+        ret = parse_xml_file(argv[optind]);
+        trusty_keymaster_disconnect();
+    }
+
+    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/trusty/libtrusty/include/trusty/ipc.h b/trusty/libtrusty/include/trusty/ipc.h
new file mode 100644
index 0000000..1fa6fe4
--- /dev/null
+++ b/trusty/libtrusty/include/trusty/ipc.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 _UAPI_LINUX_TRUSTY_IPC_H_
+#define _UAPI_LINUX_TRUSTY_IPC_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/uio.h>
+
+/**
+ * enum transfer_kind - How to send an fd to Trusty
+ * @TRUSTY_SHARE: Memory will be accessible by Linux and Trusty. On ARM it will
+ *                be mapped as nonsecure. Suitable for shared memory. The paired
+ *                fd must be a "memfd".
+ * @TRUSTY_LEND:  Memory will be accessible only to Trusty. On ARM it will be
+ *                transitioned to "Secure" memory if Trusty is in TrustZone.
+ *                This transfer kind is suitable for donating video buffers or
+ *                other similar resources. The paired fd may need to come from a
+ *                platform-specific allocator for memory that may be
+ *                transitioned to "Secure".
+ *
+ * Describes how the user would like the resource in question to be sent to
+ * Trusty. Options may be valid only for certain kinds of fds.
+ */
+enum transfer_kind {
+    TRUSTY_SHARE = 0,
+    TRUSTY_LEND = 1,
+};
+
+/**
+ * struct trusty_shm - Describes a transfer of memory to Trusty
+ * @fd:       The fd to transfer
+ * @transfer: How to transfer it - see &enum transfer_kind
+ */
+struct trusty_shm {
+    __s32 fd;
+    __u32 transfer;
+};
+
+/**
+ * struct tipc_send_msg_req - Request struct for @TIPC_IOC_SEND_MSG
+ * @iov:     Pointer to an array of &struct iovec describing data to be sent
+ * @shm:     Pointer to an array of &struct trusty_shm describing any file
+ *           descriptors to be transferred.
+ * @iov_cnt: Number of elements in the @iov array
+ * @shm_cnt: Number of elements in the @shm array
+ */
+struct tipc_send_msg_req {
+    __u64 iov;
+    __u64 shm;
+    __u64 iov_cnt;
+    __u64 shm_cnt;
+};
+
+#define TIPC_IOC_MAGIC 'r'
+#define TIPC_IOC_CONNECT _IOW(TIPC_IOC_MAGIC, 0x80, char*)
+#define TIPC_IOC_SEND_MSG _IOW(TIPC_IOC_MAGIC, 0x81, struct tipc_send_msg_req)
+
+#if defined(CONFIG_COMPAT)
+#define TIPC_IOC_CONNECT_COMPAT _IOW(TIPC_IOC_MAGIC, 0x80, compat_uptr_t)
+#endif
+
+#endif
diff --git a/trusty/libtrusty/include/trusty/tipc.h b/trusty/libtrusty/include/trusty/tipc.h
index a3f2a3f..b44afd3 100644
--- a/trusty/libtrusty/include/trusty/tipc.h
+++ b/trusty/libtrusty/include/trusty/tipc.h
@@ -21,7 +21,11 @@
 extern "C" {
 #endif
 
+#include <sys/uio.h>
+#include <trusty/ipc.h>
+
 int tipc_connect(const char *dev_name, const char *srv_name);
+ssize_t tipc_send(int fd, const struct iovec* iov, int iovcnt, struct trusty_shm* shm, int shmcnt);
 int tipc_close(int fd);
 
 #ifdef __cplusplus
diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c
index d20d4ee..ca581dc 100644
--- a/trusty/libtrusty/tipc-test/tipc_test.c
+++ b/trusty/libtrusty/tipc-test/tipc_test.c
@@ -21,6 +21,8 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <getopt.h>
+#define __USE_GNU
+#include <sys/mman.h>
 #include <sys/uio.h>
 
 #include <trusty/tipc.h>
@@ -39,6 +41,7 @@
 static const char *closer2_name = "com.android.ipc-unittest.srv.closer2";
 static const char *closer3_name = "com.android.ipc-unittest.srv.closer3";
 static const char *main_ctrl_name = "com.android.ipc-unittest.ctrl";
+static const char* receiver_name = "com.android.trusty.memref.receiver";
 
 static const char *_sopts = "hsvD:t:r:m:b:";
 static const struct option _lopts[] =  {
@@ -66,25 +69,25 @@
 "\n"
 ;
 
-static const char *usage_long =
-"\n"
-"The following tests are available:\n"
-"   connect      - connect to datasink service\n"
-"   connect_foo  - connect to non existing service\n"
-"   burst_write  - send messages to datasink service\n"
-"   echo         - send/receive messages to echo service\n"
-"   select       - test select call\n"
-"   blocked_read - test blocked read\n"
-"   closer1      - connection closed by remote (test1)\n"
-"   closer2      - connection closed by remote (test2)\n"
-"   closer3      - connection closed by remote (test3)\n"
-"   ta2ta-ipc    - execute TA to TA unittest\n"
-"   dev-uuid     - print device uuid\n"
-"   ta-access    - test ta-access flags\n"
-"   writev       - writev test\n"
-"   readv        - readv test\n"
-"\n"
-;
+static const char* usage_long =
+        "\n"
+        "The following tests are available:\n"
+        "   connect      - connect to datasink service\n"
+        "   connect_foo  - connect to non existing service\n"
+        "   burst_write  - send messages to datasink service\n"
+        "   echo         - send/receive messages to echo service\n"
+        "   select       - test select call\n"
+        "   blocked_read - test blocked read\n"
+        "   closer1      - connection closed by remote (test1)\n"
+        "   closer2      - connection closed by remote (test2)\n"
+        "   closer3      - connection closed by remote (test3)\n"
+        "   ta2ta-ipc    - execute TA to TA unittest\n"
+        "   dev-uuid     - print device uuid\n"
+        "   ta-access    - test ta-access flags\n"
+        "   writev       - writev test\n"
+        "   readv        - readv test\n"
+        "   send-fd      - transmit memfd to trusty, use as shm\n"
+        "\n";
 
 static uint opt_repeat  = 1;
 static uint opt_msgsize = 32;
@@ -885,6 +888,66 @@
 	return 0;
 }
 
+static int send_fd_test(void) {
+    int ret;
+    int memfd = -1;
+    int fd = -1;
+    volatile char* buf = MAP_FAILED;
+
+    fd = tipc_connect(dev_name, receiver_name);
+    if (fd < 0) {
+        fprintf(stderr, "Failed to connect to test support TA - is it missing?\n");
+        ret = -1;
+        goto cleanup;
+    }
+
+    memfd = memfd_create("tipc-send-fd", 0);
+    if (memfd < 0) {
+        fprintf(stderr, "Failed to create memfd: %s\n", strerror(errno));
+        ret = -1;
+        goto cleanup;
+    }
+
+    if (ftruncate(memfd, PAGE_SIZE) < 0) {
+        fprintf(stderr, "Failed to resize memfd: %s\n", strerror(errno));
+        ret = -1;
+        goto cleanup;
+    }
+
+    buf = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, memfd, 0);
+    if (buf == MAP_FAILED) {
+        fprintf(stderr, "Failed to map memfd: %s\n", strerror(errno));
+        ret = -1;
+        goto cleanup;
+    }
+
+    strcpy((char*)buf, "From NS");
+
+    struct trusty_shm shm = {
+            .fd = memfd,
+            .transfer = TRUSTY_SHARE,
+    };
+
+    ssize_t rc = tipc_send(fd, NULL, 0, &shm, 1);
+    if (rc < 0) {
+        fprintf(stderr, "tipc_send failed\n");
+        ret = rc;
+        goto cleanup;
+    }
+    char c;
+    read(fd, &c, 1);
+    tipc_close(fd);
+
+    ret = strcmp("Hello from Trusty!", (const char*)buf) ? (-1) : 0;
+
+cleanup:
+    if (buf != MAP_FAILED) {
+        munmap((char*)buf, PAGE_SIZE);
+    }
+    close(memfd);
+    tipc_close(fd);
+    return ret;
+}
 
 int main(int argc, char **argv)
 {
@@ -933,10 +996,12 @@
 		rc = writev_test(opt_repeat, opt_msgsize, opt_variable);
 	} else if (strcmp(test_name, "readv") == 0) {
 		rc = readv_test(opt_repeat, opt_msgsize, opt_variable);
-	} else {
-		fprintf(stderr, "Unrecognized test name '%s'\n", test_name);
-		print_usage_and_exit(argv[0], EXIT_FAILURE, true);
-	}
+    } else if (strcmp(test_name, "send-fd") == 0) {
+        rc = send_fd_test();
+    } else {
+        fprintf(stderr, "Unrecognized test name '%s'\n", test_name);
+        print_usage_and_exit(argv[0], EXIT_FAILURE, true);
+    }
 
-	return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+    return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
 }
diff --git a/trusty/libtrusty/tipc_ioctl.h b/trusty/libtrusty/tipc_ioctl.h
deleted file mode 100644
index 27da56a..0000000
--- a/trusty/libtrusty/tipc_ioctl.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 _TIPC_IOCTL_H
-#define _TIPC_IOCTL_H
-
-#include <linux/ioctl.h>
-#include <linux/types.h>
-
-#define TIPC_IOC_MAGIC			'r'
-#define TIPC_IOC_CONNECT		_IOW(TIPC_IOC_MAGIC, 0x80, char *)
-
-#endif
diff --git a/trusty/libtrusty/trusty.c b/trusty/libtrusty/trusty.c
index a6238af..ad4d8cd 100644
--- a/trusty/libtrusty/trusty.c
+++ b/trusty/libtrusty/trusty.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,7 +27,7 @@
 
 #include <log/log.h>
 
-#include "tipc_ioctl.h"
+#include <trusty/ipc.h>
 
 int tipc_connect(const char *dev_name, const char *srv_name)
 {
@@ -55,6 +55,22 @@
 	return fd;
 }
 
+ssize_t tipc_send(int fd, const struct iovec* iov, int iovcnt, struct trusty_shm* shms,
+                  int shmcnt) {
+    struct tipc_send_msg_req req;
+    req.iov = (__u64)iov;
+    req.iov_cnt = (__u64)iovcnt;
+    req.shm = (__u64)shms;
+    req.shm_cnt = (__u64)shmcnt;
+
+    int rc = ioctl(fd, TIPC_IOC_SEND_MSG, &req);
+    if (rc < 0) {
+        ALOGE("%s: failed to send message (err=%d)\n", __func__, rc);
+    }
+
+    return rc;
+}
+
 void tipc_close(int fd)
 {
 	close(fd);
diff --git a/trusty/trusty-test.mk b/trusty/trusty-test.mk
new file mode 100644
index 0000000..dc4c962
--- /dev/null
+++ b/trusty/trusty-test.mk
@@ -0,0 +1,18 @@
+# Copyright (C) 2020 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+PRODUCT_PACKAGES += \
+	spiproxyd \
+	trusty_keymaster_set_attestation_key \
+	keymaster_soft_attestation_keys.xml \
\ No newline at end of file
diff --git a/trusty/utils/spiproxyd/Android.bp b/trusty/utils/spiproxyd/Android.bp
new file mode 100644
index 0000000..c1d0987
--- /dev/null
+++ b/trusty/utils/spiproxyd/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2020 The Android Open-Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+    name: "spiproxyd",
+    vendor: true,
+
+    srcs: [
+        "main.c",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libtrusty",
+    ],
+
+    init_rc: [
+        "proxy.rc",
+    ],
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/trusty/utils/spiproxyd/main.c b/trusty/utils/spiproxyd/main.c
new file mode 100644
index 0000000..c10866b
--- /dev/null
+++ b/trusty/utils/spiproxyd/main.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "spiproxyd"
+
+#include <assert.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <log/log.h>
+#include <stdlib.h>
+#include <string.h>
+#include <trusty/tipc.h>
+#include <unistd.h>
+
+int handle_msg(int trusty_dev_fd, int spi_dev_fd) {
+    int rc;
+    uint8_t msg_buf[4096];
+    size_t msg_len;
+
+    /* read request from SPI Trusty app */
+    rc = read(trusty_dev_fd, &msg_buf, sizeof(msg_buf));
+    if (rc < 0) {
+        ALOGE("failed (%d) to read request from TA\n", rc);
+        return rc;
+    }
+    msg_len = rc;
+
+    /* forward request to SPI host device */
+    rc = write(spi_dev_fd, &msg_buf, msg_len);
+    if (rc < 0 || (size_t)rc != msg_len) {
+        ALOGE("failed (%d) to forward request to host\n", rc);
+        return rc < 0 ? rc : -1;
+    }
+
+    /* read response from SPI host device */
+    rc = read(spi_dev_fd, &msg_buf, sizeof(msg_buf));
+    if (rc < 0) {
+        ALOGE("failed (%d) to read response from host\n", rc);
+        return rc;
+    }
+    msg_len = rc;
+
+    /* forward response to SPI Trusty app */
+    rc = write(trusty_dev_fd, &msg_buf, msg_len);
+    if (rc < 0 || (size_t)rc != msg_len) {
+        ALOGE("failed (%d) to forward response to TA\n", rc);
+        return rc < 0 ? rc : -1;
+    }
+
+    return 0;
+}
+
+int event_loop(int trusty_dev_fd, int spi_dev_fd) {
+    while (true) {
+        int rc = handle_msg(trusty_dev_fd, spi_dev_fd);
+        if (rc < 0) {
+            ALOGE("exiting event loop\n");
+            return EXIT_FAILURE;
+        }
+    }
+}
+
+static void show_usage() {
+    ALOGE("usage: spiproxyd -t TRUSTY_DEVICE -s SPI_DEVICE -p SPI_PROXY_PORT\n");
+}
+
+static void parse_args(int argc, char* argv[], const char** trusty_dev_name,
+                       const char** spi_dev_name, const char** spi_proxy_port) {
+    int opt;
+    while ((opt = getopt(argc, argv, "ht:s:p:")) != -1) {
+        switch (opt) {
+            case 'h':
+                show_usage();
+                exit(EXIT_SUCCESS);
+                break;
+            case 't':
+                *trusty_dev_name = strdup(optarg);
+                break;
+            case 's':
+                *spi_dev_name = strdup(optarg);
+                break;
+            case 'p':
+                *spi_proxy_port = strdup(optarg);
+                break;
+            default:
+                show_usage();
+                exit(EXIT_FAILURE);
+                break;
+        }
+    }
+
+    if (!*trusty_dev_name || !*spi_dev_name || !*spi_proxy_port) {
+        show_usage();
+        exit(EXIT_FAILURE);
+    }
+}
+
+int main(int argc, char* argv[]) {
+    int rc;
+    const char* trusty_dev_name = NULL;
+    const char* spi_dev_name = NULL;
+    const char* spi_proxy_port = NULL;
+    int trusty_dev_fd;
+    int spi_dev_fd;
+
+    parse_args(argc, argv, &trusty_dev_name, &spi_dev_name, &spi_proxy_port);
+
+    rc = tipc_connect(trusty_dev_name, spi_proxy_port);
+    if (rc < 0) {
+        ALOGE("failed (%d) to connect to SPI proxy port\n", rc);
+        return rc;
+    }
+    trusty_dev_fd = rc;
+
+    rc = open(spi_dev_name, O_RDWR, 0);
+    if (rc < 0) {
+        ALOGE("failed (%d) to open SPI device\n", rc);
+        return rc;
+    }
+    spi_dev_fd = rc;
+
+    return event_loop(trusty_dev_fd, spi_dev_fd);
+}
diff --git a/trusty/utils/spiproxyd/proxy.rc b/trusty/utils/spiproxyd/proxy.rc
new file mode 100644
index 0000000..7d63e6a
--- /dev/null
+++ b/trusty/utils/spiproxyd/proxy.rc
@@ -0,0 +1,20 @@
+# Copyright (C) 2020 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+service spiproxyd /vendor/bin/spiproxyd -t /dev/trusty-ipc-dev0 \
+        -s /dev/vport3p2 -p com.android.trusty.spi.proxy
+    class main
+    user system
+    group system
+    oneshot