Merge "SF: Introduce VsyncTimeline to VsyncPredictor" into main
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 3af9ec7..bf7a0ba 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -258,24 +258,11 @@
     }
 }
 
-void ABBinder::addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& /* recipient */,
-                                 void* /* cookie */) {
-    LOG_ALWAYS_FATAL("Should not reach this. Can't linkToDeath local binders.");
-}
-
 ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder)
     : AIBinder(nullptr /*clazz*/), mRemote(binder) {
     LOG_ALWAYS_FATAL_IF(binder == nullptr, "binder == nullptr");
 }
-
-ABpBinder::~ABpBinder() {
-    for (auto& recip : mDeathRecipients) {
-        sp<AIBinder_DeathRecipient> strongRecip = recip.recipient.promote();
-        if (strongRecip) {
-            strongRecip->pruneThisTransferEntry(getBinder(), recip.cookie);
-        }
-    }
-}
+ABpBinder::~ABpBinder() {}
 
 sp<AIBinder> ABpBinder::lookupOrCreateFromBinder(const ::android::sp<::android::IBinder>& binder) {
     if (binder == nullptr) {
@@ -314,11 +301,6 @@
     return ret;
 }
 
-void ABpBinder::addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& recipient,
-                                  void* cookie) {
-    mDeathRecipients.emplace_back(recipient, cookie);
-}
-
 struct AIBinder_Weak {
     wp<AIBinder> binder;
 };
@@ -444,17 +426,6 @@
     LOG_ALWAYS_FATAL_IF(onDied == nullptr, "onDied == nullptr");
 }
 
-void AIBinder_DeathRecipient::pruneThisTransferEntry(const sp<IBinder>& who, void* cookie) {
-    std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
-    mDeathRecipients.erase(std::remove_if(mDeathRecipients.begin(), mDeathRecipients.end(),
-                                          [&](const sp<TransferDeathRecipient>& tdr) {
-                                              auto tdrWho = tdr->getWho();
-                                              return tdrWho != nullptr && tdrWho.promote() == who &&
-                                                     cookie == tdr->getCookie();
-                                          }),
-                           mDeathRecipients.end());
-}
-
 void AIBinder_DeathRecipient::pruneDeadTransferEntriesLocked() {
     mDeathRecipients.erase(std::remove_if(mDeathRecipients.begin(), mDeathRecipients.end(),
                                           [](const sp<TransferDeathRecipient>& tdr) {
@@ -583,11 +554,8 @@
         return STATUS_UNEXPECTED_NULL;
     }
 
-    binder_status_t ret = recipient->linkToDeath(binder->getBinder(), cookie);
-    if (ret == STATUS_OK) {
-        binder->addDeathRecipient(recipient, cookie);
-    }
-    return ret;
+    // returns binder_status_t
+    return recipient->linkToDeath(binder->getBinder(), cookie);
 }
 
 binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index a2682d8..9d5368f 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -51,8 +51,6 @@
         ::android::sp<::android::IBinder> binder = const_cast<AIBinder*>(this)->getBinder();
         return binder->remoteBinder() != nullptr;
     }
-    virtual void addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& recipient,
-                                   void* cookie) = 0;
 
    private:
     // AIBinder instance is instance of this class for a local object. In order to transact on a
@@ -80,8 +78,6 @@
     ::android::status_t dump(int fd, const ::android::Vector<::android::String16>& args) override;
     ::android::status_t onTransact(uint32_t code, const ::android::Parcel& data,
                                    ::android::Parcel* reply, binder_flags_t flags) override;
-    void addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& /* recipient */,
-                           void* /* cookie */) override;
 
    private:
     ABBinder(const AIBinder_Class* clazz, void* userData);
@@ -110,19 +106,12 @@
 
     bool isServiceFuzzing() const { return mServiceFuzzing; }
     void setServiceFuzzing() { mServiceFuzzing = true; }
-    void addDeathRecipient(const ::android::sp<AIBinder_DeathRecipient>& recipient,
-                           void* cookie) override;
 
    private:
     friend android::sp<ABpBinder>;
     explicit ABpBinder(const ::android::sp<::android::IBinder>& binder);
     ::android::sp<::android::IBinder> mRemote;
     bool mServiceFuzzing = false;
-    struct DeathRecipientInfo {
-        android::wp<AIBinder_DeathRecipient> recipient;
-        void* cookie;
-    };
-    std::vector<DeathRecipientInfo> mDeathRecipients;
 };
 
 struct AIBinder_Class {
@@ -194,7 +183,6 @@
     binder_status_t linkToDeath(const ::android::sp<::android::IBinder>&, void* cookie);
     binder_status_t unlinkToDeath(const ::android::sp<::android::IBinder>& binder, void* cookie);
     void setOnUnlinked(AIBinder_DeathRecipient_onBinderUnlinked onUnlinked);
-    void pruneThisTransferEntry(const ::android::sp<::android::IBinder>&, void* cookie);
 
    private:
     // When the user of this API deletes a Bp object but not the death recipient, the
diff --git a/libs/binder/ndk/tests/iface.cpp b/libs/binder/ndk/tests/iface.cpp
index ca92727..3ee36cd 100644
--- a/libs/binder/ndk/tests/iface.cpp
+++ b/libs/binder/ndk/tests/iface.cpp
@@ -25,7 +25,6 @@
 
 const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo";
 const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die";
-const char* IFoo::kInstanceNameToDieFor2 = "libbinder_ndk-test-IFoo-to-die2";
 const char* IFoo::kIFooDescriptor = "my-special-IFoo-class";
 
 struct IFoo_Class_Data {
diff --git a/libs/binder/ndk/tests/include/iface/iface.h b/libs/binder/ndk/tests/include/iface/iface.h
index 0cdd50b..0a562f0 100644
--- a/libs/binder/ndk/tests/include/iface/iface.h
+++ b/libs/binder/ndk/tests/include/iface/iface.h
@@ -27,7 +27,6 @@
    public:
     static const char* kSomeInstanceName;
     static const char* kInstanceNameToDieFor;
-    static const char* kInstanceNameToDieFor2;
     static const char* kIFooDescriptor;
 
     static AIBinder_Class* kClass;
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index ce63b82..966ec95 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -536,7 +536,6 @@
     bool deathReceived = false;
 
     std::function<void(void)> onDeath = [&] {
-        std::unique_lock<std::mutex> lockDeath(deathMutex);
         std::cerr << "Binder died (as requested)." << std::endl;
         deathReceived = true;
         deathCv.notify_one();
@@ -548,7 +547,6 @@
     bool wasDeathReceivedFirst = false;
 
     std::function<void(void)> onUnlink = [&] {
-        std::unique_lock<std::mutex> lockUnlink(unlinkMutex);
         std::cerr << "Binder unlinked (as requested)." << std::endl;
         wasDeathReceivedFirst = deathReceived;
         unlinkReceived = true;
@@ -562,6 +560,7 @@
 
     EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(cookie)));
 
+    // the binder driver should return this if the service dies during the transaction
     EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
 
     foo = nullptr;
@@ -580,123 +579,6 @@
     binder = nullptr;
 }
 
-TEST(NdkBinder, DeathRecipientDropBinderNoDeath) {
-    using namespace std::chrono_literals;
-
-    std::mutex deathMutex;
-    std::condition_variable deathCv;
-    bool deathReceived = false;
-
-    std::function<void(void)> onDeath = [&] {
-        std::unique_lock<std::mutex> lockDeath(deathMutex);
-        std::cerr << "Binder died (as requested)." << std::endl;
-        deathReceived = true;
-        deathCv.notify_one();
-    };
-
-    std::mutex unlinkMutex;
-    std::condition_variable unlinkCv;
-    bool unlinkReceived = false;
-    bool wasDeathReceivedFirst = false;
-
-    std::function<void(void)> onUnlink = [&] {
-        std::unique_lock<std::mutex> lockUnlink(unlinkMutex);
-        std::cerr << "Binder unlinked (as requested)." << std::endl;
-        wasDeathReceivedFirst = deathReceived;
-        unlinkReceived = true;
-        unlinkCv.notify_one();
-    };
-
-    // keep the death recipient around
-    ndk::ScopedAIBinder_DeathRecipient recipient(AIBinder_DeathRecipient_new(LambdaOnDeath));
-    AIBinder_DeathRecipient_setOnUnlinked(recipient.get(), LambdaOnUnlink);
-
-    {
-        AIBinder* binder;
-        sp<IFoo> foo = IFoo::getService(IFoo::kInstanceNameToDieFor2, &binder);
-        ASSERT_NE(nullptr, foo.get());
-        ASSERT_NE(nullptr, binder);
-
-        DeathRecipientCookie* cookie = new DeathRecipientCookie{&onDeath, &onUnlink};
-
-        EXPECT_EQ(STATUS_OK,
-                  AIBinder_linkToDeath(binder, recipient.get(), static_cast<void*>(cookie)));
-        // let the sp<IFoo> and AIBinder fall out of scope
-        AIBinder_decStrong(binder);
-        binder = nullptr;
-    }
-
-    {
-        std::unique_lock<std::mutex> lockDeath(deathMutex);
-        EXPECT_FALSE(deathCv.wait_for(lockDeath, 100ms, [&] { return deathReceived; }));
-        EXPECT_FALSE(deathReceived);
-    }
-
-    {
-        std::unique_lock<std::mutex> lockUnlink(unlinkMutex);
-        EXPECT_TRUE(deathCv.wait_for(lockUnlink, 1s, [&] { return unlinkReceived; }));
-        EXPECT_TRUE(unlinkReceived);
-        EXPECT_FALSE(wasDeathReceivedFirst);
-    }
-}
-
-TEST(NdkBinder, DeathRecipientDropBinderOnDied) {
-    using namespace std::chrono_literals;
-
-    std::mutex deathMutex;
-    std::condition_variable deathCv;
-    bool deathReceived = false;
-
-    sp<IFoo> foo;
-    AIBinder* binder;
-    std::function<void(void)> onDeath = [&] {
-        std::unique_lock<std::mutex> lockDeath(deathMutex);
-        std::cerr << "Binder died (as requested)." << std::endl;
-        deathReceived = true;
-        AIBinder_decStrong(binder);
-        binder = nullptr;
-        deathCv.notify_one();
-    };
-
-    std::mutex unlinkMutex;
-    std::condition_variable unlinkCv;
-    bool unlinkReceived = false;
-    bool wasDeathReceivedFirst = false;
-
-    std::function<void(void)> onUnlink = [&] {
-        std::unique_lock<std::mutex> lockUnlink(unlinkMutex);
-        std::cerr << "Binder unlinked (as requested)." << std::endl;
-        wasDeathReceivedFirst = deathReceived;
-        unlinkReceived = true;
-        unlinkCv.notify_one();
-    };
-
-    ndk::ScopedAIBinder_DeathRecipient recipient(AIBinder_DeathRecipient_new(LambdaOnDeath));
-    AIBinder_DeathRecipient_setOnUnlinked(recipient.get(), LambdaOnUnlink);
-
-    foo = IFoo::getService(IFoo::kInstanceNameToDieFor2, &binder);
-    ASSERT_NE(nullptr, foo.get());
-    ASSERT_NE(nullptr, binder);
-
-    DeathRecipientCookie* cookie = new DeathRecipientCookie{&onDeath, &onUnlink};
-    EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient.get(), static_cast<void*>(cookie)));
-
-    EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
-
-    {
-        std::unique_lock<std::mutex> lockDeath(deathMutex);
-        EXPECT_TRUE(deathCv.wait_for(lockDeath, 1s, [&] { return deathReceived; }));
-        EXPECT_TRUE(deathReceived);
-    }
-
-    {
-        std::unique_lock<std::mutex> lockUnlink(unlinkMutex);
-        EXPECT_TRUE(deathCv.wait_for(lockUnlink, 100ms, [&] { return unlinkReceived; }));
-        EXPECT_TRUE(unlinkReceived);
-        EXPECT_TRUE(wasDeathReceivedFirst);
-    }
-}
-
 TEST(NdkBinder, RetrieveNonNdkService) {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -1076,10 +958,6 @@
     }
     if (fork() == 0) {
         prctl(PR_SET_PDEATHSIG, SIGHUP);
-        return manualThreadPoolService(IFoo::kInstanceNameToDieFor2);
-    }
-    if (fork() == 0) {
-        prctl(PR_SET_PDEATHSIG, SIGHUP);
         return manualPollingService(IFoo::kSomeInstanceName);
     }
     if (fork() == 0) {
diff --git a/libs/gui/FrameRateUtils.cpp b/libs/gui/FrameRateUtils.cpp
index 11524e2..01aa7ed 100644
--- a/libs/gui/FrameRateUtils.cpp
+++ b/libs/gui/FrameRateUtils.cpp
@@ -42,6 +42,7 @@
 
     if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT &&
         compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE &&
+        compatibility != ANATIVEWINDOW_FRAME_RATE_GTE &&
         (!privileged ||
          (compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT &&
           compatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE))) {
diff --git a/libs/gui/tests/FrameRateUtilsTest.cpp b/libs/gui/tests/FrameRateUtilsTest.cpp
index 5fe22b0..04bfb28 100644
--- a/libs/gui/tests/FrameRateUtilsTest.cpp
+++ b/libs/gui/tests/FrameRateUtilsTest.cpp
@@ -34,6 +34,8 @@
                                   ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, ""));
     EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
                                   ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
+    EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_GTE,
+                                  ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, ""));
 
     // Privileged APIs.
     EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT,
diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
index b43ab6c..eb7a9d5 100644
--- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp
@@ -378,6 +378,11 @@
         BAIL("Could not find a Vulkan 1.1+ physical device");
     }
 
+    if (physDevProps.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
+        // TODO: b/326633110 - SkiaVK is not working correctly on swiftshader path.
+        BAIL("CPU implementations of Vulkan is not supported");
+    }
+
     // Check for syncfd support. Bail if we cannot both import and export them.
     VkPhysicalDeviceExternalSemaphoreInfo semInfo = {
             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO,
diff --git a/services/sensorservice/AidlSensorHalWrapper.cpp b/services/sensorservice/AidlSensorHalWrapper.cpp
index e60db93..91c2d1f 100644
--- a/services/sensorservice/AidlSensorHalWrapper.cpp
+++ b/services/sensorservice/AidlSensorHalWrapper.cpp
@@ -178,6 +178,11 @@
         if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mReconnecting) {
             ALOGD("Event FMQ internal wake, returning from poll with no events");
             return DEAD_OBJECT;
+        } else if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mInHalBypassMode &&
+                   availableEvents == 0) {
+            ALOGD("Event FMQ internal wake due to HAL Bypass Mode, returning from poll with no "
+                  "events");
+            return OK;
         }
     }
 
@@ -221,6 +226,17 @@
 
 status_t AidlSensorHalWrapper::setOperationMode(SensorService::Mode mode) {
     if (mSensors == nullptr) return NO_INIT;
+    if (mode == SensorService::Mode::HAL_BYPASS_REPLAY_DATA_INJECTION) {
+        if (!mInHalBypassMode) {
+            mInHalBypassMode = true;
+            mEventQueueFlag->wake(asBaseType(INTERNAL_WAKE));
+        }
+        return OK;
+    } else {
+        if (mInHalBypassMode) {
+            mInHalBypassMode = false;
+        }
+    }
     return convertToStatus(mSensors->setOperationMode(static_cast<ISensors::OperationMode>(mode)));
 }
 
diff --git a/services/sensorservice/HidlSensorHalWrapper.cpp b/services/sensorservice/HidlSensorHalWrapper.cpp
index c55c9b4..8c867bd 100644
--- a/services/sensorservice/HidlSensorHalWrapper.cpp
+++ b/services/sensorservice/HidlSensorHalWrapper.cpp
@@ -203,6 +203,11 @@
         if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mReconnecting) {
             ALOGD("Event FMQ internal wake, returning from poll with no events");
             return DEAD_OBJECT;
+        } else if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mInHalBypassMode &&
+                   availableEvents == 0) {
+            ALOGD("Event FMQ internal wake due to HAL Bypass Mode, returning from poll with no "
+                  "events");
+            return OK;
         }
     }
 
@@ -251,6 +256,17 @@
 
 status_t HidlSensorHalWrapper::setOperationMode(SensorService::Mode mode) {
     if (mSensors == nullptr) return NO_INIT;
+    if (mode == SensorService::Mode::HAL_BYPASS_REPLAY_DATA_INJECTION) {
+        if (!mInHalBypassMode) {
+            mInHalBypassMode = true;
+            mEventQueueFlag->wake(asBaseType(INTERNAL_WAKE));
+        }
+        return OK;
+    } else {
+        if (mInHalBypassMode) {
+            mInHalBypassMode = false;
+        }
+    }
     return checkReturnAndGetStatus(
             mSensors->setOperationMode(static_cast<hardware::sensors::V1_0::OperationMode>(mode)));
 }
diff --git a/services/sensorservice/ISensorHalWrapper.h b/services/sensorservice/ISensorHalWrapper.h
index 3d33540..891dfe5 100644
--- a/services/sensorservice/ISensorHalWrapper.h
+++ b/services/sensorservice/ISensorHalWrapper.h
@@ -97,6 +97,8 @@
     virtual void writeWakeLockHandled(uint32_t count) = 0;
 
     std::atomic_bool mReconnecting = false;
+
+    std::atomic_bool mInHalBypassMode = false;
 };
 
 } // namespace android
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 8e9dfea..f62562c 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -812,7 +812,6 @@
             }
             mInHalBypassMode = true;
         }
-        return OK;
     } else {
         if (mInHalBypassMode) {
             // We are transitioning out of HAL Bypass mode. We need to notify the reader thread
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index c888ccc..77e045d 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -377,8 +377,8 @@
     constexpr bool kIsProtected = false;
 
     if (const auto fenceResult =
-                mFlinger.captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, buffer,
-                                             kRegionSampling, kGrayscale, kIsProtected, nullptr)
+                mFlinger.captureScreenshot(std::move(renderAreaFuture), getLayerSnapshots, buffer,
+                                           kRegionSampling, kGrayscale, kIsProtected, nullptr)
                         .get();
         fenceResult.ok()) {
         fenceResult.value()->waitForever(LOG_TAG);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index e696e8c..93350b5 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -972,6 +972,7 @@
             LOG_ALWAYS_FATAL_IF(layer->vote != LayerVoteType::ExplicitDefault &&
                                         layer->vote != LayerVoteType::ExplicitExactOrMultiple &&
                                         layer->vote != LayerVoteType::ExplicitExact &&
+                                        layer->vote != LayerVoteType::ExplicitGte &&
                                         layer->vote != LayerVoteType::ExplicitCategory,
                                 "Invalid layer vote type for frame rate overrides");
             for (auto& [fps, score] : scoredFrameRates) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9e13144..46a2259 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -8069,6 +8069,19 @@
                         args.allowProtected, args.grayscale, captureListener);
 }
 
+bool SurfaceFlinger::layersHasProtectedLayer(
+        const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const {
+    bool protectedLayerFound = false;
+    for (auto& [_, layerFe] : layers) {
+        protectedLayerFound |=
+                (layerFe->mSnapshot->isVisible && layerFe->mSnapshot->hasProtectedContent);
+        if (protectedLayerFound) {
+            break;
+        }
+    }
+    return protectedLayerFound;
+}
+
 void SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
                                          GetLayerSnapshotsFunction getLayerSnapshots,
                                          ui::Size bufferSize, ui::PixelFormat reqPixelFormat,
@@ -8084,6 +8097,9 @@
         return;
     }
 
+    // Snapshots must be taken from the main thread.
+    auto layers = mScheduler->schedule([=]() { return getLayerSnapshots(); }).get();
+
     // Loop over all visible layers to see whether there's any protected layer. A protected layer is
     // typically a layer with DRM contents, or have the GRALLOC_USAGE_PROTECTED set on the buffer.
     // A protected layer has no implication on whether it's secure, which is explicitly set by
@@ -8091,18 +8107,7 @@
     const bool supportsProtected = getRenderEngine().supportsProtectedContent();
     bool hasProtectedLayer = false;
     if (allowProtected && supportsProtected) {
-        hasProtectedLayer = mScheduler
-                                    ->schedule([=]() {
-                                        bool protectedLayerFound = false;
-                                        auto layers = getLayerSnapshots();
-                                        for (auto& [_, layerFe] : layers) {
-                                            protectedLayerFound |=
-                                                    (layerFe->mSnapshot->isVisible &&
-                                                     layerFe->mSnapshot->hasProtectedContent);
-                                        }
-                                        return protectedLayerFound;
-                                    })
-                                    .get();
+        hasProtectedLayer = layersHasProtectedLayer(layers);
     }
     const bool isProtected = hasProtectedLayer && allowProtected && supportsProtected;
     const uint32_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_RENDER |
@@ -8127,52 +8132,53 @@
             renderengine::impl::ExternalTexture>(buffer, getRenderEngine(),
                                                  renderengine::impl::ExternalTexture::Usage::
                                                          WRITEABLE);
-    auto fence = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, texture,
-                                     false /* regionSampling */, grayscale, isProtected,
-                                     captureListener);
-    fence.get();
+    auto futureFence =
+            captureScreenshot(std::move(renderAreaFuture), getLayerSnapshots, texture,
+                              false /* regionSampling */, grayscale, isProtected, captureListener);
+    futureFence.get();
 }
 
-ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon(
+ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot(
         RenderAreaFuture renderAreaFuture, GetLayerSnapshotsFunction getLayerSnapshots,
         const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
         bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
 
-    auto future = mScheduler->schedule(
-            [=, this, renderAreaFuture = std::move(renderAreaFuture)]() FTL_FAKE_GUARD(
-                    kMainThreadContext) mutable -> ftl::SharedFuture<FenceResult> {
-                ScreenCaptureResults captureResults;
-                std::shared_ptr<RenderArea> renderArea = renderAreaFuture.get();
-                if (!renderArea) {
-                    ALOGW("Skipping screen capture because of invalid render area.");
-                    if (captureListener) {
-                        captureResults.fenceResult = base::unexpected(NO_MEMORY);
+    auto takeScreenshotFn = [=, this, renderAreaFuture = std::move(renderAreaFuture)]() REQUIRES(
+                                    kMainThreadContext) mutable -> ftl::SharedFuture<FenceResult> {
+        ScreenCaptureResults captureResults;
+        std::shared_ptr<RenderArea> renderArea = renderAreaFuture.get();
+        if (!renderArea) {
+            ALOGW("Skipping screen capture because of invalid render area.");
+            if (captureListener) {
+                captureResults.fenceResult = base::unexpected(NO_MEMORY);
+                captureListener->onScreenCaptureCompleted(captureResults);
+            }
+            return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share();
+        }
+
+        ftl::SharedFuture<FenceResult> renderFuture;
+        renderArea->render([&]() FTL_FAKE_GUARD(kMainThreadContext) {
+            renderFuture = renderScreenImpl(renderArea, getLayerSnapshots, buffer, regionSampling,
+                                            grayscale, isProtected, captureResults);
+        });
+
+        if (captureListener) {
+            // Defer blocking on renderFuture back to the Binder thread.
+            return ftl::Future(std::move(renderFuture))
+                    .then([captureListener, captureResults = std::move(captureResults)](
+                                  FenceResult fenceResult) mutable -> FenceResult {
+                        captureResults.fenceResult = std::move(fenceResult);
                         captureListener->onScreenCaptureCompleted(captureResults);
-                    }
-                    return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share();
-                }
+                        return base::unexpected(NO_ERROR);
+                    })
+                    .share();
+        }
+        return renderFuture;
+    };
 
-                ftl::SharedFuture<FenceResult> renderFuture;
-                renderArea->render([&]() FTL_FAKE_GUARD(kMainThreadContext) {
-                    renderFuture =
-                            renderScreenImpl(renderArea, getLayerSnapshots, buffer, regionSampling,
-                                             grayscale, isProtected, captureResults);
-                });
-
-                if (captureListener) {
-                    // Defer blocking on renderFuture back to the Binder thread.
-                    return ftl::Future(std::move(renderFuture))
-                            .then([captureListener, captureResults = std::move(captureResults)](
-                                          FenceResult fenceResult) mutable -> FenceResult {
-                                captureResults.fenceResult = std::move(fenceResult);
-                                captureListener->onScreenCaptureCompleted(captureResults);
-                                return base::unexpected(NO_ERROR);
-                            })
-                            .share();
-                }
-                return renderFuture;
-            });
+    auto future =
+            mScheduler->schedule(FTL_FAKE_GUARD(kMainThreadContext, std::move(takeScreenshotFn)));
 
     // Flatten nested futures.
     auto chain = ftl::Future(std::move(future)).then([](ftl::SharedFuture<FenceResult> future) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 678be54..1ce8606 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -874,13 +874,17 @@
     // Boot animation, on/off animations and screen capture
     void startBootAnim();
 
+    bool layersHasProtectedLayer(const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) const;
+
     void captureScreenCommon(RenderAreaFuture, GetLayerSnapshotsFunction, ui::Size bufferSize,
                              ui::PixelFormat, bool allowProtected, bool grayscale,
                              const sp<IScreenCaptureListener>&);
-    ftl::SharedFuture<FenceResult> captureScreenCommon(
+
+    ftl::SharedFuture<FenceResult> captureScreenshot(
             RenderAreaFuture, GetLayerSnapshotsFunction,
             const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
             bool grayscale, bool isProtected, const sp<IScreenCaptureListener>&);
+
     ftl::SharedFuture<FenceResult> renderScreenImpl(
             std::shared_ptr<const RenderArea>, GetLayerSnapshotsFunction,
             const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling,
diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig
index c8f4218..eda0674 100644
--- a/services/surfaceflinger/surfaceflinger_flags.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags.aconfig
@@ -189,6 +189,10 @@
   namespace: "core_graphics"
   description: "This flag is guarding the behaviour where SurfaceFlinger is trying to opportunistically present a frame when the configuration change from late to early"
   bug: "273702768"
+  is_fixed_read_only: true
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
 }
 
 flag {