Merge tag 'android-15.0.0_r10' into staging/lineage-22.1_merge-android-15.0.0_r10

Android 15.0.0 release 10

# -----BEGIN PGP SIGNATURE-----
#
# iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCZ32Y6wAKCRDorT+BmrEO
# eF+uAJ4ih5KzthOgb0Kd4LK/qvlPoIuQyACgiUklzqenLL/7h+KfWlr4somovr4=
# =rWiQ
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue Jan  7 23:13:15 2025 EET
# gpg:                using DSA key 4340D13570EF945E83810964E8AD3F819AB10E78
# gpg: Can't check signature: No public key

# By Steven Moreland (2) and Frederick Mayle (1)
# Via Android Build Coastguard Worker
* tag 'android-15.0.0_r10':
  binder: fix FD handling in continueWrite
  libbinder: Parcel: validate read data before write
  libbinder: Parcel: grow rejects large data pos

Change-Id: I8a0f49b42ecfa84a3007533dd36a74e437fa516e
diff --git a/include/powermanager/PowerManager.h b/include/powermanager/PowerManager.h
index 9bac242..d73e19f 100644
--- a/include/powermanager/PowerManager.h
+++ b/include/powermanager/PowerManager.h
@@ -44,6 +44,12 @@
     THERMAL_STATUS_SHUTDOWN = 6,
 };
 
+enum {
+    USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1 << 0,
+    USER_ACTIVITY_FLAG_INDIRECT = 1 << 1,
+    USER_ACTIVITY_FLAG_NO_BUTTON_LIGHTS = 1 << 2,
+};
+
 }; // namespace android
 
 #endif // ANDROID_POWERMANAGER_H
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 1243b21..4a2ee20 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -309,10 +309,8 @@
     ],
 }
 
-cc_library_shared {
-    name: "libgui",
-    vendor_available: true,
-    double_loadable: true,
+cc_defaults {
+    name: "libgui_defaults",
 
     defaults: [
         "libgui-defaults",
@@ -505,4 +503,17 @@
     ],
 }
 
+cc_library_shared {
+    name: "libgui",
+    double_loadable: true,
+    vendor_available: true,
+    defaults: ["libgui_defaults"]
+}
+
+cc_library_shared {
+    name: "libgui_vendor",
+    vendor: true,
+    defaults: ["libgui_defaults"]
+}
+
 subdirs = ["tests"]
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index da74e9c..f1e5eb7 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -167,13 +167,14 @@
             return BAD_VALUE;
         }
 
-        int bufferCount = mCore->getMinUndequeuedBufferCountLocked();
-        bufferCount += maxDequeuedBuffers;
+        int minUndequedBufferCount = mCore->getMinUndequeuedBufferCountLocked();
+        int bufferCount = minUndequedBufferCount + maxDequeuedBuffers;
 
         if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) {
             BQ_LOGE("setMaxDequeuedBufferCount: bufferCount %d too large "
                     "(max %d)", bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
-            return BAD_VALUE;
+            bufferCount = BufferQueueDefs::NUM_BUFFER_SLOTS;
+            maxDequeuedBuffers = bufferCount - minUndequedBufferCount;
         }
 
         const int minBufferSlots = mCore->getMinMaxBufferCountLocked();
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 12230f9..4664d04 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -153,6 +153,7 @@
         "android.hardware.graphics.allocator-ndk_shared",
         "android.hardware.graphics.common-ndk_shared",
         "libui-defaults",
+        "gralloc_10_usage_bits_defaults",
         // Uncomment the following line to enable VALIDATE_REGIONS traces
         //defaults: ["libui-validate-regions-defaults"],
     ],
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index a5aca99..41306b5 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -48,6 +48,13 @@
         for (const auto bit : hardware::hidl_enum_range<BufferUsage>()) {
             bits = bits | bit;
         }
+
+        if (ADDNL_GRALLOC_10_USAGE_BITS) {
+            uint64_t addnl_bits = static_cast<uint64_t>(ADDNL_GRALLOC_10_USAGE_BITS);
+            ALOGI("Adding additional valid usage bits: 0x%" PRIx64, addnl_bits);
+            bits = bits | addnl_bits;
+        }
+
         return bits;
     }();
     return valid10UsageBits;
diff --git a/libs/ui/Gralloc3.cpp b/libs/ui/Gralloc3.cpp
index 152b35a..e9aa9c8 100644
--- a/libs/ui/Gralloc3.cpp
+++ b/libs/ui/Gralloc3.cpp
@@ -47,6 +47,13 @@
              hardware::hidl_enum_range<hardware::graphics::common::V1_2::BufferUsage>()) {
             bits = bits | bit;
         }
+
+        if (ADDNL_GRALLOC_10_USAGE_BITS) {
+            uint64_t addnl_bits = static_cast<uint64_t>(ADDNL_GRALLOC_10_USAGE_BITS);
+            ALOGI("Adding additional valid usage bits: 0x%" PRIx64, addnl_bits);
+            bits = bits | addnl_bits;
+        }
+
         return bits;
     }();
     return validUsageBits;
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 2a60730..f1322f1 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -75,6 +75,13 @@
              hardware::hidl_enum_range<hardware::graphics::common::V1_2::BufferUsage>()) {
             bits = bits | bit;
         }
+
+        if (ADDNL_GRALLOC_10_USAGE_BITS) {
+            uint64_t addnl_bits = static_cast<uint64_t>(ADDNL_GRALLOC_10_USAGE_BITS);
+            ALOGI("Adding additional valid usage bits: 0x%" PRIx64, addnl_bits);
+            bits = bits | addnl_bits;
+        }
+
         return bits;
     }();
     return validUsageBits | kRemovedUsageBits;
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 5159ffe..e4616a8 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -139,7 +139,11 @@
 
 cc_library_shared {
     name: "libEGL",
-    defaults: ["egl_libs_defaults"],
+    defaults: [
+        "egl_libs_defaults",
+        "egl_display_array_defaults",
+        "nvidia_enhancements_defaults"
+    ],
     llndk: {
         symbol_file: "libEGL.map.txt",
         export_llndk_headers: ["gl_headers"],
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index bf0e38e..7616e59 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -703,6 +703,11 @@
         ALOGE_IF(!getProcAddress,
                 "can't find eglGetProcAddress() in EGL driver library");
 
+#ifdef NV_ANDROID_FRAMEWORK_ENHANCEMENTS
+        // This internally sets a bit in the main Nvidia EGL driver to enable desktop openGL
+        getProcAddress("eglSentinelForNVFrameworks");
+#endif
+
         egl_t* egl = &cnx->egl;
         __eglMustCastToProperFunctionPointerType* curr =
             (__eglMustCastToProperFunctionPointerType*)egl;
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index b1a287f..132d97f 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -69,8 +69,12 @@
     return eglDisplay ? eglDisplay->getRefsCount() : 0;
 }
 
+#ifdef EGL_DISPLAY_ARRAY
+egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
+#else
 std::map<EGLDisplay, std::unique_ptr<egl_display_t>> egl_display_t::displayMap;
 std::mutex egl_display_t::displayMapLock;
+#endif
 
 egl_display_t::egl_display_t()
       : magic('_dpy'),
@@ -89,12 +93,21 @@
         return nullptr;
     }
 
+#ifdef EGL_DISPLAY_ARRAY
+    uintptr_t index = uintptr_t(dpy) - 1U;
+    if (index >= NUM_DISPLAYS || !sDisplay[index].isValid()) {
+#else
     const std::lock_guard<std::mutex> lock(displayMapLock);
     auto search = displayMap.find(dpy);
     if (search == displayMap.end() || !search->second->isValid()) {
+#endif
         return nullptr;
     }
+#ifdef EGL_DISPLAY_ARRAY
+    return &sDisplay[index];
+#else
     return search->second.get();
+#endif
 }
 
 void egl_display_t::addObject(egl_object_t* object) {
@@ -122,7 +135,11 @@
                                                const EGLAttrib* attrib_list) {
     if (uintptr_t(disp) >= NUM_DISPLAYS) return nullptr;
 
+#ifdef EGL_DISPLAY_ARRAY
+    return sDisplay[uintptr_t(disp)].getPlatformDisplay(disp, attrib_list);
+#else
     return getPlatformDisplay(disp, attrib_list);
+#endif
 }
 
 static EGLDisplay getPlatformDisplayAngle(EGLNativeDisplayType display, egl_connection_t* const cnx,
@@ -177,6 +194,9 @@
 
 EGLDisplay egl_display_t::getPlatformDisplay(EGLNativeDisplayType display,
                                              const EGLAttrib* attrib_list) {
+#ifdef EGL_DISPLAY_ARRAY
+    std::lock_guard<std::mutex> _l(lock);
+#endif
     ATRACE_CALL();
 
     // get our driver loader
@@ -212,9 +232,14 @@
             }
         }
 
+#ifdef EGL_DISPLAY_ARRAY
+        disp.dpy = dpy;
+#endif
         if (dpy == EGL_NO_DISPLAY) {
             loader.close(cnx);
-        } else {
+        }
+#ifndef EGL_DISPLAY_ARRAY
+        else {
             const std::lock_guard<std::mutex> lock(displayMapLock);
             if (displayMap.find(dpy) == displayMap.end()) {
                 auto d = std::make_unique<egl_display_t>();
@@ -223,9 +248,14 @@
             }
             return dpy;
         }
+#endif
     }
 
+#ifdef EGL_DISPLAY_ARRAY
+    return EGLDisplay(uintptr_t(display) + 1U);
+#else
     return nullptr;
+#endif
 }
 
 EGLBoolean egl_display_t::initialize(EGLint* major, EGLint* minor) {
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 867a117..f6fc266 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -23,8 +23,10 @@
 #include <stdint.h>
 
 #include <condition_variable>
+#ifndef EGL_DISPLAY_ARRAY
 #include <map>
 #include <memory>
+#endif
 #include <mutex>
 #include <string>
 #include <unordered_set>
@@ -41,11 +43,19 @@
 bool findExtension(const char* exts, const char* name, size_t nameLen = 0);
 
 class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
+#ifdef EGL_DISPLAY_ARRAY
+    static egl_display_t sDisplay[NUM_DISPLAYS];
+#else
     static std::map<EGLDisplay, std::unique_ptr<egl_display_t>> displayMap;
     static std::mutex displayMapLock;
+#endif
     EGLDisplay getDisplay(EGLNativeDisplayType display);
+#ifdef EGL_DISPLAY_ARRAY
+    EGLDisplay getPlatformDisplay(EGLNativeDisplayType display, const EGLAttrib* attrib_list);
+#else
     static EGLDisplay getPlatformDisplay(EGLNativeDisplayType display,
                                          const EGLAttrib* attrib_list);
+#endif
     void loseCurrentImpl(egl_context_t* cur_c);
 
 public:
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 33a77c4..9a787d4 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -317,7 +317,14 @@
 
     // call the implementation's glGetString(GL_EXTENSIONS)
     const char* exts = (const char*)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS);
-    if (!exts) return;
+    if (!exts) {
+#ifndef NV_ANDROID_FRAMEWORK_ENHANCEMENTS
+        return;
+#else
+        gEGLImpl.hooks[version]->gl.glGetError();
+        exts = "";
+#endif
+}
 
     // If this context is sharing with another context, and the other context was reset
     // e.g. due to robustness failure, this context might also be reset and glGetString can
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 6e35041..39e7dda 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -968,6 +968,12 @@
         if (context != EGL_NO_CONTEXT) {
             // figure out if it's a GLESv1 or GLESv2
             int version = egl_connection_t::GLESv1_INDEX;
+
+#ifdef NV_ANDROID_FRAMEWORK_ENHANCEMENTS
+            if (cnx->egl.eglQueryAPI() == EGL_OPENGL_API)
+                version = egl_connection_t::GLESv2_INDEX;
+#endif
+
             GLint version_value;
             if (findAttribute(attrib_list, EGL_CONTEXT_CLIENT_VERSION, &version_value)) {
                 if (version_value == 2 || version_value == 3) {
@@ -1195,6 +1201,10 @@
     addr = findBuiltinWrapper(procname);
     if (addr) return addr;
 
+#ifdef NV_ANDROID_FRAMEWORK_ENHANCEMENTS
+    if (gEGLImpl.dso && gEGLImpl.egl.eglGetProcAddress)
+        addr = gEGLImpl.egl.eglGetProcAddress(procname);
+#else
     // this protects accesses to sGLExtensionMap, sGLExtensionSlot, and sGLExtensionSlotMap
     pthread_mutex_lock(&sExtensionMapMutex);
 
@@ -1279,6 +1289,7 @@
     }
 
     pthread_mutex_unlock(&sExtensionMapMutex);
+#endif
     return addr;
 }
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 05139cf..fa90cae 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3299,6 +3299,7 @@
         }
     }
 
+    int32_t keyCode = AKEYCODE_UNKNOWN;
     switch (eventEntry.type) {
         case EventEntry::Type::MOTION: {
             const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
@@ -3329,6 +3330,8 @@
                 }
                 return;
             }
+
+            keyCode = keyEntry.keyCode;
             break;
         }
         default: {
@@ -3339,10 +3342,10 @@
     }
 
     mLastUserActivityTimes[eventType] = eventEntry.eventTime;
-    auto command = [this, eventTime = eventEntry.eventTime, eventType, displayId]()
+    auto command = [this, eventTime = eventEntry.eventTime, eventType, displayId, keyCode]()
                            REQUIRES(mLock) {
                                scoped_unlock unlock(mLock);
-                               mPolicy.pokeUserActivity(eventTime, eventType, displayId);
+                               mPolicy.pokeUserActivity(eventTime, eventType, displayId, keyCode);
                            };
     postCommandLocked(std::move(command));
 }
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index b885ba1..489e5e9 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -123,7 +123,7 @@
 
     /* Poke user activity for an event dispatched to a window. */
     virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType,
-                                  ui::LogicalDisplayId displayId) = 0;
+                                  ui::LogicalDisplayId displayId, int32_t keyCode) = 0;
 
     /*
      * Return true if the provided event is stale, and false otherwise. Used for determining
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 2f6c6d7..d8e0507 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -96,6 +96,9 @@
         // The key remapping has changed.
         KEY_REMAPPING = 1u << 14,
 
+        // Volume keys rotation option changed.
+        VOLUME_KEYS_ROTATION = 1u << 15,
+
         // All devices must be reopened.
         MUST_REOPEN = 1u << 31,
     };
@@ -252,6 +255,10 @@
     // Keycodes to be remapped.
     std::map<int32_t /* fromKeyCode */, int32_t /* toKeyCode */> keyRemapping;
 
+    // Remap volume keys according to display rotation
+    // 0 - disabled, 1 - phone or hybrid rotation mode, 2 - tablet rotation mode
+    int volumeKeysRotationMode;
+
     InputReaderConfiguration()
           : virtualKeyQuietTime(0),
             defaultPointerDisplayId(ui::LogicalDisplayId::DEFAULT),
@@ -282,7 +289,8 @@
             shouldNotifyTouchpadHardwareState(false),
             touchpadRightClickZoneEnabled(false),
             stylusButtonMotionEventsEnabled(true),
-            stylusPointerIconEnabled(false) {}
+            stylusPointerIconEnabled(false),
+            volumeKeysRotationMode(0) {}
 
     std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const;
     std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueDisplayId)
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 38dcd65..c1742d9 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -28,10 +28,20 @@
 
 // --- Static Definitions ---
 
-static int32_t rotateKeyCode(int32_t keyCode, ui::Rotation orientation) {
+static int32_t rotateKeyCode(int32_t keyCode, ui::Rotation orientation, int rotationMapOffset) {
     static constexpr int32_t KEYCODE_ROTATION_MAP[][4] = {
             // key codes enumerated counter-clockwise with the original (unrotated) key first
             // no rotation,        90 degree rotation,  180 degree rotation, 270 degree rotation
+
+            // volume keys - tablet
+            {AKEYCODE_VOLUME_UP, AKEYCODE_VOLUME_UP, AKEYCODE_VOLUME_DOWN, AKEYCODE_VOLUME_DOWN},
+            {AKEYCODE_VOLUME_DOWN, AKEYCODE_VOLUME_DOWN, AKEYCODE_VOLUME_UP, AKEYCODE_VOLUME_UP},
+
+            // volume keys - phone or hybrid
+            {AKEYCODE_VOLUME_UP, AKEYCODE_VOLUME_DOWN, AKEYCODE_VOLUME_DOWN, AKEYCODE_VOLUME_UP},
+            {AKEYCODE_VOLUME_DOWN, AKEYCODE_VOLUME_UP, AKEYCODE_VOLUME_UP, AKEYCODE_VOLUME_DOWN},
+
+            // dpad keys - common
             {AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT},
             {AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN},
             {AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT},
@@ -45,9 +55,12 @@
             {AKEYCODE_SYSTEM_NAVIGATION_LEFT, AKEYCODE_SYSTEM_NAVIGATION_DOWN,
              AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP},
     };
+    static const size_t KEYCODE_ROTATION_MAP_SIZE =
+            sizeof(KEYCODE_ROTATION_MAP) / sizeof(KEYCODE_ROTATION_MAP[0]);
 
     if (orientation != ui::ROTATION_0) {
-        for (const auto& rotation : KEYCODE_ROTATION_MAP) {
+        for (size_t i = rotationMapOffset; i < KEYCODE_ROTATION_MAP_SIZE; i++) {
+            const auto& rotation = KEYCODE_ROTATION_MAP[i];
             if (rotation[static_cast<size_t>(ui::ROTATION_0)] == keyCode) {
                 return rotation[static_cast<size_t>(orientation)];
             }
@@ -200,6 +213,14 @@
             bumpGeneration();
         }
     }
+
+    if (!changes.any() || changes.test(InputReaderConfiguration::Change::VOLUME_KEYS_ROTATION)) {
+        // mode 0 (disabled) ~ offset 4
+        // mode 1 (phone) ~ offset 2
+        // mode 2 (tablet) ~ offset 0
+        mRotationMapOffset = 4 - 2 * config.volumeKeysRotationMode;
+    }
+
     return out;
 }
 
@@ -215,7 +236,8 @@
 
 void KeyboardInputMapper::configureParameters() {
     const PropertyMap& config = getDeviceContext().getConfiguration();
-    mParameters.orientationAware = config.getBool("keyboard.orientationAware").value_or(false);
+    mParameters.orientationAware = config.getBool("keyboard.orientationAware").value_or(
+            !getDeviceContext().isExternal());
     mParameters.handlesKeyRepeat = config.getBool("keyboard.handlesKeyRepeat").value_or(false);
     mParameters.doNotWakeByDefault = config.getBool("keyboard.doNotWakeByDefault").value_or(false);
 }
@@ -273,7 +295,7 @@
     if (down) {
         // Rotate key codes according to orientation if needed.
         if (mParameters.orientationAware) {
-            keyCode = rotateKeyCode(keyCode, getOrientation());
+            keyCode = rotateKeyCode(keyCode, getOrientation(), mRotationMapOffset);
         }
 
         // Add key down.
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index 2df0b85..3c811f9 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -66,6 +66,8 @@
 
     std::optional<KeyboardLayoutInfo> mKeyboardLayoutInfo;
 
+    int32_t mRotationMapOffset; // determines if and how volume keys rotate
+
     std::vector<KeyDown> mKeyDowns{}; // keys that are down
     int32_t mMetaState{};
 
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index c2a9880..a0a49c1 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -48,6 +48,7 @@
         "libsurfaceflinger_common_deps",
         "surfaceflinger_defaults",
         "libsurfaceflinger_proto_deps",
+        "surfaceflinger_qcom_ext_defaults",
     ],
     cflags: [
         "-DLOG_TAG=\"SurfaceFlinger\"",
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index b4ac9ba..3006077 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -86,6 +86,7 @@
         "src/OutputLayer.cpp",
         "src/OutputLayerCompositionState.cpp",
         "src/RenderSurface.cpp",
+        "src/UdfpsExtension.cpp",
     ],
 }
 
@@ -94,6 +95,7 @@
     defaults: [
         "libcompositionengine_defaults",
         "libsurfaceflinger_common_deps",
+        "surfaceflinger_udfps_lib_defaults",
     ],
     srcs: [
         ":libcompositionengine_sources",
@@ -128,6 +130,14 @@
     export_include_dirs: ["include"],
 }
 
+cc_library_static {
+    name: "surfaceflinger_udfps_lib",
+    srcs: [
+        "src/UdfpsExtension.cpp",
+    ],
+    export_include_dirs: ["include"],
+}
+
 cc_test {
     name: "libcompositionengine_test",
     test_suites: ["device-tests"],
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/UdfpsExtension.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/UdfpsExtension.h
new file mode 100644
index 0000000..cf69da9
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/UdfpsExtension.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021-2024 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#ifndef __UDFPS_EXTENSION__H__
+#define __UDFPS_EXTENSION__H__
+
+#define UDFPS_BIOMETRIC_PROMPT_LAYER_NAME "BiometricPrompt"
+#define UDFPS_DIM_LAYER_NAME "Dim Layer for UDFPS"
+#define UDFPS_LAYER_NAME "UdfpsControllerOverlay"
+#define UDFPS_TOUCHED_LAYER_NAME "SurfaceView[UdfpsControllerOverlay](BLAST)"
+
+extern uint32_t getUdfpsDimZOrder(uint32_t z);
+extern uint32_t getUdfpsZOrder(uint32_t z, bool touched);
+extern uint64_t getUdfpsUsageBits(uint64_t usageBits, bool touched);
+
+#endif /* __UDFPS_EXTENSION__H__ */
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 2d8f98f..9c145b6 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -24,6 +24,7 @@
 #include <compositionengine/LayerFE.h>
 #include <compositionengine/LayerFECompositionState.h>
 #include <compositionengine/RenderSurface.h>
+#include <compositionengine/UdfpsExtension.h>
 #include <compositionengine/impl/HwcAsyncWorker.h>
 #include <compositionengine/impl/Output.h>
 #include <compositionengine/impl/OutputCompositionState.h>
@@ -911,7 +912,10 @@
 
 compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const {
     compositionengine::OutputLayer* layerRequestingBgComposition = nullptr;
-    for (auto* layer : getOutputLayersOrderedByZ()) {
+    for (size_t i = 0; i < getOutputLayerCount(); i++) {
+        compositionengine::OutputLayer* layer = getOutputLayerOrderedByZByIndex(i);
+        compositionengine::OutputLayer* nextLayer = getOutputLayerOrderedByZByIndex(i + 1);
+
         const auto* compState = layer->getLayerFE().getCompositionState();
 
         // If any layer has a sideband stream, we will disable blurs. In that case, we don't
@@ -931,6 +935,16 @@
         if (compState->backgroundBlurRadius > 0 || compState->blurRegions.size() > 0) {
             layerRequestingBgComposition = layer;
         }
+
+        // If the next layer is the Udfps touched layer, enable client composition for it
+        // because that somehow leads to the Udfps touched layer getting device composition
+        // consistently.
+        if ((nextLayer != nullptr && layerRequestingBgComposition == nullptr) &&
+            (strncmp(nextLayer->getLayerFE().getDebugName(), UDFPS_TOUCHED_LAYER_NAME,
+                     strlen(UDFPS_TOUCHED_LAYER_NAME)) == 0)) {
+            layerRequestingBgComposition = layer;
+            break;
+        }
     }
     return layerRequestingBgComposition;
 }
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 091c207..45f98eb 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -18,6 +18,7 @@
 #include <compositionengine/DisplayColorProfile.h>
 #include <compositionengine/LayerFECompositionState.h>
 #include <compositionengine/Output.h>
+#include <compositionengine/UdfpsExtension.h>
 #include <compositionengine/impl/HwcBufferCache.h>
 #include <compositionengine/impl/OutputCompositionState.h>
 #include <compositionengine/impl/OutputLayer.h>
@@ -457,7 +458,20 @@
               sourceCrop.bottom, to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
-    if (auto error = hwcLayer->setZOrder(z); error != hal::Error::NONE) {
+    uint32_t z_udfps = z;
+    if ((strncmp(getLayerFE().getDebugName(), UDFPS_LAYER_NAME, strlen(UDFPS_LAYER_NAME)) == 0) ||
+        (strncmp(getLayerFE().getDebugName(), UDFPS_BIOMETRIC_PROMPT_LAYER_NAME,
+                 strlen(UDFPS_BIOMETRIC_PROMPT_LAYER_NAME)) == 0)) {
+        z_udfps = getUdfpsZOrder(z, false);
+    } else if (strncmp(getLayerFE().getDebugName(), UDFPS_DIM_LAYER_NAME,
+                       strlen(UDFPS_DIM_LAYER_NAME)) == 0) {
+        z_udfps = getUdfpsDimZOrder(z);
+    } else if (strncmp(getLayerFE().getDebugName(), UDFPS_TOUCHED_LAYER_NAME,
+                       strlen(UDFPS_TOUCHED_LAYER_NAME)) == 0) {
+        z_udfps = getUdfpsZOrder(z, true);
+    }
+
+    if (auto error = hwcLayer->setZOrder(z_udfps); error != hal::Error::NONE) {
         ALOGE("[%s] Failed to set Z %u: %s (%d)", getLayerFE().getDebugName(), z,
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
diff --git a/services/surfaceflinger/CompositionEngine/src/UdfpsExtension.cpp b/services/surfaceflinger/CompositionEngine/src/UdfpsExtension.cpp
new file mode 100644
index 0000000..5ae3815
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/UdfpsExtension.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2020-2024 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TARGET_PROVIDES_UDFPS_LIB
+#include <compositionengine/UdfpsExtension.h>
+
+uint32_t getUdfpsDimZOrder(uint32_t z) {
+    return z;
+}
+
+uint32_t getUdfpsZOrder(uint32_t z, __unused bool touched) {
+    return z;
+}
+
+uint64_t getUdfpsUsageBits(uint64_t usageBits, __unused bool touched) {
+    return usageBits;
+}
+#endif
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 384f7b2..7e29bff 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -51,7 +51,7 @@
                                              const sp<IGraphicBufferProducer>& sink,
                                              const sp<IGraphicBufferProducer>& bqProducer,
                                              const sp<IGraphicBufferConsumer>& bqConsumer,
-                                             const std::string& name)
+                                             const std::string& name, bool secure)
 #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
       : ConsumerBase(bqProducer, bqConsumer),
 #else
@@ -74,7 +74,9 @@
         mOutputFence(Fence::NO_FENCE),
         mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
         mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
-        mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv) {
+        mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv),
+        mSecure(secure),
+        mSinkUsage(0) {
     mSource[SOURCE_SINK] = sink;
     mSource[SOURCE_SCRATCH] = bqProducer;
 
@@ -92,6 +94,8 @@
     // on usage bits.
     int sinkUsage;
     sink->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &sinkUsage);
+    mSinkUsage |= (GRALLOC_USAGE_HW_COMPOSER | sinkUsage);
+    setOutputUsage(mSinkUsage);
     if (sinkUsage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
         int sinkFormat;
         sink->query(NATIVE_WINDOW_FORMAT, &sinkFormat);
@@ -124,7 +128,11 @@
     }
 
     mMustRecompose = mustRecompose;
-
+    //For WFD use cases we must always set the recompose flag in order
+    //to support pause/resume functionality
+    if (mOutputUsage & GRALLOC_USAGE_HW_VIDEO_ENCODER) {
+        mMustRecompose = true;
+    }
     VDS_LOGW_IF(mDebugState != DebugState::Idle, "Unexpected %s in %s state", __func__,
                 ftl::enum_string(mDebugState).c_str());
     mDebugState = DebugState::Begun;
@@ -161,7 +169,7 @@
     }
 
     if (mCompositionType != CompositionType::Gpu &&
-        (mOutputFormat != mDefaultOutputFormat || mOutputUsage != GRALLOC_USAGE_HW_COMPOSER)) {
+        (mOutputFormat != mDefaultOutputFormat || !(mOutputUsage & GRALLOC_USAGE_HW_COMPOSER))) {
         // We must have just switched from GPU-only to MIXED or HWC
         // composition. Stop using the format and usage requested by the GPU
         // driver; they may be suboptimal when HWC is writing to the output
@@ -173,7 +181,7 @@
         // format/usage and get a new buffer when the GPU driver calls
         // dequeueBuffer().
         mOutputFormat = mDefaultOutputFormat;
-        mOutputUsage = GRALLOC_USAGE_HW_COMPOSER;
+        setOutputUsage(GRALLOC_USAGE_HW_COMPOSER);
         refreshOutputBuffer();
     }
 
@@ -259,7 +267,7 @@
         int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot);
         QueueBufferOutput qbo;
         VDS_LOGV("%s: queue sink sslot=%d", __func__, sslot);
-        if (mMustRecompose) {
+        if (retireFence->isValid() && mMustRecompose) {
             status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
                     QueueBufferInput(
                         systemTime(), false /* isAutoTimestamp */,
@@ -323,6 +331,14 @@
         PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
     LOG_ALWAYS_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId).has_value());
 
+    // Exclude video encoder usage flag from scratch buffer usage flags.
+    if (source == SOURCE_SCRATCH) {
+        usage |= GRALLOC_USAGE_HW_FB;
+        usage &= ~(GRALLOC_USAGE_HW_VIDEO_ENCODER);
+        VDS_LOGV("%s(%s): updated scratch buffer usage flags=%#" PRIx64,
+                __func__, ftl::enum_string(source).c_str(), usage);
+    }
+
     status_t result =
             mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight,
                                            format, usage, nullptr, nullptr);
@@ -352,11 +368,11 @@
         }
     }
     if (result & BUFFER_NEEDS_REALLOCATION) {
-        result = mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
-        if (result < 0) {
+        auto status  = mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
+        if (status < 0) {
             mProducerBuffers[pslot].clear();
             mSource[source]->cancelBuffer(*sslot, *fence);
-            return result;
+            return status;
         }
         VDS_LOGV("%s(%s): buffers[%d]=%p fmt=%d usage=%#" PRIx64, __func__,
                  ftl::enum_string(source).c_str(), pslot, mProducerBuffers[pslot].get(),
@@ -417,7 +433,7 @@
                      __func__, w, h, format, usage, mSinkBufferWidth, mSinkBufferHeight,
                      buf->getPixelFormat(), buf->getUsage());
             mOutputFormat = format;
-            mOutputUsage = usage;
+            setOutputUsage(usage);
             result = refreshOutputBuffer();
             if (result < 0)
                 return result;
@@ -671,6 +687,21 @@
     return type == CompositionType::Unknown ? "Unknown"s : ftl::Flags(type).string();
 }
 
+/* Helper to update the output usage when the display is secure */
+
+void VirtualDisplaySurface::setOutputUsage(uint64_t /*flag*/) {
+
+    mOutputUsage = mSinkUsage;
+    if (mSecure && (mOutputUsage & GRALLOC_USAGE_HW_VIDEO_ENCODER)) {
+        /*TODO: Currently, the framework can only say whether the display
+         * and its subsequent session are secure or not. However, there is
+         * no mechanism to distinguish the different levels of security.
+         * The current solution assumes WV L3 protection.
+         */
+        mOutputUsage |= GRALLOC_USAGE_PROTECTED;
+    }
+}
+
 } // namespace android
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 90426f7..805fce9 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -77,7 +77,8 @@
 public:
     VirtualDisplaySurface(HWComposer&, VirtualDisplayId, const sp<IGraphicBufferProducer>& sink,
                           const sp<IGraphicBufferProducer>& bqProducer,
-                          const sp<IGraphicBufferConsumer>& bqConsumer, const std::string& name);
+                          const sp<IGraphicBufferConsumer>& bqConsumer,
+                          const std::string& name, bool secure);
 
     //
     // DisplaySurface interface
@@ -134,6 +135,7 @@
             sp<Fence>* outFence, float outTransformMatrix[16]) override;
     virtual status_t getUniqueId(uint64_t* outId) const override;
     virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
+    virtual void setOutputUsage(uint64_t flag);
 
     //
     // Utility methods
@@ -265,6 +267,8 @@
     bool mMustRecompose = false;
 
     bool mForceHwcCopy;
+    bool mSecure;
+    int mSinkUsage;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 65a0ed3..23a2f9f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -165,6 +165,14 @@
 #include "Utils/Dumper.h"
 #include "WindowInfosListenerInvoker.h"
 
+#ifdef QCOM_UM_FAMILY
+#if __has_include("QtiGralloc.h")
+#include "QtiGralloc.h"
+#else
+#include "gralloc_priv.h"
+#endif
+#endif
+
 #include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
 #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
 #include <aidl/android/hardware/graphics/composer3/RenderIntent.h>
@@ -640,8 +648,10 @@
 }
 
 VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution,
-                                                       ui::PixelFormat format) {
-    if (auto& generator = mVirtualDisplayIdGenerators.hal) {
+                                                       ui::PixelFormat format,
+                                                       bool canAllocateHwcForVDS) {
+    auto& generator = mVirtualDisplayIdGenerators.hal;
+    if (canAllocateHwcForVDS && generator) {
         if (const auto id = generator->generateId()) {
             if (getHwComposer().allocateVirtualDisplay(*id, resolution, &format)) {
                 return *id;
@@ -899,9 +909,9 @@
 
     enableLatchUnsignaledConfig = getLatchUnsignaledConfig();
 
-    if (base::GetBoolProperty("debug.sf.enable_hwc_vds"s, false)) {
-        enableHalVirtualDisplays(true);
-    }
+    mAllowHwcForWFD = base::GetBoolProperty("vendor.display.vds_allow_hwc"s, false);
+    mAllowHwcForVDS = mAllowHwcForWFD && base::GetBoolProperty("debug.sf.enable_hwc_vds"s, false);
+    mFirstApiLevel = android::base::GetIntProperty("ro.product.first_api_level", 0);
 
     // Process hotplug for displays connected at boot.
     LOG_ALWAYS_FATAL_IF(!configureLocked(),
@@ -3657,6 +3667,11 @@
 
 void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
                                          const DisplayDeviceState& state) {
+#ifdef QCOM_UM_FAMILY
+    bool canAllocateHwcForVDS = false;
+#else
+    bool canAllocateHwcForVDS = true;
+#endif
     ui::Size resolution(0, 0);
     ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN);
     if (state.physical) {
@@ -3671,6 +3686,20 @@
         status = state.surface->query(NATIVE_WINDOW_FORMAT, &format);
         ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
         pixelFormat = static_cast<ui::PixelFormat>(format);
+#ifdef QCOM_UM_FAMILY
+        // Check if VDS is allowed to use HWC
+        size_t maxVirtualDisplaySize = getHwComposer().getMaxVirtualDisplayDimension();
+        if (maxVirtualDisplaySize == 0 || ((uint64_t)resolution.width <= maxVirtualDisplaySize &&
+            (uint64_t)resolution.height <= maxVirtualDisplaySize)) {
+            uint64_t usage = 0;
+            // Replace with native_window_get_consumer_usage ?
+            status = state .surface->getConsumerUsage(&usage);
+            ALOGW_IF(status != NO_ERROR, "Unable to query usage (%d)", status);
+            if ((status == NO_ERROR) && canAllocateHwcDisplayIdForVDS(usage)) {
+                canAllocateHwcForVDS = true;
+            }
+        }
+#endif
     } else {
         // Virtual displays without a surface are dormant:
         // they have external state (layer stack, projection,
@@ -3682,7 +3711,7 @@
     if (const auto& physical = state.physical) {
         builder.setId(physical->id);
     } else {
-        builder.setId(acquireVirtualDisplay(resolution, pixelFormat));
+        builder.setId(acquireVirtualDisplay(resolution, pixelFormat, canAllocateHwcForVDS));
     }
 
     builder.setPixels(resolution);
@@ -3703,7 +3732,8 @@
         const auto displayId = VirtualDisplayId::tryCast(compositionDisplay->getId());
         LOG_FATAL_IF(!displayId);
         auto surface = sp<VirtualDisplaySurface>::make(getHwComposer(), *displayId, state.surface,
-                                                       bqProducer, bqConsumer, state.displayName);
+                                                       bqProducer, bqConsumer, state.displayName,
+                                                       state.isSecure);
         displaySurface = surface;
         producer = std::move(surface);
     } else {
@@ -7787,6 +7817,35 @@
 
 } // namespace
 
+#ifdef QCOM_UM_FAMILY
+bool SurfaceFlinger::canAllocateHwcDisplayIdForVDS(uint64_t usage) {
+    uint64_t flag_mask_pvt_wfd = ~0;
+    uint64_t flag_mask_hw_video = ~0;
+    // Reserve hardware acceleration for WFD use-case
+    // GRALLOC_USAGE_PRIVATE_WFD + GRALLOC_USAGE_HW_VIDEO_ENCODER = WFD using HW composer.
+    flag_mask_pvt_wfd = GRALLOC_USAGE_PRIVATE_WFD;
+    flag_mask_hw_video = GRALLOC_USAGE_HW_VIDEO_ENCODER;
+    bool isWfd = (usage & flag_mask_pvt_wfd) && (usage & flag_mask_hw_video);
+    // Enabling only the vendor property would allow WFD to use HWC
+    // Enabling both the aosp and vendor properties would allow all other VDS to use HWC
+    // Disabling both would set all virtual displays to fall back to GPU
+    // In vendor frozen targets, allow WFD to use HWC without any property settings.
+    bool canAllocate = mAllowHwcForVDS || (isWfd && mAllowHwcForWFD) || (isWfd &&
+                       mFirstApiLevel < __ANDROID_API_T__);
+
+    if (canAllocate) {
+        enableHalVirtualDisplays(true);
+    }
+
+    return canAllocate;
+
+}
+#else
+bool SurfaceFlinger::canAllocateHwcDisplayIdForVDS(uint64_t) {
+    return true;
+}
+#endif
+
 status_t SurfaceFlinger::setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
                                                     const gui::DisplayModeSpecs& specs) {
     SFTRACE_CALL();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3eb72cc..1ccfdc9 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -893,6 +893,8 @@
             std::vector<std::pair<Layer*, sp<LayerFE>>>& layers,
             std::vector<sp<LayerFE>>& layerFEs);
 
+    bool canAllocateHwcDisplayIdForVDS(uint64_t usage);
+
     void readPersistentProperties();
 
     uint32_t getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t uid) const;
@@ -1078,7 +1080,8 @@
     void enableHalVirtualDisplays(bool);
 
     // Virtual display lifecycle for ID generation and HAL allocation.
-    VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat) REQUIRES(mStateLock);
+    VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat, bool canAllocateHwcForVDS)
+            REQUIRES(mStateLock);
     void releaseVirtualDisplay(VirtualDisplayId);
 
     // Returns a display other than `mActiveDisplayId` that can be activated, if any.
@@ -1406,6 +1409,10 @@
 
     const sp<WindowInfosListenerInvoker> mWindowInfosListenerInvoker;
 
+    bool mAllowHwcForVDS = false;
+    bool mAllowHwcForWFD = false;
+    int mFirstApiLevel = 0;
+
     // returns the framerate of the layer with the given sequence ID
     float getLayerFramerate(nsecs_t now, int32_t id) const {
         return mScheduler->getLayerFramerate(now, id);