Merge "SF: Fix two display identification bugs"
diff --git a/libs/binder/ndk/AIBinder.cpp b/libs/binder/ndk/AIBinder.cpp
index 40d3a00..b7f5636 100644
--- a/libs/binder/ndk/AIBinder.cpp
+++ b/libs/binder/ndk/AIBinder.cpp
@@ -202,6 +202,22 @@
     return binder->isRemote();
 }
 
+bool AIBinder_isAlive(const AIBinder* binder) {
+    if (binder == nullptr) {
+        return false;
+    }
+
+    return const_cast<AIBinder*>(binder)->getBinder()->isBinderAlive();
+}
+
+binder_status_t AIBinder_ping(AIBinder* binder) {
+    if (binder == nullptr) {
+        return EX_NULL_POINTER;
+    }
+
+    return binder->getBinder()->pingBinder();
+}
+
 void AIBinder_incStrong(AIBinder* binder) {
     if (binder == nullptr) {
         LOG(ERROR) << __func__ << ": on null binder";
@@ -269,6 +285,10 @@
         return EX_ILLEGAL_STATE;
     }
 
+    if (!binder->isRemote()) {
+        LOG(WARNING) << "A binder object at " << binder << " is being transacted on, however, this object is in the same process as its proxy. Transacting with this binder is expensive compared to just calling the corresponding functionality in the same process.";
+    }
+
     *in = new AParcel(binder);
     binder_status_t status = (**in)->writeInterfaceToken(clazz->getInterfaceDescriptor());
     if (status != EX_NONE) {
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 91a87fd..aa29437 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -147,6 +147,22 @@
 bool AIBinder_isRemote(const AIBinder* binder);
 
 /**
+ * If this binder is known to be alive. This will not send a transaction to a remote process and
+ * returns a result based on the last known information. That is, whenever a transaction is made,
+ * this is automatically updated to reflect the current alive status of this binder. This will be
+ * updated as the result of a transaction made using AIBinder_transact, but it will also be updated
+ * based on the results of bookkeeping or other transactions made internally.
+ */
+bool AIBinder_isAlive(const AIBinder* binder);
+
+/**
+ * Built-in transaction for all binder objects. This sends a transaction which will immediately
+ * return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a
+ * sanity check.
+ */
+binder_status_t AIBinder_ping(AIBinder* binder);
+
+/**
  * This can only be called if a strong reference to this object already exists in process.
  */
 void AIBinder_incStrong(AIBinder* binder);
@@ -172,7 +188,7 @@
  */
 bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz);
 
-/*
+/**
  * Returns the class that this binder was constructed with or associated with.
  */
 const AIBinder_Class* AIBinder_getClass(AIBinder* binder);
@@ -221,13 +237,13 @@
 binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
                                   AParcel** out, binder_flags_t flags);
 
-/*
+/**
  * This does not take any ownership of the input binder, but it can be used to retrieve it if
  * something else in some process still holds a reference to it.
  */
 __attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder);
 
-/*
+/**
  * Deletes the weak reference. This will have no impact on the lifetime of the binder.
  */
 void AIBinder_Weak_delete(AIBinder_Weak** weakBinder);
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index 7c53e51..967789f 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -38,6 +38,10 @@
 TEST(NdkBinder, RetrieveNonNdkService) {
     AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
     ASSERT_NE(nullptr, binder);
+    EXPECT_TRUE(AIBinder_isRemote(binder));
+    EXPECT_TRUE(AIBinder_isAlive(binder));
+    EXPECT_EQ(EX_NONE, AIBinder_ping(binder));
+
     AIBinder_decStrong(binder);
 }
 
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index ef3e592..98264ac 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -31,6 +31,7 @@
         "-Werror",
     ],
     cppflags: [
+        "-std=c++1z",
         "-Weverything",
 
         // The static constructors and destructors in this library have not been noted to
@@ -58,7 +59,7 @@
         "-Wno-weak-vtables",
 
         // Allow four-character integer literals
-	"-Wno-four-char-constants",
+        "-Wno-four-char-constants",
 
         // Allow documentation warnings
         "-Wno-documentation",
@@ -116,7 +117,7 @@
         "SyncFeatures.cpp",
         "view/Surface.cpp",
         "bufferqueue/1.0/B2HProducerListener.cpp",
-        "bufferqueue/1.0/H2BGraphicBufferProducer.cpp"
+        "bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
     ],
 
     shared_libs: [
@@ -124,7 +125,7 @@
         "libsync",
         "libbinder",
         "libbufferhub",
-        "libbufferhubqueue",  // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
+        "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
         "libpdx_default_transport",
         "libcutils",
         "libEGL",
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 7f9668f..08fbfff 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -558,6 +558,25 @@
         outLayers->clear();
         return reply.readParcelableVector(outLayers);
     }
+
+    virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
+                                              ui::PixelFormat* pixelFormat) const {
+        Parcel data, reply;
+        status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        if (error != NO_ERROR) {
+            return error;
+        }
+        error = remote()->transact(BnSurfaceComposer::GET_COMPOSITION_PREFERENCE, data, &reply);
+        if (error != NO_ERROR) {
+            return error;
+        }
+        error = static_cast<status_t>(reply.readInt32());
+        if (error == NO_ERROR) {
+            *dataSpace = static_cast<ui::Dataspace>(reply.readInt32());
+            *pixelFormat = static_cast<ui::PixelFormat>(reply.readInt32());
+        }
+        return error;
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -881,6 +900,18 @@
             }
             return result;
         }
+        case GET_COMPOSITION_PREFERENCE: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            ui::Dataspace dataSpace;
+            ui::PixelFormat pixelFormat;
+            status_t error = getCompositionPreference(&dataSpace, &pixelFormat);
+            reply->writeInt32(error);
+            if (error == NO_ERROR) {
+                reply->writeInt32(static_cast<int32_t>(dataSpace));
+                reply->writeInt32(static_cast<int32_t>(pixelFormat));
+            }
+            return NO_ERROR;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7168de4..4caadd1 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -854,6 +854,11 @@
     ComposerService::getComposerService()->setPowerMode(token, mode);
 }
 
+status_t SurfaceComposerClient::getCompositionPreference(ui::Dataspace* dataSpace,
+                                                         ui::PixelFormat* pixelFormat) {
+    return ComposerService::getComposerService()->getCompositionPreference(dataSpace, pixelFormat);
+}
+
 status_t SurfaceComposerClient::clearAnimationFrameStats() {
     return ComposerService::getComposerService()->clearAnimationFrameStats();
 }
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
index 3b89291..8af1a67 100644
--- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -100,7 +100,12 @@
  */
 // convert: Return<Status> -> status_t
 inline status_t toStatusT(Return<Status> const& t) {
-    return t.isOk() ? static_cast<status_t>(static_cast<Status>(t)) : UNKNOWN_ERROR;
+    if (t.isOk()) {
+        return static_cast<status_t>(static_cast<Status>(t));
+    } else if (t.isDeadObject()) {
+        return DEAD_OBJECT;
+    }
+    return UNKNOWN_ERROR;
 }
 
 /**
@@ -111,7 +116,7 @@
  */
 // convert: Return<void> -> status_t
 inline status_t toStatusT(Return<void> const& t) {
-    return t.isOk() ? OK : UNKNOWN_ERROR;
+    return t.isOk() ? OK : (t.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR);
 }
 
 /**
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 98ec338..46103c4 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -171,8 +171,25 @@
     virtual status_t setActiveColorMode(const sp<IBinder>& display,
             ui::ColorMode colorMode) = 0;
 
-    /* Capture the specified screen. requires READ_FRAME_BUFFER permission
-     * This function will fail if there is a secure window on screen.
+    /**
+     * Capture the specified screen. This requires READ_FRAME_BUFFER
+     * permission.  This function will fail if there is a secure window on
+     * screen.
+     *
+     * This function can capture a subregion (the source crop) of the screen.
+     * The subregion can be optionally rotated.  It will also be scaled to
+     * match the size of the output buffer.
+     *
+     * At the moment, sourceCrop is ignored and is always set to the visible
+     * region (projected display viewport) of the screen.
+     *
+     * reqWidth and reqHeight specifies the size of the buffer.  When either
+     * of them is 0, they are set to the size of the logical display viewport.
+     *
+     * When useIdentityTransform is true, layer transformations are disabled.
+     *
+     * rotation specifies the rotation of the source crop (and the pixels in
+     * it) around its center.
      */
     virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
                                    Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
@@ -214,6 +231,9 @@
      * Requires the ACCESS_SURFACE_FLINGER permission.
      */
     virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const = 0;
+
+    virtual status_t getCompositionPreference(ui::Dataspace* dataSpace,
+                                              ui::PixelFormat* pixelFormat) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -250,7 +270,8 @@
         ENABLE_VSYNC_INJECTIONS,
         INJECT_VSYNC,
         GET_LAYER_DEBUG_INFO,
-        CREATE_SCOPED_CONNECTION
+        CREATE_SCOPED_CONNECTION,
+        GET_COMPOSITION_PREFERENCE,
     };
 
     virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 0859aff..9a9f633 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -183,10 +183,24 @@
     sp<IBinder> token;
     sp<IGraphicBufferProducer> surface;
     uint32_t layerStack;
+
+    // These states define how layers are projected onto the physical display.
+    //
+    // Layers are first clipped to `viewport'.  They are then translated and
+    // scaled from `viewport' to `frame'.  Finally, they are rotated according
+    // to `orientation', `width', and `height'.
+    //
+    // For example, assume viewport is Rect(0, 0, 200, 100), frame is Rect(20,
+    // 10, 420, 210), and the size of the display is WxH.  When orientation is
+    // 0, layers will be scaled by a factor of 2 and translated by (20, 10).
+    // When orientation is 1, layers will be additionally rotated by 90
+    // degrees around the origin clockwise and translated by (W, 0).
     uint32_t orientation;
     Rect viewport;
     Rect frame;
+
     uint32_t width, height;
+
     status_t write(Parcel& output) const;
     status_t read(const Parcel& input);
 };
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index d83ba84..662acc9 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -101,6 +101,10 @@
     /* Triggers screen on/off or low power mode and waits for it to complete */
     static void setDisplayPowerMode(const sp<IBinder>& display, int mode);
 
+    //
+    static status_t getCompositionPreference(ui::Dataspace* dataSpace,
+                                             ui::PixelFormat* pixelFormat);
+
     // ------------------------------------------------------------------------
     // surface creation / destruction
 
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 3542aba..243f27f 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -622,6 +622,10 @@
     status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) const override {
         return NO_ERROR;
     }
+    status_t getCompositionPreference(ui::Dataspace* /*outDataSpace*/,
+                                      ui::PixelFormat* /*outPixelFormat*/) const override {
+        return NO_ERROR;
+    }
 
 protected:
     IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index e3ef2a9..1605050 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -26,6 +26,7 @@
         "-Werror",
     ],
     cppflags: [
+        "-std=c++1z",
         "-Weverything",
 
         // The static constructors and destructors in this library have not been noted to
diff --git a/libs/ui/FenceTime.cpp b/libs/ui/FenceTime.cpp
index 1414766..340231d 100644
--- a/libs/ui/FenceTime.cpp
+++ b/libs/ui/FenceTime.cpp
@@ -33,18 +33,6 @@
 
 const auto FenceTime::NO_FENCE = std::make_shared<FenceTime>(Fence::NO_FENCE);
 
-void* FenceTime::operator new(size_t byteCount) noexcept {
-    void *p = nullptr;
-    if (posix_memalign(&p, alignof(FenceTime), byteCount)) {
-        return nullptr;
-    }
-    return p;
-}
-
-void FenceTime::operator delete(void *p) {
-    free(p);
-}
-
 FenceTime::FenceTime(const sp<Fence>& fence)
   : mState(((fence.get() != nullptr) && fence->isValid()) ?
             State::VALID : State::INVALID),
diff --git a/libs/ui/include/ui/FenceTime.h b/libs/ui/include/ui/FenceTime.h
index 871fcf2..a5a1fcb 100644
--- a/libs/ui/include/ui/FenceTime.h
+++ b/libs/ui/include/ui/FenceTime.h
@@ -113,11 +113,6 @@
 
     void signalForTest(nsecs_t signalTime);
 
-    // Override new and delete since this needs 8-byte alignment, which
-    // is not guaranteed on x86.
-    static void* operator new(size_t nbytes) noexcept;
-    static void operator delete(void *p);
-
 private:
     // For tests only. If forceValidForTest is true, then getSignalTime will
     // never return SIGNAL_TIME_INVALID and isValid will always return true.
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index c805805..d609573 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -515,9 +515,10 @@
 sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
         int32_t x, int32_t y) {
     // Traverse windows from front to back to find touched window.
-    size_t numWindows = mWindowHandles.size();
+    const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+    size_t numWindows = windowHandles.size();
     for (size_t i = 0; i < numWindows; i++) {
-        sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+        sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
         const InputWindowInfo* windowInfo = windowHandle->getInfo();
         if (windowInfo->displayId == displayId) {
             int32_t flags = windowInfo->layoutParamsFlags;
@@ -1247,9 +1248,10 @@
         bool isTouchModal = false;
 
         // Traverse windows from front to back to find touched window and outside targets.
-        size_t numWindows = mWindowHandles.size();
+        const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+        size_t numWindows = windowHandles.size();
         for (size_t i = 0; i < numWindows; i++) {
-            sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+            sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
             const InputWindowInfo* windowInfo = windowHandle->getInfo();
             if (windowInfo->displayId != displayId) {
                 continue; // wrong display
@@ -1472,8 +1474,10 @@
         sp<InputWindowHandle> foregroundWindowHandle =
                 mTempTouchState.getFirstForegroundWindowHandle();
         if (foregroundWindowHandle->getInfo()->hasWallpaper) {
-            for (size_t i = 0; i < mWindowHandles.size(); i++) {
-                sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
+            const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+            size_t numWindows = windowHandles.size();
+            for (size_t i = 0; i < numWindows; i++) {
+                sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
                 const InputWindowInfo* info = windowHandle->getInfo();
                 if (info->displayId == displayId
                         && windowHandle->getInfo()->layoutParamsType
@@ -1658,9 +1662,10 @@
 bool InputDispatcher::isWindowObscuredAtPointLocked(
         const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
     int32_t displayId = windowHandle->getInfo()->displayId;
-    size_t numWindows = mWindowHandles.size();
+    const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+    size_t numWindows = windowHandles.size();
     for (size_t i = 0; i < numWindows; i++) {
-        sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
+        sp<InputWindowHandle> otherHandle = windowHandles.itemAt(i);
         if (otherHandle == windowHandle) {
             break;
         }
@@ -1678,10 +1683,11 @@
 
 bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const {
     int32_t displayId = windowHandle->getInfo()->displayId;
+    const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
     const InputWindowInfo* windowInfo = windowHandle->getInfo();
-    size_t numWindows = mWindowHandles.size();
+    size_t numWindows = windowHandles.size();
     for (size_t i = 0; i < numWindows; i++) {
-        sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i);
+        sp<InputWindowHandle> otherHandle = windowHandles.itemAt(i);
         if (otherHandle == windowHandle) {
             break;
         }
@@ -2909,13 +2915,27 @@
     }
 }
 
+Vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(int32_t displayId) const {
+    std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>>::const_iterator it =
+        mWindowHandlesByDisplay.find(displayId);
+    if(it != mWindowHandlesByDisplay.end()) {
+        return it->second;
+    }
+
+    // Return an empty one if nothing found.
+    return Vector<sp<InputWindowHandle>>();
+}
+
 sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
         const sp<InputChannel>& inputChannel) const {
-    size_t numWindows = mWindowHandles.size();
-    for (size_t i = 0; i < numWindows; i++) {
-        const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
-        if (windowHandle->getInputChannel() == inputChannel) {
-            return windowHandle;
+    for (auto& it : mWindowHandlesByDisplay) {
+        const Vector<sp<InputWindowHandle>> windowHandles = it.second;
+        size_t numWindows = windowHandles.size();
+        for (size_t i = 0; i < numWindows; i++) {
+            const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+            if (windowHandle->getInputChannel() == inputChannel) {
+                return windowHandle;
+            }
         }
     }
     return nullptr;
@@ -2923,45 +2943,90 @@
 
 bool InputDispatcher::hasWindowHandleLocked(
         const sp<InputWindowHandle>& windowHandle) const {
-    size_t numWindows = mWindowHandles.size();
-    for (size_t i = 0; i < numWindows; i++) {
-        if (mWindowHandles.itemAt(i) == windowHandle) {
-            return true;
+    for (auto& it : mWindowHandlesByDisplay) {
+        const Vector<sp<InputWindowHandle>> windowHandles = it.second;
+        size_t numWindows = windowHandles.size();
+        for (size_t i = 0; i < numWindows; i++) {
+            if (windowHandles.itemAt(i) == windowHandle) {
+                if (windowHandle->getInfo()->displayId != it.first) {
+                    ALOGE("Found window %s in display %d, but it should belong to display %d",
+                        windowHandle->getName().c_str(), it.first,
+                        windowHandle->getInfo()->displayId);
+                }
+                return true;
+            }
         }
     }
     return false;
 }
 
-void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) {
+/**
+ * Called from InputManagerService, update window handle list by displayId that can receive input.
+ * A window handle contains information about InputChannel, Touch Region, Types, Focused,...
+ * If set an empty list, remove all handles from the specific display.
+ * For focused handle, check if need to change and send a cancel event to previous one.
+ * For removed handle, check if need to send a cancel event if already in touch.
+ */
+void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& inputWindowHandles,
+        int32_t displayId) {
 #if DEBUG_FOCUS
     ALOGD("setInputWindows");
 #endif
     { // acquire lock
         AutoMutex _l(mLock);
 
-        Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles;
-        mWindowHandles = inputWindowHandles;
+        // Copy old handles for release if they are no longer present.
+        const Vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
 
-        sp<InputWindowHandle> newFocusedWindowHandle;
+        // TODO(b/111361570): multi-display focus, one focus window per display.
+        sp<InputWindowHandle> newFocusedWindowHandle = mFocusedWindowHandle;
+        // Reset newFocusedWindowHandle to nullptr if current display own the focus window,
+        // that will be updated below when going through all window handles in current display.
+        // And if list of window handles becomes empty then it will be updated by other display.
+        if (mFocusedWindowHandle != nullptr) {
+            const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
+            if (info == nullptr || info->displayId == displayId) {
+                newFocusedWindowHandle = nullptr;
+            }
+        }
+
         bool foundHoveredWindow = false;
-        for (size_t i = 0; i < mWindowHandles.size(); i++) {
-            const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
-            if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) {
-                mWindowHandles.removeAt(i--);
-                continue;
+
+        if (inputWindowHandles.isEmpty()) {
+            // Remove all handles on a display if there are no windows left.
+            mWindowHandlesByDisplay.erase(displayId);
+        } else {
+            size_t numWindows = inputWindowHandles.size();
+            for (size_t i = 0; i < numWindows; i++) {
+                const sp<InputWindowHandle>& windowHandle = inputWindowHandles.itemAt(i);
+                if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) {
+                    continue;
+                }
+
+                if (windowHandle->getInfo()->displayId != displayId) {
+                    ALOGE("Window %s updated by wrong display %d, should belong to display %d",
+                        windowHandle->getName().c_str(), displayId,
+                        windowHandle->getInfo()->displayId);
+                    continue;
+                }
+
+                if (windowHandle->getInfo()->hasFocus) {
+                    newFocusedWindowHandle = windowHandle;
+                }
+                if (windowHandle == mLastHoverWindowHandle) {
+                    foundHoveredWindow = true;
+                }
             }
-            if (windowHandle->getInfo()->hasFocus) {
-                newFocusedWindowHandle = windowHandle;
-            }
-            if (windowHandle == mLastHoverWindowHandle) {
-                foundHoveredWindow = true;
-            }
+
+            // Insert or replace
+            mWindowHandlesByDisplay[displayId] = inputWindowHandles;
         }
 
         if (!foundHoveredWindow) {
             mLastHoverWindowHandle = nullptr;
         }
 
+        // TODO(b/111361570): multi-display focus, one focus in all display in current.
         if (mFocusedWindowHandle != newFocusedWindowHandle) {
             if (mFocusedWindowHandle != nullptr) {
 #if DEBUG_FOCUS
@@ -2985,8 +3050,9 @@
             mFocusedWindowHandle = newFocusedWindowHandle;
         }
 
-        for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) {
-            TouchState& state = mTouchStatesByDisplay.editValueAt(d);
+        ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
+        if (stateIndex >= 0) {
+            TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex);
             for (size_t i = 0; i < state.windows.size(); ) {
                 TouchedWindow& touchedWindow = state.windows.editItemAt(i);
                 if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
@@ -3013,7 +3079,8 @@
         // This ensures that unused input channels are released promptly.
         // Otherwise, they might stick around until the window handle is destroyed
         // which might not happen until the next GC.
-        for (size_t i = 0; i < oldWindowHandles.size(); i++) {
+        size_t numWindows = oldWindowHandles.size();
+        for (size_t i = 0; i < numWindows; i++) {
             const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i);
             if (!hasWindowHandleLocked(oldWindowHandle)) {
 #if DEBUG_FOCUS
@@ -3266,36 +3333,44 @@
         dump += INDENT "TouchStates: <no displays touched>\n";
     }
 
-    if (!mWindowHandles.isEmpty()) {
-        dump += INDENT "Windows:\n";
-        for (size_t i = 0; i < mWindowHandles.size(); i++) {
-            const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
-            const InputWindowInfo* windowInfo = windowHandle->getInfo();
+    if (!mWindowHandlesByDisplay.empty()) {
+       for (auto& it : mWindowHandlesByDisplay) {
+            const Vector<sp<InputWindowHandle>> windowHandles = it.second;
+            dump += StringPrintf(INDENT "Display: %d\n", it.first);
+            if (!windowHandles.isEmpty()) {
+                dump += INDENT2 "Windows:\n";
+                for (size_t i = 0; i < windowHandles.size(); i++) {
+                    const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+                    const InputWindowInfo* windowInfo = windowHandle->getInfo();
 
-            dump += StringPrintf(INDENT2 "%zu: name='%s', displayId=%d, "
-                    "paused=%s, hasFocus=%s, hasWallpaper=%s, "
-                    "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
-                    "frame=[%d,%d][%d,%d], scale=%f, "
-                    "touchableRegion=",
-                    i, windowInfo->name.c_str(), windowInfo->displayId,
-                    toString(windowInfo->paused),
-                    toString(windowInfo->hasFocus),
-                    toString(windowInfo->hasWallpaper),
-                    toString(windowInfo->visible),
-                    toString(windowInfo->canReceiveKeys),
-                    windowInfo->layoutParamsFlags, windowInfo->layoutParamsType,
-                    windowInfo->layer,
-                    windowInfo->frameLeft, windowInfo->frameTop,
-                    windowInfo->frameRight, windowInfo->frameBottom,
-                    windowInfo->scaleFactor);
-            dumpRegion(dump, windowInfo->touchableRegion);
-            dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
-            dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
-                    windowInfo->ownerPid, windowInfo->ownerUid,
-                    windowInfo->dispatchingTimeout / 1000000.0);
+                    dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, "
+                            "paused=%s, hasFocus=%s, hasWallpaper=%s, "
+                            "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
+                            "frame=[%d,%d][%d,%d], scale=%f, "
+                            "touchableRegion=",
+                            i, windowInfo->name.c_str(), windowInfo->displayId,
+                            toString(windowInfo->paused),
+                            toString(windowInfo->hasFocus),
+                            toString(windowInfo->hasWallpaper),
+                            toString(windowInfo->visible),
+                            toString(windowInfo->canReceiveKeys),
+                            windowInfo->layoutParamsFlags, windowInfo->layoutParamsType,
+                            windowInfo->layer,
+                            windowInfo->frameLeft, windowInfo->frameTop,
+                            windowInfo->frameRight, windowInfo->frameBottom,
+                            windowInfo->scaleFactor);
+                    dumpRegion(dump, windowInfo->touchableRegion);
+                    dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
+                    dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
+                            windowInfo->ownerPid, windowInfo->ownerUid,
+                            windowInfo->dispatchingTimeout / 1000000.0);
+                }
+            } else {
+                dump += INDENT2 "Windows: <none>\n";
+            }
         }
     } else {
-        dump += INDENT "Windows: <none>\n";
+        dump += INDENT "Displays: <none>\n";
     }
 
     if (!mMonitoringChannels.isEmpty()) {
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 31ab339..fdf75f6 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -31,6 +31,7 @@
 #include <stddef.h>
 #include <unistd.h>
 #include <limits.h>
+#include <unordered_map>
 
 #include "InputWindow.h"
 #include "InputApplication.h"
@@ -307,7 +308,8 @@
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) = 0;
+    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
+            int32_t displayId) = 0;
 
     /* Sets the focused application.
      *
@@ -387,7 +389,8 @@
             int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
             uint32_t policyFlags);
 
-    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles);
+    virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
+            int32_t displayId);
     virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle);
     virtual void setInputDispatchMode(bool enabled, bool frozen);
     virtual void setInputFilterEnabled(bool enabled);
@@ -956,8 +959,9 @@
     bool mDispatchFrozen;
     bool mInputFilterEnabled;
 
-    Vector<sp<InputWindowHandle> > mWindowHandles;
-
+    std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay;
+    // Get window handles by display, return an empty vector if not found.
+    Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const;
     sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const;
     bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const;
 
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 0e26d4a..61dcdd9 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -103,13 +103,20 @@
 protected:
     sp<FakeInputDispatcherPolicy> mFakePolicy;
     sp<InputDispatcher> mDispatcher;
+    sp<InputDispatcherThread> mDispatcherThread;
 
     virtual void SetUp() {
         mFakePolicy = new FakeInputDispatcherPolicy();
         mDispatcher = new InputDispatcher(mFakePolicy);
+        mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
+        //Start InputDispatcher thread
+        mDispatcherThread = new InputDispatcherThread(mDispatcher);
+        mDispatcherThread->run("InputDispatcherTest", PRIORITY_URGENT_DISPLAY);
     }
 
     virtual void TearDown() {
+        mDispatcherThread->requestExit();
+        mDispatcherThread.clear();
         mFakePolicy.clear();
         mDispatcher.clear();
     }
@@ -253,4 +260,297 @@
             << "Should reject motion events with duplicate pointer ids.";
 }
 
+// --- InputDispatcherTest SetInputWindowTest ---
+static const int32_t INJECT_EVENT_TIMEOUT = 500;
+static const int32_t DISPATCHING_TIMEOUT = 100;
+
+class FakeApplicationHandle : public InputApplicationHandle {
+public:
+    FakeApplicationHandle() {}
+    virtual ~FakeApplicationHandle() {}
+
+    virtual bool updateInfo() {
+        if (!mInfo) {
+            mInfo = new InputApplicationInfo();
+        }
+        mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
+        return true;
+    }
+};
+
+class FakeWindowHandle : public InputWindowHandle {
+public:
+    static const int32_t WIDTH = 600;
+    static const int32_t HEIGHT = 800;
+
+    FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
+        const sp<InputDispatcher>& dispatcher, const std::string name) :
+            InputWindowHandle(inputApplicationHandle), mDispatcher(dispatcher),
+            mName(name), mFocused(false), mDisplayId(ADISPLAY_ID_DEFAULT) {
+        InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
+        mConsumer = new InputConsumer(mClientChannel);
+        mDispatcher->registerInputChannel(mServerChannel, this, false);
+    }
+
+    virtual ~FakeWindowHandle() {
+        mDispatcher->unregisterInputChannel(mServerChannel);
+        mServerChannel.clear();
+        mClientChannel.clear();
+        mDispatcher.clear();
+
+        if (mConsumer != nullptr) {
+            delete mConsumer;
+        }
+    }
+
+    virtual bool updateInfo() {
+        if (!mInfo) {
+            mInfo = new InputWindowInfo();
+        }
+        mInfo->inputChannel = mServerChannel;
+        mInfo->name = mName;
+        mInfo->layoutParamsFlags = 0;
+        mInfo->layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
+        mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
+        mInfo->frameLeft = 0;
+        mInfo->frameTop = 0;
+        mInfo->frameRight = WIDTH;
+        mInfo->frameBottom = HEIGHT;
+        mInfo->scaleFactor = 1.0;
+        mInfo->addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
+        mInfo->visible = true;
+        mInfo->canReceiveKeys = true;
+        mInfo->hasFocus = mFocused;
+        mInfo->hasWallpaper = false;
+        mInfo->paused = false;
+        mInfo->layer = 0;
+        mInfo->ownerPid = INJECTOR_PID;
+        mInfo->ownerUid = INJECTOR_UID;
+        mInfo->inputFeatures = 0;
+        mInfo->displayId = mDisplayId;
+
+        return true;
+    }
+
+    void setFocus() {
+        mFocused = true;
+    }
+
+    void setDisplayId(int32_t displayId) {
+        mDisplayId = displayId;
+    }
+
+    void consumeEvent(int32_t expectedEventType, int32_t expectedDisplayId) {
+        uint32_t consumeSeq;
+        InputEvent* event;
+        status_t status = mConsumer->consume(&mEventFactory, false /*consumeBatches*/, -1,
+            &consumeSeq, &event);
+
+        ASSERT_EQ(OK, status)
+                << mName.c_str() << ": consumer consume should return OK.";
+        ASSERT_TRUE(event != nullptr)
+                << mName.c_str() << ": consumer should have returned non-NULL event.";
+        ASSERT_EQ(expectedEventType, event->getType())
+                << mName.c_str() << ": consumer type should same as expected one.";
+
+        ASSERT_EQ(expectedDisplayId, event->getDisplayId())
+                << mName.c_str() << ": consumer displayId should same as expected one.";
+
+        status = mConsumer->sendFinishedSignal(consumeSeq, true /*handled*/);
+        ASSERT_EQ(OK, status)
+                << mName.c_str() << ": consumer sendFinishedSignal should return OK.";
+    }
+
+    void assertNoEvents() {
+        uint32_t consumeSeq;
+        InputEvent* event;
+        status_t status = mConsumer->consume(&mEventFactory, false /*consumeBatches*/, -1,
+            &consumeSeq, &event);
+        ASSERT_NE(OK, status)
+                << mName.c_str()
+                << ": should not have received any events, so consume(..) should not return OK.";
+    }
+
+    private:
+        sp<InputDispatcher> mDispatcher;
+        sp<InputChannel> mServerChannel, mClientChannel;
+        InputConsumer *mConsumer;
+        PreallocatedInputEventFactory mEventFactory;
+
+        std::string mName;
+        bool mFocused;
+        int32_t mDisplayId;
+};
+
+static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher) {
+    KeyEvent event;
+    nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
+    // Define a valid key down event.
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
+            AKEY_EVENT_ACTION_DOWN, /* flags */ 0,
+            AKEYCODE_A, KEY_A, AMETA_NONE, /* repeatCount */ 0, currentTime, currentTime);
+
+    // Inject event until dispatch out.
+    return dispatcher->injectInputEvent(
+            &event,
+            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
+            INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+}
+
+static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t displayId) {
+    MotionEvent event;
+    PointerProperties pointerProperties[1];
+    PointerCoords pointerCoords[1];
+
+    pointerProperties[0].clear();
+    pointerProperties[0].id = 0;
+    pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
+
+    pointerCoords[0].clear();
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100);
+    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 200);
+
+    nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    // Define a valid motion down event.
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, displayId,
+            AMOTION_EVENT_ACTION_DOWN, /* actionButton */0, /* flags */ 0, /* edgeFlags */ 0,
+            AMETA_NONE, /* buttonState */ 0, /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
+            /* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties,
+            pointerCoords);
+
+    // Inject event until dispatch out.
+    return dispatcher->injectInputEvent(
+            &event,
+            INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
+            INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
+}
+
+TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window");
+
+    Vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.add(window);
+
+    mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+    // Window should receive motion event.
+    window->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+}
+
+// The foreground window should receive the first touch down event.
+TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top");
+    sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second");
+
+    Vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.add(windowTop);
+    inputWindowHandles.add(windowSecond);
+
+    mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+    // Top window should receive the touch down event. Second window should not receive anything.
+    windowTop->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+    windowSecond->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTest, SetInputWindow_FocusedWindow) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top");
+    sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second");
+
+    // Set focus application.
+    mDispatcher->setFocusedApplication(application);
+
+    // Expect one focus window exist in display.
+    windowSecond->setFocus();
+    Vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.add(windowTop);
+    inputWindowHandles.add(windowSecond);
+
+    mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+            << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+    // Focused window should receive event.
+    windowTop->assertNoEvents();
+    windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+}
+
+TEST_F(InputDispatcherTest, SetInputWindow_MultiDisplayTouch) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1");
+    sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application, mDispatcher, "D_2");
+
+    // Test the primary display touch down.
+    Vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.push(windowInPrimary);
+
+    mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+    windowInPrimary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+    windowInSecondary->assertNoEvents();
+
+    // Test the second display touch down.
+    constexpr int32_t SECOND_DISPLAY_ID = 1;
+    windowInSecondary->setDisplayId(SECOND_DISPLAY_ID);
+    Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
+    inputWindowHandles_Second.push(windowInSecondary);
+
+    mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher, SECOND_DISPLAY_ID))
+            << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+    windowInPrimary->assertNoEvents();
+    windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID);
+}
+
+// TODO(b/111361570): multi-display focus, one focus window per display.
+TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+    sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1");
+    sp<FakeApplicationHandle> application2 = new FakeApplicationHandle();
+    sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2");
+
+    // Set focus to second display window.
+    mDispatcher->setFocusedApplication(application2);
+    windowInSecondary->setFocus();
+
+    // Update all windows per displays.
+    Vector<sp<InputWindowHandle>> inputWindowHandles;
+    inputWindowHandles.push(windowInPrimary);
+    mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+
+    constexpr int32_t SECOND_DISPLAY_ID = 1;
+    windowInSecondary->setDisplayId(SECOND_DISPLAY_ID);
+    Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
+    inputWindowHandles_Second.push(windowInSecondary);
+    mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
+
+    // Test inject a key down.
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+            << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+    windowInPrimary->assertNoEvents();
+    windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+
+    // Remove secondary display.
+    inputWindowHandles_Second.clear();
+    mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID);
+
+    // Expect old focus should receive a cancel event.
+    windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+
+    // Test inject a key down, should timeout because of no target window.
+    ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
+            << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
+    windowInPrimary->assertNoEvents();
+    windowInSecondary->assertNoEvents();
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 29de50c..a1e45b0 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -284,7 +284,7 @@
 }
 
 Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
-    const Layer::State& s(getDrawingState());
+    const State& s(getDrawingState());
     Rect win(getActiveWidth(s), getActiveHeight(s));
 
     Rect crop = getCrop(s);
@@ -319,12 +319,12 @@
 }
 
 FloatRect Layer::computeBounds() const {
-    const Layer::State& s(getDrawingState());
+    const State& s(getDrawingState());
     return computeBounds(getActiveTransparentRegion(s));
 }
 
 FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const {
-    const Layer::State& s(getDrawingState());
+    const State& s(getDrawingState());
     Rect win(getActiveWidth(s), getActiveHeight(s));
 
     Rect crop = getCrop(s);
@@ -762,7 +762,7 @@
 }
 
 bool Layer::isSecure() const {
-    const Layer::State& s(mDrawingState);
+    const State& s(mDrawingState);
     return (s.flags & layer_state_t::eLayerSecure);
 }
 
@@ -885,7 +885,7 @@
 }
 
 uint32_t Layer::doTransactionResize(uint32_t flags, State* stateToCommit) {
-    const Layer::State& s(getDrawingState());
+    const State& s(getDrawingState());
 
     const bool sizeChanged = (stateToCommit->requested_legacy.w != s.requested_legacy.w) ||
             (stateToCommit->requested_legacy.h != s.requested_legacy.h);
@@ -941,7 +941,7 @@
     // latching configuration. See Layer.h for a detailed discussion of
     // how geometry latching is controlled.
     if (!(flags & eDontUpdateGeometryState)) {
-        Layer::State& editCurrentState(getCurrentState());
+        State& editCurrentState(getCurrentState());
 
         // If mFreezeGeometryUpdates is true we are in the setGeometryAppliesWithResize
         // mode, which causes attributes which normally latch regardless of scaling mode,
@@ -974,14 +974,14 @@
     ATRACE_CALL();
 
     pushPendingState();
-    Layer::State c = getCurrentState();
+    State c = getCurrentState();
     if (!applyPendingStates(&c)) {
         return 0;
     }
 
     flags = doTransactionResize(flags, &c);
 
-    const Layer::State& s(getDrawingState());
+    const State& s(getDrawingState());
 
     if (getActiveGeometry(c) != getActiveGeometry(s)) {
         // invalidate and recompute the visible regions if needed
@@ -1272,7 +1272,7 @@
 // ----------------------------------------------------------------------------
 
 bool Layer::isHiddenByPolicy() const {
-    const Layer::State& s(mDrawingState);
+    const State& s(mDrawingState);
     const auto& parent = mDrawingParent.promote();
     if (parent != nullptr && parent->isHiddenByPolicy()) {
         return true;
@@ -1315,7 +1315,7 @@
 // TODO(marissaw): add new layer state info to layer debugging
 LayerDebugInfo Layer::getLayerDebugInfo() const {
     LayerDebugInfo info;
-    const Layer::State& ds = getDrawingState();
+    const State& ds = getDrawingState();
     info.mName = getName();
     sp<Layer> parent = getParent();
     info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string());
@@ -1392,7 +1392,7 @@
 
     result.appendFormat(" %s\n", name.string());
 
-    const Layer::State& layerState(getDrawingState());
+    const State& layerState(getDrawingState());
     const LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers.at(displayId);
     if (layerState.zOrderRelativeOf != nullptr || mDrawingParent != nullptr) {
         result.appendFormat("  rel %6d | ", layerState.z);
diff --git a/services/surfaceflinger/RenderEngine/Android.bp b/services/surfaceflinger/RenderEngine/Android.bp
index 064eb17..e1ab066 100644
--- a/services/surfaceflinger/RenderEngine/Android.bp
+++ b/services/surfaceflinger/RenderEngine/Android.bp
@@ -20,10 +20,6 @@
         "-DEGL_EGLEXT_PROTOTYPES",
     ],
     shared_libs: [
-        "android.hardware.configstore-utils",
-        "android.hardware.configstore@1.0",
-        "android.hardware.configstore@1.1",
-        "android.hardware.configstore@1.2",
         "libcutils",
         "libEGL",
         "libGLESv1_CM",
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index e94200e..3b54873 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -16,165 +16,33 @@
 
 #include <renderengine/RenderEngine.h>
 
-#include <vector>
-
-#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
-#include <configstore/Utils.h>
+#include <cutils/properties.h>
 #include <log/log.h>
 #include <private/gui/SyncFeatures.h>
-#include <renderengine/Image.h>
-#include <renderengine/Mesh.h>
-#include <renderengine/Surface.h>
-#include <ui/Rect.h>
-#include <ui/Region.h>
-#include <utils/KeyedVector.h>
 #include "gl/GLES20RenderEngine.h"
-#include "gl/GLExtensions.h"
-#include "gl/ProgramCache.h"
-
-using namespace android::hardware::configstore;
-using namespace android::hardware::configstore::V1_0;
-using namespace android::renderengine::gl;
-
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
 
 namespace android {
 namespace renderengine {
 
+std::unique_ptr<impl::RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) {
+    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::GLES20RenderEngine::create(hwcFormat, featureFlags);
+    }
+    ALOGE("UNKNOWN BackendType: %s, create GLES RenderEngine.", prop);
+    return renderengine::gl::GLES20RenderEngine::create(hwcFormat, featureFlags);
+}
+
 RenderEngine::~RenderEngine() = default;
 
 namespace impl {
 
-std::unique_ptr<RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) {
-    // initialize EGL for the default display
-    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    if (!eglInitialize(display, nullptr, nullptr)) {
-        LOG_ALWAYS_FATAL("failed to initialize EGL");
-    }
-
-    GLExtensions& extensions = GLExtensions::getInstance();
-    extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION),
-                                  eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS));
-
-    // The code assumes that ES2 or later is available if this extension is
-    // supported.
-    EGLConfig config = EGL_NO_CONFIG;
-    if (!extensions.hasNoConfigContext()) {
-        config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
-    }
-
-    EGLint renderableType = 0;
-    if (config == EGL_NO_CONFIG) {
-        renderableType = EGL_OPENGL_ES2_BIT;
-    } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
-        LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
-    }
-    EGLint contextClientVersion = 0;
-    if (renderableType & EGL_OPENGL_ES2_BIT) {
-        contextClientVersion = 2;
-    } else if (renderableType & EGL_OPENGL_ES_BIT) {
-        contextClientVersion = 1;
-    } else {
-        LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
-    }
-
-    std::vector<EGLint> contextAttributes;
-    contextAttributes.reserve(6);
-    contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
-    contextAttributes.push_back(contextClientVersion);
-    bool useContextPriority = overrideUseContextPriorityFromConfig(extensions.hasContextPriority());
-    if (useContextPriority) {
-        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
-        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
-    }
-    contextAttributes.push_back(EGL_NONE);
-
-    EGLContext ctxt = eglCreateContext(display, config, nullptr, contextAttributes.data());
-
-    // if can't create a GL context, we can only abort.
-    LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
-
-    // now figure out what version of GL did we actually get
-    // NOTE: a dummy surface is not needed if KHR_create_context is supported
-
-    EGLConfig dummyConfig = config;
-    if (dummyConfig == EGL_NO_CONFIG) {
-        dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
-    }
-    EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
-    EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);
-    LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
-    EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
-    LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
-
-    extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
-                                 glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
-
-    GlesVersion version = parseGlesVersion(extensions.getVersion());
-
-    // initialize the renderer while GL is current
-
-    std::unique_ptr<RenderEngine> engine;
-    switch (version) {
-        case GLES_VERSION_1_0:
-        case GLES_VERSION_1_1:
-            LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run.");
-            break;
-        case GLES_VERSION_2_0:
-        case GLES_VERSION_3_0:
-            engine = std::make_unique<GLES20RenderEngine>(featureFlags);
-            break;
-    }
-    engine->setEGLHandles(display, config, ctxt);
-
-    ALOGI("OpenGL ES informations:");
-    ALOGI("vendor    : %s", extensions.getVendor());
-    ALOGI("renderer  : %s", extensions.getRenderer());
-    ALOGI("version   : %s", extensions.getVersion());
-    ALOGI("extensions: %s", extensions.getExtensions());
-    ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
-    ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
-
-    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    eglDestroySurface(display, dummy);
-
-    return engine;
-}
-
-bool RenderEngine::overrideUseContextPriorityFromConfig(bool useContextPriority) {
-    OptionalBool ret;
-    ISurfaceFlingerConfigs::getService()->useContextPriority([&ret](OptionalBool b) { ret = b; });
-    if (ret.specified) {
-        return ret.value;
-    } else {
-        return useContextPriority;
-    }
-}
-
 RenderEngine::RenderEngine(uint32_t featureFlags)
-      : mEGLDisplay(EGL_NO_DISPLAY),
-        mEGLConfig(nullptr),
-        mEGLContext(EGL_NO_CONTEXT),
-        mFeatureFlags(featureFlags) {}
+      : mFeatureFlags(featureFlags) {}
 
-RenderEngine::~RenderEngine() {
-    eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
-    eglTerminate(mEGLDisplay);
-}
-
-void RenderEngine::setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt) {
-    mEGLDisplay = display;
-    mEGLConfig = config;
-    mEGLContext = ctxt;
-}
-
-EGLDisplay RenderEngine::getEGLDisplay() const {
-    return mEGLDisplay;
-}
-
-EGLConfig RenderEngine::getEGLConfig() const {
-    return mEGLConfig;
-}
+RenderEngine::~RenderEngine() = default;
 
 bool RenderEngine::useNativeFenceSync() const {
     return SyncFeatures::getInstance().useNativeFenceSync();
@@ -184,185 +52,6 @@
     return SyncFeatures::getInstance().useWaitSync();
 }
 
-RenderEngine::GlesVersion RenderEngine::parseGlesVersion(const char* str) {
-    int major, minor;
-    if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) {
-        if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) {
-            ALOGW("Unable to parse GL_VERSION string: \"%s\"", str);
-            return GLES_VERSION_1_0;
-        }
-    }
-
-    if (major == 1 && minor == 0) return GLES_VERSION_1_0;
-    if (major == 1 && minor >= 1) return GLES_VERSION_1_1;
-    if (major == 2 && minor >= 0) return GLES_VERSION_2_0;
-    if (major == 3 && minor >= 0) return GLES_VERSION_3_0;
-
-    ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor);
-    return GLES_VERSION_1_0;
-}
-
-void RenderEngine::dump(String8& result) {
-    const GLExtensions& extensions = GLExtensions::getInstance();
-
-    result.appendFormat("EGL implementation : %s\n", extensions.getEGLVersion());
-    result.appendFormat("%s\n", extensions.getEGLExtensions());
-
-    result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
-                        extensions.getVersion());
-    result.appendFormat("%s\n", extensions.getExtensions());
-}
-
-static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
-                                         EGLint wanted, EGLConfig* outConfig) {
-    EGLint numConfigs = -1, n = 0;
-    eglGetConfigs(dpy, nullptr, 0, &numConfigs);
-    EGLConfig* const configs = new EGLConfig[numConfigs];
-    eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
-
-    if (n) {
-        if (attribute != EGL_NONE) {
-            for (int i = 0; i < n; i++) {
-                EGLint value = 0;
-                eglGetConfigAttrib(dpy, configs[i], attribute, &value);
-                if (wanted == value) {
-                    *outConfig = configs[i];
-                    delete[] configs;
-                    return NO_ERROR;
-                }
-            }
-        } else {
-            // just pick the first one
-            *outConfig = configs[0];
-            delete[] configs;
-            return NO_ERROR;
-        }
-    }
-    delete[] configs;
-    return NAME_NOT_FOUND;
-}
-
-class EGLAttributeVector {
-    struct Attribute;
-    class Adder;
-    friend class Adder;
-    KeyedVector<Attribute, EGLint> mList;
-    struct Attribute {
-        Attribute() : v(0){};
-        explicit Attribute(EGLint v) : v(v) {}
-        EGLint v;
-        bool operator<(const Attribute& other) const {
-            // this places EGL_NONE at the end
-            EGLint lhs(v);
-            EGLint rhs(other.v);
-            if (lhs == EGL_NONE) lhs = 0x7FFFFFFF;
-            if (rhs == EGL_NONE) rhs = 0x7FFFFFFF;
-            return lhs < rhs;
-        }
-    };
-    class Adder {
-        friend class EGLAttributeVector;
-        EGLAttributeVector& v;
-        EGLint attribute;
-        Adder(EGLAttributeVector& v, EGLint attribute) : v(v), attribute(attribute) {}
-
-    public:
-        void operator=(EGLint value) {
-            if (attribute != EGL_NONE) {
-                v.mList.add(Attribute(attribute), value);
-            }
-        }
-        operator EGLint() const { return v.mList[attribute]; }
-    };
-
-public:
-    EGLAttributeVector() { mList.add(Attribute(EGL_NONE), EGL_NONE); }
-    void remove(EGLint attribute) {
-        if (attribute != EGL_NONE) {
-            mList.removeItem(Attribute(attribute));
-        }
-    }
-    Adder operator[](EGLint attribute) { return Adder(*this, attribute); }
-    EGLint operator[](EGLint attribute) const { return mList[attribute]; }
-    // cast-operator to (EGLint const*)
-    operator EGLint const*() const { return &mList.keyAt(0).v; }
-};
-
-static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType,
-                                EGLConfig* config) {
-    // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
-    // it is to be used with WIFI displays
-    status_t err;
-    EGLint wantedAttribute;
-    EGLint wantedAttributeValue;
-
-    EGLAttributeVector attribs;
-    if (renderableType) {
-        attribs[EGL_RENDERABLE_TYPE] = renderableType;
-        attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE;
-        attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
-        attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE;
-        attribs[EGL_RED_SIZE] = 8;
-        attribs[EGL_GREEN_SIZE] = 8;
-        attribs[EGL_BLUE_SIZE] = 8;
-        attribs[EGL_ALPHA_SIZE] = 8;
-        wantedAttribute = EGL_NONE;
-        wantedAttributeValue = EGL_NONE;
-    } else {
-        // if no renderable type specified, fallback to a simplified query
-        wantedAttribute = EGL_NATIVE_VISUAL_ID;
-        wantedAttributeValue = format;
-    }
-
-    err = selectConfigForAttribute(display, attribs, wantedAttribute, wantedAttributeValue, config);
-    if (err == NO_ERROR) {
-        EGLint caveat;
-        if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
-            ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!");
-    }
-
-    return err;
-}
-
-EGLConfig RenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
-    status_t err;
-    EGLConfig config;
-
-    // First try to get an ES2 config
-    err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config);
-    if (err != NO_ERROR) {
-        // If ES2 fails, try ES1
-        err = selectEGLConfig(display, format, EGL_OPENGL_ES_BIT, &config);
-        if (err != NO_ERROR) {
-            // still didn't work, probably because we're on the emulator...
-            // try a simplified query
-            ALOGW("no suitable EGLConfig found, trying a simpler query");
-            err = selectEGLConfig(display, format, 0, &config);
-            if (err != NO_ERROR) {
-                // this EGL is too lame for android
-                LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up");
-            }
-        }
-    }
-
-    if (logConfig) {
-        // print some debugging info
-        EGLint r, g, b, a;
-        eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
-        eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
-        eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
-        eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
-        ALOGI("EGL information:");
-        ALOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
-        ALOGI("version   : %s", eglQueryString(display, EGL_VERSION));
-        ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
-        ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported");
-        ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
-    }
-
-    return config;
-}
-
 }  // namespace impl
 }  // namespace renderengine
 }  // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
index 61df675..7121cc2 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
@@ -44,6 +44,8 @@
 #include "Program.h"
 #include "ProgramCache.h"
 
+extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+
 bool checkGlError(const char* op, int lineNumber) {
     bool errorFound = false;
     GLint error = glGetError();
@@ -109,8 +111,259 @@
 
 using ui::Dataspace;
 
+static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
+                                         EGLint wanted, EGLConfig* outConfig) {
+    EGLint numConfigs = -1, n = 0;
+    eglGetConfigs(dpy, nullptr, 0, &numConfigs);
+    EGLConfig* const configs = new EGLConfig[numConfigs];
+    eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
+
+    if (n) {
+        if (attribute != EGL_NONE) {
+            for (int i = 0; i < n; i++) {
+                EGLint value = 0;
+                eglGetConfigAttrib(dpy, configs[i], attribute, &value);
+                if (wanted == value) {
+                    *outConfig = configs[i];
+                    delete[] configs;
+                    return NO_ERROR;
+                }
+            }
+        } else {
+            // just pick the first one
+            *outConfig = configs[0];
+            delete[] configs;
+            return NO_ERROR;
+        }
+    }
+    delete[] configs;
+    return NAME_NOT_FOUND;
+}
+
+class EGLAttributeVector {
+    struct Attribute;
+    class Adder;
+    friend class Adder;
+    KeyedVector<Attribute, EGLint> mList;
+    struct Attribute {
+        Attribute() : v(0){};
+        explicit Attribute(EGLint v) : v(v) {}
+        EGLint v;
+        bool operator<(const Attribute& other) const {
+            // this places EGL_NONE at the end
+            EGLint lhs(v);
+            EGLint rhs(other.v);
+            if (lhs == EGL_NONE) lhs = 0x7FFFFFFF;
+            if (rhs == EGL_NONE) rhs = 0x7FFFFFFF;
+            return lhs < rhs;
+        }
+    };
+    class Adder {
+        friend class EGLAttributeVector;
+        EGLAttributeVector& v;
+        EGLint attribute;
+        Adder(EGLAttributeVector& v, EGLint attribute) : v(v), attribute(attribute) {}
+
+    public:
+        void operator=(EGLint value) {
+            if (attribute != EGL_NONE) {
+                v.mList.add(Attribute(attribute), value);
+            }
+        }
+        operator EGLint() const { return v.mList[attribute]; }
+    };
+
+public:
+    EGLAttributeVector() { mList.add(Attribute(EGL_NONE), EGL_NONE); }
+    void remove(EGLint attribute) {
+        if (attribute != EGL_NONE) {
+            mList.removeItem(Attribute(attribute));
+        }
+    }
+    Adder operator[](EGLint attribute) { return Adder(*this, attribute); }
+    EGLint operator[](EGLint attribute) const { return mList[attribute]; }
+    // cast-operator to (EGLint const*)
+    operator EGLint const*() const { return &mList.keyAt(0).v; }
+};
+
+static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType,
+                                EGLConfig* config) {
+    // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if
+    // it is to be used with WIFI displays
+    status_t err;
+    EGLint wantedAttribute;
+    EGLint wantedAttributeValue;
+
+    EGLAttributeVector attribs;
+    if (renderableType) {
+        attribs[EGL_RENDERABLE_TYPE] = renderableType;
+        attribs[EGL_RECORDABLE_ANDROID] = EGL_TRUE;
+        attribs[EGL_SURFACE_TYPE] = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
+        attribs[EGL_FRAMEBUFFER_TARGET_ANDROID] = EGL_TRUE;
+        attribs[EGL_RED_SIZE] = 8;
+        attribs[EGL_GREEN_SIZE] = 8;
+        attribs[EGL_BLUE_SIZE] = 8;
+        attribs[EGL_ALPHA_SIZE] = 8;
+        wantedAttribute = EGL_NONE;
+        wantedAttributeValue = EGL_NONE;
+    } else {
+        // if no renderable type specified, fallback to a simplified query
+        wantedAttribute = EGL_NATIVE_VISUAL_ID;
+        wantedAttributeValue = format;
+    }
+
+    err = selectConfigForAttribute(display, attribs, wantedAttribute, wantedAttributeValue, config);
+    if (err == NO_ERROR) {
+        EGLint caveat;
+        if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat))
+            ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!");
+    }
+
+    return err;
+}
+
+std::unique_ptr<GLES20RenderEngine> GLES20RenderEngine::create(int hwcFormat,
+                                                               uint32_t featureFlags) {
+    // initialize EGL for the default display
+    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    if (!eglInitialize(display, nullptr, nullptr)) {
+        LOG_ALWAYS_FATAL("failed to initialize EGL");
+    }
+
+    GLExtensions& extensions = GLExtensions::getInstance();
+    extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION),
+                                  eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS));
+
+    // The code assumes that ES2 or later is available if this extension is
+    // supported.
+    EGLConfig config = EGL_NO_CONFIG;
+    if (!extensions.hasNoConfigContext()) {
+        config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+    }
+
+    EGLint renderableType = 0;
+    if (config == EGL_NO_CONFIG) {
+        renderableType = EGL_OPENGL_ES2_BIT;
+    } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) {
+        LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE");
+    }
+    EGLint contextClientVersion = 0;
+    if (renderableType & EGL_OPENGL_ES2_BIT) {
+        contextClientVersion = 2;
+    } else if (renderableType & EGL_OPENGL_ES_BIT) {
+        contextClientVersion = 1;
+    } else {
+        LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs");
+    }
+
+    std::vector<EGLint> contextAttributes;
+    contextAttributes.reserve(6);
+    contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
+    contextAttributes.push_back(contextClientVersion);
+    bool useContextPriority = extensions.hasContextPriority() &&
+                              (featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
+    if (useContextPriority) {
+        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
+        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
+    }
+    contextAttributes.push_back(EGL_NONE);
+
+    EGLContext ctxt = eglCreateContext(display, config, nullptr, contextAttributes.data());
+
+    // if can't create a GL context, we can only abort.
+    LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed");
+
+    // now figure out what version of GL did we actually get
+    // NOTE: a dummy surface is not needed if KHR_create_context is supported
+
+    EGLConfig dummyConfig = config;
+    if (dummyConfig == EGL_NO_CONFIG) {
+        dummyConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+    }
+    EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
+    EGLSurface dummy = eglCreatePbufferSurface(display, dummyConfig, attribs);
+    LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
+    EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
+    LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
+
+    extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
+                                 glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
+
+    GlesVersion version = parseGlesVersion(extensions.getVersion());
+
+    // initialize the renderer while GL is current
+
+    std::unique_ptr<GLES20RenderEngine> engine;
+    switch (version) {
+        case GLES_VERSION_1_0:
+        case GLES_VERSION_1_1:
+            LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run.");
+            break;
+        case GLES_VERSION_2_0:
+        case GLES_VERSION_3_0:
+            engine = std::make_unique<GLES20RenderEngine>(featureFlags);
+            break;
+    }
+    engine->setEGLHandles(display, config, ctxt);
+
+    ALOGI("OpenGL ES informations:");
+    ALOGI("vendor    : %s", extensions.getVendor());
+    ALOGI("renderer  : %s", extensions.getRenderer());
+    ALOGI("version   : %s", extensions.getVersion());
+    ALOGI("extensions: %s", extensions.getExtensions());
+    ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
+    ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
+
+    eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglDestroySurface(display, dummy);
+
+    return engine;
+}
+
+EGLConfig GLES20RenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) {
+    status_t err;
+    EGLConfig config;
+
+    // First try to get an ES2 config
+    err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config);
+    if (err != NO_ERROR) {
+        // If ES2 fails, try ES1
+        err = selectEGLConfig(display, format, EGL_OPENGL_ES_BIT, &config);
+        if (err != NO_ERROR) {
+            // still didn't work, probably because we're on the emulator...
+            // try a simplified query
+            ALOGW("no suitable EGLConfig found, trying a simpler query");
+            err = selectEGLConfig(display, format, 0, &config);
+            if (err != NO_ERROR) {
+                // this EGL is too lame for android
+                LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up");
+            }
+        }
+    }
+
+    if (logConfig) {
+        // print some debugging info
+        EGLint r, g, b, a;
+        eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r);
+        eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g);
+        eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b);
+        eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a);
+        ALOGI("EGL information:");
+        ALOGI("vendor    : %s", eglQueryString(display, EGL_VENDOR));
+        ALOGI("version   : %s", eglQueryString(display, EGL_VERSION));
+        ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS));
+        ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported");
+        ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config);
+    }
+
+    return config;
+}
+
 GLES20RenderEngine::GLES20RenderEngine(uint32_t featureFlags)
-      : RenderEngine(featureFlags),
+      : renderengine::impl::RenderEngine(featureFlags),
+        mEGLDisplay(EGL_NO_DISPLAY),
+        mEGLConfig(nullptr),
+        mEGLContext(EGL_NO_CONTEXT),
         mVpWidth(0),
         mVpHeight(0),
         mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
@@ -154,7 +407,10 @@
     }
 }
 
-GLES20RenderEngine::~GLES20RenderEngine() {}
+GLES20RenderEngine::~GLES20RenderEngine() {
+    eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglTerminate(mEGLDisplay);
+}
 
 std::unique_ptr<Framebuffer> GLES20RenderEngine::createFramebuffer() {
     return std::make_unique<GLFramebuffer>(*this);
@@ -278,6 +534,11 @@
     return true;
 }
 
+void GLES20RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
+    glClearColor(red, green, blue, alpha);
+    glClear(GL_COLOR_BUFFER_BIT);
+}
+
 void GLES20RenderEngine::fillRegionWithColor(const Region& region, uint32_t height, float red,
                                              float green, float blue, float alpha) {
     size_t c;
@@ -302,11 +563,6 @@
     drawMesh(mesh);
 }
 
-void GLES20RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
-    glClearColor(red, green, blue, alpha);
-    glClear(GL_COLOR_BUFFER_BIT);
-}
-
 void GLES20RenderEngine::setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) {
     glScissor(left, bottom, right, top);
     glEnable(GL_SCISSOR_TEST);
@@ -632,12 +888,37 @@
 }
 
 void GLES20RenderEngine::dump(String8& result) {
-    RenderEngine::dump(result);
+    const GLExtensions& extensions = GLExtensions::getInstance();
+
+    result.appendFormat("EGL implementation : %s\n", extensions.getEGLVersion());
+    result.appendFormat("%s\n", extensions.getEGLExtensions());
+
+    result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
+                        extensions.getVersion());
+    result.appendFormat("%s\n", extensions.getExtensions());
     result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n",
                         dataspaceDetails(static_cast<android_dataspace>(mDataSpace)).c_str(),
                         dataspaceDetails(static_cast<android_dataspace>(mOutputDataSpace)).c_str());
 }
 
+GLES20RenderEngine::GlesVersion GLES20RenderEngine::parseGlesVersion(const char* str) {
+    int major, minor;
+    if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) {
+        if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) {
+            ALOGW("Unable to parse GL_VERSION string: \"%s\"", str);
+            return GLES_VERSION_1_0;
+        }
+    }
+
+    if (major == 1 && minor == 0) return GLES_VERSION_1_0;
+    if (major == 1 && minor >= 1) return GLES_VERSION_1_1;
+    if (major == 2 && minor >= 0) return GLES_VERSION_2_0;
+    if (major == 3 && minor >= 0) return GLES_VERSION_3_0;
+
+    ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor);
+    return GLES_VERSION_1_0;
+}
+
 bool GLES20RenderEngine::isHdrDataSpace(const Dataspace dataSpace) const {
     const Dataspace standard = static_cast<Dataspace>(dataSpace & Dataspace::STANDARD_MASK);
     const Dataspace transfer = static_cast<Dataspace>(dataSpace & Dataspace::TRANSFER_MASK);
@@ -665,6 +946,12 @@
     return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer;
 }
 
+void GLES20RenderEngine::setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt) {
+    mEGLDisplay = display;
+    mEGLConfig = config;
+    mEGLContext = ctxt;
+}
+
 }  // namespace gl
 }  // namespace renderengine
 }  // namespace android
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
index 04dc1b1..2502cb8 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
@@ -20,10 +20,14 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
 #include <GLES2/gl2.h>
 #include <renderengine/RenderEngine.h>
 #include <renderengine/private/Description.h>
 
+#define EGL_NO_CONFIG ((EGLConfig)0)
+
 namespace android {
 
 class String8;
@@ -40,6 +44,9 @@
 
 class GLES20RenderEngine : public impl::RenderEngine {
 public:
+    static std::unique_ptr<GLES20RenderEngine> create(int hwcFormat, uint32_t featureFlags);
+    static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
+
     GLES20RenderEngine(uint32_t featureFlags); // See RenderEngine::FeatureFlag
     ~GLES20RenderEngine() override;
 
@@ -56,7 +63,7 @@
     bool waitFence(base::unique_fd fenceFd) override;
     void clearWithColor(float red, float green, float blue, float alpha) override;
     void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
-                                     float blue, float alpha) override;
+                             float blue, float alpha) override;
     void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) override;
     void disableScissor() override;
     void genTextures(size_t count, uint32_t* names) override;
@@ -67,19 +74,16 @@
     void unbindFrameBuffer(Framebuffer* framebuffer) override;
     void checkErrors() const override;
 
+    // internal to RenderEngine
+    EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
+    EGLConfig getEGLConfig() const { return mEGLConfig; }
+
 protected:
     void dump(String8& result) override;
     void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
                                   ui::Transform::orientation_flags rotation) override;
     void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
                             const half4& color) override;
-
-    // Color management related functions and state
-    void setSourceY410BT2020(bool enable) override;
-    void setSourceDataSpace(ui::Dataspace source) override;
-    void setOutputDataSpace(ui::Dataspace dataspace) override;
-    void setDisplayMaxLuminance(const float maxLuminance) override;
-
     void setupLayerTexturing(const Texture& texture) override;
     void setupLayerBlackedOut() override;
     void setupFillWithColor(float r, float g, float b, float a) override;
@@ -87,17 +91,37 @@
     void disableTexturing() override;
     void disableBlending() override;
 
+    // HDR and color management related functions and state
+    void setSourceY410BT2020(bool enable) override;
+    void setSourceDataSpace(ui::Dataspace source) override;
+    void setOutputDataSpace(ui::Dataspace dataspace) override;
+    void setDisplayMaxLuminance(const float maxLuminance) override;
+
+    // drawing
     void drawMesh(const Mesh& mesh) override;
 
     size_t getMaxTextureSize() const override;
     size_t getMaxViewportDims() const override;
 
 private:
+    enum GlesVersion {
+        GLES_VERSION_1_0 = 0x10000,
+        GLES_VERSION_1_1 = 0x10001,
+        GLES_VERSION_2_0 = 0x20000,
+        GLES_VERSION_3_0 = 0x30000,
+    };
+
+    static GlesVersion parseGlesVersion(const char* str);
+
     // A data space is considered HDR data space if it has BT2020 color space
     // with PQ or HLG transfer function.
     bool isHdrDataSpace(const ui::Dataspace dataSpace) const;
     bool needsXYZTransformMatrix() const;
+    void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt);
 
+    EGLDisplay mEGLDisplay;
+    EGLConfig mEGLConfig;
+    EGLContext mEGLContext;
     GLuint mProtectedTexName;
     GLint mMaxViewportDims[2];
     GLint mMaxTextureSize;
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
index 86a1264..d0ca0d9 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
@@ -21,8 +21,6 @@
 #include <sys/types.h>
 #include <memory>
 
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
 #include <android-base/unique_fd.h>
 #include <math/mat4.h>
 #include <renderengine/Framebuffer.h>
@@ -30,7 +28,10 @@
 #include <ui/GraphicTypes.h>
 #include <ui/Transform.h>
 
-#define EGL_NO_CONFIG ((EGLConfig)0)
+/**
+ * Allows to set RenderEngine backend to GLES (default) or Vulkan (NOT yet supported).
+ */
+#define PROPERTY_DEBUG_RENDERENGINE_BACKEND "debug.renderengine.backend"
 
 struct ANativeWindowBuffer;
 
@@ -56,8 +57,11 @@
 public:
     enum FeatureFlag {
         USE_COLOR_MANAGEMENT = 1 << 0, // Device manages color
+        USE_HIGH_PRIORITY_CONTEXT = 1 << 1, // Use high priority context
     };
 
+    static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags);
+
     virtual ~RenderEngine() = 0;
 
     virtual std::unique_ptr<Framebuffer> createFramebuffer() = 0;
@@ -92,7 +96,6 @@
     virtual void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
                                      float blue, float alpha) = 0;
 
-    // common to all GL versions
     virtual void setScissor(uint32_t left, uint32_t bottom, uint32_t right, uint32_t top) = 0;
     virtual void disableScissor() = 0;
     virtual void genTextures(size_t count, uint32_t* names) = 0;
@@ -154,45 +157,18 @@
 
 namespace impl {
 
+// impl::RenderEngine contains common implementation that is graphics back-end agnostic.
 class RenderEngine : public renderengine::RenderEngine {
-protected:
-    enum GlesVersion {
-        GLES_VERSION_1_0 = 0x10000,
-        GLES_VERSION_1_1 = 0x10001,
-        GLES_VERSION_2_0 = 0x20000,
-        GLES_VERSION_3_0 = 0x30000,
-    };
-    static GlesVersion parseGlesVersion(const char* str);
-
-    EGLDisplay mEGLDisplay;
-    EGLConfig mEGLConfig;
-    EGLContext mEGLContext;
-    void setEGLHandles(EGLDisplay display, EGLConfig config, EGLContext ctxt);
-
-    static bool overrideUseContextPriorityFromConfig(bool useContextPriority);
-
-    RenderEngine(uint32_t featureFlags);
-
-    const uint32_t mFeatureFlags;
-
 public:
     virtual ~RenderEngine() = 0;
 
-    static std::unique_ptr<RenderEngine> create(int hwcFormat, uint32_t featureFlags);
-
-    static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
-
-    // dump the extension strings. always call the base class.
-    void dump(String8& result) override;
-
     bool useNativeFenceSync() const override;
     bool useWaitSync() const override;
-
     void setupColorTransform(const mat4& /* colorTransform */) override {}
 
-    // internal to RenderEngine
-    EGLDisplay getEGLDisplay() const;
-    EGLConfig getEGLConfig() const;
+protected:
+    RenderEngine(uint32_t featureFlags);
+    const uint32_t mFeatureFlags;
 };
 
 }  // namespace impl
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8c46e8a..55ef909 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -196,6 +196,9 @@
 bool SurfaceFlinger::hasWideColorDisplay;
 int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
 bool SurfaceFlinger::useColorManagement;
+bool SurfaceFlinger::useContextPriority;
+Dataspace SurfaceFlinger::compositionDataSpace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::compositionPixelFormat = ui::PixelFormat::RGBA_8888;
 
 std::string getHwcServiceName() {
     char value[PROPERTY_VALUE_MAX] = {};
@@ -322,10 +325,24 @@
     hasWideColorDisplay =
             getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
     useColorManagement =
-            getBool<V1_2::ISurfaceFlingerConfigs, &V1_2::ISurfaceFlingerConfigs::useColorManagement>(false);
+            getBool<V1_2::ISurfaceFlingerConfigs,
+                    &V1_2::ISurfaceFlingerConfigs::useColorManagement>(false);
+
+    auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService();
+    if (surfaceFlingerConfigsServiceV1_2) {
+        surfaceFlingerConfigsServiceV1_2->getCompositionPreference(
+            [&](Dataspace tmpDataSpace, ui::PixelFormat tmpPixelFormat) {
+                compositionDataSpace = tmpDataSpace;
+                compositionPixelFormat = tmpPixelFormat;
+            });
+    }
+
+    useContextPriority = getBool<ISurfaceFlingerConfigs,
+                                 &ISurfaceFlingerConfigs::useContextPriority>(true);
 
     V1_1::DisplayOrientation primaryDisplayOrientation =
-        getDisplayOrientation< V1_1::ISurfaceFlingerConfigs, &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>(
+        getDisplayOrientation<V1_1::ISurfaceFlingerConfigs,
+                              &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>(
             V1_1::DisplayOrientation::ORIENTATION_0);
 
     switch (primaryDisplayOrientation) {
@@ -645,8 +662,13 @@
     int32_t renderEngineFeature = 0;
     renderEngineFeature |= (useColorManagement ?
                             renderengine::RenderEngine::USE_COLOR_MANAGEMENT : 0);
-    getBE().mRenderEngine = renderengine::impl::RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
-                                                                      renderEngineFeature);
+    renderEngineFeature |= (useContextPriority ?
+                            renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0);
+
+    // TODO(b/77156734): We need to stop casting and use HAL types when possible.
+    getBE().mRenderEngine =
+        renderengine::RenderEngine::create(static_cast<int32_t>(compositionPixelFormat),
+                                           renderEngineFeature);
     LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine");
 
     LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
@@ -1164,6 +1186,13 @@
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::getCompositionPreference(Dataspace* outDataSpace,
+                                                  ui::PixelFormat* outPixelFormat) const {
+    *outDataSpace = compositionDataSpace;
+    *outPixelFormat = compositionPixelFormat;
+    return NO_ERROR;
+}
+
 // ----------------------------------------------------------------------------
 
 sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
@@ -4818,7 +4847,8 @@
         // granted a reference to Client* and Handle* to do anything with it.
         case SET_TRANSACTION_STATE:
         // Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h
-        case CREATE_SCOPED_CONNECTION: {
+        case CREATE_SCOPED_CONNECTION:
+        case GET_COMPOSITION_PREFERENCE: {
             return OK;
         }
         case CAPTURE_LAYERS:
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3e76904..72ede93 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -294,6 +294,14 @@
     // Indicate if device wants color management on its display.
     static bool useColorManagement;
 
+    static bool useContextPriority;
+
+    // The data space and pixel format that SurfaceFlinger expects hardware composer
+    // to composite efficiently. Meaning under most scenarios, hardware composer
+    // will accept layers with the data space and pixel format.
+    static ui::Dataspace compositionDataSpace;
+    static ui::PixelFormat compositionPixelFormat;
+
     static char const* getServiceName() ANDROID_API {
         return "SurfaceFlinger";
     }
@@ -452,6 +460,8 @@
     virtual status_t enableVSyncInjections(bool enable);
     virtual status_t injectVSync(nsecs_t when);
     virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
+    status_t getCompositionPreference(ui::Dataspace* outDataSpace,
+                                      ui::PixelFormat* outPixelFormat) const override;
 
 
     /* ------------------------------------------------------------------------