Merge "Export AIDL files as a filegroup for framework.jar"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index aba08d9..4b67d8f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1085,7 +1085,7 @@
                    CommandOptions::WithTimeout(90).DropRoot().Build());
     } else {
         RunDumpsys("DUMPSYS", {"--skip", "meminfo", "cpuinfo"},
-                   CommandOptions::WithTimeout(90).Build(), 10);
+                   CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
     }
 }
 
@@ -1307,8 +1307,10 @@
     printf("== Android Framework Services\n");
     printf("========================================================\n");
 
-    RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), 10);
-    RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), 10);
+    RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
+               SEC_TO_MSEC(10));
+    RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
+               SEC_TO_MSEC(10));
 
     printf("========================================================\n");
     printf("== Running Application Services\n");
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index e10fb6c..48d5b36 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -342,6 +342,56 @@
 #endif
 }
 
+static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
+    if (!property_get_bool("dalvik.vm.usejitprofiles", false)) {
+        return true;
+    }
+
+    int32_t uid = multiuser_get_uid(userId, appId);
+    int shared_app_gid = multiuser_get_shared_gid(userId, appId);
+    if (shared_app_gid == -1) {
+        // TODO(calin): this should no longer be possible but do not continue if we don't get
+        // a valid shared gid.
+        PLOG(WARNING) << "Invalid shared_app_gid for " << packageName;
+        return true;
+    }
+
+    const std::string profile_dir =
+            create_primary_current_profile_package_dir_path(userId, packageName);
+    // read-write-execute only for the app user.
+    if (fs_prepare_dir_strict(profile_dir.c_str(), 0700, uid, uid) != 0) {
+        PLOG(ERROR) << "Failed to prepare " << profile_dir;
+        return false;
+    }
+    const std::string profile_file = create_current_profile_path(userId, packageName,
+            /*is_secondary_dex*/false);
+    // read-write only for the app user.
+    if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
+        PLOG(ERROR) << "Failed to prepare " << profile_file;
+        return false;
+    }
+
+    const std::string ref_profile_path =
+            create_primary_reference_profile_package_dir_path(packageName);
+
+    // Prepare the reference profile directory. Note that we use the non strict version of
+    // fs_prepare_dir. This will fix the permission and the ownership to the correct values.
+    // This is particularly important given that in O there were some fixes for how the
+    // shared_app_gid is computed.
+    //
+    // Note that by the time we get here we know that we are using a correct uid (otherwise
+    // prepare_app_dir and the above fs_prepare_file_strict which check the uid). So we
+    // are sure that the gid being used belongs to the owning app and not someone else.
+    //
+    // dex2oat/profman runs under the shared app gid and it needs to read/write reference profiles.
+    if (fs_prepare_dir(ref_profile_path.c_str(), 0770, AID_SYSTEM, shared_app_gid) != 0) {
+        PLOG(ERROR) << "Failed to prepare " << ref_profile_path;
+        return false;
+    }
+
+    return true;
+}
+
 binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
         const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
@@ -417,28 +467,8 @@
             return error("Failed to set hard quota " + path);
         }
 
-        if (property_get_bool("dalvik.vm.usejitprofiles", false)) {
-            const std::string profile_dir =
-                    create_primary_current_profile_package_dir_path(userId, pkgname);
-            // read-write-execute only for the app user.
-            if (fs_prepare_dir_strict(profile_dir.c_str(), 0700, uid, uid) != 0) {
-                return error("Failed to prepare " + profile_dir);
-            }
-            const std::string profile_file = create_current_profile_path(userId, pkgname,
-                    /*is_secondary_dex*/false);
-            // read-write only for the app user.
-            if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
-                return error("Failed to prepare " + profile_file);
-            }
-            const std::string ref_profile_path =
-                    create_primary_reference_profile_package_dir_path(pkgname);
-            // dex2oat/profman runs under the shared app gid and it needs to read/write reference
-            // profiles.
-            int shared_app_gid = multiuser_get_shared_gid(0, appId);
-            if ((shared_app_gid != -1) && fs_prepare_dir_strict(
-                    ref_profile_path.c_str(), 0700, shared_app_gid, shared_app_gid) != 0) {
-                return error("Failed to prepare " + ref_profile_path);
-            }
+        if (!prepare_app_profile_dir(packageName, appId, userId)) {
+            return error("Failed to prepare profiles for " + packageName);
         }
     }
     return ok();
@@ -1833,6 +1863,29 @@
     return ok();
 }
 
+binder::Status InstalldNativeService::snapshotProfile(int32_t appId, const std::string& packageName,
+        const std::string& codePath, bool* _aidl_return) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    *_aidl_return = snapshot_profile(appId, packageName, codePath);
+    return ok();
+}
+
+binder::Status InstalldNativeService::destroyProfileSnapshot(const std::string& packageName,
+        const std::string& codePath) {
+    ENFORCE_UID(AID_SYSTEM);
+    CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+    std::lock_guard<std::recursive_mutex> lock(mLock);
+
+    std::string snapshot = create_snapshot_profile_path(packageName, codePath);
+    if ((unlink(snapshot.c_str()) != 0) && (errno != ENOENT)) {
+        return error("Failed to destroy profile snapshot for " + packageName + ":" + codePath);
+    }
+    return ok();
+}
+
 binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid,
         const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
         int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 5167a14..eb7231c 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -96,6 +96,11 @@
     binder::Status clearAppProfiles(const std::string& packageName);
     binder::Status destroyAppProfiles(const std::string& packageName);
 
+    binder::Status snapshotProfile(int32_t appId, const std::string& packageName,
+            const std::string& codePath, bool* _aidl_return);
+    binder::Status destroyProfileSnapshot(const std::string& packageName,
+            const std::string& codePath);
+
     binder::Status idmap(const std::string& targetApkPath, const std::string& overlayApkPath,
             int32_t uid);
     binder::Status removeIdmap(const std::string& overlayApkPath);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 0f9862d..16ba2af 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -62,6 +62,9 @@
     void clearAppProfiles(@utf8InCpp String packageName);
     void destroyAppProfiles(@utf8InCpp String packageName);
 
+    boolean snapshotProfile(int appId, @utf8InCpp String packageName, @utf8InCpp String codePath);
+    void destroyProfileSnapshot(@utf8InCpp String packageName, @utf8InCpp String codePath);
+
     void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid);
     void removeIdmap(@utf8InCpp String overlayApkPath);
     void rmPackageDir(@utf8InCpp String packageDir);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 6f160b9..beffe00 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -566,14 +566,12 @@
     }
 }
 
-static bool create_profile(int uid, const std::string& profile) {
-    unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), O_CREAT | O_NOFOLLOW, 0600)));
+static unique_fd create_profile(uid_t uid, const std::string& profile, int32_t flags) {
+    unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags, 0600)));
     if (fd.get() < 0) {
-        if (errno == EEXIST) {
-            return true;
-        } else {
+        if (errno != EEXIST) {
             PLOG(ERROR) << "Failed to create profile " << profile;
-            return false;
+            return invalid_unique_fd();
         }
     }
     // Profiles should belong to the app; make sure of that by giving ownership to
@@ -581,27 +579,26 @@
     // since dex2oat/profman will fail with SElinux denials.
     if (fchown(fd.get(), uid, uid) < 0) {
         PLOG(ERROR) << "Could not chwon profile " << profile;
-        return false;
+        return invalid_unique_fd();
     }
-    return true;
+    return fd;
 }
 
-static unique_fd open_profile(int uid, const std::string& profile, bool read_write) {
-    // Check if we need to open the profile for a read-write operation. If so, we
-    // might need to create the profile since the file might not be there. Reference
-    // profiles are created on the fly so they might not exist beforehand.
-    if (read_write) {
-        if (!create_profile(uid, profile)) {
-            return invalid_unique_fd();
-        }
-    }
-    int flags = read_write ? O_RDWR : O_RDONLY;
+static unique_fd open_profile(uid_t uid, const std::string& profile, int32_t flags) {
     // Do not follow symlinks when opening a profile:
     //   - primary profiles should not contain symlinks in their paths
     //   - secondary dex paths should have been already resolved and validated
     flags |= O_NOFOLLOW;
 
-    unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags)));
+    // Check if we need to create the profile
+    // Reference profiles and snapshots are created on the fly; so they might not exist beforehand.
+    unique_fd fd;
+    if ((flags & O_CREAT) != 0) {
+        fd = create_profile(uid, profile, flags);
+    } else {
+        fd.reset(TEMP_FAILURE_RETRY(open(profile.c_str(), flags)));
+    }
+
     if (fd.get() < 0) {
         if (errno != ENOENT) {
             // Profiles might be missing for various reasons. For example, in a
@@ -621,13 +618,19 @@
 static unique_fd open_current_profile(uid_t uid, userid_t user, const std::string& location,
         bool is_secondary_dex) {
     std::string profile = create_current_profile_path(user, location, is_secondary_dex);
-    return open_profile(uid, profile, /*read_write*/false);
+    return open_profile(uid, profile, O_RDONLY);
 }
 
 static unique_fd open_reference_profile(uid_t uid, const std::string& location, bool read_write,
         bool is_secondary_dex) {
     std::string profile = create_reference_profile_path(location, is_secondary_dex);
-    return open_profile(uid, profile, read_write);
+    return open_profile(uid, profile, read_write ? (O_CREAT | O_RDWR) : O_RDONLY);
+}
+
+static unique_fd open_spnashot_profile(uid_t uid, const std::string& package_name,
+        const std::string& code_path) {
+    std::string profile = create_snapshot_profile_path(package_name, code_path);
+    return open_profile(uid, profile, O_CREAT | O_RDWR | O_TRUNC);
 }
 
 static void open_profile_files(uid_t uid, const std::string& location, bool is_secondary_dex,
@@ -2396,5 +2399,42 @@
     }
 }
 
+bool snapshot_profile(int32_t app_id, const std::string& package_name,
+        const std::string& code_path) {
+    int app_shared_gid = multiuser_get_shared_gid(/*user_id*/ 0, app_id);
+
+    unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, code_path);
+    if (snapshot_fd < 0) {
+        return false;
+    }
+
+    std::vector<unique_fd> profiles_fd;
+    unique_fd reference_profile_fd;
+    open_profile_files(app_shared_gid, package_name, /*is_secondary_dex*/ false, &profiles_fd,
+            &reference_profile_fd);
+    if (profiles_fd.empty() || (reference_profile_fd.get() < 0)) {
+        return false;
+    }
+
+    profiles_fd.push_back(std::move(reference_profile_fd));
+
+    pid_t pid = fork();
+    if (pid == 0) {
+        /* child -- drop privileges before continuing */
+        drop_capabilities(app_shared_gid);
+        run_profman_merge(profiles_fd, snapshot_fd);
+        exit(42);   /* only get here on exec failure */
+    }
+
+    /* parent */
+    int return_code = wait_child(pid);
+    if (!WIFEXITED(return_code)) {
+        LOG(WARNING) << "profman failed for " << package_name << ":" << code_path;
+        return false;
+    }
+
+    return true;
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 798e211..8a9ffd2 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -50,6 +50,17 @@
 // the reference profiles accessible with open_reference_profile().
 bool analyze_primary_profiles(uid_t uid, const std::string& pkgname);
 
+// Create a snapshot of the profile information for the given package and code path.
+// The profile snapshot is the aggregation of all existing profiles (all current user
+// profiles & the reference profile) and is meant to capture the all the profile information
+// without performing a merge into the reference profile which might impact future dex2oat
+// compilations.
+// The snapshot is created next to the reference profile of the package and the
+// ownership is assigned to AID_SYSTEM.
+// The snapshot location is reference_profile_location.snapshot. If a snapshot is already
+// there, it will be truncated and overwritten.
+bool snapshot_profile(int32_t app_id, const std::string& package, const std::string& code_path);
+
 bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);
 
 bool copy_system_profile(const std::string& system_profile,
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 821b96f..05d7b6c 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -14,20 +14,33 @@
  * limitations under the License.
  */
 
+#include <fcntl.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+
 #include <cutils/properties.h>
+
 #include <gtest/gtest.h>
 
+#include <selinux/android.h>
+#include <selinux/avc.h>
+
 #include "dexopt.h"
 #include "InstalldNativeService.h"
 #include "globals.h"
 #include "tests/test_utils.h"
 #include "utils.h"
 
+using android::base::ReadFully;
+using android::base::unique_fd;
+
 namespace android {
 namespace installd {
 
@@ -76,6 +89,42 @@
     ::chmod(path.c_str(), mode);
 }
 
+static int log_callback(int type, const char *fmt, ...) { // NOLINT
+    va_list ap;
+    int priority;
+
+    switch (type) {
+        case SELINUX_WARNING:
+            priority = ANDROID_LOG_WARN;
+            break;
+        case SELINUX_INFO:
+            priority = ANDROID_LOG_INFO;
+            break;
+        default:
+            priority = ANDROID_LOG_ERROR;
+            break;
+    }
+    va_start(ap, fmt);
+    LOG_PRI_VA(priority, "SELinux", fmt, ap);
+    va_end(ap);
+    return 0;
+}
+
+static bool init_selinux() {
+    int selinux_enabled = (is_selinux_enabled() > 0);
+
+    union selinux_callback cb;
+    cb.func_log = log_callback;
+    selinux_set_callback(SELINUX_CB_LOG, cb);
+
+    if (selinux_enabled && selinux_status_open(true) < 0) {
+        LOG(ERROR) << "Could not open selinux status; exiting";
+        return false;
+    }
+
+    return true;
+}
+
 // Base64 encoding of a simple dex files with 2 methods.
 static const char kDexFile[] =
     "UEsDBBQAAAAIAOiOYUs9y6BLCgEAABQCAAALABwAY2xhc3Nlcy5kZXhVVAkAA/Ns+lkOHv1ZdXgL"
@@ -95,9 +144,11 @@
     static constexpr uid_t kSystemGid = 1000;
     static constexpr int32_t kOSdkVersion = 25;
     static constexpr int32_t kAppDataFlags = FLAG_STORAGE_CE | FLAG_STORAGE_DE;
-    static constexpr uid_t kTestAppUid = 19999;
-    static constexpr gid_t kTestAppGid = 19999;
     static constexpr int32_t kTestUserId = 0;
+    static constexpr uid_t kTestAppId = 19999;
+
+    const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId);
+    const uid_t kTestAppGid = multiuser_get_shared_gid(kTestUserId, kTestAppId);
 
     InstalldNativeService* service_;
     std::unique_ptr<std::string> volume_uuid_;
@@ -116,15 +167,18 @@
     virtual void SetUp() {
         setenv("ANDROID_LOG_TAGS", "*:v", 1);
         android::base::InitLogging(nullptr);
-
+        // Initialize the globals holding the file system main paths (/data/, /system/ etc..).
+        // This is needed in order to compute the application and profile paths.
+        ASSERT_TRUE(init_globals_from_data_and_root());
+        // Initialize selinux log callbacks.
+        // This ensures that selinux is up and running and re-directs the selinux messages
+        // to logcat (in order to make it easier to investigate test results).
+        ASSERT_TRUE(init_selinux());
         service_ = new InstalldNativeService();
 
         volume_uuid_ = nullptr;
         package_name_ = "com.installd.test.dexopt";
         se_info_ = "default";
-
-        init_globals_from_data_and_root();
-
         app_apk_dir_ = android_app_dir + package_name_;
 
         create_mock_app();
@@ -183,16 +237,19 @@
     }
 
 
-    std::string get_secondary_dex_artifact(const std::string& path, const std::string& type) {
+    std::string GetSecondaryDexArtifact(const std::string& path, const std::string& type) {
         std::string::size_type end = path.rfind('.');
         std::string::size_type start = path.rfind('/', end);
         return path.substr(0, start) + "/oat/" + kRuntimeIsa + "/" +
                 path.substr(start + 1, end - start) + type;
     }
 
-    void compile_secondary_dex(const std::string& path, int32_t dex_storage_flag,
+    void CompileSecondaryDex(const std::string& path, int32_t dex_storage_flag,
             bool should_binder_call_succeed, bool should_dex_be_compiled = true,
-            int uid = kTestAppUid) {
+            int32_t uid = -1) {
+        if (uid == -1) {
+            uid = kTestAppUid;
+        }
         std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
         int32_t dexopt_needed = 0;  // does not matter;
         std::unique_ptr<std::string> out_path = nullptr;  // does not matter
@@ -216,9 +273,9 @@
                                                  downgrade);
         ASSERT_EQ(should_binder_call_succeed, result.isOk());
         int expected_access = should_dex_be_compiled ? 0 : -1;
-        std::string odex = get_secondary_dex_artifact(path, "odex");
-        std::string vdex = get_secondary_dex_artifact(path, "vdex");
-        std::string art = get_secondary_dex_artifact(path, "art");
+        std::string odex = GetSecondaryDexArtifact(path, "odex");
+        std::string vdex = GetSecondaryDexArtifact(path, "vdex");
+        std::string art = GetSecondaryDexArtifact(path, "art");
         ASSERT_EQ(expected_access, access(odex.c_str(), R_OK));
         ASSERT_EQ(expected_access, access(vdex.c_str(), R_OK));
         ASSERT_EQ(-1, access(art.c_str(), R_OK));  // empty profiles do not generate an image.
@@ -226,7 +283,10 @@
 
     void reconcile_secondary_dex(const std::string& path, int32_t storage_flag,
             bool should_binder_call_succeed, bool should_dex_exist, bool should_dex_be_deleted,
-            int uid = kTestAppUid, std::string* package_override = nullptr) {
+            int32_t uid = -1, std::string* package_override = nullptr) {
+        if (uid == -1) {
+            uid = kTestAppUid;
+        }
         std::vector<std::string> isas;
         isas.push_back(kRuntimeIsa);
         bool out_secondary_dex_exists = false;
@@ -243,56 +303,64 @@
         ASSERT_EQ(should_dex_exist, out_secondary_dex_exists);
 
         int expected_access = should_dex_be_deleted ? -1 : 0;
-        std::string odex = get_secondary_dex_artifact(path, "odex");
-        std::string vdex = get_secondary_dex_artifact(path, "vdex");
-        std::string art = get_secondary_dex_artifact(path, "art");
+        std::string odex = GetSecondaryDexArtifact(path, "odex");
+        std::string vdex = GetSecondaryDexArtifact(path, "vdex");
+        std::string art = GetSecondaryDexArtifact(path, "art");
         ASSERT_EQ(expected_access, access(odex.c_str(), F_OK));
         ASSERT_EQ(expected_access, access(vdex.c_str(), F_OK));
         ASSERT_EQ(-1, access(art.c_str(), R_OK));  // empty profiles do not generate an image.
     }
+
+    void CheckFileAccess(const std::string& file, uid_t uid, gid_t gid, mode_t mode) {
+        struct stat st;
+        ASSERT_EQ(0, stat(file.c_str(), &st));
+        ASSERT_EQ(uid, st.st_uid);
+        ASSERT_EQ(gid, st.st_gid);
+        ASSERT_EQ(mode, st.st_mode);
+    }
 };
 
 
 TEST_F(DexoptTest, DexoptSecondaryCe) {
     LOG(INFO) << "DexoptSecondaryCe";
-    compile_secondary_dex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+    CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
         /*binder_ok*/ true, /*compile_ok*/ true);
 }
 
 TEST_F(DexoptTest, DexoptSecondaryCeLink) {
     LOG(INFO) << "DexoptSecondaryCeLink";
-    compile_secondary_dex(secondary_dex_ce_link_, DEXOPT_STORAGE_CE,
+    CompileSecondaryDex(secondary_dex_ce_link_, DEXOPT_STORAGE_CE,
         /*binder_ok*/ true, /*compile_ok*/ true);
 }
 
 TEST_F(DexoptTest, DexoptSecondaryDe) {
     LOG(INFO) << "DexoptSecondaryDe";
-    compile_secondary_dex(secondary_dex_de_, DEXOPT_STORAGE_DE,
+    CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
         /*binder_ok*/ true, /*compile_ok*/ true);
 }
 
 TEST_F(DexoptTest, DexoptSecondaryDoesNotExist) {
     LOG(INFO) << "DexoptSecondaryDoesNotExist";
     // If the file validates but does not exist we do not treat it as an error.
-    compile_secondary_dex(secondary_dex_ce_ + "not.there", DEXOPT_STORAGE_CE,
+    CompileSecondaryDex(secondary_dex_ce_ + "not.there", DEXOPT_STORAGE_CE,
         /*binder_ok*/ true,  /*compile_ok*/ false);
 }
 
 TEST_F(DexoptTest, DexoptSecondaryStorageValidationError) {
     LOG(INFO) << "DexoptSecondaryStorageValidationError";
-    compile_secondary_dex(secondary_dex_ce_, DEXOPT_STORAGE_DE,
+    CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_DE,
         /*binder_ok*/ false,  /*compile_ok*/ false);
 }
 
 TEST_F(DexoptTest, DexoptSecondaryAppOwnershipValidationError) {
     LOG(INFO) << "DexoptSecondaryAppOwnershipValidationError";
-    compile_secondary_dex("/data/data/random.app/secondary.jar", DEXOPT_STORAGE_CE,
+    CompileSecondaryDex("/data/data/random.app/secondary.jar", DEXOPT_STORAGE_CE,
         /*binder_ok*/ false,  /*compile_ok*/ false);
 }
 
 TEST_F(DexoptTest, DexoptSecondaryAcessViaDifferentUidError) {
     LOG(INFO) << "DexoptSecondaryAcessViaDifferentUidError";
-    compile_secondary_dex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+    CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
         /*binder_ok*/ false,  /*compile_ok*/ false, kSystemUid);
 }
 
@@ -300,9 +368,9 @@
 class ReconcileTest : public DexoptTest {
     virtual void SetUp() {
         DexoptTest::SetUp();
-        compile_secondary_dex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+        CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
             /*binder_ok*/ true, /*compile_ok*/ true);
-        compile_secondary_dex(secondary_dex_de_, DEXOPT_STORAGE_DE,
+        CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
             /*binder_ok*/ true, /*compile_ok*/ true);
     }
 };
@@ -355,5 +423,191 @@
         /*binder_ok*/ true, /*dex_ok */ false, /*odex_deleted*/ false, kSystemUid);
 }
 
+class ProfileTest : public DexoptTest {
+  protected:
+    std::string cur_profile_;
+    std::string ref_profile_;
+    std::string snap_profile_;
+
+    virtual void SetUp() {
+        DexoptTest::SetUp();
+        cur_profile_ = create_current_profile_path(
+                kTestUserId, package_name_, /*is_secondary_dex*/ false);
+        ref_profile_ = create_reference_profile_path(package_name_, /*is_secondary_dex*/ false);
+        snap_profile_ = create_snapshot_profile_path(package_name_, "base.jar");
+    }
+
+    void SetupProfile(const std::string& path, uid_t uid, gid_t gid, mode_t mode, int32_t seed) {
+        run_cmd("profman --generate-test-profile-seed=" + std::to_string(seed) +
+                " --generate-test-profile-num-dex=2 --generate-test-profile=" + path);
+        ::chmod(path.c_str(), mode);
+        ::chown(path.c_str(), uid, gid);
+    }
+
+    void SetupProfiles(bool setup_ref) {
+        SetupProfile(cur_profile_, kTestAppUid, kTestAppGid, 0600, 1);
+        if (setup_ref) {
+            SetupProfile(ref_profile_, kTestAppUid, kTestAppGid, 0060, 2);
+        }
+    }
+
+    void SnapshotProfile(int32_t appid, const std::string& package_name, bool expected_result) {
+        bool result;
+        binder::Status binder_result = service_->snapshotProfile(
+                appid, package_name, "base.jar", &result);
+        ASSERT_TRUE(binder_result.isOk());
+        ASSERT_EQ(expected_result, result);
+
+        if (!expected_result) {
+            // Do not check the files if we expect to fail.
+            return;
+        }
+
+        // Check that the snapshot was created witht he expected acess flags.
+        CheckFileAccess(snap_profile_, kSystemUid, kSystemGid, 0600 | S_IFREG);
+
+        // The snapshot should be equivalent to the merge of profiles.
+        std::string expected_profile_content = snap_profile_ + ".expected";
+        run_cmd("rm -f " + expected_profile_content);
+        run_cmd("touch " + expected_profile_content);
+        run_cmd("profman --profile-file=" + cur_profile_ +
+                " --profile-file=" + ref_profile_ +
+                " --reference-profile-file=" + expected_profile_content);
+
+        ASSERT_TRUE(AreFilesEqual(expected_profile_content, snap_profile_));
+
+        pid_t pid = fork();
+        if (pid == 0) {
+            /* child */
+            TransitionToSystemServer();
+
+            // System server should be able to open the the spanshot.
+            unique_fd fd(open(snap_profile_.c_str(), O_RDONLY));
+            ASSERT_TRUE(fd > -1) << "Failed to open profile as kSystemUid: " << strerror(errno);
+            _exit(0);
+        }
+        /* parent */
+        ASSERT_TRUE(WIFEXITED(wait_child(pid)));
+    }
+
+  private:
+    void TransitionToSystemServer() {
+        ASSERT_TRUE(DropCapabilities(kSystemUid, kSystemGid));
+        int32_t res = selinux_android_setcontext(
+                kSystemUid, true, se_info_.c_str(), "system_server");
+        ASSERT_EQ(0, res) << "Failed to setcon " << strerror(errno);
+    }
+
+    bool AreFilesEqual(const std::string& file1, const std::string& file2) {
+        std::vector<uint8_t> content1;
+        std::vector<uint8_t> content2;
+
+        if (!ReadAll(file1, &content1)) return false;
+        if (!ReadAll(file2, &content2)) return false;
+        return content1 == content2;
+    }
+
+    bool ReadAll(const std::string& file, std::vector<uint8_t>* content) {
+        unique_fd fd(open(file.c_str(), O_RDONLY));
+        if (fd < 0) {
+            PLOG(ERROR) << "Failed to open " << file;
+            return false;
+        }
+        struct stat st;
+        if (fstat(fd, &st) != 0) {
+            PLOG(ERROR) << "Failed to stat " << file;
+            return false;
+        }
+        content->resize(st.st_size);
+        bool result = ReadFully(fd, content->data(), content->size());
+        if (!result) {
+            PLOG(ERROR) << "Failed to read " << file;
+        }
+        return result;
+    }
+};
+
+TEST_F(ProfileTest, ProfileSnapshotOk) {
+    LOG(INFO) << "ProfileSnapshotOk";
+
+    SetupProfiles(/*setup_ref*/ true);
+    SnapshotProfile(kTestAppId, package_name_, /*expected_result*/ true);
+}
+
+// The reference profile is created on the fly. We need to be able to
+// snapshot without one.
+TEST_F(ProfileTest, ProfileSnapshotOkNoReference) {
+    LOG(INFO) << "ProfileSnapshotOkNoReference";
+
+    SetupProfiles(/*setup_ref*/ false);
+    SnapshotProfile(kTestAppId, package_name_, /*expected_result*/ true);
+}
+
+TEST_F(ProfileTest, ProfileSnapshotFailWrongPackage) {
+    LOG(INFO) << "ProfileSnapshotFailWrongPackage";
+
+    SetupProfiles(/*setup_ref*/ true);
+    SnapshotProfile(kTestAppId, "not.there", /*expected_result*/ false);
+}
+
+TEST_F(ProfileTest, ProfileSnapshotDestroySnapshot) {
+    LOG(INFO) << "ProfileSnapshotDestroySnapshot";
+
+    SetupProfiles(/*setup_ref*/ true);
+    SnapshotProfile(kTestAppId, package_name_, /*expected_result*/ true);
+
+    binder::Status binder_result = service_->destroyProfileSnapshot(package_name_, "base.jar");
+    ASSERT_TRUE(binder_result.isOk());
+    struct stat st;
+    ASSERT_EQ(-1, stat(snap_profile_.c_str(), &st));
+    ASSERT_EQ(ENOENT, errno);
+}
+
+TEST_F(ProfileTest, ProfileDirOk) {
+    LOG(INFO) << "ProfileDirOk";
+
+    std::string cur_profile_dir = create_primary_current_profile_package_dir_path(
+            kTestUserId, package_name_);
+    std::string cur_profile_file = create_current_profile_path(kTestUserId, package_name_,
+            /*is_secondary_dex*/false);
+    std::string ref_profile_dir = create_primary_reference_profile_package_dir_path(package_name_);
+
+    CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
+    CheckFileAccess(cur_profile_file, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
+    CheckFileAccess(ref_profile_dir, kSystemUid, kTestAppGid, 0770 | S_IFDIR);
+}
+
+// Verify that the profile directories are fixed up during an upgrade.
+// (The reference profile directory is prepared lazily).
+TEST_F(ProfileTest, ProfileDirOkAfterFixup) {
+    LOG(INFO) << "ProfileDirOkAfterFixup";
+
+    std::string cur_profile_dir = create_primary_current_profile_package_dir_path(
+            kTestUserId, package_name_);
+    std::string cur_profile_file = create_current_profile_path(kTestUserId, package_name_,
+            /*is_secondary_dex*/false);
+    std::string ref_profile_dir = create_primary_reference_profile_package_dir_path(package_name_);
+
+    // Simulate a pre-P setup by changing the owner to kTestAppGid and permissions to 0700.
+    ASSERT_EQ(0, chown(ref_profile_dir.c_str(), kTestAppGid, kTestAppGid));
+    ASSERT_EQ(0, chmod(ref_profile_dir.c_str(), 0700));
+
+    // Run createAppData again which will offer to fix-up the profile directories.
+    ASSERT_TRUE(service_->createAppData(
+            volume_uuid_,
+            package_name_,
+            kTestUserId,
+            kAppDataFlags,
+            kTestAppUid,
+            se_info_,
+            kOSdkVersion,
+            &ce_data_inode_).isOk());
+
+    // Check the file access.
+    CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
+    CheckFileAccess(cur_profile_file, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
+    CheckFileAccess(ref_profile_dir, kSystemUid, kTestAppGid, 0770 | S_IFDIR);
+}
+
 }  // namespace installd
 }  // namespace android
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index a6a4451..49da85d 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -350,6 +350,12 @@
             create_reference_profile_path("com.example", /*is_secondary*/false));
 }
 
+TEST_F(UtilsTest, CreateProfileSnapshot) {
+    std::string expected =
+        create_primary_reference_profile_package_dir_path("com.example") + "/primary.prof.snapshot";
+    EXPECT_EQ(expected, create_snapshot_profile_path("com.example", "base.apk"));
+}
+
 TEST_F(UtilsTest, CreateSecondaryCurrentProfile) {
     EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.cur.prof",
             create_current_profile_path(/*user*/0,
diff --git a/cmds/installd/tests/test_utils.h b/cmds/installd/tests/test_utils.h
index 7d1162e..b8785c6 100644
--- a/cmds/installd/tests/test_utils.h
+++ b/cmds/installd/tests/test_utils.h
@@ -1,6 +1,9 @@
-#include <android-base/logging.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/capability.h>
+
+#include <android-base/logging.h>
+#include <selinux/android.h>
 
 uint8_t kBase64Map[256] = {
     255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
@@ -105,3 +108,27 @@
     }
     return true;
 }
+
+// TODO(calin): fix dexopt drop_capabilities and move to general utils (b/69678790).
+bool DropCapabilities(uid_t uid, gid_t gid) {
+    if (setgid(gid) != 0) {
+        PLOG(ERROR) << "setgid failed: " <<  gid;
+        return false;
+    }
+    if (setuid(uid) != 0) {
+        PLOG(ERROR) << "setuid failed: " <<  uid;
+        return false;
+    }
+    // drop capabilities
+    struct __user_cap_header_struct capheader;
+    struct __user_cap_data_struct capdata[2];
+    memset(&capheader, 0, sizeof(capheader));
+    memset(&capdata, 0, sizeof(capdata));
+    capheader.version = _LINUX_CAPABILITY_VERSION_3;
+    if (capset(&capheader, &capdata[0]) < 0) {
+        PLOG(ERROR) << "capset failed";
+        return false;
+    }
+
+    return true;
+}
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 7dca7c6..61c9c8f 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -236,6 +236,7 @@
 const std::string PROFILE_EXT = ".prof";
 const std::string CURRENT_PROFILE_EXT = ".cur";
 const std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT;
+const std::string SNAPSHOT_PROFILE_EXT = ".snapshot";
 
 // Gets the parent directory and the file name for the given secondary dex path.
 // Returns true on success, false on failure (if the dex_path does not have the expected
@@ -289,6 +290,14 @@
     }
 }
 
+std::string create_snapshot_profile_path(const std::string& package,
+        const std::string& code_path ATTRIBUTE_UNUSED) {
+    // TODD(calin): code_path is ignored for now. It will be used when each split gets its own
+    // profile file.
+    std::string ref_profile = create_reference_profile_path(package, /*is_secondary_dex*/ false);
+    return ref_profile + SNAPSHOT_PROFILE_EXT;
+}
+
 std::vector<userid_t> get_known_users(const char* volume_uuid) {
     std::vector<userid_t> users;
 
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index b90caf9..5391061 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -83,6 +83,7 @@
         userid_t user, const std::string& package_name, bool is_secondary_dex);
 std::string create_reference_profile_path(
         const std::string& package_name, bool is_secondary_dex);
+std::string create_snapshot_profile_path(const std::string& package, const std::string& code_path);
 
 std::vector<userid_t> get_known_users(const char* volume_uuid);
 
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 973302c..c21c5e3 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -124,12 +124,13 @@
 
     virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
                                    const sp<IGraphicBufferProducer>& producer,
-                                   ISurfaceComposer::Rotation rotation) {
+                                   const Rect& sourceCrop, float frameScale) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(layerHandleBinder);
         data.writeStrongBinder(IInterface::asBinder(producer));
-        data.writeInt32(static_cast<int32_t>(rotation));
+        data.write(sourceCrop);
+        data.writeFloat(frameScale);
         remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply);
         return reply.readInt32();
     }
@@ -605,10 +606,11 @@
             sp<IBinder> layerHandleBinder = data.readStrongBinder();
             sp<IGraphicBufferProducer> producer =
                     interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
-            int32_t rotation = data.readInt32();
+            Rect sourceCrop(Rect::EMPTY_RECT);
+            data.read(sourceCrop);
+            float frameScale = data.readFloat();
 
-            status_t res = captureLayers(layerHandleBinder, producer,
-                                         static_cast<ISurfaceComposer::Rotation>(rotation));
+            status_t res = captureLayers(layerHandleBinder, producer, sourceCrop, frameScale);
             reply->writeInt32(res);
             return NO_ERROR;
         }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 2adc273..2466d25 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -757,11 +757,34 @@
 
 status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
                                          const sp<IGraphicBufferProducer>& producer,
-                                         uint32_t rotation) {
+                                         Rect sourceCrop, float frameScale) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == NULL) return NO_INIT;
-    return s->captureLayers(layerHandle, producer,
-                            static_cast<ISurfaceComposer::Rotation>(rotation));
+    return s->captureLayers(layerHandle, producer, sourceCrop, frameScale);
+}
+
+status_t ScreenshotClient::captureLayersToBuffer(const sp<IBinder>& layerHandle, Rect sourceCrop,
+                                                 float frameScale, sp<GraphicBuffer>* outBuffer) {
+    sp<ISurfaceComposer> s(ComposerService::getComposerService());
+    if (s == NULL) return NO_INIT;
+
+    sp<IGraphicBufferConsumer> gbpConsumer;
+    sp<IGraphicBufferProducer> producer;
+    BufferQueue::createBufferQueue(&producer, &gbpConsumer);
+    sp<BufferItemConsumer> consumer(new BufferItemConsumer(gbpConsumer,
+                                                           GRALLOC_USAGE_HW_TEXTURE |
+                                                                   GRALLOC_USAGE_SW_READ_NEVER |
+                                                                   GRALLOC_USAGE_SW_WRITE_NEVER,
+                                                           1, true));
+
+    status_t ret = s->captureLayers(layerHandle, producer, sourceCrop, frameScale);
+    if (ret != NO_ERROR) {
+        return ret;
+    }
+    BufferItem b;
+    consumer->acquireBuffer(&b, 0, true);
+    *outBuffer = b.mGraphicBuffer;
+    return ret;
 }
 
 ScreenshotClient::ScreenshotClient()
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index e9fc8fd..4a86021 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -187,7 +187,7 @@
     // ConsumerBase::releaseBufferLocked.
     virtual status_t releaseBufferLocked(int slot,
             const sp<GraphicBuffer> graphicBuffer,
-            EGLDisplay display, EGLSyncKHR eglFence);
+            EGLDisplay display = EGL_NO_DISPLAY, EGLSyncKHR eglFence = EGL_NO_SYNC_KHR);
 
     // returns true iff the slot still has the graphicBuffer in it.
     bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 13e7473..1e4c329 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -176,7 +176,7 @@
 
     virtual status_t captureLayers(const sp<IBinder>& layerHandleBinder,
                                    const sp<IGraphicBufferProducer>& producer,
-                                   Rotation rotation = eRotateNone) = 0;
+                                   const Rect& sourceCrop, float frameScale = 1.0) = 0;
 
     /* Clears the frame statistics for animations.
      *
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 87fdfae..b0fa922 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -297,8 +297,12 @@
             bool useIdentityTransform,
             uint32_t rotation,
             sp<GraphicBuffer>* outbuffer);
+
     static status_t captureLayers(const sp<IBinder>& layerHandle,
-                                  const sp<IGraphicBufferProducer>& producer, uint32_t rotation);
+                                  const sp<IGraphicBufferProducer>& producer, Rect sourceCrop,
+                                        float frameScale);
+    static status_t captureLayersToBuffer(const sp<IBinder>& layerHandle, Rect sourceCrop,
+                                          float frameScale, sp<GraphicBuffer>* outBuffer);
 
 private:
     mutable sp<CpuConsumer> mCpuConsumer;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 660680b..ac4eb0c 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -531,7 +531,7 @@
             Rotation /*rotation*/) override { return NO_ERROR; }
     virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
                                    const sp<IGraphicBufferProducer>& /*producer*/,
-                                   ISurfaceComposer::Rotation /*rotation*/) override {
+                                   const Rect& /*sourceCrop*/, float /*frameScale*/) override {
         return NO_ERROR;
     }
     status_t clearAnimationFrameStats() override { return NO_ERROR; }
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index ecee8ce..deead06 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -41,6 +41,7 @@
     RenderEngine/ProgramCache.cpp \
     RenderEngine/GLExtensions.cpp \
     RenderEngine/RenderEngine.cpp \
+    RenderEngine/Surface.cpp \
     RenderEngine/Texture.cpp \
     RenderEngine/GLES20RenderEngine.cpp \
     LayerProtoHelper.cpp \
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 2fa17e9..0d947b1 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -109,13 +109,14 @@
 }
 
 bool BufferLayer::isProtected() const {
-    const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
-    return (activeBuffer != 0) && (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+    const sp<GraphicBuffer>& buffer(getBE().mBuffer);
+    return (buffer != 0) &&
+            (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
 }
 
 bool BufferLayer::isVisible() const {
     return !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
-            (mActiveBuffer != NULL || getBE().mSidebandStream != NULL);
+            (getBE().mBuffer != NULL || getBE().mSidebandStream != NULL);
 }
 
 bool BufferLayer::isFixedSize() const {
@@ -171,7 +172,7 @@
                          bool useIdentityTransform) const {
     ATRACE_CALL();
 
-    if (CC_UNLIKELY(mActiveBuffer == 0)) {
+    if (CC_UNLIKELY(getBE().mBuffer == 0)) {
         // the texture has not been created yet, this Layer has
         // in fact never been drawn into. This happens frequently with
         // SurfaceView because the WindowManager can't know when the client
@@ -249,8 +250,8 @@
         }
 
         // Set things up for texturing.
-        mTexture.setDimensions(mActiveBuffer->getWidth(),
-                               mActiveBuffer->getHeight());
+        mTexture.setDimensions(getBE().mBuffer->getWidth(),
+                               getBE().mBuffer->getHeight());
         mTexture.setFiltering(useFiltering);
         mTexture.setMatrix(textureMatrix);
 
@@ -421,7 +422,7 @@
     // Capture the old state of the layer for comparisons later
     const State& s(getDrawingState());
     const bool oldOpacity = isOpaque(s);
-    sp<GraphicBuffer> oldActiveBuffer = mActiveBuffer;
+    sp<GraphicBuffer> oldBuffer = getBE().mBuffer;
 
     if (!allTransactionsSignaled()) {
         mFlinger->signalLayerUpdate();
@@ -498,9 +499,11 @@
     }
 
     // update the active buffer
-    mActiveBuffer =
-            mSurfaceFlingerConsumer->getCurrentBuffer(&mActiveBufferSlot);
-    if (mActiveBuffer == NULL) {
+    getBE().mBuffer =
+            mSurfaceFlingerConsumer->getCurrentBuffer(&getBE().mBufferSlot);
+    // replicated in LayerBE until FE/BE is ready to be synchronized
+    mActiveBuffer = getBE().mBuffer;
+    if (getBE().mBuffer == NULL) {
         // this can only happen if the very first buffer was rejected.
         return outDirtyRegion;
     }
@@ -516,7 +519,7 @@
 
     mRefreshPending = true;
     mFrameLatencyNeeded = true;
-    if (oldActiveBuffer == NULL) {
+    if (oldBuffer == NULL) {
         // the first time we receive a buffer, we need to trigger a
         // geometry invalidation.
         recomputeVisibleRegions = true;
@@ -536,16 +539,16 @@
         recomputeVisibleRegions = true;
     }
 
-    if (oldActiveBuffer != NULL) {
-        uint32_t bufWidth = mActiveBuffer->getWidth();
-        uint32_t bufHeight = mActiveBuffer->getHeight();
-        if (bufWidth != uint32_t(oldActiveBuffer->width) ||
-            bufHeight != uint32_t(oldActiveBuffer->height)) {
+    if (oldBuffer != NULL) {
+        uint32_t bufWidth = getBE().mBuffer->getWidth();
+        uint32_t bufHeight = getBE().mBuffer->getHeight();
+        if (bufWidth != uint32_t(oldBuffer->width) ||
+            bufHeight != uint32_t(oldBuffer->height)) {
             recomputeVisibleRegions = true;
         }
     }
 
-    mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
+    mCurrentOpacity = getOpacityForFormat(getBE().mBuffer->format);
     if (oldOpacity != isOpaque(s)) {
         recomputeVisibleRegions = true;
     }
@@ -638,14 +641,14 @@
 
     uint32_t hwcSlot = 0;
     sp<GraphicBuffer> hwcBuffer;
-    hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot,
-                                     mActiveBuffer, &hwcSlot, &hwcBuffer);
+    hwcInfo.bufferCache.getHwcBuffer(getBE().mBufferSlot,
+                                     getBE().mBuffer, &hwcSlot, &hwcBuffer);
 
     auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence();
     error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
-              mActiveBuffer->handle, to_string(error).c_str(),
+              getBE().mBuffer->handle, to_string(error).c_str(),
               static_cast<int32_t>(error));
     }
 }
@@ -653,7 +656,7 @@
 bool BufferLayer::isOpaque(const Layer::State& s) const {
     // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
     // layer's opaque flag.
-    if ((getBE().mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
+    if ((getBE().mSidebandStream == nullptr) && (getBE().mBuffer == nullptr)) {
         return false;
     }
 
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 078302b..1127952 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -32,9 +32,6 @@
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/LayerState.h>
 
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
 #include <ui/FrameStats.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 6d6781e..2753f11 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -53,12 +53,6 @@
 using namespace android;
 // ----------------------------------------------------------------------------
 
-#ifdef EGL_ANDROID_swap_rectangle
-static constexpr bool kEGLAndroidSwapRectangle = true;
-#else
-static constexpr bool kEGLAndroidSwapRectangle = false;
-#endif
-
 // retrieve triple buffer setting from configstore
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
@@ -66,12 +60,6 @@
 static bool useTripleFramebuffer = getInt64< ISurfaceFlingerConfigs,
         &ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2) >= 3;
 
-#if !defined(EGL_EGLEXT_PROTOTYPES) || !defined(EGL_ANDROID_swap_rectangle)
-// Dummy implementation in case it is missing.
-inline void eglSetSwapRectangleANDROID (EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint) {
-}
-#endif
-
 /*
  * Initialize the display to the specified values.
  *
@@ -88,7 +76,6 @@
         const wp<IBinder>& displayToken,
         const sp<DisplaySurface>& displaySurface,
         const sp<IGraphicBufferProducer>& producer,
-        EGLConfig config,
         bool supportWideColor)
     : lastCompositionHadVisibleLayers(false),
       mFlinger(flinger),
@@ -96,11 +83,9 @@
       mHwcDisplayId(hwcId),
       mDisplayToken(displayToken),
       mDisplaySurface(displaySurface),
-      mDisplay(EGL_NO_DISPLAY),
-      mSurface(EGL_NO_SURFACE),
+      mSurface{flinger->getRenderEngine()},
       mDisplayWidth(),
       mDisplayHeight(),
-      mFlags(),
       mPageFlipCount(),
       mIsSecure(isSecure),
       mLayerStack(NO_LAYER_STACK),
@@ -118,16 +103,11 @@
     /*
      * Create our display's surface
      */
-
-    EGLSurface eglSurface;
-    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    if (config == EGL_NO_CONFIG) {
-        config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888,
-                                               /*logConfig*/ false);
-    }
-    eglSurface = eglCreateWindowSurface(display, config, window, NULL);
-    eglQuerySurface(display, eglSurface, EGL_WIDTH,  &mDisplayWidth);
-    eglQuerySurface(display, eglSurface, EGL_HEIGHT, &mDisplayHeight);
+    mSurface.setCritical(mType == DisplayDevice::DISPLAY_PRIMARY);
+    mSurface.setAsync(mType >= DisplayDevice::DISPLAY_VIRTUAL);
+    mSurface.setNativeWindow(window);
+    mDisplayWidth = mSurface.queryWidth();
+    mDisplayHeight = mSurface.queryHeight();
 
     // Make sure that composition can never be stalled by a virtual display
     // consumer that isn't processing buffers fast enough. We have to do this
@@ -139,9 +119,6 @@
     if (mType >= DisplayDevice::DISPLAY_VIRTUAL)
         window->setSwapInterval(window, 0);
 
-    mConfig = config;
-    mDisplay = display;
-    mSurface = eglSurface;
     mPageFlipCount = 0;
     mViewport.makeInvalid();
     mFrame.makeInvalid();
@@ -173,10 +150,6 @@
 }
 
 DisplayDevice::~DisplayDevice() {
-    if (mSurface != EGL_NO_SURFACE) {
-        eglDestroySurface(mDisplay, mSurface);
-        mSurface = EGL_NO_SURFACE;
-    }
 }
 
 void DisplayDevice::disconnect(HWComposer& hwc) {
@@ -198,10 +171,6 @@
     return mDisplayHeight;
 }
 
-EGLSurface DisplayDevice::getEGLSurface() const {
-    return mSurface;
-}
-
 void DisplayDevice::setDisplayName(const String8& displayName) {
     if (!displayName.isEmpty()) {
         // never override the name with an empty name
@@ -213,19 +182,9 @@
     return mPageFlipCount;
 }
 
-void DisplayDevice::flip(const Region& dirty) const
+void DisplayDevice::flip() const
 {
     mFlinger->getRenderEngine().checkErrors();
-
-    if (kEGLAndroidSwapRectangle) {
-        if (mFlags & SWAP_RECTANGLE) {
-            const Region newDirty(dirty.intersect(bounds()));
-            const Rect b(newDirty.getBounds());
-            eglSetSwapRectangleANDROID(mDisplay, mSurface,
-                    b.left, b.top, b.width(), b.height());
-        }
-    }
-
     mPageFlipCount++;
 }
 
@@ -259,18 +218,7 @@
 
 void DisplayDevice::swapBuffers(HWComposer& hwc) const {
     if (hwc.hasClientComposition(mHwcDisplayId)) {
-        EGLBoolean success = eglSwapBuffers(mDisplay, mSurface);
-        if (!success) {
-            EGLint error = eglGetError();
-            if (error == EGL_CONTEXT_LOST ||
-                    mType == DisplayDevice::DISPLAY_PRIMARY) {
-                LOG_ALWAYS_FATAL("eglSwapBuffers(%p, %p) failed with 0x%08x",
-                        mDisplay, mSurface, error);
-            } else {
-                ALOGE("eglSwapBuffers(%p, %p) failed with 0x%08x",
-                        mDisplay, mSurface, error);
-            }
-        }
+        mSurface.swapBuffers();
     }
 
     status_t result = mDisplaySurface->advanceFrame();
@@ -284,23 +232,10 @@
     mDisplaySurface->onFrameCommitted();
 }
 
-uint32_t DisplayDevice::getFlags() const
-{
-    return mFlags;
-}
-
-EGLBoolean DisplayDevice::makeCurrent(EGLDisplay dpy, EGLContext ctx) const {
-    EGLBoolean result = EGL_TRUE;
-    EGLSurface sur = eglGetCurrentSurface(EGL_DRAW);
-    if (sur != mSurface) {
-        result = eglMakeCurrent(dpy, mSurface, mSurface, ctx);
-        if (result == EGL_TRUE) {
-            if (mType >= DisplayDevice::DISPLAY_VIRTUAL)
-                eglSwapInterval(dpy, 0);
-        }
-    }
+bool DisplayDevice::makeCurrent() const {
+    bool success = mFlinger->getRenderEngine().setCurrentSurface(mSurface);
     setViewportAndProjection();
-    return result;
+    return success;
 }
 
 void DisplayDevice::setViewportAndProjection() const {
@@ -436,17 +371,14 @@
 void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
     dirtyRegion.set(getBounds());
 
-    if (mSurface != EGL_NO_SURFACE) {
-        eglDestroySurface(mDisplay, mSurface);
-        mSurface = EGL_NO_SURFACE;
-    }
+    mSurface.setNativeWindow(nullptr);
 
     mDisplaySurface->resizeBuffers(newWidth, newHeight);
 
     ANativeWindow* const window = mNativeWindow.get();
-    mSurface = eglCreateWindowSurface(mDisplay, mConfig, window, NULL);
-    eglQuerySurface(mDisplay, mSurface, EGL_WIDTH,  &mDisplayWidth);
-    eglQuerySurface(mDisplay, mSurface, EGL_HEIGHT, &mDisplayHeight);
+    mSurface.setNativeWindow(window);
+    mDisplayWidth = mSurface.queryWidth();
+    mDisplayHeight = mSurface.queryHeight();
 
     LOG_FATAL_IF(mDisplayWidth != newWidth,
                 "Unable to set new width to %d", newWidth);
@@ -548,17 +480,13 @@
 void DisplayDevice::dump(String8& result) const {
     const Transform& tr(mGlobalTransform);
     ANativeWindow* const window = mNativeWindow.get();
-    EGLint redSize, greenSize, blueSize, alphaSize;
-    eglGetConfigAttrib(mDisplay, mConfig, EGL_RED_SIZE, &redSize);
-    eglGetConfigAttrib(mDisplay, mConfig, EGL_GREEN_SIZE, &greenSize);
-    eglGetConfigAttrib(mDisplay, mConfig, EGL_BLUE_SIZE, &blueSize);
-    eglGetConfigAttrib(mDisplay, mConfig, EGL_ALPHA_SIZE, &alphaSize);
     result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.string());
     result.appendFormat("   type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
                         "(%d:%d:%d:%d), orient=%2d (type=%08x), "
                         "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n",
                         mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, window,
-                        redSize, greenSize, blueSize, alphaSize, mOrientation, tr.getType(),
+                        mSurface.queryRedSize(), mSurface.queryGreenSize(), mSurface.queryBlueSize(),
+                        mSurface.queryAlphaSize(), mOrientation, tr.getType(),
                         getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
                         mVisibleLayersSortedByZ.size());
     result.appendFormat("   v:[%d,%d,%d,%d], f:[%d,%d,%d,%d], s:[%d,%d,%d,%d],"
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e388a5b..499bf8e 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -23,9 +23,6 @@
 
 #include <ui/Region.h>
 
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
 #include <binder/IBinder.h>
 #include <utils/RefBase.h>
 #include <utils/Mutex.h>
@@ -35,6 +32,7 @@
 #include <gui/ISurfaceComposer.h>
 #include <hardware/hwcomposer_defs.h>
 #include "RenderArea.h"
+#include "RenderEngine/Surface.h"
 
 #include <memory>
 
@@ -56,8 +54,6 @@
     // region in layer-stack space
     mutable Region dirtyRegion;
     // region in screen space
-    mutable Region swapRegion;
-    // region in screen space
     Region undefinedRegion;
     bool lastCompositionHadVisibleLayers;
 
@@ -70,11 +66,6 @@
     };
 
     enum {
-        PARTIAL_UPDATES = 0x00020000, // video driver feature
-        SWAP_RECTANGLE  = 0x00080000,
-    };
-
-    enum {
         NO_LAYER_STACK = 0xFFFFFFFF,
     };
 
@@ -87,7 +78,6 @@
             const wp<IBinder>& displayToken,
             const sp<DisplaySurface>& displaySurface,
             const sp<IGraphicBufferProducer>& producer,
-            EGLConfig config,
             bool supportWideColor);
     // clang-format on
 
@@ -103,13 +93,10 @@
 
     // Flip the front and back buffers if the back buffer is "dirty".  Might
     // be instantaneous, might involve copying the frame buffer around.
-    void flip(const Region& dirty) const;
+    void flip() const;
 
     int         getWidth() const;
     int         getHeight() const;
-    uint32_t    getFlags() const;
-
-    EGLSurface  getEGLSurface() const;
 
     void                    setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
     const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
@@ -155,7 +142,7 @@
     void setDisplayName(const String8& displayName);
     const String8& getDisplayName() const { return mDisplayName; }
 
-    EGLBoolean makeCurrent(EGLDisplay dpy, EGLContext ctx) const;
+    bool makeCurrent() const;
     void setViewportAndProjection() const;
 
     const sp<Fence>& getClientTargetAcquireFence() const;
@@ -199,12 +186,9 @@
     sp<ANativeWindow> mNativeWindow;
     sp<DisplaySurface> mDisplaySurface;
 
-    EGLConfig       mConfig;
-    EGLDisplay      mDisplay;
-    EGLSurface      mSurface;
+    RE::Surface     mSurface;
     int             mDisplayWidth;
     int             mDisplayHeight;
-    uint32_t        mFlags;
     mutable uint32_t mPageFlipCount;
     String8         mDisplayName;
     bool            mIsSecure;
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 182629c..8b5d4c9 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -27,8 +27,6 @@
 #include <utils/String8.h>
 #include <log/log.h>
 
-#include <EGL/egl.h>
-
 #include <hardware/hardware.h>
 #include <gui/BufferItem.h>
 #include <gui/BufferQueue.h>
@@ -164,8 +162,7 @@
             ALOGE_IF(result != NO_ERROR, "onFrameCommitted: failed to add the"
                     " fence: %s (%d)", strerror(-result), result);
         }
-        status_t result = releaseBufferLocked(mPreviousBufferSlot,
-                mPreviousBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+        status_t result = releaseBufferLocked(mPreviousBufferSlot, mPreviousBuffer);
         ALOGE_IF(result != NO_ERROR, "onFrameCommitted: error releasing buffer:"
                 " %s (%d)", strerror(-result), result);
 
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index dba6f7c..cde96e4 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -244,8 +244,7 @@
         VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot);
         addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot],
                 retireFence);
-        releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot],
-                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+        releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot]);
     }
 
     if (mOutputProducerSlot >= 0) {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 359b64f..2a4abcb 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -63,7 +63,9 @@
 namespace android {
 
 LayerBE::LayerBE()
-      : mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2) {
+      : mBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
+        mBuffer(nullptr),
+        mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2) {
 }
 
 
@@ -255,9 +257,9 @@
     if (!mCurrentCrop.isEmpty()) {
         // if the buffer crop is defined, we use that
         crop = mCurrentCrop;
-    } else if (mActiveBuffer != NULL) {
+    } else if (getBE().mBuffer != NULL) {
         // otherwise we use the whole buffer
-        crop = mActiveBuffer->getBounds();
+        crop = getBE().mBuffer->getBounds();
     } else {
         // if we don't have a buffer yet, we use an empty/invalid crop
         crop.makeInvalid();
@@ -1000,7 +1002,7 @@
     // to the old buffer. However in the state where we don't have an old buffer
     // there is no such concern but we may still be being used as a parent layer.
     const bool resizePending = ((c.requested.w != c.active.w) || (c.requested.h != c.active.h)) &&
-            (mActiveBuffer != nullptr);
+            (getBE().mBuffer != nullptr);
     if (!isFixedSize()) {
         if (resizePending && getBE().mSidebandStream == NULL) {
             flags |= eDontUpdateGeometryState;
@@ -1399,12 +1401,12 @@
     info.mMatrix[1][0] = ds.active.transform[1][0];
     info.mMatrix[1][1] = ds.active.transform[1][1];
     {
-        sp<const GraphicBuffer> activeBuffer = getActiveBuffer();
-        if (activeBuffer != 0) {
-            info.mActiveBufferWidth = activeBuffer->getWidth();
-            info.mActiveBufferHeight = activeBuffer->getHeight();
-            info.mActiveBufferStride = activeBuffer->getStride();
-            info.mActiveBufferFormat = activeBuffer->format;
+        sp<const GraphicBuffer> buffer = getBE().mBuffer;
+        if (buffer != 0) {
+            info.mActiveBufferWidth = buffer->getWidth();
+            info.mActiveBufferHeight = buffer->getHeight();
+            info.mActiveBufferStride = buffer->getStride();
+            info.mActiveBufferFormat = buffer->format;
         } else {
             info.mActiveBufferWidth = 0;
             info.mActiveBufferHeight = 0;
@@ -1718,15 +1720,15 @@
         // for in the transform. We need to mirror this scaling in child surfaces
         // or we will break the contract where WM can treat child surfaces as
         // pixels in the parent surface.
-        if (p->isFixedSize() && p->mActiveBuffer != nullptr) {
+        if (p->isFixedSize() && p->getBE().mBuffer != nullptr) {
             int bufferWidth;
             int bufferHeight;
             if ((p->mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
-                bufferWidth = p->mActiveBuffer->getWidth();
-                bufferHeight = p->mActiveBuffer->getHeight();
+                bufferWidth = p->getBE().mBuffer->getWidth();
+                bufferHeight = p->getBE().mBuffer->getHeight();
             } else {
-                bufferHeight = p->mActiveBuffer->getWidth();
-                bufferWidth = p->mActiveBuffer->getHeight();
+                bufferHeight = p->getBE().mBuffer->getWidth();
+                bufferWidth = p->getBE().mBuffer->getHeight();
             }
             float sx = p->getDrawingState().active.w / static_cast<float>(bufferWidth);
             float sy = p->getDrawingState().active.h / static_cast<float>(bufferHeight);
@@ -1826,9 +1828,9 @@
         layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
     }
 
-    auto activeBuffer = getActiveBuffer();
-    if (activeBuffer != nullptr) {
-        LayerProtoHelper::writeToProto(activeBuffer, layerInfo->mutable_active_buffer());
+    auto buffer = getBE().mBuffer;
+    if (buffer != nullptr) {
+        LayerProtoHelper::writeToProto(buffer, layerInfo->mutable_active_buffer());
     }
 
     layerInfo->set_queued_frames(getQueuedFrameCount());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b7b7a3a..8ac5094 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -20,9 +20,6 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 #include <utils/Timers.h>
@@ -73,6 +70,9 @@
 public:
     LayerBE();
 
+    // main thread
+    int mBufferSlot;
+    sp<GraphicBuffer> mBuffer;
     sp<NativeHandle> mSidebandStream;
 
     // The mesh used to draw the layer in GLES composition mode
@@ -472,8 +472,6 @@
     void setFiltering(bool filtering);
     bool getFiltering() const;
 
-    // only for debugging
-    inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
 
     inline const State& getDrawingState() const { return mDrawingState; }
     inline const State& getCurrentState() const { return mCurrentState; }
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 44b9dc9..fa4df83 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -6,7 +6,8 @@
 
 class RenderArea {
 public:
-    RenderArea(uint32_t reqHeight, uint32_t reqWidth, ISurfaceComposer::Rotation rotation)
+    RenderArea(uint32_t reqHeight, uint32_t reqWidth,
+               ISurfaceComposer::Rotation rotation = ISurfaceComposer::eRotateNone)
           : mReqHeight(reqHeight), mReqWidth(reqWidth) {
         mRotationFlags = Transform::fromRotation(rotation);
     }
diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp
index 706960c..e014406 100644
--- a/services/surfaceflinger/RenderEngine/Description.cpp
+++ b/services/surfaceflinger/RenderEngine/Description.cpp
@@ -33,8 +33,7 @@
     mColorMatrixEnabled = false;
 }
 
-Description::~Description() {
-}
+Description::~Description() {}
 
 void Description::setPremultipliedAlpha(bool premultipliedAlpha) {
     mPremultipliedAlpha = premultipliedAlpha;
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 3ae7042..3161888 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -33,15 +33,15 @@
 #include <gui/ISurfaceComposer.h>
 #include <math.h>
 
+#include "Description.h"
 #include "GLES20RenderEngine.h"
+#include "Mesh.h"
 #include "Program.h"
 #include "ProgramCache.h"
-#include "Description.h"
-#include "Mesh.h"
 #include "Texture.h"
 
-#include <sstream>
 #include <fstream>
+#include <sstream>
 
 // ---------------------------------------------------------------------------
 bool checkGlError(const char* op, int lineNumber) {
@@ -107,34 +107,31 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags) :
-         mVpWidth(0),
-         mVpHeight(0),
-         mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) {
-
+GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags)
+      : mVpWidth(0), mVpHeight(0), mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) {
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
 
     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
     glPixelStorei(GL_PACK_ALIGNMENT, 4);
 
-    const uint16_t protTexData[] = { 0 };
+    const uint16_t protTexData[] = {0};
     glGenTextures(1, &mProtectedTexName);
     glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0,
-            GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);
 
-    //mColorBlindnessCorrection = M;
+    // mColorBlindnessCorrection = M;
 
     if (mPlatformHasWideColor) {
         // Compute sRGB to DisplayP3 color transform
         // NOTE: For now, we are limiting wide-color support to
         // Display-P3 only.
-        mat3 srgbToP3 = ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform();
+        mat3 srgbToP3 =
+                ColorSpaceConnector(ColorSpace::sRGB(), ColorSpace::DisplayP3()).getTransform();
 
         // color transform needs to be expanded to 4x4 to be what the shader wants
         // mat has an initializer that expands mat3 to mat4, but
@@ -144,24 +141,19 @@
     }
 }
 
-GLES20RenderEngine::~GLES20RenderEngine() {
-}
-
+GLES20RenderEngine::~GLES20RenderEngine() {}
 
 size_t GLES20RenderEngine::getMaxTextureSize() const {
     return mMaxTextureSize;
 }
 
 size_t GLES20RenderEngine::getMaxViewportDims() const {
-    return
-        mMaxViewportDims[0] < mMaxViewportDims[1] ?
-            mMaxViewportDims[0] : mMaxViewportDims[1];
+    return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1];
 }
 
-void GLES20RenderEngine::setViewportAndProjection(
-        size_t vpw, size_t vph, Rect sourceCrop, size_t hwh, bool yswap,
-        Transform::orientation_flags rotation) {
-
+void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
+                                                  size_t hwh, bool yswap,
+                                                  Transform::orientation_flags rotation) {
     size_t l = sourceCrop.left;
     size_t r = sourceCrop.right;
 
@@ -182,13 +174,13 @@
         case Transform::ROT_0:
             break;
         case Transform::ROT_90:
-            m = mat4::rotate(rot90InRadians, vec3(0,0,1)) * m;
+            m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m;
             break;
         case Transform::ROT_180:
-            m = mat4::rotate(rot90InRadians * 2.0f, vec3(0,0,1)) * m;
+            m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m;
             break;
         case Transform::ROT_270:
-            m = mat4::rotate(rot90InRadians * 3.0f, vec3(0,0,1)) * m;
+            m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m;
             break;
         default:
             break;
@@ -200,8 +192,8 @@
     mVpHeight = vph;
 }
 
-void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha,
-        bool opaque, bool disableTexture, const half4& color) {
+void GLES20RenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque,
+                                            bool disableTexture, const half4& color) {
     mState.setPremultipliedAlpha(premultipliedAlpha);
     mState.setOpaque(opaque);
     mState.setColor(color);
@@ -288,9 +280,8 @@
     glDisable(GL_BLEND);
 }
 
-
-void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image,
-        uint32_t* texName, uint32_t* fbName, uint32_t* status) {
+void GLES20RenderEngine::bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName,
+                                                uint32_t* fbName, uint32_t* status) {
     GLuint tname, name;
     // turn our EGLImage into a texture
     glGenTextures(1, &tname);
@@ -322,21 +313,14 @@
 }
 
 void GLES20RenderEngine::drawMesh(const Mesh& mesh) {
-
     if (mesh.getTexCoordsSize()) {
         glEnableVertexAttribArray(Program::texCoords);
-        glVertexAttribPointer(Program::texCoords,
-                mesh.getTexCoordsSize(),
-                GL_FLOAT, GL_FALSE,
-                mesh.getByteStride(),
-                mesh.getTexCoords());
+        glVertexAttribPointer(Program::texCoords, mesh.getTexCoordsSize(), GL_FLOAT, GL_FALSE,
+                              mesh.getByteStride(), mesh.getTexCoords());
     }
 
-    glVertexAttribPointer(Program::position,
-            mesh.getVertexSize(),
-            GL_FLOAT, GL_FALSE,
-            mesh.getByteStride(),
-            mesh.getPositions());
+    glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
+                          mesh.getByteStride(), mesh.getPositions());
 
     if (usesWideColor()) {
         Description wideColorState = mState;
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index b96bfe0..5ee9326 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 #ifndef SF_GLES20RENDERENGINE_H_
 #define SF_GLES20RENDERENGINE_H_
 
@@ -24,9 +23,9 @@
 #include <GLES2/gl2.h>
 #include <Transform.h>
 
-#include "RenderEngine.h"
-#include "ProgramCache.h"
 #include "Description.h"
+#include "ProgramCache.h"
+#include "RenderEngine.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -54,22 +53,20 @@
     Description mState;
     Vector<Group> mGroupStack;
 
-    virtual void bindImageAsFramebuffer(EGLImageKHR image,
-            uint32_t* texName, uint32_t* fbName, uint32_t* status);
+    virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName,
+                                        uint32_t* status);
     virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName);
 
 public:
     GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag
-
-protected:
     virtual ~GLES20RenderEngine();
 
+protected:
     virtual void dump(String8& result);
-    virtual void setViewportAndProjection(size_t vpw, size_t vph,
-            Rect sourceCrop, size_t hwh, bool yswap,
-            Transform::orientation_flags rotation);
-    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
-            bool disableTexture, const half4& color) override;
+    virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh,
+                                          bool yswap, Transform::orientation_flags rotation);
+    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+                                    const half4& color) override;
 
     // Color management related functions and state
     void setColorMode(android_color_mode mode);
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
index 76bbcc1..7ffcc96 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.cpp
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
@@ -14,42 +14,35 @@
  * limitations under the License.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
 #include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
 
 #include "GLExtensions.h"
 
 namespace android {
 // ---------------------------------------------------------------------------
 
-ANDROID_SINGLETON_STATIC_INSTANCE( GLExtensions )
+ANDROID_SINGLETON_STATIC_INSTANCE(GLExtensions)
 
-GLExtensions::GLExtensions()
-    : mHaveFramebufferObject(false)
-{
-}
+GLExtensions::GLExtensions() : mHaveFramebufferObject(false) {}
 
-void GLExtensions::initWithGLStrings(
-        GLubyte const* vendor,
-        GLubyte const* renderer,
-        GLubyte const* version,
-        GLubyte const* extensions)
-{
-    mVendor     = (char const*)vendor;
-    mRenderer   = (char const*)renderer;
-    mVersion    = (char const*)version;
+void GLExtensions::initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer,
+                                     GLubyte const* version, GLubyte const* extensions) {
+    mVendor = (char const*)vendor;
+    mRenderer = (char const*)renderer;
+    mVersion = (char const*)version;
     mExtensions = (char const*)extensions;
 
     char const* curr = (char const*)extensions;
     char const* head = curr;
     do {
         head = strchr(curr, ' ');
-        String8 s(curr, head ? head-curr : strlen(curr));
+        String8 s(curr, head ? head - curr : strlen(curr));
         if (s.length()) {
             mExtensionList.add(s);
         }
-        curr = head+1;
+        curr = head + 1;
     } while (head);
 
     if (hasExtension("GL_OES_framebuffer_object")) {
@@ -57,8 +50,7 @@
     }
 }
 
-bool GLExtensions::hasExtension(char const* extension) const
-{
+bool GLExtensions::hasExtension(char const* extension) const {
     const String8 s(extension);
     return mExtensionList.indexOf(s) >= 0;
 }
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.h b/services/surfaceflinger/RenderEngine/GLExtensions.h
index d81ed2a..ee7b446 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.h
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.h
@@ -20,9 +20,9 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/String8.h>
-#include <utils/SortedVector.h>
 #include <utils/Singleton.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
@@ -32,8 +32,7 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-class GLExtensions : public Singleton<GLExtensions>
-{
+class GLExtensions : public Singleton<GLExtensions> {
     friend class Singleton<GLExtensions>;
 
     bool mHaveFramebufferObject : 1;
@@ -45,22 +44,16 @@
     SortedVector<String8> mExtensionList;
 
     GLExtensions(const GLExtensions&);
-    GLExtensions& operator = (const GLExtensions&);
+    GLExtensions& operator=(const GLExtensions&);
 
 protected:
     GLExtensions();
 
 public:
+    inline bool haveFramebufferObject() const { return mHaveFramebufferObject; }
 
-    inline bool haveFramebufferObject() const {
-        return mHaveFramebufferObject;
-    }
-
-    void initWithGLStrings(
-            GLubyte const* vendor,
-            GLubyte const* renderer,
-            GLubyte const* version,
-            GLubyte const* extensions);
+    void initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version,
+                           GLubyte const* extensions);
 
     char const* getVendor() const;
     char const* getRenderer() const;
@@ -70,7 +63,6 @@
     bool hasExtension(char const* extension) const;
 };
 
-
 // ---------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/services/surfaceflinger/RenderEngine/Mesh.cpp b/services/surfaceflinger/RenderEngine/Mesh.cpp
index ffd9be2..6a62b1d 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.cpp
+++ b/services/surfaceflinger/RenderEngine/Mesh.cpp
@@ -21,9 +21,10 @@
 namespace android {
 
 Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize)
-    : mVertexCount(vertexCount), mVertexSize(vertexSize), mTexCoordsSize(texCoordSize),
-      mPrimitive(primitive)
-{
+      : mVertexCount(vertexCount),
+        mVertexSize(vertexSize),
+        mTexCoordsSize(texCoordSize),
+        mPrimitive(primitive) {
     if (vertexCount == 0) {
         mVertices = new float[1];
         mVertices[0] = 0.0f;
@@ -37,8 +38,7 @@
     // either vertexSize or texCoordSize, it must have overflowed. remainder
     // will be equal to stride as long as stride * vertexCount doesn't overflow.
     if ((stride < vertexSize) || (remainder != stride)) {
-        ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize,
-                texCoordSize);
+        ALOGE("Overflow in Mesh(..., %zu, %zu, %zu)", vertexCount, vertexSize, texCoordSize);
         mVertices = new float[1];
         mVertices[0] = 0.0f;
         mVertexCount = 0;
@@ -53,14 +53,13 @@
 }
 
 Mesh::~Mesh() {
-    delete [] mVertices;
+    delete[] mVertices;
 }
 
 Mesh::Primitive Mesh::getPrimitive() const {
     return mPrimitive;
 }
 
-
 float const* Mesh::getPositions() const {
     return mVertices;
 }
@@ -75,7 +74,6 @@
     return mVertices + mVertexSize;
 }
 
-
 size_t Mesh::getVertexCount() const {
     return mVertexCount;
 }
@@ -89,7 +87,7 @@
 }
 
 size_t Mesh::getByteStride() const {
-    return mStride*sizeof(float);
+    return mStride * sizeof(float);
 }
 
 size_t Mesh::getStride() const {
diff --git a/services/surfaceflinger/RenderEngine/Mesh.h b/services/surfaceflinger/RenderEngine/Mesh.h
index b6d42b0..d0a9ac0 100644
--- a/services/surfaceflinger/RenderEngine/Mesh.h
+++ b/services/surfaceflinger/RenderEngine/Mesh.h
@@ -24,9 +24,9 @@
 class Mesh {
 public:
     enum Primitive {
-        TRIANGLES       = 0x0004,       // GL_TRIANGLES
-        TRIANGLE_STRIP  = 0x0005,       // GL_TRIANGLE_STRIP
-        TRIANGLE_FAN    = 0x0006        // GL_TRIANGLE_FAN
+        TRIANGLES = 0x0004,      // GL_TRIANGLES
+        TRIANGLE_STRIP = 0x0005, // GL_TRIANGLE_STRIP
+        TRIANGLE_FAN = 0x0006    // GL_TRIANGLE_FAN
     };
 
     Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordsSize = 0);
@@ -40,21 +40,24 @@
         friend class Mesh;
         float* mData;
         size_t mStride;
-        VertexArray(float* data, size_t stride) : mData(data), mStride(stride) { }
+        VertexArray(float* data, size_t stride) : mData(data), mStride(stride) {}
+
     public:
-        TYPE& operator[](size_t index) {
-            return *reinterpret_cast<TYPE*>(&mData[index*mStride]);
-        }
+        TYPE& operator[](size_t index) { return *reinterpret_cast<TYPE*>(&mData[index * mStride]); }
         TYPE const& operator[](size_t index) const {
-            return *reinterpret_cast<TYPE const*>(&mData[index*mStride]);
+            return *reinterpret_cast<TYPE const*>(&mData[index * mStride]);
         }
     };
 
     template <typename TYPE>
-    VertexArray<TYPE> getPositionArray() { return VertexArray<TYPE>(getPositions(), mStride); }
+    VertexArray<TYPE> getPositionArray() {
+        return VertexArray<TYPE>(getPositions(), mStride);
+    }
 
     template <typename TYPE>
-    VertexArray<TYPE> getTexCoordArray() { return VertexArray<TYPE>(getTexCoords(), mStride); }
+    VertexArray<TYPE> getTexCoordArray() {
+        return VertexArray<TYPE>(getTexCoords(), mStride);
+    }
 
     Primitive getPrimitive() const;
 
@@ -81,8 +84,8 @@
 
 private:
     Mesh(const Mesh&);
-    Mesh& operator = (const Mesh&);
-    Mesh const& operator = (const Mesh&) const;
+    Mesh& operator=(const Mesh&);
+    Mesh const& operator=(const Mesh&) const;
 
     float* getPositions();
     float* getTexCoords();
@@ -94,6 +97,5 @@
     Primitive mPrimitive;
 };
 
-
 } /* namespace android */
 #endif /* SF_RENDER_ENGINE_MESH_H */
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp
index bd2188b..baf92eb 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/Program.cpp
@@ -19,15 +19,15 @@
 #include <log/log.h>
 #include <utils/String8.h>
 
+#include <math/mat4.h>
+#include "Description.h"
 #include "Program.h"
 #include "ProgramCache.h"
-#include "Description.h"
-#include <math/mat4.h>
 
 namespace android {
 
 Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment)
-        : mInitialized(false) {
+      : mInitialized(false) {
     GLuint vertexId = buildShader(vertex, GL_VERTEX_SHADER);
     GLuint fragmentId = buildShader(fragment, GL_FRAGMENT_SHADER);
     GLuint programId = glCreateProgram();
@@ -67,14 +67,12 @@
 
         // set-up the default values for our uniforms
         glUseProgram(programId);
-        const GLfloat m[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
-        glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, m);
+        glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, mat4().asArray());
         glEnableVertexAttribArray(0);
     }
 }
 
-Program::~Program() {
-}
+Program::~Program() {}
 
 bool Program::isValid() const {
     return mInitialized;
@@ -119,12 +117,11 @@
     char* src = new char[l];
     glGetShaderSource(shader, l, NULL, src);
     result.append(src);
-    delete [] src;
+    delete[] src;
     return result;
 }
 
 void Program::setUniforms(const Description& desc) {
-
     // TODO: we should have a mechanism here to not always reset uniforms that
     // didn't change for this program.
 
diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/Program.h
index a2ae2ee..6e57fdd 100644
--- a/services/surfaceflinger/RenderEngine/Program.h
+++ b/services/surfaceflinger/RenderEngine/Program.h
@@ -34,7 +34,7 @@
 class Program {
 public:
     // known locations for position and texture coordinates
-    enum { position=0, texCoords=1 };
+    enum { position = 0, texCoords = 1 };
 
     Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment);
     ~Program();
@@ -54,7 +54,6 @@
     /* set-up uniforms from the description */
     void setUniforms(const Description& desc);
 
-
 private:
     GLuint buildShader(const char* source, GLenum type);
     String8& dumpShader(String8& result, GLenum type);
@@ -83,7 +82,6 @@
     GLint mColorLoc;
 };
 
-
 } /* namespace android */
 
 #endif /* SF_RENDER_ENGINE_PROGRAM_H */
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index b437545..4f138dc 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -19,14 +19,13 @@
 
 #include <utils/String8.h>
 
-#include "ProgramCache.h"
-#include "Program.h"
 #include "Description.h"
+#include "Program.h"
+#include "ProgramCache.h"
 
 namespace android {
 // -----------------------------------------------------------------------------------------------
 
-
 /*
  * A simple formatter class to automatically add the endl and
  * manage the indentation.
@@ -42,23 +41,22 @@
     typedef Formatter& (*FormaterManipFunc)(Formatter&);
     friend Formatter& indent(Formatter& f);
     friend Formatter& dedent(Formatter& f);
+
 public:
     Formatter() : mIndent(0) {}
 
-    String8 getString() const {
-        return mString;
-    }
+    String8 getString() const { return mString; }
 
-    friend Formatter& operator << (Formatter& out, const char* in) {
-        for (int i=0 ; i<out.mIndent ; i++) {
+    friend Formatter& operator<<(Formatter& out, const char* in) {
+        for (int i = 0; i < out.mIndent; i++) {
             out.mString.append("    ");
         }
         out.mString.append(in);
         out.mString.append("\n");
         return out;
     }
-    friend inline Formatter& operator << (Formatter& out, const String8& in) {
-        return operator << (out, in.string());
+    friend inline Formatter& operator<<(Formatter& out, const String8& in) {
+        return operator<<(out, in.string());
     }
     friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) {
         return (*func)(to);
@@ -83,13 +81,11 @@
     primeCache();
 }
 
-ProgramCache::~ProgramCache() {
-}
+ProgramCache::~ProgramCache() {}
 
 void ProgramCache::primeCache() {
     uint32_t shaderCount = 0;
-    uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK |
-                       Key::ALPHA_MASK | Key::TEXTURE_MASK;
+    uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK;
     // Prime the cache for all combinations of the above masks,
     // leaving off the experimental color matrix mask options.
 
@@ -98,9 +94,7 @@
         Key shaderKey;
         shaderKey.set(keyMask, keyVal);
         uint32_t tex = shaderKey.getTextureTarget();
-        if (tex != Key::TEXTURE_OFF &&
-            tex != Key::TEXTURE_EXT &&
-            tex != Key::TEXTURE_2D) {
+        if (tex != Key::TEXTURE_OFF && tex != Key::TEXTURE_EXT && tex != Key::TEXTURE_2D) {
             continue;
         }
         Program* program = mCache.valueFor(shaderKey);
@@ -118,34 +112,36 @@
 ProgramCache::Key ProgramCache::computeKey(const Description& description) {
     Key needs;
     needs.set(Key::TEXTURE_MASK,
-            !description.mTextureEnabled ? Key::TEXTURE_OFF :
-            description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES ? Key::TEXTURE_EXT :
-            description.mTexture.getTextureTarget() == GL_TEXTURE_2D           ? Key::TEXTURE_2D :
-            Key::TEXTURE_OFF)
-    .set(Key::ALPHA_MASK,
-            (description.mColor.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE)
-    .set(Key::BLEND_MASK,
-            description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
-    .set(Key::OPACITY_MASK,
-            description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
-    .set(Key::COLOR_MATRIX_MASK,
-            description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON :  Key::COLOR_MATRIX_OFF)
-    .set(Key::WIDE_GAMUT_MASK,
-            description.mIsWideGamut ? Key::WIDE_GAMUT_ON : Key::WIDE_GAMUT_OFF);
+              !description.mTextureEnabled
+                      ? Key::TEXTURE_OFF
+                      : description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES
+                              ? Key::TEXTURE_EXT
+                              : description.mTexture.getTextureTarget() == GL_TEXTURE_2D
+                                      ? Key::TEXTURE_2D
+                                      : Key::TEXTURE_OFF)
+            .set(Key::ALPHA_MASK,
+                 (description.mColor.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE)
+            .set(Key::BLEND_MASK,
+                 description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
+            .set(Key::OPACITY_MASK,
+                 description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
+            .set(Key::COLOR_MATRIX_MASK,
+                 description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON : Key::COLOR_MATRIX_OFF)
+            .set(Key::WIDE_GAMUT_MASK,
+                 description.mIsWideGamut ? Key::WIDE_GAMUT_ON : Key::WIDE_GAMUT_OFF);
     return needs;
 }
 
 String8 ProgramCache::generateVertexShader(const Key& needs) {
     Formatter vs;
     if (needs.isTexturing()) {
-        vs  << "attribute vec4 texCoords;"
-            << "varying vec2 outTexCoords;";
+        vs << "attribute vec4 texCoords;"
+           << "varying vec2 outTexCoords;";
     }
     vs << "attribute vec4 position;"
        << "uniform mat4 projection;"
        << "uniform mat4 texture;"
-       << "void main(void) {" << indent
-       << "gl_Position = projection * position;";
+       << "void main(void) {" << indent << "gl_Position = projection * position;";
     if (needs.isTexturing()) {
         vs << "outTexCoords = (texture * texCoords).st;";
     }
@@ -272,11 +268,10 @@
 }
 
 void ProgramCache::useProgram(const Description& description) {
-
     // generate the key for the shader based on the description
     Key needs(computeKey(description));
 
-     // look-up the program in the cache
+    // look-up the program in the cache
     Program* program = mCache.valueFor(needs);
     if (program == NULL) {
         // we didn't find our program, so generate one...
@@ -285,7 +280,7 @@
         mCache.add(needs, program);
         time += systemTime();
 
-        //ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)",
+        // ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)",
         //        needs.mNeeds, uint32_t(ns2ms(time)), mCache.size());
     }
 
@@ -296,5 +291,4 @@
     }
 }
 
-
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
index ff5cf0f..54d3722 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -19,8 +19,8 @@
 
 #include <GLES2/gl2.h>
 
-#include <utils/Singleton.h>
 #include <utils/KeyedVector.h>
+#include <utils/Singleton.h>
 #include <utils/TypeHelpers.h>
 
 #include "Description.h"
@@ -47,63 +47,50 @@
         friend class ProgramCache;
         typedef uint32_t key_t;
         key_t mKey;
+
     public:
         enum {
-            BLEND_PREMULT           =       0x00000001,
-            BLEND_NORMAL            =       0x00000000,
-            BLEND_MASK              =       0x00000001,
+            BLEND_PREMULT = 0x00000001,
+            BLEND_NORMAL = 0x00000000,
+            BLEND_MASK = 0x00000001,
 
-            OPACITY_OPAQUE          =       0x00000002,
-            OPACITY_TRANSLUCENT     =       0x00000000,
-            OPACITY_MASK            =       0x00000002,
+            OPACITY_OPAQUE = 0x00000002,
+            OPACITY_TRANSLUCENT = 0x00000000,
+            OPACITY_MASK = 0x00000002,
 
-            ALPHA_LT_ONE            =       0x00000004,
-            ALPHA_EQ_ONE            =       0x00000000,
-            ALPHA_MASK              =       0x00000004,
+            ALPHA_LT_ONE = 0x00000004,
+            ALPHA_EQ_ONE = 0x00000000,
+            ALPHA_MASK = 0x00000004,
 
-            TEXTURE_OFF             =       0x00000000,
-            TEXTURE_EXT             =       0x00000008,
-            TEXTURE_2D              =       0x00000010,
-            TEXTURE_MASK            =       0x00000018,
+            TEXTURE_OFF = 0x00000000,
+            TEXTURE_EXT = 0x00000008,
+            TEXTURE_2D = 0x00000010,
+            TEXTURE_MASK = 0x00000018,
 
-            COLOR_MATRIX_OFF        =       0x00000000,
-            COLOR_MATRIX_ON         =       0x00000020,
-            COLOR_MATRIX_MASK       =       0x00000020,
+            COLOR_MATRIX_OFF = 0x00000000,
+            COLOR_MATRIX_ON = 0x00000020,
+            COLOR_MATRIX_MASK = 0x00000020,
 
-            WIDE_GAMUT_OFF          =       0x00000000,
-            WIDE_GAMUT_ON           =       0x00000040,
-            WIDE_GAMUT_MASK         =       0x00000040,
+            WIDE_GAMUT_OFF = 0x00000000,
+            WIDE_GAMUT_ON = 0x00000040,
+            WIDE_GAMUT_MASK = 0x00000040,
         };
 
-        inline Key() : mKey(0) { }
-        inline Key(const Key& rhs) : mKey(rhs.mKey) { }
+        inline Key() : mKey(0) {}
+        inline Key(const Key& rhs) : mKey(rhs.mKey) {}
 
         inline Key& set(key_t mask, key_t value) {
             mKey = (mKey & ~mask) | value;
             return *this;
         }
 
-        inline bool isTexturing() const {
-            return (mKey & TEXTURE_MASK) != TEXTURE_OFF;
-        }
-        inline int getTextureTarget() const {
-            return (mKey & TEXTURE_MASK);
-        }
-        inline bool isPremultiplied() const {
-            return (mKey & BLEND_MASK) == BLEND_PREMULT;
-        }
-        inline bool isOpaque() const {
-            return (mKey & OPACITY_MASK) == OPACITY_OPAQUE;
-        }
-        inline bool hasAlpha() const {
-            return (mKey & ALPHA_MASK) == ALPHA_LT_ONE;
-        }
-        inline bool hasColorMatrix() const {
-            return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON;
-        }
-        inline bool isWideGamut() const {
-            return (mKey & WIDE_GAMUT_MASK) == WIDE_GAMUT_ON;
-        }
+        inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; }
+        inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); }
+        inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; }
+        inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; }
+        inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; }
+        inline bool hasColorMatrix() const { return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON; }
+        inline bool isWideGamut() const { return (mKey & WIDE_GAMUT_MASK) == WIDE_GAMUT_ON; }
 
         // this is the definition of a friend function -- not a method of class Needs
         friend inline int strictly_order_type(const Key& lhs, const Key& rhs) {
@@ -135,7 +122,6 @@
     DefaultKeyedVector<Key, Program*> mCache;
 };
 
-
 ANDROID_BASIC_TYPES_TRAITS(ProgramCache::Key)
 
 } /* namespace android */
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 56e9ac0..883ae26 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -18,13 +18,13 @@
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
-#include "RenderEngine.h"
 #include "GLES20RenderEngine.h"
 #include "GLExtensions.h"
 #include "Mesh.h"
+#include "RenderEngine.h"
 
-#include <vector>
 #include <SurfaceFlinger.h>
+#include <vector>
 
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
 
@@ -33,21 +33,25 @@
 // ---------------------------------------------------------------------------
 
 static bool findExtension(const char* exts, const char* name) {
-    if (!exts)
-        return false;
+    if (!exts) return false;
     size_t len = strlen(name);
 
     const char* pos = exts;
     while ((pos = strstr(pos, name)) != NULL) {
-        if (pos[len] == '\0' || pos[len] == ' ')
-            return true;
+        if (pos[len] == '\0' || pos[len] == ' ') return true;
         pos += len;
     }
 
     return false;
 }
 
-RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat, uint32_t featureFlags) {
+std::unique_ptr<RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) {
+    // initialize EGL for the default display
+    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    if (!eglInitialize(display, NULL, NULL)) {
+        LOG_ALWAYS_FATAL("failed to initialize EGL");
+    }
+
     // EGL_ANDROIDX_no_config_context is an experimental extension with no
     // written specification. It will be replaced by something more formal.
     // SurfaceFlinger is using it to allow a single EGLContext to render to
@@ -70,8 +74,7 @@
     EGLint renderableType = 0;
     if (config == EGL_NO_CONFIG) {
         renderableType = EGL_OPENGL_ES2_BIT;
-    } else if (!eglGetConfigAttrib(display, config,
-            EGL_RENDERABLE_TYPE, &renderableType)) {
+    } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
         LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
     }
     EGLint contextClientVersion = 0;
@@ -96,12 +99,10 @@
     contextAttributes.push_back(EGL_NONE);
     contextAttributes.push_back(EGL_NONE);
 
-    EGLContext ctxt = eglCreateContext(display, config, NULL,
-                                       contextAttributes.data());
+    EGLContext ctxt = eglCreateContext(display, config, NULL, contextAttributes.data());
 
     // if can't create a GL context, we can only abort.
-    LOG_ALWAYS_FATAL_IF(ctxt==EGL_NO_CONTEXT, "EGLContext creation failed");
-
+    LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
 
     // now figure out what version of GL did we actually get
     // NOTE: a dummy surface is not needed if KHR_create_context is supported
@@ -110,35 +111,32 @@
     if (dummyConfig == EGL_NO_CONFIG) {
         dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
     }
-    EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE };
+    EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
     EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);
-    LOG_ALWAYS_FATAL_IF(dummy==EGL_NO_SURFACE, "can't create dummy pbuffer");
+    LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
     EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
     LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
 
     GLExtensions& extensions(GLExtensions::getInstance());
-    extensions.initWithGLStrings(
-            glGetString(GL_VENDOR),
-            glGetString(GL_RENDERER),
-            glGetString(GL_VERSION),
-            glGetString(GL_EXTENSIONS));
+    extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
+                                 glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
 
-    GlesVersion version = parseGlesVersion( extensions.getVersion() );
+    GlesVersion version = parseGlesVersion(extensions.getVersion());
 
     // initialize the renderer while GL is current
 
-    RenderEngine* engine = NULL;
+    std::unique_ptr<RenderEngine> engine;
     switch (version) {
-    case GLES_VERSION_1_0:
-    case GLES_VERSION_1_1:
-        LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run.");
-        break;
-    case GLES_VERSION_2_0:
-    case GLES_VERSION_3_0:
-        engine = new GLES20RenderEngine(featureFlags);
-        break;
+        case GLES_VERSION_1_0:
+        case GLES_VERSION_1_1:
+            LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run.");
+            break;
+        case GLES_VERSION_2_0:
+        case GLES_VERSION_3_0:
+            engine = std::make_unique<GLES20RenderEngine>(featureFlags);
+            break;
     }
-    engine->setEGLHandles(config, ctxt);
+    engine->setEGLHandles(display, config, ctxt);
 
     ALOGI("OpenGL ES informations:");
     ALOGI("vendor    : %s", extensions.getVendor());
@@ -154,31 +152,50 @@
     return engine;
 }
 
-RenderEngine::RenderEngine() : mEGLConfig(NULL), mEGLContext(EGL_NO_CONTEXT) {
-}
+RenderEngine::RenderEngine()
+      : mEGLDisplay(EGL_NO_DISPLAY), mEGLConfig(NULL), mEGLContext(EGL_NO_CONTEXT) {}
 
 RenderEngine::~RenderEngine() {
+    eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglTerminate(mEGLDisplay);
 }
 
-void RenderEngine::setEGLHandles(EGLConfig config, EGLContext ctxt) {
+void RenderEngine::setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt) {
+    mEGLDisplay = display;
     mEGLConfig = config;
     mEGLContext = ctxt;
 }
 
-EGLContext RenderEngine::getEGLConfig() const {
+EGLDisplay RenderEngine::getEGLDisplay() const {
+    return mEGLDisplay;
+}
+
+EGLConfig RenderEngine::getEGLConfig() const {
     return mEGLConfig;
 }
 
-EGLContext RenderEngine::getEGLContext() const {
-    return mEGLContext;
+bool RenderEngine::setCurrentSurface(const RE::Surface& surface) {
+    bool success = true;
+    EGLSurface eglSurface = surface.getEGLSurface();
+    if (eglSurface != eglGetCurrentSurface(EGL_DRAW)) {
+        success = eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext) == EGL_TRUE;
+        if (success && surface.getAsync()) {
+            eglSwapInterval(mEGLDisplay, 0);
+        }
+    }
+
+    return success;
+}
+
+void RenderEngine::resetCurrentSurface() {
+    eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 }
 
 void RenderEngine::checkErrors() const {
     do {
         // there could be more than one error flag
         GLenum error = glGetError();
-        if (error == GL_NO_ERROR)
-            break;
+        if (error == GL_NO_ERROR) break;
         ALOGE("GL error 0x%04x", int(error));
     } while (true);
 }
@@ -201,32 +218,74 @@
     return GLES_VERSION_1_0;
 }
 
-void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height,
-        float red, float green, float blue, float alpha) {
+void RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, float red,
+                                       float green, float blue, float alpha) {
     size_t c;
     Rect const* r = region.getArray(&c);
-    Mesh mesh(Mesh::TRIANGLES, c*6, 2);
+    Mesh mesh(Mesh::TRIANGLES, c * 6, 2);
     Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
-    for (size_t i=0 ; i<c ; i++, r++) {
-        position[i*6 + 0].x = r->left;
-        position[i*6 + 0].y = height - r->top;
-        position[i*6 + 1].x = r->left;
-        position[i*6 + 1].y = height - r->bottom;
-        position[i*6 + 2].x = r->right;
-        position[i*6 + 2].y = height - r->bottom;
-        position[i*6 + 3].x = r->left;
-        position[i*6 + 3].y = height - r->top;
-        position[i*6 + 4].x = r->right;
-        position[i*6 + 4].y = height - r->bottom;
-        position[i*6 + 5].x = r->right;
-        position[i*6 + 5].y = height - r->top;
+    for (size_t i = 0; i < c; i++, r++) {
+        position[i * 6 + 0].x = r->left;
+        position[i * 6 + 0].y = height - r->top;
+        position[i * 6 + 1].x = r->left;
+        position[i * 6 + 1].y = height - r->bottom;
+        position[i * 6 + 2].x = r->right;
+        position[i * 6 + 2].y = height - r->bottom;
+        position[i * 6 + 3].x = r->left;
+        position[i * 6 + 3].y = height - r->top;
+        position[i * 6 + 4].x = r->right;
+        position[i * 6 + 4].y = height - r->bottom;
+        position[i * 6 + 5].x = r->right;
+        position[i * 6 + 5].y = height - r->top;
     }
     setupFillWithColor(red, green, blue, alpha);
     drawMesh(mesh);
 }
 
-void RenderEngine::flush() {
-    glFlush();
+int RenderEngine::flush(bool wait) {
+    // Attempt to create a sync khr object that can produce a sync point. If that
+    // isn't available, create a non-dupable sync object in the fallback path and
+    // wait on it directly.
+    EGLSyncKHR sync;
+    if (!wait) {
+        EGLint syncFd = EGL_NO_NATIVE_FENCE_FD_ANDROID;
+
+        sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+        if (sync != EGL_NO_SYNC_KHR) {
+            // native fence fd will not be populated until flush() is done.
+            glFlush();
+
+            // get the sync fd
+            syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
+            if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+                ALOGW("failed to dup sync khr object");
+            }
+
+            eglDestroySyncKHR(mEGLDisplay, sync);
+        }
+
+        if (syncFd != EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+            return syncFd;
+        }
+    }
+
+    // fallback or explicit wait
+    sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
+    if (sync != EGL_NO_SYNC_KHR) {
+        EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
+                                             2000000000 /*2 sec*/);
+        EGLint eglErr = eglGetError();
+        if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+            ALOGW("fence wait timed out");
+        } else {
+            ALOGW_IF(eglErr != EGL_SUCCESS, "error waiting on EGL fence: %#x", eglErr);
+        }
+        eglDestroySyncKHR(mEGLDisplay, sync);
+    } else {
+        ALOGW("error creating EGL fence: %#x", eglGetError());
+    }
+
+    return -1;
 }
 
 void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
@@ -234,8 +293,7 @@
     glClear(GL_COLOR_BUFFER_BIT);
 }
 
-void RenderEngine::setScissor(
-        uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
+void RenderEngine::setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
     glScissor(left, bottom, right, top);
     glEnable(GL_SCISSOR_TEST);
 }
@@ -257,38 +315,52 @@
 }
 
 void RenderEngine::dump(String8& result) {
+    result.appendFormat("EGL implementation : %s\n",
+                        eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION));
+    result.appendFormat("%s\n", eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS));
+
     const GLExtensions& extensions(GLExtensions::getInstance());
-    result.appendFormat("GLES: %s, %s, %s\n",
-            extensions.getVendor(),
-            extensions.getRenderer(),
-            extensions.getVersion());
+    result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
+                        extensions.getVersion());
     result.appendFormat("%s\n", extensions.getExtension());
 }
 
 // ---------------------------------------------------------------------------
 
-RenderEngine::BindImageAsFramebuffer::BindImageAsFramebuffer(
-        RenderEngine& engine, EGLImageKHR image) : mEngine(engine)
-{
-    mEngine.bindImageAsFramebuffer(image, &mTexName, &mFbName, &mStatus);
+RenderEngine::BindNativeBufferAsFramebuffer::BindNativeBufferAsFramebuffer(
+        RenderEngine& engine, ANativeWindowBuffer* buffer)
+      : mEngine(engine) {
+    mImage = eglCreateImageKHR(mEngine.mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                               buffer, NULL);
+    if (mImage == EGL_NO_IMAGE_KHR) {
+        mStatus = GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+        return;
+    }
 
-    ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES,
-            "glCheckFramebufferStatusOES error %d", mStatus);
+    mEngine.bindImageAsFramebuffer(mImage, &mTexName, &mFbName, &mStatus);
+
+    ALOGE_IF(mStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
+             mStatus);
 }
 
-RenderEngine::BindImageAsFramebuffer::~BindImageAsFramebuffer() {
+RenderEngine::BindNativeBufferAsFramebuffer::~BindNativeBufferAsFramebuffer() {
+    if (mImage == EGL_NO_IMAGE_KHR) {
+        return;
+    }
+
     // back to main framebuffer
     mEngine.unbindFramebuffer(mTexName, mFbName);
+    eglDestroyImageKHR(mEngine.mEGLDisplay, mImage);
 }
 
-status_t RenderEngine::BindImageAsFramebuffer::getStatus() const {
+status_t RenderEngine::BindNativeBufferAsFramebuffer::getStatus() const {
     return mStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE;
 }
 
 // ---------------------------------------------------------------------------
 
-static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs,
-        EGLint attribute, EGLint wanted, EGLConfig* outConfig) {
+static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
+                                         EGLint wanted, EGLConfig* outConfig) {
     EGLint numConfigs = -1, n = 0;
     eglGetConfigs(dpy, NULL, 0, &numConfigs);
     EGLConfig* const configs = new EGLConfig[numConfigs];
@@ -296,23 +368,23 @@
 
     if (n) {
         if (attribute != EGL_NONE) {
-            for (int i=0 ; i<n ; i++) {
+            for (int i = 0; i < n; i++) {
                 EGLint value = 0;
                 eglGetConfigAttrib(dpy, configs[i], attribute, &value);
                 if (wanted == value) {
                     *outConfig = configs[i];
-                    delete [] configs;
+                    delete[] configs;
                     return NO_ERROR;
                 }
             }
         } else {
             // just pick the first one
             *outConfig = configs[0];
-            delete [] configs;
+            delete[] configs;
             return NO_ERROR;
         }
     }
-    delete [] configs;
+    delete[] configs;
     return NAME_NOT_FOUND;
 }
 
@@ -322,10 +394,10 @@
     friend class Adder;
     KeyedVector<Attribute, EGLint> mList;
     struct Attribute {
-        Attribute() : v(0) {};
-        explicit Attribute(EGLint v) : v(v) { }
+        Attribute() : v(0){};
+        explicit Attribute(EGLint v) : v(v) {}
         EGLint v;
-        bool operator < (const Attribute& other) const {
+        bool operator<(const Attribute& other) const {
             // this places EGL_NONE at the end
             EGLint lhs(v);
             EGLint rhs(other.v);
@@ -338,39 +410,32 @@
         friend class EGLAttributeVector;
         EGLAttributeVector& v;
         EGLint attribute;
-        Adder(EGLAttributeVector& v, EGLint attribute)
-            : v(v), attribute(attribute) {
-        }
+        Adder(EGLAttributeVector& v, EGLint attribute) : v(v), attribute(attribute) {}
+
     public:
-        void operator = (EGLint value) {
+        void operator=(EGLint value) {
             if (attribute != EGL_NONE) {
                 v.mList.add(Attribute(attribute), value);
             }
         }
-        operator EGLint () const { return v.mList[attribute]; }
+        operator EGLint() const { return v.mList[attribute]; }
     };
+
 public:
-    EGLAttributeVector() {
-        mList.add(Attribute(EGL_NONE), EGL_NONE);
-    }
+    EGLAttributeVector() { mList.add(Attribute(EGL_NONE), EGL_NONE); }
     void remove(EGLint attribute) {
         if (attribute != EGL_NONE) {
             mList.removeItem(Attribute(attribute));
         }
     }
-    Adder operator [] (EGLint attribute) {
-        return Adder(*this, attribute);
-    }
-    EGLint operator [] (EGLint attribute) const {
-       return mList[attribute];
-    }
+    Adder operator[](EGLint attribute) { return Adder(*this, attribute); }
+    EGLint operator[](EGLint attribute) const { return mList[attribute]; }
     // cast-operator to (EGLint const*)
-    operator EGLint const* () const { return &mList.keyAt(0).v; }
+    operator EGLint const*() const { return &mList.keyAt(0).v; }
 };
 
-
-static status_t selectEGLConfig(EGLDisplay display, EGLint format,
-    EGLint renderableType, EGLConfig* config) {
+static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType,
+                                EGLConfig* config) {
     // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
     // it is to be used with WIFI displays
     status_t err;
@@ -379,24 +444,23 @@
 
     EGLAttributeVector attribs;
     if (renderableType) {
-        attribs[EGL_RENDERABLE_TYPE]            = renderableType;
-        attribs[EGL_RECORDABLE_ANDROID]         = EGL_TRUE;
-        attribs[EGL_SURFACE_TYPE]               = EGL_WINDOW_BIT|EGL_PBUFFER_BIT;
+        attribs[EGL_RENDERABLE_TYPE] = renderableType;
+        attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE;
+        attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
         attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE;
-        attribs[EGL_RED_SIZE]                   = 8;
-        attribs[EGL_GREEN_SIZE]                 = 8;
-        attribs[EGL_BLUE_SIZE]                  = 8;
-        attribs[EGL_ALPHA_SIZE]                 = 8;
-        wantedAttribute                         = EGL_NONE;
-        wantedAttributeValue                    = EGL_NONE;
+        attribs[EGL_RED_SIZE] = 8;
+        attribs[EGL_GREEN_SIZE] = 8;
+        attribs[EGL_BLUE_SIZE] = 8;
+        attribs[EGL_ALPHA_SIZE] = 8;
+        wantedAttribute = EGL_NONE;
+        wantedAttributeValue = EGL_NONE;
     } else {
         // if no renderable type specified, fallback to a simplified query
-        wantedAttribute                         = EGL_NATIVE_VISUAL_ID;
-        wantedAttributeValue                    = format;
+        wantedAttribute = EGL_NATIVE_VISUAL_ID;
+        wantedAttributeValue = format;
     }
 
-    err = selectConfigForAttribute(display, attribs,
-            wantedAttribute, wantedAttributeValue, config);
+    err = selectConfigForAttribute(display, attribs, wantedAttribute, wantedAttributeValue, config);
     if (err == NO_ERROR) {
         EGLint caveat;
         if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
@@ -406,8 +470,7 @@
     return err;
 }
 
-EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format,
-                                        bool logConfig) {
+EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
     status_t err;
     EGLConfig config;
 
@@ -430,23 +493,22 @@
 
     if (logConfig) {
         // print some debugging info
-        EGLint r,g,b,a;
-        eglGetConfigAttrib(display, config, EGL_RED_SIZE,   &r);
+        EGLint r, g, b, a;
+        eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
         eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
-        eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,  &b);
+        eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
         eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
         ALOGI("EGL information:");
         ALOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
         ALOGI("version   : %s", eglQueryString(display, EGL_VERSION));
         ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
-        ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS)?:"Not Supported");
+        ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported");
         ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
     }
 
     return config;
 }
 
-
 void RenderEngine::primeCache() const {
     // Getting the ProgramCache instance causes it to prime its shader cache,
     // which is performed in its constructor
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 7e05cec..3847347 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -14,21 +14,24 @@
  * limitations under the License.
  */
 
-
 #ifndef SF_RENDERENGINE_H_
 #define SF_RENDERENGINE_H_
 
+#include <memory>
+
 #include <stdint.h>
 #include <sys/types.h>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
-#include <math/mat4.h>
 #include <Transform.h>
 #include <gui/SurfaceControl.h>
+#include <math/mat4.h>
 
 #define EGL_NO_CONFIG ((EGLConfig)0)
 
+struct ANativeWindowBuffer;
+
 // ---------------------------------------------------------------------------
 namespace android {
 // ---------------------------------------------------------------------------
@@ -39,31 +42,38 @@
 class Mesh;
 class Texture;
 
+namespace RE {
+class Surface;
+}
+
 class RenderEngine {
     enum GlesVersion {
-        GLES_VERSION_1_0    = 0x10000,
-        GLES_VERSION_1_1    = 0x10001,
-        GLES_VERSION_2_0    = 0x20000,
-        GLES_VERSION_3_0    = 0x30000,
+        GLES_VERSION_1_0 = 0x10000,
+        GLES_VERSION_1_1 = 0x10001,
+        GLES_VERSION_2_0 = 0x20000,
+        GLES_VERSION_3_0 = 0x30000,
     };
     static GlesVersion parseGlesVersion(const char* str);
 
+    EGLDisplay mEGLDisplay;
     EGLConfig mEGLConfig;
     EGLContext mEGLContext;
-    void setEGLHandles(EGLConfig config, EGLContext ctxt);
+    void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt);
 
-    virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName, uint32_t* status) = 0;
+    virtual void bindImageAsFramebuffer(EGLImageKHR image, uint32_t* texName, uint32_t* fbName,
+                                        uint32_t* status) = 0;
     virtual void unbindFramebuffer(uint32_t texName, uint32_t fbName) = 0;
 
 protected:
     RenderEngine();
-    virtual ~RenderEngine() = 0;
 
 public:
+    virtual ~RenderEngine() = 0;
+
     enum FeatureFlag {
         WIDE_COLOR_SUPPORT = 1 << 0 // Platform has a wide color display
     };
-    static RenderEngine* create(EGLDisplay display, int hwcFormat, uint32_t featureFlags);
+    static std::unique_ptr<RenderEngine> create(int hwcFormat, uint32_t featureFlags);
 
     static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
 
@@ -73,10 +83,11 @@
     virtual void dump(String8& result);
 
     // helpers
-    void flush();
+    // flush returns -1 or a valid native fence fd owned by the caller
+    int flush(bool wait);
     void clearWithColor(float red, float green, float blue, float alpha);
-    void fillRegionWithColor(const Region& region, uint32_t height,
-            float red, float green, float blue, float alpha);
+    void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
+                             float blue, float alpha);
 
     // common to all GL versions
     void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top);
@@ -85,22 +96,27 @@
     void deleteTextures(size_t count, uint32_t const* names);
     void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels);
 
-    class BindImageAsFramebuffer {
+    class BindNativeBufferAsFramebuffer {
         RenderEngine& mEngine;
+        EGLImageKHR mImage;
         uint32_t mTexName, mFbName;
         uint32_t mStatus;
+
     public:
-        BindImageAsFramebuffer(RenderEngine& engine, EGLImageKHR image);
-        ~BindImageAsFramebuffer();
+        BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer);
+        ~BindNativeBufferAsFramebuffer();
         int getStatus() const;
     };
 
+    bool setCurrentSurface(const RE::Surface& surface);
+    void resetCurrentSurface();
+
     // set-up
     virtual void checkErrors() const;
-    virtual void setViewportAndProjection(size_t vpw, size_t vph,
-            Rect sourceCrop, size_t hwh, bool yswap, Transform::orientation_flags rotation) = 0;
-    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque,
-            bool disableTexture, const half4& color) = 0;
+    virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh,
+                                          bool yswap, Transform::orientation_flags rotation) = 0;
+    virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+                                    const half4& color) = 0;
     virtual void setColorMode(android_color_mode mode) = 0;
     virtual void setSourceDataSpace(android_dataspace source) = 0;
     virtual void setWideColor(bool hasWideColor) = 0;
@@ -109,9 +125,7 @@
     virtual void setupLayerBlackedOut() = 0;
     virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
 
-    virtual mat4 setupColorTransform(const mat4& /* colorTransform */) {
-        return mat4();
-    }
+    virtual mat4 setupColorTransform(const mat4& /* colorTransform */) { return mat4(); }
 
     virtual void disableTexturing() = 0;
     virtual void disableBlending() = 0;
@@ -123,8 +137,9 @@
     virtual size_t getMaxTextureSize() const = 0;
     virtual size_t getMaxViewportDims() const = 0;
 
+    // internal to RenderEngine
+    EGLDisplay getEGLDisplay() const;
     EGLConfig getEGLConfig() const;
-    EGLContext getEGLContext() const;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/Surface.cpp b/services/surfaceflinger/RenderEngine/Surface.cpp
new file mode 100644
index 0000000..a23d9fb
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Surface.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright 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 "Surface.h"
+
+#include "RenderEngine.h"
+
+#include <log/log.h>
+
+namespace android {
+namespace RE {
+
+Surface::Surface(const RenderEngine& engine)
+      : mEGLDisplay(engine.getEGLDisplay()), mEGLConfig(engine.getEGLConfig()) {
+    // RE does not assume any config when EGL_KHR_no_config_context is supported
+    if (mEGLConfig == EGL_NO_CONFIG_KHR) {
+        mEGLConfig = RenderEngine::chooseEglConfig(mEGLDisplay, PIXEL_FORMAT_RGBA_8888, false);
+    }
+}
+
+Surface::~Surface() {
+    setNativeWindow(nullptr);
+}
+
+void Surface::setNativeWindow(ANativeWindow* window) {
+    if (mEGLSurface != EGL_NO_SURFACE) {
+        eglDestroySurface(mEGLDisplay, mEGLSurface);
+        mEGLSurface = EGL_NO_SURFACE;
+    }
+
+    mWindow = window;
+    if (mWindow) {
+        mEGLSurface = eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mWindow, nullptr);
+    }
+}
+
+void Surface::swapBuffers() const {
+    if (!eglSwapBuffers(mEGLDisplay, mEGLSurface)) {
+        EGLint error = eglGetError();
+
+        const char format[] = "eglSwapBuffers(%p, %p) failed with 0x%08x";
+        if (mCritical || error == EGL_CONTEXT_LOST) {
+            LOG_ALWAYS_FATAL(format, mEGLDisplay, mEGLSurface, error);
+        } else {
+            ALOGE(format, mEGLDisplay, mEGLSurface, error);
+        }
+    }
+}
+
+EGLint Surface::queryConfig(EGLint attrib) const {
+    EGLint value;
+    if (!eglGetConfigAttrib(mEGLConfig, mEGLConfig, attrib, &value)) {
+        value = 0;
+    }
+
+    return value;
+}
+
+EGLint Surface::querySurface(EGLint attrib) const {
+    EGLint value;
+    if (!eglQuerySurface(mEGLDisplay, mEGLSurface, attrib, &value)) {
+        value = 0;
+    }
+
+    return value;
+}
+
+int32_t Surface::queryRedSize() const {
+    return queryConfig(EGL_RED_SIZE);
+}
+
+int32_t Surface::queryGreenSize() const {
+    return queryConfig(EGL_GREEN_SIZE);
+}
+
+int32_t Surface::queryBlueSize() const {
+    return queryConfig(EGL_BLUE_SIZE);
+}
+
+int32_t Surface::queryAlphaSize() const {
+    return queryConfig(EGL_ALPHA_SIZE);
+}
+
+int32_t Surface::queryWidth() const {
+    return querySurface(EGL_WIDTH);
+}
+
+int32_t Surface::queryHeight() const {
+    return querySurface(EGL_HEIGHT);
+}
+
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Surface.h b/services/surfaceflinger/RenderEngine/Surface.h
new file mode 100644
index 0000000..8b10be9
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Surface.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 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
+
+#include <cstdint>
+
+#include <EGL/egl.h>
+
+struct ANativeWindow;
+
+namespace android {
+
+class RenderEngine;
+
+namespace RE {
+
+class Surface {
+public:
+    Surface(const RenderEngine& engine);
+    ~Surface();
+
+    Surface(const Surface&) = delete;
+    Surface& operator=(const Surface&) = delete;
+
+    void setCritical(bool enable) { mCritical = enable; }
+    void setAsync(bool enable) { mAsync = enable; }
+
+    void setNativeWindow(ANativeWindow* window);
+    void swapBuffers() const;
+
+    int32_t queryRedSize() const;
+    int32_t queryGreenSize() const;
+    int32_t queryBlueSize() const;
+    int32_t queryAlphaSize() const;
+
+    int32_t queryWidth() const;
+    int32_t queryHeight() const;
+
+private:
+    EGLint queryConfig(EGLint attrib) const;
+    EGLint querySurface(EGLint attrib) const;
+
+    // methods internal to RenderEngine
+    friend class android::RenderEngine;
+    bool getAsync() const { return mAsync; }
+    EGLSurface getEGLSurface() const { return mEGLSurface; }
+
+    EGLDisplay mEGLDisplay;
+    EGLConfig mEGLConfig;
+
+    bool mCritical = false;
+    bool mAsync = false;
+
+    ANativeWindow* mWindow = nullptr;
+    EGLSurface mEGLSurface = EGL_NO_SURFACE;
+};
+
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Texture.cpp b/services/surfaceflinger/RenderEngine/Texture.cpp
index 8875b6d..351430f 100644
--- a/services/surfaceflinger/RenderEngine/Texture.cpp
+++ b/services/surfaceflinger/RenderEngine/Texture.cpp
@@ -20,24 +20,22 @@
 
 namespace android {
 
-Texture::Texture() :
-    mTextureName(0), mTextureTarget(TEXTURE_2D),
-    mWidth(0), mHeight(0), mFiltering(false) {
-}
+Texture::Texture()
+      : mTextureName(0), mTextureTarget(TEXTURE_2D), mWidth(0), mHeight(0), mFiltering(false) {}
 
-Texture::Texture(Target textureTarget, uint32_t textureName) :
-            mTextureName(textureName), mTextureTarget(textureTarget),
-            mWidth(0), mHeight(0), mFiltering(false) {
-}
+Texture::Texture(Target textureTarget, uint32_t textureName)
+      : mTextureName(textureName),
+        mTextureTarget(textureTarget),
+        mWidth(0),
+        mHeight(0),
+        mFiltering(false) {}
 
 void Texture::init(Target textureTarget, uint32_t textureName) {
     mTextureName = textureName;
     mTextureTarget = textureTarget;
 }
 
-Texture::~Texture() {
-}
-
+Texture::~Texture() {}
 
 void Texture::setMatrix(float const* matrix) {
     mTextureMatrix = mat4(matrix);
diff --git a/services/surfaceflinger/RenderEngine/Texture.h b/services/surfaceflinger/RenderEngine/Texture.h
index a07e0c3..56b6b31 100644
--- a/services/surfaceflinger/RenderEngine/Texture.h
+++ b/services/surfaceflinger/RenderEngine/Texture.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <stdint.h>
 #include <math/mat4.h>
+#include <stdint.h>
 
 #ifndef SF_RENDER_ENGINE_TEXTURE_H
 #define SF_RENDER_ENGINE_TEXTURE_H
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cab9219..555f4a8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -28,8 +28,6 @@
 #include <stdatomic.h>
 #include <optional>
 
-#include <EGL/egl.h>
-
 #include <cutils/properties.h>
 #include <log/log.h>
 
@@ -101,8 +99,6 @@
  */
 #define DEBUG_SCREENSHOTS   false
 
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-
 namespace android {
 
 using namespace android::hardware::configstore;
@@ -285,9 +281,6 @@
 
 SurfaceFlinger::~SurfaceFlinger()
 {
-    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    eglTerminate(display);
 }
 
 void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
@@ -594,10 +587,6 @@
 
     Mutex::Autolock _l(mStateLock);
 
-    // initialize EGL for the default display
-    mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    eglInitialize(mEGLDisplay, NULL, NULL);
-
     // start the EventThread
     sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
             vsyncPhaseOffsetNs, true, "app");
@@ -618,15 +607,9 @@
     }
 
     // Get a RenderEngine for the given display / config (can't fail)
-    mRenderEngine = RenderEngine::create(mEGLDisplay,
-            HAL_PIXEL_FORMAT_RGBA_8888,
+    mRenderEngine = RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
             hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0);
-
-    // retrieve the EGL context that was selected/created
-    mEGLContext = mRenderEngine->getEGLContext();
-
-    LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
-            "couldn't create EGLContext");
+    LOG_ALWAYS_FATAL_IF(mRenderEngine == nullptr, "couldn't create RenderEngine");
 
     LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
             "Starting with vr flinger active is not currently supported.");
@@ -1308,8 +1291,7 @@
     }
     bool useWideColorMode = hasWideColorModes && hasWideColorDisplay && !mForceNativeColorMode;
     sp<DisplayDevice> hw = new DisplayDevice(this, DisplayDevice::DISPLAY_PRIMARY, type, isSecure,
-                                             token, fbs, producer, mRenderEngine->getEGLConfig(),
-                                             useWideColorMode);
+                                             token, fbs, producer, useWideColorMode);
     mDisplays.add(token, hw);
     android_color_mode defaultColorMode = HAL_COLOR_MODE_NATIVE;
     if (useWideColorMode) {
@@ -1324,7 +1306,7 @@
 
     // make the GLContext current so that we can create textures when creating
     // Layers (which may happens before we render something)
-    hw->makeCurrent(mEGLDisplay, mEGLContext);
+    hw->makeCurrent();
 }
 
 void SurfaceFlinger::onHotplugReceived(int32_t sequenceId,
@@ -1395,7 +1377,7 @@
     // mCurrentState and mDrawingState and re-apply all changes when we make the
     // transition.
     mDrawingState.displays.clear();
-    eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    getRenderEngine().resetCurrentSurface();
     mDisplays.clear();
 }
 
@@ -1552,7 +1534,7 @@
             const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
             if (!dirtyRegion.isEmpty()) {
                 // redraw the whole screen
-                doComposeSurfaces(hw, Region(hw->bounds()));
+                doComposeSurfaces(hw);
 
                 // and draw the dirty region
                 const int32_t height = hw->getHeight();
@@ -2027,8 +2009,7 @@
             doDisplayComposition(hw, dirtyRegion);
 
             hw->dirtyRegion.clear();
-            hw->flip(hw->swapRegion);
-            hw->swapRegion.clear();
+            hw->flip();
         }
     }
     postFramebuffer();
@@ -2052,7 +2033,7 @@
             mHwc->presentAndGetReleaseFences(hwcId);
         }
         displayDevice->onSwapBuffersCompleted();
-        displayDevice->makeCurrent(mEGLDisplay, mEGLContext);
+        displayDevice->makeCurrent();
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
             // The layer buffer from the previous frame (if any) is released
             // by HWC only when the release fence from this frame (if any) is
@@ -2178,7 +2159,7 @@
                         // be sure that nothing associated with this display
                         // is current.
                         const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked());
-                        defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext);
+                        defaultDisplay->makeCurrent();
                         sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i)));
                         if (hw != NULL)
                             hw->disconnect(getHwComposer());
@@ -2296,9 +2277,7 @@
                     if (dispSurface != NULL) {
                         sp<DisplayDevice> hw =
                                 new DisplayDevice(this, state.type, hwcId, state.isSecure, display,
-                                                  dispSurface, producer,
-                                                  mRenderEngine->getEGLConfig(),
-                                                  hasWideColorDisplay);
+                                                  dispSurface, producer, hasWideColorDisplay);
                         hw->setLayerStack(state.layerStack);
                         hw->setProjection(state.orientation,
                                 state.viewport, state.frame);
@@ -2663,46 +2642,17 @@
     }
 
     ALOGV("doDisplayComposition");
-
-    Region dirtyRegion(inDirtyRegion);
-
-    // compute the invalid region
-    displayDevice->swapRegion.orSelf(dirtyRegion);
-
-    uint32_t flags = displayDevice->getFlags();
-    if (flags & DisplayDevice::SWAP_RECTANGLE) {
-        // we can redraw only what's dirty, but since SWAP_RECTANGLE only
-        // takes a rectangle, we must make sure to update that whole
-        // rectangle in that case
-        dirtyRegion.set(displayDevice->swapRegion.bounds());
-    } else {
-        if (flags & DisplayDevice::PARTIAL_UPDATES) {
-            // We need to redraw the rectangle that will be updated
-            // (pushed to the framebuffer).
-            // This is needed because PARTIAL_UPDATES only takes one
-            // rectangle instead of a region (see DisplayDevice::flip())
-            dirtyRegion.set(displayDevice->swapRegion.bounds());
-        } else {
-            // we need to redraw everything (the whole screen)
-            dirtyRegion.set(displayDevice->bounds());
-            displayDevice->swapRegion = dirtyRegion;
-        }
-    }
-
-    if (!doComposeSurfaces(displayDevice, dirtyRegion)) return;
-
-    // update the swap region and clear the dirty region
-    displayDevice->swapRegion.orSelf(dirtyRegion);
+    if (!doComposeSurfaces(displayDevice)) return;
 
     // swap buffers (presentation)
     displayDevice->swapBuffers(getHwComposer());
 }
 
-bool SurfaceFlinger::doComposeSurfaces(
-        const sp<const DisplayDevice>& displayDevice, const Region& dirty)
+bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDevice)
 {
     ALOGV("doComposeSurfaces");
 
+    const Region bounds(displayDevice->bounds());
     const DisplayRenderArea renderArea(displayDevice);
     const auto hwcId = displayDevice->getHwcDisplayId();
 
@@ -2722,13 +2672,13 @@
                 displayDevice->getWideColorSupport() && !mForceNativeColorMode);
         mRenderEngine->setColorMode(mForceNativeColorMode ?
                 HAL_COLOR_MODE_NATIVE : displayDevice->getActiveColorMode());
-        if (!displayDevice->makeCurrent(mEGLDisplay, mEGLContext)) {
+        if (!displayDevice->makeCurrent()) {
             ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
                   displayDevice->getDisplayName().string());
-            eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+            getRenderEngine().resetCurrentSurface();
 
             // |mStateLock| not needed as we are on the main thread
-            if(!getDefaultDisplayDeviceLocked()->makeCurrent(mEGLDisplay, mEGLContext)) {
+            if(!getDefaultDisplayDeviceLocked()->makeCurrent()) {
               ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
             }
             return false;
@@ -2744,10 +2694,7 @@
             // We'll revisit later if needed.
             mRenderEngine->clearWithColor(0, 0, 0, 0);
         } else {
-            // we start with the whole screen area
-            const Region bounds(displayDevice->getBounds());
-
-            // we remove the scissor part
+            // we start with the whole screen area and remove the scissor part
             // we're left with the letterbox region
             // (common case is that letterbox ends-up being empty)
             const Region letterbox(bounds.subtract(displayDevice->getScissor()));
@@ -2755,9 +2702,6 @@
             // compute the area to clear
             Region region(displayDevice->undefinedRegion.merge(letterbox));
 
-            // but limit it to the dirty region
-            region.andSelf(dirty);
-
             // screen is already cleared here
             if (!region.isEmpty()) {
                 // can happen with SurfaceView
@@ -2794,7 +2738,7 @@
         // we're using h/w composer
         bool firstLayer = true;
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-            const Region clip(dirty.intersect(
+            const Region clip(bounds.intersect(
                     displayTransform.transform(layer->visibleRegion)));
             ALOGV("Layer: %s", layer->getName().string());
             ALOGV("  Composition type: %s",
@@ -2830,7 +2774,7 @@
     } else {
         // we're not using h/w composer
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-            const Region clip(dirty.intersect(
+            const Region clip(bounds.intersect(
                     displayTransform.transform(layer->visibleRegion)));
             if (!clip.isEmpty()) {
                 layer->draw(renderArea, clip);
@@ -3224,7 +3168,11 @@
         // changed, we don't want this to cause any more work
     }
     if (what & layer_state_t::eReparent) {
+        bool hadParent = layer->hasParent();
         if (layer->reparent(s.parentHandleForChild)) {
+            if (!hadParent) {
+                mCurrentState.layersSortedByZ.remove(layer);
+            }
             flags |= eTransactionNeeded|eTraversalNeeded;
         }
     }
@@ -3933,13 +3881,6 @@
     HWComposer& hwc(getHwComposer());
     sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
 
-    colorizer.bold(result);
-    result.appendFormat("EGL implementation : %s\n",
-            eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION));
-    colorizer.reset(result);
-    result.appendFormat("%s\n",
-            eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS));
-
     mRenderEngine->dump(result);
 
     hw->undefinedRegion.dump(result, "undefinedRegion");
@@ -4392,15 +4333,14 @@
 
 status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
                                        const sp<IGraphicBufferProducer>& producer,
-                                       ISurfaceComposer::Rotation rotation) {
+                                       const Rect& sourceCrop, float frameScale) {
     ATRACE_CALL();
 
     class LayerRenderArea : public RenderArea {
     public:
-        LayerRenderArea(const sp<Layer>& layer, ISurfaceComposer::Rotation rotation)
-              : RenderArea(layer->getCurrentState().active.h, layer->getCurrentState().active.w,
-                           rotation),
-                mLayer(layer) {}
+        LayerRenderArea(const sp<Layer>& layer, const Rect crop, int32_t reqWidth,
+            int32_t reqHeight)
+              : RenderArea(reqHeight, reqWidth), mLayer(layer), mCrop(crop) {}
         const Transform& getTransform() const override {
             // Make the top level transform the inverse the transform and it's parent so it sets
             // the whole capture back to 0,0
@@ -4415,18 +4355,45 @@
         bool isSecure() const override { return false; }
         bool needsFiltering() const override { return false; }
 
-        Rect getSourceCrop() const override { return getBounds(); }
+        Rect getSourceCrop() const override {
+            if (mCrop.isEmpty()) {
+                return getBounds();
+            } else {
+                return mCrop;
+            }
+        }
         bool getWideColorSupport() const override { return false; }
         android_color_mode_t getActiveColorMode() const override { return HAL_COLOR_MODE_NATIVE; }
 
     private:
-        const sp<Layer>& mLayer;
+        const sp<Layer> mLayer;
+        const Rect mCrop;
     };
 
     auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
     auto parent = layerHandle->owner.promote();
 
-    LayerRenderArea renderArea(parent, rotation);
+    if (parent == nullptr || parent->isPendingRemoval()) {
+        ALOGE("captureLayers called with a removed parent");
+        return NAME_NOT_FOUND;
+    }
+
+    Rect crop(sourceCrop);
+    if (sourceCrop.width() <= 0) {
+        crop.left = 0;
+        crop.right = parent->getCurrentState().active.w;
+    }
+
+    if (sourceCrop.height() <= 0) {
+        crop.top = 0;
+        crop.bottom = parent->getCurrentState().active.h;
+    }
+
+    int32_t reqWidth = crop.width() * frameScale;
+    int32_t reqHeight = crop.height() * frameScale;
+
+    LayerRenderArea renderArea(parent, crop, reqWidth, reqHeight);
+
     auto traverseLayers = [parent](const LayerVector::Visitor& visitor) {
         parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
             if (!layer->isVisible()) {
@@ -4596,26 +4563,6 @@
     });
 }
 
-// A simple RAII class that holds an EGLImage and destroys it either:
-//   a) When the destroy() method is called
-//   b) When the object goes out of scope
-class ImageHolder {
-public:
-    ImageHolder(EGLDisplay display, EGLImageKHR image) : mDisplay(display), mImage(image) {}
-    ~ImageHolder() { destroy(); }
-
-    void destroy() {
-        if (mImage != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mDisplay, mImage);
-            mImage = EGL_NO_IMAGE_KHR;
-        }
-    }
-
-private:
-    const EGLDisplay mDisplay;
-    EGLImageKHR mImage;
-};
-
 status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea,
                                                  TraverseLayersFunction traverseLayers,
                                                  ANativeWindowBuffer* buffer,
@@ -4634,23 +4581,11 @@
         return PERMISSION_DENIED;
     }
 
-    int syncFd = -1;
-    // create an EGLImage from the buffer so we can later
-    // turn it into a texture
-    EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT,
-            EGL_NATIVE_BUFFER_ANDROID, buffer, NULL);
-    if (image == EGL_NO_IMAGE_KHR) {
-        return BAD_VALUE;
-    }
-
-    // This will automatically destroy the image if we return before calling its destroy method
-    ImageHolder imageHolder(mEGLDisplay, image);
-
     // this binds the given EGLImage as a framebuffer for the
     // duration of this scope.
-    RenderEngine::BindImageAsFramebuffer imageBond(getRenderEngine(), image);
-    if (imageBond.getStatus() != NO_ERROR) {
-        ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES error while taking screenshot");
+    RenderEngine::BindNativeBufferAsFramebuffer bufferBond(getRenderEngine(), buffer);
+    if (bufferBond.getStatus() != NO_ERROR) {
+        ALOGE("got ANWB binding error while taking screenshot");
         return INVALID_OPERATION;
     }
 
@@ -4660,43 +4595,7 @@
     // dependent on the context's EGLConfig.
     renderScreenImplLocked(renderArea, traverseLayers, true, useIdentityTransform);
 
-    // Attempt to create a sync khr object that can produce a sync point. If that
-    // isn't available, create a non-dupable sync object in the fallback path and
-    // wait on it directly.
-    EGLSyncKHR sync = EGL_NO_SYNC_KHR;
-    if (!DEBUG_SCREENSHOTS) {
-       sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
-       // native fence fd will not be populated until flush() is done.
-       getRenderEngine().flush();
-    }
-
-    if (sync != EGL_NO_SYNC_KHR) {
-        // get the sync fd
-        syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
-        if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
-            ALOGW("captureScreen: failed to dup sync khr object");
-            syncFd = -1;
-        }
-        eglDestroySyncKHR(mEGLDisplay, sync);
-    } else {
-        // fallback path
-        sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
-        if (sync != EGL_NO_SYNC_KHR) {
-            EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync,
-                EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, 2000000000 /*2 sec*/);
-            EGLint eglErr = eglGetError();
-            if (result == EGL_TIMEOUT_EXPIRED_KHR) {
-                ALOGW("captureScreen: fence wait timed out");
-            } else {
-                ALOGW_IF(eglErr != EGL_SUCCESS,
-                        "captureScreen: error waiting on EGL fence: %#x", eglErr);
-            }
-            eglDestroySyncKHR(mEGLDisplay, sync);
-        } else {
-            ALOGW("captureScreen: error creating EGL fence: %#x", eglGetError());
-        }
-    }
-    *outSyncFd = syncFd;
+    *outSyncFd = getRenderEngine().flush(DEBUG_SCREENSHOTS);
 
     if (DEBUG_SCREENSHOTS) {
         const auto reqWidth = renderArea.getReqWidth();
@@ -4708,8 +4607,6 @@
         delete [] pixels;
     }
 
-    // destroy our image
-    imageHolder.destroy();
     return NO_ERROR;
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 386d42b..d991f68 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -21,8 +21,6 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <EGL/egl.h>
-
 /*
  * NOTE: Make sure this file doesn't include  anything from <gl/ > or <gl2/ >
  */
@@ -298,7 +296,7 @@
             bool useIdentityTransform, ISurfaceComposer::Rotation rotation);
     virtual status_t captureLayers(const sp<IBinder>& parentHandle,
                                    const sp<IGraphicBufferProducer>& producer,
-                                   ISurfaceComposer::Rotation rotation);
+                                   const Rect& sourceCrop, float frameScale);
     virtual status_t getDisplayStats(const sp<IBinder>& display,
             DisplayStatInfo* stats);
     virtual status_t getDisplayConfigs(const sp<IBinder>& display,
@@ -549,7 +547,7 @@
 
     // compose surfaces for display hw. this fails if using GL and the surface
     // has been destroyed and is no longer valid.
-    bool doComposeSurfaces(const sp<const DisplayDevice>& displayDevice, const Region& dirty);
+    bool doComposeSurfaces(const sp<const DisplayDevice>& displayDevice);
 
     void postFramebuffer();
     void drawWormhole(const sp<const DisplayDevice>& displayDevice, const Region& region) const;
@@ -663,7 +661,7 @@
     const std::string mHwcServiceName; // "default" for real use, something else for testing.
 
     // constant members (no synchronization needed for access)
-    RenderEngine* mRenderEngine;
+    std::unique_ptr<RenderEngine> mRenderEngine;
     nsecs_t mBootTime;
     bool mGpuToCpuSupported;
     sp<EventThread> mEventThread;
@@ -671,8 +669,6 @@
     sp<EventThread> mInjectorEventThread;
     sp<InjectVSyncSource> mVSyncInjector;
     sp<EventControlThread> mEventControlThread;
-    EGLContext mEGLContext;
-    EGLDisplay mEGLDisplay;
     sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
 
     // Can only accessed from the main thread, these members
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 943fafd..39aef81 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -276,15 +276,15 @@
 
 class CaptureLayer {
 public:
-    static void captureScreen(std::unique_ptr<CaptureLayer>* sc, sp<IBinder>& parentHandle) {
+    static void captureScreen(std::unique_ptr<CaptureLayer>* sc, sp<IBinder>& parentHandle,
+                              Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
         sp<IGraphicBufferProducer> producer;
         sp<IGraphicBufferConsumer> consumer;
         BufferQueue::createBufferQueue(&producer, &consumer);
         sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
         sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
         SurfaceComposerClient::Transaction().apply(true);
-        ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, producer));
+        ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, producer, crop, frameScale));
         *sc = std::make_unique<CaptureLayer>(cpuConsumer);
     }
 
@@ -2412,4 +2412,89 @@
     mCapture->checkPixel(4, 4, 50, 50, 50);
 }
 
-} // namespace android
+TEST_F(ScreenCaptureTest, CaptureCrop) {
+    sp<SurfaceControl> redLayer = mComposerClient->createSurface(
+        String8("Red surface"),
+        60, 60, PIXEL_FORMAT_RGBA_8888, 0);
+    sp<SurfaceControl> blueLayer = mComposerClient->createSurface(
+        String8("Blue surface"),
+        30, 30, PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+
+    fillSurfaceRGBA8(redLayer, 255, 0, 0);
+    fillSurfaceRGBA8(blueLayer, 0, 0, 255);
+
+    SurfaceComposerClient::Transaction()
+        .setLayer(redLayer, INT32_MAX-1)
+        .show(redLayer)
+        .show(blueLayer)
+        .apply(true);
+
+    auto redLayerHandle = redLayer->getHandle();
+
+    // Capturing full screen should have both red and blue are visible.
+    CaptureLayer::captureScreen(&mCapture, redLayerHandle);
+    mCapture->checkPixel(29, 29, 0, 0, 255);
+    mCapture->checkPixel(30, 30, 255, 0, 0);
+
+    Rect crop = Rect(0, 0, 30, 30);
+    CaptureLayer::captureScreen(&mCapture, redLayerHandle, crop);
+    // Capturing the cropped screen, cropping out the shown red area, should leave only the blue
+    // area visible.
+    mCapture->checkPixel(29, 29, 0, 0, 255);
+    mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureSize) {
+    sp<SurfaceControl> redLayer = mComposerClient->createSurface(
+        String8("Red surface"),
+        60, 60, PIXEL_FORMAT_RGBA_8888, 0);
+    sp<SurfaceControl> blueLayer = mComposerClient->createSurface(
+        String8("Blue surface"),
+        30, 30, PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+
+    fillSurfaceRGBA8(redLayer, 255, 0, 0);
+    fillSurfaceRGBA8(blueLayer, 0, 0, 255);
+
+    SurfaceComposerClient::Transaction()
+        .setLayer(redLayer, INT32_MAX-1)
+        .show(redLayer)
+        .show(blueLayer)
+        .apply(true);
+
+    auto redLayerHandle = redLayer->getHandle();
+
+    // Capturing full screen should have both red and blue are visible.
+    CaptureLayer::captureScreen(&mCapture, redLayerHandle);
+    mCapture->checkPixel(29, 29, 0, 0, 255);
+    mCapture->checkPixel(30, 30, 255, 0, 0);
+
+    CaptureLayer::captureScreen(&mCapture, redLayerHandle, Rect::EMPTY_RECT, 0.5);
+    // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
+    mCapture->checkPixel(14, 14, 0, 0, 255);
+    mCapture->checkPixel(15, 15, 255, 0, 0);
+    mCapture->checkPixel(29, 29, 255, 0, 0);
+    mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
+    sp<SurfaceControl> redLayer = mComposerClient->createSurface(
+        String8("Red surface"),
+        60, 60, PIXEL_FORMAT_RGBA_8888, 0);
+
+    fillSurfaceRGBA8(redLayer, 255, 0, 0);
+
+    auto redLayerHandle = redLayer->getHandle();
+    mComposerClient->destroySurface(redLayerHandle);
+    SurfaceComposerClient::Transaction().apply(true);
+
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    sp<CpuConsumer> cpuConsumer = new CpuConsumer(consumer, 1);
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+    // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
+    ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, producer, Rect::EMPTY_RECT, 1.0));
+}
+
+}
\ No newline at end of file