Merge changes Ib4fb6c27,I9c41b483,I40372758,Ic787ce17

* changes:
  vulkan: update Vulkan headers to 1.0.43
  vulkan: update Vulkan headers to 1.0.42
  vulkan: update Vulkan headers to 1.0.41
  vulkan: update Vulkan headers to 1.0.39
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index a61cb00..66beb6d 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -23,6 +23,7 @@
 
 #include <android-base/file.h>
 #include <utils/String16.h>
+#include <utils/String8.h>
 #include <utils/Vector.h>
 
 using namespace android;
@@ -95,7 +96,7 @@
     int i = 0;
     std::ostringstream actual_stream, expected_stream;
     for (String16 actual : arg) {
-        std::string actual_str = String16::std_string(actual);
+        std::string actual_str = String8(actual).c_str();
         std::string expected_str = expected[i];
         actual_stream << "'" << actual_str << "' ";
         expected_stream << "'" << expected_str << "' ";
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 5c04f6c..dfc3e58 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -25,7 +25,6 @@
  namespace android {
 
 GLHelper::GLHelper() :
-    mGraphicBufferAlloc(new GraphicBufferAlloc()),
     mDisplay(EGL_NO_DISPLAY),
     mContext(EGL_NO_CONTEXT),
     mDummySurface(EGL_NO_SURFACE),
@@ -203,7 +202,7 @@
         sp<GLConsumer>* glConsumer, EGLSurface* surface) {
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
-    BufferQueue::createBufferQueue(&producer, &consumer, mGraphicBufferAlloc);
+    BufferQueue::createBufferQueue(&producer, &consumer);
     sp<GLConsumer> glc = new GLConsumer(consumer, name,
             GL_TEXTURE_EXTERNAL_OES, false, true);
     glc->setDefaultBufferSize(w, h);
diff --git a/cmds/flatland/GLHelper.h b/cmds/flatland/GLHelper.h
index 7a9e9e3..d09463a 100644
--- a/cmds/flatland/GLHelper.h
+++ b/cmds/flatland/GLHelper.h
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <gui/GraphicBufferAlloc.h>
 #include <gui/GLConsumer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceControl.h>
@@ -75,8 +74,6 @@
 
     bool setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders);
 
-    sp<GraphicBufferAlloc> mGraphicBufferAlloc;
-
     EGLDisplay mDisplay;
     EGLContext mContext;
     EGLSurface mDummySurface;
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index c47b0c8..ec1e543 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -16,7 +16,6 @@
 
 #define ATRACE_TAG ATRACE_TAG_ALWAYS
 
-#include <gui/GraphicBufferAlloc.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceControl.h>
 #include <gui/GLConsumer.h>
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index fbb30db..71595f0 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -426,12 +426,11 @@
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
-    const char* pkgname = packageName.c_str();
     binder::Status res = ok();
-    if (!clear_reference_profile(pkgname)) {
+    if (!clear_reference_profile(packageName)) {
         res = error("Failed to clear reference profile for " + packageName);
     }
-    if (!clear_current_profiles(pkgname)) {
+    if (!clear_current_profiles(packageName)) {
         res = error("Failed to clear current profiles for " + packageName);
     }
     return res;
@@ -479,7 +478,7 @@
             }
         }
         if (!only_cache) {
-            if (!clear_current_profile(pkgname, userId)) {
+            if (!clear_current_profile(packageName, userId)) {
                 res = error("Failed to clear current profile for " + packageName);
             }
         }
@@ -487,13 +486,13 @@
     return res;
 }
 
-static int destroy_app_reference_profile(const char *pkgname) {
+static int destroy_app_reference_profile(const std::string& pkgname) {
     return delete_dir_contents_and_dir(
         create_data_ref_profile_package_path(pkgname),
         /*ignore_if_missing*/ true);
 }
 
-static int destroy_app_current_profiles(const char *pkgname, userid_t userid) {
+static int destroy_app_current_profiles(const std::string& pkgname, userid_t userid) {
     return delete_dir_contents_and_dir(
         create_data_user_profile_package_path(userid, pkgname),
         /*ignore_if_missing*/ true);
@@ -504,15 +503,14 @@
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
-    const char* pkgname = packageName.c_str();
     binder::Status res = ok();
     std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
     for (auto user : users) {
-        if (destroy_app_current_profiles(pkgname, user) != 0) {
+        if (destroy_app_current_profiles(packageName, user) != 0) {
             res = error("Failed to destroy current profiles for " + packageName);
         }
     }
-    if (destroy_app_reference_profile(pkgname) != 0) {
+    if (destroy_app_reference_profile(packageName) != 0) {
         res = error("Failed to destroy reference profile for " + packageName);
     }
     return res;
@@ -540,11 +538,11 @@
         if (delete_dir_contents_and_dir(path) != 0) {
             res = error("Failed to delete " + path);
         }
-        destroy_app_current_profiles(pkgname, userId);
+        destroy_app_current_profiles(packageName, userId);
         // TODO(calin): If the package is still installed by other users it's probably
         // beneficial to keep the reference profile around.
         // Verify if it's ok to do that.
-        destroy_app_reference_profile(pkgname);
+        destroy_app_reference_profile(packageName);
     }
     return res;
 }
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 0fb207b..58b9d2c 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -101,19 +101,19 @@
     return truncated;
 }
 
-bool clear_reference_profile(const char* pkgname) {
+bool clear_reference_profile(const std::string& pkgname) {
     std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
     std::string reference_profile = create_primary_profile(reference_profile_dir);
     return clear_profile(reference_profile);
 }
 
-bool clear_current_profile(const char* pkgname, userid_t user) {
+bool clear_current_profile(const std::string& pkgname, userid_t user) {
     std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
     std::string profile = create_primary_profile(profile_dir);
     return clear_profile(profile);
 }
 
-bool clear_current_profiles(const char* pkgname) {
+bool clear_current_profiles(const std::string& pkgname) {
     bool success = true;
     std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
     for (auto user : users) {
@@ -512,12 +512,12 @@
     return profile_fd;
 }
 
-static fd_t open_primary_profile_file(userid_t user, const char* pkgname) {
+static fd_t open_primary_profile_file(userid_t user, const std::string& pkgname) {
     std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
     return open_primary_profile_file_from_dir(profile_dir, O_RDONLY);
 }
 
-static fd_t open_reference_profile(uid_t uid, const char* pkgname, bool read_write) {
+static fd_t open_reference_profile(uid_t uid, const std::string& pkgname, bool read_write) {
     std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
     int flags = read_write ? O_RDWR | O_CREAT : O_RDONLY;
     fd_t fd = open_primary_profile_file_from_dir(reference_profile_dir, flags);
@@ -534,7 +534,7 @@
     return fd;
 }
 
-static void open_profile_files(uid_t uid, const char* pkgname,
+static void open_profile_files(uid_t uid, const std::string& pkgname,
             /*out*/ std::vector<fd_t>* profiles_fd, /*out*/ fd_t* reference_profile_fd) {
     // Open the reference profile in read-write mode as profman might need to save the merge.
     *reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ true);
@@ -614,7 +614,7 @@
 // a re-compilation of the package.
 // If the return value is true all the current profiles would have been merged into
 // the reference profiles accessible with open_reference_profile().
-bool analyse_profiles(uid_t uid, const char* pkgname) {
+bool analyse_profiles(uid_t uid, const std::string& pkgname) {
     std::vector<fd_t> profiles_fd;
     fd_t reference_profile_fd = -1;
     open_profile_files(uid, pkgname, &profiles_fd, &reference_profile_fd);
@@ -628,8 +628,6 @@
         return false;
     }
 
-    ALOGV("PROFMAN (MERGE): --- BEGIN '%s' ---\n", pkgname);
-
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
@@ -740,12 +738,10 @@
     }
 }
 
-bool dump_profiles(int32_t uid, const char* pkgname, const char* code_paths) {
+bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths) {
     std::vector<fd_t> profile_fds;
     fd_t reference_profile_fd = -1;
-    std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname);
-
-    ALOGV("PROFMAN (DUMP): --- BEGIN '%s' ---\n", pkgname);
+    std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname.c_str());
 
     open_profile_files(uid, pkgname, &profile_fds, &reference_profile_fd);
 
@@ -753,7 +749,7 @@
     const bool has_profiles = !profile_fds.empty();
 
     if (!has_reference_profile && !has_profiles) {
-        ALOGE("profman dump: no profiles to dump for '%s'", pkgname);
+        LOG(ERROR)  << "profman dump: no profiles to dump for " << pkgname;
         return false;
     }
 
@@ -1105,8 +1101,8 @@
 // Opens the vdex files and assigns the input fd to in_vdex_wrapper_fd and the output fd to
 // out_vdex_wrapper_fd. Returns true for success or false in case of errors.
 bool open_vdex_files(const char* apk_path, const char* out_oat_path, int dexopt_needed,
-        const char* instruction_set, bool is_public, int uid, bool is_secondary_dex,
-        Dex2oatFileWrapper* in_vdex_wrapper_fd,
+        const char* instruction_set, bool is_public, bool profile_guided,
+        int uid, bool is_secondary_dex, Dex2oatFileWrapper* in_vdex_wrapper_fd,
         Dex2oatFileWrapper* out_vdex_wrapper_fd) {
     CHECK(in_vdex_wrapper_fd != nullptr);
     CHECK(out_vdex_wrapper_fd != nullptr);
@@ -1116,7 +1112,9 @@
     int dexopt_action = abs(dexopt_needed);
     bool is_odex_location = dexopt_needed < 0;
     std::string in_vdex_path_str;
-    if (dexopt_action != DEX2OAT_FROM_SCRATCH) {
+    // Disable passing an input vdex when the compilation is profile-guided. The dexlayout
+    // optimization in dex2oat is incompatible with it. b/35872504.
+    if (dexopt_action != DEX2OAT_FROM_SCRATCH && !profile_guided) {
         // Open the possibly existing vdex. If none exist, we pass -1 to dex2oat for input-vdex-fd.
         const char* path = nullptr;
         if (is_odex_location) {
@@ -1135,7 +1133,7 @@
             return false;
         }
         if (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE) {
-            // When we dex2oat because iof boot image change, we are going to update
+            // When we dex2oat because of boot image change, we are going to update
             // in-place the vdex file.
             in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0));
         } else {
@@ -1449,8 +1447,8 @@
     // Open vdex files.
     Dex2oatFileWrapper in_vdex_fd;
     Dex2oatFileWrapper out_vdex_fd;
-    if (!open_vdex_files(dex_path, out_oat_path, dexopt_needed, instruction_set, is_public, uid,
-            is_secondary_dex, &in_vdex_fd, &out_vdex_fd)) {
+    if (!open_vdex_files(dex_path, out_oat_path, dexopt_needed, instruction_set, is_public,
+            profile_guided, uid, is_secondary_dex, &in_vdex_fd, &out_vdex_fd)) {
         return -1;
     }
 
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 7bb6eee..fab4d94 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -34,14 +34,14 @@
 
 typedef int fd_t;
 
-bool clear_reference_profile(const char* pkgname);
-bool clear_current_profile(const char* pkgname, userid_t user);
-bool clear_current_profiles(const char* pkgname);
+bool clear_reference_profile(const std::string& pkgname);
+bool clear_current_profile(const std::string& pkgname, userid_t user);
+bool clear_current_profiles(const std::string& pkgname);
 
 bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path);
 
-bool analyse_profiles(uid_t uid, const char* pkgname);
-bool dump_profiles(int32_t uid, const char* pkgname, const char* code_paths);
+bool analyse_profiles(uid_t uid, const std::string& pkgname);
+bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);
 
 bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path);
 
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 93a1458..850d257 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -36,6 +36,8 @@
 #define TEST_SYSTEM_DIR1 "/system/app/"
 #define TEST_SYSTEM_DIR2 "/vendor/app/"
 
+#define TEST_PROFILE_DIR "/data/misc/profiles"
+
 #define REALLY_LONG_APP_NAME "com.example." \
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
@@ -78,6 +80,9 @@
 
         android_system_dirs.dirs[1].path = (char*) TEST_SYSTEM_DIR2;
         android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2);
+
+        android_profiles_dir.path = (char*) TEST_PROFILE_DIR;
+        android_profiles_dir.len = strlen(TEST_PROFILE_DIR);
     }
 
     virtual void TearDown() {
@@ -519,5 +524,31 @@
     EXPECT_EQ(false, is_valid_package_name("/com.evil"));
 }
 
+TEST_F(UtilsTest, CreateDataUserProfilePath) {
+    EXPECT_EQ("/data/misc/profiles/cur/0", create_data_user_profile_path(0));
+    EXPECT_EQ("/data/misc/profiles/cur/1", create_data_user_profile_path(1));
+}
+
+TEST_F(UtilsTest, CreateDataUserProfilePackagePath) {
+    EXPECT_EQ("/data/misc/profiles/cur/0/com.example",
+            create_data_user_profile_package_path(0, "com.example"));
+    EXPECT_EQ("/data/misc/profiles/cur/1/com.example",
+            create_data_user_profile_package_path(1, "com.example"));
+}
+
+TEST_F(UtilsTest, CreateDataRefProfilePath) {
+    EXPECT_EQ("/data/misc/profiles/ref", create_data_ref_profile_path());
+}
+
+TEST_F(UtilsTest, CreateDataRefProfilePackagePath) {
+    EXPECT_EQ("/data/misc/profiles/ref/com.example",
+        create_data_ref_profile_package_path("com.example"));
+}
+
+TEST_F(UtilsTest, CreatePrimaryProfile) {
+    EXPECT_EQ("/data/misc/profiles/ref/com.example/primary.prof",
+        create_primary_profile("/data/misc/profiles/ref/com.example"));
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index af7a7c6..e5b243a 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -221,18 +221,18 @@
     return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid);
 }
 
-std::string create_data_user_profile_package_path(userid_t user, const char* package_name) {
-    check_package_name(package_name);
-    return StringPrintf("%s/%s",create_data_user_profile_path(user).c_str(), package_name);
+std::string create_data_user_profile_package_path(userid_t user, const std::string& package_name) {
+    check_package_name(package_name.c_str());
+    return StringPrintf("%s/%s",create_data_user_profile_path(user).c_str(), package_name.c_str());
 }
 
 std::string create_data_ref_profile_path() {
     return StringPrintf("%s/ref", android_profiles_dir.path);
 }
 
-std::string create_data_ref_profile_package_path(const char* package_name) {
-    check_package_name(package_name);
-    return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name);
+std::string create_data_ref_profile_package_path(const std::string& package_name) {
+    check_package_name(package_name.c_str());
+    return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name.c_str());
 }
 
 std::string create_data_dalvik_cache_path() {
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index d99b445..1c36a54 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -97,10 +97,10 @@
 std::string create_data_misc_legacy_path(userid_t userid);
 
 std::string create_data_user_profile_path(userid_t userid);
-std::string create_data_user_profile_package_path(userid_t user, const char* package_name);
+std::string create_data_user_profile_package_path(userid_t user, const std::string& package_name);
 
 std::string create_data_ref_profile_path();
-std::string create_data_ref_profile_package_path(const char* package_name);
+std::string create_data_ref_profile_package_path(const std::string& package_name);
 
 std::string create_data_dalvik_cache_path();
 
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 9e60461..8750147 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -160,14 +160,14 @@
 }
 
 void Lshal::forEachTable(const std::function<void(Table &)> &f) {
-    for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) {
-        f(const_cast<Table &>(table));
-    }
+    f(mServicesTable);
+    f(mPassthroughRefTable);
+    f(mImplementationsTable);
 }
 void Lshal::forEachTable(const std::function<void(const Table &)> &f) const {
-    for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) {
-        f(table);
-    }
+    f(mServicesTable);
+    f(mPassthroughRefTable);
+    f(mImplementationsTable);
 }
 
 void Lshal::postprocess() {
@@ -183,6 +183,26 @@
             }
         }
     });
+    // use a double for loop here because lshal doesn't care about efficiency.
+    for (TableEntry &packageEntry : mImplementationsTable) {
+        std::string packageName = packageEntry.interfaceName;
+        FQName fqPackageName{packageName.substr(0, packageName.find("::"))};
+        if (!fqPackageName.isValid()) {
+            continue;
+        }
+        for (TableEntry &interfaceEntry : mPassthroughRefTable) {
+            if (interfaceEntry.arch != ARCH_UNKNOWN) {
+                continue;
+            }
+            FQName interfaceName{splitFirst(interfaceEntry.interfaceName, '/').first};
+            if (!interfaceName.isValid()) {
+                continue;
+            }
+            if (interfaceName.getPackageAndVersion() == fqPackageName) {
+                interfaceEntry.arch = packageEntry.arch;
+            }
+        }
+    }
 }
 
 void Lshal::printLine(
@@ -247,10 +267,25 @@
                     &table == &mImplementationsTable ? "" : splittedFqInstanceName.second;
 
             vintf::Transport transport;
+            vintf::Arch arch;
             if (entry.transport == "hwbinder") {
                 transport = vintf::Transport::HWBINDER;
+                arch = vintf::Arch::ARCH_EMPTY;
             } else if (entry.transport == "passthrough") {
                 transport = vintf::Transport::PASSTHROUGH;
+                switch (entry.arch) {
+                    case lshal::ARCH32:
+                        arch = vintf::Arch::ARCH_32;    break;
+                    case lshal::ARCH64:
+                        arch = vintf::Arch::ARCH_64;    break;
+                    case lshal::ARCH_BOTH:
+                        arch = vintf::Arch::ARCH_32_64; break;
+                    case lshal::ARCH_UNKNOWN: // fallthrough
+                    default:
+                        mErr << "Warning: '" << fqName.package()
+                             << "' doesn't have bitness info, assuming 32+64." << std::endl;
+                        arch = vintf::Arch::ARCH_32_64;
+                }
             } else {
                 mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
                 continue;
@@ -262,7 +297,7 @@
                     .format = vintf::HalFormat::HIDL,
                     .name = fqName.package(),
                     .impl = {.implLevel = vintf::ImplLevel::GENERIC, .impl = ""},
-                    .transport = transport
+                    .transportArch = {transport, arch}
                 })) {
                     mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
                     continue;
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 2407b42..9ae8f78 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -37,8 +37,8 @@
 
 enum : unsigned int {
     ARCH_UNKNOWN = 0,
-    ARCH64       = 1 << 0,
-    ARCH32       = 1 << 1,
+    ARCH32       = 1 << 0,
+    ARCH64       = 1 << 1,
     ARCH_BOTH    = ARCH32 | ARCH64
 };
 using Architecture = unsigned int;
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index c95c535..bd62d85 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -23,10 +23,6 @@
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IConsumerListener.h>
 
-// These are only required to keep other parts of the framework with incomplete
-// dependencies building successfully
-#include <gui/IGraphicBufferAlloc.h>
-
 namespace android {
 
 class BufferQueue {
@@ -81,11 +77,9 @@
     // needed gralloc buffers.
     static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
             sp<IGraphicBufferConsumer>* outConsumer,
-            const sp<IGraphicBufferAlloc>& allocator = NULL,
             bool consumerIsSurfaceFlinger = false);
 
-private:
-    BufferQueue(); // Create through createBufferQueue
+    BufferQueue() = delete; // Create through createBufferQueue
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index b1c730a..1e9585c 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -51,7 +51,6 @@
 namespace android {
 
 class IConsumerListener;
-class IGraphicBufferAlloc;
 class IProducerListener;
 
 class BufferQueueCore : public virtual RefBase {
@@ -79,9 +78,8 @@
     typedef Vector<BufferItem> Fifo;
 
     // BufferQueueCore manages a pool of gralloc memory slots to be used by
-    // producers and consumers. allocator is used to allocate all the needed
-    // gralloc buffers.
-    BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator = NULL);
+    // producers and consumers.
+    BufferQueueCore();
     virtual ~BufferQueueCore();
 
 private:
@@ -143,10 +141,6 @@
     void validateConsistencyLocked() const;
 #endif
 
-    // mAllocator is the connection to SurfaceFlinger that is used to allocate
-    // new GraphicBuffer objects.
-    sp<IGraphicBufferAlloc> mAllocator;
-
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of BufferQueueCore objects. It must be locked whenever any
     // member variable is accessed.
diff --git a/include/gui/GraphicBufferAlloc.h b/include/gui/GraphicBufferAlloc.h
deleted file mode 100644
index 54c9829..0000000
--- a/include/gui/GraphicBufferAlloc.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_GUI_GRAPHIC_BUFFER_ALLOC_H
-#define ANDROID_GUI_GRAPHIC_BUFFER_ALLOC_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <gui/IGraphicBufferAlloc.h>
-#include <ui/PixelFormat.h>
-#include <utils/Errors.h>
-
-namespace android {
-
-class GraphicBuffer;
-
-/*
- * Concrete implementation of the IGraphicBufferAlloc interface.
- *
- * This can create GraphicBuffer instance across processes. This is mainly used
- * by surfaceflinger.
- */
-
-class GraphicBufferAlloc : public BnGraphicBufferAlloc {
-public:
-    GraphicBufferAlloc();
-    virtual ~GraphicBufferAlloc();
-    virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
-            uint32_t height, PixelFormat format, uint32_t layerCount,
-            uint64_t producerUsage, uint64_t consumerUsage,
-            std::string requestorName, status_t* error) override;
-};
-
-
-} // namespace android
-
-#endif // ANDROID_GUI_GRAPHIC_BUFFER_ALLOC_H
diff --git a/include/gui/IGraphicBufferAlloc.h b/include/gui/IGraphicBufferAlloc.h
deleted file mode 100644
index 1e578cc..0000000
--- a/include/gui/IGraphicBufferAlloc.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_GUI_IGRAPHIC_BUFFER_ALLOC_H
-#define ANDROID_GUI_IGRAPHIC_BUFFER_ALLOC_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/IInterface.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/PixelFormat.h>
-#include <utils/RefBase.h>
-
-#include <string>
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-class IGraphicBufferAlloc : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(GraphicBufferAlloc)
-
-    /* Create a new GraphicBuffer for the client to use.
-     */
-    virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
-            PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
-            uint64_t consumerUsage, std::string requestorName,
-            status_t* error) = 0;
-
-    sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
-            PixelFormat format, uint32_t layerCount, uint32_t usage,
-            status_t* error) {
-        return createGraphicBuffer(w, h, format, layerCount, usage,
-                usage, "<Unknown>", error);
-    }
-
-    sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
-            PixelFormat format, uint32_t layerCount, uint32_t usage,
-            std::string requestorName, status_t* error) {
-        return createGraphicBuffer(w, h, format, layerCount, usage,
-                usage, requestorName, error);
-    }
-
-    sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
-            PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
-            uint64_t consumerUsage, status_t* error) {
-        return createGraphicBuffer(w, h, format, layerCount, producerUsage,
-                consumerUsage, "<Unknown>", error);
-    }
-};
-
-// ----------------------------------------------------------------------------
-
-class BnGraphicBufferAlloc : public BnInterface<IGraphicBufferAlloc>
-{
-public:
-    virtual status_t onTransact(uint32_t code,
-                                const Parcel& data,
-                                Parcel* reply,
-                                uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GUI_IGRAPHIC_BUFFER_ALLOC_H
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 9870ba0..1112973 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -41,7 +41,6 @@
 struct DisplayStatInfo;
 class HdrCapabilities;
 class IDisplayEventConnection;
-class IGraphicBufferAlloc;
 class IGraphicBufferProducer;
 class ISurfaceComposerClient;
 class Rect;
@@ -89,10 +88,6 @@
     virtual sp<ISurfaceComposerClient> createScopedConnection(
             const sp<IGraphicBufferProducer>& parent) = 0;
 
-    /* create a graphic buffer allocator
-     */
-    virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() = 0;
-
     /* return an IDisplayEventConnection */
     virtual sp<IDisplayEventConnection> createDisplayEventConnection() = 0;
 
@@ -205,7 +200,7 @@
         // Java by ActivityManagerService.
         BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
         CREATE_CONNECTION,
-        CREATE_GRAPHIC_BUFFER_ALLOC,
+        UNUSED, // formerly CREATE_GRAPHIC_BUFFER_ALLOC
         CREATE_DISPLAY_EVENT_CONNECTION,
         CREATE_DISPLAY,
         DESTROY_DISPLAY,
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
index a22b2cb..a86c586 100644
--- a/include/private/ui/RegionHelper.h
+++ b/include/private/ui/RegionHelper.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_UI_PRIVATE_REGION_HELPER_H
 #define ANDROID_UI_PRIVATE_REGION_HELPER_H
 
+#include <limits>
 #include <stdint.h>
 #include <sys/types.h>
 
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index a1b4abc..9d2dcb6 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -70,11 +70,9 @@
         "DisplayEventReceiver.cpp",
         "FrameTimestamps.cpp",
         "GLConsumer.cpp",
-        "GraphicBufferAlloc.cpp",
         "GuiConfig.cpp",
         "IDisplayEventConnection.cpp",
         "IConsumerListener.cpp",
-        "IGraphicBufferAlloc.cpp",
         "IGraphicBufferConsumer.cpp",
         "IGraphicBufferProducer.cpp",
         "IProducerListener.cpp",
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 13692eb..4151212 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -79,14 +79,13 @@
 
 void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
         sp<IGraphicBufferConsumer>* outConsumer,
-        const sp<IGraphicBufferAlloc>& allocator,
         bool consumerIsSurfaceFlinger) {
     LOG_ALWAYS_FATAL_IF(outProducer == NULL,
             "BufferQueue: outProducer must not be NULL");
     LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
             "BufferQueue: outConsumer must not be NULL");
 
-    sp<BufferQueueCore> core(new BufferQueueCore(allocator));
+    sp<BufferQueueCore> core(new BufferQueueCore());
     LOG_ALWAYS_FATAL_IF(core == NULL,
             "BufferQueue: failed to create BufferQueueCore");
 
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 9e3fecb..1b8ffd7 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -33,9 +33,7 @@
 
 #include <gui/BufferItem.h>
 #include <gui/BufferQueueCore.h>
-#include <gui/GraphicBufferAlloc.h>
 #include <gui/IConsumerListener.h>
-#include <gui/IGraphicBufferAlloc.h>
 #include <gui/IProducerListener.h>
 #include <gui/ISurfaceComposer.h>
 #include <private/gui/ComposerService.h>
@@ -54,8 +52,7 @@
     return id | counter++;
 }
 
-BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
-    mAllocator(allocator),
+BufferQueueCore::BufferQueueCore() :
     mMutex(),
     mIsAbandoned(false),
     mConsumerControlledByApp(false),
@@ -97,30 +94,6 @@
     mLastQueuedSlot(INVALID_BUFFER_SLOT),
     mUniqueId(getUniqueId())
 {
-    if (allocator == NULL) {
-
-#ifdef HAVE_NO_SURFACE_FLINGER
-        // Without a SurfaceFlinger, allocate in-process.  This only makes
-        // sense in systems with static SELinux configurations and no
-        // applications (since applications need dynamic SELinux policy).
-        mAllocator = new GraphicBufferAlloc();
-#else
-        // Run time check for headless, where we also allocate in-process.
-        char value[PROPERTY_VALUE_MAX];
-        property_get("config.headless", value, "0");
-        if (atoi(value) == 1) {
-            mAllocator = new GraphicBufferAlloc();
-        } else {
-            sp<ISurfaceComposer> composer(ComposerService::getComposerService());
-            mAllocator = composer->createGraphicBufferAlloc();
-        }
-#endif  // HAVE_NO_SURFACE_FLINGER
-
-        if (mAllocator == NULL) {
-            BQ_LOGE("createGraphicBufferAlloc failed");
-        }
-    }
-
     int numStartingBuffers = getMaxBufferCountLocked();
     for (int s = 0; s < numStartingBuffers; s++) {
         mFreeSlots.insert(s);
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 27ced61..b92e895 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -34,7 +34,6 @@
 #include <gui/BufferQueueProducer.h>
 #include <gui/GLConsumer.h>
 #include <gui/IConsumerListener.h>
-#include <gui/IGraphicBufferAlloc.h>
 #include <gui/IProducerListener.h>
 
 #include <utils/Log.h>
@@ -454,8 +453,7 @@
         mSlots[found].mBufferState.dequeue();
 
         if ((buffer == NULL) ||
-                buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT,
-                usage))
+                buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
         {
             mSlots[found].mAcquireCalled = false;
             mSlots[found].mGraphicBuffer = NULL;
@@ -503,11 +501,13 @@
     } // Autolock scope
 
     if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
-        status_t error;
         BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
-        sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
-                width, height, format, BQ_LAYER_COUNT, usage,
-                {mConsumerName.string(), mConsumerName.size()}, &error));
+        sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
+                width, height, format, BQ_LAYER_COUNT, usage, usage,
+                {mConsumerName.string(), mConsumerName.size()});
+
+        status_t error = graphicBuffer->initCheck();
+
         { // Autolock scope
             Mutex::Autolock lock(mCore->mMutex);
 
@@ -1329,11 +1329,12 @@
 
         Vector<sp<GraphicBuffer>> buffers;
         for (size_t i = 0; i <  newBufferCount; ++i) {
-            status_t result = NO_ERROR;
-            sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
+            sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
                     allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
-                    allocUsage, {mConsumerName.string(), mConsumerName.size()},
-                    &result));
+                    allocUsage, allocUsage, {mConsumerName.string(), mConsumerName.size()});
+
+            status_t result = graphicBuffer->initCheck();
+
             if (result != NO_ERROR) {
                 BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
                         " %u, usage %u)", width, height, format, usage);
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 8acdfed..9d0fa7e 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -30,7 +30,6 @@
 #include <cutils/atomic.h>
 
 #include <gui/BufferItem.h>
-#include <gui/IGraphicBufferAlloc.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 #include <gui/ConsumerBase.h>
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 55e0d26..c654f08 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -31,7 +31,6 @@
 
 #include <gui/BufferItem.h>
 #include <gui/GLConsumer.h>
-#include <gui/IGraphicBufferAlloc.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 
diff --git a/libs/gui/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp
deleted file mode 100644
index cc7d403..0000000
--- a/libs/gui/GraphicBufferAlloc.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- **
- ** 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.
- */
-
-#include <gui/GraphicBufferAlloc.h>
-
-#include <log/log.h>
-
-
-namespace android {
-
-GraphicBufferAlloc::GraphicBufferAlloc() = default;
-GraphicBufferAlloc::~GraphicBufferAlloc() = default;
-
-sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,
-        uint32_t height, PixelFormat format, uint32_t layerCount,
-        uint64_t producerUsage, uint64_t consumerUsage,
-        std::string requestorName, status_t* error) {
-    sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(
-            width, height, format, layerCount, producerUsage, consumerUsage,
-            std::move(requestorName)));
-    status_t err = graphicBuffer->initCheck();
-    *error = err;
-    if (err != 0 || graphicBuffer->handle == 0) {
-        if (err == NO_MEMORY) {
-            GraphicBuffer::dumpAllocationsToSystemLog();
-        }
-        ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%u, h=%u, lc=%u) failed (%s), handle=%p",
-                width, height, layerCount, strerror(-err),
-                graphicBuffer->handle);
-        graphicBuffer.clear();
-    }
-    return graphicBuffer;
-}
-
-} // namespace android
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
deleted file mode 100644
index 21a0dd5..0000000
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// tag as surfaceflinger
-#define LOG_TAG "SurfaceFlinger"
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include <gui/IGraphicBufferAlloc.h>
-
-// ---------------------------------------------------------------------------
-
-namespace android {
-
-enum {
-    CREATE_GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
-};
-
-class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc>
-{
-public:
-    explicit BpGraphicBufferAlloc(const sp<IBinder>& impl)
-        : BpInterface<IGraphicBufferAlloc>(impl)
-    {
-    }
-
-    virtual ~BpGraphicBufferAlloc();
-
-    virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
-            uint32_t height, PixelFormat format, uint32_t layerCount,
-            uint64_t producerUsage, uint64_t consumerUsage,
-            std::string requestorName, status_t* error) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor());
-        data.writeUint32(width);
-        data.writeUint32(height);
-        data.writeInt32(static_cast<int32_t>(format));
-        data.writeUint32(layerCount);
-        data.writeUint64(producerUsage);
-        data.writeUint64(consumerUsage);
-        if (requestorName.empty()) {
-            requestorName += "[PID ";
-            requestorName += std::to_string(getpid());
-            requestorName += ']';
-        }
-        data.writeUtf8AsUtf16(requestorName);
-        remote()->transact(CREATE_GRAPHIC_BUFFER, data, &reply);
-        sp<GraphicBuffer> graphicBuffer;
-        status_t result = reply.readInt32();
-        if (result == NO_ERROR) {
-            graphicBuffer = new GraphicBuffer();
-            result = reply.read(*graphicBuffer);
-            if (result != NO_ERROR) {
-                graphicBuffer.clear();
-            }
-            // reply.readStrongBinder();
-            // here we don't even have to read the BufferReference from
-            // the parcel, it'll die with the parcel.
-        }
-        *error = result;
-        return graphicBuffer;
-    }
-};
-
-// Out-of-line virtual method definition to trigger vtable emission in this
-// translation unit (see clang warning -Wweak-vtables)
-BpGraphicBufferAlloc::~BpGraphicBufferAlloc() {}
-
-IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc");
-
-// ----------------------------------------------------------------------
-
-status_t BnGraphicBufferAlloc::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    // codes that don't require permission check
-
-    // BufferReference just keeps a strong reference to a GraphicBuffer until it
-    // is destroyed (that is, until no local or remote process have a reference
-    // to it).
-    class BufferReference : public BBinder {
-        sp<GraphicBuffer> mBuffer;
-    public:
-        explicit BufferReference(const sp<GraphicBuffer>& buffer) : mBuffer(buffer) {}
-    };
-
-
-    switch (code) {
-        case CREATE_GRAPHIC_BUFFER: {
-            CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
-            uint32_t width = data.readUint32();
-            uint32_t height = data.readUint32();
-            PixelFormat format = static_cast<PixelFormat>(data.readInt32());
-            uint32_t layerCount = data.readUint32();
-            uint64_t producerUsage = data.readUint64();
-            uint64_t consumerUsage = data.readUint64();
-            status_t error = NO_ERROR;
-            std::string requestorName;
-            data.readUtf8FromUtf16(&requestorName);
-            sp<GraphicBuffer> result = createGraphicBuffer(width, height,
-                    format, layerCount, producerUsage, consumerUsage,
-                    requestorName, &error);
-            reply->writeInt32(error);
-            if (result != 0) {
-                reply->write(*result);
-                // We add a BufferReference to this parcel to make sure the
-                // buffer stays alive until the GraphicBuffer object on
-                // the other side has been created.
-                // This is needed so that the buffer handle can be
-                // registered before the buffer is destroyed on implementations
-                // that do not use file-descriptors to track their buffers.
-                reply->writeStrongBinder( new BufferReference(result) );
-            }
-            return NO_ERROR;
-        }
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-}; // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 4d2692f..2516fb8 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -25,7 +25,6 @@
 #include <binder/IServiceManager.h>
 
 #include <gui/IDisplayEventConnection.h>
-#include <gui/IGraphicBufferAlloc.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/ISurfaceComposerClient.h>
@@ -72,14 +71,6 @@
         return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
     }
 
-    virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc()
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, data, &reply);
-        return interface_cast<IGraphicBufferAlloc>(reply.readStrongBinder());
-    }
-
     virtual void setTransactionState(
             const Vector<ComposerState>& state,
             const Vector<DisplayState>& displays,
@@ -505,12 +496,6 @@
             reply->writeStrongBinder(b);
             return NO_ERROR;
         }
-        case CREATE_GRAPHIC_BUFFER_ALLOC: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> b = IInterface::asBinder(createGraphicBufferAlloc());
-            reply->writeStrongBinder(b);
-            return NO_ERROR;
-        }
         case SET_TRANSACTION_STATE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
 
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index ad1984a..a2e12f7 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -836,6 +836,10 @@
                 *value = mFrameTimestampsSupportsRetire ? 1 : 0;
                 return NO_ERROR;
             }
+            case NATIVE_WINDOW_IS_VALID: {
+                *value = mGraphicBufferProducer != nullptr ? 1 : 0;
+                return NO_ERROR;
+            }
         }
     }
     return mGraphicBufferProducer->query(what, value);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index da6f13d..be48c11 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -366,9 +366,6 @@
             const sp<IGraphicBufferProducer>& /* parent */) override {
         return nullptr;
     }
-    sp<IGraphicBufferAlloc> createGraphicBufferAlloc() override {
-        return nullptr;
-    }
     sp<IDisplayEventConnection> createDisplayEventConnection() override {
         return nullptr;
     }
diff --git a/libs/hwc2on1adapter/Android.bp b/libs/hwc2on1adapter/Android.bp
new file mode 100644
index 0000000..2be3e67
--- /dev/null
+++ b/libs/hwc2on1adapter/Android.bp
@@ -0,0 +1,68 @@
+// Copyright 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.
+
+cc_library_shared {
+    name: "libhwc2on1adapter",
+
+    clang: true,
+    cppflags: [
+        "-Weverything",
+        "-Wall",
+        "-Wunused",
+        "-Wunreachable-code",
+
+        // The static constructors and destructors in this library have not been noted to
+        // introduce significant overheads
+        "-Wno-exit-time-destructors",
+        "-Wno-global-constructors",
+
+        // We only care about compiling as C++14
+        "-Wno-c++98-compat-pedantic",
+
+        // android/sensors.h uses nested anonymous unions and anonymous structs
+        "-Wno-nested-anon-types",
+        "-Wno-gnu-anonymous-struct",
+
+        // Don't warn about struct padding
+        "-Wno-padded",
+
+        // hwcomposer2.h features switch covering all cases.
+        "-Wno-covered-switch-default",
+
+        // hwcomposer.h features zero size array.
+        "-Wno-zero-length-array",
+
+        // Disabling warning specific to hwc2on1adapter code
+        "-Wno-double-promotion",
+        "-Wno-sign-conversion",
+        "-Wno-switch-enum",
+        "-Wno-float-equal",
+    ],
+
+    srcs: [
+        "HWC2On1Adapter.cpp",
+        "MiniFence.cpp",
+    ],
+
+    shared_libs: [
+        "libutils",
+        "libcutils",
+        "liblog",
+        "libhardware",
+    ],
+
+    export_include_dirs: ["include"],
+
+    export_shared_lib_headers: ["libutils"],
+}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
similarity index 99%
rename from services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
rename to libs/hwc2on1adapter/HWC2On1Adapter.cpp
index 13bf0b5..5ad05c7 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
+#include "hwc2on1adapter/HWC2On1Adapter.h"
+
 //#define LOG_NDEBUG 0
 
 #undef LOG_TAG
 #define LOG_TAG "HWC2On1Adapter"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include "HWC2On1Adapter.h"
 
 #include <inttypes.h>
 
@@ -317,15 +318,6 @@
         return Error::NoResources;
     }
 
-    if (MAX_VIRTUAL_DISPLAY_DIMENSION != 0 &&
-            (width > MAX_VIRTUAL_DISPLAY_DIMENSION ||
-            height > MAX_VIRTUAL_DISPLAY_DIMENSION)) {
-        ALOGE("createVirtualDisplay: Can't create a virtual display with"
-                " a dimension > %u (tried %u x %u)",
-                MAX_VIRTUAL_DISPLAY_DIMENSION, width, height);
-        return Error::NoResources;
-    }
-
     mHwc1VirtualDisplay = std::make_shared<HWC2On1Adapter::Display>(*this,
             HWC2::DisplayType::Virtual);
     mHwc1VirtualDisplay->populateConfigs(width, height);
diff --git a/services/surfaceflinger/DisplayHardware/MiniFence.cpp b/libs/hwc2on1adapter/MiniFence.cpp
similarity index 95%
rename from services/surfaceflinger/DisplayHardware/MiniFence.cpp
rename to libs/hwc2on1adapter/MiniFence.cpp
index ecfb063..dfbe4d6 100644
--- a/services/surfaceflinger/DisplayHardware/MiniFence.cpp
+++ b/libs/hwc2on1adapter/MiniFence.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "MiniFence.h"
+#include "hwc2on1adapter/MiniFence.h"
 
 #include <unistd.h>
 
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h b/libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
similarity index 100%
rename from services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
rename to libs/hwc2on1adapter/include/hwc2on1adapter/HWC2On1Adapter.h
diff --git a/services/surfaceflinger/DisplayHardware/MiniFence.h b/libs/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h
similarity index 100%
rename from services/surfaceflinger/DisplayHardware/MiniFence.h
rename to libs/hwc2on1adapter/include/hwc2on1adapter/MiniFence.h
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 3fbab17..e25e909 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -69,7 +69,7 @@
         if (err == NO_MEMORY) {
             GraphicBuffer::dumpAllocationsToSystemLog();
         }
-        ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%u, h=%u, lc=%u) failed (%s), handle=%p",
+        ALOGE("GraphicBuffer(w=%u, h=%u, lc=%u) failed (%s), handle=%p",
                 desc->width, desc->height, desc->layers, strerror(-err), gbuffer->handle);
         return err;
     }
@@ -428,6 +428,14 @@
     return reinterpret_cast<GraphicBuffer*>(buffer);
 }
 
+const ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(const AHardwareBuffer* buffer) {
+    return AHardwareBuffer_to_GraphicBuffer(buffer)->getNativeBuffer();
+}
+
+ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(AHardwareBuffer* buffer) {
+    return AHardwareBuffer_to_GraphicBuffer(buffer)->getNativeBuffer();
+}
+
 AHardwareBuffer* AHardwareBuffer_from_GraphicBuffer(GraphicBuffer* buffer) {
     return reinterpret_cast<AHardwareBuffer*>(buffer);
 }
diff --git a/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
index 612ee80..ee5da84 100644
--- a/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
+++ b/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
@@ -28,6 +28,7 @@
 #include <stdint.h>
 
 struct AHardwareBuffer;
+struct ANativeWindowBuffer;
 
 namespace android {
 
@@ -44,8 +45,11 @@
 class GraphicBuffer;
 const GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(const AHardwareBuffer* buffer);
 GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(AHardwareBuffer* buffer);
-AHardwareBuffer* AHardwareBuffer_from_GraphicBuffer(GraphicBuffer* buffer);
 
+const ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(const AHardwareBuffer* buffer);
+ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(AHardwareBuffer* buffer);
+
+AHardwareBuffer* AHardwareBuffer_from_GraphicBuffer(GraphicBuffer* buffer);
 } // namespace android
 
 #endif // ANDROID_PRIVATE_NATIVE_AHARDWARE_BUFFER_HELPERS_H
diff --git a/libs/vr/libdisplay/Android.mk b/libs/vr/libdisplay/Android.mk
index 6a9458c..60f73c6 100644
--- a/libs/vr/libdisplay/Android.mk
+++ b/libs/vr/libdisplay/Android.mk
@@ -15,7 +15,6 @@
 LOCAL_PATH := $(call my-dir)
 
 sourceFiles := \
-	native_window.cpp \
 	native_buffer_queue.cpp \
 	display_client.cpp \
 	display_manager_client.cpp \
@@ -72,8 +71,7 @@
 LOCAL_MODULE := libdisplay
 include $(BUILD_STATIC_LIBRARY)
 
-
-testFiles := \
+graphicsAppTestFiles := \
   tests/graphics_app_tests.cpp
 
 include $(CLEAR_VARS)
@@ -81,7 +79,7 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_SRC_FILES := \
-  $(testFiles) \
+  $(graphicsAppTestFiles) \
 
 LOCAL_C_INCLUDES := \
   $(includeFiles) \
@@ -94,3 +92,25 @@
   $(staticLibraries) \
 
 include $(BUILD_NATIVE_TEST)
+
+dummyNativeWindowTestFiles := \
+  tests/dummy_native_window_tests.cpp \
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dummy_native_window_tests
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+  $(dummyNativeWindowTestFiles) \
+
+LOCAL_C_INCLUDES := \
+  $(includeFiles) \
+
+LOCAL_SHARED_LIBRARIES := \
+  $(sharedLibraries) \
+
+LOCAL_STATIC_LIBRARIES := \
+  libdisplay \
+  $(staticLibraries) \
+include $(BUILD_NATIVE_TEST)
+
diff --git a/libs/vr/libdisplay/dummy_native_window.cpp b/libs/vr/libdisplay/dummy_native_window.cpp
index 5547f53..4628b8e 100644
--- a/libs/vr/libdisplay/dummy_native_window.cpp
+++ b/libs/vr/libdisplay/dummy_native_window.cpp
@@ -30,6 +30,11 @@
 
 int DummyNativeWindow::Query(const ANativeWindow*, int what, int* value) {
   switch (what) {
+    // This must be 1 in order for eglCreateWindowSurface to not trigger an
+    // error
+    case NATIVE_WINDOW_IS_VALID:
+      *value = 1;
+      return NO_ERROR;
     case NATIVE_WINDOW_WIDTH:
     case NATIVE_WINDOW_HEIGHT:
     case NATIVE_WINDOW_FORMAT:
diff --git a/libs/vr/libdisplay/graphics.cpp b/libs/vr/libdisplay/graphics.cpp
index d0557a9..61f6fea 100644
--- a/libs/vr/libdisplay/graphics.cpp
+++ b/libs/vr/libdisplay/graphics.cpp
@@ -483,25 +483,6 @@
   return 0;
 }
 
-extern "C" int dvrGetDisplaySurfaceInfo(EGLNativeWindowType win, int* width,
-                                        int* height, int* format) {
-  ANativeWindow* nwin = reinterpret_cast<ANativeWindow*>(win);
-  int w, h, f;
-
-  nwin->query(nwin, NATIVE_WINDOW_DEFAULT_WIDTH, &w);
-  nwin->query(nwin, NATIVE_WINDOW_DEFAULT_HEIGHT, &h);
-  nwin->query(nwin, NATIVE_WINDOW_FORMAT, &f);
-
-  if (width)
-    *width = w;
-  if (height)
-    *height = h;
-  if (format)
-    *format = f;
-
-  return 0;
-}
-
 struct DvrGraphicsContext : public android::ANativeObjectBase<
                                 ANativeWindow, DvrGraphicsContext,
                                 android::LightRefBase<DvrGraphicsContext>> {
diff --git a/libs/vr/libdisplay/include/dvr/graphics.h b/libs/vr/libdisplay/include/dvr/graphics.h
index 50d2754..19deec3 100644
--- a/libs/vr/libdisplay/include/dvr/graphics.h
+++ b/libs/vr/libdisplay/include/dvr/graphics.h
@@ -21,11 +21,6 @@
 
 __BEGIN_DECLS
 
-// Create a stereo surface that will be lens-warped by the system.
-EGLNativeWindowType dvrCreateWarpedDisplaySurface(int* display_width,
-                                                  int* display_height);
-EGLNativeWindowType dvrCreateDisplaySurface(void);
-
 // Display surface parameters used to specify display surface options.
 enum {
   DVR_SURFACE_PARAMETER_NONE = 0,
@@ -163,9 +158,16 @@
   float right_fov[4];
 };
 
-// Creates a display surface with the given parameters. The list of parameters
-// is terminated with an entry where key == DVR_SURFACE_PARAMETER_NONE.
-// For example, the parameters array could be built as follows:
+int dvrGetNativeDisplayDimensions(int* native_width, int* native_height);
+
+// Opaque struct that represents a graphics context, the texture swap chain,
+// and surfaces.
+typedef struct DvrGraphicsContext DvrGraphicsContext;
+
+// Create the graphics context. with the given parameters. The list of
+// parameters is terminated with an entry where key ==
+// DVR_SURFACE_PARAMETER_NONE. For example, the parameters array could be built
+// as follows:
 //   int display_width = 0, display_height = 0;
 //   int surface_width = 0, surface_height = 0;
 //   float inter_lens_meters = 0.0f;
@@ -183,38 +185,6 @@
 //       DVR_SURFACE_PARAMETER_OUT(RIGHT_FOV_LRBT, right_fov),
 //       DVR_SURFACE_PARAMETER_LIST_END,
 //   };
-EGLNativeWindowType dvrCreateDisplaySurfaceExtended(
-    struct DvrSurfaceParameter* parameters);
-
-int dvrGetNativeDisplayDimensions(int* native_width, int* native_height);
-
-int dvrGetDisplaySurfaceInfo(EGLNativeWindowType win, int* width, int* height,
-                             int* format);
-
-// NOTE: Only call the functions below on windows created with the API above.
-
-// Sets the display surface visible based on the boolean evaluation of
-// |visible|.
-void dvrDisplaySurfaceSetVisible(EGLNativeWindowType window, int visible);
-
-// Sets the application z-order of the display surface. Higher values display on
-// top of lower values.
-void dvrDisplaySurfaceSetZOrder(EGLNativeWindowType window, int z_order);
-
-// Post the next buffer early. This allows the application to race with either
-// the async EDS process or the scanline for applications that are not using
-// system distortion. When this is called, the next buffer in the queue is
-// posted for display. It is up to the application to kick its GPU rendering
-// work in time. If the rendering is incomplete there will be significant,
-// undesirable tearing artifacts.
-// It is not recommended to use this feature with system distortion.
-void dvrDisplayPostEarly(EGLNativeWindowType window);
-
-// Opaque struct that represents a graphics context, the texture swap chain,
-// and surfaces.
-typedef struct DvrGraphicsContext DvrGraphicsContext;
-
-// Create the graphics context.
 int dvrGraphicsContextCreate(struct DvrSurfaceParameter* parameters,
                              DvrGraphicsContext** return_graphics_context);
 
diff --git a/libs/vr/libdisplay/native_window.cpp b/libs/vr/libdisplay/native_window.cpp
deleted file mode 100644
index 24ecd8a..0000000
--- a/libs/vr/libdisplay/native_window.cpp
+++ /dev/null
@@ -1,458 +0,0 @@
-#include <EGL/egl.h>
-
-#include <android/native_window.h>
-#include <cutils/native_handle.h>
-#include <errno.h>
-#include <pthread.h>
-#include <semaphore.h>
-#include <stdarg.h>
-#include <string.h>
-#include <sys/timerfd.h>
-#include <system/window.h>
-#include <time.h>
-#include <ui/ANativeObjectBase.h>
-#include <utils/Errors.h>
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <utils/Trace.h>
-
-#include <log/log.h>
-
-#include <memory>
-#include <mutex>
-
-#include <dvr/graphics.h>
-#include <private/dvr/clock_ns.h>
-#include <private/dvr/display_client.h>
-#include <private/dvr/native_buffer.h>
-#include <private/dvr/native_buffer_queue.h>
-
-namespace {
-
-constexpr int kDefaultDisplaySurfaceUsage =
-    GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
-constexpr int kDefaultDisplaySurfaceFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-constexpr int kWarpedDisplaySurfaceFlags = 0;
-constexpr int kUnwarpedDisplaySurfaceFlags =
-    DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_EDS |
-    DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION |
-    DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_CAC;
-constexpr int kDefaultBufferCount = 4;
-
-}  // anonymous namespace
-
-namespace android {
-namespace dvr {
-
-// NativeWindow is an implementation of ANativeWindow. This class interacts with
-// displayd through the DisplaySurfaceClient and NativeBufferQueue.
-class NativeWindow : public ANativeObjectBase<ANativeWindow, NativeWindow,
-                                              LightRefBase<NativeWindow> > {
- public:
-  explicit NativeWindow(const std::shared_ptr<DisplaySurfaceClient>& surface);
-
-  void SetVisible(bool visible);
-  void SetZOrder(int z_order);
-  void PostEarly();
-
- private:
-  friend class LightRefBase<NativeWindow>;
-
-  void Post(sp<NativeBufferProducer> buffer, int fence_fd);
-
-  static int SetSwapInterval(ANativeWindow* window, int interval);
-  static int DequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
-                           int* fence_fd);
-  static int QueueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
-                         int fence_fd);
-  static int CancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
-                          int fence_fd);
-  static int Query(const ANativeWindow* window, int what, int* value);
-  static int Perform(ANativeWindow* window, int operation, ...);
-
-  static int DequeueBuffer_DEPRECATED(ANativeWindow* window,
-                                      ANativeWindowBuffer** buffer);
-  static int CancelBuffer_DEPRECATED(ANativeWindow* window,
-                                     ANativeWindowBuffer* buffer);
-  static int QueueBuffer_DEPRECATED(ANativeWindow* window,
-                                    ANativeWindowBuffer* buffer);
-  static int LockBuffer_DEPRECATED(ANativeWindow* window,
-                                   ANativeWindowBuffer* buffer);
-
-  std::shared_ptr<DisplaySurfaceClient> surface_;
-
-  std::mutex lock_;
-  NativeBufferQueue buffer_queue_;
-  sp<NativeBufferProducer> next_post_buffer_;
-  bool next_buffer_already_posted_;
-
-  NativeWindow(const NativeWindow&) = delete;
-  void operator=(NativeWindow&) = delete;
-};
-
-NativeWindow::NativeWindow(const std::shared_ptr<DisplaySurfaceClient>& surface)
-    : surface_(surface),
-      buffer_queue_(surface, kDefaultBufferCount),
-      next_post_buffer_(nullptr),
-      next_buffer_already_posted_(false) {
-  ANativeWindow::setSwapInterval = SetSwapInterval;
-  ANativeWindow::dequeueBuffer = DequeueBuffer;
-  ANativeWindow::cancelBuffer = CancelBuffer;
-  ANativeWindow::queueBuffer = QueueBuffer;
-  ANativeWindow::query = Query;
-  ANativeWindow::perform = Perform;
-
-  ANativeWindow::dequeueBuffer_DEPRECATED = DequeueBuffer_DEPRECATED;
-  ANativeWindow::cancelBuffer_DEPRECATED = CancelBuffer_DEPRECATED;
-  ANativeWindow::lockBuffer_DEPRECATED = LockBuffer_DEPRECATED;
-  ANativeWindow::queueBuffer_DEPRECATED = QueueBuffer_DEPRECATED;
-}
-
-void NativeWindow::SetVisible(bool visible) { surface_->SetVisible(visible); }
-
-void NativeWindow::SetZOrder(int z_order) { surface_->SetZOrder(z_order); }
-
-void NativeWindow::PostEarly() {
-  ATRACE_NAME("NativeWindow::PostEarly");
-  ALOGI_IF(TRACE, "NativeWindow::PostEarly");
-
-  std::lock_guard<std::mutex> autolock(lock_);
-
-  if (!next_buffer_already_posted_) {
-    next_buffer_already_posted_ = true;
-
-    if (!next_post_buffer_.get()) {
-      next_post_buffer_ = buffer_queue_.Dequeue();
-    }
-    ATRACE_ASYNC_BEGIN("BufferPost", next_post_buffer_->buffer()->id());
-    Post(next_post_buffer_, -1);
-  }
-}
-
-void NativeWindow::Post(sp<NativeBufferProducer> buffer, int fence_fd) {
-  ATRACE_NAME(__PRETTY_FUNCTION__);
-  ALOGI_IF(TRACE, "NativeWindow::Post: buffer_id=%d, fence_fd=%d",
-           buffer->buffer()->id(), fence_fd);
-  ALOGW_IF(!surface_->visible(),
-           "NativeWindow::Post: Posting buffer on invisible surface!!!");
-  buffer->Post(fence_fd, 0);
-}
-
-int NativeWindow::SetSwapInterval(ANativeWindow* window, int interval) {
-  ALOGI_IF(TRACE, "SetSwapInterval: window=%p interval=%d", window, interval);
-  return 0;
-}
-
-int NativeWindow::DequeueBuffer(ANativeWindow* window,
-                                ANativeWindowBuffer** buffer, int* fence_fd) {
-  ATRACE_NAME(__PRETTY_FUNCTION__);
-
-  NativeWindow* self = getSelf(window);
-  std::lock_guard<std::mutex> autolock(self->lock_);
-
-  if (!self->next_post_buffer_.get()) {
-    self->next_post_buffer_ = self->buffer_queue_.Dequeue();
-  }
-  ATRACE_ASYNC_BEGIN("BufferDraw", self->next_post_buffer_->buffer()->id());
-  *fence_fd = self->next_post_buffer_->ClaimReleaseFence().Release();
-  *buffer = self->next_post_buffer_.get();
-
-  ALOGI_IF(TRACE, "NativeWindow::DequeueBuffer: fence_fd=%d", *fence_fd);
-  return 0;
-}
-
-int NativeWindow::QueueBuffer(ANativeWindow* window,
-                              ANativeWindowBuffer* buffer, int fence_fd) {
-  ATRACE_NAME("NativeWindow::QueueBuffer");
-  ALOGI_IF(TRACE, "NativeWindow::QueueBuffer: fence_fd=%d", fence_fd);
-
-  NativeWindow* self = getSelf(window);
-  std::lock_guard<std::mutex> autolock(self->lock_);
-
-  NativeBufferProducer* native_buffer =
-      static_cast<NativeBufferProducer*>(buffer);
-  ATRACE_ASYNC_END("BufferDraw", native_buffer->buffer()->id());
-  bool do_post = true;
-  if (self->next_buffer_already_posted_) {
-    // Check that the buffer is the one we expect, but handle it if this happens
-    // in production by allowing this buffer to post on top of the previous one.
-    LOG_FATAL_IF(native_buffer != self->next_post_buffer_.get());
-    if (native_buffer == self->next_post_buffer_.get()) {
-      do_post = false;
-      if (fence_fd >= 0)
-        close(fence_fd);
-    }
-  }
-  if (do_post) {
-    ATRACE_ASYNC_BEGIN("BufferPost", native_buffer->buffer()->id());
-    self->Post(native_buffer, fence_fd);
-  }
-  self->next_buffer_already_posted_ = false;
-  self->next_post_buffer_ = nullptr;
-
-  return NO_ERROR;
-}
-
-int NativeWindow::CancelBuffer(ANativeWindow* window,
-                               ANativeWindowBuffer* buffer, int fence_fd) {
-  ATRACE_NAME("NativeWindow::CancelBuffer");
-  ALOGI_IF(TRACE, "NativeWindow::CancelBuffer: fence_fd: %d", fence_fd);
-
-  NativeWindow* self = getSelf(window);
-  std::lock_guard<std::mutex> autolock(self->lock_);
-
-  NativeBufferProducer* native_buffer =
-      static_cast<NativeBufferProducer*>(buffer);
-  ATRACE_ASYNC_END("BufferDraw", native_buffer->buffer()->id());
-  ATRACE_INT("CancelBuffer", native_buffer->buffer()->id());
-  bool do_enqueue = true;
-  if (self->next_buffer_already_posted_) {
-    // Check that the buffer is the one we expect, but handle it if this happens
-    // in production by returning this buffer to the buffer queue.
-    LOG_FATAL_IF(native_buffer != self->next_post_buffer_.get());
-    if (native_buffer == self->next_post_buffer_.get()) {
-      do_enqueue = false;
-    }
-  }
-  if (do_enqueue) {
-    self->buffer_queue_.Enqueue(native_buffer);
-  }
-  if (fence_fd >= 0)
-    close(fence_fd);
-  self->next_buffer_already_posted_ = false;
-  self->next_post_buffer_ = nullptr;
-
-  return NO_ERROR;
-}
-
-int NativeWindow::Query(const ANativeWindow* window, int what, int* value) {
-  NativeWindow* self = getSelf(const_cast<ANativeWindow*>(window));
-  std::lock_guard<std::mutex> autolock(self->lock_);
-
-  switch (what) {
-    case NATIVE_WINDOW_WIDTH:
-      *value = self->surface_->width();
-      return NO_ERROR;
-    case NATIVE_WINDOW_HEIGHT:
-      *value = self->surface_->height();
-      return NO_ERROR;
-    case NATIVE_WINDOW_FORMAT:
-      *value = self->surface_->format();
-      return NO_ERROR;
-    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
-      *value = 1;
-      return NO_ERROR;
-    case NATIVE_WINDOW_CONCRETE_TYPE:
-      *value = NATIVE_WINDOW_SURFACE;
-      return NO_ERROR;
-    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
-      *value = 1;
-      return NO_ERROR;
-    case NATIVE_WINDOW_DEFAULT_WIDTH:
-      *value = self->surface_->width();
-      return NO_ERROR;
-    case NATIVE_WINDOW_DEFAULT_HEIGHT:
-      *value = self->surface_->height();
-      return NO_ERROR;
-    case NATIVE_WINDOW_TRANSFORM_HINT:
-      *value = 0;
-      return NO_ERROR;
-  }
-
-  *value = 0;
-  return BAD_VALUE;
-}
-
-int NativeWindow::Perform(ANativeWindow* window, int operation, ...) {
-  NativeWindow* self = getSelf(window);
-  std::lock_guard<std::mutex> autolock(self->lock_);
-
-  va_list args;
-  va_start(args, operation);
-
-  // TODO(eieio): The following operations are not used at this time. They are
-  // included here to help document which operations may be useful and what
-  // parameters they take.
-  switch (operation) {
-    case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: {
-      int w = va_arg(args, int);
-      int h = va_arg(args, int);
-      ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: w=%d h=%d", w, h);
-      return NO_ERROR;
-    }
-
-    case NATIVE_WINDOW_SET_BUFFERS_FORMAT: {
-      int format = va_arg(args, int);
-      ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFERS_FORMAT: format=%d", format);
-      return NO_ERROR;
-    }
-
-    case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: {
-      int transform = va_arg(args, int);
-      ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: transform=%d",
-               transform);
-      return NO_ERROR;
-    }
-
-    case NATIVE_WINDOW_SET_USAGE: {
-      int usage = va_arg(args, int);
-      ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_USAGE: usage=%d", usage);
-      return NO_ERROR;
-    }
-
-    case NATIVE_WINDOW_CONNECT:
-    case NATIVE_WINDOW_DISCONNECT:
-    case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
-    case NATIVE_WINDOW_API_CONNECT:
-    case NATIVE_WINDOW_API_DISCONNECT:
-      // TODO(eieio): we should implement these
-      return NO_ERROR;
-
-    case NATIVE_WINDOW_SET_BUFFER_COUNT: {
-      int buffer_count = va_arg(args, int);
-      ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFER_COUNT: bufferCount=%d",
-               buffer_count);
-      return NO_ERROR;
-    }
-    case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: {
-      android_dataspace_t data_space =
-          static_cast<android_dataspace_t>(va_arg(args, int));
-      ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_BUFFERS_DATASPACE: dataSpace=%d",
-               data_space);
-      return NO_ERROR;
-    }
-    case NATIVE_WINDOW_SET_SCALING_MODE: {
-      int mode = va_arg(args, int);
-      ALOGD_IF(TRACE, "NATIVE_WINDOW_SET_SCALING_MODE: mode=%d", mode);
-      return NO_ERROR;
-    }
-
-    case NATIVE_WINDOW_LOCK:
-    case NATIVE_WINDOW_UNLOCK_AND_POST:
-    case NATIVE_WINDOW_SET_CROP:
-    case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
-      return INVALID_OPERATION;
-  }
-
-  return NAME_NOT_FOUND;
-}
-
-int NativeWindow::DequeueBuffer_DEPRECATED(ANativeWindow* window,
-                                           ANativeWindowBuffer** buffer) {
-  int fence_fd = -1;
-  int ret = DequeueBuffer(window, buffer, &fence_fd);
-
-  // wait for fence
-  if (ret == NO_ERROR && fence_fd != -1)
-    close(fence_fd);
-
-  return ret;
-}
-
-int NativeWindow::CancelBuffer_DEPRECATED(ANativeWindow* window,
-                                          ANativeWindowBuffer* buffer) {
-  return CancelBuffer(window, buffer, -1);
-}
-
-int NativeWindow::QueueBuffer_DEPRECATED(ANativeWindow* window,
-                                         ANativeWindowBuffer* buffer) {
-  return QueueBuffer(window, buffer, -1);
-}
-
-int NativeWindow::LockBuffer_DEPRECATED(ANativeWindow* /*window*/,
-                                        ANativeWindowBuffer* /*buffer*/) {
-  return NO_ERROR;
-}
-
-}  // namespace dvr
-}  // namespace android
-
-static EGLNativeWindowType CreateDisplaySurface(int* display_width,
-                                                int* display_height, int format,
-                                                int usage, int flags) {
-  auto client = android::dvr::DisplayClient::Create();
-  if (!client) {
-    ALOGE("Failed to create display client!");
-    return nullptr;
-  }
-
-  // TODO(eieio,jbates): Consider passing flags and other parameters to get
-  // metrics based on specific surface requirements.
-  android::dvr::SystemDisplayMetrics metrics;
-  const int ret = client->GetDisplayMetrics(&metrics);
-  if (ret < 0) {
-    ALOGE("Failed to get display metrics: %s", strerror(-ret));
-    return nullptr;
-  }
-
-  int width, height;
-
-  if (flags & DVR_DISPLAY_SURFACE_FLAGS_DISABLE_SYSTEM_DISTORTION) {
-    width = metrics.display_native_width;
-    height = metrics.display_native_height;
-  } else {
-    width = metrics.distorted_width;
-    height = metrics.distorted_height;
-  }
-
-  std::shared_ptr<android::dvr::DisplaySurfaceClient> surface =
-      client->CreateDisplaySurface(width, height, format, usage, flags);
-
-  if (display_width)
-    *display_width = metrics.display_native_width;
-  if (display_height)
-    *display_height = metrics.display_native_height;
-
-  // Set the surface visible by default.
-  // TODO(eieio,jbates): Remove this from here and set visible somewhere closer
-  // to the application to account for situations where the application wants to
-  // create surfaces that will be used later or shouldn't be visible yet.
-  surface->SetVisible(true);
-
-  return new android::dvr::NativeWindow(surface);
-}
-
-std::shared_ptr<android::dvr::DisplaySurfaceClient> CreateDisplaySurfaceClient(
-    struct DvrSurfaceParameter* parameters,
-    /*out*/ android::dvr::SystemDisplayMetrics* metrics);
-
-extern "C" EGLNativeWindowType dvrCreateDisplaySurfaceExtended(
-    struct DvrSurfaceParameter* parameters) {
-  android::dvr::SystemDisplayMetrics metrics;
-  auto surface = CreateDisplaySurfaceClient(parameters, &metrics);
-  if (!surface) {
-    ALOGE("Failed to create display surface client");
-    return nullptr;
-  }
-  return new android::dvr::NativeWindow(surface);
-}
-
-extern "C" EGLNativeWindowType dvrCreateDisplaySurface() {
-  return CreateDisplaySurface(NULL, NULL, kDefaultDisplaySurfaceFormat,
-                              kDefaultDisplaySurfaceUsage,
-                              kUnwarpedDisplaySurfaceFlags);
-}
-
-extern "C" EGLNativeWindowType dvrCreateWarpedDisplaySurface(
-    int* display_width, int* display_height) {
-  return CreateDisplaySurface(
-      display_width, display_height, kDefaultDisplaySurfaceFormat,
-      kDefaultDisplaySurfaceUsage, kWarpedDisplaySurfaceFlags);
-}
-
-extern "C" void dvrDisplaySurfaceSetVisible(EGLNativeWindowType window,
-                                            int visible) {
-  auto native_window = reinterpret_cast<android::dvr::NativeWindow*>(window);
-  native_window->SetVisible(visible);
-}
-
-extern "C" void dvrDisplaySurfaceSetZOrder(EGLNativeWindowType window,
-                                           int z_order) {
-  auto native_window = reinterpret_cast<android::dvr::NativeWindow*>(window);
-  native_window->SetZOrder(z_order);
-}
-
-extern "C" void dvrDisplayPostEarly(EGLNativeWindowType window) {
-  auto native_window = reinterpret_cast<android::dvr::NativeWindow*>(window);
-  native_window->PostEarly();
-}
diff --git a/libs/vr/libdisplay/native_window_test.cpp b/libs/vr/libdisplay/native_window_test.cpp
deleted file mode 100644
index 2f3bc33..0000000
--- a/libs/vr/libdisplay/native_window_test.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <iostream>
-#include <memory>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <dvr/graphics.h>
-#include <private/dvr/display_client.h>
-
-#include <cpp_free_mock/cpp_free_mock.h>
-
-// Checks querying the VSync of the device on display surface creation.
-TEST(CreateDisplaySurface, QueryVSyncPeriod) {
-  using ::testing::_;
-
-  const uint64_t kExpectedVSync = 123456;
-
-  // We only care about the expected VSync value
-  android::dvr::DisplayMetrics metrics;
-  metrics.vsync_period_ns = kExpectedVSync;
-
-  uint64_t outPeriod;
-
-  DvrSurfaceParameter display_params[] = {
-      DVR_SURFACE_PARAMETER_IN(WIDTH, 256),
-      DVR_SURFACE_PARAMETER_IN(HEIGHT, 256),
-      DVR_SURFACE_PARAMETER_OUT(VSYNC_PERIOD, &outPeriod),
-      DVR_SURFACE_PARAMETER_LIST_END,
-  };
-
-  // inject the mocking code to the target method
-  auto mocked_function =
-      MOCKER(&android::dvr::DisplayClient::GetDisplayMetrics);
-
-  // instrument the mock function to return our custom metrics
-  EXPECT_CALL(*mocked_function, MOCK_FUNCTION(_, _))
-      .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(metrics),
-                                 ::testing::Return(0)));
-
-  ASSERT_NE(nullptr, dvrCreateDisplaySurfaceExtended(display_params));
-
-  EXPECT_EQ(kExpectedVSync, outPeriod);
-}
diff --git a/libs/vr/libdisplay/tests/dummy_native_window_tests.cpp b/libs/vr/libdisplay/tests/dummy_native_window_tests.cpp
new file mode 100644
index 0000000..5f3ff53
--- /dev/null
+++ b/libs/vr/libdisplay/tests/dummy_native_window_tests.cpp
@@ -0,0 +1,64 @@
+#include <private/dvr/dummy_native_window.h>
+#include <gtest/gtest.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+
+class DummyNativeWindowTests : public ::testing::Test {
+ public:
+  EGLDisplay display_;
+  bool initialized_;
+
+  DummyNativeWindowTests()
+      : display_(nullptr)
+      , initialized_(false)
+  {
+  }
+
+  virtual void SetUp() {
+    display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+    ASSERT_NE(nullptr, display_);
+    initialized_ = eglInitialize(display_, nullptr, nullptr);
+
+    ASSERT_TRUE(initialized_);
+  }
+
+  virtual void TearDown() {
+    if (display_ && initialized_) {
+      eglTerminate(display_);
+    }
+  }
+};
+
+// Test that eglCreateWindowSurface works with DummyNativeWindow
+TEST_F(DummyNativeWindowTests, TryCreateEglWindow) {
+  EGLint attribs[] = {
+      EGL_NONE,
+  };
+
+  EGLint num_configs;
+  EGLConfig config;
+  ASSERT_TRUE(eglChooseConfig(display_, attribs, &config, 1, &num_configs));
+
+  std::unique_ptr<android::dvr::DummyNativeWindow> dummy_window(
+      new android::dvr::DummyNativeWindow());
+
+  EGLint context_attribs[] = {
+    EGL_NONE,
+  };
+
+  EGLSurface surface = eglCreateWindowSurface(display_, config,
+                                              dummy_window.get(),
+                                              context_attribs);
+
+  EXPECT_NE(nullptr, surface);
+
+  bool destroyed = eglDestroySurface(display_, surface);
+
+  EXPECT_TRUE(destroyed);
+}
+
diff --git a/libs/vr/libdisplay/tests/graphics_app_tests.cpp b/libs/vr/libdisplay/tests/graphics_app_tests.cpp
index 7ea3952..f51dd8a 100644
--- a/libs/vr/libdisplay/tests/graphics_app_tests.cpp
+++ b/libs/vr/libdisplay/tests/graphics_app_tests.cpp
@@ -1,55 +1,6 @@
 #include <dvr/graphics.h>
 #include <gtest/gtest.h>
 
-TEST(GraphicsAppTests, CreateWarpedDisplaySurfaceParams) {
-  int width = 0, height = 0;
-  EGLNativeWindowType window = dvrCreateWarpedDisplaySurface(&width, &height);
-  EXPECT_GT(width, 0);
-  EXPECT_GT(height, 0);
-  EXPECT_NE(window, nullptr);
-}
-
-TEST(GraphicsAppTests, CreateDisplaySurface) {
-  EGLNativeWindowType window = dvrCreateDisplaySurface();
-  EXPECT_NE(window, nullptr);
-}
-
-TEST(GraphicsAppTests, CreateDisplaySurfaceExtended) {
-  int display_width = 0, display_height = 0;
-  int surface_width = 0, surface_height = 0;
-  float inter_lens_meters = 0.0f;
-  float left_fov[4] = {0.0f};
-  float right_fov[4] = {0.0f};
-  int disable_warp = 0;
-  DvrSurfaceParameter surface_params[] = {
-      DVR_SURFACE_PARAMETER_IN(DISABLE_DISTORTION, disable_warp),
-      DVR_SURFACE_PARAMETER_OUT(DISPLAY_WIDTH, &display_width),
-      DVR_SURFACE_PARAMETER_OUT(DISPLAY_HEIGHT, &display_height),
-      DVR_SURFACE_PARAMETER_OUT(SURFACE_WIDTH, &surface_width),
-      DVR_SURFACE_PARAMETER_OUT(SURFACE_HEIGHT, &surface_height),
-      DVR_SURFACE_PARAMETER_OUT(INTER_LENS_METERS, &inter_lens_meters),
-      DVR_SURFACE_PARAMETER_OUT(LEFT_FOV_LRBT, left_fov),
-      DVR_SURFACE_PARAMETER_OUT(RIGHT_FOV_LRBT, right_fov),
-      DVR_SURFACE_PARAMETER_LIST_END,
-  };
-
-  EGLNativeWindowType window = dvrCreateDisplaySurfaceExtended(surface_params);
-  EXPECT_NE(window, nullptr);
-  EXPECT_GT(display_width, 0);
-  EXPECT_GT(display_height, 0);
-  EXPECT_GT(surface_width, 0);
-  EXPECT_GT(surface_height, 0);
-  EXPECT_GT(inter_lens_meters, 0);
-  EXPECT_GT(left_fov[0], 0);
-  EXPECT_GT(left_fov[1], 0);
-  EXPECT_GT(left_fov[2], 0);
-  EXPECT_GT(left_fov[3], 0);
-  EXPECT_GT(right_fov[0], 0);
-  EXPECT_GT(right_fov[1], 0);
-  EXPECT_GT(right_fov[2], 0);
-  EXPECT_GT(right_fov[3], 0);
-}
-
 TEST(GraphicsAppTests, GetNativeDisplayDimensions) {
   int width, height;
   dvrGetNativeDisplayDimensions(&width, &height);
@@ -57,17 +8,6 @@
   EXPECT_GT(height, 0);
 }
 
-TEST(GraphicsAppTests, GetDisplaySurfaceInfo) {
-  int ret, width, height, format;
-  EGLNativeWindowType window = dvrCreateDisplaySurface();
-  ASSERT_NE(window, nullptr);
-  ret = dvrGetDisplaySurfaceInfo(window, &width, &height, &format);
-  ASSERT_EQ(0, ret);
-  ASSERT_GT(width, 0);
-  ASSERT_GT(height, 0);
-  ASSERT_NE(0, format);
-}
-
 // TODO(jpoichet) How to check it worked?
 TEST(GraphicsAppTests, GraphicsSurfaceSetVisible) {
   DvrSurfaceParameter surface_params[] = {DVR_SURFACE_PARAMETER_LIST_END};
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 4fa6a33..aa67d41 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -77,7 +77,6 @@
         "-DLOG_TAG=\"libEGL\"",
     ],
     shared_libs: [
-        "libbinder",
         "libutils",
         "libui",
         "libnativewindow",
@@ -106,9 +105,20 @@
         "EGL/egl.cpp",
         "EGL/eglApi.cpp",
         "EGL/Loader.cpp",
+        "EGL/BlobCache.cpp",
     ],
     static_libs: ["libEGL_getProcAddress"],
     ldflags: ["-Wl,--exclude-libs=ALL"],
+    export_include_dirs: ["EGL/include"],
+}
+
+cc_test {
+    name: "libEGL_test",
+    defaults: ["egl_libs_defaults"],
+    srcs: [
+        "EGL/BlobCache.cpp",
+        "EGL/BlobCache_test.cpp",
+    ],
 }
 
 cc_defaults {
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
new file mode 100644
index 0000000..f1b30c7
--- /dev/null
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -0,0 +1,373 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+
+#include "BlobCache.h"
+
+#include <inttypes.h>
+
+#include <cutils/properties.h>
+#include <log/log.h>
+#include <chrono>
+
+namespace android {
+
+// BlobCache::Header::mMagicNumber value
+static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$';
+
+// BlobCache::Header::mBlobCacheVersion value
+static const uint32_t blobCacheVersion = 3;
+
+// BlobCache::Header::mDeviceVersion value
+static const uint32_t blobCacheDeviceVersion = 1;
+
+BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize):
+        mMaxKeySize(maxKeySize),
+        mMaxValueSize(maxValueSize),
+        mMaxTotalSize(maxTotalSize),
+        mTotalSize(0) {
+    int64_t now = std::chrono::steady_clock::now().time_since_epoch().count();
+#ifdef _WIN32
+    srand(now);
+#else
+    mRandState[0] = (now >> 0) & 0xFFFF;
+    mRandState[1] = (now >> 16) & 0xFFFF;
+    mRandState[2] = (now >> 32) & 0xFFFF;
+#endif
+    ALOGV("initializing random seed using %lld", (unsigned long long)now);
+}
+
+void BlobCache::set(const void* key, size_t keySize, const void* value,
+        size_t valueSize) {
+    if (mMaxKeySize < keySize) {
+        ALOGV("set: not caching because the key is too large: %zu (limit: %zu)",
+                keySize, mMaxKeySize);
+        return;
+    }
+    if (mMaxValueSize < valueSize) {
+        ALOGV("set: not caching because the value is too large: %zu (limit: %zu)",
+                valueSize, mMaxValueSize);
+        return;
+    }
+    if (mMaxTotalSize < keySize + valueSize) {
+        ALOGV("set: not caching because the combined key/value size is too "
+                "large: %zu (limit: %zu)", keySize + valueSize, mMaxTotalSize);
+        return;
+    }
+    if (keySize == 0) {
+        ALOGW("set: not caching because keySize is 0");
+        return;
+    }
+    if (valueSize <= 0) {
+        ALOGW("set: not caching because valueSize is 0");
+        return;
+    }
+
+    std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false));
+    CacheEntry dummyEntry(dummyKey, NULL);
+
+    while (true) {
+        auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry);
+        if (index == mCacheEntries.end() || dummyEntry < *index) {
+            // Create a new cache entry.
+            std::shared_ptr<Blob> keyBlob(new Blob(key, keySize, true));
+            std::shared_ptr<Blob> valueBlob(new Blob(value, valueSize, true));
+            size_t newTotalSize = mTotalSize + keySize + valueSize;
+            if (mMaxTotalSize < newTotalSize) {
+                if (isCleanable()) {
+                    // Clean the cache and try again.
+                    clean();
+                    continue;
+                } else {
+                    ALOGV("set: not caching new key/value pair because the "
+                            "total cache size limit would be exceeded: %zu "
+                            "(limit: %zu)",
+                            keySize + valueSize, mMaxTotalSize);
+                    break;
+                }
+            }
+            mCacheEntries.insert(index, CacheEntry(keyBlob, valueBlob));
+            mTotalSize = newTotalSize;
+            ALOGV("set: created new cache entry with %zu byte key and %zu byte value",
+                    keySize, valueSize);
+        } else {
+            // Update the existing cache entry.
+            std::shared_ptr<Blob> valueBlob(new Blob(value, valueSize, true));
+            std::shared_ptr<Blob> oldValueBlob(index->getValue());
+            size_t newTotalSize = mTotalSize + valueSize - oldValueBlob->getSize();
+            if (mMaxTotalSize < newTotalSize) {
+                if (isCleanable()) {
+                    // Clean the cache and try again.
+                    clean();
+                    continue;
+                } else {
+                    ALOGV("set: not caching new value because the total cache "
+                            "size limit would be exceeded: %zu (limit: %zu)",
+                            keySize + valueSize, mMaxTotalSize);
+                    break;
+                }
+            }
+            index->setValue(valueBlob);
+            mTotalSize = newTotalSize;
+            ALOGV("set: updated existing cache entry with %zu byte key and %zu byte "
+                    "value", keySize, valueSize);
+        }
+        break;
+    }
+}
+
+size_t BlobCache::get(const void* key, size_t keySize, void* value,
+        size_t valueSize) {
+    if (mMaxKeySize < keySize) {
+        ALOGV("get: not searching because the key is too large: %zu (limit %zu)",
+                keySize, mMaxKeySize);
+        return 0;
+    }
+    std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false));
+    CacheEntry dummyEntry(dummyKey, NULL);
+    auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry);
+    if (index == mCacheEntries.end() || dummyEntry < *index) {
+        ALOGV("get: no cache entry found for key of size %zu", keySize);
+        return 0;
+    }
+
+    // The key was found. Return the value if the caller's buffer is large
+    // enough.
+    std::shared_ptr<Blob> valueBlob(index->getValue());
+    size_t valueBlobSize = valueBlob->getSize();
+    if (valueBlobSize <= valueSize) {
+        ALOGV("get: copying %zu bytes to caller's buffer", valueBlobSize);
+        memcpy(value, valueBlob->getData(), valueBlobSize);
+    } else {
+        ALOGV("get: caller's buffer is too small for value: %zu (needs %zu)",
+                valueSize, valueBlobSize);
+    }
+    return valueBlobSize;
+}
+
+static inline size_t align4(size_t size) {
+    return (size + 3) & ~3;
+}
+
+size_t BlobCache::getFlattenedSize() const {
+    size_t size = align4(sizeof(Header) + PROPERTY_VALUE_MAX);
+    for (const CacheEntry& e :  mCacheEntries) {
+        std::shared_ptr<Blob> const& keyBlob = e.getKey();
+        std::shared_ptr<Blob> const& valueBlob = e.getValue();
+        size += align4(sizeof(EntryHeader) + keyBlob->getSize() + valueBlob->getSize());
+    }
+    return size;
+}
+
+int BlobCache::flatten(void* buffer, size_t size) const {
+    // Write the cache header
+    if (size < sizeof(Header)) {
+        ALOGE("flatten: not enough room for cache header");
+        return 0;
+    }
+    Header* header = reinterpret_cast<Header*>(buffer);
+    header->mMagicNumber = blobCacheMagic;
+    header->mBlobCacheVersion = blobCacheVersion;
+    header->mDeviceVersion = blobCacheDeviceVersion;
+    header->mNumEntries = mCacheEntries.size();
+    char buildId[PROPERTY_VALUE_MAX];
+    header->mBuildIdLength = property_get("ro.build.id", buildId, "");
+    memcpy(header->mBuildId, buildId, header->mBuildIdLength);
+
+    // Write cache entries
+    uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer);
+    off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength);
+    for (const CacheEntry& e :  mCacheEntries) {
+        std::shared_ptr<Blob> const& keyBlob = e.getKey();
+        std::shared_ptr<Blob> const& valueBlob = e.getValue();
+        size_t keySize = keyBlob->getSize();
+        size_t valueSize = valueBlob->getSize();
+
+        size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
+        size_t totalSize = align4(entrySize);
+        if (byteOffset + totalSize > size) {
+            ALOGE("flatten: not enough room for cache entries");
+            return -EINVAL;
+        }
+
+        EntryHeader* eheader = reinterpret_cast<EntryHeader*>(&byteBuffer[byteOffset]);
+        eheader->mKeySize = keySize;
+        eheader->mValueSize = valueSize;
+
+        memcpy(eheader->mData, keyBlob->getData(), keySize);
+        memcpy(eheader->mData + keySize, valueBlob->getData(), valueSize);
+
+        if (totalSize > entrySize) {
+            // We have padding bytes. Those will get written to storage, and contribute to the CRC,
+            // so make sure we zero-them to have reproducible results.
+            memset(eheader->mData + keySize + valueSize, 0, totalSize - entrySize);
+        }
+
+        byteOffset += totalSize;
+    }
+
+    return 0;
+}
+
+int BlobCache::unflatten(void const* buffer, size_t size) {
+    // All errors should result in the BlobCache being in an empty state.
+    mCacheEntries.clear();
+
+    // Read the cache header
+    if (size < sizeof(Header)) {
+        ALOGE("unflatten: not enough room for cache header");
+        return -EINVAL;
+    }
+    const Header* header = reinterpret_cast<const Header*>(buffer);
+    if (header->mMagicNumber != blobCacheMagic) {
+        ALOGE("unflatten: bad magic number: %" PRIu32, header->mMagicNumber);
+        return -EINVAL;
+    }
+    char buildId[PROPERTY_VALUE_MAX];
+    int len = property_get("ro.build.id", buildId, "");
+    if (header->mBlobCacheVersion != blobCacheVersion ||
+            header->mDeviceVersion != blobCacheDeviceVersion ||
+            len != header->mBuildIdLength ||
+            strncmp(buildId, header->mBuildId, len)) {
+        // We treat version mismatches as an empty cache.
+        return 0;
+    }
+
+    // Read cache entries
+    const uint8_t* byteBuffer = reinterpret_cast<const uint8_t*>(buffer);
+    off_t byteOffset = align4(sizeof(Header) + header->mBuildIdLength);
+    size_t numEntries = header->mNumEntries;
+    for (size_t i = 0; i < numEntries; i++) {
+        if (byteOffset + sizeof(EntryHeader) > size) {
+            mCacheEntries.clear();
+            ALOGE("unflatten: not enough room for cache entry headers");
+            return -EINVAL;
+        }
+
+        const EntryHeader* eheader = reinterpret_cast<const EntryHeader*>(
+                &byteBuffer[byteOffset]);
+        size_t keySize = eheader->mKeySize;
+        size_t valueSize = eheader->mValueSize;
+        size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
+
+        size_t totalSize = align4(entrySize);
+        if (byteOffset + totalSize > size) {
+            mCacheEntries.clear();
+            ALOGE("unflatten: not enough room for cache entry headers");
+            return -EINVAL;
+        }
+
+        const uint8_t* data = eheader->mData;
+        set(data, keySize, data + keySize, valueSize);
+
+        byteOffset += totalSize;
+    }
+
+    return 0;
+}
+
+long int BlobCache::blob_random() {
+#ifdef _WIN32
+    return rand();
+#else
+    return nrand48(mRandState);
+#endif
+}
+
+void BlobCache::clean() {
+    // Remove a random cache entry until the total cache size gets below half
+    // the maximum total cache size.
+    while (mTotalSize > mMaxTotalSize / 2) {
+        size_t i = size_t(blob_random() % (mCacheEntries.size()));
+        const CacheEntry& entry(mCacheEntries[i]);
+        mTotalSize -= entry.getKey()->getSize() + entry.getValue()->getSize();
+        mCacheEntries.erase(mCacheEntries.begin() + i);
+    }
+}
+
+bool BlobCache::isCleanable() const {
+    return mTotalSize > mMaxTotalSize / 2;
+}
+
+BlobCache::Blob::Blob(const void* data, size_t size, bool copyData) :
+        mData(copyData ? malloc(size) : data),
+        mSize(size),
+        mOwnsData(copyData) {
+    if (data != NULL && copyData) {
+        memcpy(const_cast<void*>(mData), data, size);
+    }
+}
+
+BlobCache::Blob::~Blob() {
+    if (mOwnsData) {
+        free(const_cast<void*>(mData));
+    }
+}
+
+bool BlobCache::Blob::operator<(const Blob& rhs) const {
+    if (mSize == rhs.mSize) {
+        return memcmp(mData, rhs.mData, mSize) < 0;
+    } else {
+        return mSize < rhs.mSize;
+    }
+}
+
+const void* BlobCache::Blob::getData() const {
+    return mData;
+}
+
+size_t BlobCache::Blob::getSize() const {
+    return mSize;
+}
+
+BlobCache::CacheEntry::CacheEntry() {
+}
+
+BlobCache::CacheEntry::CacheEntry(
+        const std::shared_ptr<Blob>& key, const std::shared_ptr<Blob>& value):
+        mKey(key),
+        mValue(value) {
+}
+
+BlobCache::CacheEntry::CacheEntry(const CacheEntry& ce):
+        mKey(ce.mKey),
+        mValue(ce.mValue) {
+}
+
+bool BlobCache::CacheEntry::operator<(const CacheEntry& rhs) const {
+    return *mKey < *rhs.mKey;
+}
+
+const BlobCache::CacheEntry& BlobCache::CacheEntry::operator=(const CacheEntry& rhs) {
+    mKey = rhs.mKey;
+    mValue = rhs.mValue;
+    return *this;
+}
+
+std::shared_ptr<BlobCache::Blob> BlobCache::CacheEntry::getKey() const {
+    return mKey;
+}
+
+std::shared_ptr<BlobCache::Blob> BlobCache::CacheEntry::getValue() const {
+    return mValue;
+}
+
+void BlobCache::CacheEntry::setValue(const std::shared_ptr<Blob>& value) {
+    mValue = value;
+}
+
+} // namespace android
diff --git a/opengl/libs/EGL/BlobCache.h b/opengl/libs/EGL/BlobCache.h
new file mode 100644
index 0000000..a0a270a
--- /dev/null
+++ b/opengl/libs/EGL/BlobCache.h
@@ -0,0 +1,245 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef ANDROID_BLOB_CACHE_H
+#define ANDROID_BLOB_CACHE_H
+
+#include <stddef.h>
+
+#include <memory>
+#include <vector>
+
+namespace android {
+
+// A BlobCache is an in-memory cache for binary key/value pairs.  A BlobCache
+// does NOT provide any thread-safety guarantees.
+//
+// The cache contents can be serialized to an in-memory buffer or mmap'd file
+// and then reloaded in a subsequent execution of the program.  This
+// serialization is non-portable and the data should only be used by the device
+// that generated it.
+class BlobCache {
+public:
+    // Create an empty blob cache. The blob cache will cache key/value pairs
+    // with key and value sizes less than or equal to maxKeySize and
+    // maxValueSize, respectively. The total combined size of ALL cache entries
+    // (key sizes plus value sizes) will not exceed maxTotalSize.
+    BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize);
+
+    // set inserts a new binary value into the cache and associates it with the
+    // given binary key.  If the key or value are too large for the cache then
+    // the cache remains unchanged.  This includes the case where a different
+    // value was previously associated with the given key - the old value will
+    // remain in the cache.  If the given key and value are small enough to be
+    // put in the cache (based on the maxKeySize, maxValueSize, and maxTotalSize
+    // values specified to the BlobCache constructor), then the key/value pair
+    // will be in the cache after set returns.  Note, however, that a subsequent
+    // call to set may evict old key/value pairs from the cache.
+    //
+    // Preconditions:
+    //   key != NULL
+    //   0 < keySize
+    //   value != NULL
+    //   0 < valueSize
+    void set(const void* key, size_t keySize, const void* value,
+            size_t valueSize);
+
+    // get retrieves from the cache the binary value associated with a given
+    // binary key.  If the key is present in the cache then the length of the
+    // binary value associated with that key is returned.  If the value argument
+    // is non-NULL and the size of the cached value is less than valueSize bytes
+    // then the cached value is copied into the buffer pointed to by the value
+    // argument.  If the key is not present in the cache then 0 is returned and
+    // the buffer pointed to by the value argument is not modified.
+    //
+    // Note that when calling get multiple times with the same key, the later
+    // calls may fail, returning 0, even if earlier calls succeeded.  The return
+    // value must be checked for each call.
+    //
+    // Preconditions:
+    //   key != NULL
+    //   0 < keySize
+    //   0 <= valueSize
+    size_t get(const void* key, size_t keySize, void* value, size_t valueSize);
+
+
+    // getFlattenedSize returns the number of bytes needed to store the entire
+    // serialized cache.
+    size_t getFlattenedSize() const;
+
+    // flatten serializes the current contents of the cache into the memory
+    // pointed to by 'buffer'.  The serialized cache contents can later be
+    // loaded into a BlobCache object using the unflatten method.  The contents
+    // of the BlobCache object will not be modified.
+    //
+    // Preconditions:
+    //   size >= this.getFlattenedSize()
+    int flatten(void* buffer, size_t size) const;
+
+    // unflatten replaces the contents of the cache with the serialized cache
+    // contents in the memory pointed to by 'buffer'.  The previous contents of
+    // the BlobCache will be evicted from the cache.  If an error occurs while
+    // unflattening the serialized cache contents then the BlobCache will be
+    // left in an empty state.
+    //
+    int unflatten(void const* buffer, size_t size);
+
+private:
+    // Copying is disallowed.
+    BlobCache(const BlobCache&);
+    void operator=(const BlobCache&);
+
+    // A random function helper to get around MinGW not having nrand48()
+    long int blob_random();
+
+    // clean evicts a randomly chosen set of entries from the cache such that
+    // the total size of all remaining entries is less than mMaxTotalSize/2.
+    void clean();
+
+    // isCleanable returns true if the cache is full enough for the clean method
+    // to have some effect, and false otherwise.
+    bool isCleanable() const;
+
+    // A Blob is an immutable sized unstructured data blob.
+    class Blob {
+    public:
+        Blob(const void* data, size_t size, bool copyData);
+        ~Blob();
+
+        bool operator<(const Blob& rhs) const;
+
+        const void* getData() const;
+        size_t getSize() const;
+
+    private:
+        // Copying is not allowed.
+        Blob(const Blob&);
+        void operator=(const Blob&);
+
+        // mData points to the buffer containing the blob data.
+        const void* mData;
+
+        // mSize is the size of the blob data in bytes.
+        size_t mSize;
+
+        // mOwnsData indicates whether or not this Blob object should free the
+        // memory pointed to by mData when the Blob gets destructed.
+        bool mOwnsData;
+    };
+
+    // A CacheEntry is a single key/value pair in the cache.
+    class CacheEntry {
+    public:
+        CacheEntry();
+        CacheEntry(const std::shared_ptr<Blob>& key, const std::shared_ptr<Blob>& value);
+        CacheEntry(const CacheEntry& ce);
+
+        bool operator<(const CacheEntry& rhs) const;
+        const CacheEntry& operator=(const CacheEntry&);
+
+        std::shared_ptr<Blob> getKey() const;
+        std::shared_ptr<Blob> getValue() const;
+
+        void setValue(const std::shared_ptr<Blob>& value);
+
+    private:
+
+        // mKey is the key that identifies the cache entry.
+        std::shared_ptr<Blob> mKey;
+
+        // mValue is the cached data associated with the key.
+        std::shared_ptr<Blob> mValue;
+    };
+
+    // A Header is the header for the entire BlobCache serialization format. No
+    // need to make this portable, so we simply write the struct out.
+    struct Header {
+        // mMagicNumber is the magic number that identifies the data as
+        // serialized BlobCache contents.  It must always contain 'Blb$'.
+        uint32_t mMagicNumber;
+
+        // mBlobCacheVersion is the serialization format version.
+        uint32_t mBlobCacheVersion;
+
+        // mDeviceVersion is the device-specific version of the cache.  This can
+        // be used to invalidate the cache.
+        uint32_t mDeviceVersion;
+
+        // mNumEntries is number of cache entries following the header in the
+        // data.
+        size_t mNumEntries;
+
+        // mBuildId is the build id of the device when the cache was created.
+        // When an update to the build happens (via an OTA or other update) this
+        // is used to invalidate the cache.
+        int mBuildIdLength;
+        char mBuildId[];
+    };
+
+    // An EntryHeader is the header for a serialized cache entry.  No need to
+    // make this portable, so we simply write the struct out.  Each EntryHeader
+    // is followed imediately by the key data and then the value data.
+    //
+    // The beginning of each serialized EntryHeader is 4-byte aligned, so the
+    // number of bytes that a serialized cache entry will occupy is:
+    //
+    //   ((sizeof(EntryHeader) + keySize + valueSize) + 3) & ~3
+    //
+    struct EntryHeader {
+        // mKeySize is the size of the entry key in bytes.
+        size_t mKeySize;
+
+        // mValueSize is the size of the entry value in bytes.
+        size_t mValueSize;
+
+        // mData contains both the key and value data for the cache entry.  The
+        // key comes first followed immediately by the value.
+        uint8_t mData[];
+    };
+
+    // mMaxKeySize is the maximum key size that will be cached. Calls to
+    // BlobCache::set with a keySize parameter larger than mMaxKeySize will
+    // simply not add the key/value pair to the cache.
+    const size_t mMaxKeySize;
+
+    // mMaxValueSize is the maximum value size that will be cached. Calls to
+    // BlobCache::set with a valueSize parameter larger than mMaxValueSize will
+    // simply not add the key/value pair to the cache.
+    const size_t mMaxValueSize;
+
+    // mMaxTotalSize is the maximum size that all cache entries can occupy. This
+    // includes space for both keys and values. When a call to BlobCache::set
+    // would otherwise cause this limit to be exceeded, either the key/value
+    // pair passed to BlobCache::set will not be cached or other cache entries
+    // will be evicted from the cache to make room for the new entry.
+    const size_t mMaxTotalSize;
+
+    // mTotalSize is the total combined size of all keys and values currently in
+    // the cache.
+    size_t mTotalSize;
+
+    // mRandState is the pseudo-random number generator state. It is passed to
+    // nrand48 to generate random numbers when needed.
+    unsigned short mRandState[3];
+
+    // mCacheEntries stores all the cache entries that are resident in memory.
+    // Cache entries are added to it by the 'set' method.
+    std::vector<CacheEntry> mCacheEntries;
+};
+
+}
+
+#endif // ANDROID_BLOB_CACHE_H
diff --git a/opengl/libs/EGL/BlobCache_test.cpp b/opengl/libs/EGL/BlobCache_test.cpp
new file mode 100644
index 0000000..edbaaf0
--- /dev/null
+++ b/opengl/libs/EGL/BlobCache_test.cpp
@@ -0,0 +1,434 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include "BlobCache.h"
+
+namespace android {
+
+template<typename T> using sp = std::shared_ptr<T>;
+
+class BlobCacheTest : public ::testing::Test {
+protected:
+
+    enum {
+        OK = 0,
+        BAD_VALUE = -EINVAL
+    };
+
+    enum {
+        MAX_KEY_SIZE = 6,
+        MAX_VALUE_SIZE = 8,
+        MAX_TOTAL_SIZE = 13,
+    };
+
+    virtual void SetUp() {
+        mBC.reset(new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE));
+    }
+
+    virtual void TearDown() {
+        mBC.reset();
+    }
+
+    std::unique_ptr<BlobCache> mBC;
+};
+
+TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+    ASSERT_EQ('e', buf[0]);
+    ASSERT_EQ('f', buf[1]);
+    ASSERT_EQ('g', buf[2]);
+    ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
+    unsigned char buf[2] = { 0xee, 0xee };
+    mBC->set("ab", 2, "cd", 2);
+    mBC->set("ef", 2, "gh", 2);
+    ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
+    ASSERT_EQ('c', buf[0]);
+    ASSERT_EQ('d', buf[1]);
+    ASSERT_EQ(size_t(2), mBC->get("ef", 2, buf, 2));
+    ASSERT_EQ('g', buf[0]);
+    ASSERT_EQ('h', buf[1]);
+}
+
+TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
+    unsigned char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ('e', buf[1]);
+    ASSERT_EQ('f', buf[2]);
+    ASSERT_EQ('g', buf[3]);
+    ASSERT_EQ('h', buf[4]);
+    ASSERT_EQ(0xee, buf[5]);
+}
+
+TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
+    unsigned char buf[3] = { 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ(0xee, buf[1]);
+    ASSERT_EQ(0xee, buf[2]);
+}
+
+TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    mBC->set("abcd", 4, "ijkl", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+    ASSERT_EQ('i', buf[0]);
+    ASSERT_EQ('j', buf[1]);
+    ASSERT_EQ('k', buf[2]);
+    ASSERT_EQ('l', buf[3]);
+}
+
+TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
+    unsigned char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+    ASSERT_EQ('e', buf[0]);
+    ASSERT_EQ('f', buf[1]);
+    ASSERT_EQ('g', buf[2]);
+    ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) {
+    char key[MAX_KEY_SIZE+1];
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    for (int i = 0; i < MAX_KEY_SIZE+1; i++) {
+        key[i] = 'a';
+    }
+    mBC->set(key, MAX_KEY_SIZE+1, "bbbb", 4);
+    ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE+1, buf, 4));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ(0xee, buf[1]);
+    ASSERT_EQ(0xee, buf[2]);
+    ASSERT_EQ(0xee, buf[3]);
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) {
+    char buf[MAX_VALUE_SIZE+1];
+    for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+        buf[i] = 'b';
+    }
+    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
+    for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+        buf[i] = 0xee;
+    }
+    ASSERT_EQ(size_t(0), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE+1));
+    for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+        SCOPED_TRACE(i);
+        ASSERT_EQ(0xee, buf[i]);
+    }
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfKeyValuePairIsTooBig) {
+    // Check a testing assumptions
+    ASSERT_TRUE(MAX_TOTAL_SIZE < MAX_KEY_SIZE + MAX_VALUE_SIZE);
+    ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+    enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE + 1 };
+
+    char key[MAX_KEY_SIZE];
+    char buf[bufSize];
+    for (int i = 0; i < MAX_KEY_SIZE; i++) {
+        key[i] = 'a';
+    }
+    for (int i = 0; i < bufSize; i++) {
+        buf[i] = 'b';
+    }
+
+    mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE);
+    ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
+    char key[MAX_KEY_SIZE];
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    for (int i = 0; i < MAX_KEY_SIZE; i++) {
+        key[i] = 'a';
+    }
+    mBC->set(key, MAX_KEY_SIZE, "wxyz", 4);
+    ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4));
+    ASSERT_EQ('w', buf[0]);
+    ASSERT_EQ('x', buf[1]);
+    ASSERT_EQ('y', buf[2]);
+    ASSERT_EQ('z', buf[3]);
+}
+
+TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) {
+    char buf[MAX_VALUE_SIZE];
+    for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+        buf[i] = 'b';
+    }
+    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE);
+    for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+        buf[i] = 0xee;
+    }
+    ASSERT_EQ(size_t(MAX_VALUE_SIZE), mBC->get("abcd", 4, buf,
+            MAX_VALUE_SIZE));
+    for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+        SCOPED_TRACE(i);
+        ASSERT_EQ('b', buf[i]);
+    }
+}
+
+TEST_F(BlobCacheTest, CacheMaxKeyValuePairSizeSucceeds) {
+    // Check a testing assumption
+    ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+    enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE };
+
+    char key[MAX_KEY_SIZE];
+    char buf[bufSize];
+    for (int i = 0; i < MAX_KEY_SIZE; i++) {
+        key[i] = 'a';
+    }
+    for (int i = 0; i < bufSize; i++) {
+        buf[i] = 'b';
+    }
+
+    mBC->set(key, MAX_KEY_SIZE, buf, bufSize);
+    ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
+    unsigned char buf[1] = { 0xee };
+    mBC->set("x", 1, "y", 1);
+    ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
+    ASSERT_EQ('y', buf[0]);
+}
+
+TEST_F(BlobCacheTest, CacheSizeDoesntExceedTotalLimit) {
+    for (int i = 0; i < 256; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, "x", 1);
+    }
+    int numCached = 0;
+    for (int i = 0; i < 256; i++) {
+        uint8_t k = i;
+        if (mBC->get(&k, 1, NULL, 0) == 1) {
+            numCached++;
+        }
+    }
+    ASSERT_GE(MAX_TOTAL_SIZE / 2, numCached);
+}
+
+TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) {
+    // Fill up the entire cache with 1 char key/value pairs.
+    const int maxEntries = MAX_TOTAL_SIZE / 2;
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, "x", 1);
+    }
+    // Insert one more entry, causing a cache overflow.
+    {
+        uint8_t k = maxEntries;
+        mBC->set(&k, 1, "x", 1);
+    }
+    // Count the number of entries in the cache.
+    int numCached = 0;
+    for (int i = 0; i < maxEntries+1; i++) {
+        uint8_t k = i;
+        if (mBC->get(&k, 1, NULL, 0) == 1) {
+            numCached++;
+        }
+    }
+    ASSERT_EQ(maxEntries/2 + 1, numCached);
+}
+
+class BlobCacheFlattenTest : public BlobCacheTest {
+protected:
+    virtual void SetUp() {
+        BlobCacheTest::SetUp();
+        mBC2.reset(new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE));
+    }
+
+    virtual void TearDown() {
+        mBC2.reset();
+        BlobCacheTest::TearDown();
+    }
+
+    void roundTrip() {
+        size_t size = mBC->getFlattenedSize();
+        uint8_t* flat = new uint8_t[size];
+        ASSERT_EQ(OK, mBC->flatten(flat, size));
+        ASSERT_EQ(OK, mBC2->unflatten(flat, size));
+        delete[] flat;
+    }
+
+    sp<BlobCache> mBC2;
+};
+
+TEST_F(BlobCacheFlattenTest, FlattenOneValue) {
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    roundTrip();
+    ASSERT_EQ(size_t(4), mBC2->get("abcd", 4, buf, 4));
+    ASSERT_EQ('e', buf[0]);
+    ASSERT_EQ('f', buf[1]);
+    ASSERT_EQ('g', buf[2]);
+    ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheFlattenTest, FlattenFullCache) {
+    // Fill up the entire cache with 1 char key/value pairs.
+    const int maxEntries = MAX_TOTAL_SIZE / 2;
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, &k, 1);
+    }
+
+    roundTrip();
+
+    // Verify the deserialized cache
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        uint8_t v = 0xee;
+        ASSERT_EQ(size_t(1), mBC2->get(&k, 1, &v, 1));
+        ASSERT_EQ(k, v);
+    }
+}
+
+TEST_F(BlobCacheFlattenTest, FlattenDoesntChangeCache) {
+    // Fill up the entire cache with 1 char key/value pairs.
+    const int maxEntries = MAX_TOTAL_SIZE / 2;
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, &k, 1);
+    }
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size));
+    delete[] flat;
+
+    // Verify the cache that we just serialized
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        uint8_t v = 0xee;
+        ASSERT_EQ(size_t(1), mBC->get(&k, 1, &v, 1));
+        ASSERT_EQ(k, v);
+    }
+}
+
+TEST_F(BlobCacheFlattenTest, FlattenCatchesBufferTooSmall) {
+    // Fill up the entire cache with 1 char key/value pairs.
+    const int maxEntries = MAX_TOTAL_SIZE / 2;
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, &k, 1);
+    }
+
+    size_t size = mBC->getFlattenedSize() - 1;
+    uint8_t* flat = new uint8_t[size];
+    // ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size));
+    // TODO: The above fails. I expect this is so because getFlattenedSize()
+    // overstimates the size by using PROPERTY_VALUE_MAX.
+    delete[] flat;
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) {
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size));
+    flat[1] = ~flat[1];
+
+    // Bad magic should cause an error.
+    ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size));
+    delete[] flat;
+
+    // The error should cause the unflatten to result in an empty cache
+    ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) {
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size));
+    flat[5] = ~flat[5];
+
+    // Version mismatches shouldn't cause errors, but should not use the
+    // serialized entries
+    ASSERT_EQ(OK, mBC2->unflatten(flat, size));
+    delete[] flat;
+
+    // The version mismatch should cause the unflatten to result in an empty
+    // cache
+    ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) {
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size));
+    flat[10] = ~flat[10];
+
+    // Version mismatches shouldn't cause errors, but should not use the
+    // serialized entries
+    ASSERT_EQ(OK, mBC2->unflatten(flat, size));
+    delete[] flat;
+
+    // The version mismatch should cause the unflatten to result in an empty
+    // cache
+    ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) {
+    unsigned char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size));
+
+    // A buffer truncation shouldt cause an error
+    // ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1));
+    // TODO: The above appears to fail because getFlattenedSize() is
+    // conservative.
+    delete[] flat;
+
+    // The error should cause the unflatten to result in an empty cache
+    ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+} // namespace android
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 9aedc61..683e6ca 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -19,6 +19,8 @@
 
 #include "Loader.h"
 
+#include <string>
+
 #include <dirent.h>
 #include <dlfcn.h>
 
@@ -26,11 +28,9 @@
 #include <cutils/properties.h>
 #include <log/log.h>
 
-#include <utils/String8.h>
-#include <utils/Trace.h>
-
 #include <ui/GraphicsEnv.h>
 
+#include "egl_trace.h"
 #include "egldefs.h"
 
 // ----------------------------------------------------------------------------
@@ -61,7 +61,10 @@
  *
  */
 
-ANDROID_SINGLETON_STATIC_INSTANCE( Loader )
+Loader& Loader::getInstance() {
+    static Loader loader;
+    return loader;
+}
 
 /* This function is called to check whether we run inside the emulator,
  * and if this is the case whether GLES GPU emulation is supported.
@@ -122,7 +125,7 @@
     }
 }
 
-status_t Loader::driver_t::set(void* hnd, int32_t api)
+int Loader::driver_t::set(void* hnd, int32_t api)
 {
     switch (api) {
         case EGL:
@@ -135,9 +138,9 @@
             dso[2] = hnd;
             break;
         default:
-            return BAD_INDEX;
+            return -EOVERFLOW;
     }
-    return NO_ERROR;
+    return 0;
 }
 
 // ----------------------------------------------------------------------------
@@ -233,11 +236,10 @@
     return (void*)hnd;
 }
 
-status_t Loader::close(void* driver)
+void Loader::close(void* driver)
 {
     driver_t* hnd = (driver_t*)driver;
     delete hnd;
-    return NO_ERROR;
 }
 
 void Loader::init_api(void* dso,
@@ -302,23 +304,23 @@
     ATRACE_CALL();
     class MatchFile {
     public:
-        static String8 find(const char* kind) {
-            String8 result;
+        static std::string find(const char* kind) {
+            std::string result;
             int emulationStatus = checkGlesEmulationStatus();
             switch (emulationStatus) {
                 case 0:
 #if defined(__LP64__)
-                    result.setTo("/system/lib64/egl/libGLES_android.so");
+                    result = "/system/lib64/egl/libGLES_android.so";
 #else
-                    result.setTo("/system/lib/egl/libGLES_android.so");
+                    result = "/system/lib/egl/libGLES_android.so";
 #endif
                     return result;
                 case 1:
                     // Use host-side OpenGL through the "emulation" library
 #if defined(__LP64__)
-                    result.appendFormat("/system/lib64/egl/lib%s_emulation.so", kind);
+                    result = std::string("/system/lib64/egl/lib") + kind + "_emulation.so";
 #else
-                    result.appendFormat("/system/lib/egl/lib%s_emulation.so", kind);
+                    result = std::string("/system/lib/egl/lib") + kind + "_emulation.so";
 #endif
                     return result;
                 default:
@@ -326,8 +328,7 @@
                     break;
             }
 
-            String8 pattern;
-            pattern.appendFormat("lib%s", kind);
+            std::string pattern = std::string("lib") + kind;
             const char* const searchPaths[] = {
 #if defined(__LP64__)
                     "/vendor/lib64/egl",
@@ -368,12 +369,11 @@
         }
 
     private:
-        static bool find(String8& result,
-                const String8& pattern, const char* const search, bool exact) {
+        static bool find(std::string& result,
+                const std::string& pattern, const char* const search, bool exact) {
             if (exact) {
-                String8 absolutePath;
-                absolutePath.appendFormat("%s/%s.so", search, pattern.string());
-                if (!access(absolutePath.string(), R_OK)) {
+                std::string absolutePath = std::string(search) + "/" + pattern;
+                if (!access(absolutePath.c_str(), R_OK)) {
                     result = absolutePath;
                     return true;
                 }
@@ -392,10 +392,9 @@
                         // always skip the software renderer
                         continue;
                     }
-                    if (strstr(e->d_name, pattern.string()) == e->d_name) {
+                    if (strstr(e->d_name, pattern.c_str()) == e->d_name) {
                         if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) {
-                            result.clear();
-                            result.appendFormat("%s/%s", search, e->d_name);
+                            result = std::string(search) + "/" + e->d_name;
                             closedir(d);
                             return true;
                         }
@@ -408,17 +407,17 @@
     };
 
 
-    String8 absolutePath = MatchFile::find(kind);
-    if (absolutePath.isEmpty()) {
+    std::string absolutePath = MatchFile::find(kind);
+    if (absolutePath.empty()) {
         // this happens often, we don't want to log an error
         return 0;
     }
-    const char* const driver_absolute_path = absolutePath.string();
+    const char* const driver_absolute_path = absolutePath.c_str();
 
     void* dso = do_dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
     if (dso == 0) {
         const char* err = dlerror();
-        ALOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown");
+        ALOGE("load_driver(%s): %s", driver_absolute_path, err ? err : "unknown");
         return 0;
     }
 
@@ -447,9 +446,8 @@
     char prop[PROPERTY_VALUE_MAX + 1];
     for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
         if (property_get(key, prop, nullptr) > 0) {
-            String8 name;
-            name.appendFormat("lib%s_%s.so", kind, prop);
-            so = do_android_dlopen_ext(name.string(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+            std::string name = std::string("lib") + kind + "_" + prop + ".so";
+            so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
             if (so) {
                 return so;
             }
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 2dd4206..6a32bb3 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -19,9 +19,6 @@
 
 #include <stdint.h>
 
-#include <utils/Errors.h>
-#include <utils/Singleton.h>
-
 #include <EGL/egl.h>
 
 // ----------------------------------------------------------------------------
@@ -30,9 +27,7 @@
 
 struct egl_connection_t;
 
-class Loader : public Singleton<Loader> {
-    friend class Singleton<Loader>;
-
+class Loader {
     typedef __eglMustCastToProperFunctionPointerType (* getProcAddressType)(const char*);
    
     enum {
@@ -43,17 +38,19 @@
     struct driver_t {
         explicit driver_t(void* gles);
         ~driver_t();
-        status_t set(void* hnd, int32_t api);
+        // returns -errno
+        int set(void* hnd, int32_t api);
         void* dso[3];
     };
     
     getProcAddressType getProcAddress;
 
 public:
+    static Loader& getInstance();
     ~Loader();
     
     void* open(egl_connection_t* cnx);
-    status_t close(void* driver);
+    void close(void* driver);
     
 private:
     Loader();
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 34b0ba2..f44c1ca 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -20,7 +20,6 @@
 
 #include <EGL/egl.h>
 
-#include <cutils/atomic.h>
 #include <cutils/properties.h>
 
 #include <log/log.h>
@@ -128,7 +127,7 @@
     if (name != GL_EXTENSIONS)
         return NULL;
 
-    return (const GLubyte *)c->gl_extensions.string();
+    return (const GLubyte *)c->gl_extensions.c_str();
 }
 
 const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index) {
@@ -151,7 +150,7 @@
     if (index >= c->tokenized_gl_extensions.size())
         return NULL;
 
-    return (const GLubyte *)c->tokenized_gl_extensions.itemAt(index).string();
+    return (const GLubyte *)c->tokenized_gl_extensions[index].c_str();
 }
 
 GLint egl_get_num_extensions_for_current_context() {
@@ -208,14 +207,14 @@
 }
 
 static pthread_mutex_t sLogPrintMutex = PTHREAD_MUTEX_INITIALIZER;
-static nsecs_t sLogPrintTime = 0;
-#define NSECS_DURATION 1000000000
+static std::chrono::steady_clock::time_point sLogPrintTime;
+static constexpr std::chrono::seconds DURATION(1);
 
 void gl_unimplemented() {
     bool printLog = false;
-    nsecs_t now = systemTime();
+    auto now = std::chrono::steady_clock::now();
     pthread_mutex_lock(&sLogPrintMutex);
-    if ((now - sLogPrintTime) > NSECS_DURATION) {
+    if ((now - sLogPrintTime) > DURATION) {
         sLogPrintTime = now;
         printLog = true;
     }
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index e52713f..d124c89 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -33,25 +33,19 @@
 #include <cutils/properties.h>
 #include <log/log.h>
 
-#include <gui/ISurfaceComposer.h>
-
-#include <ui/GraphicBuffer.h>
-
-
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/Trace.h>
-#include <utils/Thread.h>
-
-#include "binder/Binder.h"
-#include "binder/Parcel.h"
-#include "binder/IServiceManager.h"
+#include <condition_variable>
+#include <deque>
+#include <mutex>
+#include <unordered_map>
+#include <string>
+#include <thread>
 
 #include "../egl_impl.h"
 
 #include "egl_display.h"
 #include "egl_object.h"
 #include "egl_tls.h"
+#include "egl_trace.h"
 
 using namespace android;
 
@@ -59,6 +53,8 @@
 
 namespace android {
 
+using nsecs_t = int64_t;
+
 struct extention_map_t {
     const char* name;
     __eglMustCastToProperFunctionPointerType address;
@@ -87,7 +83,6 @@
         "EGL_KHR_get_all_proc_addresses "
         "EGL_ANDROID_presentation_time "
         "EGL_KHR_swap_buffers_with_damage "
-        "EGL_ANDROID_create_native_client_buffer "
         "EGL_ANDROID_get_native_client_buffer "
         "EGL_ANDROID_front_buffer_auto_refresh "
         "EGL_ANDROID_get_frame_timestamps "
@@ -184,10 +179,6 @@
     { "eglSwapBuffersWithDamageKHR",
             (__eglMustCastToProperFunctionPointerType)&eglSwapBuffersWithDamageKHR },
 
-    // EGL_ANDROID_create_native_client_buffer
-    { "eglCreateNativeClientBufferANDROID",
-            (__eglMustCastToProperFunctionPointerType)&eglCreateNativeClientBufferANDROID },
-
     // EGL_ANDROID_get_native_client_buffer
     { "eglGetNativeClientBufferANDROID",
             (__eglMustCastToProperFunctionPointerType)&eglGetNativeClientBufferANDROID },
@@ -247,7 +238,8 @@
 
 
 // accesses protected by sExtensionMapMutex
-static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
+static std::unordered_map<std::string, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
+
 static int sGLExtentionSlot = 0;
 static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;
 
@@ -478,8 +470,18 @@
     if (dp) {
         EGLDisplay iDpy = dp->disp.dpy;
 
+        if (!window) {
+            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+        }
+
+        int value = 0;
+        window->query(window, NATIVE_WINDOW_IS_VALID, &value);
+        if (!value) {
+            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+        }
+
         int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
-        if (result != OK) {
+        if (result < 0) {
             ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "
                     "failed (%#x) (already connected to another API?)",
                     window, result);
@@ -992,8 +994,11 @@
          *
          */
 
-        const String8 name(procname);
-        addr = sGLExtentionMap.valueFor(name);
+        const std::string name(procname);
+
+    auto& extentionMap = sGLExtentionMap;
+    auto pos = extentionMap.find(name);
+        addr = (pos != extentionMap.end()) ? pos->second : nullptr;
         const int slot = sGLExtentionSlot;
 
         ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
@@ -1015,7 +1020,7 @@
 
             if (found) {
                 addr = gExtensionForwarders[slot];
-                sGLExtentionMap.add(name, addr);
+                extentionMap[name] = addr;
                 sGLExtentionSlot++;
             }
         }
@@ -1024,45 +1029,57 @@
     return addr;
 }
 
-class FrameCompletionThread : public Thread {
+class FrameCompletionThread {
 public:
 
     static void queueSync(EGLSyncKHR sync) {
-        static sp<FrameCompletionThread> thread(new FrameCompletionThread);
-        static bool running = false;
-        if (!running) {
-            thread->run("GPUFrameCompletion");
-            running = true;
-        }
-        {
-            Mutex::Autolock lock(thread->mMutex);
-            ScopedTrace st(ATRACE_TAG, String8::format("kicked off frame %d",
-                    thread->mFramesQueued).string());
-            thread->mQueue.push_back(sync);
-            thread->mCondition.signal();
-            thread->mFramesQueued++;
-            ATRACE_INT("GPU Frames Outstanding", int32_t(thread->mQueue.size()));
-        }
+        static FrameCompletionThread thread;
+
+        char name[64];
+
+        std::lock_guard<std::mutex> lock(thread.mMutex);
+        snprintf(name, sizeof(name), "kicked off frame %u", (unsigned int)thread.mFramesQueued);
+        ATRACE_NAME(name);
+
+        thread.mQueue.push_back(sync);
+        thread.mCondition.notify_one();
+        thread.mFramesQueued++;
+        ATRACE_INT("GPU Frames Outstanding", int32_t(thread.mQueue.size()));
     }
 
 private:
-    FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {}
 
-    virtual bool threadLoop() {
+    FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {
+        std::thread thread(&FrameCompletionThread::loop, this);
+        thread.detach();
+    }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-noreturn"
+    void loop() {
+        while (true) {
+            threadLoop();
+        }
+    }
+#pragma clang diagnostic pop
+
+    void threadLoop() {
         EGLSyncKHR sync;
         uint32_t frameNum;
         {
-            Mutex::Autolock lock(mMutex);
-            while (mQueue.isEmpty()) {
-                mCondition.wait(mMutex);
+            std::unique_lock<std::mutex> lock(mMutex);
+            while (mQueue.empty()) {
+                mCondition.wait(lock);
             }
             sync = mQueue[0];
             frameNum = mFramesCompleted;
         }
         EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
         {
-            ScopedTrace st(ATRACE_TAG, String8::format("waiting for frame %d",
-                    frameNum).string());
+            char name[64];
+            snprintf(name, sizeof(name), "waiting for frame %u", (unsigned int)frameNum);
+            ATRACE_NAME(name);
+
             EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR);
             if (result == EGL_FALSE) {
                 ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError());
@@ -1072,19 +1089,18 @@
             eglDestroySyncKHR(dpy, sync);
         }
         {
-            Mutex::Autolock lock(mMutex);
-            mQueue.removeAt(0);
+            std::lock_guard<std::mutex> lock(mMutex);
+            mQueue.pop_front();
             mFramesCompleted++;
             ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size()));
         }
-        return true;
     }
 
     uint32_t mFramesQueued;
     uint32_t mFramesCompleted;
-    Vector<EGLSyncKHR> mQueue;
-    Condition mCondition;
-    Mutex mMutex;
+    std::deque<EGLSyncKHR> mQueue;
+    std::condition_variable mCondition;
+    std::mutex mMutex;
 };
 
 EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw,
@@ -1123,7 +1139,7 @@
         return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
     }
 
-    Vector<android_native_rect_t> androidRects;
+    std::vector<android_native_rect_t> androidRects((size_t)n_rects);
     for (int r = 0; r < n_rects; ++r) {
         int offset = r * 4;
         int x = rects[offset];
@@ -1137,8 +1153,7 @@
         androidRect.bottom = y;
         androidRects.push_back(androidRect);
     }
-    native_window_set_surface_damage(s->win.get(), androidRects.array(),
-            androidRects.size());
+    native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(), androidRects.size());
 
     if (s->cnx->egl.eglSwapBuffersWithDamageKHR) {
         return s->cnx->egl.eglSwapBuffersWithDamageKHR(dp->disp.dpy, s->surface,
@@ -1242,19 +1257,19 @@
     egl_surface_t * const s = get_surface(surface);
 
     if (attribute == EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID) {
-        if (!s->win.get()) {
+        if (!s->getNativeWindow()) {
             setError(EGL_BAD_SURFACE, EGL_FALSE);
         }
-        int err = native_window_set_auto_refresh(s->win.get(), value ? true : false);
-        return (err == NO_ERROR) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+        int err = native_window_set_auto_refresh(s->getNativeWindow(), value != 0);
+        return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
     }
 
     if (attribute == EGL_TIMESTAMPS_ANDROID) {
-        if (!s->win.get()) {
+        if (!s->getNativeWindow()) {
             return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
         }
-        int err = native_window_enable_frame_timestamps(s->win.get(), value ? true : false);
-        return (err == NO_ERROR) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+        int err = native_window_enable_frame_timestamps(s->getNativeWindow(), value != 0);
+        return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
     }
 
     if (s->cnx->egl.eglSurfaceAttrib) {
@@ -1829,169 +1844,15 @@
     }
 
     egl_surface_t const * const s = get_surface(surface);
-    native_window_set_buffers_timestamp(s->win.get(), time);
+    native_window_set_buffers_timestamp(s->getNativeWindow(), time);
 
     return EGL_TRUE;
 }
 
-EGLClientBuffer eglCreateNativeClientBufferANDROID(const EGLint *attrib_list)
-{
-    clearError();
-
-    uint64_t producerUsage = 0;
-    uint64_t consumerUsage = 0;
-    uint32_t width = 0;
-    uint32_t height = 0;
-    uint32_t format = 0;
-    uint32_t layer_count = 1;
-    uint32_t red_size = 0;
-    uint32_t green_size = 0;
-    uint32_t blue_size = 0;
-    uint32_t alpha_size = 0;
-
-#define GET_NONNEGATIVE_VALUE(case_name, target) \
-    case case_name: \
-        if (value >= 0) { \
-            target = value; \
-        } else { \
-            return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0); \
-        } \
-        break
-
-    if (attrib_list) {
-        while (*attrib_list != EGL_NONE) {
-            GLint attr = *attrib_list++;
-            GLint value = *attrib_list++;
-            switch (attr) {
-                GET_NONNEGATIVE_VALUE(EGL_WIDTH, width);
-                GET_NONNEGATIVE_VALUE(EGL_HEIGHT, height);
-                GET_NONNEGATIVE_VALUE(EGL_RED_SIZE, red_size);
-                GET_NONNEGATIVE_VALUE(EGL_GREEN_SIZE, green_size);
-                GET_NONNEGATIVE_VALUE(EGL_BLUE_SIZE, blue_size);
-                GET_NONNEGATIVE_VALUE(EGL_ALPHA_SIZE, alpha_size);
-                GET_NONNEGATIVE_VALUE(EGL_LAYER_COUNT_ANDROID, layer_count);
-                case EGL_NATIVE_BUFFER_USAGE_ANDROID:
-                    if (value & EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID) {
-                        producerUsage |= GRALLOC1_PRODUCER_USAGE_PROTECTED;
-                    }
-                    if (value & EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID) {
-                        producerUsage |= GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET;
-                    }
-                    if (value & EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID) {
-                        consumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE;
-                    }
-                    break;
-                default:
-                    return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
-            }
-        }
-    }
-#undef GET_NONNEGATIVE_VALUE
-
-    // Validate format.
-    if (red_size == 8 && green_size == 8 && blue_size == 8) {
-        if (alpha_size == 8) {
-            format = HAL_PIXEL_FORMAT_RGBA_8888;
-        } else {
-            format = HAL_PIXEL_FORMAT_RGB_888;
-        }
-    } else if (red_size == 5 && green_size == 6 && blue_size == 5 &&
-               alpha_size == 0) {
-        format = HAL_PIXEL_FORMAT_RGB_565;
-    } else {
-        ALOGE("Invalid native pixel format { r=%u, g=%u, b=%u, a=%u }",
-                red_size, green_size, blue_size, alpha_size);
-        return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
-    }
-
-#define CHECK_ERROR_CONDITION(message) \
-    if (err != NO_ERROR) { \
-        ALOGE(message); \
-        goto error_condition; \
-    }
-
-    // The holder is used to destroy the buffer if an error occurs.
-    GraphicBuffer* gBuffer = new GraphicBuffer();
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> surfaceFlinger = sm->getService(String16("SurfaceFlinger"));
-    sp<IBinder> allocator;
-    Parcel sc_data, sc_reply, data, reply;
-    status_t err = NO_ERROR;
-    if (sm == NULL) {
-        ALOGE("Unable to connect to ServiceManager");
-        goto error_condition;
-    }
-
-    // Obtain an allocator.
-    if (surfaceFlinger == NULL) {
-        ALOGE("Unable to connect to SurfaceFlinger");
-        goto error_condition;
-    }
-    sc_data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
-    err = surfaceFlinger->transact(
-            BnSurfaceComposer::CREATE_GRAPHIC_BUFFER_ALLOC, sc_data, &sc_reply);
-    CHECK_ERROR_CONDITION("Unable to obtain allocator from SurfaceFlinger");
-    allocator = sc_reply.readStrongBinder();
-
-    if (allocator == NULL) {
-        ALOGE("Unable to obtain an ISurfaceComposer");
-        goto error_condition;
-    }
-    data.writeInterfaceToken(String16("android.ui.IGraphicBufferAlloc"));
-    err = data.writeUint32(width);
-    CHECK_ERROR_CONDITION("Unable to write width");
-    err = data.writeUint32(height);
-    CHECK_ERROR_CONDITION("Unable to write height");
-    err = data.writeInt32(static_cast<int32_t>(format));
-    CHECK_ERROR_CONDITION("Unable to write format");
-    err = data.writeUint32(layer_count);
-    CHECK_ERROR_CONDITION("Unable to write layer count");
-    err = data.writeUint64(producerUsage);
-    CHECK_ERROR_CONDITION("Unable to write producer usage");
-    err = data.writeUint64(consumerUsage);
-    CHECK_ERROR_CONDITION("Unable to write consumer usage");
-    err = data.writeUtf8AsUtf16(
-            std::string("[eglCreateNativeClientBufferANDROID pid ") +
-            std::to_string(getpid()) + ']');
-    CHECK_ERROR_CONDITION("Unable to write requestor name");
-    err = allocator->transact(IBinder::FIRST_CALL_TRANSACTION, data,
-            &reply);
-    CHECK_ERROR_CONDITION(
-            "Unable to request buffer allocation from surface composer");
-    err = reply.readInt32();
-    CHECK_ERROR_CONDITION("Unable to obtain buffer from surface composer");
-    err = reply.read(*gBuffer);
-    CHECK_ERROR_CONDITION("Unable to read buffer from surface composer");
-
-    err = gBuffer->initCheck();
-    if (err != NO_ERROR) {
-        ALOGE("Unable to create native buffer "
-                "{ w=%u, h=%u, f=%u, pu=%" PRIx64 " cu=%" PRIx64 ", lc=%u} %#x",
-                width, height, format, producerUsage, consumerUsage,
-                layer_count, err);
-        goto error_condition;
-    }
-    ALOGV("Created new native buffer %p { w=%u, h=%u, f=%u, pu=%" PRIx64
-          " cu=%" PRIx64 ", lc=%u}",
-            gBuffer, width, height, format, producerUsage, consumerUsage,
-            layer_count);
-    return static_cast<EGLClientBuffer>(gBuffer->getNativeBuffer());
-
-#undef CHECK_ERROR_CONDITION
-
-error_condition:
-    // Delete the buffer.
-    sp<GraphicBuffer> holder(gBuffer);
-    return setError(EGL_BAD_ALLOC, (EGLClientBuffer)0);
-}
-
 EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) {
     clearError();
-
     if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
-
-    const GraphicBuffer* graphicBuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
-    return static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
+    return const_cast<ANativeWindowBuffer *>(AHardwareBuffer_to_ANativeWindowBuffer(buffer));
 }
 
 // ----------------------------------------------------------------------------
@@ -2078,14 +1939,14 @@
 
     egl_surface_t const * const s = get_surface(surface);
 
-    if (!s->win.get()) {
+    if (!s->getNativeWindow()) {
         return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
     }
 
     uint64_t nextFrameId = 0;
-    status_t ret = native_window_get_next_frame_id(s->win.get(), &nextFrameId);
+    int ret = native_window_get_next_frame_id(s->getNativeWindow(), &nextFrameId);
 
-    if (ret != NO_ERROR) {
+    if (ret != 0) {
         // This should not happen. Return an error that is not in the spec
         // so it's obvious something is very wrong.
         ALOGE("eglGetNextFrameId: Unexpected error.");
@@ -2113,7 +1974,7 @@
 
     egl_surface_t const * const s = get_surface(surface);
 
-    if (!s->win.get()) {
+    if (!s->getNativeWindow()) {
         return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
     }
 
@@ -2137,13 +1998,13 @@
         }
     }
 
-    status_t ret = native_window_get_compositor_timing(s->win.get(),
+    int ret = native_window_get_compositor_timing(s->getNativeWindow(),
             compositeDeadline, compositeInterval, compositeToPresentLatency);
 
     switch (ret) {
-      case NO_ERROR:
+      case 0:
         return EGL_TRUE;
-      case INVALID_OPERATION:
+      case -ENOSYS:
         return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
       default:
         // This should not happen. Return an error that is not in the spec
@@ -2170,7 +2031,7 @@
 
     egl_surface_t const * const s = get_surface(surface);
 
-    ANativeWindow* window = s->win.get();
+    ANativeWindow* window = s->getNativeWindow();
     if (!window) {
         return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
     }
@@ -2203,7 +2064,7 @@
 
     egl_surface_t const * const s = get_surface(surface);
 
-    if (!s->win.get()) {
+    if (!s->getNativeWindow()) {
         return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
     }
 
@@ -2255,19 +2116,19 @@
         }
     }
 
-    status_t ret = native_window_get_frame_timestamps(s->win.get(), frameId,
+    int ret = native_window_get_frame_timestamps(s->getNativeWindow(), frameId,
             requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime,
             lastRefreshStartTime, gpuCompositionDoneTime, displayPresentTime,
             displayRetireTime, dequeueReadyTime, releaseTime);
 
     switch (ret) {
-        case NO_ERROR:
+        case 0:
             return EGL_TRUE;
-        case NAME_NOT_FOUND:
+        case -ENOENT:
             return setError(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE);
-        case INVALID_OPERATION:
+        case -ENOSYS:
             return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
-        case BAD_VALUE:
+        case -EINVAL:
             return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
         default:
             // This should not happen. Return an error that is not in the spec
@@ -2294,7 +2155,7 @@
 
     egl_surface_t const * const s = get_surface(surface);
 
-    ANativeWindow* window = s->win.get();
+    ANativeWindow* window = s->getNativeWindow();
     if (!window) {
         return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
     }
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index e46716c..dc1a4af 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -20,11 +20,16 @@
 
 #include "egl_display.h"
 
+
+#include <private/EGL/cache.h>
+
 #include <inttypes.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 
-#include <utils/Thread.h>
+#include <thread>
+
+#include <log/log.h>
 
 // Cache size limits.
 static const size_t maxKeySize = 12 * 1024;
@@ -44,6 +49,11 @@
 
 #define BC_EXT_STR "EGL_ANDROID_blob_cache"
 
+// called from android_view_ThreadedRenderer.cpp
+void egl_set_cache_filename(const char* filename) {
+    egl_cache_t::get()->setCacheFilename(filename);
+}
+
 //
 // Callback functions passed to EGL.
 //
@@ -61,8 +71,7 @@
 // egl_cache_t definition
 //
 egl_cache_t::egl_cache_t() :
-        mInitialized(false),
-        mBlobCache(NULL) {
+        mInitialized(false) {
 }
 
 egl_cache_t::~egl_cache_t() {
@@ -75,7 +84,7 @@
 }
 
 void egl_cache_t::initialize(egl_display_t *display) {
-    Mutex::Autolock lock(mMutex);
+    std::lock_guard<std::mutex> lock(mMutex);
 
     egl_connection_t* const cnx = &gEGLImpl;
     if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
@@ -113,14 +122,14 @@
 }
 
 void egl_cache_t::terminate() {
-    Mutex::Autolock lock(mMutex);
+    std::lock_guard<std::mutex> lock(mMutex);
     saveBlobCacheLocked();
     mBlobCache = NULL;
 }
 
 void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize,
         const void* value, EGLsizeiANDROID valueSize) {
-    Mutex::Autolock lock(mMutex);
+    std::lock_guard<std::mutex> lock(mMutex);
 
     if (keySize < 0 || valueSize < 0) {
         ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
@@ -128,38 +137,27 @@
     }
 
     if (mInitialized) {
-        sp<BlobCache> bc = getBlobCacheLocked();
+        BlobCache* bc = getBlobCacheLocked();
         bc->set(key, keySize, value, valueSize);
 
         if (!mSavePending) {
-            class DeferredSaveThread : public Thread {
-            public:
-                DeferredSaveThread() : Thread(false) {}
-
-                virtual bool threadLoop() {
-                    sleep(deferredSaveDelay);
-                    egl_cache_t* c = egl_cache_t::get();
-                    Mutex::Autolock lock(c->mMutex);
-                    if (c->mInitialized) {
-                        c->saveBlobCacheLocked();
-                    }
-                    c->mSavePending = false;
-                    return false;
-                }
-            };
-
-            // The thread will hold a strong ref to itself until it has finished
-            // running, so there's no need to keep a ref around.
-            sp<Thread> deferredSaveThread(new DeferredSaveThread());
             mSavePending = true;
-            deferredSaveThread->run("DeferredSaveThread");
+            std::thread deferredSaveThread([this]() {
+                sleep(deferredSaveDelay);
+                std::lock_guard<std::mutex> lock(mMutex);
+                if (mInitialized) {
+                    saveBlobCacheLocked();
+                }
+                mSavePending = false;
+            });
+            deferredSaveThread.detach();
         }
     }
 }
 
 EGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize,
         void* value, EGLsizeiANDROID valueSize) {
-    Mutex::Autolock lock(mMutex);
+    std::lock_guard<std::mutex> lock(mMutex);
 
     if (keySize < 0 || valueSize < 0) {
         ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
@@ -167,23 +165,23 @@
     }
 
     if (mInitialized) {
-        sp<BlobCache> bc = getBlobCacheLocked();
+        BlobCache* bc = getBlobCacheLocked();
         return bc->get(key, keySize, value, valueSize);
     }
     return 0;
 }
 
 void egl_cache_t::setCacheFilename(const char* filename) {
-    Mutex::Autolock lock(mMutex);
+    std::lock_guard<std::mutex> lock(mMutex);
     mFilename = filename;
 }
 
-sp<BlobCache> egl_cache_t::getBlobCacheLocked() {
-    if (mBlobCache == NULL) {
-        mBlobCache = new BlobCache(maxKeySize, maxValueSize, maxTotalSize);
+BlobCache* egl_cache_t::getBlobCacheLocked() {
+    if (mBlobCache == nullptr) {
+        mBlobCache.reset(new BlobCache(maxKeySize, maxValueSize, maxTotalSize));
         loadBlobCacheLocked();
     }
-    return mBlobCache;
+    return mBlobCache.get();
 }
 
 static uint32_t crc32c(const uint8_t* buf, size_t len) {
@@ -206,7 +204,7 @@
     if (mFilename.length() > 0 && mBlobCache != NULL) {
         size_t cacheSize = mBlobCache->getFlattenedSize();
         size_t headerSize = cacheFileHeaderSize;
-        const char* fname = mFilename.string();
+        const char* fname = mFilename.c_str();
 
         // Try to create the file with no permissions so we can write it
         // without anyone trying to read it.
@@ -241,8 +239,8 @@
             return;
         }
 
-        status_t err = mBlobCache->flatten(buf + headerSize, cacheSize);
-        if (err != OK) {
+        int err = mBlobCache->flatten(buf + headerSize, cacheSize);
+        if (err < 0) {
             ALOGE("error writing cache contents: %s (%d)", strerror(-err),
                     -err);
             delete [] buf;
@@ -275,10 +273,10 @@
     if (mFilename.length() > 0) {
         size_t headerSize = cacheFileHeaderSize;
 
-        int fd = open(mFilename.string(), O_RDONLY, 0);
+        int fd = open(mFilename.c_str(), O_RDONLY, 0);
         if (fd == -1) {
             if (errno != ENOENT) {
-                ALOGE("error opening cache file %s: %s (%d)", mFilename.string(),
+                ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(),
                         strerror(errno), errno);
             }
             return;
@@ -323,8 +321,8 @@
             return;
         }
 
-        status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize);
-        if (err != OK) {
+        int err = mBlobCache->unflatten(buf + headerSize, cacheSize);
+        if (err < 0) {
             ALOGE("error reading cache contents: %s (%d)", strerror(-err),
                     -err);
             munmap(buf, fileSize);
diff --git a/opengl/libs/EGL/egl_cache.h b/opengl/libs/EGL/egl_cache.h
index e7f1712..56360f0 100644
--- a/opengl/libs/EGL/egl_cache.h
+++ b/opengl/libs/EGL/egl_cache.h
@@ -20,10 +20,11 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 
-#include <utils/BlobCache.h>
-#include <utils/Mutex.h>
-#include <utils/String8.h>
-#include <utils/StrongPointer.h>
+#include "BlobCache.h"
+
+#include <memory>
+#include <mutex>
+#include <string>
 
 // ----------------------------------------------------------------------------
 namespace android {
@@ -79,7 +80,7 @@
     // key/value blob pairs.  If the BlobCache object has not yet been created,
     // this will do so, loading the serialized cache contents from disk if
     // possible.
-    sp<BlobCache> getBlobCacheLocked();
+    BlobCache* getBlobCacheLocked();
 
     // saveBlobCache attempts to save the current contents of mBlobCache to
     // disk.
@@ -100,14 +101,14 @@
     // mBlobCache is the cache in which the key/value blob pairs are stored.  It
     // is initially NULL, and will be initialized by getBlobCacheLocked the
     // first time it's needed.
-    sp<BlobCache> mBlobCache;
+    std::unique_ptr<BlobCache> mBlobCache;
 
     // mFilename is the name of the file for storing cache contents in between
     // program invocations.  It is initialized to an empty string at
     // construction time, and can be set with the setCacheFilename method.  An
     // empty string indicates that the cache should not be saved to or restored
     // from disk.
-    String8 mFilename;
+    std::string mFilename;
 
     // mSavePending indicates whether or not a deferred save operation is
     // pending.  Each time a key/value pair is inserted into the cache via
@@ -118,7 +119,7 @@
 
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables. It must be locked whenever the member variables are accessed.
-    mutable Mutex mMutex;
+    mutable std::mutex mMutex;
 
     // sCache is the singleton egl_cache_t object.
     static egl_cache_t sCache;
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index c804fa7..b696920 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -21,14 +21,15 @@
 
 #include "../egl_impl.h"
 
+#include <private/EGL/display.h>
+
 #include "egl_cache.h"
 #include "egl_object.h"
 #include "egl_tls.h"
+#include "egl_trace.h"
 #include "Loader.h"
 #include <cutils/properties.h>
 
-#include <utils/Trace.h>
-
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
@@ -55,6 +56,11 @@
     return false;
 }
 
+int egl_get_init_count(EGLDisplay dpy) {
+    egl_display_t* eglDisplay = egl_display_t::get(dpy);
+    return eglDisplay ? eglDisplay->getRefsCount() : 0;
+}
+
 egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
 
 egl_display_t::egl_display_t() :
@@ -75,18 +81,18 @@
 }
 
 void egl_display_t::addObject(egl_object_t* object) {
-    Mutex::Autolock _l(lock);
-    objects.add(object);
+    std::lock_guard<std::mutex> _l(lock);
+    objects.insert(object);
 }
 
 void egl_display_t::removeObject(egl_object_t* object) {
-    Mutex::Autolock _l(lock);
-    objects.remove(object);
+    std::lock_guard<std::mutex> _l(lock);
+    objects.erase(object);
 }
 
 bool egl_display_t::getObject(egl_object_t* object) const {
-    Mutex::Autolock _l(lock);
-    if (objects.indexOf(object) >= 0) {
+    std::lock_guard<std::mutex> _l(lock);
+    if (objects.find(object) != objects.end()) {
         if (object->getDisplay() == this) {
             object->incRef();
             return true;
@@ -104,7 +110,7 @@
 
 EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
 
-    Mutex::Autolock _l(lock);
+    std::lock_guard<std::mutex> _l(lock);
     ATRACE_CALL();
 
     // get our driver loader
@@ -125,24 +131,26 @@
 
 EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
 
-    {
-        Mutex::Autolock _rf(refLock);
-
+    { // scope for refLock
+        std::unique_lock<std::mutex> _l(refLock);
         refs++;
         if (refs > 1) {
             if (major != NULL)
                 *major = VERSION_MAJOR;
             if (minor != NULL)
                 *minor = VERSION_MINOR;
-            while(!eglIsInitialized) refCond.wait(refLock);
+            while(!eglIsInitialized) {
+                refCond.wait(_l);
+            }
             return EGL_TRUE;
         }
-
-        while(eglIsInitialized) refCond.wait(refLock);
+        while(eglIsInitialized) {
+            refCond.wait(_l);
+        }
     }
 
-    {
-        Mutex::Autolock _l(lock);
+    { // scope for lock
+        std::lock_guard<std::mutex> _l(lock);
 
         setGLHooksThreadSpecific(&gHooksNoContext);
 
@@ -179,20 +187,19 @@
         }
 
         // the query strings are per-display
-        mVendorString.setTo(sVendorString);
-        mVersionString.setTo(sVersionString);
-        mClientApiString.setTo(sClientApiString);
+        mVendorString = sVendorString;
+        mVersionString = sVersionString;
+        mClientApiString = sClientApiString;
 
-        mExtensionString.setTo(gBuiltinExtensionString);
+        mExtensionString = gBuiltinExtensionString;
         char const* start = gExtensionString;
         do {
             // length of the extension name
             size_t len = strcspn(start, " ");
             if (len) {
                 // NOTE: we could avoid the copy if we had strnstr.
-                const String8 ext(start, len);
-                if (findExtension(disp.queryString.extensions, ext.string(),
-                        len)) {
+                const std::string ext(start, len);
+                if (findExtension(disp.queryString.extensions, ext.c_str(), len)) {
                     mExtensionString.append(ext + " ");
                 }
                 // advance to the next extension name, skipping the space.
@@ -220,10 +227,10 @@
             *minor = VERSION_MINOR;
     }
 
-    {
-        Mutex::Autolock _rf(refLock);
+    { // scope for refLock
+        std::unique_lock<std::mutex> _l(refLock);
         eglIsInitialized = true;
-        refCond.broadcast();
+        refCond.notify_all();
     }
 
     return EGL_TRUE;
@@ -231,8 +238,8 @@
 
 EGLBoolean egl_display_t::terminate() {
 
-    {
-        Mutex::Autolock _rl(refLock);
+    { // scope for refLock
+        std::unique_lock<std::mutex> _rl(refLock);
         if (refs == 0) {
             /*
              * From the EGL spec (3.2):
@@ -252,8 +259,8 @@
 
     EGLBoolean res = EGL_FALSE;
 
-    {
-        Mutex::Autolock _l(lock);
+    { // scope for lock
+        std::lock_guard<std::mutex> _l(lock);
 
         egl_connection_t* const cnx = &gEGLImpl;
         if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
@@ -268,15 +275,14 @@
 
         // Reset the extension string since it will be regenerated if we get
         // reinitialized.
-        mExtensionString.setTo("");
+        mExtensionString.clear();
 
         // Mark all objects remaining in the list as terminated, unless
         // there are no reference to them, it which case, we're free to
         // delete them.
         size_t count = objects.size();
         ALOGW_IF(count, "eglTerminate() called w/ %zu objects remaining", count);
-        for (size_t i=0 ; i<count ; i++) {
-            egl_object_t* o = objects.itemAt(i);
+        for (auto o : objects) {
             o->destroy();
         }
 
@@ -284,10 +290,10 @@
         objects.clear();
     }
 
-    {
-        Mutex::Autolock _rl(refLock);
+    { // scope for refLock
+        std::unique_lock<std::mutex> _rl(refLock);
         eglIsInitialized = false;
-        refCond.broadcast();
+        refCond.notify_all();
     }
 
     return res;
@@ -312,7 +318,7 @@
     SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
 
     { // scope for the lock
-        Mutex::Autolock _l(lock);
+        std::lock_guard<std::mutex> _l(lock);
         cur_c->onLooseCurrent();
 
     }
@@ -338,7 +344,7 @@
     SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
 
     { // scope for the lock
-        Mutex::Autolock _l(lock);
+        std::lock_guard<std::mutex> _l(lock);
         if (c) {
             result = c->cnx->egl.eglMakeCurrent(
                     disp.dpy, impl_draw, impl_read, impl_ctx);
@@ -370,7 +376,7 @@
     if (!nameLen) {
         nameLen = strlen(name);
     }
-    return findExtension(mExtensionString.string(), name, nameLen);
+    return findExtension(mExtensionString.c_str(), name, nameLen);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index f5e7294..661f47e 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -21,14 +21,15 @@
 #include <stdint.h>
 #include <stddef.h>
 
+#include <condition_variable>
+#include <mutex>
+#include <string>
+#include <unordered_set>
+
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 
 #include <cutils/compiler.h>
-#include <utils/SortedVector.h>
-#include <utils/Condition.h>
-#include <utils/Mutex.h>
-#include <utils/String8.h>
 
 #include "egldefs.h"
 #include "../hooks.h"
@@ -80,10 +81,10 @@
     inline bool isValid() const { return magic == '_dpy'; }
     inline bool isAlive() const { return isValid(); }
 
-    char const * getVendorString() const { return mVendorString.string(); }
-    char const * getVersionString() const { return mVersionString.string(); }
-    char const * getClientApiString() const { return mClientApiString.string(); }
-    char const * getExtensionString() const { return mExtensionString.string(); }
+    char const * getVendorString() const { return mVendorString.c_str(); }
+    char const * getVersionString() const { return mVersionString.c_str(); }
+    char const * getClientApiString() const { return mClientApiString.c_str(); }
+    char const * getExtensionString() const { return mExtensionString.c_str(); }
 
     bool haveExtension(const char* name, size_t nameLen = 0) const;
 
@@ -116,13 +117,14 @@
 
             uint32_t                    refs;
             bool                        eglIsInitialized;
-    mutable Mutex                       lock, refLock;
-    mutable Condition                   refCond;
-            SortedVector<egl_object_t*> objects;
-            String8 mVendorString;
-            String8 mVersionString;
-            String8 mClientApiString;
-            String8 mExtensionString;
+    mutable std::mutex                  lock;
+    mutable std::mutex                  refLock;
+    mutable std::condition_variable     refCond;
+            std::unordered_set<egl_object_t*> objects;
+            std::string mVendorString;
+            std::string mVersionString;
+            std::string mClientApiString;
+            std::string mExtensionString;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index b553d71..7ed34be 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -60,21 +60,24 @@
         egl_connection_t const* cnx) :
     egl_object_t(dpy), surface(surface), config(config), win(win), cnx(cnx),
     connected(true)
-{}
+{
+    if (win) {
+        win->incStrong(this);
+    }
+}
 
 egl_surface_t::~egl_surface_t() {
-    ANativeWindow* const window = win.get();
-    if (window != NULL) {
+    if (win != NULL) {
         disconnect();
+        win->decStrong(this);
     }
 }
 
 void egl_surface_t::disconnect() {
-    ANativeWindow* const window = win.get();
-    if (window != NULL && connected) {
-        native_window_set_buffers_format(window, 0);
-        if (native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL)) {
-            ALOGW("EGLNativeWindowType %p disconnect failed", window);
+    if (win != NULL && connected) {
+        native_window_set_buffers_format(win, 0);
+        if (native_window_api_disconnect(win, NATIVE_WINDOW_API_EGL)) {
+            ALOGW("EGLNativeWindowType %p disconnect failed", win);
         }
         connected = false;
     }
@@ -107,22 +110,20 @@
      * add the extensions always handled by the wrapper
      */
 
-    if (gl_extensions.isEmpty()) {
+    if (gl_extensions.empty()) {
         // call the implementation's glGetString(GL_EXTENSIONS)
         const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS);
-        gl_extensions.setTo(exts);
-        if (gl_extensions.find("GL_EXT_debug_marker") < 0) {
-            String8 temp("GL_EXT_debug_marker ");
-            temp.append(gl_extensions);
-            gl_extensions.setTo(temp);
+        gl_extensions = exts;
+        if (gl_extensions.find("GL_EXT_debug_marker") != std::string::npos) {
+            gl_extensions.insert(0, "GL_EXT_debug_marker ");
         }
 
         // tokenize the supported extensions for the glGetStringi() wrapper
         std::stringstream ss;
         std::string str;
-        ss << gl_extensions.string();
+        ss << gl_extensions;
         while (ss >> str) {
-            tokenized_gl_extensions.push(String8(str.c_str()));
+            tokenized_gl_extensions.push_back(str);
         }
     }
 }
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index f4012ab..8988905 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -17,18 +17,20 @@
 #ifndef ANDROID_EGL_OBJECT_H
 #define ANDROID_EGL_OBJECT_H
 
+#include <atomic>
 #include <stdint.h>
 #include <stddef.h>
 
+#include <string>
+#include <vector>
+
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 
-#include <utils/StrongPointer.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
-
 #include <system/window.h>
 
+#include <log/log.h>
+
 #include "egl_display.h"
 
 // ----------------------------------------------------------------------------
@@ -133,9 +135,16 @@
             EGLNativeWindowType win, EGLSurface surface,
             egl_connection_t const* cnx);
 
+    ANativeWindow* getNativeWindow() { return win; }
+    ANativeWindow* getNativeWindow() const { return win; }
+
+    // Try to keep the order of these fields and size unchanged. It's not public API, but
+    // it's not hard to imagine native games accessing them.
     EGLSurface surface;
     EGLConfig config;
-    sp<ANativeWindow> win;
+private:
+    ANativeWindow* win;
+public:
     egl_connection_t const* cnx;
 private:
     bool connected;
@@ -161,8 +170,8 @@
     EGLSurface draw;
     egl_connection_t const* cnx;
     int version;
-    String8 gl_extensions;
-    Vector<String8> tokenized_gl_extensions;
+    std::string gl_extensions;
+    std::vector<std::string> tokenized_gl_extensions;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_trace.h b/opengl/libs/EGL/egl_trace.h
new file mode 100644
index 0000000..7664de2
--- /dev/null
+++ b/opengl/libs/EGL/egl_trace.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+#if defined(__ANDROID__)
+
+#include <stdint.h>
+
+#include <cutils/trace.h>
+
+// See <cutils/trace.h> for more ATRACE_* macros.
+
+// ATRACE_NAME traces from its location until the end of its enclosing scope.
+#define _PASTE(x, y) x ## y
+#define PASTE(x, y) _PASTE(x,y)
+#define ATRACE_NAME(name) android::EglScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG, name)
+
+// ATRACE_CALL is an ATRACE_NAME that uses the current function name.
+#define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)
+
+namespace android {
+
+class EglScopedTrace {
+public:
+    inline EglScopedTrace(uint64_t tag, const char* name) : mTag(tag) {
+        atrace_begin(mTag, name);
+    }
+
+    inline ~EglScopedTrace() {
+        atrace_end(mTag);
+    }
+
+private:
+    uint64_t mTag;
+};
+
+}; // namespace android
+
+#else // !__ANDROID__
+
+#define ATRACE_NAME(...)
+#define ATRACE_CALL()
+
+#endif // __ANDROID__
diff --git a/services/surfaceflinger/DisplayHardware/MiniFence.cpp b/opengl/libs/EGL/include/private/EGL/cache.h
similarity index 62%
copy from services/surfaceflinger/DisplayHardware/MiniFence.cpp
copy to opengl/libs/EGL/include/private/EGL/cache.h
index ecfb063..0a176a8 100644
--- a/services/surfaceflinger/DisplayHardware/MiniFence.cpp
+++ b/opengl/libs/EGL/include/private/EGL/cache.h
@@ -14,29 +14,12 @@
  * limitations under the License.
  */
 
-#include "MiniFence.h"
+#pragma once
 
-#include <unistd.h>
+#include <cutils/compiler.h>
 
 namespace android {
 
-const sp<MiniFence> MiniFence::NO_FENCE = sp<MiniFence>(new MiniFence);
+ANDROID_API void egl_set_cache_filename(const char* filename);
 
-MiniFence::MiniFence() :
-    mFenceFd(-1) {
-}
-
-MiniFence::MiniFence(int fenceFd) :
-    mFenceFd(fenceFd) {
-}
-
-MiniFence::~MiniFence() {
-    if (mFenceFd != -1) {
-        close(mFenceFd);
-    }
-}
-
-int MiniFence::dup() const {
-    return ::dup(mFenceFd);
-}
-}
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/MiniFence.cpp b/opengl/libs/EGL/include/private/EGL/display.h
similarity index 62%
copy from services/surfaceflinger/DisplayHardware/MiniFence.cpp
copy to opengl/libs/EGL/include/private/EGL/display.h
index ecfb063..9560de2 100644
--- a/services/surfaceflinger/DisplayHardware/MiniFence.cpp
+++ b/opengl/libs/EGL/include/private/EGL/display.h
@@ -14,29 +14,14 @@
  * limitations under the License.
  */
 
-#include "MiniFence.h"
+#pragma once
 
-#include <unistd.h>
+#include <EGL/egl.h>
+
+#include <cutils/compiler.h>
 
 namespace android {
 
-const sp<MiniFence> MiniFence::NO_FENCE = sp<MiniFence>(new MiniFence);
+ANDROID_API int egl_get_init_count(EGLDisplay dpy);
 
-MiniFence::MiniFence() :
-    mFenceFd(-1) {
-}
-
-MiniFence::MiniFence(int fenceFd) :
-    mFenceFd(fenceFd) {
-}
-
-MiniFence::~MiniFence() {
-    if (mFenceFd != -1) {
-        close(mFenceFd);
-    }
-}
-
-int MiniFence::dup() const {
-    return ::dup(mFenceFd);
-}
-}
+} // namespace android
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index a317ea2..1c1db74 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -25,8 +25,7 @@
     DisplayHardware/ComposerHal.cpp \
     DisplayHardware/FramebufferSurface.cpp \
     DisplayHardware/HWC2.cpp \
-    DisplayHardware/HWC2On1Adapter.cpp \
-    DisplayHardware/MiniFence.cpp \
+    DisplayHardware/HWComposerBufferCache.cpp \
     DisplayHardware/PowerHAL.cpp \
     DisplayHardware/VirtualDisplaySurface.cpp \
     Effects/Daltonizer.cpp \
@@ -85,39 +84,6 @@
     LOCAL_CFLAGS += -DRUNNING_WITHOUT_SYNC_FRAMEWORK
 endif
 
-# The following two BoardConfig variables define (respectively):
-#
-#   - The phase offset between hardware vsync and when apps are woken up by the
-#     Choreographer callback
-#   - The phase offset between hardware vsync and when SurfaceFlinger wakes up
-#     to consume input
-#
-# Their values can be tuned to trade off between display pipeline latency (both
-# overall latency and the lengths of the app --> SF and SF --> display phases)
-# and frame delivery jitter (which typically manifests as "jank" or "jerkiness"
-# while interacting with the device). The default values should produce a
-# relatively low amount of jitter at the expense of roughly two frames of
-# app --> display latency, and unless significant testing is performed to avoid
-# increased display jitter (both manual investigation using systrace [1] and
-# automated testing using dumpsys gfxinfo [2] are recommended), they should not
-# be modified.
-#
-# [1] https://developer.android.com/studio/profile/systrace.html
-# [2] https://developer.android.com/training/testing/performance.html
-
-# These are left just for non-treble devices
-ifneq ($(VSYNC_EVENT_PHASE_OFFSET_NS),)
-    LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=$(VSYNC_EVENT_PHASE_OFFSET_NS)
-else
-    LOCAL_CFLAGS += -DVSYNC_EVENT_PHASE_OFFSET_NS=1000000
-endif
-
-ifneq ($(SF_VSYNC_EVENT_PHASE_OFFSET_NS),)
-    LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=$(SF_VSYNC_EVENT_PHASE_OFFSET_NS)
-else
-    LOCAL_CFLAGS += -DSF_VSYNC_EVENT_PHASE_OFFSET_NS=1000000
-endif
-
 ifneq ($(PRESENT_TIME_OFFSET_FROM_VSYNC_NS),)
     LOCAL_CFLAGS += -DPRESENT_TIME_OFFSET_FROM_VSYNC_NS=$(PRESENT_TIME_OFFSET_FROM_VSYNC_NS)
 else
@@ -152,6 +118,7 @@
     libdl \
     libfmq \
     libhardware \
+    libhwc2on1adapter \
     libhidlbase \
     libhidltransport \
     libhwbinder \
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index ae6e0cc..92a7794 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -32,7 +32,6 @@
 #include <hardware/hardware.h>
 #include <gui/BufferItem.h>
 #include <gui/BufferQueue.h>
-#include <gui/GraphicBufferAlloc.h>
 #include <gui/Surface.h>
 
 #include <ui/GraphicBuffer.h>
@@ -138,7 +137,7 @@
     status_t err = acquireBufferLocked(&item, 0);
     if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
 #ifdef USE_HWC2
-        mHwcBufferCache->getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
+        mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
                 &outSlot, &outBuffer);
 #else
         outBuffer = mCurrentBuffer;
@@ -179,7 +178,7 @@
 
     outFence = item.mFence;
 #ifdef USE_HWC2
-    mHwcBufferCache->getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
+    mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
             &outSlot, &outBuffer);
     outDataspace = item.mDataSpace;
 #else
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 5eea6b6..69a72d7 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -18,14 +18,13 @@
 #define ANDROID_SF_FRAMEBUFFER_SURFACE_H
 
 #include "DisplaySurface.h"
+#include "HWComposerBufferCache.h"
 
 #include <stdint.h>
 #include <sys/types.h>
 
 #include <gui/ConsumerBase.h>
 
-#include <memory>
-
 // ---------------------------------------------------------------------------
 namespace android {
 // ---------------------------------------------------------------------------
@@ -33,7 +32,6 @@
 class Rect;
 class String8;
 class HWComposer;
-class HWComposerBufferCache;
 
 // ---------------------------------------------------------------------------
 
@@ -96,8 +94,7 @@
     HWComposer& mHwc;
 
 #ifdef USE_HWC2
-    std::unique_ptr<HWComposerBufferCache> mHwcBufferCache =
-        std::make_unique<HWComposerBufferCache>();
+    HWComposerBufferCache mHwcBufferCache;
 
     // Previous buffer to release after getting an updated retire fence
     bool mHasPendingRelease;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index f03491f..6644bd9 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -47,7 +47,7 @@
 #include <log/log.h>
 
 #include "HWComposer.h"
-#include "HWC2On1Adapter.h"
+#include "hwc2on1adapter/HWC2On1Adapter.h"
 #include "HWC2.h"
 #include "ComposerHal.h"
 
@@ -267,6 +267,15 @@
         return NO_MEMORY;
     }
 
+    if (MAX_VIRTUAL_DISPLAY_DIMENSION != 0 &&
+        (width > MAX_VIRTUAL_DISPLAY_DIMENSION ||
+         height > MAX_VIRTUAL_DISPLAY_DIMENSION)) {
+        ALOGE("createVirtualDisplay: Can't create a virtual display with"
+                      " a dimension > %u (tried %u x %u)",
+              MAX_VIRTUAL_DISPLAY_DIMENSION, width, height);
+        return INVALID_OPERATION;
+    }
+
     std::shared_ptr<HWC2::Display> display;
     auto error = mHwcDevice->createVirtualDisplay(width, height, format,
             &display);
@@ -916,41 +925,5 @@
     *this = DisplayData();
 }
 
-void HWComposerBufferCache::clear()
-{
-    mBuffers.clear();
-}
-
-void HWComposerBufferCache::getHwcBuffer(int slot,
-        const sp<GraphicBuffer>& buffer,
-        uint32_t* outSlot, sp<GraphicBuffer>* outBuffer)
-{
-#ifdef BYPASS_IHWC
-    *outSlot = slot;
-    *outBuffer = buffer;
-#else
-    if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0) {
-        // default to slot 0
-        slot = 0;
-    }
-
-    if (static_cast<size_t>(slot) >= mBuffers.size()) {
-        mBuffers.resize(slot + 1);
-    }
-
-    *outSlot = slot;
-
-    if (mBuffers[slot] == buffer) {
-        // already cached in HWC, skip sending the buffer
-        *outBuffer = nullptr;
-    } else {
-        *outBuffer = buffer;
-
-        // update cache
-        mBuffers[slot] = buffer;
-    }
-#endif
-}
-
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 20cca39..117db4a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -26,8 +26,6 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <gui/BufferQueue.h>
-
 #include <ui/Fence.h>
 
 #include <utils/BitSet.h>
@@ -236,19 +234,6 @@
     mutable std::atomic<bool> mDumpMayLockUp;
 };
 
-class HWComposerBufferCache {
-public:
-    void clear();
-
-    void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer,
-            uint32_t* outSlot, sp<GraphicBuffer>* outBuffer);
-
-private:
-    // a vector as we expect "slot" to be in the range of [0, 63] (that is,
-    // less than BufferQueue::NUM_BUFFER_SLOTS).
-    std::vector<sp<GraphicBuffer>> mBuffers;
-};
-
 // ---------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp b/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp
new file mode 100644
index 0000000..6b91224
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "HWComposerBufferCache.h"
+
+#include <gui/BufferQueue.h>
+
+namespace android {
+
+HWComposerBufferCache::HWComposerBufferCache()
+{
+    mBuffers.reserve(BufferQueue::NUM_BUFFER_SLOTS);
+}
+
+void HWComposerBufferCache::getHwcBuffer(int slot,
+        const sp<GraphicBuffer>& buffer,
+        uint32_t* outSlot, sp<GraphicBuffer>* outBuffer)
+{
+#ifdef BYPASS_IHWC
+    *outSlot = slot;
+    *outBuffer = buffer;
+#else
+    if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0) {
+        // default to slot 0
+        slot = 0;
+    }
+
+    if (static_cast<size_t>(slot) >= mBuffers.size()) {
+        mBuffers.resize(slot + 1);
+    }
+
+    *outSlot = slot;
+
+    if (mBuffers[slot] == buffer) {
+        // already cached in HWC, skip sending the buffer
+        *outBuffer = nullptr;
+    } else {
+        *outBuffer = buffer;
+
+        // update cache
+        mBuffers[slot] = buffer;
+    }
+#endif
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.h b/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.h
new file mode 100644
index 0000000..a008ca9
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_SF_HWCOMPOSERBUFFERCACHE_H
+#define ANDROID_SF_HWCOMPOSERBUFFERCACHE_H
+
+#include <stdint.h>
+
+#include <utils/StrongPointer.h>
+
+#include <vector>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class GraphicBuffer;
+
+// With HIDLized hwcomposer HAL, the HAL can maintain a buffer cache for each
+// HWC display and layer.  When updating a display target or a layer buffer,
+// we have the option to send the buffer handle over or to request the HAL to
+// retrieve it from its cache.  The latter is cheaper since it eliminates the
+// overhead to transfer the handle over the trasport layer, and the overhead
+// for the HAL to clone and retain the handle.
+//
+// To be able to find out whether a buffer is already in the HAL's cache, we
+// use HWComposerBufferCache to mirror the cache in SF.
+class HWComposerBufferCache {
+public:
+    HWComposerBufferCache();
+
+    // Given a buffer queue slot and buffer, return the HWC cache slot and
+    // buffer to be sent to HWC.
+    //
+    // outBuffer is set to buffer when buffer is not in the HWC cache;
+    // otherwise, outBuffer is set to nullptr.
+    void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer,
+            uint32_t* outSlot, sp<GraphicBuffer>* outBuffer);
+
+private:
+    // a vector as we expect "slot" to be in the range of [0, 63] (that is,
+    // less than BufferQueue::NUM_BUFFER_SLOTS).
+    std::vector<sp<GraphicBuffer>> mBuffers;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SF_HWCOMPOSERBUFFERCACHE_H
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index c5a4f99..6f253ab 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -224,7 +224,7 @@
 #ifdef USE_HWC2
         uint32_t hwcSlot = 0;
         sp<GraphicBuffer> hwcBuffer;
-        mHwcBufferCache->getHwcBuffer(mFbProducerSlot, fbBuffer,
+        mHwcBufferCache.getHwcBuffer(mFbProducerSlot, fbBuffer,
                 &hwcSlot, &hwcBuffer);
 
         // TODO: Correctly propagate the dataspace from GL composition
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index fb5fcc8..ee2772a 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -18,18 +18,16 @@
 #define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
 
 #include "DisplaySurface.h"
+#include "HWComposerBufferCache.h"
 
 #include <gui/ConsumerBase.h>
 #include <gui/IGraphicBufferProducer.h>
 
-#include <memory>
-
 // ---------------------------------------------------------------------------
 namespace android {
 // ---------------------------------------------------------------------------
 
 class HWComposer;
-class HWComposerBufferCache;
 class IProducerListener;
 
 /* This DisplaySurface implementation supports virtual displays, where GLES
@@ -255,8 +253,7 @@
     bool mMustRecompose;
 
 #ifdef USE_HWC2
-    std::unique_ptr<HWComposerBufferCache> mHwcBufferCache =
-        std::make_unique<HWComposerBufferCache>();
+    HWComposerBufferCache mHwcBufferCache;
 #endif
 };
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c3f8665..51984b7 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -167,7 +167,7 @@
     // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
-    BufferQueue::createBufferQueue(&producer, &consumer, nullptr, true);
+    BufferQueue::createBufferQueue(&producer, &consumer, true);
     mProducer = new MonitoredProducer(producer, mFlinger, this);
     mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName, this);
     mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
@@ -276,16 +276,6 @@
     }
 }
 
-void Layer::onBuffersReleased() {
-#ifdef USE_HWC2
-    Mutex::Autolock lock(mHwcBufferCacheMutex);
-
-    for (auto info : mHwcBufferCaches) {
-        info.second.clear();
-    }
-#endif
-}
-
 void Layer::onSidebandStreamChanged() {
     if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
         // mSidebandStreamChanged was false
@@ -780,7 +770,8 @@
     const auto& viewport = displayDevice->getViewport();
     Region visible = tr.transform(visibleRegion.intersect(viewport));
     auto hwcId = displayDevice->getHwcDisplayId();
-    auto& hwcLayer = mHwcLayers[hwcId].layer;
+    auto& hwcInfo = mHwcLayers[hwcId];
+    auto& hwcLayer = hwcInfo.layer;
     auto error = hwcLayer->setVisibleRegion(visible);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
@@ -809,7 +800,7 @@
     }
 
     // Client layers
-    if (mHwcLayers[hwcId].forceClientComposition ||
+    if (hwcInfo.forceClientComposition ||
             (mActiveBuffer != nullptr && mActiveBuffer->handle == nullptr)) {
         ALOGV("[%s] Requesting Client composition", mName.string());
         setCompositionType(hwcId, HWC2::Composition::Client);
@@ -858,11 +849,8 @@
     uint32_t hwcSlot = 0;
     buffer_handle_t hwcHandle = nullptr;
     {
-        Mutex::Autolock lock(mHwcBufferCacheMutex);
-
-        auto& hwcBufferCache = mHwcBufferCaches[hwcId];
         sp<GraphicBuffer> hwcBuffer;
-        hwcBufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer,
+        hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer,
                 &hwcSlot, &hwcBuffer);
         if (hwcBuffer != nullptr) {
             hwcHandle = hwcBuffer->handle;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 0efdf54..6b228b0 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -47,6 +47,7 @@
 #include "Transform.h"
 
 #include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/HWComposerBufferCache.h"
 #include "RenderEngine/Mesh.h"
 #include "RenderEngine/Texture.h"
 
@@ -383,20 +384,13 @@
 #ifdef USE_HWC2
     // -----------------------------------------------------------------------
 
-    void eraseHwcLayer(int32_t hwcId) {
-        mHwcLayers.erase(hwcId);
-
-        Mutex::Autolock lock(mHwcBufferCacheMutex);
-        mHwcBufferCaches.erase(hwcId);
-    }
-
     bool hasHwcLayer(int32_t hwcId) {
         if (mHwcLayers.count(hwcId) == 0) {
             return false;
         }
         if (mHwcLayers[hwcId].layer->isAbandoned()) {
             ALOGI("Erasing abandoned layer %s on %d", mName.string(), hwcId);
-            eraseHwcLayer(hwcId);
+            mHwcLayers.erase(hwcId);
             return false;
         }
         return true;
@@ -412,11 +406,8 @@
     void setHwcLayer(int32_t hwcId, std::shared_ptr<HWC2::Layer>&& layer) {
         if (layer) {
             mHwcLayers[hwcId].layer = layer;
-
-            Mutex::Autolock lock(mHwcBufferCacheMutex);
-            mHwcBufferCaches[hwcId] = HWComposerBufferCache();
         } else {
-            eraseHwcLayer(hwcId);
+            mHwcLayers.erase(hwcId);
         }
     }
 
@@ -511,7 +502,6 @@
     // Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
     virtual void onFrameAvailable(const BufferItem& item) override;
     virtual void onFrameReplaced(const BufferItem& item) override;
-    virtual void onBuffersReleased() override;
     virtual void onSidebandStreamChanged() override;
 
     void commitTransaction(const State& stateToCommit);
@@ -703,6 +693,7 @@
         bool clearClientTarget;
         Rect displayFrame;
         FloatRect sourceCrop;
+        HWComposerBufferCache bufferCache;
     };
 
     // A layer can be attached to multiple displays when operating in mirror mode
@@ -710,12 +701,6 @@
     // case we need to keep track. In non-mirror mode, a layer will have only one
     // HWCInfo. This map key is a display layerStack.
     std::unordered_map<int32_t, HWCInfo> mHwcLayers;
-
-    // We need one HWComposerBufferCache for each HWC display.  We cannot have
-    // HWComposerBufferCache in HWCInfo because HWCInfo can only be accessed
-    // from the main thread.
-    Mutex mHwcBufferCacheMutex;
-    std::unordered_map<int32_t, HWComposerBufferCache> mHwcBufferCaches;
 #else
     bool mIsGlesComposition;
 #endif
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 46f5a1f..ca6d941 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -44,7 +44,6 @@
 #include <gui/GuiConfig.h>
 #include <gui/IDisplayEventConnection.h>
 #include <gui/Surface.h>
-#include <gui/GraphicBufferAlloc.h>
 
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/PixelFormat.h>
@@ -102,33 +101,6 @@
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
 
-// This is the phase offset in nanoseconds of the software vsync event
-// relative to the vsync event reported by HWComposer.  The software vsync
-// event is when SurfaceFlinger and Choreographer-based applications run each
-// frame.
-//
-// This phase offset allows adjustment of the minimum latency from application
-// wake-up (by Choregographer) time to the time at which the resulting window
-// image is displayed.  This value may be either positive (after the HW vsync)
-// or negative (before the HW vsync).  Setting it to 0 will result in a
-// minimum latency of two vsync periods because the app and SurfaceFlinger
-// will run just after the HW vsync.  Setting it to a positive number will
-// result in the minimum latency being:
-//
-//     (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD))
-//
-// Note that reducing this latency makes it more likely for the applications
-// to not have their window content image ready in time.  When this happens
-// the latency will end up being an additional vsync period, and animations
-// will hiccup.  Therefore, this latency should be tuned somewhat
-// conservatively (or at least with awareness of the trade-off being made).
-static int64_t vsyncPhaseOffsetNs = getInt64<
-        ISurfaceFlingerConfigs,
-        &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);
-
-// This is the phase offset at which SurfaceFlinger's composition runs.
-static constexpr int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS;
-
 // ---------------------------------------------------------------------------
 
 const String16 sHardwareTest("android.permission.HARDWARE_TEST");
@@ -137,6 +109,8 @@
 const String16 sDump("android.permission.DUMP");
 
 // ---------------------------------------------------------------------------
+int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
+int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
 
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
@@ -180,6 +154,13 @@
         ,mEnterVrMode(false)
 #endif
 {
+
+    vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);
+
+    sfVsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs>(1000000);
+
     ALOGI("SurfaceFlinger is starting");
 
     // debugging stuff...
@@ -340,12 +321,6 @@
     return mBuiltinDisplays[id];
 }
 
-sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
-{
-    sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
-    return gba;
-}
-
 void SurfaceFlinger::bootFinished()
 {
     if (mStartBootAnimThread->join() != NO_ERROR) {
@@ -750,7 +725,7 @@
         // We add an additional 1ms to allow for processing time and
         // differences between the ideal and actual refresh rate.
         info.presentationDeadline = hwConfig->getVsyncPeriod() -
-                SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000;
+                sfVsyncPhaseOffsetNs + 1000000;
 
         // All non-virtual displays are currently considered secure.
         info.secure = true;
@@ -1151,8 +1126,7 @@
 
         sp<IGraphicBufferProducer> producer;
         sp<IGraphicBufferConsumer> consumer;
-        BufferQueue::createBufferQueue(&producer, &consumer,
-                new GraphicBufferAlloc());
+        BufferQueue::createBufferQueue(&producer, &consumer);
 
         sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc,
                 DisplayDevice::DISPLAY_PRIMARY, consumer);
@@ -1913,8 +1887,7 @@
                     sp<IGraphicBufferProducer> producer;
                     sp<IGraphicBufferProducer> bqProducer;
                     sp<IGraphicBufferConsumer> bqConsumer;
-                    BufferQueue::createBufferQueue(&bqProducer, &bqConsumer,
-                            new GraphicBufferAlloc());
+                    BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
 
                     int32_t hwcId = -1;
                     if (state.isVirtualDisplay()) {
@@ -2546,6 +2519,8 @@
 }
 
 status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
+    Mutex::Autolock _l(mStateLock);
+
     const auto& p = layer->getParent();
     const ssize_t index = (p != nullptr) ? p->removeChild(layer) :
         mCurrentState.layersSortedByZ.remove(layer);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index d63c0bb..e5aa0bb 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -76,7 +76,6 @@
 class Client;
 class DisplayEventConnection;
 class EventThread;
-class IGraphicBufferAlloc;
 class Layer;
 class LayerDim;
 class Surface;
@@ -104,6 +103,31 @@
                        private HWComposer::EventHandler
 {
 public:
+
+
+    // This is the phase offset in nanoseconds of the software vsync event
+    // relative to the vsync event reported by HWComposer.  The software vsync
+    // event is when SurfaceFlinger and Choreographer-based applications run each
+    // frame.
+    //
+    // This phase offset allows adjustment of the minimum latency from application
+    // wake-up time (by Choreographer) to the time at which the resulting window
+    // image is displayed.  This value may be either positive (after the HW vsync)
+    // or negative (before the HW vsync). Setting it to 0 will result in a lower
+    // latency bound of two vsync periods because the app and SurfaceFlinger
+    // will run just after the HW vsync.  Setting it to a positive number will
+    // result in the minimum latency being:
+    //
+    //     (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD))
+    //
+    // Note that reducing this latency makes it more likely for the applications
+    // to not have their window content image ready in time.  When this happens
+    // the latency will end up being an additional vsync period, and animations
+    // will hiccup.  Therefore, this latency should be tuned somewhat
+    // conservatively (or at least with awareness of the trade-off being made).
+    static int64_t vsyncPhaseOffsetNs;
+    static int64_t sfVsyncPhaseOffsetNs;
+
     static char const* getServiceName() ANDROID_API {
         return "SurfaceFlinger";
     }
@@ -203,7 +227,6 @@
      */
     virtual sp<ISurfaceComposerClient> createConnection();
     virtual sp<ISurfaceComposerClient> createScopedConnection(const sp<IGraphicBufferProducer>& gbp);
-    virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc();
     virtual sp<IBinder> createDisplay(const String8& displayName, bool secure);
     virtual void destroyDisplay(const sp<IBinder>& display);
     virtual sp<IBinder> getBuiltInDisplay(int32_t id);
@@ -659,7 +682,6 @@
     std::atomic<bool> mEnterVrMode;
 #endif
     };
-
 }; // namespace android
 
 #endif // ANDROID_SURFACE_FLINGER_H
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 2fcbdba..01226e0 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -183,7 +183,7 @@
     // we don't need to factor that in here.  Pad a little to avoid
     // weird effects if apps might be requesting times right on the edge.
     nsecs_t extraPadding = 0;
-    if (VSYNC_EVENT_PHASE_OFFSET_NS == 0) {
+    if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
         extraPadding = 1000000;        // 1ms (6% of 60Hz)
     }
 
@@ -237,19 +237,6 @@
     mContentsChangedListener = listener;
 }
 
-void SurfaceFlingerConsumer::onBuffersReleased() {
-    sp<ContentsChangedListener> listener;
-    {   // scope for the lock
-        Mutex::Autolock lock(mMutex);
-        ALOG_ASSERT(mFrameAvailableListener.unsafe_get() == mContentsChangedListener.unsafe_get());
-        listener = mContentsChangedListener.promote();
-    }
-
-    if (listener != NULL) {
-        listener->onBuffersReleased();
-    }
-}
-
 void SurfaceFlingerConsumer::onSidebandStreamChanged() {
     sp<ContentsChangedListener> listener;
     {   // scope for the lock
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index cfa70ed..1126233 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -35,7 +35,6 @@
     static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8;
 
     struct ContentsChangedListener: public FrameAvailableListener {
-        virtual void onBuffersReleased() = 0;
         virtual void onSidebandStreamChanged() = 0;
     };
 
@@ -93,7 +92,6 @@
             FrameEventHistoryDelta* outDelta) override;
 
 private:
-    virtual void onBuffersReleased();
     virtual void onSidebandStreamChanged();
 
     wp<ContentsChangedListener> mContentsChangedListener;
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 6cd7152..147232c 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -42,7 +42,6 @@
 #include <gui/GuiConfig.h>
 #include <gui/IDisplayEventConnection.h>
 #include <gui/Surface.h>
-#include <gui/GraphicBufferAlloc.h>
 
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/HdrCapabilities.h>
@@ -84,6 +83,9 @@
 #include "RenderEngine/RenderEngine.h"
 #include <cutils/compiler.h>
 
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <configstore/Utils.h>
+
 #define DISPLAY_COUNT       1
 
 /*
@@ -95,40 +97,19 @@
 EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
 
 namespace android {
-
-// This is the phase offset in nanoseconds of the software vsync event
-// relative to the vsync event reported by HWComposer.  The software vsync
-// event is when SurfaceFlinger and Choreographer-based applications run each
-// frame.
-//
-// This phase offset allows adjustment of the minimum latency from application
-// wake-up (by Choregographer) time to the time at which the resulting window
-// image is displayed.  This value may be either positive (after the HW vsync)
-// or negative (before the HW vsync).  Setting it to 0 will result in a
-// minimum latency of two vsync periods because the app and SurfaceFlinger
-// will run just after the HW vsync.  Setting it to a positive number will
-// result in the minimum latency being:
-//
-//     (2 * VSYNC_PERIOD - (vsyncPhaseOffsetNs % VSYNC_PERIOD))
-//
-// Note that reducing this latency makes it more likely for the applications
-// to not have their window content image ready in time.  When this happens
-// the latency will end up being an additional vsync period, and animations
-// will hiccup.  Therefore, this latency should be tuned somewhat
-// conservatively (or at least with awareness of the trade-off being made).
-static const int64_t vsyncPhaseOffsetNs = VSYNC_EVENT_PHASE_OFFSET_NS;
-
-// This is the phase offset at which SurfaceFlinger's composition runs.
-static const int64_t sfVsyncPhaseOffsetNs = SF_VSYNC_EVENT_PHASE_OFFSET_NS;
-
 // ---------------------------------------------------------------------------
 
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+
 const String16 sHardwareTest("android.permission.HARDWARE_TEST");
 const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
 const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
 const String16 sDump("android.permission.DUMP");
 
 // ---------------------------------------------------------------------------
+int64_t SurfaceFlinger::vsyncPhaseOffsetNs;
+int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs;
 
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
@@ -165,6 +146,12 @@
         mLastSwapTime(0),
         mNumLayers(0)
 {
+    vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);
+
+    sfVsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs,
+            &ISurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs>(1000000);
+
     ALOGI("SurfaceFlinger is starting");
 
     char value[PROPERTY_VALUE_MAX];
@@ -307,12 +294,6 @@
     return mBuiltinDisplays[id];
 }
 
-sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
-{
-    sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
-    return gba;
-}
-
 void SurfaceFlinger::bootFinished()
 {
     if (mStartBootAnimThread->join() != NO_ERROR) {
@@ -549,8 +530,7 @@
 
             sp<IGraphicBufferProducer> producer;
             sp<IGraphicBufferConsumer> consumer;
-            BufferQueue::createBufferQueue(&producer, &consumer,
-                    new GraphicBufferAlloc());
+            BufferQueue::createBufferQueue(&producer, &consumer);
 
             sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
                     consumer);
@@ -719,7 +699,7 @@
         info.xdpi = xdpi;
         info.ydpi = ydpi;
         info.fps = float(1e9 / hwConfig.refresh);
-        info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
+        info.appVsyncOffset = vsyncPhaseOffsetNs;
 
         // This is how far in advance a buffer must be queued for
         // presentation at a given time.  If you want a buffer to appear
@@ -734,7 +714,7 @@
         // We add an additional 1ms to allow for processing time and
         // differences between the ideal and actual refresh rate.
         info.presentationDeadline =
-                hwConfig.refresh - SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000;
+                hwConfig.refresh - sfVsyncPhaseOffsetNs + 1000000;
 
         // All non-virtual displays are currently considered secure.
         info.secure = true;
@@ -1680,8 +1660,7 @@
                     sp<IGraphicBufferProducer> producer;
                     sp<IGraphicBufferProducer> bqProducer;
                     sp<IGraphicBufferConsumer> bqConsumer;
-                    BufferQueue::createBufferQueue(&bqProducer, &bqConsumer,
-                            new GraphicBufferAlloc());
+                    BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
 
                     int32_t hwcDisplayId = -1;
                     if (state.isVirtualDisplay()) {
@@ -2317,6 +2296,8 @@
 }
 
 status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
+    Mutex::Autolock _l(mStateLock);
+
     const auto& p = layer->getParent();
     const ssize_t index = (p != nullptr) ? p->removeChild(layer) :
              mCurrentState.layersSortedByZ.remove(layer);
diff --git a/services/vr/sensord/Android.mk b/services/vr/sensord/Android.mk
index e213bd6..f86664e 100644
--- a/services/vr/sensord/Android.mk
+++ b/services/vr/sensord/Android.mk
@@ -14,6 +14,8 @@
 
 LOCAL_PATH := $(call my-dir)
 
+SENSORD_EXTEND ?= libsensordextensionstub
+
 sourceFiles := \
 	pose_service.cpp \
 	sensord.cpp \
@@ -42,6 +44,7 @@
 	liblog \
 	libhardware \
 	libutils \
+	$(SENSORD_EXTEND) \
 
 cFlags := -DLOG_TAG=\"sensord\" \
           -DTRACE=0
@@ -67,3 +70,8 @@
 LOCAL_SRC_FILES := test/poselatencytest.cpp
 LOCAL_MODULE := poselatencytest
 include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libsensordextensionstub
+LOCAL_SRC_FILES := sensord_extension.cpp
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/vr/sensord/sensord.cpp b/services/vr/sensord/sensord.cpp
index 0a75318..db39152 100644
--- a/services/vr/sensord/sensord.cpp
+++ b/services/vr/sensord/sensord.cpp
@@ -14,6 +14,7 @@
 #include "sensor_ndk_thread.h"
 #include "sensor_service.h"
 #include "sensor_thread.h"
+#include "sensord_extension.h"
 
 using android::dvr::PoseService;
 using android::dvr::SensorHalThread;
@@ -22,10 +23,13 @@
 using android::dvr::SensorThread;
 using android::pdx::Service;
 using android::pdx::ServiceDispatcher;
+using android::dvr::SensordExtension;
 
 int main(int, char**) {
   ALOGI("Starting up...");
 
+  SensordExtension::run();
+
   // We need to be able to create endpoints with full perms.
   umask(0000);
 
diff --git a/services/vr/sensord/sensord_extension.cpp b/services/vr/sensord/sensord_extension.cpp
new file mode 100644
index 0000000..6cd7db3
--- /dev/null
+++ b/services/vr/sensord/sensord_extension.cpp
@@ -0,0 +1,4 @@
+#include "sensord_extension.h"
+
+void android::dvr::SensordExtension::run() {
+}
diff --git a/services/vr/sensord/sensord_extension.h b/services/vr/sensord/sensord_extension.h
new file mode 100644
index 0000000..e553eed
--- /dev/null
+++ b/services/vr/sensord/sensord_extension.h
@@ -0,0 +1,16 @@
+#ifndef ANDROID_DVR_SENSORD_EXTENSION_H_
+#define ANDROID_DVR_SENSORD_EXTENSION_H_
+
+namespace android {
+namespace dvr {
+
+// Allows sensord to be extended with additional code.
+class SensordExtension {
+ public:
+  static void run();
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_SENSORD_EXTENSION_H_
diff --git a/services/vr/virtual_touchpad/Android.mk b/services/vr/virtual_touchpad/Android.mk
index b78eb99..88b2dd9 100644
--- a/services/vr/virtual_touchpad/Android.mk
+++ b/services/vr/virtual_touchpad/Android.mk
@@ -9,7 +9,8 @@
   VirtualTouchpadEvdev.cpp
 
 shared_libs := \
-  libbase
+  libbase \
+  libutils
 
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(src)
@@ -24,21 +25,23 @@
 
 # Touchpad unit tests.
 
-test_src_files := \
-  tests/VirtualTouchpad_test.cpp
-
-static_libs := \
+test_static_libs := \
   libbase \
   libcutils \
-  libutils \
   libvirtualtouchpad
 
+test_shared_libs := \
+  libutils
+
+test_src_files := \
+  tests/VirtualTouchpad_test.cpp
+
 $(foreach file,$(test_src_files), \
     $(eval include $(CLEAR_VARS)) \
     $(eval LOCAL_SRC_FILES := $(file)) \
     $(eval LOCAL_C_INCLUDES := $(LOCAL_PATH)/include) \
-    $(eval LOCAL_STATIC_LIBRARIES := $(static_libs)) \
-    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libs)) \
+    $(eval LOCAL_STATIC_LIBRARIES := $(test_static_libs)) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(test_shared_libs)) \
     $(eval LOCAL_CPPFLAGS += -std=c++11) \
     $(eval LOCAL_LDLIBS := -llog) \
     $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
@@ -70,7 +73,7 @@
 LOCAL_STATIC_LIBRARIES := $(static_libs)
 LOCAL_SHARED_LIBRARIES := $(shared_libs)
 LOCAL_CPPFLAGS += -std=c++11
-LOCAL_CFLAGS += -DLOG_TAG=\"VrVirtualTouchpad\"
+LOCAL_CFLAGS += -DLOG_TAG=\"VrVirtualTouchpad\" -DSELINUX_ACCESS_CONTROL
 LOCAL_LDLIBS := -llog
 LOCAL_MODULE := virtual_touchpad
 LOCAL_MODULE_TAGS := optional
diff --git a/services/vr/virtual_touchpad/EvdevInjector.cpp b/services/vr/virtual_touchpad/EvdevInjector.cpp
index d8a1dfa..b4c0a52 100644
--- a/services/vr/virtual_touchpad/EvdevInjector.cpp
+++ b/services/vr/virtual_touchpad/EvdevInjector.cpp
@@ -307,5 +307,11 @@
   return 0;
 }
 
+void EvdevInjector::dumpInternal(String8& result) {
+  result.append("[injector]\n");
+  result.appendFormat("state = %d\n", static_cast<int>(state_));
+  result.appendFormat("error = %d\n\n", error_);
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/virtual_touchpad/EvdevInjector.h b/services/vr/virtual_touchpad/EvdevInjector.h
index 1b1c4da..c69dbef 100644
--- a/services/vr/virtual_touchpad/EvdevInjector.h
+++ b/services/vr/virtual_touchpad/EvdevInjector.h
@@ -3,6 +3,7 @@
 
 #include <android-base/unique_fd.h>
 #include <linux/uinput.h>
+#include <utils/String8.h>
 
 #include <cstdint>
 #include <memory>
@@ -99,6 +100,8 @@
   int SendMultiTouchXY(int32_t slot, int32_t id, int32_t x, int32_t y);
   int SendMultiTouchLift(int32_t slot);
 
+  void dumpInternal(String8& result);
+
  protected:
   // Must be called only between construction and ConfigureBegin().
   inline void SetUInputForTesting(UInput* uinput) { uinput_ = uinput; }
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
index 175173f..782b19c 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
@@ -10,17 +10,49 @@
 
 class VirtualTouchpadClientImpl : public VirtualTouchpadClient {
  public:
-  VirtualTouchpadClientImpl(sp<IVirtualTouchpadService> service)
-      : service_(service) {}
-  ~VirtualTouchpadClientImpl() override {}
+  VirtualTouchpadClientImpl() {}
+  ~VirtualTouchpadClientImpl() override {
+    if (service_ != nullptr) {
+      Detach();
+    }
+  }
 
-  status_t Touch(int touchpad,
-                 float x, float y, float pressure) override {
+  status_t Attach() {
+    if (service_ != nullptr) {
+      return ALREADY_EXISTS;
+    }
+    sp<IServiceManager> sm = defaultServiceManager();
+    if (sm == nullptr) {
+      ALOGE("no service manager");
+      return NO_INIT;
+    }
+    sp<IVirtualTouchpadService> service =
+        interface_cast<IVirtualTouchpadService>(
+            sm->getService(IVirtualTouchpadService::SERVICE_NAME()));
+    if (service == nullptr) {
+      ALOGE("failed to get service");
+      return NAME_NOT_FOUND;
+    }
+    service_ = service;
+    return service_->attach().transactionError();
+  }
+
+  status_t Detach() {
+    if (service_ == nullptr) {
+      return NO_INIT;
+    }
+    status_t status = service_->detach().transactionError();
+    service_ = nullptr;
+    return status;
+  }
+
+  status_t Touch(int touchpad, float x, float y, float pressure) override {
     if (service_ == nullptr) {
       return NO_INIT;
     }
     return service_->touch(touchpad, x, y, pressure).transactionError();
   }
+
   status_t ButtonState(int touchpad, int buttons) override {
     if (service_ == nullptr) {
       return NO_INIT;
@@ -28,6 +60,12 @@
     return service_->buttonState(touchpad, buttons).transactionError();
   }
 
+  void dumpInternal(String8& result) override {
+    result.append("[virtual touchpad]\n");
+    result.appendFormat("connected = %s\n\n",
+                        service_ != nullptr ? "true" : "false");
+  }
+
  private:
   sp<IVirtualTouchpadService> service_;
 };
@@ -35,18 +73,7 @@
 }  // anonymous namespace
 
 sp<VirtualTouchpad> VirtualTouchpadClient::Create() {
-  sp<IServiceManager> sm = defaultServiceManager();
-  if (sm == nullptr) {
-    ALOGE("no service manager");
-    return sp<VirtualTouchpad>();
-  }
-  sp<IVirtualTouchpadService> service = interface_cast<IVirtualTouchpadService>(
-      sm->getService(IVirtualTouchpadService::SERVICE_NAME()));
-  if (service == nullptr) {
-    ALOGE("failed to get service");
-    return sp<VirtualTouchpad>();
-  }
-  return new VirtualTouchpadClientImpl(service);
+  return new VirtualTouchpadClientImpl();
 }
 
 }  // namespace dvr
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index f25a2ad..bc29408 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -32,15 +32,10 @@
 
 sp<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
   VirtualTouchpadEvdev* const touchpad = new VirtualTouchpadEvdev();
-  const status_t status = touchpad->Initialize();
-  if (status) {
-    ALOGE("initialization failed: %d", status);
-    return sp<VirtualTouchpad>();
-  }
   return sp<VirtualTouchpad>(touchpad);
 }
 
-int VirtualTouchpadEvdev::Initialize() {
+status_t VirtualTouchpadEvdev::Attach() {
   if (!injector_) {
     owned_injector_.reset(new EvdevInjector());
     injector_ = owned_injector_.get();
@@ -56,9 +51,20 @@
   return injector_->GetError();
 }
 
+status_t VirtualTouchpadEvdev::Detach() {
+  injector_->Close();
+  injector_ = nullptr;
+  owned_injector_.reset();
+  last_device_x_ = INT32_MIN;
+  last_device_y_ = INT32_MIN;
+  touches_ = 0;
+  last_motion_event_buttons_ = 0;
+  return OK;
+}
+
 int VirtualTouchpadEvdev::Touch(int touchpad, float x, float y,
                                 float pressure) {
-  (void)touchpad; // TODO(b/35992608) Support multiple virtual touchpad devices.
+  (void)touchpad;  // TODO(b/35992608) Support multiple touchpad devices.
   if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
     return EINVAL;
   }
@@ -104,7 +110,7 @@
 }
 
 int VirtualTouchpadEvdev::ButtonState(int touchpad, int buttons) {
-  (void)touchpad; // TODO(b/35992608) Support multiple virtual touchpad devices.
+  (void)touchpad;  // TODO(b/35992608) Support multiple touchpad devices.
   const int changes = last_motion_event_buttons_ ^ buttons;
   if (!changes) {
     return 0;
@@ -123,10 +129,26 @@
     injector_->SendKey(BTN_BACK, (buttons & AMOTION_EVENT_BUTTON_BACK)
                                      ? EvdevInjector::KEY_PRESS
                                      : EvdevInjector::KEY_RELEASE);
+    injector_->SendSynReport();
   }
   last_motion_event_buttons_ = buttons;
   return injector_->GetError();
 }
 
+void VirtualTouchpadEvdev::dumpInternal(String8& result) {
+  result.append("[virtual touchpad]\n");
+  if (!injector_) {
+    result.append("injector = none\n");
+    return;
+  }
+  result.appendFormat("injector = %s\n", owned_injector_ ? "normal" : "test");
+  result.appendFormat("touches = %d\n", touches_);
+  result.appendFormat("last_position = (%" PRId32 ", %" PRId32 ")\n",
+                      last_device_x_, last_device_y_);
+  result.appendFormat("last_buttons = 0x%" PRIX32 "\n\n",
+                      last_motion_event_buttons_);
+  injector_->dumpInternal(result);
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
index ec8006b..b158cec 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
@@ -18,15 +18,17 @@
   static sp<VirtualTouchpad> Create();
 
   // VirtualTouchpad implementation:
+  status_t Attach() override;
+  status_t Detach() override;
   status_t Touch(int touchpad, float x, float y, float pressure) override;
   status_t ButtonState(int touchpad, int buttons) override;
+  void dumpInternal(String8& result) override;
 
  protected:
   VirtualTouchpadEvdev() {}
   ~VirtualTouchpadEvdev() override {}
-  status_t Initialize();
 
-  // Must be called only between construction and Initialize().
+  // Must be called only between construction and Attach().
   inline void SetEvdevInjectorForTesting(EvdevInjector* injector) {
     injector_ = injector;
   }
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
index a1f281c..2e2f622 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
@@ -1,22 +1,136 @@
 #include "VirtualTouchpadService.h"
 
+#include <inttypes.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/PermissionCache.h>
 #include <binder/Status.h>
+#include <cutils/log.h>
 #include <linux/input.h>
-#include <log/log.h>
+#include <private/android_filesystem_config.h>
 #include <utils/Errors.h>
 
 namespace android {
 namespace dvr {
 
-binder::Status VirtualTouchpadService::touch(int touchpad,
-                                             float x, float y, float pressure) {
-  const status_t error = touchpad_->Touch(touchpad, x, y, pressure);
-  return error ? binder::Status::fromStatusT(error) : binder::Status::ok();
+namespace {
+const String16 kDumpPermission("android.permission.DUMP");
+const String16 kTouchPermission("android.permission.RESTRICTED_VR_ACCESS");
+}  // anonymous namespace
+
+VirtualTouchpadService::~VirtualTouchpadService() {
+  if (client_pid_) {
+    client_pid_ = 0;
+    touchpad_->Detach();
+  }
+}
+
+binder::Status VirtualTouchpadService::attach() {
+  pid_t pid;
+  if (!CheckTouchPermission(&pid)) {
+    return binder::Status::fromStatusT(PERMISSION_DENIED);
+  }
+  if (client_pid_ == pid) {
+    // The same client has called attach() twice with no intervening detach().
+    // This indicates a problem with the client, so return an error.
+    // However, since the client is already attached, any touchpad actions
+    // it takes will still work.
+    ALOGE("pid=%ld attached twice", static_cast<long>(pid));
+    return binder::Status::fromStatusT(ALREADY_EXISTS);
+  }
+  if (client_pid_ != 0) {
+    // Attach while another client is attached. This can happen if the client
+    // dies without cleaning up after itself, so move ownership to the current
+    // caller. If two actual clients have connected, the problem will be
+    // reported when the previous client performs any touchpad action.
+    ALOGE("pid=%ld replaces %ld", static_cast<long>(pid),
+          static_cast<long>(client_pid_));
+  }
+  client_pid_ = pid;
+  if (const status_t error = touchpad_->Attach()) {
+    return binder::Status::fromStatusT(error);
+  }
+  return binder::Status::ok();
+}
+
+binder::Status VirtualTouchpadService::detach() {
+  if (!CheckPermissions()) {
+    return binder::Status::fromStatusT(PERMISSION_DENIED);
+  }
+  client_pid_ = 0;
+  if (const status_t error = touchpad_->Detach()) {
+    return binder::Status::fromStatusT(error);
+  }
+  return binder::Status::ok();
+}
+
+binder::Status VirtualTouchpadService::touch(int touchpad, float x, float y,
+                                             float pressure) {
+  if (!CheckPermissions()) {
+    return binder::Status::fromStatusT(PERMISSION_DENIED);
+  }
+  if (const status_t error = touchpad_->Touch(touchpad, x, y, pressure)) {
+    return binder::Status::fromStatusT(error);
+  }
+  return binder::Status::ok();
 }
 
 binder::Status VirtualTouchpadService::buttonState(int touchpad, int buttons) {
-  const status_t error = touchpad_->ButtonState(touchpad, buttons);
-  return error ? binder::Status::fromStatusT(error) : binder::Status::ok();
+  if (!CheckPermissions()) {
+    return binder::Status::fromStatusT(PERMISSION_DENIED);
+  }
+  if (const status_t error = touchpad_->ButtonState(touchpad, buttons)) {
+    return binder::Status::fromStatusT(error);
+  }
+  return binder::Status::ok();
+}
+
+status_t VirtualTouchpadService::dump(
+    int fd, const Vector<String16>& args[[gnu::unused]]) {
+  String8 result;
+  const android::IPCThreadState* ipc = android::IPCThreadState::self();
+  const pid_t pid = ipc->getCallingPid();
+  const uid_t uid = ipc->getCallingUid();
+  if ((uid != AID_SHELL) &&
+      !PermissionCache::checkPermission(kDumpPermission, pid, uid)) {
+    result.appendFormat("Permission denial: can't dump " LOG_TAG
+                        " from pid=%ld, uid=%ld\n",
+                        static_cast<long>(pid), static_cast<long>(uid));
+  } else {
+    result.appendFormat("[service]\nclient_pid = %ld\n\n",
+                        static_cast<long>(client_pid_));
+    touchpad_->dumpInternal(result);
+  }
+  write(fd, result.string(), result.size());
+  return OK;
+}
+
+bool VirtualTouchpadService::CheckPermissions() {
+  pid_t pid;
+  if (!CheckTouchPermission(&pid)) {
+    return false;
+  }
+  if (client_pid_ != pid) {
+    ALOGE("pid=%ld is not owner", static_cast<long>(pid));
+    return false;
+  }
+  return true;
+}
+
+bool VirtualTouchpadService::CheckTouchPermission(pid_t* out_pid) {
+  const android::IPCThreadState* ipc = android::IPCThreadState::self();
+  *out_pid = ipc->getCallingPid();
+#ifdef SELINUX_ACCESS_CONTROL
+  return true;
+#else
+  const uid_t uid = ipc->getCallingUid();
+  const bool permission = PermissionCache::checkPermission(kTouchPermission, *out_pid, uid);
+  if (!permission) {
+    ALOGE("permission denied to pid=%ld uid=%ld", static_cast<long>(*out_pid),
+          static_cast<long>(uid));
+  }
+  return permission;
+#endif
 }
 
 }  // namespace dvr
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.h b/services/vr/virtual_touchpad/VirtualTouchpadService.h
index 9b880b2..194d787 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.h
@@ -14,17 +14,28 @@
 class VirtualTouchpadService : public BnVirtualTouchpadService {
  public:
   VirtualTouchpadService(sp<VirtualTouchpad> touchpad)
-      : touchpad_(touchpad) {}
-  ~VirtualTouchpadService() override {}
+      : touchpad_(touchpad), client_pid_(0) {}
+  ~VirtualTouchpadService() override;
 
  protected:
   // Implements IVirtualTouchpadService.
+  binder::Status attach() override;
+  binder::Status detach() override;
   binder::Status touch(int touchpad, float x, float y, float pressure) override;
   binder::Status buttonState(int touchpad, int buttons) override;
 
+  // Implements BBinder::dump().
+  status_t dump(int fd, const Vector<String16>& args) override;
+
  private:
+  bool CheckPermissions();
+  bool CheckTouchPermission(pid_t* out_pid);
+
   sp<VirtualTouchpad> touchpad_;
 
+  // Only one client at a time can use the virtual touchpad.
+  pid_t client_pid_;
+
   VirtualTouchpadService(const VirtualTouchpadService&) = delete;
   void operator=(const VirtualTouchpadService&) = delete;
 };
diff --git a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
index 496c5e2..9cfb186 100644
--- a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
+++ b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
@@ -6,6 +6,16 @@
   const String SERVICE_NAME = "virtual_touchpad";
 
   /**
+   * Initialize the virtual touchpad.
+   */
+  void attach() = 0;
+
+  /**
+   * Shut down the virtual touchpad.
+   */
+  void detach() = 1;
+
+  /**
    * Generate a simulated touch event.
    *
    * @param touchpad Selects touchpad.
@@ -15,7 +25,7 @@
    *
    * Position values in the range [0.0, 1.0) map to the screen.
    */
-  void touch(int touchpad, float x, float y, float pressure);
+  void touch(int touchpad, float x, float y, float pressure) = 2;
 
   /**
    * Generate a simulated touchpad button state event.
@@ -23,5 +33,5 @@
    * @param touchpad Selects touchpad.
    * @param buttons A union of MotionEvent BUTTON_* values.
    */
-  void buttonState(int touchpad, int buttons);
+  void buttonState(int touchpad, int buttons) = 3;
 }
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpad.h b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
index d24d121..b1ee700 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpad.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
@@ -3,6 +3,7 @@
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include <utils/String8.h>
 #include <utils/StrongPointer.h>
 
 namespace android {
@@ -21,10 +22,18 @@
   // Implementations should provide this, and hide their constructors.
   // For the user, switching implementations should be as simple as changing
   // the class whose |Create()| is called.
+  // Implementations should be minimial; major resource allocation should
+  // be performed in Attach().
   static sp<VirtualTouchpad> Create() {
     return sp<VirtualTouchpad>();
   }
 
+  // Initialize a virtual touchpad.
+  virtual status_t Attach() = 0;
+
+  // Shut down a virtual touchpad.
+  virtual status_t Detach() = 0;
+
   // Generate a simulated touch event.
   //
   // @param touchpad Touchpad selector index.
@@ -49,6 +58,9 @@
   //
   virtual status_t ButtonState(int touchpad, int buttons) = 0;
 
+  // Report state for 'dumpsys'.
+  virtual void dumpInternal(String8& result) = 0;
+
  protected:
   VirtualTouchpad() {}
   ~VirtualTouchpad() override {}
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
index dd9c265..471d9e0 100644
--- a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
@@ -13,8 +13,11 @@
  public:
   // VirtualTouchpad implementation:
   static sp<VirtualTouchpad> Create();
+  status_t Attach() override;
+  status_t Detach() override;
   status_t Touch(int touchpad, float x, float y, float pressure) override;
   status_t ButtonState(int touchpad, int buttons) override;
+  void dumpInternal(String8& result) override;
 
  protected:
   VirtualTouchpadClient() {}
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index 469a2d0..b11a983 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -97,7 +97,6 @@
   static sp<VirtualTouchpad> Create(EvdevInjectorForTesting& injector) {
     VirtualTouchpadForTesting* const touchpad = new VirtualTouchpadForTesting();
     touchpad->SetEvdevInjectorForTesting(&injector);
-    touchpad->Initialize();
     return sp<VirtualTouchpad>(touchpad);
   }
 };
@@ -123,6 +122,9 @@
   EvdevInjectorForTesting injector(record);
   sp<VirtualTouchpad> touchpad(VirtualTouchpadForTesting::Create(injector));
 
+  status_t touch_status = touchpad->Attach();
+  EXPECT_EQ(0, touch_status);
+
   // Check some aspects of uinput_user_dev.
   const uinput_user_dev* uidev = injector.GetUiDev();
   for (int i = 0; i < ABS_CNT; ++i) {
@@ -151,6 +153,7 @@
   // From ConfigureKey(BTN_TOUCH):
   expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
   expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
+  expect.IoctlSetInt(UI_SET_KEYBIT, BTN_BACK);
   // From ConfigureEnd():
   expect.Write(uidev, sizeof(uinput_user_dev));
   expect.IoctlVoid(UI_DEV_CREATE);
@@ -158,7 +161,7 @@
 
   expect.Reset();
   record.Reset();
-  int touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0, 0, 0);
+  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0, 0, 0);
   EXPECT_EQ(0, touch_status);
   expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0);
   expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
@@ -180,16 +183,22 @@
 
   expect.Reset();
   record.Reset();
-  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 1.0f, 1.0f, 1.0f);
+  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 0.99f, 0.99f, 0.99f);
   EXPECT_EQ(0, touch_status);
   expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
-  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, width);
-  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, height);
+  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.99f * width);
+  expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_Y, 0.99f * height);
   expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
   EXPECT_EQ(expect.GetString(), record.GetString());
 
   expect.Reset();
   record.Reset();
+  touch_status = touchpad->Touch(VirtualTouchpad::PRIMARY, 1.0f, 1.0f, 1.0f);
+  EXPECT_EQ(EINVAL, touch_status);
+  EXPECT_EQ(expect.GetString(), record.GetString());
+
+  expect.Reset();
+  record.Reset();
   touch_status =
       touchpad->Touch(VirtualTouchpad::PRIMARY, 0.25f, 0.75f, -0.01f);
   EXPECT_EQ(0, touch_status);
@@ -224,6 +233,10 @@
 
   expect.Reset();
   record.Reset();
+  touch_status = touchpad->Detach();
+  EXPECT_EQ(0, touch_status);
+  expect.Close();
+  EXPECT_EQ(expect.GetString(), record.GetString());
 }
 
 TEST_F(VirtualTouchpadTest, Badness) {
@@ -232,11 +245,14 @@
   EvdevInjectorForTesting injector(record);
   sp<VirtualTouchpad> touchpad(VirtualTouchpadForTesting::Create(injector));
 
+  status_t touch_status = touchpad->Attach();
+  EXPECT_EQ(0, touch_status);
+
   // Touch off-screen should return an error,
   // and should not result in any system calls.
   expect.Reset();
   record.Reset();
-  status_t touch_status =
+  touch_status =
       touchpad->Touch(VirtualTouchpad::PRIMARY, -0.25f, 0.75f, 1.0f);
   EXPECT_NE(OK, touch_status);
   touch_status =
@@ -256,6 +272,10 @@
                                        AMOTION_EVENT_BUTTON_FORWARD);
   EXPECT_NE(OK, touch_status);
   EXPECT_EQ(expect.GetString(), record.GetString());
+
+  // Repeated attach is an error.
+  touch_status = touchpad->Attach();
+  EXPECT_NE(0, touch_status);
 }
 
 }  // namespace dvr
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index fae1dd9..10588b7 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -250,8 +250,12 @@
 
   translate_ = Eigen::Translation3f(0, 0, -2.5f);
 
-  if (!InitializeTouch())
-    ALOGE("Failed to initialize virtual touchpad");
+  virtual_touchpad_ = VirtualTouchpadClient::Create();
+  const status_t touchpad_status = virtual_touchpad_->Attach();
+  if (touchpad_status != OK) {
+    ALOGE("Failed to connect to virtual touchpad");
+    return touchpad_status;
+  }
 
   surface_flinger_view_.reset(new SurfaceFlingerView);
   if (!surface_flinger_view_->Initialize(this))
@@ -702,22 +706,10 @@
   controller_mesh_->Draw();
 }
 
-bool ShellView::InitializeTouch() {
-  virtual_touchpad_ = VirtualTouchpadClient::Create();
-  if (!virtual_touchpad_.get()) {
-    ALOGE("Failed to connect to virtual touchpad");
-    return false;
-  }
-  return true;
-}
-
 void ShellView::Touch() {
   if (!virtual_touchpad_.get()) {
     ALOGE("missing virtual touchpad");
-    // Try to reconnect; useful in development.
-    if (!InitializeTouch()) {
-      return;
-    }
+    return;
   }
 
   const android::status_t status = virtual_touchpad_->Touch(
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index c477669..49456c6 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -58,7 +58,6 @@
              bool test_ime);
   bool IsImeHit(const vec3& view_location, const vec3& view_direction,
                 vec3 *hit_location);
-  bool InitializeTouch();
   void Touch();
   bool OnTouchpadButton(bool down, int button);
 
diff --git a/services/vr/vr_window_manager/vr_window_manager_binder.cpp b/services/vr/vr_window_manager/vr_window_manager_binder.cpp
index c2138b7..bd3f3ee 100644
--- a/services/vr/vr_window_manager/vr_window_manager_binder.cpp
+++ b/services/vr/vr_window_manager/vr_window_manager_binder.cpp
@@ -16,7 +16,8 @@
 
 namespace {
 const String16 kDumpPermission("android.permission.DUMP");
-const String16 kSendMeControllerInputPermission("TODO");  // TODO(kpschoedel)
+const String16 kSendMeControllerInputPermission(
+    "android.permission.RESTRICTED_VR_ACCESS");
 }  // anonymous namespace
 
 constexpr size_t AshmemControllerDataProvider::kRegionLength;
@@ -136,8 +137,8 @@
     int fd, const Vector<String16>& args [[gnu::unused]]) {
   String8 result;
   const android::IPCThreadState* ipc = android::IPCThreadState::self();
-  const int pid = ipc->getCallingPid();
-  const int uid = ipc->getCallingUid();
+  const pid_t pid = ipc->getCallingPid();
+  const uid_t uid = ipc->getCallingUid();
   if ((uid != AID_SHELL) &&
       !PermissionCache::checkPermission(kDumpPermission, pid, uid)) {
     result.appendFormat("Permission denial: can't dump " LOG_TAG