Merge "Synthesize cancel event to global monitor specify display id" into main
diff --git a/include/ftl/details/future.h b/include/ftl/details/future.h
index df1323e..8d82e0f 100644
--- a/include/ftl/details/future.h
+++ b/include/ftl/details/future.h
@@ -73,8 +73,18 @@
return std::get<Impl>(self()).get();
}
+ template <class Rep, class Period>
+ std::future_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const {
+ if (std::holds_alternative<T>(self())) {
+ return std::future_status::ready;
+ }
+
+ return std::get<Impl>(self()).wait_for(timeout_duration);
+ }
+
private:
auto& self() { return static_cast<Self&>(*this).future_; }
+ const auto& self() const { return static_cast<const Self&>(*this).future_; }
};
template <typename Self, typename T>
@@ -90,6 +100,15 @@
return std::get<Impl>(self()).get();
}
+ template <class Rep, class Period>
+ std::future_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const {
+ if (std::holds_alternative<T>(self())) {
+ return std::future_status::ready;
+ }
+
+ return std::get<Impl>(self()).wait_for(timeout_duration);
+ }
+
private:
const auto& self() const { return static_cast<const Self&>(*this).future_; }
};
diff --git a/include/ftl/future.h b/include/ftl/future.h
index c78f9b7..dad180f 100644
--- a/include/ftl/future.h
+++ b/include/ftl/future.h
@@ -51,6 +51,7 @@
// Forwarding functions. Base::share is only defined when FutureImpl is std::future, whereas the
// following are defined for either FutureImpl:
using Base::get;
+ using Base::wait_for;
// Attaches a continuation to the future. The continuation is a function that maps T to either R
// or ftl::Future<R>. In the former case, the chain wraps the result in a future as if by
diff --git a/libs/ftl/future_test.cpp b/libs/ftl/future_test.cpp
index 5a245b6..1140639 100644
--- a/libs/ftl/future_test.cpp
+++ b/libs/ftl/future_test.cpp
@@ -102,4 +102,42 @@
decrement_thread.join();
}
+TEST(Future, WaitFor) {
+ using namespace std::chrono_literals;
+ {
+ auto future = ftl::yield(42);
+ // Check that we can wait_for multiple times without invalidating the future
+ EXPECT_EQ(future.wait_for(1s), std::future_status::ready);
+ EXPECT_EQ(future.wait_for(1s), std::future_status::ready);
+ EXPECT_EQ(future.get(), 42);
+ }
+
+ {
+ std::condition_variable cv;
+ std::mutex m;
+ bool ready = false;
+
+ std::packaged_task<int32_t()> get_int([&] {
+ std::unique_lock lk(m);
+ cv.wait(lk, [&] { return ready; });
+ return 24;
+ });
+
+ auto get_future = ftl::Future(get_int.get_future());
+ std::thread get_thread(std::move(get_int));
+
+ EXPECT_EQ(get_future.wait_for(0s), std::future_status::timeout);
+ {
+ std::unique_lock lk(m);
+ ready = true;
+ }
+ cv.notify_one();
+
+ EXPECT_EQ(get_future.wait_for(1s), std::future_status::ready);
+ EXPECT_EQ(get_future.get(), 24);
+
+ get_thread.join();
+ }
+}
+
} // namespace android::test
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 8d18551..83c2b7f 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -56,6 +56,7 @@
#include <android-base/thread_annotations.h>
#include <gui/LayerStatePermissions.h>
+#include <gui/ScreenCaptureResults.h>
#include <private/gui/ComposerService.h>
#include <private/gui/ComposerServiceAIDL.h>
@@ -3138,11 +3139,19 @@
}
status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs,
- const sp<IScreenCaptureListener>& captureListener) {
+ const sp<IScreenCaptureListener>& captureListener,
+ bool sync) {
sp<gui::ISurfaceComposer> s(ComposerServiceAIDL::getComposerService());
if (s == nullptr) return NO_INIT;
- binder::Status status = s->captureLayers(captureArgs, captureListener);
+ binder::Status status;
+ if (sync) {
+ gui::ScreenCaptureResults captureResults;
+ status = s->captureLayersSync(captureArgs, &captureResults);
+ captureListener->onScreenCaptureCompleted(captureResults);
+ } else {
+ status = s->captureLayers(captureArgs, captureListener);
+ }
return statusTFromBinderStatus(status);
}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index e3122bc..51e0193 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -46,6 +46,7 @@
import android.gui.LayerDebugInfo;
import android.gui.OverlayProperties;
import android.gui.PullAtomData;
+import android.gui.ScreenCaptureResults;
import android.gui.ARect;
import android.gui.SchedulingPolicy;
import android.gui.StalledTransactionInfo;
@@ -245,6 +246,16 @@
/**
* Capture a subtree of the layer hierarchy, potentially ignoring the root node.
* This requires READ_FRAME_BUFFER permission. This function will fail if there
+ * is a secure window on screen. This is a blocking call and will return the
+ * ScreenCaptureResults, including the captured buffer. Because this is blocking, the
+ * caller doesn't care about the fence and the binder thread in SurfaceFlinger will wait
+ * on the fence to fire before returning the results.
+ */
+ ScreenCaptureResults captureLayersSync(in LayerCaptureArgs args);
+
+ /**
+ * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
+ * This requires READ_FRAME_BUFFER permission. This function will fail if there
* is a secure window on screen
*/
oneway void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener);
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
index c952ba2..2bdbd43 100644
--- a/libs/gui/fuzzer/libgui_fuzzer_utils.h
+++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h
@@ -104,6 +104,8 @@
(int64_t, const gui::CaptureArgs&, const sp<IScreenCaptureListener>&), (override));
MOCK_METHOD(binder::Status, captureLayers,
(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&), (override));
+ MOCK_METHOD(binder::Status, captureLayersSync,
+ (const LayerCaptureArgs&, gui::ScreenCaptureResults*), (override));
MOCK_METHOD(binder::Status, clearAnimationFrameStats, (), (override));
MOCK_METHOD(binder::Status, getAnimationFrameStats, (gui::FrameStats*), (override));
MOCK_METHOD(binder::Status, overrideHdrTypes, (const sp<IBinder>&, const std::vector<int32_t>&),
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 14e3dd5..88a2c34 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -849,7 +849,8 @@
static status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&);
static status_t captureDisplay(DisplayId, const gui::CaptureArgs&,
const sp<IScreenCaptureListener>&);
- static status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&);
+ static status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&,
+ bool sync);
[[deprecated]] static status_t captureDisplay(DisplayId id,
const sp<IScreenCaptureListener>& listener) {
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index c6ea317..577d239 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -791,6 +791,10 @@
return binder::Status::ok();
}
+ binder::Status captureLayersSync(const LayerCaptureArgs&, ScreenCaptureResults*) override {
+ return binder::Status::ok();
+ }
+
binder::Status captureLayers(const LayerCaptureArgs&,
const sp<IScreenCaptureListener>&) override {
return binder::Status::ok();
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index fc84bbf..330cc66 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -1016,7 +1016,7 @@
.fakeOutputDataspace = fakeDataspace}));
// Turn on dithering when dimming beyond this (arbitrary) threshold...
- static constexpr float kDimmingThreshold = 0.2f;
+ static constexpr float kDimmingThreshold = 0.9f;
// ...or we're rendering an HDR layer down to an 8-bit target
// Most HDR standards require at least 10-bits of color depth for source content, so we
// can just extract the transfer function rather than dig into precise gralloc layout.
diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp
index d992aa5..cc92bc3 100644
--- a/libs/sensor/Android.bp
+++ b/libs/sensor/Android.bp
@@ -21,6 +21,18 @@
default_applicable_licenses: ["frameworks_native_license"],
}
+aconfig_declarations {
+ name: "libsensor_flags",
+ package: "com.android.hardware.libsensor.flags",
+ srcs: ["libsensor_flags.aconfig"],
+}
+
+cc_aconfig_library {
+ name: "libsensor_flags_c_lib",
+ host_supported: true,
+ aconfig_declarations: "libsensor_flags",
+}
+
cc_library {
name: "libsensor",
@@ -52,6 +64,10 @@
"android.companion.virtual.virtualdevice_aidl-cpp",
],
+ static_libs: [
+ "libsensor_flags_c_lib",
+ ],
+
export_include_dirs: ["include"],
export_shared_lib_headers: [
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index b82a79f..9411e20 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -37,6 +37,8 @@
#include <sensor/Sensor.h>
#include <sensor/SensorEventQueue.h>
+#include <com_android_hardware_libsensor_flags.h>
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -192,6 +194,9 @@
}
status_t SensorManager::assertStateLocked() {
+#if COM_ANDROID_HARDWARE_LIBSENSOR_FLAGS(SENSORMANAGER_PING_BINDER)
+ if (mSensorServer == nullptr) {
+#else
bool initSensorManager = false;
if (mSensorServer == nullptr) {
initSensorManager = true;
@@ -203,6 +208,7 @@
}
}
if (initSensorManager) {
+#endif
waitForSensorService(&mSensorServer);
LOG_ALWAYS_FATAL_IF(mSensorServer == nullptr, "getService(SensorService) NULL");
diff --git a/libs/sensor/libsensor_flags.aconfig b/libs/sensor/libsensor_flags.aconfig
new file mode 100644
index 0000000..a8b38e9
--- /dev/null
+++ b/libs/sensor/libsensor_flags.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.hardware.libsensor.flags"
+
+flag {
+ name: "sensormanager_ping_binder"
+ namespace: "libsensors"
+ description: "Whether to pingBinder on SensorManager init"
+ bug: "322228259"
+ is_fixed_read_only: true
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c8b1059..219a8e2 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -78,11 +78,13 @@
#include "SurfaceFlinger.h"
#include "TimeStats/TimeStats.h"
#include "TunnelModeEnabledReporter.h"
+#include "Utils/FenceUtils.h"
#define DEBUG_RESIZE 0
#define EARLY_RELEASE_ENABLED false
namespace android {
+using namespace std::chrono_literals;
namespace {
constexpr int kDumpTableRowLength = 159;
@@ -2911,7 +2913,8 @@
}
void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult,
- ui::LayerStack layerStack) {
+ ui::LayerStack layerStack,
+ std::function<FenceResult(FenceResult)>&& continuation) {
// If we are displayed on multiple displays in a single composition cycle then we would
// need to do careful tracking to enable the use of the mLastClientCompositionFence.
// For example we can only use it if all the displays are client comp, and we need
@@ -2946,11 +2949,41 @@
break;
}
}
+
+ if (!FlagManager::getInstance().screenshot_fence_preservation() && continuation) {
+ futureFenceResult = ftl::Future(futureFenceResult).then(std::move(continuation)).share();
+ }
+
if (ch != nullptr) {
ch->previousReleaseCallbackId = mPreviousReleaseCallbackId;
ch->previousReleaseFences.emplace_back(std::move(futureFenceResult));
ch->name = mName;
+ } else if (FlagManager::getInstance().screenshot_fence_preservation()) {
+ // If we didn't get a release callback yet, e.g. some scenarios when capturing screenshots
+ // asynchronously, then make sure we don't drop the fence.
+ mAdditionalPreviousReleaseFences.emplace_back(std::move(futureFenceResult),
+ std::move(continuation));
+ std::vector<FenceAndContinuation> mergedFences;
+ sp<Fence> prevFence = nullptr;
+ // For a layer that's frequently screenshotted, try to merge fences to make sure we don't
+ // grow unbounded.
+ for (const auto& futureAndContinution : mAdditionalPreviousReleaseFences) {
+ auto result = futureAndContinution.future.wait_for(0s);
+ if (result != std::future_status::ready) {
+ mergedFences.emplace_back(futureAndContinution);
+ continue;
+ }
+
+ mergeFence(getDebugName(), futureAndContinution.chain().get().value_or(Fence::NO_FENCE),
+ prevFence);
+ }
+ if (prevFence != nullptr) {
+ mergedFences.emplace_back(ftl::yield(FenceResult(std::move(prevFence))).share());
+ }
+
+ mAdditionalPreviousReleaseFences.swap(mergedFences);
}
+
if (mBufferInfo.mBuffer) {
mPreviouslyPresentedLayerStacks.push_back(layerStack);
}
@@ -3440,6 +3473,15 @@
handle->acquireTimeOrFence = mCallbackHandleAcquireTimeOrFence;
handle->frameNumber = mDrawingState.frameNumber;
handle->previousFrameNumber = mDrawingState.previousFrameNumber;
+ if (FlagManager::getInstance().screenshot_fence_preservation() &&
+ mPreviousReleaseBufferEndpoint == handle->listener) {
+ // Add fences from previous screenshots now so that they can be dispatched to the
+ // client.
+ for (const auto& futureAndContinution : mAdditionalPreviousReleaseFences) {
+ handle->previousReleaseFences.emplace_back(futureAndContinution.chain());
+ }
+ mAdditionalPreviousReleaseFences.clear();
+ }
// Store so latched time and release fence can be set
mDrawingState.callbackHandles.push_back(handle);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c772e0e..dfd57c6 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -555,7 +555,8 @@
const compositionengine::LayerFECompositionState* getCompositionState() const;
bool fenceHasSignaled() const;
void onPreComposition(nsecs_t refreshStartTime);
- void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack);
+ void onLayerDisplayed(ftl::SharedFuture<FenceResult>, ui::LayerStack layerStack,
+ std::function<FenceResult(FenceResult)>&& continuation = nullptr);
void setWasClientComposed(const sp<Fence>& fence) {
mLastClientCompositionFence = fence;
@@ -932,6 +933,19 @@
// the release fences from the correct displays when we release the last buffer
// from the layer.
std::vector<ui::LayerStack> mPreviouslyPresentedLayerStacks;
+ struct FenceAndContinuation {
+ ftl::SharedFuture<FenceResult> future;
+ std::function<FenceResult(FenceResult)> continuation;
+
+ ftl::SharedFuture<FenceResult> chain() const {
+ if (continuation) {
+ return ftl::Future(future).then(continuation).share();
+ } else {
+ return future;
+ }
+ }
+ };
+ std::vector<FenceAndContinuation> mAdditionalPreviousReleaseFences;
// Exposed so SurfaceFlinger can assert that it's held
const sp<SurfaceFlinger> mFlinger;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index c3709e5..7614453 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -843,9 +843,13 @@
const auto touchRefreshRates = rankFrameRates(anchorGroup, RefreshRateOrder::Descending);
using fps_approx_ops::operator<;
+ // A method for UI Toolkit to send the touch signal via "HighHint" category vote,
+ // which will touch boost when there are no ExplicitDefault layer votes. This is an
+ // incomplete solution but accounts for cases such as games that use `setFrameRate` with default
+ // compatibility to limit the frame rate, which should not have touch boost.
const bool hasInteraction = signals.touch || interactiveLayers > 0;
- if (hasInteraction && explicitDefaultVoteLayers == 0 && explicitCategoryVoteLayers == 0 &&
- touchBoostForExplicitExact &&
+
+ if (hasInteraction && explicitDefaultVoteLayers == 0 && touchBoostForExplicitExact &&
scores.front().frameRateMode.fps < touchRefreshRates.front().frameRateMode.fps) {
ALOGV("Touch Boost");
ATRACE_FORMAT_INSTANT("%s (Touch Boost [late])",
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d9b2fd8..aa6be36 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -116,6 +116,7 @@
#include <common/FlagManager.h>
#include <gui/LayerStatePermissions.h>
#include <gui/SchedulingPolicy.h>
+#include <gui/SyncScreenCaptureListener.h>
#include <ui/DisplayIdentification.h>
#include "BackgroundExecutor.h"
#include "Client.h"
@@ -7739,6 +7740,12 @@
kAllowProtected, kGrayscale, captureListener);
}
+ScreenCaptureResults SurfaceFlinger::captureLayersSync(const LayerCaptureArgs& args) {
+ sp<SyncScreenCaptureListener> captureListener = sp<SyncScreenCaptureListener>::make();
+ captureLayers(args, captureListener);
+ return captureListener->waitForResults();
+}
+
void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
const sp<IScreenCaptureListener>& captureListener) {
ATRACE_CALL();
@@ -8152,14 +8159,23 @@
: ftl::yield(present()).share();
for (auto& [layer, layerFE] : layers) {
- layer->onLayerDisplayed(ftl::Future(presentFuture)
- .then([layerFE = std::move(layerFE)](FenceResult) {
- return layerFE->stealCompositionResult()
- .releaseFences.back()
- .first.get();
- })
- .share(),
- ui::INVALID_LAYER_STACK);
+ layer->onLayerDisplayed(presentFuture, ui::INVALID_LAYER_STACK,
+ [layerFE = std::move(layerFE)](FenceResult) {
+ if (FlagManager::getInstance()
+ .screenshot_fence_preservation()) {
+ const auto compositionResult =
+ layerFE->stealCompositionResult();
+ const auto& fences = compositionResult.releaseFences;
+ // CompositionEngine may choose to cull layers that
+ // aren't visible, so pass a non-fence.
+ return fences.empty() ? Fence::NO_FENCE
+ : fences.back().first.get();
+ } else {
+ return layerFE->stealCompositionResult()
+ .releaseFences.back()
+ .first.get();
+ }
+ });
}
return presentFuture;
@@ -9578,6 +9594,12 @@
return binderStatusFromStatusT(NO_ERROR);
}
+binder::Status SurfaceComposerAIDL::captureLayersSync(const LayerCaptureArgs& args,
+ ScreenCaptureResults* outResults) {
+ *outResults = mFlinger->captureLayersSync(args);
+ return binderStatusFromStatusT(NO_ERROR);
+}
+
binder::Status SurfaceComposerAIDL::captureLayers(
const LayerCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) {
mFlinger->captureLayers(args, captureListener);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 7cfe46c..c8e2a4d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -560,6 +560,7 @@
void captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&);
void captureDisplay(DisplayId, const CaptureArgs&, const sp<IScreenCaptureListener>&);
+ ScreenCaptureResults captureLayersSync(const LayerCaptureArgs&);
void captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&);
status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
@@ -1547,6 +1548,7 @@
const sp<IScreenCaptureListener>&) override;
binder::Status captureLayers(const LayerCaptureArgs&,
const sp<IScreenCaptureListener>&) override;
+ binder::Status captureLayersSync(const LayerCaptureArgs&, ScreenCaptureResults* results);
// TODO(b/239076119): Remove deprecated AIDL.
[[deprecated]] binder::Status clearAnimationFrameStats() override {
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
index 6a155c1..7b5298c 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.cpp
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -25,6 +25,7 @@
#include "TransactionCallbackInvoker.h"
#include "BackgroundExecutor.h"
+#include "Utils/FenceUtils.h"
#include <cinttypes>
@@ -127,33 +128,8 @@
sp<IBinder> surfaceControl = handle->surfaceControl.promote();
if (surfaceControl) {
sp<Fence> prevFence = nullptr;
-
for (const auto& future : handle->previousReleaseFences) {
- sp<Fence> currentFence = future.get().value_or(Fence::NO_FENCE);
- if (prevFence == nullptr && currentFence->getStatus() != Fence::Status::Invalid) {
- prevFence = std::move(currentFence);
- } else if (prevFence != nullptr) {
- // If both fences are signaled or both are unsignaled, we need to merge
- // them to get an accurate timestamp.
- if (prevFence->getStatus() != Fence::Status::Invalid &&
- prevFence->getStatus() == currentFence->getStatus()) {
- char fenceName[32] = {};
- snprintf(fenceName, 32, "%.28s", handle->name.c_str());
- sp<Fence> mergedFence = Fence::merge(fenceName, prevFence, currentFence);
- if (mergedFence->isValid()) {
- prevFence = std::move(mergedFence);
- }
- } else if (currentFence->getStatus() == Fence::Status::Unsignaled) {
- // If one fence has signaled and the other hasn't, the unsignaled
- // fence will approximately correspond with the correct timestamp.
- // There's a small race if both fences signal at about the same time
- // and their statuses are retrieved with unfortunate timing. However,
- // by this point, they will have both signaled and only the timestamp
- // will be slightly off; any dependencies after this point will
- // already have been met.
- prevFence = std::move(currentFence);
- }
- }
+ mergeFence(handle->name.c_str(), future.get().value_or(Fence::NO_FENCE), prevFence);
}
handle->previousReleaseFence = prevFence;
handle->previousReleaseFences.clear();
diff --git a/services/surfaceflinger/Utils/FenceUtils.h b/services/surfaceflinger/Utils/FenceUtils.h
new file mode 100644
index 0000000..f6f7006
--- /dev/null
+++ b/services/surfaceflinger/Utils/FenceUtils.h
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ui/Fence.h>
+
+namespace android {
+
+// TODO: measure if Fence::merge is cheaper
+inline void mergeFence(const char* debugName, sp<Fence>&& incomingFence, sp<Fence>& prevFence) {
+ if (prevFence == nullptr && incomingFence->getStatus() != Fence::Status::Invalid) {
+ prevFence = std::move(incomingFence);
+ } else if (prevFence != nullptr) {
+ // If both fences are signaled or both are unsignaled, we need to merge
+ // them to get an accurate timestamp.
+ if (prevFence->getStatus() != Fence::Status::Invalid &&
+ prevFence->getStatus() == incomingFence->getStatus()) {
+ char fenceName[32] = {};
+ snprintf(fenceName, 32, "%.28s", debugName);
+ sp<Fence> mergedFence = Fence::merge(fenceName, prevFence, incomingFence);
+ if (mergedFence->isValid()) {
+ prevFence = std::move(mergedFence);
+ }
+ } else if (incomingFence->getStatus() == Fence::Status::Unsignaled) {
+ // If one fence has signaled and the other hasn't, the unsignaled
+ // fence will approximately correspond with the correct timestamp.
+ // There's a small race if both fences signal at about the same time
+ // and their statuses are retrieved with unfortunate timing. However,
+ // by this point, they will have both signaled and only the timestamp
+ // will be slightly off; any dependencies after this point will
+ // already have been met.
+ prevFence = std::move(incomingFence);
+ }
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index 255b517..b07e7ac 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -128,6 +128,7 @@
DUMP_READ_ONLY_FLAG(fp16_client_target);
DUMP_READ_ONLY_FLAG(game_default_frame_rate);
DUMP_READ_ONLY_FLAG(enable_layer_command_batching);
+ DUMP_READ_ONLY_FLAG(screenshot_fence_preservation);
DUMP_READ_ONLY_FLAG(vulkan_renderengine);
#undef DUMP_READ_ONLY_FLAG
#undef DUMP_SERVER_FLAG
@@ -203,6 +204,7 @@
FLAG_MANAGER_READ_ONLY_FLAG(fp16_client_target, "debug.sf.fp16_client_target")
FLAG_MANAGER_READ_ONLY_FLAG(game_default_frame_rate, "")
FLAG_MANAGER_READ_ONLY_FLAG(enable_layer_command_batching, "")
+FLAG_MANAGER_READ_ONLY_FLAG(screenshot_fence_preservation, "debug.sf.screenshot_fence_preservation")
FLAG_MANAGER_READ_ONLY_FLAG(vulkan_renderengine, "debug.renderengine.vulkan")
/// Trunk stable server flags ///
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 15938c0..2a30a40 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -68,6 +68,7 @@
bool fp16_client_target() const;
bool game_default_frame_rate() const;
bool enable_layer_command_batching() const;
+ bool screenshot_fence_preservation() const;
bool vulkan_renderengine() const;
protected:
diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig
index f097a13..fcbef01 100644
--- a/services/surfaceflinger/surfaceflinger_flags.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags.aconfig
@@ -166,3 +166,11 @@
bug: "293371537"
is_fixed_read_only: true
}
+
+flag {
+ name: "screenshot_fence_preservation"
+ namespace: "core_graphics"
+ description: "Bug fix around screenshot fences"
+ bug: "302703346"
+ is_fixed_read_only: true
+}
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index 1e526ba..c03cbd7 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -1624,6 +1624,7 @@
EXPECT_EQ(120_Hz, actualFrameRateMode.fps);
EXPECT_EQ(kModeId120, actualFrameRateMode.modePtr->getId());
+ // No touch boost, for example a game that uses setFrameRate(30, default compatibility).
lr1.vote = LayerVoteType::ExplicitCategory;
lr1.frameRateCategory = FrameRateCategory::HighHint;
lr1.name = "ExplicitCategory HighHint";
@@ -1652,8 +1653,9 @@
lr2.frameRateCategory = FrameRateCategory::Low;
lr2.name = "ExplicitCategory Low";
actualFrameRateMode = selector.getBestFrameRateMode(layers);
- EXPECT_EQ(30_Hz, actualFrameRateMode.fps);
- EXPECT_EQ(kModeId30, actualFrameRateMode.modePtr->getId());
+ // Gets touch boost
+ EXPECT_EQ(120_Hz, actualFrameRateMode.fps);
+ EXPECT_EQ(kModeId120, actualFrameRateMode.modePtr->getId());
lr1.vote = LayerVoteType::ExplicitCategory;
lr1.frameRateCategory = FrameRateCategory::HighHint;