Merge "SurfaceFlinger: fix flakiness in IdleTimerTest"
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index 768cb4f..ddae9ea 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -127,7 +127,7 @@
     if (ds_ != nullptr) {
         MYLOGE("Error! There is already a bugreport in progress. Returning.");
         if (listener != nullptr) {
-            listener->onError(IDumpstateListener::BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN);
+            listener->onError(IDumpstateListener::BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
         }
         return exception(binder::Status::EX_SERVICE_SPECIFIC,
                          "There is already a bugreport in progress");
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index 42858e0..ea1e467 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -50,7 +50,7 @@
     const int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4;
 
     /* There is currently a bugreport running. The caller should try again later. */
-    const int BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN = 5;
+    const int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5;
 
     /**
      * Called on an error condition with one of the error codes listed above.
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 60a7de2..03a15bb 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -766,6 +766,17 @@
                ZipWriter::ErrorCodeString(err));
         return UNKNOWN_ERROR;
     }
+    bool finished_entry = false;
+    auto finish_entry = [this, &finished_entry] {
+        if (!finished_entry) {
+            // This should only be called when we're going to return an earlier error,
+            // which would've been logged. This may imply the file is already corrupt
+            // and any further logging from FinishEntry is more likely to mislead than
+            // not.
+            this->zip_writer_->FinishEntry();
+        }
+    };
+    auto scope_guard = android::base::make_scope_guard(finish_entry);
     auto start = std::chrono::steady_clock::now();
     auto end = start + timeout;
     struct pollfd pfd = {fd, POLLIN};
@@ -782,11 +793,11 @@
 
             int rc = TEMP_FAILURE_RETRY(poll(&pfd, 1, time_left_ms()));
             if (rc < 0) {
-                MYLOGE("Error in poll while adding from fd to zip entry %s:%s", entry_name.c_str(),
-                       strerror(errno));
+                MYLOGE("Error in poll while adding from fd to zip entry %s:%s\n",
+                       entry_name.c_str(), strerror(errno));
                 return -errno;
             } else if (rc == 0) {
-                MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms",
+                MYLOGE("Timed out adding from fd to zip entry %s:%s Timeout:%lldms\n",
                        entry_name.c_str(), strerror(errno), timeout.count());
                 return TIMED_OUT;
             }
@@ -807,6 +818,7 @@
     }
 
     err = zip_writer_->FinishEntry();
+    finished_entry = true;
     if (err != 0) {
         MYLOGE("zip_writer_->FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
         return UNKNOWN_ERROR;
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 555badd..fc3642c 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -475,7 +475,7 @@
     EXPECT_FALSE(status.isOk());
     WaitTillExecutionComplete(listener2.get());
     EXPECT_EQ(listener2->getErrorCode(),
-              IDumpstateListener::BUGREPORT_ERROR_CONCURRENT_BUGREPORTS_FORBIDDEN);
+              IDumpstateListener::BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS);
 
     // Meanwhile the first call works as expected. Service should not die in this case.
     WaitTillExecutionComplete(listener1.get());
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 528e43d..4bc0e1d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -108,6 +108,8 @@
         if (log_only_) {
             MYLOGD("Duration of '%s': %.3fs\n", title_.c_str(), (float)elapsed / NANOS_PER_SEC);
         } else {
+            // TODO(124089395): Remove or rewrite when bugreport latency is fixed.
+            MYLOGD("Duration of '%s': %.3fs\n", title_.c_str(), (float)elapsed / NANOS_PER_SEC);
             // Use "Yoda grammar" to make it easier to grep|sort sections.
             printf("------ %.3fs was the duration of '%s' ------\n", (float)elapsed / NANOS_PER_SEC,
                    title_.c_str());
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index e33b2a8..b60bbc0 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -35,6 +35,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
 
     product_variables: {
@@ -227,6 +228,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
 }
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index acc0647..f523725 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -45,6 +45,7 @@
 #include <private/android_filesystem_config.h>
 #include <processgroup/sched_policy.h>
 #include <selinux/android.h>
+#include <server_configurable_flags/get_flags.h>
 #include <system/thread_defs.h>
 
 #include "dexopt.h"
@@ -260,6 +261,13 @@
   return "";
 }
 
+// Namespace for Android Runtime flags applied during boot time.
+static const char* RUNTIME_NATIVE_BOOT_NAMESPACE = "runtime_native_boot";
+// Feature flag name for running the JIT in Zygote experiment, b/119800099.
+static const char* ENABLE_APEX_IMAGE = "enable_apex_image";
+// Location of the apex image.
+static const char* kApexImage = "/system/framework/apex.art";
+
 class RunDex2Oat : public ExecVHelper {
   public:
     RunDex2Oat(int zip_fd,
@@ -293,6 +301,14 @@
                 : "dalvik.vm.boot-dex2oat-threads";
         std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s");
 
+        std::string bootclasspath;
+        char* dex2oat_bootclasspath = getenv("DEX2OATBOOTCLASSPATH");
+        if (dex2oat_bootclasspath != nullptr) {
+            bootclasspath = StringPrintf("-Xbootclasspath:%s", dex2oat_bootclasspath);
+        }
+        // If DEX2OATBOOTCLASSPATH is not in the environment, dex2oat is going to query
+        // BOOTCLASSPATH.
+
         const std::string dex2oat_isa_features_key =
                 StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
         std::string instruction_set_features_arg =
@@ -352,7 +368,16 @@
         bool generate_minidebug_info = kEnableMinidebugInfo &&
                 GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
 
-        std::string boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
+        std::string boot_image;
+        std::string use_apex_image =
+            server_configurable_flags::GetServerConfigurableFlag(RUNTIME_NATIVE_BOOT_NAMESPACE,
+                                                                 ENABLE_APEX_IMAGE,
+                                                                 /*default_value=*/ "");
+        if (use_apex_image == "true") {
+          boot_image = StringPrintf("-Ximage:%s", kApexImage);
+        } else {
+          boot_image = MapPropertyToArg("dalvik.vm.boot-image", "-Ximage:%s");
+        }
 
         // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
         // use arraysize instead.
@@ -440,6 +465,7 @@
         AddArg(instruction_set_features_arg);
 
         AddRuntimeArg(boot_image);
+        AddRuntimeArg(bootclasspath);
         AddRuntimeArg(dex2oat_Xms_arg);
         AddRuntimeArg(dex2oat_Xmx_arg);
 
@@ -1961,11 +1987,6 @@
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
 
-        // Clear BOOTCLASSPATH.
-        // Let dex2oat use the BCP from boot image, excluding updatable BCP
-        // modules for AOT to avoid app recompilation after their upgrades.
-        unsetenv("BOOTCLASSPATH");
-
         SetDex2OatScheduling(boot_complete);
         if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
             PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp
index b3a6daf..f52c2e7 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -44,6 +44,8 @@
 static constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under
                                                                   // ANDROID_DATA
 
+static constexpr const char* STAGING_SUBDIR = "pkg_staging/"; // sub-directory under ANDROID_DATA
+
 std::string android_app_dir;
 std::string android_app_ephemeral_dir;
 std::string android_app_lib_dir;
@@ -54,6 +56,7 @@
 std::string android_mnt_expand_dir;
 std::string android_profiles_dir;
 std::string android_root_dir;
+std::string android_staging_dir;
 
 std::vector<std::string> android_system_dirs;
 
@@ -110,6 +113,9 @@
     // Get the android profiles directory.
     android_profiles_dir = android_data_dir + PROFILES_SUBDIR;
 
+    // Get the android session staging directory.
+    android_staging_dir = android_data_dir + STAGING_SUBDIR;
+
     // Take note of the system and vendor directories.
     android_system_dirs.clear();
     android_system_dirs.push_back(android_root_dir + APP_SUBDIR);
diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h
index 633e33b..a88a86e 100644
--- a/cmds/installd/globals.h
+++ b/cmds/installd/globals.h
@@ -38,6 +38,7 @@
 extern std::string android_mnt_expand_dir;
 extern std::string android_profiles_dir;
 extern std::string android_root_dir;
+extern std::string android_staging_dir;
 
 extern std::vector<std::string> android_system_dirs;
 
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 9c9db0f..1ed49a0 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -31,6 +31,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "libdiskusage",
@@ -54,6 +55,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "libdiskusage",
@@ -77,6 +79,7 @@
         "libprocessgroup",
         "libselinux",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "libdiskusage",
@@ -96,6 +99,7 @@
         "libbase",
         "libcutils",
         "libutils",
+        "server_configurable_flags",
     ],
     static_libs: [
         "liblog",
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 52ca0df..da097db 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -928,6 +928,8 @@
 static int validate_apk_path_internal(const std::string& path, int maxSubdirs) {
     if (validate_path(android_app_dir, path, maxSubdirs) == 0) {
         return 0;
+    } else if (validate_path(android_staging_dir, path, maxSubdirs) == 0) {
+        return 0;
     } else if (validate_path(android_app_private_dir, path, maxSubdirs) == 0) {
         return 0;
     } else if (validate_path(android_app_ephemeral_dir, path, maxSubdirs) == 0) {
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsAtoms.h b/libs/graphicsenv/include/graphicsenv/GpuStatsAtoms.h
new file mode 100644
index 0000000..f8b0ad7
--- /dev/null
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsAtoms.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+namespace android {
+
+struct GpuStatsGlobalAtom {
+    std::string driverPackageName = "";
+    std::string driverVersionName = "";
+    uint64_t driverVersionCode = 0;
+    int64_t driverBuildTime = 0;
+    int32_t glLoadingCount = 0;
+    int32_t glLoadingFailureCount = 0;
+    int32_t vkLoadingCount = 0;
+    int32_t vkLoadingFailureCount = 0;
+};
+
+struct GpuStatsAppAtom {
+    std::string appPackageName = "";
+    uint64_t driverVersionCode = 0;
+    std::vector<int64_t> glDriverLoadingTime = {};
+    std::vector<int64_t> vkDriverLoadingTime = {};
+};
+
+} // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 09f1ed7..d2f2539 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -100,7 +100,7 @@
                                    const ui::Dataspace reqDataspace,
                                    const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                                   ISurfaceComposer::Rotation rotation) {
+                                   ISurfaceComposer::Rotation rotation, bool captureSecureLayers) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
@@ -111,6 +111,7 @@
         data.writeUint32(reqHeight);
         data.writeInt32(static_cast<int32_t>(useIdentityTransform));
         data.writeInt32(static_cast<int32_t>(rotation));
+        data.writeInt32(static_cast<int32_t>(captureSecureLayers));
         status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
         if (result != NO_ERROR) {
             ALOGE("captureScreen failed to transact: %d", result);
@@ -910,10 +911,11 @@
             uint32_t reqHeight = data.readUint32();
             bool useIdentityTransform = static_cast<bool>(data.readInt32());
             int32_t rotation = data.readInt32();
+            bool captureSecureLayers = static_cast<bool>(data.readInt32());
 
             status_t res = captureScreen(display, &outBuffer, reqDataspace, reqPixelFormat,
                                          sourceCrop, reqWidth, reqHeight, useIdentityTransform,
-                                         static_cast<ISurfaceComposer::Rotation>(rotation));
+                                         static_cast<ISurfaceComposer::Rotation>(rotation), captureSecureLayers);
             reply->writeInt32(res);
             if (res == NO_ERROR) {
                 reply->write(*outBuffer);
diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp
index 745433a..04d2871 100644
--- a/libs/gui/LayerMetadata.cpp
+++ b/libs/gui/LayerMetadata.cpp
@@ -31,10 +31,23 @@
 
 LayerMetadata::LayerMetadata(LayerMetadata&& other) = default;
 
-void LayerMetadata::merge(const LayerMetadata& other) {
+bool LayerMetadata::merge(const LayerMetadata& other, bool eraseEmpty) {
+    bool changed = false;
     for (const auto& entry : other.mMap) {
-        mMap[entry.first] = entry.second;
+        auto it = mMap.find(entry.first);
+        if (it != mMap.cend() && it->second != entry.second) {
+            if (eraseEmpty && entry.second.empty()) {
+                mMap.erase(it);
+            } else {
+                it->second = entry.second;
+            }
+            changed = true;
+        } else if (it == mMap.cend() && !entry.second.empty()) {
+            mMap[entry.first] = entry.second;
+            changed = true;
+        }
     }
+    return changed;
 }
 
 status_t LayerMetadata::writeToParcel(Parcel* parcel) const {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 55a2ae5..d583e6d 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1475,18 +1475,27 @@
 status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
                                    const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                                   uint32_t rotation, sp<GraphicBuffer>* outBuffer) {
+                                   uint32_t rotation, bool captureSecureLayers, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
     status_t ret = s->captureScreen(display, outBuffer, reqDataSpace, reqPixelFormat, sourceCrop,
-                                    reqWidth, reqHeight, useIdentityTransform,
-                                    static_cast<ISurfaceComposer::Rotation>(rotation));
+            reqWidth, reqHeight, useIdentityTransform,
+            static_cast<ISurfaceComposer::Rotation>(rotation),
+            captureSecureLayers);
     if (ret != NO_ERROR) {
         return ret;
     }
     return ret;
 }
 
+status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                   uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                                   uint32_t rotation, sp<GraphicBuffer>* outBuffer) {
+    return capture(display, reqDataSpace, reqPixelFormat, sourceCrop, reqWidth,
+            reqHeight, useIdentityTransform, rotation, false, outBuffer);
+}
+
 status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
                                          const ui::Dataspace reqDataSpace,
                                          const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 0d5b767..eedd5f5 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -209,7 +209,8 @@
                                    const ui::Dataspace reqDataspace,
                                    const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                                   Rotation rotation = eRotateNone) = 0;
+                                   Rotation rotation = eRotateNone,
+                                   bool captureSecureLayers = false) = 0;
     /**
      * Capture the specified screen. This requires READ_FRAME_BUFFER
      * permission.  This function will fail if there is a secure window on
diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h
index 3ae10e4..47f0ced 100644
--- a/libs/gui/include/gui/LayerMetadata.h
+++ b/libs/gui/include/gui/LayerMetadata.h
@@ -34,7 +34,9 @@
     LayerMetadata& operator=(const LayerMetadata& other);
     LayerMetadata& operator=(LayerMetadata&& other);
 
-    void merge(const LayerMetadata& other);
+    // Merges other into this LayerMetadata. If eraseEmpty is true, any entries in
+    // in this whose keys are paired with empty values in other will be erased.
+    bool merge(const LayerMetadata& other, bool eraseEmpty = false);
 
     status_t writeToParcel(Parcel* parcel) const override;
     status_t readFromParcel(const Parcel* parcel) override;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 3c52b10..4621a34 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -460,6 +460,10 @@
     static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
                             const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                             uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                            uint32_t rotation, bool captureSecureLayers, sp<GraphicBuffer>* outBuffer);
+    static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
+                            const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                            uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
                             uint32_t rotation, sp<GraphicBuffer>* outBuffer);
     static status_t captureLayers(const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index a5b87ec..ab6dcaa 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -23,6 +23,7 @@
         "IGraphicBufferProducer_test.cpp",
         "Malicious.cpp",
         "MultiTextureConsumer_test.cpp",
+        "RegionSampling_test.cpp",
         "StreamSplitter_test.cpp",
         "SurfaceTextureClient_test.cpp",
         "SurfaceTextureFBO_test.cpp",
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
new file mode 100644
index 0000000..5652c0c
--- /dev/null
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <thread>
+
+#include <binder/ProcessState.h>
+#include <gui/DisplayEventReceiver.h>
+#include <gui/IRegionSamplingListener.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <utils/Looper.h>
+
+using namespace std::chrono_literals;
+
+namespace android::test {
+
+struct ChoreographerSync {
+    ChoreographerSync(DisplayEventReceiver& receiver) : receiver_(receiver) {}
+    ~ChoreographerSync() = default;
+
+    void notify() const {
+        std::unique_lock<decltype(mutex_)> lk(mutex_);
+
+        auto check_event = [](auto const& ev) -> bool {
+            return ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+        };
+        DisplayEventReceiver::Event ev_;
+        int evs = receiver_.getEvents(&ev_, 1);
+        auto vsync_event_found = check_event(ev_);
+        while (evs) {
+            evs = receiver_.getEvents(&ev_, 1);
+            vsync_event_found |= check_event(ev_);
+        }
+
+        if (vsync_event_found) {
+            notification_arrived_ = true;
+            cv_.notify_all();
+        }
+    }
+
+    void wait_vsync_notify() const {
+        std::unique_lock<decltype(mutex_)> lk(mutex_);
+        cv_.wait(lk, [this] { return notification_arrived_; });
+        notification_arrived_ = false;
+    }
+
+private:
+    ChoreographerSync(ChoreographerSync const&) = delete;
+    ChoreographerSync& operator=(ChoreographerSync const&) = delete;
+
+    std::mutex mutable mutex_;
+    std::condition_variable mutable cv_;
+    bool mutable notification_arrived_ = false;
+    DisplayEventReceiver& receiver_;
+};
+
+struct ChoreographerSim {
+    static std::unique_ptr<ChoreographerSim> make() {
+        auto receiver = std::make_unique<DisplayEventReceiver>();
+        if (!receiver || receiver->initCheck() == NO_INIT) {
+            ALOGE("No display reciever");
+            return nullptr;
+        }
+        return std::unique_ptr<ChoreographerSim>(new ChoreographerSim(std::move(receiver)));
+    }
+
+    ~ChoreographerSim() {
+        poll_ = false;
+        looper->wake();
+        choreographer_thread_.join();
+    }
+
+    void request_render_wait(std::function<void()> const& render_fn) {
+        display_event_receiver_->requestNextVsync();
+        choreographer_.wait_vsync_notify();
+        render_fn();
+
+        // Purpose is to make sure that the content is latched by the time we sample.
+        // Waiting one vsync after queueing could still race with vsync, so wait for two, after
+        // which the content is pretty reliably on screen.
+        display_event_receiver_->requestNextVsync();
+        choreographer_.wait_vsync_notify();
+        display_event_receiver_->requestNextVsync();
+        choreographer_.wait_vsync_notify();
+    }
+
+private:
+    ChoreographerSim(std::unique_ptr<DisplayEventReceiver> receiver)
+          : display_event_receiver_{std::move(receiver)},
+            choreographer_{*display_event_receiver_},
+            looper{new Looper(false)} {
+        choreographer_thread_ = std::thread([this] {
+            auto vsync_notify_fd = display_event_receiver_->getFd();
+            looper->addFd(vsync_notify_fd, 0, Looper::EVENT_INPUT,
+                          [](int /*fd*/, int /*events*/, void* data) -> int {
+                              if (!data) return 0;
+                              reinterpret_cast<ChoreographerSync*>(data)->notify();
+                              return 1;
+                          },
+                          const_cast<void*>(reinterpret_cast<void const*>(&choreographer_)));
+
+            while (poll_) {
+                auto const poll_interval =
+                        std::chrono::duration_cast<std::chrono::milliseconds>(1s).count();
+                auto rc = looper->pollOnce(poll_interval);
+                if ((rc != Looper::POLL_CALLBACK) && (rc != Looper::POLL_WAKE))
+                    ALOGW("Vsync Looper returned: %i\n", rc);
+            }
+        });
+    }
+
+    ChoreographerSim(ChoreographerSim const&) = delete;
+    ChoreographerSim& operator=(ChoreographerSim const&) = delete;
+
+    std::unique_ptr<DisplayEventReceiver> const display_event_receiver_;
+    ChoreographerSync const choreographer_;
+    sp<Looper> looper;
+    std::thread choreographer_thread_;
+    std::atomic<bool> poll_{true};
+};
+
+struct Listener : BnRegionSamplingListener {
+    void onSampleCollected(float medianLuma) override {
+        std::unique_lock<decltype(mutex)> lk(mutex);
+        received = true;
+        mLuma = medianLuma;
+        cv.notify_all();
+    };
+    bool wait_event(std::chrono::milliseconds timeout) {
+        std::unique_lock<decltype(mutex)> lk(mutex);
+        return cv.wait_for(lk, timeout, [this] { return received; });
+    }
+
+    float luma() {
+        std::unique_lock<decltype(mutex)> lk(mutex);
+        return mLuma;
+    }
+
+    void reset() {
+        std::unique_lock<decltype(mutex)> lk(mutex);
+        received = false;
+    }
+
+private:
+    std::condition_variable cv;
+    std::mutex mutex;
+    bool received = false;
+    float mLuma = -0.0f;
+};
+
+// Hoisted to TestSuite setup to avoid flake in test (b/124675919)
+std::unique_ptr<ChoreographerSim> gChoreographerSim = nullptr;
+
+struct RegionSamplingTest : ::testing::Test {
+protected:
+    RegionSamplingTest() { ProcessState::self()->startThreadPool(); }
+
+    static void SetUpTestSuite() {
+        gChoreographerSim = ChoreographerSim::make();
+        ASSERT_NE(gChoreographerSim, nullptr);
+    }
+
+    void SetUp() override {
+        mSurfaceComposerClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mSurfaceComposerClient->initCheck());
+
+        mBackgroundLayer =
+                mSurfaceComposerClient->createSurface(String8("Background RegionSamplingTest"), 0,
+                                                      0, PIXEL_FORMAT_RGBA_8888,
+                                                      ISurfaceComposerClient::eFXSurfaceColor);
+        uint32_t layerPositionBottom = 0x7E000000;
+        SurfaceComposerClient::Transaction{}
+                .setLayer(mBackgroundLayer, layerPositionBottom)
+                .setPosition(mBackgroundLayer, 100, 100)
+                .setColor(mBackgroundLayer, half3{0.5, 0.5, 0.5})
+                .show(mBackgroundLayer)
+                .apply();
+
+        mContentLayer = mSurfaceComposerClient->createSurface(String8("Content RegionSamplingTest"),
+                                                              300, 300, PIXEL_FORMAT_RGBA_8888, 0);
+
+        SurfaceComposerClient::Transaction{}
+                .setLayer(mContentLayer, layerPositionBottom + 1)
+                .setPosition(mContentLayer, 100, 100)
+                .setColor(mContentLayer, half3{0.5, 0.5, 0.5})
+                .show(mContentLayer)
+                .apply();
+
+        mTopLayer = mSurfaceComposerClient->createSurface(String8("TopLayer RegionSamplingTest"), 0,
+                                                          0, PIXEL_FORMAT_RGBA_8888, 0);
+        SurfaceComposerClient::Transaction{}
+                .setLayer(mTopLayer, layerPositionBottom + 2)
+                .setPosition(mTopLayer, 0, 0)
+                .show(mBackgroundLayer)
+                .apply();
+    }
+
+    void fill_render(uint32_t rgba_value) {
+        auto surface = mContentLayer->getSurface();
+        ANativeWindow_Buffer outBuffer;
+        status_t status = surface->lock(&outBuffer, NULL);
+        ASSERT_EQ(status, android::OK);
+        auto b = reinterpret_cast<uint32_t*>(outBuffer.bits);
+        for (auto i = 0; i < outBuffer.height; i++) {
+            for (auto j = 0; j < outBuffer.width; j++) {
+                b[j] = rgba_value;
+            }
+            b += outBuffer.stride;
+        }
+
+        gChoreographerSim->request_render_wait([&surface] { surface->unlockAndPost(); });
+    }
+
+    sp<SurfaceComposerClient> mSurfaceComposerClient;
+    sp<SurfaceControl> mBackgroundLayer;
+    sp<SurfaceControl> mContentLayer;
+    sp<SurfaceControl> mTopLayer;
+
+    uint32_t const rgba_green = 0xFF00FF00;
+    float const luma_green = 0.7152;
+    uint32_t const rgba_blue = 0xFFFF0000;
+    float const luma_blue = 0.0722;
+    float const error_margin = 0.01;
+    float const luma_gray = 0.50;
+};
+
+TEST_F(RegionSamplingTest, CollectsLuma) {
+    fill_render(rgba_green);
+
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<Listener> listener = new Listener();
+    const Rect sampleArea{100, 100, 200, 200};
+    composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+
+    EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+    EXPECT_NEAR(listener->luma(), luma_green, error_margin);
+
+    composer->removeRegionSamplingListener(listener);
+}
+
+TEST_F(RegionSamplingTest, CollectsChangingLuma) {
+    fill_render(rgba_green);
+
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<Listener> listener = new Listener();
+    const Rect sampleArea{100, 100, 200, 200};
+    composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+
+    EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+    EXPECT_NEAR(listener->luma(), luma_green, error_margin);
+
+    listener->reset();
+
+    fill_render(rgba_blue);
+    EXPECT_TRUE(listener->wait_event(300ms))
+            << "timed out waiting for 2nd luma event to be received";
+    EXPECT_NEAR(listener->luma(), luma_blue, error_margin);
+
+    composer->removeRegionSamplingListener(listener);
+}
+
+TEST_F(RegionSamplingTest, CollectsLumaFromTwoRegions) {
+    fill_render(rgba_green);
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<Listener> greenListener = new Listener();
+    const Rect greenSampleArea{100, 100, 200, 200};
+    composer->addRegionSamplingListener(greenSampleArea, mTopLayer->getHandle(), greenListener);
+
+    sp<Listener> grayListener = new Listener();
+    const Rect graySampleArea{500, 100, 600, 200};
+    composer->addRegionSamplingListener(graySampleArea, mTopLayer->getHandle(), grayListener);
+
+    EXPECT_TRUE(grayListener->wait_event(300ms))
+            << "timed out waiting for luma event to be received";
+    EXPECT_NEAR(grayListener->luma(), luma_gray, error_margin);
+    EXPECT_TRUE(greenListener->wait_event(300ms))
+            << "timed out waiting for luma event to be received";
+    EXPECT_NEAR(greenListener->luma(), luma_green, error_margin);
+
+    composer->removeRegionSamplingListener(greenListener);
+    composer->removeRegionSamplingListener(grayListener);
+}
+
+} // namespace android::test
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index dae7736..7f1dc84 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -615,7 +615,8 @@
                            const ui::Dataspace /*reqDataspace*/,
                            const ui::PixelFormat /*reqPixelFormat*/, Rect /*sourceCrop*/,
                            uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
-                           bool /*useIdentityTransform*/, Rotation /*rotation*/) override {
+                           bool /*useIdentityTransform*/, Rotation /*rotation*/,
+                           bool /*captureSecureLayers*/) override {
         return NO_ERROR;
     }
     virtual status_t captureLayers(const sp<IBinder>& /*parentHandle*/,
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 0f7a1f0..e13b40e 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -59,6 +59,18 @@
 // far into the future.  This time is further bounded by 50% of the last time delta.
 static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS;
 
+/**
+ * System property for enabling / disabling touch resampling.
+ * Resampling extrapolates / interpolates the reported touch event coordinates to better
+ * align them to the VSYNC signal, thus resulting in smoother scrolling performance.
+ * Resampling is not needed (and should be disabled) on hardware that already
+ * has touch events triggered by VSYNC.
+ * Set to "1" to enable resampling (default).
+ * Set to "0" to disable resampling.
+ * Resampling is enabled by default.
+ */
+static const char* PROPERTY_RESAMPLING_ENABLED = "ro.input.resampling";
+
 template<typename T>
 inline static T min(const T& a, const T& b) {
     return a < b ? a : b;
@@ -545,18 +557,7 @@
 }
 
 bool InputConsumer::isTouchResamplingEnabled() {
-    char value[PROPERTY_VALUE_MAX];
-    int length = property_get("ro.input.noresample", value, nullptr);
-    if (length > 0) {
-        if (!strcmp("1", value)) {
-            return false;
-        }
-        if (strcmp("0", value)) {
-            ALOGD("Unrecognized property value for 'ro.input.noresample'.  "
-                    "Use '1' or '0'.");
-        }
-    }
-    return true;
+    return property_get_bool(PROPERTY_RESAMPLING_ENABLED, true);
 }
 
 status_t InputConsumer::consume(InputEventFactoryInterface* factory,
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 57ba2a2..ade931e 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -3,6 +3,7 @@
     name: "libinput_tests",
     srcs: [
         "InputChannel_test.cpp",
+        "InputDevice_test.cpp",
         "InputEvent_test.cpp",
         "InputPublisherAndConsumer_test.cpp",
         "InputWindow_test.cpp",
@@ -35,6 +36,7 @@
         "-O0",
         "-Wall",
         "-Werror",
+        "-Wextra",
     ],
     shared_libs: [
         "libinput",
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
new file mode 100644
index 0000000..c174ae9
--- /dev/null
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <gtest/gtest.h>
+#include <input/InputDevice.h>
+
+namespace android {
+
+// --- InputDeviceIdentifierTest ---
+
+TEST(InputDeviceIdentifierTest, getCanonicalName) {
+    InputDeviceIdentifier identifier;
+    identifier.name = "test device";
+    ASSERT_EQ(std::string("test_device"), identifier.getCanonicalName());
+
+    identifier.name = "deviceName-123 version_C!";
+    ASSERT_EQ(std::string("deviceName-123_version_C_"), identifier.getCanonicalName());
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/nativewindow/include/android/hdr_metadata.h b/libs/nativewindow/include/android/hdr_metadata.h
index 7e1313b..88772a9 100644
--- a/libs/nativewindow/include/android/hdr_metadata.h
+++ b/libs/nativewindow/include/android/hdr_metadata.h
@@ -33,6 +33,15 @@
  */
 
 /**
+ * HDR metadata standards that are supported by Android.
+ */
+enum AHdrMetadataType : uint32_t {
+    HDR10_SMPTE2086 = 1,
+    HDR10_CTA861_3 = 2,
+    HDR10PLUS_SEI = 3,
+};
+
+/**
  * Color is defined in CIE XYZ coordinates.
  */
 struct AColor_xy {
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 6dd7283..166c267 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -24,15 +24,16 @@
 namespace android {
 namespace renderengine {
 
-std::unique_ptr<impl::RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) {
+std::unique_ptr<impl::RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags,
+                                                         uint32_t imageCacheSize) {
     char prop[PROPERTY_VALUE_MAX];
     property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "gles");
     if (strcmp(prop, "gles") == 0) {
         ALOGD("RenderEngine GLES Backend");
-        return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags);
+        return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags, imageCacheSize);
     }
     ALOGE("UNKNOWN BackendType: %s, create GLES RenderEngine.", prop);
-    return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags);
+    return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags, imageCacheSize);
 }
 
 RenderEngine::~RenderEngine() = default;
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index e7ff9ab..5d0aa1e 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -37,6 +37,7 @@
 #include <sync/sync.h>
 #include <ui/ColorSpace.h>
 #include <ui/DebugUtils.h>
+#include <ui/GraphicBuffer.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
 #include <utils/KeyedVector.h>
@@ -225,7 +226,8 @@
     return err;
 }
 
-std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(int hwcFormat, uint32_t featureFlags) {
+std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(int hwcFormat, uint32_t featureFlags,
+                                                           uint32_t imageCacheSize) {
     // initialize EGL for the default display
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     if (!eglInitialize(display, nullptr, nullptr)) {
@@ -295,7 +297,8 @@
         case GLES_VERSION_2_0:
         case GLES_VERSION_3_0:
             engine = std::make_unique<GLESRenderEngine>(featureFlags, display, config, ctxt, dummy,
-                                                        protectedContext, protectedDummy);
+                                                        protectedContext, protectedDummy,
+                                                        imageCacheSize);
             break;
     }
 
@@ -351,7 +354,7 @@
 
 GLESRenderEngine::GLESRenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config,
                                    EGLContext ctxt, EGLSurface dummy, EGLContext protectedContext,
-                                   EGLSurface protectedDummy)
+                                   EGLSurface protectedDummy, uint32_t imageCacheSize)
       : renderengine::impl::RenderEngine(featureFlags),
         mEGLDisplay(display),
         mEGLConfig(config),
@@ -361,6 +364,7 @@
         mProtectedDummySurface(protectedDummy),
         mVpWidth(0),
         mVpHeight(0),
+        mFramebufferImageCacheSize(imageCacheSize),
         mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
@@ -428,6 +432,10 @@
 }
 
 GLESRenderEngine::~GLESRenderEngine() {
+    for (const auto& image : mFramebufferImageCache) {
+        eglDestroyImageKHR(mEGLDisplay, image.second);
+    }
+    mFramebufferImageCache.clear();
     eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
     eglTerminate(mEGLDisplay);
 }
@@ -785,6 +793,32 @@
     }
     return success;
 }
+EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer,
+                                                             bool isProtected) {
+    sp<GraphicBuffer> graphicBuffer = GraphicBuffer::from(nativeBuffer);
+    uint32_t bufferId = graphicBuffer->getId();
+    for (const auto& image : mFramebufferImageCache) {
+        if (image.first == bufferId) {
+            return image.second;
+        }
+    }
+    EGLint attributes[] = {
+            isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
+            isProtected ? EGL_TRUE : EGL_NONE,
+            EGL_NONE,
+    };
+    EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                                          nativeBuffer, attributes);
+    if (image != EGL_NO_IMAGE_KHR) {
+        if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) {
+            EGLImageKHR expired = mFramebufferImageCache.front().second;
+            mFramebufferImageCache.pop_front();
+            eglDestroyImageKHR(mEGLDisplay, expired);
+        }
+        mFramebufferImageCache.push_back({bufferId, image});
+    }
+    return image;
+}
 
 status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
                                       const std::vector<LayerSettings>& layers,
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index a86b4f5..e37c91d 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -21,16 +21,17 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <condition_variable>
+#include <deque>
 #include <mutex>
 #include <queue>
 #include <thread>
+#include <unordered_map>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <GLES2/gl2.h>
 #include <renderengine/RenderEngine.h>
 #include <renderengine/private/Description.h>
-#include <unordered_map>
 
 #define EGL_NO_CONFIG ((EGLConfig)0)
 
@@ -47,12 +48,14 @@
 
 class GLESRenderEngine : public impl::RenderEngine {
 public:
-    static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags);
+    static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags,
+                                                    uint32_t imageCacheSize);
     static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
 
     GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
                      EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy,
-                     EGLContext protectedContext, EGLSurface protectedDummy);
+                     EGLContext protectedContext, EGLSurface protectedDummy,
+                     uint32_t imageCacheSize);
     ~GLESRenderEngine() override;
 
     std::unique_ptr<Framebuffer> createFramebuffer() override;
@@ -87,6 +90,8 @@
     // internal to RenderEngine
     EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
     EGLConfig getEGLConfig() const { return mEGLConfig; }
+    // Creates an output image for rendering to
+    EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected);
 
 protected:
     Framebuffer* getFramebufferForDrawing() override;
@@ -176,6 +181,12 @@
     // If set to true, then enables tracing flush() and finish() to systrace.
     bool mTraceGpuCompletion = false;
     int32_t mFboHeight = 0;
+    // Maximum size of mFramebufferImageCache. If more images would be cached, then (approximately)
+    // the last recently used buffer should be kicked out.
+    uint32_t mFramebufferImageCacheSize = 0;
+
+    // Cache of output images, keyed by corresponding GraphicBuffer ID.
+    std::deque<std::pair<uint64_t, EGLImageKHR>> mFramebufferImageCache;
 
     // Current dataspace of layer being rendered
     ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN;
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index 0e3b405..c45598c 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -30,8 +30,8 @@
 namespace renderengine {
 namespace gl {
 
-GLFramebuffer::GLFramebuffer(const GLESRenderEngine& engine)
-      : mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) {
+GLFramebuffer::GLFramebuffer(GLESRenderEngine& engine)
+      : mEngine(engine), mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) {
     glGenTextures(1, &mTextureName);
     glGenFramebuffers(1, &mFramebufferName);
 }
@@ -39,26 +39,18 @@
 GLFramebuffer::~GLFramebuffer() {
     glDeleteFramebuffers(1, &mFramebufferName);
     glDeleteTextures(1, &mTextureName);
-    eglDestroyImageKHR(mEGLDisplay, mEGLImage);
 }
 
 bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) {
     ATRACE_CALL();
     if (mEGLImage != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(mEGLDisplay, mEGLImage);
         mEGLImage = EGL_NO_IMAGE_KHR;
         mBufferWidth = 0;
         mBufferHeight = 0;
     }
 
     if (nativeBuffer) {
-        EGLint attributes[] = {
-                isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
-                isProtected ? EGL_TRUE : EGL_NONE,
-                EGL_NONE,
-        };
-        mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-                                      nativeBuffer, attributes);
+        mEGLImage = mEngine.createFramebufferImageIfNeeded(nativeBuffer, isProtected);
         if (mEGLImage == EGL_NO_IMAGE_KHR) {
             return false;
         }
diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h
index 5043c59..1289fbf 100644
--- a/libs/renderengine/gl/GLFramebuffer.h
+++ b/libs/renderengine/gl/GLFramebuffer.h
@@ -32,7 +32,7 @@
 
 class GLFramebuffer : public renderengine::Framebuffer {
 public:
-    explicit GLFramebuffer(const GLESRenderEngine& engine);
+    explicit GLFramebuffer(GLESRenderEngine& engine);
     ~GLFramebuffer() override;
 
     bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) override;
@@ -43,6 +43,7 @@
     int32_t getBufferWidth() const { return mBufferWidth; }
 
 private:
+    GLESRenderEngine& mEngine;
     EGLDisplay mEGLDisplay;
     EGLImageKHR mEGLImage;
     uint32_t mTextureName, mFramebufferName;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 812d761..2a2b48f 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -65,7 +65,8 @@
         USE_HIGH_PRIORITY_CONTEXT = 1 << 1, // Use high priority context
     };
 
-    static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags);
+    static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags,
+                                                      uint32_t imageCacheSize);
 
     virtual ~RenderEngine() = 0;
 
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index f28f672..a2bbaff 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -210,7 +210,7 @@
 };
 
 std::unique_ptr<renderengine::RenderEngine> RenderEngineTest::sRE =
-        renderengine::RenderEngine::create(static_cast<int32_t>(ui::PixelFormat::RGBA_8888), 0);
+        renderengine::RenderEngine::create(static_cast<int32_t>(ui::PixelFormat::RGBA_8888), 0, 1);
 
 struct ColorSourceVariant {
     static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index 9fa58e2..da9bb49 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -90,6 +90,10 @@
 
 rm src/*.class
 
+# Add UnsupportedAppUsage.java to known sources.
+mkdir -p out/android/annotation
+cp ../../../../base/core/java/android/annotation/UnsupportedAppUsage.java out/android/annotation
+
 pushd out > /dev/null
 mkdir classes
 javac -d classes    android/opengl/EGL14.java \
@@ -109,7 +113,8 @@
                     android/opengl/GLES30.java \
                     android/opengl/GLES31.java \
                     android/opengl/GLES31Ext.java \
-                    android/opengl/GLES32.java
+                    android/opengl/GLES32.java \
+                    android/annotation/UnsupportedAppUsage.java
 popd > /dev/null
 JAVA_RESULT=$?
 if [ $JAVA_RESULT -ne 0 ]; then
@@ -142,7 +147,7 @@
             echo
             SAID_PLEASE=1
         fi
-        echo "    cp $2/$3 $1"
+        echo "    cp $2/$3 $1/$3"
         echo "    (cd $1; git add $3)"
         KEEP_GENERATED=1
     fi
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 6697189..9c80212 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -775,6 +775,19 @@
         }
     }
 
+    String getJniDefaultReturn(JType jType) {
+        if (jType.isPrimitive()) {
+            String baseType = jType.getBaseType();
+            if (baseType.equals("boolean")) {
+                return "JNI_FALSE";
+            } else {
+                return "(" + getJniType(jType) + ")0";
+            }
+        } else {
+            return "nullptr";
+        }
+    }
+
     String getJniMangledName(String name) {
         name = name.replaceAll("_", "_1");
         name = name.replaceAll(";", "_2");
@@ -943,15 +956,15 @@
                         "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
             out.println(indent +
                         "    \"" + cfunc.getName() + "\");");
-            if (!isVoid) {
-                String retval = getErrorReturnValue(cfunc);
+            if (isVoid) {
+                out.println(indent + "return;");
+            } else {
                 if (cfunc.getType().isEGLHandle()) {
                     String baseType = cfunc.getType().getBaseType().toLowerCase();
-                    out.println(indent +
-                                "return toEGLHandle(_env, " + baseType + "Class, " +
-                                baseType + "Constructor, " + retval + ");");
+                    out.println(indent + indent + "return nullptr;");
                 } else {
-                    out.println(indent + "return " + retval + ";");
+                    out.println(indent + indent + "return " +
+                                getJniDefaultReturn(jfunc.getType()) + ";");
                 }
             }
             out.println("}");
@@ -1595,8 +1608,17 @@
             out.println(indent + "if (_exception) {");
             out.println(indent + indent +
                         "jniThrowException(_env, _exceptionType, _exceptionMessage);");
-            out.println(indent + "}");
+            if (!isVoid) {
+                if (cfunc.getType().isEGLHandle()) {
+                    String baseType = cfunc.getType().getBaseType().toLowerCase();
+                    out.println(indent + indent + "return nullptr;");
+                } else {
+                    out.println(indent + indent + "return " +
+                                getJniDefaultReturn(jfunc.getType()) + ";");
+                }
+            }
 
+            out.println(indent + "}");
         }
 
 
diff --git a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
index f3bf220..12728f5 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
+++ b/opengl/tools/glgen/stubs/egl/EGL14Header.java-if
@@ -18,6 +18,7 @@
 
 package android.opengl;
 
+import android.annotation.UnsupportedAppUsage;
 import android.graphics.SurfaceTexture;
 import android.view.Surface;
 import android.view.SurfaceView;
diff --git a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
index f90e3ec..93203fd 100644
--- a/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL14cHeader.cpp
@@ -35,8 +35,6 @@
 
 #include <ui/ANativeObjectBase.h>
 
-static int initialized = 0;
-
 static jclass egldisplayClass;
 static jclass eglcontextClass;
 static jclass eglsurfaceClass;
@@ -107,6 +105,7 @@
     if (obj == NULL){
         jniThrowException(_env, "java/lang/IllegalArgumentException",
                           "Object is set to null.");
+        return nullptr;
     }
 
     jlong handle = _env->CallLongMethod(obj, mid);
diff --git a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
index 70b46f7..1c53c9e 100644
--- a/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGL15cHeader.cpp
@@ -14,21 +14,21 @@
 ** limitations under the License.
 */
 
+// This source file is automatically generated
+
 #pragma GCC diagnostic ignored "-Wunused-variable"
 #pragma GCC diagnostic ignored "-Wunused-function"
 
-#include <android_runtime/AndroidRuntime.h>
-#include <nativehelper/JNIHelp.h>
-#include <utils/misc.h>
 #include "jni.h"
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
 
-#include <EGL/egl.h>
 #include <assert.h>
+#include <EGL/egl.h>
 
 #include <ui/ANativeObjectBase.h>
 
-static int initialized = 0;
-
 // classes from EGL 1.4
 static jclass egldisplayClass;
 static jclass eglsurfaceClass;
@@ -74,16 +74,18 @@
 
 /* Cache method IDs each time the class is loaded. */
 
-static void nativeClassInit(JNIEnv *_env, jclass glImplClass) {
+static void
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
+{
     // EGL 1.4 Init
     jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
-    eglconfigClass = (jclass)_env->NewGlobalRef(eglconfigClassLocal);
+    eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal);
     jclass eglcontextClassLocal = _env->FindClass("android/opengl/EGLContext");
-    eglcontextClass = (jclass)_env->NewGlobalRef(eglcontextClassLocal);
+    eglcontextClass = (jclass) _env->NewGlobalRef(eglcontextClassLocal);
     jclass egldisplayClassLocal = _env->FindClass("android/opengl/EGLDisplay");
-    egldisplayClass = (jclass)_env->NewGlobalRef(egldisplayClassLocal);
+    egldisplayClass = (jclass) _env->NewGlobalRef(egldisplayClassLocal);
     jclass eglsurfaceClassLocal = _env->FindClass("android/opengl/EGLSurface");
-    eglsurfaceClass = (jclass)_env->NewGlobalRef(eglsurfaceClassLocal);
+    eglsurfaceClass = (jclass) _env->NewGlobalRef(eglsurfaceClassLocal);
 
     eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
     eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
@@ -95,51 +97,46 @@
     egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
     eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
 
-    jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor,
-                                                      reinterpret_cast<jlong>(EGL_NO_CONTEXT));
+    jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, reinterpret_cast<jlong>(EGL_NO_CONTEXT));
     eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
-    jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor,
-                                                      reinterpret_cast<jlong>(EGL_NO_DISPLAY));
+    jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, reinterpret_cast<jlong>(EGL_NO_DISPLAY));
     eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
-    jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor,
-                                                      reinterpret_cast<jlong>(EGL_NO_SURFACE));
+    jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, reinterpret_cast<jlong>(EGL_NO_SURFACE));
     eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
 
     jclass eglClass = _env->FindClass("android/opengl/EGL15");
-    jfieldID noContextFieldID =
-            _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
+    jfieldID noContextFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_CONTEXT", "Landroid/opengl/EGLContext;");
     _env->SetStaticObjectField(eglClass, noContextFieldID, eglNoContextObject);
 
-    jfieldID noDisplayFieldID =
-            _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
+    jfieldID noDisplayFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_DISPLAY", "Landroid/opengl/EGLDisplay;");
     _env->SetStaticObjectField(eglClass, noDisplayFieldID, eglNoDisplayObject);
 
-    jfieldID noSurfaceFieldID =
-            _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
+    jfieldID noSurfaceFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SURFACE", "Landroid/opengl/EGLSurface;");
     _env->SetStaticObjectField(eglClass, noSurfaceFieldID, eglNoSurfaceObject);
 
     // EGL 1.5 init
     jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
-    nioAccessClass = (jclass)_env->NewGlobalRef(nioAccessClassLocal);
+    nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
 
     jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
-    bufferClass = (jclass)_env->NewGlobalRef(bufferClassLocal);
+    bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
 
-    getBasePointerID =
-            _env->GetStaticMethodID(nioAccessClass, "getBasePointer", "(Ljava/nio/Buffer;)J");
-    getBaseArrayID = _env->GetStaticMethodID(nioAccessClass, "getBaseArray",
-                                             "(Ljava/nio/Buffer;)Ljava/lang/Object;");
-    getBaseArrayOffsetID =
-            _env->GetStaticMethodID(nioAccessClass, "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+    getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
+            "getBasePointer", "(Ljava/nio/Buffer;)J");
+    getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
+            "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+    getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
+            "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
 
     positionID = _env->GetFieldID(bufferClass, "position", "I");
     limitID = _env->GetFieldID(bufferClass, "limit", "I");
-    elementSizeShiftID = _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+    elementSizeShiftID =
+        _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
 
     jclass eglimageClassLocal = _env->FindClass("android/opengl/EGLImage");
-    eglimageClass = (jclass)_env->NewGlobalRef(eglimageClassLocal);
+    eglimageClass = (jclass) _env->NewGlobalRef(eglimageClassLocal);
     jclass eglsyncClassLocal = _env->FindClass("android/opengl/EGLSync");
-    eglsyncClass = (jclass)_env->NewGlobalRef(eglsyncClassLocal);
+    eglsyncClass = (jclass) _env->NewGlobalRef(eglsyncClassLocal);
 
     eglimageGetHandleID = _env->GetMethodID(eglimageClass, "getNativeHandle", "()J");
     eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
@@ -147,17 +144,16 @@
     eglimageConstructor = _env->GetMethodID(eglimageClass, "<init>", "(J)V");
     eglsyncConstructor = _env->GetMethodID(eglsyncClass, "<init>", "(J)V");
 
-    jfieldID noImageFieldID =
-            _env->GetStaticFieldID(eglClass, "EGL_NO_IMAGE", "Landroid/opengl/EGLImage;");
+    jfieldID noImageFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_IMAGE", "Landroid/opengl/EGLImage;");
     _env->SetStaticObjectField(eglClass, noImageFieldID, eglNoImageObject);
 
-    jfieldID noSyncFieldID =
-            _env->GetStaticFieldID(eglClass, "EGL_NO_SYNC", "Landroid/opengl/EGLSync;");
+    jfieldID noSyncFieldID = _env->GetStaticFieldID(eglClass, "EGL_NO_SYNC", "Landroid/opengl/EGLSync;");
     _env->SetStaticObjectField(eglClass, noSyncFieldID, eglNoSyncObject);
 }
 
-static void *getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining,
-                        jint *offset) {
+static void *
+getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset)
+{
     jint position;
     jint limit;
     jint elementSizeShift;
@@ -167,34 +163,42 @@
     limit = _env->GetIntField(buffer, limitID);
     elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
     *remaining = (limit - position) << elementSizeShift;
-    pointer = _env->CallStaticLongMethod(nioAccessClass, getBasePointerID, buffer);
+    pointer = _env->CallStaticLongMethod(nioAccessClass,
+            getBasePointerID, buffer);
     if (pointer != 0L) {
         *array = NULL;
-        return reinterpret_cast<void *>(pointer);
+        return reinterpret_cast<void*>(pointer);
     }
-    eglimageGetHandleID = _env->GetMethodID(eglimageClass, "getNativeHandle", "()J");
-    eglsyncGetHandleID = _env->GetMethodID(eglsyncClass, "getNativeHandle", "()J");
 
-    *array = (jarray)_env->CallStaticObjectMethod(nioAccessClass, getBaseArrayID, buffer);
-    *offset = _env->CallStaticIntMethod(nioAccessClass, getBaseArrayOffsetID, buffer);
+    *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
+            getBaseArrayID, buffer);
+    *offset = _env->CallStaticIntMethod(nioAccessClass,
+            getBaseArrayOffsetID, buffer);
 
     return NULL;
 }
 
-static void releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) {
-    _env->ReleasePrimitiveArrayCritical(array, data, commit ? 0 : JNI_ABORT);
+static void
+releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
+{
+    _env->ReleasePrimitiveArrayCritical(array, data,
+                       commit ? 0 : JNI_ABORT);
 }
 
-static void *fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
+static void *
+fromEGLHandle(JNIEnv *_env, jmethodID mid, jobject obj) {
     if (obj == NULL) {
-        jniThrowException(_env, "java/lang/IllegalArgumentException", "Object is set to null.");
+        jniThrowException(_env, "java/lang/IllegalArgumentException",
+                          "Object is set to null.");
+        return nullptr;
     }
 
     jlong handle = _env->CallLongMethod(obj, mid);
-    return reinterpret_cast<void *>(handle);
+    return reinterpret_cast<void*>(handle);
 }
 
-static jobject toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void *handle) {
+static jobject
+toEGLHandle(JNIEnv *_env, jclass cls, jmethodID con, void *handle) {
     if (cls == eglimageClass && (EGLImage)handle == EGL_NO_IMAGE) {
         return eglNoImageObject;
     }
diff --git a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
index 12b96f4..b3b0690 100644
--- a/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/egl/EGLExtcHeader.cpp
@@ -36,8 +36,6 @@
 
 #include <ui/ANativeObjectBase.h>
 
-static int initialized = 0;
-
 static jclass egldisplayClass;
 static jclass eglcontextClass;
 static jclass eglsurfaceClass;
@@ -104,6 +102,7 @@
     if (obj == NULL){
         jniThrowException(_env, "java/lang/IllegalArgumentException",
                           "Object is set to null.");
+        return nullptr;
     }
 
     return reinterpret_cast<void*>(_env->CallLongMethod(obj, mid));
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
index 497d284..f229860 100755
--- a/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePbufferFromClientBuffer.cpp
@@ -54,6 +54,7 @@
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
     }
     return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
 }
diff --git a/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp
index 3eacf3c..2e146a8 100644
--- a/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreatePixmapSurface.cpp
@@ -4,6 +4,6 @@
   (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jint pixmap, jintArray attrib_list_ref, jint offset) {
     jniThrowException(_env, "java/lang/UnsupportedOperationException",
         "eglCreatePixmapSurface");
-    return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, (EGLSurface) 0);
+    return nullptr;
 }
 
diff --git a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
index 355c4b0..7c255ed 100644
--- a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
@@ -67,6 +67,7 @@
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
     }
     return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
 }
@@ -149,6 +150,7 @@
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
     }
     return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
 }
diff --git a/opengl/tools/glgen/stubs/egl/eglGetDisplay.java b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
index 7532abf..85f743d 100755
--- a/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
+++ b/opengl/tools/glgen/stubs/egl/eglGetDisplay.java
@@ -7,6 +7,7 @@
     /**
      * {@hide}
      */
+    @UnsupportedAppUsage
     public static native EGLDisplay eglGetDisplay(
         long display_id
     );
diff --git a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
index fd44498..3a6176f 100644
--- a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
@@ -40,6 +40,7 @@
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
     }
     return toEGLHandle(_env, egldisplayClass, egldisplayConstructor, _returnValue);
 }
diff --git a/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if b/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
index 9ce6728..c2711aa 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
+++ b/opengl/tools/glgen/stubs/gles11/GLES20Header.java-if
@@ -19,6 +19,8 @@
 
 package android.opengl;
 
+import android.annotation.UnsupportedAppUsage;
+
 /** OpenGL ES 2.0
  */
 public class GLES20 {
diff --git a/opengl/tools/glgen/stubs/gles11/common.cpp b/opengl/tools/glgen/stubs/gles11/common.cpp
index 2163d76..51e62ed 100644
--- a/opengl/tools/glgen/stubs/gles11/common.cpp
+++ b/opengl/tools/glgen/stubs/gles11/common.cpp
@@ -4,8 +4,6 @@
 #include <utils/misc.h>
 #include <assert.h>
 
-static int initialized = 0;
-
 static jclass nioAccessClass;
 static jclass bufferClass;
 static jmethodID getBasePointerID;
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java
index d66200f..b297b7a 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveAttrib.java
@@ -17,6 +17,7 @@
     // C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )
 
     /** @hide Method is broken, but used to be public (b/6006380) */
+    @UnsupportedAppUsage
     public static native void glGetActiveAttrib(
         int program,
         int index,
diff --git a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java
index 8c8d5a2..f211440 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java
+++ b/opengl/tools/glgen/stubs/gles11/glGetActiveUniform.java
@@ -17,6 +17,7 @@
     // C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )
 
     /** @hide Method is broken, but used to be public (b/6006380) */
+    @UnsupportedAppUsage
     public static native void glGetActiveUniform(
         int program,
         int index,
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 29296ff..c808fe9 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -64,8 +64,6 @@
         GLsizei stride, const GLvoid *pointer, GLsizei count);
 }
 
-static int initialized = 0;
-
 static jclass nioAccessClass;
 static jclass bufferClass;
 static jclass G11ImplClass;
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index e21d8e7..dbb6ba6 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -2,6 +2,7 @@
     name: "gpuservice_sources",
     srcs: [
         "GpuService.cpp",
+        "gpustats/GpuStats.cpp"
     ],
 }
 
@@ -29,6 +30,7 @@
         "frameworks/native/vulkan/include",
     ],
     shared_libs: [
+        "libbase",
         "libbinder",
         "libcutils",
         "libgraphicsenv",
@@ -37,6 +39,7 @@
         "libvulkan",
     ],
     static_libs: [
+        "libserviceutils",
         "libvkjson",
     ],
 }
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index ed56c49..d7696f9 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -18,24 +18,33 @@
 
 #include "GpuService.h"
 
+#include <android-base/stringprintf.h>
+#include <binder/IPCThreadState.h>
 #include <binder/IResultReceiver.h>
 #include <binder/Parcel.h>
+#include <binder/PermissionCache.h>
+#include <private/android_filesystem_config.h>
 #include <utils/String8.h>
 #include <utils/Trace.h>
 
 #include <vkjson.h>
 
+#include "gpustats/GpuStats.h"
+
 namespace android {
 
+using base::StringAppendF;
 
 namespace {
-    status_t cmd_help(int out);
-    status_t cmd_vkjson(int out, int err);
-}
+status_t cmdHelp(int out);
+status_t cmdVkjson(int out, int err);
+} // namespace
+
+const String16 sDump("android.permission.DUMP");
 
 const char* const GpuService::SERVICE_NAME = "gpu";
 
-GpuService::GpuService() = default;
+GpuService::GpuService() : mGpuStats(std::make_unique<GpuStats>()){};
 
 void GpuService::setGpuStats(const std::string& driverPackageName,
                              const std::string& driverVersionName, uint64_t driverVersionCode,
@@ -44,18 +53,8 @@
                              int64_t driverLoadingTime) {
     ATRACE_CALL();
 
-    std::lock_guard<std::mutex> lock(mStateLock);
-    ALOGV("Received:\n"
-          "\tdriverPackageName[%s]\n"
-          "\tdriverVersionName[%s]\n"
-          "\tdriverVersionCode[%" PRIu64 "]\n"
-          "\tdriverBuildTime[%" PRId64 "]\n"
-          "\tappPackageName[%s]\n"
-          "\tdriver[%d]\n"
-          "\tisDriverLoaded[%d]\n"
-          "\tdriverLoadingTime[%" PRId64 "]",
-          driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
-          appPackageName.c_str(), static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
+    mGpuStats->insert(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
+                      appPackageName, driver, isDriverLoaded, driverLoadingTime);
 }
 
 status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) {
@@ -66,28 +65,56 @@
         ALOGV("  arg[%zu]: '%s'", i, String8(args[i]).string());
 
     if (args.size() >= 1) {
-        if (args[0] == String16("vkjson"))
-            return cmd_vkjson(out, err);
-        if (args[0] == String16("help"))
-            return cmd_help(out);
+        if (args[0] == String16("vkjson")) return cmdVkjson(out, err);
+        if (args[0] == String16("help")) return cmdHelp(out);
     }
     // no command, or unrecognized command
-    cmd_help(err);
+    cmdHelp(err);
     return BAD_VALUE;
 }
 
+status_t GpuService::doDump(int fd, const Vector<String16>& args, bool /*asProto*/) {
+    std::string result;
+
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+
+    if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) {
+        StringAppendF(&result, "Permission Denial: can't dump gpu from pid=%d, uid=%d\n", pid, uid);
+    } else {
+        bool dumpAll = true;
+        size_t index = 0;
+        size_t numArgs = args.size();
+
+        if (numArgs) {
+            if ((index < numArgs) && (args[index] == String16("--gpustats"))) {
+                index++;
+                mGpuStats->dump(args, &result);
+                dumpAll = false;
+            }
+        }
+
+        if (dumpAll) {
+            mGpuStats->dump(Vector<String16>(), &result);
+        }
+    }
+
+    write(fd, result.c_str(), result.size());
+    return NO_ERROR;
+}
+
 namespace {
 
-status_t cmd_help(int out) {
+status_t cmdHelp(int out) {
     FILE* outs = fdopen(out, "w");
     if (!outs) {
-        ALOGE("vkjson: failed to create out stream: %s (%d)", strerror(errno),
-            errno);
+        ALOGE("vkjson: failed to create out stream: %s (%d)", strerror(errno), errno);
         return BAD_VALUE;
     }
     fprintf(outs,
-        "GPU Service commands:\n"
-        "  vkjson   dump Vulkan properties as JSON\n");
+            "GPU Service commands:\n"
+            "  vkjson   dump Vulkan properties as JSON\n");
     fclose(outs);
     return NO_ERROR;
 }
@@ -98,7 +125,7 @@
     fputc('\n', out);
 }
 
-status_t cmd_vkjson(int out, int /*err*/) {
+status_t cmdVkjson(int out, int /*err*/) {
     FILE* outs = fdopen(out, "w");
     if (!outs) {
         int errnum = errno;
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index 389e695..0cf48bb 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -20,13 +20,16 @@
 #include <binder/IInterface.h>
 #include <cutils/compiler.h>
 #include <graphicsenv/IGpuService.h>
+#include <serviceutils/PriorityDumper.h>
 
 #include <mutex>
 #include <vector>
 
 namespace android {
 
-class GpuService : public BnGpuService {
+class GpuStats;
+
+class GpuService : public BnGpuService, public PriorityDumper {
 public:
     static const char* const SERVICE_NAME ANDROID_API;
 
@@ -36,14 +39,36 @@
     status_t shellCommand(int in, int out, int err, std::vector<String16>& args) override;
 
 private:
-    // IGpuService interface
+    /*
+     * IGpuService interface
+     */
     void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
                      uint64_t driverVersionCode, int64_t driverBuildTime,
                      const std::string& appPackageName, GraphicsEnv::Driver driver,
                      bool isDriverLoaded, int64_t driverLoadingTime);
 
-    // GpuStats access must be protected by mStateLock
-    std::mutex mStateLock;
+    /*
+     * IBinder interface
+     */
+    status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); }
+
+    /*
+     * Debugging & dumpsys
+     */
+    status_t dumpCritical(int fd, const Vector<String16>& /*args*/, bool asProto) override {
+        return doDump(fd, Vector<String16>(), asProto);
+    }
+
+    status_t dumpAll(int fd, const Vector<String16>& args, bool asProto) override {
+        return doDump(fd, args, asProto);
+    }
+
+    status_t doDump(int fd, const Vector<String16>& args, bool asProto);
+
+    /*
+     * Attributes
+     */
+    std::unique_ptr<GpuStats> mGpuStats;
 };
 
 } // namespace android
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
new file mode 100644
index 0000000..43c9492
--- /dev/null
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#undef LOG_TAG
+#define LOG_TAG "GpuStats"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "GpuStats.h"
+
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <utils/Trace.h>
+
+#include <unordered_set>
+
+namespace android {
+
+using base::StringAppendF;
+
+static bool addLoadingCount(GraphicsEnv::Driver driver, bool isDriverLoaded,
+                            GpuStatsGlobalAtom* const outGlobalAtom) {
+    switch (driver) {
+        case GraphicsEnv::Driver::GL:
+        case GraphicsEnv::Driver::GL_UPDATED:
+            outGlobalAtom->glLoadingCount++;
+            if (!isDriverLoaded) outGlobalAtom->glLoadingFailureCount++;
+            break;
+        case GraphicsEnv::Driver::VULKAN:
+        case GraphicsEnv::Driver::VULKAN_UPDATED:
+            outGlobalAtom->vkLoadingCount++;
+            if (!isDriverLoaded) outGlobalAtom->vkLoadingFailureCount++;
+            break;
+        default:
+            // Currently we don't support GraphicsEnv::Driver::ANGLE because the
+            // basic driver package info only belongs to system or updated driver.
+            return false;
+    }
+
+    return true;
+}
+
+static void addLoadingTime(GraphicsEnv::Driver driver, int64_t driverLoadingTime,
+                           GpuStatsAppAtom* const outAppAtom) {
+    switch (driver) {
+        case GraphicsEnv::Driver::GL:
+        case GraphicsEnv::Driver::GL_UPDATED:
+            outAppAtom->glDriverLoadingTime.emplace_back(driverLoadingTime);
+            break;
+        case GraphicsEnv::Driver::VULKAN:
+        case GraphicsEnv::Driver::VULKAN_UPDATED:
+            outAppAtom->vkDriverLoadingTime.emplace_back(driverLoadingTime);
+            break;
+        default:
+            break;
+    }
+}
+
+void GpuStats::insert(const std::string& driverPackageName, const std::string& driverVersionName,
+                      uint64_t driverVersionCode, int64_t driverBuildTime,
+                      const std::string& appPackageName, GraphicsEnv::Driver driver,
+                      bool isDriverLoaded, int64_t driverLoadingTime) {
+    ATRACE_CALL();
+
+    std::lock_guard<std::mutex> lock(mLock);
+    ALOGV("Received:\n"
+          "\tdriverPackageName[%s]\n"
+          "\tdriverVersionName[%s]\n"
+          "\tdriverVersionCode[%" PRIu64 "]\n"
+          "\tdriverBuildTime[%" PRId64 "]\n"
+          "\tappPackageName[%s]\n"
+          "\tdriver[%d]\n"
+          "\tisDriverLoaded[%d]\n"
+          "\tdriverLoadingTime[%" PRId64 "]",
+          driverPackageName.c_str(), driverVersionName.c_str(), driverVersionCode, driverBuildTime,
+          appPackageName.c_str(), static_cast<int32_t>(driver), isDriverLoaded, driverLoadingTime);
+
+    if (!mGlobalStats.count(driverVersionCode)) {
+        GpuStatsGlobalAtom globalAtom;
+        if (!addLoadingCount(driver, isDriverLoaded, &globalAtom)) {
+            return;
+        }
+        globalAtom.driverPackageName = driverPackageName;
+        globalAtom.driverVersionName = driverVersionName;
+        globalAtom.driverVersionCode = driverVersionCode;
+        globalAtom.driverBuildTime = driverBuildTime;
+        mGlobalStats.insert({driverVersionCode, globalAtom});
+    } else if (!addLoadingCount(driver, isDriverLoaded, &mGlobalStats[driverVersionCode])) {
+        return;
+    }
+
+    if (mAppStats.size() >= MAX_NUM_APP_RECORDS) {
+        ALOGV("GpuStatsAppAtom has reached maximum size. Ignore new stats.");
+        return;
+    }
+
+    const std::string appStatsKey = appPackageName + std::to_string(driverVersionCode);
+    if (!mAppStats.count(appStatsKey)) {
+        GpuStatsAppAtom appAtom;
+        addLoadingTime(driver, driverLoadingTime, &appAtom);
+        appAtom.appPackageName = appPackageName;
+        appAtom.driverVersionCode = driverVersionCode;
+        mAppStats.insert({appStatsKey, appAtom});
+        return;
+    }
+
+    addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]);
+}
+
+void GpuStats::dump(const Vector<String16>& args, std::string* result) {
+    ATRACE_CALL();
+
+    if (!result) {
+        ALOGE("Dump result shouldn't be nullptr.");
+        return;
+    }
+
+    std::lock_guard<std::mutex> lock(mLock);
+    bool dumpAll = true;
+
+    std::unordered_set<std::string> argsSet;
+    for (size_t i = 0; i < args.size(); i++) {
+        argsSet.insert(String8(args[i]).c_str());
+    }
+
+    const bool dumpGlobal = argsSet.count("--global") != 0;
+    if (dumpGlobal) {
+        dumpGlobalLocked(result);
+        dumpAll = false;
+    }
+
+    const bool dumpApp = argsSet.count("--app") != 0;
+    if (dumpApp) {
+        dumpAppLocked(result);
+        dumpAll = false;
+    }
+
+    if (argsSet.count("--clear")) {
+        bool clearAll = true;
+
+        if (dumpGlobal) {
+            mGlobalStats.clear();
+            clearAll = false;
+        }
+
+        if (dumpApp) {
+            mAppStats.clear();
+            clearAll = false;
+        }
+
+        if (clearAll) {
+            mGlobalStats.clear();
+            mAppStats.clear();
+        }
+
+        dumpAll = false;
+    }
+
+    if (dumpAll) {
+        dumpGlobalLocked(result);
+        dumpAppLocked(result);
+    }
+}
+
+void GpuStats::dumpGlobalLocked(std::string* result) {
+    result->append("GpuStats global:\n");
+
+    for (const auto& ele : mGlobalStats) {
+        StringAppendF(result, "  driverPackageName = %s\n", ele.second.driverPackageName.c_str());
+        StringAppendF(result, "  driverVersionName = %s\n", ele.second.driverVersionName.c_str());
+        StringAppendF(result, "  driverVersionCode = %" PRIu64 "\n", ele.second.driverVersionCode);
+        StringAppendF(result, "  driverBuildTime = %" PRId64 "\n", ele.second.driverBuildTime);
+        StringAppendF(result, "  glLoadingCount = %d\n", ele.second.glLoadingCount);
+        StringAppendF(result, "  glLoadingFailureCount = %d\n", ele.second.glLoadingFailureCount);
+        StringAppendF(result, "  vkLoadingCount = %d\n", ele.second.vkLoadingCount);
+        StringAppendF(result, "  vkLoadingFailureCount = %d\n", ele.second.vkLoadingFailureCount);
+        result->append("\n");
+    }
+}
+
+void GpuStats::dumpAppLocked(std::string* result) {
+    result->append("GpuStats app:\n");
+
+    for (const auto& ele : mAppStats) {
+        StringAppendF(result, "  appPackageName = %s\n", ele.second.appPackageName.c_str());
+        StringAppendF(result, "  driverVersionCode = %" PRIu64 "\n", ele.second.driverVersionCode);
+
+        result->append("  glDriverLoadingTime:");
+        for (int32_t loadingTime : ele.second.glDriverLoadingTime) {
+            StringAppendF(result, " %d", loadingTime);
+        }
+        result->append("\n");
+
+        result->append("  vkDriverLoadingTime:");
+        for (int32_t loadingTime : ele.second.vkDriverLoadingTime) {
+            StringAppendF(result, " %d", loadingTime);
+        }
+        result->append("\n\n");
+    }
+}
+
+} // namespace android
diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h
new file mode 100644
index 0000000..8837c39
--- /dev/null
+++ b/services/gpuservice/gpustats/GpuStats.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include <graphicsenv/GpuStatsAtoms.h>
+#include <graphicsenv/GraphicsEnv.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class GpuStats {
+public:
+    GpuStats() = default;
+    ~GpuStats() = default;
+
+    // Insert new gpu stats into global stats and app stats.
+    void insert(const std::string& driverPackageName, const std::string& driverVersionName,
+                uint64_t driverVersionCode, int64_t driverBuildTime,
+                const std::string& appPackageName, GraphicsEnv::Driver driver, bool isDriverLoaded,
+                int64_t driverLoadingTime);
+    // dumpsys interface
+    void dump(const Vector<String16>& args, std::string* result);
+
+private:
+    // Dump global stats
+    void dumpGlobalLocked(std::string* result);
+    // Dump app stats
+    void dumpAppLocked(std::string* result);
+
+    // This limits the memory usage of GpuStats to be less than 30KB. This is
+    // the maximum atom size statsd could afford.
+    static const size_t MAX_NUM_APP_RECORDS = 300;
+    // GpuStats access should be guarded by mLock.
+    std::mutex mLock;
+    // Key is driver version code.
+    std::unordered_map<uint64_t, GpuStatsGlobalAtom> mGlobalStats;
+    // Key is <app package name>+<driver version code>.
+    std::unordered_map<std::string, GpuStatsAppAtom> mAppStats;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 3304fd1..9bf499b 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -134,7 +134,6 @@
         "EventLog/EventLog.cpp",
         "FrameTracker.cpp",
         "Layer.cpp",
-        "LayerBE.cpp",
         "LayerProtoHelper.cpp",
         "LayerRejecter.cpp",
         "LayerStats.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 2501fae..6badc73 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -125,9 +125,11 @@
 
 bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
                                      bool useIdentityTransform, Region& clearRegion,
+                                     const bool supportProtectedContent,
                                      renderengine::LayerSettings& layer) {
     ATRACE_CALL();
-    Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, layer);
+    Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
+                              supportProtectedContent, layer);
     if (CC_UNLIKELY(mActiveBuffer == 0)) {
         // the texture has not been created yet, this Layer has
         // in fact never been drawn into. This happens frequently with
@@ -154,7 +156,8 @@
         }
         return false;
     }
-    bool blackOutLayer = isProtected() || (isSecure() && !renderArea.isSecure());
+    bool blackOutLayer =
+            (isProtected() && !supportProtectedContent) || (isSecure() && !renderArea.isSecure());
     const State& s(getDrawingState());
     if (!blackOutLayer) {
         layer.source.buffer.buffer = mActiveBuffer;
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index e3b10fc..c48146f 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -168,7 +168,8 @@
     // prepareClientLayer - constructs a RenderEngine layer for GPU composition.
     bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
                             bool useIdentityTransform, Region& clearRegion,
-                            renderengine::LayerSettings& layer);
+                            const bool supportProtectedContent,
+                            renderengine::LayerSettings& layer) override;
 
 private:
     // Returns true if this layer requires filtering
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 96c4992..215dea1 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -199,7 +199,6 @@
     bool sidebandStreamChanged = true;
     if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
         // mSidebandStreamChanged was changed to false
-        // replicated in LayerBE until FE/BE is ready to be synchronized
         auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
         layerCompositionState.sidebandStream = mConsumer->getSidebandStream();
         if (layerCompositionState.sidebandStream != nullptr) {
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index e48c41e..f6b69eb 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -198,7 +198,6 @@
         mReleasePreviousBuffer = true;
     }
 
-    mCurrentState.sequence++;
     mCurrentState.buffer = buffer;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -217,7 +216,6 @@
 
 bool BufferStateLayer::setDataspace(ui::Dataspace dataspace) {
     if (mCurrentState.dataspace == dataspace) return false;
-    mCurrentState.sequence++;
     mCurrentState.dataspace = dataspace;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 9ea0a46..2aeece7 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -50,8 +50,10 @@
 
 bool ColorLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
                                     bool useIdentityTransform, Region& clearRegion,
+                                    const bool supportProtectedContent,
                                     renderengine::LayerSettings& layer) {
-    Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion, layer);
+    Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
+                              supportProtectedContent, layer);
     half4 color(getColor());
     half3 solidColor(color.r, color.g, color.b);
     layer.source.solidColor = solidColor;
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index df0adac..9786419 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -42,9 +42,10 @@
 
 protected:
     FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; }
-    virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
-                                    bool useIdentityTransform, Region& clearRegion,
-                                    renderengine::LayerSettings& layer);
+    bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
+                            bool useIdentityTransform, Region& clearRegion,
+                            const bool supportProtectedContent,
+                            renderengine::LayerSettings& layer) override;
 
 private:
     std::shared_ptr<compositionengine::Layer> mCompositionLayer;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index f9a3624..6cc87ba 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -18,10 +18,19 @@
 
 #include <utils/RefBase.h>
 
-namespace android::compositionengine {
+namespace android {
+
+class Fence;
+
+namespace compositionengine {
 
 // Defines the interface used by the CompositionEngine to make requests
 // of the front-end layer
-class LayerFE : public virtual RefBase {};
+class LayerFE : public virtual RefBase {
+public:
+    // Called after the layer is displayed to update the presentation fence
+    virtual void onLayerDisplayed(const sp<Fence>&) = 0;
+};
 
-} // namespace android::compositionengine
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 92e0070..a0c2a63 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -18,6 +18,7 @@
 
 #include <compositionengine/LayerFE.h>
 #include <gmock/gmock.h>
+#include <ui/Fence.h>
 
 namespace android::compositionengine::mock {
 
@@ -27,6 +28,8 @@
 public:
     LayerFE();
     virtual ~LayerFE();
+
+    MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
 };
 
 } // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 22c40d7..738f4b6 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -26,7 +26,7 @@
 
 ContainerLayer::~ContainerLayer() = default;
 
-bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&,
+bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&, const bool,
                                         renderengine::LayerSettings&) {
     return false;
 }
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index c69997d..c7cfdcd 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -43,7 +43,8 @@
 protected:
     bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
                             bool useIdentityTransform, Region& clearRegion,
-                            renderengine::LayerSettings& layer);
+                            const bool supportProtectedContent,
+                            renderengine::LayerSettings& layer) override;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index a827c47..c80925e 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -255,17 +255,18 @@
                               device->getCompositionDataSpace(), rotation) {}
     DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqWidth,
                       uint32_t reqHeight, ui::Dataspace reqDataSpace,
-                      ui::Transform::orientation_flags rotation)
+                      ui::Transform::orientation_flags rotation, bool allowSecureLayers = true)
           : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, reqDataSpace,
                        getDisplayRotation(rotation, device->getInstallOrientation())),
             mDevice(device),
-            mSourceCrop(sourceCrop) {}
+            mSourceCrop(sourceCrop),
+            mAllowSecureLayers(allowSecureLayers) {}
 
     const ui::Transform& getTransform() const override { return mDevice->getTransform(); }
     Rect getBounds() const override { return mDevice->getBounds(); }
     int getHeight() const override { return mDevice->getHeight(); }
     int getWidth() const override { return mDevice->getWidth(); }
-    bool isSecure() const override { return mDevice->isSecure(); }
+    bool isSecure() const override { return mAllowSecureLayers && mDevice->isSecure(); }
     const sp<const DisplayDevice> getDisplayDevice() const override { return mDevice; }
 
     bool needsFiltering() const override {
@@ -356,6 +357,7 @@
 
     const sp<const DisplayDevice> mDevice;
     const Rect mSourceCrop;
+    const bool mAllowSecureLayers;
 };
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index daef7c6..a6adeb3 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -69,10 +69,7 @@
 std::atomic<int32_t> Layer::sSequence{1};
 
 Layer::Layer(const LayerCreationArgs& args)
-      : mFlinger(args.flinger),
-        mName(args.name),
-        mClientRef(args.client),
-        mBE{this, args.name.string()} {
+      : mFlinger(args.flinger), mName(args.name), mClientRef(args.client) {
     mCurrentCrop.makeInvalid();
 
     uint32_t layerFlags = 0;
@@ -683,18 +680,21 @@
 // ---------------------------------------------------------------------------
 
 bool Layer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
-                               Region& clearRegion, renderengine::LayerSettings& layer) {
-    return prepareClientLayer(renderArea, clip, false, clearRegion, layer);
+                               Region& clearRegion, const bool supportProtectedContent,
+                               renderengine::LayerSettings& layer) {
+    return prepareClientLayer(renderArea, clip, false, clearRegion, supportProtectedContent, layer);
 }
 
 bool Layer::prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
-                               Region& clearRegion, renderengine::LayerSettings& layer) {
+                               Region& clearRegion, const bool supportProtectedContent,
+                               renderengine::LayerSettings& layer) {
     return prepareClientLayer(renderArea, Region(renderArea.getBounds()), useIdentityTransform,
-                              clearRegion, layer);
+                              clearRegion, supportProtectedContent, layer);
 }
 
 bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/,
                                bool useIdentityTransform, Region& /*clearRegion*/,
+                               const bool /*supportProtectedContent*/,
                                renderengine::LayerSettings& layer) {
     FloatRect bounds = getBounds();
     half alpha = getAlpha();
@@ -1338,10 +1338,8 @@
     return true;
 }
 
-bool Layer::setMetadata(LayerMetadata data) {
-    bool changed = data.mMap != mCurrentState.metadata.mMap;
-    if (!changed) return false;
-    mCurrentState.metadata = std::move(data);
+bool Layer::setMetadata(const LayerMetadata& data) {
+    if (!mCurrentState.metadata.merge(data, true /* eraseEmpty */)) return false;
     mCurrentState.sequence++;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -2042,26 +2040,26 @@
     }
 
     LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
-                                   layerInfo->mutable_transparent_region());
-    LayerProtoHelper::writeToProto(visibleRegion, layerInfo->mutable_visible_region());
-    LayerProtoHelper::writeToProto(surfaceDamageRegion, layerInfo->mutable_damage_region());
+                                   [&]() { return layerInfo->mutable_transparent_region(); });
+    LayerProtoHelper::writeToProto(visibleRegion,
+                                   [&]() { return layerInfo->mutable_visible_region(); });
+    LayerProtoHelper::writeToProto(surfaceDamageRegion,
+                                   [&]() { return layerInfo->mutable_damage_region(); });
 
     layerInfo->set_layer_stack(getLayerStack());
     layerInfo->set_z(state.z);
 
-    PositionProto* position = layerInfo->mutable_position();
-    position->set_x(transform.tx());
-    position->set_y(transform.ty());
+    LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
+                                           [&]() { return layerInfo->mutable_position(); });
 
-    PositionProto* requestedPosition = layerInfo->mutable_requested_position();
-    requestedPosition->set_x(requestedTransform.tx());
-    requestedPosition->set_y(requestedTransform.ty());
+    LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() {
+        return layerInfo->mutable_requested_position();
+    });
 
-    SizeProto* size = layerInfo->mutable_size();
-    size->set_w(state.active_legacy.w);
-    size->set_h(state.active_legacy.h);
+    LayerProtoHelper::writeSizeToProto(state.active_legacy.w, state.active_legacy.h,
+                                       [&]() { return layerInfo->mutable_size(); });
 
-    LayerProtoHelper::writeToProto(state.crop_legacy, layerInfo->mutable_crop());
+    LayerProtoHelper::writeToProto(state.crop_legacy, [&]() { return layerInfo->mutable_crop(); });
     layerInfo->set_corner_radius(getRoundedCornerState().radius);
 
     layerInfo->set_is_opaque(isOpaque(state));
@@ -2071,8 +2069,9 @@
     layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
 
     layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
-    LayerProtoHelper::writeToProto(getColor(), layerInfo->mutable_color());
-    LayerProtoHelper::writeToProto(state.color, layerInfo->mutable_requested_color());
+    LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
+    LayerProtoHelper::writeToProto(state.color,
+                                   [&]() { return layerInfo->mutable_requested_color(); });
     layerInfo->set_flags(state.flags);
 
     LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
@@ -2094,7 +2093,8 @@
 
     auto buffer = mActiveBuffer;
     if (buffer != nullptr) {
-        LayerProtoHelper::writeToProto(buffer, layerInfo->mutable_active_buffer());
+        LayerProtoHelper::writeToProto(buffer,
+                                       [&]() { return layerInfo->mutable_active_buffer(); });
         LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
                                        layerInfo->mutable_buffer_transform());
     }
@@ -2118,9 +2118,11 @@
         (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
     }
     LayerProtoHelper::writeToProto(mEffectiveTransform, layerInfo->mutable_effective_transform());
-    LayerProtoHelper::writeToProto(mSourceBounds, layerInfo->mutable_source_bounds());
-    LayerProtoHelper::writeToProto(mScreenBounds, layerInfo->mutable_screen_bounds());
-    LayerProtoHelper::writeToProto(mBounds, layerInfo->mutable_bounds());
+    LayerProtoHelper::writeToProto(mSourceBounds,
+                                   [&]() { return layerInfo->mutable_source_bounds(); });
+    LayerProtoHelper::writeToProto(mScreenBounds,
+                                   [&]() { return layerInfo->mutable_screen_bounds(); });
+    LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
 }
 
 void Layer::writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice) {
@@ -2134,10 +2136,10 @@
     const auto& compositionState = outputLayer->getState();
 
     const Rect& frame = compositionState.displayFrame;
-    LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame());
+    LayerProtoHelper::writeToProto(frame, [&]() { return layerInfo->mutable_hwc_frame(); });
 
     const FloatRect& crop = compositionState.sourceCrop;
-    LayerProtoHelper::writeToProto(crop, layerInfo->mutable_hwc_crop());
+    LayerProtoHelper::writeToProto(crop, [&]() { return layerInfo->mutable_hwc_crop(); });
 
     const int32_t transform =
             getCompositionLayer() ? static_cast<int32_t>(compositionState.bufferTransform) : 0;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 1375a39..046482c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -45,7 +45,6 @@
 
 #include "Client.h"
 #include "FrameTracker.h"
-#include "LayerBE.h"
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
@@ -67,7 +66,6 @@
 class GraphicBuffer;
 class SurfaceFlinger;
 class LayerDebugInfo;
-class LayerBE;
 
 namespace compositionengine {
 class Layer;
@@ -97,9 +95,6 @@
     static std::atomic<int32_t> sSequence;
 
 public:
-    friend class LayerBE;
-    LayerBE& getBE() { return mBE; }
-    LayerBE& getBE() const { return mBE; }
     mutable bool contentDirty{false};
     // regions below are in window-manager space
     Region visibleRegion;
@@ -292,7 +287,7 @@
                                               uint64_t frameNumber);
     virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber);
     virtual bool setOverrideScalingMode(int32_t overrideScalingMode);
-    virtual bool setMetadata(LayerMetadata data);
+    virtual bool setMetadata(const LayerMetadata& data);
     virtual bool reparentChildren(const sp<IBinder>& layer);
     virtual void setChildrenDrawingParent(const sp<Layer>& layer);
     virtual bool reparent(const sp<IBinder>& newParentHandle);
@@ -437,9 +432,15 @@
 protected:
     virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
                                     bool useIdentityTransform, Region& clearRegion,
-                                    renderengine::LayerSettings& layer) = 0;
+                                    const bool supportProtectedContent,
+                                    renderengine::LayerSettings& layer);
 
 public:
+    /*
+     * compositionengine::LayerFE overrides
+     */
+    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+
     virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
 
     virtual bool isHdrY410() const { return false; }
@@ -460,11 +461,6 @@
     bool getClearClientTarget(const sp<const DisplayDevice>& display) const;
     void updateCursorPosition(const sp<const DisplayDevice>& display);
 
-    /*
-     * called after page-flip
-     */
-    virtual void onLayerDisplayed(const sp<Fence>& releaseFence);
-
     virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
     virtual void setTransformHint(uint32_t /*orientation*/) const { }
 
@@ -494,9 +490,10 @@
      * false otherwise.
      */
     bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, Region& clearRegion,
-                            renderengine::LayerSettings& layer);
+                            const bool supportProtectedContent, renderengine::LayerSettings& layer);
     bool prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
-                            Region& clearRegion, renderengine::LayerSettings& layer);
+                            Region& clearRegion, const bool supportProtectedContent,
+                            renderengine::LayerSettings& layer);
 
     /*
      * doTransaction - process the transaction. This is a good place to figure
@@ -860,8 +857,6 @@
     wp<Layer> mCurrentParent;
     wp<Layer> mDrawingParent;
 
-    mutable LayerBE mBE;
-
     // Can only be accessed with the SF state lock held.
     bool mLayerDetached{false};
     // Can only be accessed with the SF state lock held.
diff --git a/services/surfaceflinger/LayerBE.cpp b/services/surfaceflinger/LayerBE.cpp
deleted file mode 100644
index 9f63440..0000000
--- a/services/surfaceflinger/LayerBE.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "LayerBE"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "Layer.h"
-
-namespace android {
-
-LayerBE::LayerBE(Layer* layer, std::string layerName) : mLayer(layer) {
-    compositionInfo.layer = std::make_shared<LayerBE>(*this);
-    compositionInfo.layerName = layerName;
-}
-
-LayerBE::LayerBE(const LayerBE& layer) : mLayer(layer.mLayer) {
-    compositionInfo.layer = layer.compositionInfo.layer;
-    compositionInfo.layerName = layer.mLayer->getName().string();
-}
-
-void LayerBE::onLayerDisplayed(const sp<Fence>& releaseFence) {
-    mLayer->onLayerDisplayed(releaseFence);
-}
-
-}; // namespace android
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
deleted file mode 100644
index 51f7857..0000000
--- a/services/surfaceflinger/LayerBE.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <string.h>
-
-#include <ui/Fence.h>
-#include <utils/StrongPointer.h>
-
-#include "DisplayHardware/DisplayIdentification.h"
-
-namespace android {
-
-class LayerBE;
-
-struct CompositionInfo {
-    std::string layerName;
-    std::shared_ptr<LayerBE> layer;
-    struct {
-        DisplayId displayId;
-    } hwc;
-};
-
-class LayerBE {
-public:
-    friend class Layer;
-    friend class BufferLayer;
-    friend class BufferQueueLayer;
-    friend class BufferStateLayer;
-    friend class ColorLayer;
-    friend class SurfaceFlinger;
-
-    // For unit tests
-    friend class TestableSurfaceFlinger;
-
-    LayerBE(Layer* layer, std::string layerName);
-    explicit LayerBE(const LayerBE& layer);
-
-    void onLayerDisplayed(const sp<Fence>& releaseFence);
-
-    Layer*const mLayer;
-
-private:
-    CompositionInfo compositionInfo;
-};
-
-}; // namespace android
-
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 3289e8f..02383a6 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -18,53 +18,106 @@
 
 namespace android {
 namespace surfaceflinger {
-void LayerProtoHelper::writeToProto(const Region& region, RegionProto* regionProto) {
+
+void LayerProtoHelper::writePositionToProto(const float x, const float y,
+                                            std::function<PositionProto*()> getPositionProto) {
+    if (x != 0 || y != 0) {
+        // Use a lambda do avoid writing the object header when the object is empty
+        PositionProto* position = getPositionProto();
+        position->set_x(x);
+        position->set_y(y);
+    }
+}
+
+void LayerProtoHelper::writeSizeToProto(const uint32_t w, const uint32_t h,
+                                        std::function<SizeProto*()> getSizeProto) {
+    if (w != 0 || h != 0) {
+        // Use a lambda do avoid writing the object header when the object is empty
+        SizeProto* size = getSizeProto();
+        size->set_w(w);
+        size->set_h(h);
+    }
+}
+
+void LayerProtoHelper::writeToProto(const Region& region,
+                                    std::function<RegionProto*()> getRegionProto) {
+    if (region.isEmpty()) {
+        return;
+    }
+
     Region::const_iterator head = region.begin();
     Region::const_iterator const tail = region.end();
+    // Use a lambda do avoid writing the object header when the object is empty
+    RegionProto* regionProto = getRegionProto();
     uint64_t address = reinterpret_cast<uint64_t>(&region);
     regionProto->set_id(address);
     while (head != tail) {
-        RectProto* rectProto = regionProto->add_rect();
-        writeToProto(*head, rectProto);
+        std::function<RectProto*()> getProtoRect = [&]() { return regionProto->add_rect(); };
+        writeToProto(*head, getProtoRect);
         head++;
     }
 }
 
-void LayerProtoHelper::writeToProto(const Rect& rect, RectProto* rectProto) {
-    rectProto->set_left(rect.left);
-    rectProto->set_top(rect.top);
-    rectProto->set_bottom(rect.bottom);
-    rectProto->set_right(rect.right);
+void LayerProtoHelper::writeToProto(const Rect& rect, std::function<RectProto*()> getRectProto) {
+    if (rect.left != 0 || rect.right != 0 || rect.top != 0 || rect.bottom != 0) {
+        // Use a lambda do avoid writing the object header when the object is empty
+        RectProto* rectProto = getRectProto();
+        rectProto->set_left(rect.left);
+        rectProto->set_top(rect.top);
+        rectProto->set_bottom(rect.bottom);
+        rectProto->set_right(rect.right);
+    }
 }
 
-void LayerProtoHelper::writeToProto(const FloatRect& rect, FloatRectProto* rectProto) {
-    rectProto->set_left(rect.left);
-    rectProto->set_top(rect.top);
-    rectProto->set_bottom(rect.bottom);
-    rectProto->set_right(rect.right);
+void LayerProtoHelper::writeToProto(const FloatRect& rect,
+                                    std::function<FloatRectProto*()> getFloatRectProto) {
+    if (rect.left != 0 || rect.right != 0 || rect.top != 0 || rect.bottom != 0) {
+        // Use a lambda do avoid writing the object header when the object is empty
+        FloatRectProto* rectProto = getFloatRectProto();
+        rectProto->set_left(rect.left);
+        rectProto->set_top(rect.top);
+        rectProto->set_bottom(rect.bottom);
+        rectProto->set_right(rect.right);
+    }
 }
 
-void LayerProtoHelper::writeToProto(const half4 color, ColorProto* colorProto) {
-    colorProto->set_r(color.r);
-    colorProto->set_g(color.g);
-    colorProto->set_b(color.b);
-    colorProto->set_a(color.a);
+void LayerProtoHelper::writeToProto(const half4 color, std::function<ColorProto*()> getColorProto) {
+    if (color.r != 0 || color.g != 0 || color.b != 0 || color.a != 0) {
+        // Use a lambda do avoid writing the object header when the object is empty
+        ColorProto* colorProto = getColorProto();
+        colorProto->set_r(color.r);
+        colorProto->set_g(color.g);
+        colorProto->set_b(color.b);
+        colorProto->set_a(color.a);
+    }
 }
 
 void LayerProtoHelper::writeToProto(const ui::Transform& transform,
                                     TransformProto* transformProto) {
-    transformProto->set_dsdx(transform[0][0]);
-    transformProto->set_dtdx(transform[0][1]);
-    transformProto->set_dsdy(transform[1][0]);
-    transformProto->set_dtdy(transform[1][1]);
+    const uint32_t type = transform.getType();
+    transformProto->set_type(type);
+
+    if (type &
+        (ui::Transform::SCALE | ui::Transform::ROTATE | ui::Transform::TRANSLATE |
+         ui::Transform::UNKNOWN)) {
+        transformProto->set_dsdx(transform[0][0]);
+        transformProto->set_dtdx(transform[0][1]);
+        transformProto->set_dsdy(transform[1][0]);
+        transformProto->set_dtdy(transform[1][1]);
+    }
 }
 
 void LayerProtoHelper::writeToProto(const sp<GraphicBuffer>& buffer,
-                                    ActiveBufferProto* activeBufferProto) {
-    activeBufferProto->set_width(buffer->getWidth());
-    activeBufferProto->set_height(buffer->getHeight());
-    activeBufferProto->set_stride(buffer->getStride());
-    activeBufferProto->set_format(buffer->format);
+                                    std::function<ActiveBufferProto*()> getActiveBufferProto) {
+    if (buffer->getWidth() != 0 || buffer->getHeight() != 0 || buffer->getStride() != 0 ||
+        buffer->format != 0) {
+        // Use a lambda do avoid writing the object header when the object is empty
+        ActiveBufferProto* activeBufferProto = getActiveBufferProto();
+        activeBufferProto->set_width(buffer->getWidth());
+        activeBufferProto->set_height(buffer->getHeight());
+        activeBufferProto->set_stride(buffer->getStride());
+        activeBufferProto->set_format(buffer->format);
+    }
 }
 
 } // namespace surfaceflinger
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 6df5aea..dca9a5e 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -26,12 +26,18 @@
 namespace surfaceflinger {
 class LayerProtoHelper {
 public:
-    static void writeToProto(const Rect& rect, RectProto* rectProto);
-    static void writeToProto(const FloatRect& rect, FloatRectProto* rectProto);
-    static void writeToProto(const Region& region, RegionProto* regionProto);
-    static void writeToProto(const half4 color, ColorProto* colorProto);
+    static void writePositionToProto(const float x, const float y,
+                                     std::function<PositionProto*()> getPositionProto);
+    static void writeSizeToProto(const uint32_t w, const uint32_t h,
+                                 std::function<SizeProto*()> getSizeProto);
+    static void writeToProto(const Rect& rect, std::function<RectProto*()> getRectProto);
+    static void writeToProto(const FloatRect& rect,
+                             std::function<FloatRectProto*()> getFloatRectProto);
+    static void writeToProto(const Region& region, std::function<RegionProto*()> getRegionProto);
+    static void writeToProto(const half4 color, std::function<ColorProto*()> getColorProto);
     static void writeToProto(const ui::Transform& transform, TransformProto* transformProto);
-    static void writeToProto(const sp<GraphicBuffer>& buffer, ActiveBufferProto* activeBufferProto);
+    static void writeToProto(const sp<GraphicBuffer>& buffer,
+                             std::function<ActiveBufferProto*()> getActiveBufferProto);
 };
 
 } // namespace surfaceflinger
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 075e238..665179e 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -78,6 +78,11 @@
         mPeriod = period;
         mPhase = phase;
         mReferenceTime = referenceTime;
+        if (mTraceDetailedInfo) {
+            ATRACE_INT64("DispSync:Period", mPeriod);
+            ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
+            ATRACE_INT64("DispSync:Reference Time", mReferenceTime);
+        }
         ALOGV("[%s] updateModel: mPeriod = %" PRId64 ", mPhase = %" PRId64
               " mReferenceTime = %" PRId64,
               mName, ns2us(mPeriod), ns2us(mPhase), ns2us(mReferenceTime));
@@ -580,11 +585,6 @@
             ALOGV("[%s] Adjusting mPhase -> %" PRId64, mName, ns2us(mPhase));
         }
 
-        if (mTraceDetailedInfo) {
-            ATRACE_INT64("DispSync:Period", mPeriod);
-            ATRACE_INT64("DispSync:Phase", mPhase + mPeriod / 2);
-        }
-
         // Artificially inflate the period if requested.
         mPeriod += mPeriod * mRefreshSkipCount;
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f651bdf..dde6cd9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -203,19 +203,6 @@
 const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
 const String16 sDump("android.permission.DUMP");
 
-constexpr float kSrgbRedX = 0.4123f;
-constexpr float kSrgbRedY = 0.2126f;
-constexpr float kSrgbRedZ = 0.0193f;
-constexpr float kSrgbGreenX = 0.3576f;
-constexpr float kSrgbGreenY = 0.7152f;
-constexpr float kSrgbGreenZ = 0.1192f;
-constexpr float kSrgbBlueX = 0.1805f;
-constexpr float kSrgbBlueY = 0.0722f;
-constexpr float kSrgbBlueZ = 0.9506f;
-constexpr float kSrgbWhiteX = 0.9505f;
-constexpr float kSrgbWhiteY = 1.0000f;
-constexpr float kSrgbWhiteZ = 1.0891f;
-
 constexpr float kDefaultRefreshRate = 60.f;
 constexpr float kPerformanceRefreshRate = 90.f;
 
@@ -288,6 +275,7 @@
         mDebugRegion(0),
         mDebugDisableHWC(0),
         mDebugDisableTransformHint(0),
+        mDebugEnableProtectedContent(false),
         mDebugInTransaction(0),
         mLastTransactionTime(0),
         mForceFullDamage(false),
@@ -353,15 +341,7 @@
     }
     ALOGV("Primary Display Orientation is set to %2d.", SurfaceFlinger::primaryDisplayOrientation);
 
-    auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
-    if (surfaceFlingerConfigsServiceV1_2) {
-        surfaceFlingerConfigsServiceV1_2->getDisplayNativePrimaries(
-                [&](auto tmpPrimaries) {
-                    memcpy(&mInternalDisplayPrimaries, &tmpPrimaries, sizeof(ui::DisplayPrimaries));
-                });
-    } else {
-        initDefaultDisplayNativePrimaries();
-    }
+    mInternalDisplayPrimaries = sysprop::getDisplayNativePrimaries();
 
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
@@ -666,9 +646,10 @@
                             renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0);
 
     // TODO(b/77156734): We need to stop casting and use HAL types when possible.
+    // Sending maxFrameBufferAcquiredBuffers as the cache size is tightly tuned to single-display.
     mCompositionEngine->setRenderEngine(
             renderengine::RenderEngine::create(static_cast<int32_t>(defaultCompositionPixelFormat),
-                                               renderEngineFeature));
+                                               renderEngineFeature, maxFrameBufferAcquiredBuffers));
 
     LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
             "Starting with vr flinger active is not currently supported.");
@@ -1741,8 +1722,6 @@
 
     mVsyncModulator.onRefreshed(mHadClientComposition);
 
-    getBE().mEndOfFrameCompositionInfo = std::move(getBE().mCompositionInfo);
-
     mLayersWithQueuedFrames.clear();
 }
 
@@ -1855,12 +1834,9 @@
     for (const auto& [token, displayDevice] : mDisplays) {
         auto display = displayDevice->getCompositionDisplay();
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-            const auto displayId = display->getId();
             auto& layerState = layer->getCompositionLayer()->editState().frontEnd;
             layerState.compositionType = static_cast<Hwc2::IComposerClient::Composition>(
                     layer->getCompositionType(displayDevice));
-            layer->getBE().compositionInfo.hwc.displayId = *displayId;
-            getBE().mCompositionInfo[token].push_back(layer->getBE().compositionInfo);
         }
     }
 }
@@ -2235,17 +2211,6 @@
     ATRACE_CALL();
     ALOGV("rebuildLayerStacks");
 
-    // We need to clear these out now as these may be holding on to a
-    // HWC2::Layer reference at the same time as the LayerBE::HWCInfo structure
-    // also holds a reference. When the set of visible layers is recomputed,
-    // some layers may be destroyed if the only thing keeping them alive was
-    // that list of visible layers associated with each display. The layer
-    // destruction code asserts that the HWC2::Layer is properly destroyed, but
-    // that doesn't happen if SurfaceFlingerBE::mCompositionInfo keeps it alive.
-    for (const auto& [token, display] : mDisplays) {
-        getBE().mCompositionInfo[token].clear();
-    }
-
     // rebuild the visible layer list per screen
     if (CC_UNLIKELY(mVisibleRegionsDirty)) {
         ATRACE_NAME("rebuildLayerStacks VR Dirty");
@@ -2519,16 +2484,19 @@
             getHwComposer().presentAndGetReleaseFences(*displayId);
         }
         display->getRenderSurface()->onPresentDisplayCompleted();
-        for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+        for (auto& layer : display->getOutputLayersOrderedByZ()) {
             sp<Fence> releaseFence = Fence::NO_FENCE;
+            bool usedClientComposition = true;
 
             // The layer buffer from the previous frame (if any) is released
             // by HWC only when the release fence from this frame (if any) is
             // signaled.  Always get the release fence from HWC first.
-            if (displayId && layer->hasHwcLayer(displayDevice)) {
+            if (layer->getState().hwc) {
+                const auto& hwcState = *layer->getState().hwc;
                 releaseFence =
-                        getHwComposer().getLayerReleaseFence(*displayId,
-                                                             layer->getHwcLayer(displayDevice));
+                        getHwComposer().getLayerReleaseFence(*displayId, hwcState.hwcLayer.get());
+                usedClientComposition =
+                        hwcState.hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
             }
 
             // If the layer was client composited in the previous frame, we
@@ -2536,14 +2504,13 @@
             // Since we do not track that, always merge with the current
             // client target acquire fence when it is available, even though
             // this is suboptimal.
-            if (layer->getCompositionType(displayDevice) ==
-                Hwc2::IComposerClient::Composition::CLIENT) {
+            if (usedClientComposition) {
                 releaseFence =
                         Fence::merge("LayerRelease", releaseFence,
                                      display->getRenderSurface()->getClientTargetAcquireFence());
             }
 
-            layer->getBE().onLayerDisplayed(releaseFence);
+            layer->getLayerFE().onLayerDisplayed(releaseFence);
         }
 
         // We've got a list of layers needing fences, that are disjoint with
@@ -2553,7 +2520,7 @@
             sp<Fence> presentFence =
                     displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE;
             for (auto& layer : displayDevice->getLayersNeedingFences()) {
-                layer->getBE().onLayerDisplayed(presentFence);
+                layer->getCompositionLayer()->getLayerFE()->onLayerDisplayed(presentFence);
             }
         }
 
@@ -3244,21 +3211,6 @@
     }
 }
 
-void SurfaceFlinger::initDefaultDisplayNativePrimaries() {
-    mInternalDisplayPrimaries.red.X = kSrgbRedX;
-    mInternalDisplayPrimaries.red.Y = kSrgbRedY;
-    mInternalDisplayPrimaries.red.Z = kSrgbRedZ;
-    mInternalDisplayPrimaries.green.X = kSrgbGreenX;
-    mInternalDisplayPrimaries.green.Y = kSrgbGreenY;
-    mInternalDisplayPrimaries.green.Z = kSrgbGreenZ;
-    mInternalDisplayPrimaries.blue.X = kSrgbBlueX;
-    mInternalDisplayPrimaries.blue.Y = kSrgbBlueY;
-    mInternalDisplayPrimaries.blue.Z = kSrgbBlueZ;
-    mInternalDisplayPrimaries.white.X = kSrgbWhiteX;
-    mInternalDisplayPrimaries.white.Y = kSrgbWhiteY;
-    mInternalDisplayPrimaries.white.Z = kSrgbWhiteZ;
-}
-
 bool SurfaceFlinger::handlePageFlip()
 {
     ALOGV("handlePageFlip");
@@ -3361,6 +3313,9 @@
     auto display = displayDevice->getCompositionDisplay();
     const auto& displayState = display->getState();
     const auto displayId = display->getId();
+    auto& renderEngine = getRenderEngine();
+    const bool supportProtectedContent =
+            mDebugEnableProtectedContent && renderEngine.supportsProtectedContent();
 
     const Region bounds(displayState.bounds);
     const DisplayRenderArea renderArea(displayDevice);
@@ -3378,7 +3333,23 @@
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
 
+        if (displayDevice->isPrimary() && supportProtectedContent) {
+            bool needsProtected = false;
+            for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+                // If the layer is a protected layer, mark protected context is needed.
+                if (layer->isProtected()) {
+                    needsProtected = true;
+                    break;
+                }
+            }
+            if (needsProtected != renderEngine.isProtected() &&
+                renderEngine.useProtectedContext(needsProtected)) {
+                display->getRenderSurface()->setProtected(needsProtected);
+            }
+        }
+
         buf = display->getRenderSurface()->dequeueBuffer(&fd);
+
         if (buf == nullptr) {
             ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
                   "client composition for this frame",
@@ -3450,8 +3421,9 @@
                         // guaranteed the FB is already cleared
                         renderengine::LayerSettings layerSettings;
                         Region dummyRegion;
-                        bool prepared = layer->prepareClientLayer(renderArea, clip, dummyRegion,
-                                                                  layerSettings);
+                        bool prepared =
+                                layer->prepareClientLayer(renderArea, clip, dummyRegion,
+                                                          supportProtectedContent, layerSettings);
 
                         if (prepared) {
                             layerSettings.source.buffer.buffer = nullptr;
@@ -3466,7 +3438,8 @@
                 case Hwc2::IComposerClient::Composition::CLIENT: {
                     renderengine::LayerSettings layerSettings;
                     bool prepared =
-                            layer->prepareClientLayer(renderArea, clip, clearRegion, layerSettings);
+                            layer->prepareClientLayer(renderArea, clip, clearRegion,
+                                                      supportProtectedContent, layerSettings);
                     if (prepared) {
                         clientCompositionLayers.push_back(layerSettings);
                     }
@@ -3497,8 +3470,8 @@
                 clientCompositionLayers.push_back(layerSettings);
             }
         }
-        getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers,
-                                     buf->getNativeBuffer(), std::move(fd), readyFence);
+        renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
+                                buf->getNativeBuffer(), std::move(fd), readyFence);
     }
     return true;
 }
@@ -4132,7 +4105,7 @@
         }
     }
 
-    layer->setMetadata(std::move(metadata));
+    layer->setMetadata(metadata);
 
     bool addToCurrentState = callingThreadHasUnscopedSurfaceFlingerAccess();
     result = addClientLayer(client, *handle, *gbp, layer, *parent,
@@ -5018,9 +4991,9 @@
         code == IBinder::SYSPROPS_TRANSACTION) {
         return OK;
     }
-    // Numbers from 1000 to 1031 are currently use for backdoors. The code
+    // Numbers from 1000 to 1032 are currently use for backdoors. The code
     // in onTransact verifies that the user is root, and has access to use SF.
-    if (code >= 1000 && code <= 1031) {
+    if (code >= 1000 && code <= 1032) {
         ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
         return OK;
     }
@@ -5298,6 +5271,11 @@
                 }
                 return NO_ERROR;
             }
+            case 1032: {
+                n = data.readInt32();
+                mDebugEnableProtectedContent = n;
+                return NO_ERROR;
+            }
         }
     }
     return err;
@@ -5331,7 +5309,8 @@
                                        const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
                                        uint32_t reqWidth, uint32_t reqHeight,
                                        bool useIdentityTransform,
-                                       ISurfaceComposer::Rotation rotation) {
+                                       ISurfaceComposer::Rotation rotation,
+                                       bool captureSecureLayers) {
     ATRACE_CALL();
 
     if (!displayToken) return BAD_VALUE;
@@ -5354,7 +5333,7 @@
     }
 
     DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace,
-                                 renderAreaRotation);
+                                 renderAreaRotation, captureSecureLayers);
 
     auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display,
                                     std::placeholders::_1);
@@ -5678,7 +5657,7 @@
     traverseLayers([&](Layer* layer) {
         renderengine::LayerSettings layerSettings;
         bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion,
-                                                  layerSettings);
+                                                  false, layerSettings);
         if (prepared) {
             clientCompositionLayers.push_back(layerSettings);
         }
@@ -5689,6 +5668,7 @@
     // there is no need for synchronization with the GPU.
     base::unique_fd bufferFence;
     base::unique_fd drawFence;
+    getRenderEngine().useProtectedContext(false);
     getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer,
                                  std::move(bufferFence), &drawFence);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9adfb55..76d0675 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -55,7 +55,6 @@
 #include "DisplayHardware/HWComposer.h"
 #include "Effects/Daltonizer.h"
 #include "FrameTracker.h"
-#include "LayerBE.h"
 #include "LayerStats.h"
 #include "LayerVector.h"
 #include "RegionSamplingThread.h"
@@ -106,7 +105,6 @@
 class SurfaceFlingerBE;
 class TimeStats;
 class VSyncSource;
-struct CompositionInfo;
 
 namespace compositionengine {
 class DisplaySurface;
@@ -199,9 +197,6 @@
     // use to differentiate callbacks from different hardware composer
     // instances. Each hardware composer instance gets a different sequence id.
     int32_t mComposerSequenceId;
-
-    std::map<wp<IBinder>, std::vector<CompositionInfo>> mCompositionInfo;
-    std::map<wp<IBinder>, std::vector<CompositionInfo>> mEndOfFrameCompositionInfo;
 };
 
 class SetInputWindowsListener : public BnSetInputWindowsListener {
@@ -443,7 +438,8 @@
     status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
                            const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
                            Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-                           bool useIdentityTransform, ISurfaceComposer::Rotation rotation) override;
+                           bool useIdentityTransform, ISurfaceComposer::Rotation rotation,
+                           bool captureSecureLayers) override;
     status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
                            const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
                            const Rect& sourceCrop, float frameScale, bool childrenOnly) override;
@@ -711,10 +707,6 @@
     // region of all screens presenting this layer stack.
     void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
 
-    // Initialize structures containing information about the internal
-    // display's native color coordinates using default data
-    void initDefaultDisplayNativePrimaries();
-
     /* ------------------------------------------------------------------------
      * H/W composer
      */
@@ -1002,6 +994,7 @@
     int mDebugRegion;
     int mDebugDisableHWC;
     int mDebugDisableTransformHint;
+    bool mDebugEnableProtectedContent;
     volatile nsecs_t mDebugInSwapBuffers;
     volatile nsecs_t mDebugInTransaction;
     nsecs_t mLastTransactionTime;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index b654ba7..e676d20 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -7,6 +7,7 @@
 #include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
 
+#include <cstdlib>
 #include <tuple>
 
 #include "SurfaceFlingerProperties.h"
@@ -15,6 +16,7 @@
 namespace sysprop {
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
+using ::android::hardware::configstore::V1_2::DisplayPrimaries;
 using ::android::hardware::graphics::common::V1_2::Dataspace;
 using ::android::hardware::graphics::common::V1_2::PixelFormat;
 
@@ -242,5 +244,47 @@
     return static_cast<int32_t>(defaultValue);
 }
 
+#define DISPLAY_PRIMARY_SIZE 3
+
+constexpr float kSrgbRedX = 0.4123f;
+constexpr float kSrgbRedY = 0.2126f;
+constexpr float kSrgbRedZ = 0.0193f;
+constexpr float kSrgbGreenX = 0.3576f;
+constexpr float kSrgbGreenY = 0.7152f;
+constexpr float kSrgbGreenZ = 0.1192f;
+constexpr float kSrgbBlueX = 0.1805f;
+constexpr float kSrgbBlueY = 0.0722f;
+constexpr float kSrgbBlueZ = 0.9506f;
+constexpr float kSrgbWhiteX = 0.9505f;
+constexpr float kSrgbWhiteY = 1.0000f;
+constexpr float kSrgbWhiteZ = 1.0891f;
+
+DisplayPrimaries getDisplayNativePrimaries() {
+    auto mDisplay_primary_red = SurfaceFlingerProperties::display_primary_red();
+    auto mDisplay_primary_green = SurfaceFlingerProperties::display_primary_green();
+    auto mDisplay_primary_blue = SurfaceFlingerProperties::display_primary_blue();
+    auto mDisplay_primary_white = SurfaceFlingerProperties::display_primary_white();
+    // To avoid null point exception.
+    mDisplay_primary_red.resize(DISPLAY_PRIMARY_SIZE);
+    mDisplay_primary_green.resize(DISPLAY_PRIMARY_SIZE);
+    mDisplay_primary_blue.resize(DISPLAY_PRIMARY_SIZE);
+    mDisplay_primary_white.resize(DISPLAY_PRIMARY_SIZE);
+    DisplayPrimaries primaries =
+            {{static_cast<float>(mDisplay_primary_red[0].value_or(kSrgbRedX)),
+              static_cast<float>(mDisplay_primary_red[1].value_or(kSrgbRedY)),
+              static_cast<float>(mDisplay_primary_red[2].value_or(kSrgbRedZ))},
+             {static_cast<float>(mDisplay_primary_green[0].value_or(kSrgbGreenX)),
+              static_cast<float>(mDisplay_primary_green[1].value_or(kSrgbGreenY)),
+              static_cast<float>(mDisplay_primary_green[2].value_or(kSrgbGreenZ))},
+             {static_cast<float>(mDisplay_primary_blue[0].value_or(kSrgbBlueX)),
+              static_cast<float>(mDisplay_primary_blue[1].value_or(kSrgbBlueY)),
+              static_cast<float>(mDisplay_primary_blue[2].value_or(kSrgbBlueZ))},
+             {static_cast<float>(mDisplay_primary_white[0].value_or(kSrgbWhiteX)),
+              static_cast<float>(mDisplay_primary_white[1].value_or(kSrgbWhiteY)),
+              static_cast<float>(mDisplay_primary_white[2].value_or(kSrgbWhiteZ))}};
+
+    return primaries;
+}
+
 } // namespace sysprop
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 9b26883..c86880e 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -53,6 +53,8 @@
 
 int32_t wcg_composition_pixel_format(
         android::hardware::graphics::common::V1_2::PixelFormat defaultValue);
+
+android::hardware::configstore::V1_2::DisplayPrimaries getDisplayNativePrimaries();
 } // namespace sysprop
 } // namespace android
 #endif // SURFACEFLINGERPROPERTIES_H_
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index faf0c54..a0fb0a0 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -113,6 +113,7 @@
   float dtdx = 2;
   float dsdy = 3;
   float dtdy = 4;
+  int32 type = 5;
 }
 
 message RegionProto {
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index cc7b280..429636b 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -250,3 +250,39 @@
     access: Readonly
     prop_name: "ro.surface_flinger.wcg_composition_pixel_format"
 }
+
+# Return the native panel primary data. The data includes red, green,
+# blue and white. The primary format is CIE 1931 XYZ color space.
+# If unspecified, the primaries is sRGB gamut by default.
+
+prop {
+    api_name: "display_primary_red"
+    type: DoubleList
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.surface_flinger.display_primary_red"
+}
+
+prop {
+    api_name: "display_primary_green"
+    type: DoubleList
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.surface_flinger.display_primary_green"
+}
+
+prop {
+    api_name: "display_primary_blue"
+    type: DoubleList
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.surface_flinger.display_primary_blue"
+}
+
+prop {
+    api_name: "display_primary_white"
+    type: DoubleList
+    scope: Internal
+    access: Readonly
+    prop_name: "ro.surface_flinger.display_primary_white"
+}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 181dac6..34cdff7 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -33,6 +33,7 @@
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
+#include <private/android_filesystem_config.h>
 
 #include <ui/ColorSpace.h>
 #include <ui/DisplayInfo.h>
@@ -41,6 +42,8 @@
 
 #include <math.h>
 #include <math/vec3.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "BufferGenerator.h"
 
@@ -1201,6 +1204,56 @@
               composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
 }
 
+/** RAII Wrapper around get/seteuid */
+class UIDFaker {
+    uid_t oldId;
+public:
+    UIDFaker(uid_t uid) {
+        oldId = geteuid();
+        seteuid(uid);
+    }
+    ~UIDFaker() {
+        seteuid(oldId);
+    }
+};
+
+TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<GraphicBuffer> outBuffer;
+    Transaction()
+            .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
+            .apply(true);
+    ASSERT_EQ(PERMISSION_DENIED,
+              composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+    UIDFaker f(AID_SYSTEM);
+
+    // By default the system can capture screenshots with secure layers but they
+    // will be blacked out
+    ASSERT_EQ(NO_ERROR,
+              composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+    {
+        SCOPED_TRACE("as system");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able
+    // to receive them...we are expected to take care with the results.
+    ASSERT_EQ(NO_ERROR,
+              composer->captureScreen(mDisplay, &outBuffer,
+                      ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888,
+                      Rect(), 0, 0, false,
+                      ISurfaceComposer::eRotateNone, true));
+    ScreenCapture sc(outBuffer);
+    sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
 TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferQueue) {
     const Rect top(0, 0, 32, 16);
     const Rect bottom(0, 16, 32, 32);
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 19f308b..1487d47 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -1322,32 +1322,6 @@
     EXPECT_EQ(BAD_VALUE, mFlinger.getDisplayNativePrimaries(nullptr, primaries));
 }
 
-TEST_F(GetDisplayNativePrimaries, internalDisplayWithDefaultPrimariesData) {
-    auto injector = SimplePrimaryDisplayCase::Display::makeFakeExistingDisplayInjector(this);
-    injector.inject();
-    auto internalDisplayToken = injector.token();
-    // A nullptr would trigger a different execution path than what's being tested here
-    EXPECT_NE(nullptr, internalDisplayToken.get());
-
-    mFlinger.initDefaultDisplayNativePrimaries();
-
-    ui::DisplayPrimaries primaries;
-    // Expecting sRGB primaries
-    EXPECT_EQ(NO_ERROR, mFlinger.getDisplayNativePrimaries(internalDisplayToken, primaries));
-    EXPECT_EQ(primaries.red.X, 0.4123f);
-    EXPECT_EQ(primaries.red.Y, 0.2126f);
-    EXPECT_EQ(primaries.red.Z, 0.0193f);
-    EXPECT_EQ(primaries.green.X, 0.3576f);
-    EXPECT_EQ(primaries.green.Y, 0.7152f);
-    EXPECT_EQ(primaries.green.Z, 0.1192f);
-    EXPECT_EQ(primaries.blue.X, 0.1805f);
-    EXPECT_EQ(primaries.blue.Y, 0.0722f);
-    EXPECT_EQ(primaries.blue.Z, 0.9506f);
-    EXPECT_EQ(primaries.white.X, 0.9505f);
-    EXPECT_EQ(primaries.white.Y, 1.0000f);
-    EXPECT_EQ(primaries.white.Z, 1.0891f);
-}
-
 TEST_F(GetDisplayNativePrimaries, internalDisplayWithPrimariesData) {
     auto injector = SimplePrimaryDisplayCase::Display::makeFakeExistingDisplayInjector(this);
     injector.inject();
diff --git a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
index 92c9f92..75a061b 100644
--- a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp
@@ -62,17 +62,6 @@
     metadata.mMap[2] = std::vector<uint8_t>{'a', 'b'};
     ASSERT_EQ(0, metadata.getInt32(2, 0));
 
-    LayerMetadata second;
-    std::vector<uint8_t> someData{'c', 'd', '\0'};
-    second.mMap[2] = someData;
-    second.setInt32(6, 5);
-    metadata.merge(second);
-
-    ASSERT_EQ(3, metadata.mMap.size());
-    ASSERT_EQ(someData, second.mMap[2]);
-    ASSERT_EQ(5, metadata.getInt32(6, 0));
-    ASSERT_EQ(2, metadata.getInt32(4, 0));
-
     Parcel p;
     metadata.writeToParcel(&p);
     LayerMetadata reconstructed;
@@ -82,5 +71,39 @@
     ASSERT_EQ(metadata.mMap, reconstructed.mMap);
 }
 
+TEST_F(LayerMetadataTest, merge) {
+    LayerMetadata metadata;
+    metadata.setInt32(4, 2);
+    metadata.mMap[2] = std::vector<uint8_t>{'a', 'b'};
+
+    LayerMetadata second;
+    std::vector<uint8_t> someData{'c', 'd', '\0'};
+    second.mMap[2] = someData;
+    second.setInt32(6, 5);
+    second.mMap[4].clear(); // will not delete if eraseEmpty is false
+    bool changed = metadata.merge(second);
+
+    ASSERT_TRUE(changed);
+    ASSERT_EQ(3, metadata.mMap.size());
+    ASSERT_EQ(someData, second.mMap[2]);
+    ASSERT_EQ(5, metadata.getInt32(6, 0));
+    ASSERT_TRUE(metadata.mMap.at(4).empty());
+
+    LayerMetadata withErase;
+    withErase.mMap[6].clear();
+    changed = metadata.merge(withErase, true /* eraseEmpty */);
+    ASSERT_TRUE(changed);
+    ASSERT_EQ(2, metadata.mMap.size());
+    ASSERT_EQ(someData, second.mMap[2]);
+    ASSERT_EQ(true, metadata.has(4));
+
+    // test for change detection
+    LayerMetadata third;
+    third.mMap[2] = someData;
+    third.mMap[5].clear();
+    changed = metadata.merge(third);
+    ASSERT_FALSE(changed);
+}
+
 } // namespace
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 6313f1f..d61973e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -289,10 +289,6 @@
         return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
     }
 
-    void initDefaultDisplayNativePrimaries() {
-        mFlinger->SurfaceFlinger::initDefaultDisplayNativePrimaries();
-    }
-
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index b49d894..a7fd912 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -392,8 +392,8 @@
 Status<void> ProducerChannel::OnProducerPost(Message&,
                                              LocalFence acquire_fence) {
   ATRACE_NAME("ProducerChannel::OnProducerPost");
-  ALOGD("ProducerChannel::OnProducerPost: buffer_id=%d, state=0x%x",
-        buffer_id(), buffer_state_->load(std::memory_order_acquire));
+  ALOGD_IF(TRACE, "%s: buffer_id=%d, state=0x%x", __FUNCTION__, buffer_id(),
+           buffer_state_->load(std::memory_order_acquire));
 
   epoll_event event;
   event.events = 0;
@@ -437,7 +437,7 @@
 
 Status<LocalFence> ProducerChannel::OnProducerGain(Message& /*message*/) {
   ATRACE_NAME("ProducerChannel::OnGain");
-  ALOGW("ProducerChannel::OnGain: buffer_id=%d", buffer_id());
+  ALOGD_IF(TRACE, "%s: buffer_id=%d", __FUNCTION__, buffer_id());
 
   ClearAvailable();
   post_fence_.close();