summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/flatland/GLHelper.cpp2
-rw-r--r--include/powermanager/PowerHalController.h3
-rw-r--r--include/powermanager/PowerHalWrapper.h70
-rw-r--r--include/powermanager/PowerHintSessionWrapper.h2
-rw-r--r--libs/binder/rust/rpcbinder/src/server/trusty.rs4
-rw-r--r--libs/binder/trusty/include/binder/RpcServerTrusty.h9
-rw-r--r--libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp9
-rw-r--r--libs/gui/Android.bp5
-rw-r--r--libs/gui/ISurfaceComposer.cpp121
-rw-r--r--libs/gui/SurfaceComposerClient.cpp330
-rw-r--r--libs/gui/SurfaceControl.cpp4
-rw-r--r--libs/gui/include/gui/ISurfaceComposer.h9
-rw-r--r--libs/gui/include/gui/SurfaceComposerClient.h55
-rw-r--r--libs/gui/include/gui/SurfaceControl.h6
-rw-r--r--libs/gui/tests/Android.bp6
-rw-r--r--libs/gui/tests/BLASTBufferQueue_test.cpp2
-rw-r--r--libs/gui/tests/BufferQueue_test.cpp15
-rw-r--r--libs/gui/tests/DisplayedContentSampling_test.cpp2
-rw-r--r--libs/gui/tests/EndToEndNativeInputTest.cpp2
-rw-r--r--libs/gui/tests/GLTest.cpp2
-rw-r--r--libs/gui/tests/RegionSampling_test.cpp2
-rw-r--r--libs/gui/tests/SamplingDemo.cpp2
-rw-r--r--libs/gui/tests/Surface_test.cpp13
-rw-r--r--libs/renderengine/skia/filters/LutShader.cpp7
-rw-r--r--opengl/tests/lib/WindowSurface.cpp2
-rw-r--r--services/automotive/display/AutomotiveDisplayProxyService.cpp2
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp1
-rw-r--r--services/powermanager/Android.bp1
-rw-r--r--services/powermanager/PowerHalController.cpp15
-rw-r--r--services/powermanager/PowerHalWrapper.cpp18
-rw-r--r--services/powermanager/tests/PowerHalWrapperAidlTest.cpp49
-rw-r--r--services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp5
-rw-r--r--services/surfaceflinger/Display/VirtualDisplaySnapshot.h1
-rw-r--r--services/surfaceflinger/DisplayDevice.cpp11
-rw-r--r--services/surfaceflinger/DisplayDevice.h11
-rw-r--r--services/surfaceflinger/LayerVector.h3
-rw-r--r--services/surfaceflinger/PowerAdvisor/SessionManager.h5
-rw-r--r--services/surfaceflinger/QueuedTransactionState.h42
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp176
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h25
-rw-r--r--services/surfaceflinger/Tracing/TransactionProtoParser.cpp2
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp29
-rw-r--r--services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp30
-rw-r--r--services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h14
-rw-r--r--services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp112
-rw-r--r--services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp2
-rw-r--r--services/vibratorservice/Android.bp5
-rw-r--r--services/vibratorservice/VibratorController.cpp196
-rw-r--r--services/vibratorservice/include/vibratorservice/VibratorController.h118
-rw-r--r--services/vibratorservice/include/vibratorservice/VibratorHalController.h2
-rw-r--r--services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h2
-rw-r--r--services/vibratorservice/test/Android.bp5
-rw-r--r--services/vibratorservice/test/VibratorControllerTest.cpp248
-rw-r--r--vulkan/libvulkan/Android.bp40
-rw-r--r--vulkan/libvulkan/allocator.cpp113
-rw-r--r--vulkan/libvulkan/allocator.h25
-rw-r--r--vulkan/libvulkan/driver.cpp75
-rw-r--r--vulkan/libvulkan/driver.h2
58 files changed, 1661 insertions, 408 deletions
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 6e6d27d463..a2e171fa3b 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -241,7 +241,7 @@ bool GLHelper::createWindowSurface(uint32_t w, uint32_t h,
status_t err;
if (mSurfaceComposerClient == nullptr) {
- mSurfaceComposerClient = new SurfaceComposerClient;
+ mSurfaceComposerClient = sp<SurfaceComposerClient>::make();
}
err = mSurfaceComposerClient->initCheck();
if (err != NO_ERROR) {
diff --git a/include/powermanager/PowerHalController.h b/include/powermanager/PowerHalController.h
index f4f4d5e05c..e22481fceb 100644
--- a/include/powermanager/PowerHalController.h
+++ b/include/powermanager/PowerHalController.h
@@ -73,6 +73,9 @@ public:
int tgid, int uid) override;
virtual HalResult<void> closeSessionChannel(int tgid, int uid) override;
virtual HalResult<aidl::android::hardware::power::SupportInfo> getSupportInfo() override;
+ virtual HalResult<void> sendCompositionData(
+ const std::vector<hal::CompositionData>& data) override;
+ virtual HalResult<void> sendCompositionUpdate(const hal::CompositionUpdate& update) override;
private:
std::mutex mConnectedHalMutex;
diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h
index 42901821bc..17a4cd4eff 100644
--- a/include/powermanager/PowerHalWrapper.h
+++ b/include/powermanager/PowerHalWrapper.h
@@ -18,6 +18,8 @@
#include <aidl/android/hardware/power/Boost.h>
#include <aidl/android/hardware/power/ChannelConfig.h>
+#include <aidl/android/hardware/power/CompositionData.h>
+#include <aidl/android/hardware/power/CompositionUpdate.h>
#include <aidl/android/hardware/power/IPower.h>
#include <aidl/android/hardware/power/IPowerHintSession.h>
#include <aidl/android/hardware/power/Mode.h>
@@ -37,6 +39,8 @@ namespace android {
namespace power {
+namespace hal = aidl::android::hardware::power;
+
// State of Power HAL support for individual apis.
enum class HalSupport {
UNKNOWN = 0,
@@ -49,21 +53,20 @@ class HalWrapper {
public:
virtual ~HalWrapper() = default;
- virtual HalResult<void> setBoost(aidl::android::hardware::power::Boost boost,
- int32_t durationMs) = 0;
- virtual HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) = 0;
+ virtual HalResult<void> setBoost(hal::Boost boost, int32_t durationMs) = 0;
+ virtual HalResult<void> setMode(hal::Mode mode, bool enabled) = 0;
virtual HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSession(
int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
int64_t durationNanos) = 0;
virtual HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSessionWithConfig(
int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos,
- aidl::android::hardware::power::SessionTag tag,
- aidl::android::hardware::power::SessionConfig* config) = 0;
+ hal::SessionTag tag, hal::SessionConfig* config) = 0;
virtual HalResult<int64_t> getHintSessionPreferredRate() = 0;
- virtual HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid,
- int uid) = 0;
+ virtual HalResult<hal::ChannelConfig> getSessionChannel(int tgid, int uid) = 0;
virtual HalResult<void> closeSessionChannel(int tgid, int uid) = 0;
virtual HalResult<aidl::android::hardware::power::SupportInfo> getSupportInfo() = 0;
+ virtual HalResult<void> sendCompositionData(const std::vector<hal::CompositionData>& data) = 0;
+ virtual HalResult<void> sendCompositionUpdate(const hal::CompositionUpdate& update) = 0;
};
// Empty Power HAL wrapper that ignores all api calls.
@@ -72,21 +75,20 @@ public:
EmptyHalWrapper() = default;
~EmptyHalWrapper() override = default;
- HalResult<void> setBoost(aidl::android::hardware::power::Boost boost,
- int32_t durationMs) override;
- HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override;
+ HalResult<void> setBoost(hal::Boost boost, int32_t durationMs) override;
+ HalResult<void> setMode(hal::Mode mode, bool enabled) override;
HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSession(
int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
int64_t durationNanos) override;
HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSessionWithConfig(
int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos,
- aidl::android::hardware::power::SessionTag tag,
- aidl::android::hardware::power::SessionConfig* config) override;
+ hal::SessionTag tag, hal::SessionConfig* config) override;
HalResult<int64_t> getHintSessionPreferredRate() override;
- HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid,
- int uid) override;
+ HalResult<hal::ChannelConfig> getSessionChannel(int tgid, int uid) override;
HalResult<void> closeSessionChannel(int tgid, int uid) override;
HalResult<aidl::android::hardware::power::SupportInfo> getSupportInfo() override;
+ HalResult<void> sendCompositionData(const std::vector<hal::CompositionData>& data) override;
+ HalResult<void> sendCompositionUpdate(const hal::CompositionUpdate& update) override;
protected:
virtual const char* getUnsupportedMessage();
@@ -99,9 +101,8 @@ public:
: mHandleV1_0(std::move(handleV1_0)) {}
~HidlHalWrapperV1_0() override = default;
- HalResult<void> setBoost(aidl::android::hardware::power::Boost boost,
- int32_t durationMs) override;
- HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override;
+ HalResult<void> setBoost(hal::Boost boost, int32_t durationMs) override;
+ HalResult<void> setMode(hal::Mode mode, bool enabled) override;
protected:
const sp<hardware::power::V1_0::IPower> mHandleV1_0;
@@ -127,9 +128,8 @@ protected:
// Wrapper for the HIDL Power HAL v1.2.
class HidlHalWrapperV1_2 : public HidlHalWrapperV1_1 {
public:
- HalResult<void> setBoost(aidl::android::hardware::power::Boost boost,
- int32_t durationMs) override;
- HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override;
+ HalResult<void> setBoost(hal::Boost boost, int32_t durationMs) override;
+ HalResult<void> setMode(hal::Mode mode, bool enabled) override;
explicit HidlHalWrapperV1_2(sp<hardware::power::V1_2::IPower> handleV1_2)
: HidlHalWrapperV1_1(std::move(handleV1_2)) {}
~HidlHalWrapperV1_2() override = default;
@@ -141,7 +141,7 @@ protected:
// Wrapper for the HIDL Power HAL v1.3.
class HidlHalWrapperV1_3 : public HidlHalWrapperV1_2 {
public:
- HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override;
+ HalResult<void> setMode(hal::Mode mode, bool enabled) override;
explicit HidlHalWrapperV1_3(sp<hardware::power::V1_3::IPower> handleV1_3)
: HidlHalWrapperV1_2(std::move(handleV1_3)) {}
~HidlHalWrapperV1_3() override = default;
@@ -153,26 +153,24 @@ protected:
// Wrapper for the AIDL Power HAL.
class AidlHalWrapper : public EmptyHalWrapper {
public:
- explicit AidlHalWrapper(std::shared_ptr<aidl::android::hardware::power::IPower> handle)
- : mHandle(std::move(handle)) {}
+ explicit AidlHalWrapper(std::shared_ptr<hal::IPower> handle) : mHandle(std::move(handle)) {}
~AidlHalWrapper() override = default;
- HalResult<void> setBoost(aidl::android::hardware::power::Boost boost,
- int32_t durationMs) override;
- HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override;
+ HalResult<void> setBoost(hal::Boost boost, int32_t durationMs) override;
+ HalResult<void> setMode(hal::Mode mode, bool enabled) override;
HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSession(
int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
int64_t durationNanos) override;
HalResult<std::shared_ptr<PowerHintSessionWrapper>> createHintSessionWithConfig(
int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos,
- aidl::android::hardware::power::SessionTag tag,
- aidl::android::hardware::power::SessionConfig* config) override;
+ hal::SessionTag tag, hal::SessionConfig* config) override;
HalResult<int64_t> getHintSessionPreferredRate() override;
- HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid,
- int uid) override;
+ HalResult<hal::ChannelConfig> getSessionChannel(int tgid, int uid) override;
HalResult<void> closeSessionChannel(int tgid, int uid) override;
HalResult<aidl::android::hardware::power::SupportInfo> getSupportInfo() override;
+ HalResult<void> sendCompositionData(const std::vector<hal::CompositionData>& data) override;
+ HalResult<void> sendCompositionUpdate(const hal::CompositionUpdate& update) override;
protected:
const char* getUnsupportedMessage() override;
@@ -181,16 +179,10 @@ private:
// Control access to the boost and mode supported arrays.
std::mutex mBoostMutex;
std::mutex mModeMutex;
- std::shared_ptr<aidl::android::hardware::power::IPower> mHandle;
- std::array<HalSupport,
- static_cast<int32_t>(
- *(ndk::enum_range<aidl::android::hardware::power::Boost>().end() - 1)) +
- 1>
+ std::shared_ptr<hal::IPower> mHandle;
+ std::array<HalSupport, static_cast<int32_t>(*(ndk::enum_range<hal::Boost>().end() - 1)) + 1>
mBoostSupportedArray GUARDED_BY(mBoostMutex) = {HalSupport::UNKNOWN};
- std::array<HalSupport,
- static_cast<int32_t>(
- *(ndk::enum_range<aidl::android::hardware::power::Mode>().end() - 1)) +
- 1>
+ std::array<HalSupport, static_cast<int32_t>(*(ndk::enum_range<hal::Mode>().end() - 1)) + 1>
mModeSupportedArray GUARDED_BY(mModeMutex) = {HalSupport::UNKNOWN};
};
diff --git a/include/powermanager/PowerHintSessionWrapper.h b/include/powermanager/PowerHintSessionWrapper.h
index ba6fe77c80..0134e02f12 100644
--- a/include/powermanager/PowerHintSessionWrapper.h
+++ b/include/powermanager/PowerHintSessionWrapper.h
@@ -45,9 +45,11 @@ public:
virtual HalResult<void> setMode(::aidl::android::hardware::power::SessionMode in_type,
bool in_enabled);
virtual HalResult<aidl::android::hardware::power::SessionConfig> getSessionConfig();
+ std::optional<int> getSessionId();
private:
std::shared_ptr<aidl::android::hardware::power::IPowerHintSession> mSession;
+ std::optional<int> mSessionId;
int32_t mInterfaceVersion;
};
diff --git a/libs/binder/rust/rpcbinder/src/server/trusty.rs b/libs/binder/rust/rpcbinder/src/server/trusty.rs
index fe45decf25..54d82d5bd0 100644
--- a/libs/binder/rust/rpcbinder/src/server/trusty.rs
+++ b/libs/binder/rust/rpcbinder/src/server/trusty.rs
@@ -106,6 +106,10 @@ pub struct RpcServerConnection {
ctx: *mut c_void,
}
+// SAFETY: The opaque handle: `ctx` points into a dynamic allocation,
+// and not tied to anything specific to the current thread.
+unsafe impl Send for RpcServerConnection {}
+
impl Drop for RpcServerConnection {
fn drop(&mut self) {
// We do not need to close handle_fd since we do not own it.
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
index 127676bf9a..1ac00ca13f 100644
--- a/libs/binder/trusty/include/binder/RpcServerTrusty.h
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -97,6 +97,15 @@ private:
// By default we use the latest stable version.
LOG_ALWAYS_FATAL_IF(!rpcServer->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION));
+ // The default behavior in trusty is to allow handles to be passed with tipc IPC.
+ // We add mode NONE so that servers do not reject connections from clients who do
+ // not change their default transport mode.
+ static const std::vector<RpcSession::FileDescriptorTransportMode>
+ TRUSTY_SERVER_SUPPORTED_FD_MODES = {RpcSession::FileDescriptorTransportMode::TRUSTY,
+ RpcSession::FileDescriptorTransportMode::NONE};
+
+ rpcServer->setSupportedFileDescriptorTransportModes(TRUSTY_SERVER_SUPPORTED_FD_MODES);
+
return rpcServer;
}
diff --git a/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp
index 12e347e4f3..451383a90a 100644
--- a/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp
+++ b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp
@@ -27,13 +27,6 @@ using android::RpcTransportCtxFactoryTipcTrusty;
using android::sp;
using android::wp;
-// The default behavior in trusty is to allow handles to be passed with tipc IPC.
-// We add mode NONE so that servers do not reject connections from clients who do
-// not change their default transport mode.
-static const std::vector<RpcSession::FileDescriptorTransportMode> TRUSTY_SERVER_SUPPORTED_FD_MODES =
- {RpcSession::FileDescriptorTransportMode::TRUSTY,
- RpcSession::FileDescriptorTransportMode::NONE};
-
struct ARpcServerTrusty {
sp<RpcServer> mRpcServer;
@@ -60,8 +53,6 @@ ARpcServerTrusty* ARpcServerTrusty_newPerSession(AIBinder* (*cb)(const void*, si
return nullptr;
}
- rpcServer->setSupportedFileDescriptorTransportModes(TRUSTY_SERVER_SUPPORTED_FD_MODES);
-
rpcServer->setPerSessionRootObject(
[cb, cbArgSp](wp<RpcSession> /*session*/, const void* addrPtr, size_t len) {
auto* aib = (*cb)(addrPtr, len, cbArgSp.get());
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index b5fa321fc2..158c54886d 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -295,7 +295,6 @@ filegroup {
cc_defaults {
name: "libgui-defaults",
defaults: ["libgui_bufferqueue-defaults"],
- srcs: [":libgui-sources"],
static_libs: [
"libgui_aidl_static",
"libgui_window_info_static",
@@ -319,6 +318,10 @@ cc_library_shared {
"libgui-defaults",
],
+ srcs: [
+ ":libgui-sources",
+ ],
+
export_static_lib_headers: [
"libgui_aidl_static",
"libgui_window_info_static",
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index ae4b74e03b..269936858a 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -26,7 +26,6 @@
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <gui/SchedulingPolicy.h>
-#include <gui/TransactionState.h>
#include <private/gui/ParcelUtils.h>
#include <stdint.h>
#include <sys/types.h>
@@ -61,12 +60,54 @@ public:
virtual ~BpSurfaceComposer();
- status_t setTransactionState(TransactionState&& state) override {
+ status_t setTransactionState(
+ const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state,
+ Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ InputWindowCommands commands, int64_t desiredPresentTime, bool isAutoTimestamp,
+ const std::vector<client_cache_t>& uncacheBuffers, bool hasListenerCallbacks,
+ const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId,
+ const std::vector<uint64_t>& mergedTransactionIds) override {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- SAFE_PARCEL(state.writeToParcel, &data);
- if (state.mFlags & ISurfaceComposer::eOneWay) {
+ frameTimelineInfo.writeToParcel(&data);
+
+ SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(state.size()));
+ for (const auto& s : state) {
+ SAFE_PARCEL(s.write, data);
+ }
+
+ SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(displays.size()));
+ for (const auto& d : displays) {
+ SAFE_PARCEL(d.write, data);
+ }
+
+ SAFE_PARCEL(data.writeUint32, flags);
+ SAFE_PARCEL(data.writeStrongBinder, applyToken);
+ SAFE_PARCEL(commands.write, data);
+ SAFE_PARCEL(data.writeInt64, desiredPresentTime);
+ SAFE_PARCEL(data.writeBool, isAutoTimestamp);
+ SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(uncacheBuffers.size()));
+ for (const client_cache_t& uncacheBuffer : uncacheBuffers) {
+ SAFE_PARCEL(data.writeStrongBinder, uncacheBuffer.token.promote());
+ SAFE_PARCEL(data.writeUint64, uncacheBuffer.id);
+ }
+ SAFE_PARCEL(data.writeBool, hasListenerCallbacks);
+
+ SAFE_PARCEL(data.writeVectorSize, listenerCallbacks);
+ for (const auto& [listener, callbackIds] : listenerCallbacks) {
+ SAFE_PARCEL(data.writeStrongBinder, listener);
+ SAFE_PARCEL(data.writeParcelableVector, callbackIds);
+ }
+
+ SAFE_PARCEL(data.writeUint64, transactionId);
+
+ SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(mergedTransactionIds.size()));
+ for (auto mergedTransactionId : mergedTransactionIds) {
+ SAFE_PARCEL(data.writeUint64, mergedTransactionId);
+ }
+
+ if (flags & ISurfaceComposer::eOneWay) {
return remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE,
data, &reply, IBinder::FLAG_ONEWAY);
} else {
@@ -91,9 +132,75 @@ status_t BnSurfaceComposer::onTransact(
case SET_TRANSACTION_STATE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- TransactionState state;
- SAFE_PARCEL(state.readFromParcel, &data);
- return setTransactionState(std::move(state));
+ FrameTimelineInfo frameTimelineInfo;
+ frameTimelineInfo.readFromParcel(&data);
+
+ uint32_t count = 0;
+ SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize());
+ Vector<ComposerState> state;
+ state.setCapacity(count);
+ for (size_t i = 0; i < count; i++) {
+ ComposerState s;
+ SAFE_PARCEL(s.read, data);
+ state.add(s);
+ }
+
+ SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize());
+ DisplayState d;
+ Vector<DisplayState> displays;
+ displays.setCapacity(count);
+ for (size_t i = 0; i < count; i++) {
+ SAFE_PARCEL(d.read, data);
+ displays.add(d);
+ }
+
+ uint32_t stateFlags = 0;
+ SAFE_PARCEL(data.readUint32, &stateFlags);
+ sp<IBinder> applyToken;
+ SAFE_PARCEL(data.readStrongBinder, &applyToken);
+ InputWindowCommands inputWindowCommands;
+ SAFE_PARCEL(inputWindowCommands.read, data);
+
+ int64_t desiredPresentTime = 0;
+ bool isAutoTimestamp = true;
+ SAFE_PARCEL(data.readInt64, &desiredPresentTime);
+ SAFE_PARCEL(data.readBool, &isAutoTimestamp);
+
+ SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize());
+ std::vector<client_cache_t> uncacheBuffers(count);
+ sp<IBinder> tmpBinder;
+ for (size_t i = 0; i < count; i++) {
+ SAFE_PARCEL(data.readNullableStrongBinder, &tmpBinder);
+ uncacheBuffers[i].token = tmpBinder;
+ SAFE_PARCEL(data.readUint64, &uncacheBuffers[i].id);
+ }
+
+ bool hasListenerCallbacks = false;
+ SAFE_PARCEL(data.readBool, &hasListenerCallbacks);
+
+ std::vector<ListenerCallbacks> listenerCallbacks;
+ int32_t listenersSize = 0;
+ SAFE_PARCEL_READ_SIZE(data.readInt32, &listenersSize, data.dataSize());
+ for (int32_t i = 0; i < listenersSize; i++) {
+ SAFE_PARCEL(data.readStrongBinder, &tmpBinder);
+ std::vector<CallbackId> callbackIds;
+ SAFE_PARCEL(data.readParcelableVector, &callbackIds);
+ listenerCallbacks.emplace_back(tmpBinder, callbackIds);
+ }
+
+ uint64_t transactionId = -1;
+ SAFE_PARCEL(data.readUint64, &transactionId);
+
+ SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize());
+ std::vector<uint64_t> mergedTransactions(count);
+ for (size_t i = 0; i < count; i++) {
+ SAFE_PARCEL(data.readUint64, &mergedTransactions[i]);
+ }
+
+ return setTransactionState(frameTimelineInfo, state, displays, stateFlags, applyToken,
+ std::move(inputWindowCommands), desiredPresentTime,
+ isAutoTimestamp, uncacheBuffers, hasListenerCallbacks,
+ listenerCallbacks, transactionId, mergedTransactions);
}
case GET_SCHEDULING_POLICY: {
gui::SchedulingPolicy policy;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index b0650d56ff..9854274cb1 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -824,25 +824,34 @@ void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId) {
// ---------------------------------------------------------------------------
SurfaceComposerClient::Transaction::Transaction() {
- mState.mId = generateId();
+ mId = generateId();
mTransactionCompletedListener = TransactionCompletedListener::getInstance();
}
-SurfaceComposerClient::Transaction::Transaction(const Transaction& other) {
- mState = other.mState;
+SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
+ : mId(other.mId),
+ mFlags(other.mFlags),
+ mMayContainBuffer(other.mMayContainBuffer),
+ mDesiredPresentTime(other.mDesiredPresentTime),
+ mIsAutoTimestamp(other.mIsAutoTimestamp),
+ mFrameTimelineInfo(other.mFrameTimelineInfo),
+ mApplyToken(other.mApplyToken) {
+ mDisplayStates = other.mDisplayStates;
+ mComposerStates = other.mComposerStates;
+ mInputWindowCommands = other.mInputWindowCommands;
mListenerCallbacks = other.mListenerCallbacks;
mTransactionCompletedListener = TransactionCompletedListener::getInstance();
}
void SurfaceComposerClient::Transaction::sanitize(int pid, int uid) {
uint32_t permissions = LayerStatePermissions::getTransactionPermissions(pid, uid);
- for (auto& composerState : mState.mComposerStates) {
+ for (auto& composerState : mComposerStates) {
composerState.state.sanitize(permissions);
}
- if (!mState.mInputWindowCommands.empty() &&
+ if (!mInputWindowCommands.empty() &&
(permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER) == 0) {
ALOGE("Only privileged callers are allowed to send input commands.");
- mState.mInputWindowCommands.clear();
+ mInputWindowCommands.clear();
}
}
@@ -857,13 +866,34 @@ SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) {
status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) {
- TransactionState tmpState;
- SAFE_PARCEL(tmpState.readFromParcel, parcel);
-
+ const uint64_t transactionId = parcel->readUint64();
+ const uint32_t flags = parcel->readUint32();
+ const int64_t desiredPresentTime = parcel->readInt64();
+ const bool isAutoTimestamp = parcel->readBool();
+ const bool logCallPoints = parcel->readBool();
+ FrameTimelineInfo frameTimelineInfo;
+ frameTimelineInfo.readFromParcel(parcel);
+
+ sp<IBinder> applyToken;
+ parcel->readNullableStrongBinder(&applyToken);
size_t count = static_cast<size_t>(parcel->readUint32());
if (count > parcel->dataSize()) {
return BAD_VALUE;
}
+ Vector<DisplayState> displayStates;
+ displayStates.setCapacity(count);
+ for (size_t i = 0; i < count; i++) {
+ DisplayState displayState;
+ if (displayState.read(*parcel) == BAD_VALUE) {
+ return BAD_VALUE;
+ }
+ displayStates.add(displayState);
+ }
+
+ count = static_cast<size_t>(parcel->readUint32());
+ if (count > parcel->dataSize()) {
+ return BAD_VALUE;
+ }
std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash> listenerCallbacks;
listenerCallbacks.reserve(count);
for (size_t i = 0; i < count; i++) {
@@ -889,8 +919,57 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel
}
}
- mState = std::move(tmpState);
- mListenerCallbacks = std::move(listenerCallbacks);
+ count = static_cast<size_t>(parcel->readUint32());
+ if (count > parcel->dataSize()) {
+ return BAD_VALUE;
+ }
+ Vector<ComposerState> composerStates;
+ composerStates.setCapacity(count);
+ for (size_t i = 0; i < count; i++) {
+ ComposerState composerState;
+ if (composerState.read(*parcel) == BAD_VALUE) {
+ return BAD_VALUE;
+ }
+ composerStates.add(composerState);
+ }
+
+ InputWindowCommands inputWindowCommands;
+ inputWindowCommands.read(*parcel);
+
+ count = static_cast<size_t>(parcel->readUint32());
+ if (count > parcel->dataSize()) {
+ return BAD_VALUE;
+ }
+ std::vector<client_cache_t> uncacheBuffers(count);
+ for (size_t i = 0; i < count; i++) {
+ sp<IBinder> tmpBinder;
+ SAFE_PARCEL(parcel->readStrongBinder, &tmpBinder);
+ uncacheBuffers[i].token = tmpBinder;
+ SAFE_PARCEL(parcel->readUint64, &uncacheBuffers[i].id);
+ }
+
+ count = static_cast<size_t>(parcel->readUint32());
+ if (count > parcel->dataSize()) {
+ return BAD_VALUE;
+ }
+ std::vector<uint64_t> mergedTransactionIds(count);
+ for (size_t i = 0; i < count; i++) {
+ SAFE_PARCEL(parcel->readUint64, &mergedTransactionIds[i]);
+ }
+
+ // Parsing was successful. Update the object.
+ mId = transactionId;
+ mFlags = flags;
+ mDesiredPresentTime = desiredPresentTime;
+ mIsAutoTimestamp = isAutoTimestamp;
+ mFrameTimelineInfo = frameTimelineInfo;
+ mDisplayStates = std::move(displayStates);
+ mListenerCallbacks = listenerCallbacks;
+ mComposerStates = std::move(composerStates);
+ mInputWindowCommands = inputWindowCommands;
+ mApplyToken = applyToken;
+ mUncacheBuffers = std::move(uncacheBuffers);
+ mMergedTransactionIds = std::move(mergedTransactionIds);
return NO_ERROR;
}
@@ -908,7 +987,17 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const
const_cast<SurfaceComposerClient::Transaction*>(this)->cacheBuffers();
- SAFE_PARCEL(mState.writeToParcel, parcel);
+ parcel->writeUint64(mId);
+ parcel->writeUint32(mFlags);
+ parcel->writeInt64(mDesiredPresentTime);
+ parcel->writeBool(mIsAutoTimestamp);
+ parcel->writeBool(mLogCallPoints);
+ mFrameTimelineInfo.writeToParcel(parcel);
+ parcel->writeStrongBinder(mApplyToken);
+ parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size()));
+ for (auto const& displayState : mDisplayStates) {
+ displayState.write(*parcel);
+ }
parcel->writeUint32(static_cast<uint32_t>(mListenerCallbacks.size()));
for (auto const& [listener, callbackInfo] : mListenerCallbacks) {
@@ -923,6 +1012,24 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const
}
}
+ parcel->writeUint32(static_cast<uint32_t>(mComposerStates.size()));
+ for (auto const& composerState : mComposerStates) {
+ composerState.write(*parcel);
+ }
+
+ mInputWindowCommands.write(*parcel);
+
+ SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mUncacheBuffers.size()));
+ for (const client_cache_t& uncacheBuffer : mUncacheBuffers) {
+ SAFE_PARCEL(parcel->writeStrongBinder, uncacheBuffer.token.promote());
+ SAFE_PARCEL(parcel->writeUint64, uncacheBuffer.id);
+ }
+
+ SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mMergedTransactionIds.size()));
+ for (auto mergedTransactionId : mMergedTransactionIds) {
+ SAFE_PARCEL(parcel->writeUint64, mergedTransactionId);
+ }
+
return NO_ERROR;
}
@@ -947,8 +1054,50 @@ void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
- mState.merge(std::move(other.mState),
- std::bind(&Transaction::releaseBufferIfOverwriting, this, std::placeholders::_1));
+ while (mMergedTransactionIds.size() + other.mMergedTransactionIds.size() >
+ MAX_MERGE_HISTORY_LENGTH - 1 &&
+ mMergedTransactionIds.size() > 0) {
+ mMergedTransactionIds.pop_back();
+ }
+ if (other.mMergedTransactionIds.size() == MAX_MERGE_HISTORY_LENGTH) {
+ mMergedTransactionIds.insert(mMergedTransactionIds.begin(),
+ other.mMergedTransactionIds.begin(),
+ other.mMergedTransactionIds.end() - 1);
+ } else if (other.mMergedTransactionIds.size() > 0u) {
+ mMergedTransactionIds.insert(mMergedTransactionIds.begin(),
+ other.mMergedTransactionIds.begin(),
+ other.mMergedTransactionIds.end());
+ }
+ mMergedTransactionIds.insert(mMergedTransactionIds.begin(), other.mId);
+
+ for (auto const& otherState : other.mComposerStates) {
+ if (auto it = std::find_if(mComposerStates.begin(), mComposerStates.end(),
+ [&otherState](const auto& composerState) {
+ return composerState.state.surface ==
+ otherState.state.surface;
+ });
+ it != mComposerStates.end()) {
+ if (otherState.state.what & layer_state_t::eBufferChanged) {
+ releaseBufferIfOverwriting(it->state);
+ }
+ it->state.merge(otherState.state);
+ } else {
+ mComposerStates.add(otherState);
+ }
+ }
+
+ for (auto const& state : other.mDisplayStates) {
+ if (auto it = std::find_if(mDisplayStates.begin(), mDisplayStates.end(),
+ [&state](const auto& displayState) {
+ return displayState.token == state.token;
+ });
+ it != mDisplayStates.end()) {
+ it->merge(state);
+ } else {
+ mDisplayStates.add(state);
+ }
+ }
+
for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) {
auto& [callbackIds, surfaceControls] = callbackInfo;
mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator(
@@ -972,21 +1121,50 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr
}
}
+ for (const auto& cacheId : other.mUncacheBuffers) {
+ mUncacheBuffers.push_back(cacheId);
+ }
+
+ mInputWindowCommands.merge(other.mInputWindowCommands);
+
+ mMayContainBuffer |= other.mMayContainBuffer;
+ mFlags |= other.mFlags;
+ mApplyToken = other.mApplyToken;
+
+ mergeFrameTimelineInfo(mFrameTimelineInfo, other.mFrameTimelineInfo);
+
+ mLogCallPoints |= other.mLogCallPoints;
+ if (mLogCallPoints) {
+ ALOG(LOG_DEBUG, LOG_SURFACE_CONTROL_REGISTRY,
+ "Transaction %" PRIu64 " merged with transaction %" PRIu64, other.getId(), mId);
+ }
+
other.clear();
return *this;
}
void SurfaceComposerClient::Transaction::clear() {
- mState.clear();
+ mComposerStates.clear();
+ mDisplayStates.clear();
mListenerCallbacks.clear();
+ mInputWindowCommands.clear();
+ mUncacheBuffers.clear();
+ mMayContainBuffer = false;
+ mDesiredPresentTime = 0;
+ mIsAutoTimestamp = true;
+ mFrameTimelineInfo = {};
+ mApplyToken = nullptr;
+ mMergedTransactionIds.clear();
+ mLogCallPoints = false;
+ mFlags = 0;
}
-uint64_t SurfaceComposerClient::Transaction::getId() const {
- return mState.mId;
+uint64_t SurfaceComposerClient::Transaction::getId() {
+ return mId;
}
std::vector<uint64_t> SurfaceComposerClient::Transaction::getMergedTransactionIds() {
- return mState.mMergedTransactionIds;
+ return mMergedTransactionIds;
}
void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
@@ -995,13 +1173,12 @@ void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
client_cache_t uncacheBuffer;
uncacheBuffer.token = BufferCache::getInstance().getToken();
uncacheBuffer.id = cacheId;
- TransactionState state;
- state.mId = generateId();
- state.mApplyToken = Transaction::getDefaultApplyToken();
- state.mUncacheBuffers.emplace_back(std::move(uncacheBuffer));
- state.mFlags = ISurfaceComposer::eOneWay;
- state.mDesiredPresentTime = systemTime();
- status_t status = sf->setTransactionState(std::move(state));
+ Vector<ComposerState> composerStates;
+ Vector<DisplayState> displayStates;
+ status_t status = sf->setTransactionState(FrameTimelineInfo{}, composerStates, displayStates,
+ ISurfaceComposer::eOneWay,
+ Transaction::getDefaultApplyToken(), {}, systemTime(),
+ true, {uncacheBuffer}, false, {}, generateId(), {});
if (status != NO_ERROR) {
ALOGE_AND_TRACE("SurfaceComposerClient::doUncacheBufferTransaction - %s",
strerror(-status));
@@ -1009,12 +1186,12 @@ void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
}
void SurfaceComposerClient::Transaction::cacheBuffers() {
- if (!mState.mMayContainBuffer) {
+ if (!mMayContainBuffer) {
return;
}
size_t count = 0;
- for (auto& cs : mState.mComposerStates) {
+ for (auto& cs : mComposerStates) {
layer_state_t* s = &cs.state;
if (!(s->what & layer_state_t::eBufferChanged)) {
continue;
@@ -1042,7 +1219,7 @@ void SurfaceComposerClient::Transaction::cacheBuffers() {
std::optional<client_cache_t> uncacheBuffer;
cacheId = BufferCache::getInstance().cache(s->bufferData->buffer, uncacheBuffer);
if (uncacheBuffer) {
- mState.mUncacheBuffers.emplace_back(*uncacheBuffer);
+ mUncacheBuffers.push_back(*uncacheBuffer);
}
}
s->bufferData->flags |= BufferData::BufferDataChange::cachedBufferChanged;
@@ -1111,7 +1288,8 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay
/*callbackContext=*/nullptr);
}
- mState.mHasListenerCallbacks = !mListenerCallbacks.empty();
+ bool hasListenerCallbacks = !mListenerCallbacks.empty();
+ std::vector<ListenerCallbacks> listenerCallbacks;
// For every listener with registered callbacks
for (const auto& [listener, callbackInfo] : mListenerCallbacks) {
auto& [callbackIds, surfaceControls] = callbackInfo;
@@ -1120,8 +1298,7 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay
}
if (surfaceControls.empty()) {
- mState.mListenerCallbacks.emplace_back(IInterface::asBinder(listener),
- std::move(callbackIds));
+ listenerCallbacks.emplace_back(IInterface::asBinder(listener), std::move(callbackIds));
} else {
// If the listener has any SurfaceControls set on this Transaction update the surface
// state
@@ -1133,7 +1310,7 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay
}
std::vector<CallbackId> callbacks(callbackIds.begin(), callbackIds.end());
s->what |= layer_state_t::eHasListenerCallbacksChanged;
- s->listeners.emplace_back(IInterface::asBinder(listener), std::move(callbacks));
+ s->listeners.emplace_back(IInterface::asBinder(listener), callbacks);
}
}
}
@@ -1145,21 +1322,25 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay
ALOGE("Transaction attempted to set synchronous and one way at the same time"
" this is an invalid request. Synchronous will win for safety");
} else {
- mState.mFlags |= ISurfaceComposer::eOneWay;
+ mFlags |= ISurfaceComposer::eOneWay;
}
}
// If both ISurfaceComposer::eEarlyWakeupStart and ISurfaceComposer::eEarlyWakeupEnd are set
// it is equivalent for none
uint32_t wakeupFlags = ISurfaceComposer::eEarlyWakeupStart | ISurfaceComposer::eEarlyWakeupEnd;
- if ((mState.mFlags & wakeupFlags) == wakeupFlags) {
- mState.mFlags &= ~(wakeupFlags);
+ if ((mFlags & wakeupFlags) == wakeupFlags) {
+ mFlags &= ~(wakeupFlags);
}
- if (!mState.mApplyToken) mState.mApplyToken = getDefaultApplyToken();
+ sp<IBinder> applyToken = mApplyToken ? mApplyToken : getDefaultApplyToken();
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- status_t binderStatus = sf->setTransactionState(std::move(mState));
- mState.mId = generateId();
+ status_t binderStatus =
+ sf->setTransactionState(mFrameTimelineInfo, mComposerStates, mDisplayStates, mFlags,
+ applyToken, mInputWindowCommands, mDesiredPresentTime,
+ mIsAutoTimestamp, mUncacheBuffers, hasListenerCallbacks,
+ listenerCallbacks, mId, mMergedTransactionIds);
+ mId = generateId();
// Clear the current states and flags
clear();
@@ -1168,8 +1349,8 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay
syncCallback->wait();
}
- if (mState.mLogCallPoints) {
- ALOG(LOG_DEBUG, LOG_SURFACE_CONTROL_REGISTRY, "Transaction %" PRIu64 " applied", getId());
+ if (mLogCallPoints) {
+ ALOG(LOG_DEBUG, LOG_SURFACE_CONTROL_REGISTRY, "Transaction %" PRIu64 " applied", mId);
}
mStatus = NO_ERROR;
@@ -1204,7 +1385,7 @@ status_t SurfaceComposerClient::Transaction::sendSurfaceFlushJankDataTransaction
}
void SurfaceComposerClient::Transaction::enableDebugLogCallPoints() {
- mState.mLogCallPoints = true;
+ mLogCallPoints = true;
}
// ---------------------------------------------------------------------------
@@ -1262,19 +1443,34 @@ std::optional<gui::StalledTransactionInfo> SurfaceComposerClient::getStalledTran
}
void SurfaceComposerClient::Transaction::setAnimationTransaction() {
- mState.mFlags |= ISurfaceComposer::eAnimation;
+ mFlags |= ISurfaceComposer::eAnimation;
}
void SurfaceComposerClient::Transaction::setEarlyWakeupStart() {
- mState.mFlags |= ISurfaceComposer::eEarlyWakeupStart;
+ mFlags |= ISurfaceComposer::eEarlyWakeupStart;
}
void SurfaceComposerClient::Transaction::setEarlyWakeupEnd() {
- mState.mFlags |= ISurfaceComposer::eEarlyWakeupEnd;
+ mFlags |= ISurfaceComposer::eEarlyWakeupEnd;
}
layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
- return mState.getLayerState(sc);
+ auto handle = sc->getLayerStateHandle();
+ if (auto it = std::find_if(mComposerStates.begin(), mComposerStates.end(),
+ [&handle](const auto& composerState) {
+ return composerState.state.surface == handle;
+ });
+ it != mComposerStates.end()) {
+ return &it->state;
+ }
+
+ // we don't have it, add an initialized layer_state to our list
+ ComposerState s;
+ s.state.surface = handle;
+ s.state.layerId = sc->getLayerId();
+ mComposerStates.add(s);
+
+ return &mComposerStates.editItemAt(mComposerStates.size() - 1).state;
}
void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback(
@@ -1650,8 +1846,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe
setReleaseBufferCallback(bufferData.get(), callback);
}
- if (mState.mIsAutoTimestamp) {
- mState.mDesiredPresentTime = systemTime();
+ if (mIsAutoTimestamp) {
+ mDesiredPresentTime = systemTime();
}
s->what |= layer_state_t::eBufferChanged;
s->bufferData = std::move(bufferData);
@@ -1669,7 +1865,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe
const std::vector<SurfaceControlStats>&) {},
nullptr);
- mState.mMayContainBuffer = true;
+ mMayContainBuffer = true;
return *this;
}
@@ -1845,8 +2041,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSideb
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesiredPresentTime(
nsecs_t desiredPresentTime) {
- mState.mDesiredPresentTime = desiredPresentTime;
- mState.mIsAutoTimestamp = false;
+ mDesiredPresentTime = desiredPresentTime;
+ mIsAutoTimestamp = false;
return *this;
}
@@ -1935,14 +2131,14 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInput
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFocusedWindow(
const FocusRequest& request) {
- mState.mInputWindowCommands.addFocusRequest(request);
+ mInputWindowCommands.addFocusRequest(request);
return *this;
}
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addWindowInfosReportedListener(
sp<gui::IWindowInfosReportedListener> windowInfosReportedListener) {
- mState.mInputWindowCommands.addWindowInfosReportedListener(windowInfosReportedListener);
+ mInputWindowCommands.addWindowInfosReportedListener(windowInfosReportedListener);
return *this;
}
@@ -2106,7 +2302,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixed
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo(
const FrameTimelineInfo& frameTimelineInfo) {
- mState.mergeFrameTimelineInfo(frameTimelineInfo);
+ mergeFrameTimelineInfo(mFrameTimelineInfo, frameTimelineInfo);
return *this;
}
@@ -2145,7 +2341,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrust
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApplyToken(
const sp<IBinder>& applyToken) {
- mState.mApplyToken = applyToken;
+ mApplyToken = applyToken;
return *this;
}
@@ -2273,7 +2469,17 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setConte
// ---------------------------------------------------------------------------
DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
- return mState.getDisplayState(token);
+ if (auto it = std::find_if(mDisplayStates.begin(), mDisplayStates.end(),
+ [token](const auto& display) { return display.token == token; });
+ it != mDisplayStates.end()) {
+ return *it;
+ }
+
+ // If display state doesn't exist, add a new one.
+ DisplayState s;
+ s.token = token;
+ mDisplayStates.add(s);
+ return mDisplayStates.editItemAt(mDisplayStates.size() - 1);
}
status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder>& token,
@@ -2326,6 +2532,20 @@ void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token
s.what |= DisplayState::eDisplaySizeChanged;
}
+// copied from FrameTimelineInfo::merge()
+void SurfaceComposerClient::Transaction::mergeFrameTimelineInfo(FrameTimelineInfo& t,
+ const FrameTimelineInfo& other) {
+ // When merging vsync Ids we take the oldest valid one
+ if (t.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID &&
+ other.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
+ if (other.vsyncId > t.vsyncId) {
+ t = other;
+ }
+ } else if (t.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) {
+ t = other;
+ }
+}
+
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::setTrustedPresentationCallback(
const sp<SurfaceControl>& sc, TrustedPresentationCallback cb,
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 1eb9b87c3c..50877f8c56 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -194,7 +194,7 @@ const std::string& SurfaceControl::getName() const {
return mName;
}
-std::shared_ptr<Choreographer> SurfaceControl::getChoreographer() {
+sp<Choreographer> SurfaceControl::getChoreographer() {
if (mChoreographer) {
return mChoreographer;
}
@@ -203,7 +203,7 @@ std::shared_ptr<Choreographer> SurfaceControl::getChoreographer() {
ALOGE("%s: No looper prepared for thread", __func__);
return nullptr;
}
- mChoreographer = std::make_shared<Choreographer>(looper, getHandle());
+ mChoreographer = sp<Choreographer>::make(looper, getHandle());
status_t result = mChoreographer->initialize();
if (result != OK) {
ALOGE("Failed to initialize choreographer");
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index de553aef72..9a422fd808 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -65,7 +65,6 @@ struct DisplayState;
struct InputWindowCommands;
class HdrCapabilities;
class Rect;
-class TransactionState;
using gui::FrameTimelineInfo;
using gui::IDisplayEventConnection;
@@ -106,7 +105,13 @@ public:
};
/* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
- virtual status_t setTransactionState(TransactionState&& state) = 0;
+ virtual status_t setTransactionState(
+ const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state,
+ Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ InputWindowCommands inputWindowCommands, int64_t desiredPresentTime,
+ bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffer,
+ bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
+ uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 15e3341ca2..4fda8deb9c 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -52,7 +52,6 @@
#include <gui/ITransactionCompletedListener.h>
#include <gui/LayerState.h>
#include <gui/SurfaceControl.h>
-#include <gui/TransactionState.h>
#include <gui/WindowInfosListenerReporter.h>
#include <math/vec3.h>
@@ -448,11 +447,56 @@ public:
static sp<IBinder> sApplyToken;
static std::mutex sApplyTokenMutex;
void releaseBufferIfOverwriting(const layer_state_t& state);
+ static void mergeFrameTimelineInfo(FrameTimelineInfo& t, const FrameTimelineInfo& other);
// Tracks registered callbacks
sp<TransactionCompletedListener> mTransactionCompletedListener = nullptr;
+ // Prints debug logs when enabled.
+ bool mLogCallPoints = false;
- TransactionState mState;
+ protected:
+ Vector<ComposerState> mComposerStates;
+ Vector<DisplayState> mDisplayStates;
+ std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
+ mListenerCallbacks;
+ std::vector<client_cache_t> mUncacheBuffers;
+
+ // We keep track of the last MAX_MERGE_HISTORY_LENGTH merged transaction ids.
+ // Ordered most recently merged to least recently merged.
+ static const size_t MAX_MERGE_HISTORY_LENGTH = 10u;
+ std::vector<uint64_t> mMergedTransactionIds;
+
+ uint64_t mId;
+ uint32_t mFlags = 0;
+
+ // Indicates that the Transaction may contain buffers that should be cached. The reason this
+ // is only a guess is that buffers can be removed before cache is called. This is only a
+ // hint that at some point a buffer was added to this transaction before apply was called.
+ bool mMayContainBuffer = false;
+
+ // mDesiredPresentTime is the time in nanoseconds that the client would like the transaction
+ // to be presented. When it is not possible to present at exactly that time, it will be
+ // presented after the time has passed.
+ //
+ // If the client didn't pass a desired presentation time, mDesiredPresentTime will be
+ // populated to the time setBuffer was called, and mIsAutoTimestamp will be set to true.
+ //
+ // Desired present times that are more than 1 second in the future may be ignored.
+ // When a desired present time has already passed, the transaction will be presented as soon
+ // as possible.
+ //
+ // Transactions from the same process are presented in the same order that they are applied.
+ // The desired present time does not affect this ordering.
+ int64_t mDesiredPresentTime = 0;
+ bool mIsAutoTimestamp = true;
+
+ // The vsync id provided by Choreographer.getVsyncId and the input event id
+ FrameTimelineInfo mFrameTimelineInfo;
+
+ // If not null, transactions will be queued up using this token otherwise a common token
+ // per process will be used.
+ sp<IBinder> mApplyToken = nullptr;
+ InputWindowCommands mInputWindowCommands;
int mStatus = NO_ERROR;
layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
@@ -462,11 +506,6 @@ public:
void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
void setReleaseBufferCallback(BufferData*, ReleaseBufferCallback);
- protected:
- // Accessed in tests.
- std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
- mListenerCallbacks;
-
public:
Transaction();
virtual ~Transaction() = default;
@@ -483,7 +522,7 @@ public:
// Returns the current id of the transaction.
// The id is updated every time the transaction is applied.
- uint64_t getId() const;
+ uint64_t getId();
std::vector<uint64_t> getMergedTransactionIds();
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 344b957ba7..91a422d155 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -26,6 +26,7 @@
#include <android/gui/ISurfaceComposerClient.h>
+#include <gui/Choreographer.h>
#include <ui/FrameStats.h>
#include <ui/PixelFormat.h>
#include <ui/Region.h>
@@ -36,7 +37,6 @@ namespace android {
// ---------------------------------------------------------------------------
-class Choreographer;
class IGraphicBufferProducer;
class Surface;
class SurfaceComposerClient;
@@ -82,7 +82,7 @@ public:
const std::string& getName() const;
// TODO(b/267195698): Consider renaming.
- std::shared_ptr<Choreographer> getChoreographer();
+ sp<Choreographer> getChoreographer();
sp<IGraphicBufferProducer> getIGraphicBufferProducer();
@@ -134,7 +134,7 @@ private:
PixelFormat mFormat = PIXEL_FORMAT_NONE;
uint32_t mCreateFlags = 0;
uint64_t mFallbackFrameNumber = 100;
- std::shared_ptr<Choreographer> mChoreographer;
+ sp<Choreographer> mChoreographer;
};
}; // namespace android
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index e20345dd1a..bd53031e79 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -51,11 +51,6 @@ cc_test {
"-Werror",
"-Wextra",
"-Wthread-safety",
- "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_BQ_SETFRAMERATE=true",
- "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_BQ_EXTENDEDALLOCATE=true",
- "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_WB_CONSUMER_BASE_OWNS_BQ=true",
- "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_WB_PLATFORM_API_IMPROVEMENTS=true",
- "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_WB_UNLIMITED_SLOTS=true",
],
srcs: [
@@ -100,6 +95,7 @@ cc_test {
"android.hardware.configstore-utils",
"libSurfaceFlingerProp",
"libGLESv1_CM",
+ "libgui",
"libgui_test_server_aidl-cpp",
"libinput",
"libnativedisplay",
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index b861c6d4b7..4e4c8a2b63 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -201,7 +201,7 @@ public:
protected:
void SetUp() {
mComposer = ComposerService::getComposerService();
- mClient = new SurfaceComposerClient();
+ mClient = sp<SurfaceComposerClient>::make();
const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
ASSERT_FALSE(ids.empty());
// display 0 is picked as this test is not much display depedent
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index cfbb2e7386..e22f57e43e 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -1452,10 +1452,6 @@ TEST_F(BufferQueueTest, TestProducerConnectDisconnect) {
ASSERT_EQ(NO_INIT, mProducer->disconnect(NATIVE_WINDOW_API_CPU));
}
-TEST_F(BufferQueueTest, TestBqSetFrameRateFlagBuildTimeIsSet) {
- ASSERT_EQ(flags::bq_setframerate(), COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_SETFRAMERATE));
-}
-
struct BufferItemConsumerSetFrameRateListener : public BufferItemConsumer {
BufferItemConsumerSetFrameRateListener() : BufferItemConsumer(GRALLOC_USAGE_SW_READ_OFTEN, 1) {}
@@ -1561,9 +1557,14 @@ TEST_F(BufferQueueTest, TestAdditionalOptions) {
{.name = "android.hardware.graphics.common.Dataspace", ADATASPACE_DISPLAY_P3},
}};
- ASSERT_EQ(NO_INIT,
- native_window_set_buffers_additional_options(surface.get(), extras.data(),
- extras.size()));
+ auto status = native_window_set_buffers_additional_options(surface.get(), extras.data(),
+ extras.size());
+ if (flags::bq_extendedallocate()) {
+ ASSERT_EQ(NO_INIT, status);
+ } else {
+ ASSERT_EQ(INVALID_OPERATION, status);
+ GTEST_SKIP() << "Flag bq_extendedallocate not enabled";
+ }
if (!IsCuttlefish()) {
GTEST_SKIP() << "Not cuttlefish";
diff --git a/libs/gui/tests/DisplayedContentSampling_test.cpp b/libs/gui/tests/DisplayedContentSampling_test.cpp
index bffb3f0430..62d73ca752 100644
--- a/libs/gui/tests/DisplayedContentSampling_test.cpp
+++ b/libs/gui/tests/DisplayedContentSampling_test.cpp
@@ -30,7 +30,7 @@ static constexpr uint32_t INVALID_MASK = 0x10;
class DisplayedContentSamplingTest : public ::testing::Test {
protected:
void SetUp() {
- mComposerClient = new SurfaceComposerClient;
+ mComposerClient = sp<SurfaceComposerClient>::make();
ASSERT_EQ(OK, mComposerClient->initCheck());
const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
ASSERT_FALSE(ids.empty());
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index adf8fce472..5a5067b2b9 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -398,7 +398,7 @@ public:
InputSurfacesTest() { ProcessState::self()->startThreadPool(); }
void SetUp() {
- mComposerClient = new SurfaceComposerClient;
+ mComposerClient = sp<SurfaceComposerClient>::make();
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
ASSERT_FALSE(ids.empty());
diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp
index 40af8e845a..407c18ed0d 100644
--- a/libs/gui/tests/GLTest.cpp
+++ b/libs/gui/tests/GLTest.cpp
@@ -56,7 +56,7 @@ void GLTest::SetUp() {
}
if (mDisplaySecs > 0) {
- mComposerClient = new SurfaceComposerClient;
+ mComposerClient = sp<SurfaceComposerClient>::make();
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
mSurfaceControl = mComposerClient->createSurface(
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index c35efe28a3..d80d223f49 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -180,7 +180,7 @@ protected:
}
void SetUp() override {
- mSurfaceComposerClient = new SurfaceComposerClient;
+ mSurfaceComposerClient = sp<SurfaceComposerClient>::make();
ASSERT_EQ(NO_ERROR, mSurfaceComposerClient->initCheck());
mBackgroundLayer =
diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp
index 8fea689c91..a2fe8fd2ec 100644
--- a/libs/gui/tests/SamplingDemo.cpp
+++ b/libs/gui/tests/SamplingDemo.cpp
@@ -36,7 +36,7 @@ namespace android {
class Button : public gui::BnRegionSamplingListener {
public:
Button(const char* name, const Rect& samplingArea) {
- sp<SurfaceComposerClient> client = new SurfaceComposerClient;
+ sp<SurfaceComposerClient> client = sp<SurfaceComposerClient>::make();
mButton = client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceEffect);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index c4dcba856a..61c93cae14 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -134,7 +134,7 @@ protected:
}
virtual void SetUp() {
- mComposerClient = new SurfaceComposerClient;
+ mComposerClient = sp<SurfaceComposerClient>::make();
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
// TODO(brianderson): The following sometimes fails and is a source of
@@ -648,7 +648,16 @@ public:
mSupportsPresent = supportsPresent;
}
- status_t setTransactionState(TransactionState&&) override { return NO_ERROR; }
+ status_t setTransactionState(
+ const FrameTimelineInfo& /*frameTimelineInfo*/, Vector<ComposerState>& /*state*/,
+ Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
+ const sp<IBinder>& /*applyToken*/, InputWindowCommands /*inputWindowCommands*/,
+ int64_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/,
+ const std::vector<client_cache_t>& /*cachedBuffer*/, bool /*hasListenerCallbacks*/,
+ const std::vector<ListenerCallbacks>& /*listenerCallbacks*/, uint64_t /*transactionId*/,
+ const std::vector<uint64_t>& /*mergedTransactionIds*/) override {
+ return NO_ERROR;
+ }
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/renderengine/skia/filters/LutShader.cpp b/libs/renderengine/skia/filters/LutShader.cpp
index f262158f2c..6a577ff41f 100644
--- a/libs/renderengine/skia/filters/LutShader.cpp
+++ b/libs/renderengine/skia/filters/LutShader.cpp
@@ -24,7 +24,6 @@
#include <ui/ColorSpace.h>
#include "include/core/SkColorSpace.h"
-#include "src/core/SkColorFilterPriv.h"
using aidl::android::hardware::graphics::composer3::LutProperties;
@@ -116,7 +115,7 @@ static const SkString kShader = SkString(R"(
linear = mix(c0, c1, linear.b);
}
}
- return float4(linear, rgba.a);
+ return float4(fromLinearSrgb(linear), rgba.a);
})");
// same as shader::toColorSpace function
@@ -289,9 +288,7 @@ sk_sp<SkShader> LutShader::lutShader(sk_sp<SkShader>& input,
lutProperties[i].samplingKey, srcDataspace);
}
- auto colorXformLutToDst =
- SkColorFilterPriv::MakeColorSpaceXform(lutMathColorSpace, outColorSpace);
- input = input->makeWithColorFilter(colorXformLutToDst);
+ input = input->makeWithWorkingColorSpace(outColorSpace);
}
return input;
}
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index e94b565f11..beac9001bc 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -29,7 +29,7 @@ using namespace android;
WindowSurface::WindowSurface() {
status_t err;
- sp<SurfaceComposerClient> surfaceComposerClient = new SurfaceComposerClient;
+ sp<SurfaceComposerClient> surfaceComposerClient = sp<SurfaceComposerClient>::make();
err = surfaceComposerClient->initCheck();
if (err != NO_ERROR) {
fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err);
diff --git a/services/automotive/display/AutomotiveDisplayProxyService.cpp b/services/automotive/display/AutomotiveDisplayProxyService.cpp
index afa623352b..56c3b7d31f 100644
--- a/services/automotive/display/AutomotiveDisplayProxyService.cpp
+++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp
@@ -65,7 +65,7 @@ AutomotiveDisplayProxyService::getIGraphicBufferProducer(uint64_t id) {
std::swap(displayWidth, displayHeight);
}
- sp<android::SurfaceComposerClient> surfaceClient = new SurfaceComposerClient();
+ sp<android::SurfaceComposerClient> surfaceClient = sp<SurfaceComposerClient>::make();
err = surfaceClient->initCheck();
if (err != NO_ERROR) {
ALOGE("SurfaceComposerClient::initCheck error: %#x", err);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 5491ab78b4..95e1c06615 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -934,6 +934,7 @@ InputDispatcher::InputDispatcher(InputDispatcherPolicyInterface& policy,
mPendingEvent(nullptr),
mLastDropReason(DropReason::NOT_DROPPED),
mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),
+ mWindowInfosVsyncId(-1),
mMinTimeBetweenUserActivityPokes(DEFAULT_USER_ACTIVITY_POKE_INTERVAL),
mConnectionManager(mLooper),
mTouchStates(mWindowInfos, mConnectionManager),
diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp
index 4f65e77462..78f8f7bd96 100644
--- a/services/powermanager/Android.bp
+++ b/services/powermanager/Android.bp
@@ -52,6 +52,7 @@ cc_library_shared {
],
whole_static_libs: [
+ "android.adpf.sessionmanager_aidl-ndk",
"android.os.hintmanager_aidl-ndk",
],
diff --git a/services/powermanager/PowerHalController.cpp b/services/powermanager/PowerHalController.cpp
index 0ba1909a44..a817a7bf2e 100644
--- a/services/powermanager/PowerHalController.cpp
+++ b/services/powermanager/PowerHalController.cpp
@@ -173,6 +173,21 @@ HalResult<aidl::android::hardware::power::SupportInfo> PowerHalController::getSu
return CACHE_SUPPORT(6, processHalResult(handle->getSupportInfo(), "getSupportInfo"));
}
+HalResult<void> PowerHalController::sendCompositionData(
+ const std::vector<hal::CompositionData>& data) {
+ std::shared_ptr<HalWrapper> handle = initHal();
+ return CACHE_SUPPORT(6,
+ processHalResult(handle->sendCompositionData(data),
+ "sendCompositionData"));
+}
+
+HalResult<void> PowerHalController::sendCompositionUpdate(const hal::CompositionUpdate& update) {
+ std::shared_ptr<HalWrapper> handle = initHal();
+ return CACHE_SUPPORT(6,
+ processHalResult(handle->sendCompositionUpdate(update),
+ "sendCompositionUpdate"));
+}
+
} // namespace power
} // namespace android
diff --git a/services/powermanager/PowerHalWrapper.cpp b/services/powermanager/PowerHalWrapper.cpp
index 068c23f94a..9c83bf5af3 100644
--- a/services/powermanager/PowerHalWrapper.cpp
+++ b/services/powermanager/PowerHalWrapper.cpp
@@ -79,6 +79,16 @@ HalResult<Aidl::SupportInfo> EmptyHalWrapper::getSupportInfo() {
return HalResult<Aidl::SupportInfo>::unsupported();
}
+HalResult<void> EmptyHalWrapper::sendCompositionData(const std::vector<hal::CompositionData>&) {
+ ALOGV("Skipped sendCompositionData because %s", getUnsupportedMessage());
+ return HalResult<void>::unsupported();
+}
+
+HalResult<void> EmptyHalWrapper::sendCompositionUpdate(const hal::CompositionUpdate&) {
+ ALOGV("Skipped sendCompositionUpdate because %s", getUnsupportedMessage());
+ return HalResult<void>::unsupported();
+}
+
const char* EmptyHalWrapper::getUnsupportedMessage() {
return "Power HAL is not supported";
}
@@ -292,6 +302,14 @@ HalResult<Aidl::SupportInfo> AidlHalWrapper::getSupportInfo() {
return HalResult<Aidl::SupportInfo>::fromStatus(result, std::move(support));
}
+HalResult<void> AidlHalWrapper::sendCompositionData(const std::vector<hal::CompositionData>& data) {
+ return HalResult<void>::fromStatus(mHandle->sendCompositionData(data));
+}
+
+HalResult<void> AidlHalWrapper::sendCompositionUpdate(const hal::CompositionUpdate& update) {
+ return HalResult<void>::fromStatus(mHandle->sendCompositionUpdate(update));
+}
+
const char* AidlHalWrapper::getUnsupportedMessage() {
return "Power HAL doesn't support it";
}
diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
index 682d1f44dc..1c53496644 100644
--- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
+++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
@@ -26,9 +26,9 @@
#include <utils/Log.h>
#include <unistd.h>
+#include <memory>
#include <thread>
-
using android::binder::Status;
using namespace aidl::android::hardware::power;
@@ -347,3 +347,50 @@ TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionWithConfigUnsupported) {
result = mWrapper->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, tag, &out);
ASSERT_TRUE(result.isUnsupported());
}
+
+TEST_F(PowerHalWrapperAidlTest, TestSendingCompositionData) {
+ int32_t tgid = 999;
+ int32_t uid = 1001;
+ std::vector<hal::CompositionData> dataOut;
+ dataOut.emplace_back(hal::CompositionData{
+ .timestampNanos = 0L,
+ .scheduledPresentTimestampsNanos = {100},
+ .latchTimestampNanos = 50,
+ .outputIds = {0},
+ });
+ dataOut.emplace_back(hal::CompositionData{
+ .timestampNanos = 200L,
+ .scheduledPresentTimestampsNanos = {300},
+ .latchTimestampNanos = 250,
+ .outputIds = {0},
+ });
+ EXPECT_CALL(*mMockHal.get(), sendCompositionData(_))
+ .Times(Exactly(1))
+ .WillOnce([&](const std::vector<hal::CompositionData>& passedData) {
+ if (!std::equal(passedData.begin(), passedData.end(), dataOut.begin())) {
+ ADD_FAILURE() << "Passed composition data not the same";
+ }
+ return ndk::ScopedAStatus::ok();
+ });
+
+ ASSERT_TRUE(mWrapper->sendCompositionData(dataOut).isOk());
+}
+
+TEST_F(PowerHalWrapperAidlTest, TestSendingCompositionUpdate) {
+ int32_t tgid = 999;
+ int32_t uid = 1001;
+ hal::CompositionUpdate dataOut{
+ .timestampNanos = 123,
+ .deadOutputIds = {1, 2, 3},
+ };
+ EXPECT_CALL(*mMockHal.get(), sendCompositionUpdate(_))
+ .Times(Exactly(1))
+ .WillOnce([&](const hal::CompositionUpdate& passedData) {
+ if (passedData != dataOut) {
+ ADD_FAILURE() << "Passed composition update data not the same";
+ }
+ return ndk::ScopedAStatus::ok();
+ });
+
+ ASSERT_TRUE(mWrapper->sendCompositionUpdate(dataOut).isOk());
+} \ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index 48d02423f8..34c09db6f8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -62,10 +62,15 @@ struct CompositionEngineTest : public testing::Test {
void SetUp() override {
EXPECT_CALL(*mOutput1, getDisplayId)
.WillRepeatedly(Return(std::make_optional<DisplayId>(kDisplayId1)));
+ EXPECT_CALL(*mOutput1, getDisplayIdVariant).WillRepeatedly(Return(kDisplayId1));
+
EXPECT_CALL(*mOutput2, getDisplayId)
.WillRepeatedly(Return(std::make_optional<DisplayId>(kDisplayId2)));
+ EXPECT_CALL(*mOutput2, getDisplayIdVariant).WillRepeatedly(Return(kDisplayId2));
+
EXPECT_CALL(*mOutput3, getDisplayId)
.WillRepeatedly(Return(std::make_optional<DisplayId>(kDisplayId3)));
+ EXPECT_CALL(*mOutput3, getDisplayIdVariant).WillRepeatedly(Return(kDisplayId3));
// Most tests will depend on the outputs being enabled.
for (auto& state : mOutputStates) {
diff --git a/services/surfaceflinger/Display/VirtualDisplaySnapshot.h b/services/surfaceflinger/Display/VirtualDisplaySnapshot.h
index c68020ce51..71d9f2e468 100644
--- a/services/surfaceflinger/Display/VirtualDisplaySnapshot.h
+++ b/services/surfaceflinger/Display/VirtualDisplaySnapshot.h
@@ -35,6 +35,7 @@ public:
VirtualDisplayId displayId() const { return mVirtualId; }
bool isGpu() const { return mIsGpu; }
+ const std::string& uniqueId() const { return mUniqueId; }
void dump(utils::Dumper& dumper) const {
using namespace std::string_view_literals;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index bad5e2e3b5..de7d455fa4 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -50,17 +50,6 @@ namespace android {
namespace hal = hardware::graphics::composer::hal;
-namespace gui {
-inline std::string_view to_string(ISurfaceComposer::OptimizationPolicy optimizationPolicy) {
- switch (optimizationPolicy) {
- case ISurfaceComposer::OptimizationPolicy::optimizeForPower:
- return "optimizeForPower";
- case ISurfaceComposer::OptimizationPolicy::optimizeForPerformance:
- return "optimizeForPerformance";
- }
-}
-} // namespace gui
-
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(
const sp<SurfaceFlinger>& flinger, HWComposer& hwComposer, const wp<IBinder>& displayToken,
std::shared_ptr<compositionengine::Display> compositionDisplay)
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 7d7c8adb7b..1b14145147 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -67,6 +67,17 @@ namespace display {
class DisplaySnapshot;
} // namespace display
+namespace gui {
+inline const char* to_string(ISurfaceComposer::OptimizationPolicy optimizationPolicy) {
+ switch (optimizationPolicy) {
+ case ISurfaceComposer::OptimizationPolicy::optimizeForPower:
+ return "optimizeForPower";
+ case ISurfaceComposer::OptimizationPolicy::optimizeForPerformance:
+ return "optimizeForPerformance";
+ }
+}
+} // namespace gui
+
class DisplayDevice : public RefBase {
public:
constexpr static float sDefaultMinLumiance = 0.0;
diff --git a/services/surfaceflinger/LayerVector.h b/services/surfaceflinger/LayerVector.h
index 38dc11d3bc..81155fd697 100644
--- a/services/surfaceflinger/LayerVector.h
+++ b/services/surfaceflinger/LayerVector.h
@@ -49,7 +49,8 @@ public:
using Visitor = std::function<void(Layer*)>;
private:
- const StateSet mStateSet;
+ // FIXME: This is set but not used anywhere.
+ [[maybe_unused]] const StateSet mStateSet;
};
}
diff --git a/services/surfaceflinger/PowerAdvisor/SessionManager.h b/services/surfaceflinger/PowerAdvisor/SessionManager.h
index 93a80b55ab..afa52eb260 100644
--- a/services/surfaceflinger/PowerAdvisor/SessionManager.h
+++ b/services/surfaceflinger/PowerAdvisor/SessionManager.h
@@ -68,7 +68,8 @@ private:
bool isLayerRelevant(int32_t layerId);
// The UID of whoever created our ISessionManager connection
- const uid_t mUid;
+ // FIXME: This is set but is not used anywhere.
+ [[maybe_unused]] const uid_t mUid;
// State owned by the main thread
@@ -99,4 +100,4 @@ private:
};
} // namespace adpf
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/QueuedTransactionState.h b/services/surfaceflinger/QueuedTransactionState.h
index 6a17a0d0cb..86683da26c 100644
--- a/services/surfaceflinger/QueuedTransactionState.h
+++ b/services/surfaceflinger/QueuedTransactionState.h
@@ -25,7 +25,6 @@
#include <common/FlagManager.h>
#include <ftl/flags.h>
#include <gui/LayerState.h>
-#include <gui/TransactionState.h>
#include <system/window.h>
namespace android {
@@ -51,26 +50,33 @@ public:
struct QueuedTransactionState {
QueuedTransactionState() = default;
- QueuedTransactionState(TransactionState&& transactionState,
- std::vector<ResolvedComposerState>&& composerStates,
- std::vector<uint64_t>&& uncacheBufferIds, int64_t postTime,
- int originPid, int originUid)
- : frameTimelineInfo(std::move(transactionState.mFrameTimelineInfo)),
- states(composerStates),
- displays(std::move(transactionState.mDisplayStates)),
- flags(transactionState.mFlags),
- applyToken(transactionState.mApplyToken),
- inputWindowCommands(std::move(transactionState.mInputWindowCommands)),
- desiredPresentTime(transactionState.mDesiredPresentTime),
- isAutoTimestamp(transactionState.mIsAutoTimestamp),
+ QueuedTransactionState(const FrameTimelineInfo& frameTimelineInfo,
+ std::vector<ResolvedComposerState>& composerStates,
+ const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
+ const sp<IBinder>& applyToken,
+ const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime, bool isAutoTimestamp,
+ std::vector<uint64_t> uncacheBufferIds, int64_t postTime,
+ bool hasListenerCallbacks,
+ std::vector<ListenerCallbacks> listenerCallbacks, int originPid,
+ int originUid, uint64_t transactionId,
+ std::vector<uint64_t> mergedTransactionIds)
+ : frameTimelineInfo(frameTimelineInfo),
+ states(std::move(composerStates)),
+ displays(displayStates),
+ flags(transactionFlags),
+ applyToken(applyToken),
+ inputWindowCommands(inputWindowCommands),
+ desiredPresentTime(desiredPresentTime),
+ isAutoTimestamp(isAutoTimestamp),
uncacheBufferIds(std::move(uncacheBufferIds)),
postTime(postTime),
- hasListenerCallbacks(transactionState.mHasListenerCallbacks),
- listenerCallbacks(std::move(transactionState.mListenerCallbacks)),
+ hasListenerCallbacks(hasListenerCallbacks),
+ listenerCallbacks(listenerCallbacks),
originPid(originPid),
originUid(originUid),
- id(transactionState.getId()),
- mergedTransactionIds(std::move(transactionState.mMergedTransactionIds)) {}
+ id(transactionId),
+ mergedTransactionIds(std::move(mergedTransactionIds)) {}
// Invokes `void(const layer_state_t&)` visitor for matching layers.
template <typename Visitor>
@@ -129,7 +135,7 @@ struct QueuedTransactionState {
FrameTimelineInfo frameTimelineInfo;
std::vector<ResolvedComposerState> states;
- std::vector<DisplayState> displays;
+ Vector<DisplayState> displays;
uint32_t flags;
sp<IBinder> applyToken;
InputWindowCommands inputWindowCommands;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 655c24fc3f..ce7a720714 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4998,7 +4998,13 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const layer_state_t& state, size_t nu
return true;
}
-status_t SurfaceFlinger::setTransactionState(TransactionState&& transactionState) {
+status_t SurfaceFlinger::setTransactionState(
+ const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& states,
+ Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ InputWindowCommands inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp,
+ const std::vector<client_cache_t>& uncacheBuffers, bool hasListenerCallbacks,
+ const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId,
+ const std::vector<uint64_t>& mergedTransactionIds) {
SFTRACE_CALL();
IPCThreadState* ipc = IPCThreadState::self();
@@ -5006,7 +5012,7 @@ status_t SurfaceFlinger::setTransactionState(TransactionState&& transactionState
const int originUid = ipc->getCallingUid();
uint32_t permissions = LayerStatePermissions::getTransactionPermissions(originPid, originUid);
ftl::Flags<adpf::Workload> queuedWorkload;
- for (auto& composerState : transactionState.mComposerStates) {
+ for (auto& composerState : states) {
composerState.state.sanitize(permissions);
if (composerState.state.what & layer_state_t::COMPOSITION_EFFECTS) {
queuedWorkload |= adpf::Workload::EFFECTS;
@@ -5016,27 +5022,27 @@ status_t SurfaceFlinger::setTransactionState(TransactionState&& transactionState
}
}
- for (DisplayState& display : transactionState.mDisplayStates) {
+ for (DisplayState& display : displays) {
display.sanitize(permissions);
}
- if (!transactionState.mInputWindowCommands.empty() &&
+ if (!inputWindowCommands.empty() &&
(permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER) == 0) {
ALOGE("Only privileged callers are allowed to send input commands.");
- transactionState.mInputWindowCommands.clear();
+ inputWindowCommands.clear();
}
- if (transactionState.mFlags & (eEarlyWakeupStart | eEarlyWakeupEnd)) {
+ if (flags & (eEarlyWakeupStart | eEarlyWakeupEnd)) {
const bool hasPermission =
(permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER) ||
callingThreadHasPermission(sWakeupSurfaceFlinger);
if (!hasPermission) {
ALOGE("Caller needs permission android.permission.WAKEUP_SURFACE_FLINGER to use "
"eEarlyWakeup[Start|End] flags");
- transactionState.mFlags &= ~(eEarlyWakeupStart | eEarlyWakeupEnd);
+ flags &= ~(eEarlyWakeupStart | eEarlyWakeupEnd);
}
}
- if (transactionState.mFlags & eEarlyWakeupStart) {
+ if (flags & eEarlyWakeupStart) {
queuedWorkload |= adpf::Workload::WAKEUP;
}
mPowerAdvisor->setQueuedWorkload(queuedWorkload);
@@ -5044,8 +5050,8 @@ status_t SurfaceFlinger::setTransactionState(TransactionState&& transactionState
const int64_t postTime = systemTime();
std::vector<uint64_t> uncacheBufferIds;
- uncacheBufferIds.reserve(transactionState.mUncacheBuffers.size());
- for (const auto& uncacheBuffer : transactionState.mUncacheBuffers) {
+ uncacheBufferIds.reserve(uncacheBuffers.size());
+ for (const auto& uncacheBuffer : uncacheBuffers) {
sp<GraphicBuffer> buffer = ClientCache::getInstance().erase(uncacheBuffer);
if (buffer != nullptr) {
uncacheBufferIds.push_back(buffer->getId());
@@ -5053,8 +5059,8 @@ status_t SurfaceFlinger::setTransactionState(TransactionState&& transactionState
}
std::vector<ResolvedComposerState> resolvedStates;
- resolvedStates.reserve(transactionState.mComposerStates.size());
- for (auto& state : transactionState.mComposerStates) {
+ resolvedStates.reserve(states.size());
+ for (auto& state : states) {
resolvedStates.emplace_back(std::move(state));
auto& resolvedState = resolvedStates.back();
resolvedState.layerId = LayerHandle::getLayerId(resolvedState.state.surface);
@@ -5065,7 +5071,7 @@ status_t SurfaceFlinger::setTransactionState(TransactionState&& transactionState
layer->getDebugName() : std::to_string(resolvedState.state.layerId);
resolvedState.externalTexture =
getExternalTextureFromBufferData(*resolvedState.state.bufferData,
- layerName.c_str(), transactionState.getId());
+ layerName.c_str(), transactionId);
if (resolvedState.externalTexture) {
resolvedState.state.bufferData->buffer = resolvedState.externalTexture->getBuffer();
if (FlagManager::getInstance().monitor_buffer_fences()) {
@@ -5093,12 +5099,22 @@ status_t SurfaceFlinger::setTransactionState(TransactionState&& transactionState
}
}
- QueuedTransactionState state{std::move(transactionState),
- std::move(resolvedStates),
+ QueuedTransactionState state{frameTimelineInfo,
+ resolvedStates,
+ displays,
+ flags,
+ applyToken,
+ std::move(inputWindowCommands),
+ desiredPresentTime,
+ isAutoTimestamp,
std::move(uncacheBufferIds),
postTime,
+ hasListenerCallbacks,
+ listenerCallbacks,
originPid,
- originUid};
+ originUid,
+ transactionId,
+ mergedTransactionIds};
state.workloadHint = queuedWorkload;
if (mTransactionTracing) {
@@ -5121,16 +5137,16 @@ status_t SurfaceFlinger::setTransactionState(TransactionState&& transactionState
for (const auto& [displayId, data] : mNotifyExpectedPresentMap) {
if (data.hintStatus.load() == NotifyExpectedPresentHintStatus::ScheduleOnTx) {
- scheduleNotifyExpectedPresentHint(displayId, VsyncId{state.frameTimelineInfo.vsyncId});
+ scheduleNotifyExpectedPresentHint(displayId, VsyncId{frameTimelineInfo.vsyncId});
}
}
- setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken, frameHint);
+ setTransactionFlags(eTransactionFlushNeeded, schedule, applyToken, frameHint);
return NO_ERROR;
}
bool SurfaceFlinger::applyTransactionState(
const FrameTimelineInfo& frameTimelineInfo, std::vector<ResolvedComposerState>& states,
- std::span<DisplayState> displays, uint32_t flags,
+ Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime,
bool isAutoTimestamp, const std::vector<uint64_t>& uncacheBufferIds, const int64_t postTime,
bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
@@ -5620,8 +5636,7 @@ void SurfaceFlinger::initializeDisplays() {
auto layerStack = ui::DEFAULT_LAYER_STACK.id;
for (const auto& [id, display] : FTL_FAKE_GUARD(mStateLock, mPhysicalDisplays)) {
- state.displays.emplace_back(
- DisplayState(display.token(), ui::LayerStack::fromValue(layerStack++)));
+ state.displays.push(DisplayState(display.token(), ui::LayerStack::fromValue(layerStack++)));
}
std::vector<QueuedTransactionState> transactions;
@@ -5689,7 +5704,13 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa
incRefreshableDisplays();
}
+ if (displayId == mActiveDisplayId &&
+ FlagManager::getInstance().correct_virtual_display_power_state()) {
+ applyOptimizationPolicy(__func__);
+ }
+
const auto activeMode = display->refreshRateSelector().getActiveMode().modePtr;
+ using OptimizationPolicy = gui::ISurfaceComposer::OptimizationPolicy;
if (currentMode == hal::PowerMode::OFF) {
// Turn on the display
@@ -5704,12 +5725,10 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa
onActiveDisplayChangedLocked(activeDisplay.get(), *display);
}
- if (displayId == mActiveDisplayId) {
- if (FlagManager::getInstance().correct_virtual_display_power_state()) {
- applyOptimizationPolicy("setPhysicalDisplayPowerMode(ON)");
- } else {
- disablePowerOptimizations("setPhysicalDisplayPowerMode(ON)");
- }
+ if (displayId == mActiveDisplayId &&
+ !FlagManager::getInstance().correct_virtual_display_power_state()) {
+ optimizeThreadScheduling("setPhysicalDisplayPowerMode(ON/DOZE)",
+ OptimizationPolicy::optimizeForPerformance);
}
getHwComposer().setPowerMode(displayId, mode);
@@ -5718,7 +5737,8 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa
mScheduler->getVsyncSchedule(displayId)->getPendingHardwareVsyncState();
requestHardwareVsync(displayId, enable);
- if (displayId == mActiveDisplayId) {
+ if (displayId == mActiveDisplayId &&
+ !FlagManager::getInstance().correct_virtual_display_power_state()) {
mScheduler->enableSyntheticVsync(false);
}
@@ -5735,13 +5755,13 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa
if (const auto display = getActivatableDisplay()) {
onActiveDisplayChangedLocked(activeDisplay.get(), *display);
} else {
- if (FlagManager::getInstance().correct_virtual_display_power_state()) {
- applyOptimizationPolicy("setPhysicalDisplayPowerMode(OFF)");
- } else {
- enablePowerOptimizations("setPhysicalDisplayPowerMode(OFF)");
+ if (!FlagManager::getInstance().correct_virtual_display_power_state()) {
+ optimizeThreadScheduling("setPhysicalDisplayPowerMode(OFF)",
+ OptimizationPolicy::optimizeForPower);
}
- if (currentModeNotDozeSuspend) {
+ if (currentModeNotDozeSuspend &&
+ !FlagManager::getInstance().correct_virtual_display_power_state()) {
mScheduler->enableSyntheticVsync();
}
}
@@ -5769,7 +5789,9 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa
ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON.");
mVisibleRegionsDirty = true;
scheduleRepaint();
- mScheduler->enableSyntheticVsync(false);
+ if (!FlagManager::getInstance().correct_virtual_display_power_state()) {
+ mScheduler->enableSyntheticVsync(false);
+ }
}
constexpr bool kAllowToEnable = true;
mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, activeMode.get());
@@ -5779,7 +5801,8 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa
constexpr bool kDisallow = true;
mScheduler->disableHardwareVsync(displayId, kDisallow);
- if (displayId == mActiveDisplayId) {
+ if (displayId == mActiveDisplayId &&
+ !FlagManager::getInstance().correct_virtual_display_power_state()) {
mScheduler->enableSyntheticVsync();
}
getHwComposer().setPowerMode(displayId, mode);
@@ -5818,43 +5841,44 @@ void SurfaceFlinger::setVirtualDisplayPowerMode(const sp<DisplayDevice>& display
to_string(displayId).c_str());
}
-bool SurfaceFlinger::shouldOptimizeForPerformance() {
- for (const auto& [_, display] : mDisplays) {
- // Displays that are optimized for power are always powered on and should not influence
- // whether there is an active display for the purpose of power optimization, etc. If these
- // displays are being shown somewhere, a different (physical or virtual) display that is
- // optimized for performance will be powered on in addition. Displays optimized for
- // performance will change power mode, so if they are off then they are not active.
- if (display->isPoweredOn() &&
- display->getOptimizationPolicy() ==
- gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance) {
- return true;
- }
- }
- return false;
-}
-
-void SurfaceFlinger::enablePowerOptimizations(const char* whence) {
- ALOGD("%s: Enabling power optimizations", whence);
-
- setSchedAttr(false, whence);
- setSchedFifo(false, whence);
-}
-
-void SurfaceFlinger::disablePowerOptimizations(const char* whence) {
- ALOGD("%s: Disabling power optimizations", whence);
+void SurfaceFlinger::optimizeThreadScheduling(
+ const char* whence, gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy) {
+ ALOGD("%s: Optimizing thread scheduling: %s", whence, to_string(optimizationPolicy));
+ const bool optimizeForPerformance =
+ optimizationPolicy == gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance;
// TODO: b/281692563 - Merge the syscalls. For now, keep uclamp in a separate syscall
// and set it before SCHED_FIFO due to b/190237315.
- setSchedAttr(true, whence);
- setSchedFifo(true, whence);
+ setSchedAttr(optimizeForPerformance, whence);
+ setSchedFifo(optimizeForPerformance, whence);
}
void SurfaceFlinger::applyOptimizationPolicy(const char* whence) {
- if (shouldOptimizeForPerformance()) {
- disablePowerOptimizations(whence);
- } else {
- enablePowerOptimizations(whence);
+ using OptimizationPolicy = gui::ISurfaceComposer::OptimizationPolicy;
+
+ const bool optimizeForPerformance =
+ std::any_of(mDisplays.begin(), mDisplays.end(), [](const auto& pair) {
+ const auto& display = pair.second;
+ return display->isPoweredOn() &&
+ display->getOptimizationPolicy() ==
+ OptimizationPolicy::optimizeForPerformance;
+ });
+
+ optimizeThreadScheduling(whence,
+ optimizeForPerformance ? OptimizationPolicy::optimizeForPerformance
+ : OptimizationPolicy::optimizeForPower);
+
+ if (mScheduler) {
+ const bool disableSyntheticVsync =
+ std::any_of(mDisplays.begin(), mDisplays.end(), [](const auto& pair) {
+ const auto& display = pair.second;
+ const hal::PowerMode powerMode = display->getPowerMode();
+ return powerMode != hal::PowerMode::OFF &&
+ powerMode != hal::PowerMode::DOZE_SUSPEND &&
+ display->getOptimizationPolicy() ==
+ OptimizationPolicy::optimizeForPerformance;
+ });
+ mScheduler->enableSyntheticVsync(!disableSyntheticVsync);
}
}
@@ -6084,9 +6108,8 @@ void SurfaceFlinger::dumpDisplays(std::string& result) const {
display->dump(dumper);
std::lock_guard lock(mVirtualDisplaysMutex);
- const auto virtualSnapshotIt = mVirtualDisplays.find(virtualId);
- if (virtualSnapshotIt != mVirtualDisplays.end()) {
- virtualSnapshotIt->second.dump(dumper);
+ if (const auto snapshotOpt = mVirtualDisplays.get(virtualId)) {
+ snapshotOpt->get().dump(dumper);
}
}
}
@@ -6098,6 +6121,7 @@ void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const {
if (!displayId) {
continue;
}
+
const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId);
if (!hwcDisplayId) {
continue;
@@ -6106,6 +6130,7 @@ void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const {
StringAppendF(&result,
"Display %s (HWC display %" PRIu64 "): ", to_string(*displayId).c_str(),
*hwcDisplayId);
+
uint8_t port;
DisplayIdentificationData data;
if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) {
@@ -6133,6 +6158,19 @@ void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const {
result.append(edid->displayName.data(), edid->displayName.length());
result.append("\"\n");
}
+
+ for (const auto& [token, display] : mDisplays) {
+ const auto virtualDisplayId = asVirtualDisplayId(display->getDisplayIdVariant());
+ if (virtualDisplayId) {
+ StringAppendF(&result, "Display %s (Virtual display): displayName=\"%s\"",
+ to_string(*virtualDisplayId).c_str(), display->getDisplayName().c_str());
+ std::lock_guard lock(mVirtualDisplaysMutex);
+ if (const auto snapshotOpt = mVirtualDisplays.get(*virtualDisplayId)) {
+ StringAppendF(&result, " uniqueId=\"%s\"", snapshotOpt->get().uniqueId().c_str());
+ }
+ result.append("\n");
+ }
+ }
}
void SurfaceFlinger::dumpRawDisplayIdentificationData(const DumpArgs& args,
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index fe8998403e..c472c4c6d4 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -545,7 +545,13 @@ private:
}
sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const;
- status_t setTransactionState(TransactionState&&) override;
+ status_t setTransactionState(
+ const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state,
+ Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ InputWindowCommands inputWindowCommands, int64_t desiredPresentTime,
+ bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffers,
+ bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
+ uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) override;
void bootFinished();
status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const;
sp<IDisplayEventConnection> createDisplayEventConnection(
@@ -733,19 +739,14 @@ private:
void setVirtualDisplayPowerMode(const sp<DisplayDevice>& display, hal::PowerMode mode)
REQUIRES(mStateLock, kMainThreadContext);
- // Returns whether to optimize globally for performance instead of power.
- bool shouldOptimizeForPerformance() REQUIRES(mStateLock);
-
- // Turns on power optimizations, for example when there are no displays to be optimized for
- // performance.
- static void enablePowerOptimizations(const char* whence);
-
- // Turns off power optimizations.
- static void disablePowerOptimizations(const char* whence);
+ // Adjusts thread scheduling according to the optimization policy
+ static void optimizeThreadScheduling(
+ const char* whence, gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy);
// Enables or disables power optimizations depending on whether there are displays that should
// be optimized for performance.
- void applyOptimizationPolicy(const char* whence) REQUIRES(mStateLock);
+ void applyOptimizationPolicy(const char* whence) REQUIRES(kMainThreadContext)
+ REQUIRES(mStateLock);
// Returns the preferred mode for PhysicalDisplayId if the Scheduler has selected one for that
// display. Falls back to the display's defaultModeId otherwise.
@@ -792,7 +793,7 @@ private:
*/
bool applyTransactionState(const FrameTimelineInfo& info,
std::vector<ResolvedComposerState>& state,
- std::span<DisplayState> displays, uint32_t flags,
+ Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
const int64_t desiredPresentTime, bool isAutoTimestamp,
const std::vector<uint64_t>& uncacheBufferIds,
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 6bbc04cf6f..3297c16113 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -321,7 +321,7 @@ QueuedTransactionState TransactionProtoParser::fromProto(
int32_t displayCount = proto.display_changes_size();
t.displays.reserve(static_cast<size_t>(displayCount));
for (int i = 0; i < displayCount; i++) {
- t.displays.emplace_back(fromProto(proto.display_changes(i)));
+ t.displays.add(fromProto(proto.display_changes(i)));
}
return t;
}
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
index 9c143fdd41..6cc6322bfc 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp
@@ -45,15 +45,28 @@ protected:
void setTransactionState() {
ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty());
TransactionInfo transaction;
- mFlinger.setTransactionState(std::move(transaction));
+ mFlinger.setTransactionState(FrameTimelineInfo{}, transaction.states, transaction.displays,
+ transaction.flags, transaction.applyToken,
+ transaction.inputWindowCommands,
+ TimePoint::now().ns() + s2ns(1), transaction.isAutoTimestamp,
+ transaction.unCachedBuffers,
+ /*HasListenerCallbacks=*/false, transaction.callbacks,
+ transaction.id, transaction.mergedTransactionIds);
}
- struct TransactionInfo : public TransactionState {
- TransactionInfo() {
- mApplyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
- mIsAutoTimestamp = false;
- mId = static_cast<uint64_t>(-1);
- }
+ struct TransactionInfo {
+ Vector<ComposerState> states;
+ Vector<DisplayState> displays;
+ uint32_t flags = 0;
+ sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ InputWindowCommands inputWindowCommands;
+ int64_t desiredPresentTime = 0;
+ bool isAutoTimestamp = false;
+ FrameTimelineInfo frameTimelineInfo{};
+ std::vector<client_cache_t> unCachedBuffers;
+ uint64_t id = static_cast<uint64_t>(-1);
+ std::vector<uint64_t> mergedTransactionIds;
+ std::vector<ListenerCallbacks> callbacks;
};
struct Compositor final : ICompositor {
@@ -370,4 +383,4 @@ TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentRenderRateChanged) {
}
}
}
-} // namespace android
+} // namespace android \ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp
index d5c22a9601..2332bf62da 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <android_companion_virtualdevice_flags.h>
#include <com_android_graphics_surfaceflinger_flags.h>
#include <common/test/FlagUtils.h>
#include "DisplayTransactionTestHelpers.h"
@@ -78,11 +79,19 @@ struct EventThreadBaseSupportedVariant {
struct EventThreadNotSupportedVariant : public EventThreadBaseSupportedVariant {
static void setupEnableVsyncCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, true)).Times(1);
+ setupDisableSyntheticVsyncCallExpectations(test);
+ }
+
+ static void setupDisableSyntheticVsyncCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(_)).Times(0);
}
static void setupDisableVsyncCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, false)).Times(1);
+ setupEnableSyntheticVsyncCallExpectations(test);
+ }
+
+ static void setupEnableSyntheticVsyncCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(_)).Times(0);
}
};
@@ -91,12 +100,20 @@ struct EventThreadIsSupportedVariant : public EventThreadBaseSupportedVariant {
static void setupEnableVsyncCallExpectations(DisplayTransactionTest* test) {
// Expect to enable hardware VSYNC and disable synthetic VSYNC.
EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, true)).Times(1);
+ setupDisableSyntheticVsyncCallExpectations(test);
+ }
+
+ static void setupDisableSyntheticVsyncCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(false)).Times(1);
}
static void setupDisableVsyncCallExpectations(DisplayTransactionTest* test) {
// Expect to disable hardware VSYNC and enable synthetic VSYNC.
EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, false)).Times(1);
+ setupEnableSyntheticVsyncCallExpectations(test);
+ }
+
+ static void setupEnableSyntheticVsyncCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(true)).Times(1);
}
};
@@ -151,7 +168,7 @@ struct TransitionOffToDozeSuspendVariant
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
- Case::EventThread::setupVsyncNoCallExpectations(test);
+ Case::EventThread::setupEnableSyntheticVsyncCallExpectations(test);
Case::setupRepaintEverythingCallExpectations(test);
}
@@ -176,7 +193,7 @@ struct TransitionDozeSuspendToOffVariant
: public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::OFF> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncNoCallExpectations(test);
+ Case::EventThread::setupEnableSyntheticVsyncCallExpectations(test);
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
}
@@ -188,7 +205,7 @@ struct TransitionDozeSuspendToOffVariant
struct TransitionOnToDozeVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncNoCallExpectations(test);
+ Case::EventThread::setupDisableSyntheticVsyncCallExpectations(test);
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
}
};
@@ -206,7 +223,7 @@ struct TransitionDozeSuspendToDozeVariant
struct TransitionDozeToOnVariant : public TransitionVariantCommon<PowerMode::DOZE, PowerMode::ON> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncNoCallExpectations(test);
+ Case::EventThread::setupDisableSyntheticVsyncCallExpectations(test);
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
}
};
@@ -234,7 +251,7 @@ struct TransitionOnToUnknownVariant
: public TransitionVariantCommon<PowerMode::ON, static_cast<PowerMode>(POWER_MODE_LEET)> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
- Case::EventThread::setupVsyncNoCallExpectations(test);
+ Case::EventThread::setupDisableSyntheticVsyncCallExpectations(test);
Case::setupNoComposerPowerModeCallExpectations(test);
}
};
@@ -335,6 +352,9 @@ void SetPhysicalDisplayPowerModeTest::transitionDisplayCommon() {
// --------------------------------------------------------------------
// Preconditions
+ SET_FLAG_FOR_TEST(android::companion::virtualdevice::flags::correct_virtual_display_power_state,
+ true);
+
Case::Doze::setupComposerCallExpectations(this);
auto display =
Case::injectDisplayWithInitialPowerMode(this, Case::Transition::INITIAL_POWER_MODE);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 13c32bdf08..c5973db109 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -519,8 +519,18 @@ public:
return mFlinger->mTransactionHandler.mPendingTransactionCount.load();
}
- auto setTransactionState(TransactionState&& state) {
- return mFlinger->setTransactionState(std::move(state));
+ auto setTransactionState(
+ const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& states,
+ Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
+ bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffers,
+ bool hasListenerCallbacks, std::vector<ListenerCallbacks>& listenerCallbacks,
+ uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) {
+ return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken,
+ inputWindowCommands, desiredPresentTime,
+ isAutoTimestamp, uncacheBuffers, hasListenerCallbacks,
+ listenerCallbacks, transactionId,
+ mergedTransactionIds);
}
auto setTransactionStateInternal(QueuedTransactionState& transaction) {
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 6a5ac2a70e..69dfcc4a8f 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -17,8 +17,6 @@
#undef LOG_TAG
#define LOG_TAG "TransactionApplicationTest"
-#include <cstdint>
-
#include <binder/Binder.h>
#include <common/test/FlagUtils.h>
#include <compositionengine/Display.h>
@@ -71,32 +69,38 @@ public:
TestableSurfaceFlinger mFlinger;
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
- struct TransactionInfo : public TransactionState {
- TransactionInfo() {
- mApplyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
- mId = static_cast<uint64_t>(-1);
- }
+ struct TransactionInfo {
+ Vector<ComposerState> states;
+ Vector<DisplayState> displays;
+ uint32_t flags = 0;
+ sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ InputWindowCommands inputWindowCommands;
+ int64_t desiredPresentTime = 0;
+ bool isAutoTimestamp = true;
+ FrameTimelineInfo frameTimelineInfo;
+ std::vector<client_cache_t> uncacheBuffers;
+ uint64_t id = static_cast<uint64_t>(-1);
+ std::vector<uint64_t> mergedTransactionIds;
+ static_assert(0xffffffffffffffff == static_cast<uint64_t>(-1));
};
void checkEqual(TransactionInfo info, QueuedTransactionState state) {
- EXPECT_EQ(0u, info.mComposerStates.size());
+ EXPECT_EQ(0u, info.states.size());
EXPECT_EQ(0u, state.states.size());
- EXPECT_EQ(0u, info.mDisplayStates.size());
+ EXPECT_EQ(0u, info.displays.size());
EXPECT_EQ(0u, state.displays.size());
- EXPECT_EQ(info.mFlags, state.flags);
- EXPECT_EQ(info.mDesiredPresentTime, state.desiredPresentTime);
+ EXPECT_EQ(info.flags, state.flags);
+ EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime);
}
void setupSingle(TransactionInfo& transaction, uint32_t flags, int64_t desiredPresentTime,
bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo) {
mTransactionNumber++;
- transaction.mFlags |= flags;
- transaction.mDesiredPresentTime = desiredPresentTime;
- transaction.mIsAutoTimestamp = isAutoTimestamp;
- transaction.mFrameTimelineInfo = frameTimelineInfo;
- transaction.mHasListenerCallbacks = mHasListenerCallbacks;
- transaction.mListenerCallbacks = mCallbacks;
+ transaction.flags |= flags;
+ transaction.desiredPresentTime = desiredPresentTime;
+ transaction.isAutoTimestamp = isAutoTimestamp;
+ transaction.frameTimelineInfo = frameTimelineInfo;
}
void NotPlacedOnTransactionQueue(uint32_t flags) {
@@ -107,7 +111,12 @@ public:
/*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true,
FrameTimelineInfo{});
nsecs_t applicationTime = systemTime();
- mFlinger.setTransactionState(std::move(transaction));
+ mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
+ transaction.displays, transaction.flags,
+ transaction.applyToken, transaction.inputWindowCommands,
+ transaction.desiredPresentTime, transaction.isAutoTimestamp,
+ transaction.uncacheBuffers, mHasListenerCallbacks, mCallbacks,
+ transaction.id, transaction.mergedTransactionIds);
// If transaction is synchronous, SF applyTransactionState should time out (5s) wating for
// SF to commit the transaction. If this is animation, it should not time out waiting.
@@ -129,7 +138,12 @@ public:
setupSingle(transaction, flags, /*desiredPresentTime*/ time + s2ns(1), false,
FrameTimelineInfo{});
nsecs_t applicationSentTime = systemTime();
- mFlinger.setTransactionState(std::move(transaction));
+ mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
+ transaction.displays, transaction.flags,
+ transaction.applyToken, transaction.inputWindowCommands,
+ transaction.desiredPresentTime, transaction.isAutoTimestamp,
+ transaction.uncacheBuffers, mHasListenerCallbacks, mCallbacks,
+ transaction.id, transaction.mergedTransactionIds);
nsecs_t returnedTime = systemTime();
EXPECT_LE(returnedTime, applicationSentTime + TRANSACTION_TIMEOUT);
@@ -155,7 +169,12 @@ public:
/*isAutoTimestamp*/ true, FrameTimelineInfo{});
nsecs_t applicationSentTime = systemTime();
- mFlinger.setTransactionState(std::move(transactionA));
+ mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
+ transactionA.displays, transactionA.flags,
+ transactionA.applyToken, transactionA.inputWindowCommands,
+ transactionA.desiredPresentTime, transactionA.isAutoTimestamp,
+ transactionA.uncacheBuffers, mHasListenerCallbacks, mCallbacks,
+ transactionA.id, transactionA.mergedTransactionIds);
// This thread should not have been blocked by the above transaction
// (5s is the timeout period that applyTransactionState waits for SF to
@@ -165,7 +184,12 @@ public:
mFlinger.flushTransactionQueues();
applicationSentTime = systemTime();
- mFlinger.setTransactionState(std::move(transactionB));
+ mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states,
+ transactionB.displays, transactionB.flags,
+ transactionB.applyToken, transactionB.inputWindowCommands,
+ transactionB.desiredPresentTime, transactionB.isAutoTimestamp,
+ transactionB.uncacheBuffers, mHasListenerCallbacks, mCallbacks,
+ transactionB.id, transactionB.mergedTransactionIds);
// this thread should have been blocked by the above transaction
// if this is an animation, this thread should be blocked for 5s
@@ -198,7 +222,12 @@ TEST_F(TransactionApplicationTest, AddToPendingQueue) {
TransactionInfo transactionA; // transaction to go on pending queue
setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ s2ns(1), false,
FrameTimelineInfo{});
- mFlinger.setTransactionState(std::move(transactionA));
+ mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
+ transactionA.displays, transactionA.flags, transactionA.applyToken,
+ transactionA.inputWindowCommands, transactionA.desiredPresentTime,
+ transactionA.isAutoTimestamp, transactionA.uncacheBuffers,
+ mHasListenerCallbacks, mCallbacks, transactionA.id,
+ transactionA.mergedTransactionIds);
auto& transactionQueue = mFlinger.getTransactionQueue();
ASSERT_FALSE(transactionQueue.isEmpty());
@@ -214,7 +243,12 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
TransactionInfo transactionA; // transaction to go on pending queue
setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ s2ns(1), false,
FrameTimelineInfo{});
- mFlinger.setTransactionState(std::move(transactionA));
+ mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states,
+ transactionA.displays, transactionA.flags, transactionA.applyToken,
+ transactionA.inputWindowCommands, transactionA.desiredPresentTime,
+ transactionA.isAutoTimestamp, transactionA.uncacheBuffers,
+ mHasListenerCallbacks, mCallbacks, transactionA.id,
+ transactionA.mergedTransactionIds);
auto& transactionQueue = mFlinger.getTransactionQueue();
ASSERT_FALSE(transactionQueue.isEmpty());
@@ -223,10 +257,12 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
// transaction here (sending a null applyToken to fake it as from a
// different process) to re-query and reset the cached expected present time
TransactionInfo empty;
- empty.mApplyToken = sp<IBinder>();
- empty.mHasListenerCallbacks = mHasListenerCallbacks;
- empty.mListenerCallbacks = mCallbacks;
- mFlinger.setTransactionState(std::move(empty));
+ empty.applyToken = sp<IBinder>();
+ mFlinger.setTransactionState(empty.frameTimelineInfo, empty.states, empty.displays, empty.flags,
+ empty.applyToken, empty.inputWindowCommands,
+ empty.desiredPresentTime, empty.isAutoTimestamp,
+ empty.uncacheBuffers, mHasListenerCallbacks, mCallbacks, empty.id,
+ empty.mergedTransactionIds);
// flush transaction queue should flush as desiredPresentTime has
// passed
@@ -370,9 +406,9 @@ public:
const auto kFrameTimelineInfo = FrameTimelineInfo{};
setupSingle(transaction, kFlags, kDesiredPresentTime, kIsAutoTimestamp, kFrameTimelineInfo);
- transaction.mApplyToken = applyToken;
+ transaction.applyToken = applyToken;
for (const auto& state : states) {
- transaction.mComposerStates.push_back(state);
+ transaction.states.push_back(state);
}
return transaction;
@@ -384,7 +420,7 @@ public:
EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size());
std::unordered_set<uint32_t> createdLayers;
for (auto transaction : transactions) {
- for (auto& state : transaction.mComposerStates) {
+ for (auto& state : transaction.states) {
auto layerId = static_cast<uint32_t>(state.state.layerId);
if (createdLayers.find(layerId) == createdLayers.end()) {
mFlinger.addLayer(layerId);
@@ -398,8 +434,8 @@ public:
for (auto transaction : transactions) {
std::vector<ResolvedComposerState> resolvedStates;
- resolvedStates.reserve(transaction.mComposerStates.size());
- for (auto& state : transaction.mComposerStates) {
+ resolvedStates.reserve(transaction.states.size());
+ for (auto& state : transaction.states) {
ResolvedComposerState resolvedState;
resolvedState.state = std::move(state.state);
resolvedState.externalTexture =
@@ -410,9 +446,15 @@ public:
resolvedStates.emplace_back(resolvedState);
}
- QueuedTransactionState transactionState(std::move(transaction),
- std::move(resolvedStates), {}, systemTime(),
- getpid(), static_cast<int>(getuid()));
+ QueuedTransactionState transactionState(transaction.frameTimelineInfo, resolvedStates,
+ transaction.displays, transaction.flags,
+ transaction.applyToken,
+ transaction.inputWindowCommands,
+ transaction.desiredPresentTime,
+ transaction.isAutoTimestamp, {}, systemTime(),
+ mHasListenerCallbacks, mCallbacks, getpid(),
+ static_cast<int>(getuid()), transaction.id,
+ transaction.mergedTransactionIds);
mFlinger.setTransactionStateInternal(transactionState);
}
mFlinger.flushTransactionQueues();
diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
index b36ad213c8..d3eec5c6f3 100644
--- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp
@@ -66,7 +66,7 @@ TEST(TransactionProtoParserTest, parse) {
display.token = nullptr;
}
display.width = 85;
- t1.displays.push_back(display);
+ t1.displays.add(display);
}
class TestMapper : public TransactionProtoParser::FlingerDataMapper {
diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp
index ed03cfc3f5..4b12cc20a4 100644
--- a/services/vibratorservice/Android.bp
+++ b/services/vibratorservice/Android.bp
@@ -26,6 +26,7 @@ cc_library_shared {
srcs: [
"VibratorCallbackScheduler.cpp",
+ "VibratorController.cpp",
"VibratorHalController.cpp",
"VibratorHalWrapper.cpp",
"VibratorManagerHalController.cpp",
@@ -41,17 +42,17 @@ cc_library_shared {
},
shared_libs: [
+ "android.hardware.vibrator-V3-ndk",
"libbinder_ndk",
"liblog",
"libutils",
- "android.hardware.vibrator-V3-ndk",
],
cflags: [
"-Wall",
"-Werror",
- "-Wunused",
"-Wunreachable-code",
+ "-Wunused",
],
local_include_dirs: ["include"],
diff --git a/services/vibratorservice/VibratorController.cpp b/services/vibratorservice/VibratorController.cpp
new file mode 100644
index 0000000000..21924e9f13
--- /dev/null
+++ b/services/vibratorservice/VibratorController.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VibratorController"
+
+#ifndef qDoWithRetries
+#define qDoWithRetries(op) doWithRetries(op, __FUNCTION__)
+#endif
+
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/Log.h>
+
+#include <vibratorservice/VibratorController.h>
+
+using ::aidl::android::hardware::vibrator::Effect;
+using ::aidl::android::hardware::vibrator::EffectStrength;
+using ::aidl::android::hardware::vibrator::IVibrator;
+
+using Status = ::ndk::ScopedAStatus;
+
+using namespace std::placeholders;
+
+namespace android {
+
+namespace vibrator {
+
+// -------------------------------------------------------------------------------------------------
+
+inline bool isStatusUnsupported(const Status& status) {
+ // STATUS_UNKNOWN_TRANSACTION means the HAL is an older version, so operation is unsupported.
+ return status.getStatus() == STATUS_UNKNOWN_TRANSACTION ||
+ status.getExceptionCode() == EX_UNSUPPORTED_OPERATION;
+}
+
+inline bool isStatusTransactionFailed(const Status& status) {
+ // STATUS_UNKNOWN_TRANSACTION means the HAL is an older version, so operation is unsupported.
+ return status.getStatus() != STATUS_UNKNOWN_TRANSACTION &&
+ status.getExceptionCode() == EX_TRANSACTION_FAILED;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+bool VibratorProvider::isDeclared() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mIsDeclared.has_value()) {
+ return *mIsDeclared;
+ }
+
+ bool isDeclared = AServiceManager_isDeclared(mServiceName.c_str());
+ if (!isDeclared) {
+ ALOGV("Vibrator HAL service not declared.");
+ }
+
+ mIsDeclared.emplace(isDeclared);
+ return isDeclared;
+}
+
+std::shared_ptr<IVibrator> VibratorProvider::waitForVibrator() {
+ if (!isDeclared()) {
+ return nullptr;
+ }
+
+ auto vibrator = IVibrator::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(mServiceName.c_str())));
+ if (vibrator) {
+ ALOGV("Successfully connected to Vibrator HAL service.");
+ } else {
+ ALOGE("Error connecting to declared Vibrator HAL service.");
+ }
+
+ return vibrator;
+}
+
+std::shared_ptr<IVibrator> VibratorProvider::checkForVibrator() {
+ if (!isDeclared()) {
+ return nullptr;
+ }
+
+ auto vibrator = IVibrator::fromBinder(
+ ndk::SpAIBinder(AServiceManager_checkService(mServiceName.c_str())));
+ if (vibrator) {
+ ALOGV("Successfully reconnected to Vibrator HAL service.");
+ } else {
+ ALOGE("Error reconnecting to declared Vibrator HAL service.");
+ }
+
+ return vibrator;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+bool VibratorController::init() {
+ if (!mVibratorProvider->isDeclared()) {
+ return false;
+ }
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mVibrator == nullptr) {
+ mVibrator = mVibratorProvider->waitForVibrator();
+ }
+ return mVibratorProvider->isDeclared();
+}
+
+Status VibratorController::off() {
+ return qDoWithRetries(std::bind(&IVibrator::off, _1));
+}
+
+Status VibratorController::setAmplitude(float amplitude) {
+ return qDoWithRetries(std::bind(&IVibrator::setAmplitude, _1, amplitude));
+}
+
+Status VibratorController::setExternalControl(bool enabled) {
+ return qDoWithRetries(std::bind(&IVibrator::setExternalControl, _1, enabled));
+}
+
+Status VibratorController::alwaysOnEnable(int32_t id, const Effect& effect,
+ const EffectStrength& strength) {
+ return qDoWithRetries(std::bind(&IVibrator::alwaysOnEnable, _1, id, effect, strength));
+}
+
+Status VibratorController::alwaysOnDisable(int32_t id) {
+ return qDoWithRetries(std::bind(&IVibrator::alwaysOnDisable, _1, id));
+}
+
+// -------------------------------------------------------------------------------------------------
+
+std::shared_ptr<IVibrator> VibratorController::reconnectToVibrator() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mVibrator = mVibratorProvider->checkForVibrator();
+ return mVibrator;
+}
+
+Status VibratorController::doWithRetries(const VibratorController::VibratorOp& op,
+ const char* logLabel) {
+ if (!init()) {
+ ALOGV("Skipped %s because Vibrator HAL is not declared", logLabel);
+ return Status::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, "IVibrator not declared");
+ }
+ std::shared_ptr<IVibrator> vibrator;
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ vibrator = mVibrator;
+ }
+
+ if (!vibrator) {
+ ALOGE("Skipped %s because Vibrator HAL is declared but failed to load", logLabel);
+ return Status::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE,
+ "IVibrator declared but failed to load");
+ }
+
+ auto status = doOnce(vibrator.get(), op, logLabel);
+ for (int i = 1; i < MAX_ATTEMPTS && isStatusTransactionFailed(status); i++) {
+ vibrator = reconnectToVibrator();
+ if (!vibrator) {
+ // Failed to reconnect to vibrator HAL after a transaction failed, skip retries.
+ break;
+ }
+ status = doOnce(vibrator.get(), op, logLabel);
+ }
+
+ return status;
+}
+
+Status VibratorController::doOnce(IVibrator* vibrator, const VibratorController::VibratorOp& op,
+ const char* logLabel) {
+ auto status = op(vibrator);
+ if (!status.isOk()) {
+ if (isStatusUnsupported(status)) {
+ ALOGV("Vibrator HAL %s is unsupported: %s", logLabel, status.getMessage());
+ } else {
+ ALOGE("Vibrator HAL %s failed: %s", logLabel, status.getMessage());
+ }
+ }
+ return status;
+}
+
+// -------------------------------------------------------------------------------------------------
+
+}; // namespace vibrator
+
+}; // namespace android
diff --git a/services/vibratorservice/include/vibratorservice/VibratorController.h b/services/vibratorservice/include/vibratorservice/VibratorController.h
new file mode 100644
index 0000000000..691c8ae518
--- /dev/null
+++ b/services/vibratorservice/include/vibratorservice/VibratorController.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2025 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.
+ */
+
+#ifndef ANDROID_OS_VIBRATOR_CONTROLLER_H
+#define ANDROID_OS_VIBRATOR_CONTROLLER_H
+
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+
+#include <android-base/thread_annotations.h>
+
+namespace android {
+
+namespace vibrator {
+
+// -------------------------------------------------------------------------------------------------
+
+/* Provider for IVibrator HAL service instances. */
+class VibratorProvider {
+public:
+ using IVibrator = ::aidl::android::hardware::vibrator::IVibrator;
+
+ VibratorProvider() : mServiceName(std::string(IVibrator::descriptor) + "/default") {}
+ virtual ~VibratorProvider() = default;
+
+ /* Returns true if vibrator HAL service is declared in the device, false otherwise. */
+ virtual bool isDeclared();
+
+ /* Connects to vibrator HAL, possibly waiting for the declared service to become available. */
+ virtual std::shared_ptr<IVibrator> waitForVibrator();
+
+ /* Connects to vibrator HAL if declared and available, without waiting. */
+ virtual std::shared_ptr<IVibrator> checkForVibrator();
+
+private:
+ std::mutex mMutex;
+ const std::string mServiceName;
+ std::optional<bool> mIsDeclared GUARDED_BY(mMutex);
+};
+
+// -------------------------------------------------------------------------------------------------
+
+/* Controller for Vibrator HAL handle.
+ * This relies on VibratorProvider to connect to the underlying Vibrator HAL service and reconnects
+ * after each transaction failed call. This also ensures connecting to the service is thread-safe.
+ */
+class VibratorController {
+public:
+ using Effect = ::aidl::android::hardware::vibrator::Effect;
+ using EffectStrength = ::aidl::android::hardware::vibrator::EffectStrength;
+ using IVibrator = ::aidl::android::hardware::vibrator::IVibrator;
+ using Status = ::ndk::ScopedAStatus;
+ using VibratorOp = std::function<Status(IVibrator*)>;
+
+ VibratorController() : VibratorController(std::make_shared<VibratorProvider>()) {}
+ VibratorController(std::shared_ptr<VibratorProvider> vibratorProvider)
+ : mVibratorProvider(std::move(vibratorProvider)), mVibrator(nullptr) {}
+ virtual ~VibratorController() = default;
+
+ /* Connects HAL service, possibly waiting for the declared service to become available.
+ * This will automatically be called at the first API usage if it was not manually called
+ * beforehand. Call this manually during the setup phase to avoid slowing the first API call.
+ * Returns true if HAL service is declared, false otherwise.
+ */
+ bool init();
+
+ /* Turn vibrator off. */
+ Status off();
+
+ /* Set vibration amplitude in [0,1]. */
+ Status setAmplitude(float amplitude);
+
+ /* Enable/disable external control. */
+ Status setExternalControl(bool enabled);
+
+ /* Enable always-on for given id, with given effect and strength. */
+ Status alwaysOnEnable(int32_t id, const Effect& effect, const EffectStrength& strength);
+
+ /* Disable always-on for given id. */
+ Status alwaysOnDisable(int32_t id);
+
+private:
+ /* Max number of attempts to perform an operation when it fails with transaction error. */
+ static constexpr int MAX_ATTEMPTS = 2;
+
+ std::mutex mMutex;
+ std::shared_ptr<VibratorProvider> mVibratorProvider;
+ std::shared_ptr<IVibrator> mVibrator GUARDED_BY(mMutex);
+
+ /* Reconnects HAL service without waiting for the service to become available. */
+ std::shared_ptr<IVibrator> reconnectToVibrator();
+
+ /* Perform given operation on HAL with retries on transaction failures. */
+ Status doWithRetries(const VibratorOp& op, const char* logLabel);
+
+ /* Perform given operation on HAL with logs for error/unsupported results. */
+ static Status doOnce(IVibrator* vibrator, const VibratorOp& op, const char* logLabel);
+};
+
+// -------------------------------------------------------------------------------------------------
+
+}; // namespace vibrator
+
+}; // namespace android
+
+#endif // ANDROID_OS_VIBRATOR_CONTROLLER_H
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
index a1cb3fad35..9b3202bc60 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+// TODO(b/308452413): remove this file once android.os.vibrator.remove_hidl_support is removed
+
#ifndef ANDROID_OS_VIBRATORHALCONTROLLER_H
#define ANDROID_OS_VIBRATORHALCONTROLLER_H
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 065227861d..68568d4163 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+// TODO(b/308452413): remove this file once android.os.vibrator.remove_hidl_support is removed
+
#ifndef ANDROID_OS_VIBRATORHALWRAPPER_H
#define ANDROID_OS_VIBRATORHALWRAPPER_H
diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp
index 038248e636..92c6286513 100644
--- a/services/vibratorservice/test/Android.bp
+++ b/services/vibratorservice/test/Android.bp
@@ -27,6 +27,7 @@ cc_test {
test_suites: ["device-tests"],
srcs: [
"VibratorCallbackSchedulerTest.cpp",
+ "VibratorControllerTest.cpp",
"VibratorHalControllerTest.cpp",
"VibratorHalWrapperAidlTest.cpp",
"VibratorManagerHalControllerTest.cpp",
@@ -39,12 +40,12 @@ cc_test {
"-Wextra",
],
shared_libs: [
+ "android.hardware.vibrator-V3-ndk",
"libbase",
"libbinder_ndk",
"liblog",
- "libvibratorservice",
"libutils",
- "android.hardware.vibrator-V3-ndk",
+ "libvibratorservice",
],
static_libs: [
"libgmock",
diff --git a/services/vibratorservice/test/VibratorControllerTest.cpp b/services/vibratorservice/test/VibratorControllerTest.cpp
new file mode 100644
index 0000000000..11ec75bc36
--- /dev/null
+++ b/services/vibratorservice/test/VibratorControllerTest.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VibratorControllerTest"
+
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+#include <thread>
+
+#include <vibratorservice/VibratorController.h>
+
+#include "test_mocks.h"
+#include "test_utils.h"
+
+using ::aidl::android::hardware::vibrator::Effect;
+using ::aidl::android::hardware::vibrator::EffectStrength;
+using ::aidl::android::hardware::vibrator::IVibrator;
+
+using namespace android;
+using namespace testing;
+
+const auto kReturnOk = []() { return ndk::ScopedAStatus::ok(); };
+const auto kReturnUnsupported = []() {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+};
+const auto kReturnTransactionFailed = []() {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+};
+const auto kReturnUnknownTransaction = []() {
+ return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_TRANSACTION);
+};
+const auto kReturnIllegalArgument = []() {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+};
+
+// -------------------------------------------------------------------------------------------------
+
+/* Provides mock IVibrator instance for testing. */
+class FakeVibratorProvider : public vibrator::VibratorProvider {
+public:
+ FakeVibratorProvider()
+ : mIsDeclared(true),
+ mMockVibrator(ndk::SharedRefBase::make<StrictMock<vibrator::MockIVibrator>>()),
+ mConnectCount(0),
+ mReconnectCount(0) {}
+ virtual ~FakeVibratorProvider() = default;
+
+ bool isDeclared() override { return mIsDeclared; }
+
+ std::shared_ptr<IVibrator> waitForVibrator() override {
+ mConnectCount++;
+ return mIsDeclared ? mMockVibrator : nullptr;
+ }
+
+ std::shared_ptr<IVibrator> checkForVibrator() override {
+ mReconnectCount++;
+ return mIsDeclared ? mMockVibrator : nullptr;
+ }
+
+ void setDeclared(bool isDeclared) { mIsDeclared = isDeclared; }
+
+ int32_t getConnectCount() { return mConnectCount; }
+
+ int32_t getReconnectCount() { return mReconnectCount; }
+
+ std::shared_ptr<StrictMock<vibrator::MockIVibrator>> getMockVibrator() { return mMockVibrator; }
+
+private:
+ bool mIsDeclared;
+ std::shared_ptr<StrictMock<vibrator::MockIVibrator>> mMockVibrator;
+ int32_t mConnectCount;
+ int32_t mReconnectCount;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class VibratorControllerTest : public Test {
+public:
+ void SetUp() override {
+ mProvider = std::make_shared<FakeVibratorProvider>();
+ mController = std::make_unique<vibrator::VibratorController>(mProvider);
+ ASSERT_NE(mController, nullptr);
+ }
+
+protected:
+ std::shared_ptr<FakeVibratorProvider> mProvider = nullptr;
+ std::unique_ptr<vibrator::VibratorController> mController = nullptr;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(VibratorControllerTest, TestInitServiceDeclared) {
+ ASSERT_TRUE(mController->init());
+ ASSERT_EQ(1, mProvider->getConnectCount());
+ ASSERT_EQ(0, mProvider->getReconnectCount());
+
+ // Noop when wrapper was already initialized.
+ ASSERT_TRUE(mController->init());
+ ASSERT_EQ(1, mProvider->getConnectCount());
+ ASSERT_EQ(0, mProvider->getReconnectCount());
+}
+
+TEST_F(VibratorControllerTest, TestInitServiceNotDeclared) {
+ mProvider->setDeclared(false);
+
+ ASSERT_FALSE(mController->init());
+ ASSERT_EQ(0, mProvider->getConnectCount());
+ ASSERT_EQ(0, mProvider->getReconnectCount());
+
+ ASSERT_FALSE(mController->init());
+ ASSERT_EQ(0, mProvider->getConnectCount());
+ ASSERT_EQ(0, mProvider->getReconnectCount());
+}
+
+TEST_F(VibratorControllerTest, TestFirstCallTriggersInit) {
+ EXPECT_CALL(*mProvider->getMockVibrator().get(), off())
+ .Times(Exactly(1))
+ .WillRepeatedly(kReturnOk);
+
+ auto status = mController->off();
+ ASSERT_TRUE(status.isOk());
+ ASSERT_EQ(1, mProvider->getConnectCount());
+}
+
+TEST_F(VibratorControllerTest, TestSuccessfulResultDoesNotRetry) {
+ EXPECT_CALL(*mProvider->getMockVibrator().get(), off())
+ .Times(Exactly(1))
+ .WillRepeatedly(kReturnOk);
+
+ auto status = mController->off();
+ ASSERT_TRUE(status.isOk());
+ ASSERT_EQ(0, mProvider->getReconnectCount());
+}
+
+TEST_F(VibratorControllerTest, TestUnsupportedOperationResultDoesNotRetry) {
+ EXPECT_CALL(*mProvider->getMockVibrator().get(), off())
+ .Times(Exactly(1))
+ .WillRepeatedly(kReturnUnsupported);
+
+ auto status = mController->off();
+ ASSERT_FALSE(status.isOk());
+ ASSERT_EQ(0, mProvider->getReconnectCount());
+}
+
+TEST_F(VibratorControllerTest, TestUnknownTransactionResultDoesNotRetry) {
+ EXPECT_CALL(*mProvider->getMockVibrator().get(), off())
+ .Times(Exactly(1))
+ .WillRepeatedly(kReturnUnknownTransaction);
+
+ auto status = mController->off();
+ ASSERT_FALSE(status.isOk());
+ ASSERT_EQ(0, mProvider->getReconnectCount());
+}
+
+TEST_F(VibratorControllerTest, TestOperationFailedDoesNotRetry) {
+ EXPECT_CALL(*mProvider->getMockVibrator().get(), off())
+ .Times(Exactly(1))
+ .WillRepeatedly(kReturnIllegalArgument);
+
+ auto status = mController->off();
+ ASSERT_FALSE(status.isOk());
+ ASSERT_EQ(0, mProvider->getReconnectCount());
+}
+
+TEST_F(VibratorControllerTest, TestTransactionFailedRetriesOnlyOnce) {
+ EXPECT_CALL(*mProvider->getMockVibrator().get(), off())
+ .Times(Exactly(2))
+ .WillRepeatedly(kReturnTransactionFailed);
+
+ auto status = mController->off();
+ ASSERT_FALSE(status.isOk());
+ ASSERT_EQ(1, mProvider->getReconnectCount());
+}
+
+TEST_F(VibratorControllerTest, TestTransactionFailedThenSucceedsReturnsSuccessAfterRetries) {
+ EXPECT_CALL(*mProvider->getMockVibrator().get(), off())
+ .Times(Exactly(2))
+ .WillOnce(kReturnTransactionFailed)
+ .WillRepeatedly(kReturnOk);
+
+ auto status = mController->off();
+ ASSERT_TRUE(status.isOk());
+ ASSERT_EQ(1, mProvider->getReconnectCount());
+}
+
+TEST_F(VibratorControllerTest, TestOff) {
+ EXPECT_CALL(*mProvider->getMockVibrator().get(), off())
+ .Times(Exactly(1))
+ .WillRepeatedly(kReturnOk);
+
+ auto status = mController->off();
+ ASSERT_TRUE(status.isOk());
+}
+
+TEST_F(VibratorControllerTest, TestSetAmplitude) {
+ EXPECT_CALL(*mProvider->getMockVibrator().get(), setAmplitude(Eq(0.1f)))
+ .Times(Exactly(1))
+ .WillRepeatedly(kReturnOk);
+ EXPECT_CALL(*mProvider->getMockVibrator().get(), setAmplitude(Eq(0.2f)))
+ .Times(Exactly(1))
+ .WillRepeatedly(kReturnIllegalArgument);
+
+ ASSERT_TRUE(mController->setAmplitude(0.1f).isOk());
+ ASSERT_FALSE(mController->setAmplitude(0.2f).isOk());
+}
+
+TEST_F(VibratorControllerTest, TestSetExternalControl) {
+ EXPECT_CALL(*mProvider->getMockVibrator().get(), setExternalControl(Eq(false)))
+ .Times(Exactly(1))
+ .WillRepeatedly(kReturnOk);
+ EXPECT_CALL(*mProvider->getMockVibrator().get(), setExternalControl(Eq(true)))
+ .Times(Exactly(1))
+ .WillRepeatedly(kReturnIllegalArgument);
+
+ ASSERT_TRUE(mController->setExternalControl(false).isOk());
+ ASSERT_FALSE(mController->setExternalControl(true).isOk());
+}
+
+TEST_F(VibratorControllerTest, TestAlwaysOnEnable) {
+ EXPECT_CALL(*mProvider->getMockVibrator().get(),
+ alwaysOnEnable(Eq(1), Eq(Effect::CLICK), Eq(EffectStrength::LIGHT)))
+ .Times(Exactly(1))
+ .WillRepeatedly(kReturnOk);
+ EXPECT_CALL(*mProvider->getMockVibrator().get(),
+ alwaysOnEnable(Eq(2), Eq(Effect::TICK), Eq(EffectStrength::MEDIUM)))
+ .Times(Exactly(1))
+ .WillRepeatedly(kReturnIllegalArgument);
+
+ ASSERT_TRUE(mController->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isOk());
+ ASSERT_FALSE(mController->alwaysOnEnable(2, Effect::TICK, EffectStrength::MEDIUM).isOk());
+}
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index be8fb3ea1d..d75058abe3 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -48,14 +48,9 @@ cc_aconfig_library {
aconfig_declarations: "libvulkan_flags",
}
-cc_library_shared {
- name: "libvulkan",
- llndk: {
- symbol_file: "libvulkan.map.txt",
- export_llndk_headers: [
- "vulkan_headers",
- ],
- },
+cc_defaults {
+ name: "libvulkan_defaults",
+
sanitize: {
misc_undefined: ["integer"],
},
@@ -88,6 +83,34 @@ cc_library_shared {
"-Wno-global-constructors",
"-Wno-zero-length-array",
],
+}
+
+cc_library {
+ name: "libvulkanallocator",
+ defaults: ["libvulkan_defaults"],
+ cflags: [
+ // This code uses malloc_usable_size(),
+ // and thus can't be built with _FORTIFY_SOURCE=3.
+ "-U_FORTIFY_SOURCE",
+ "-D_FORTIFY_SOURCE=2",
+ ],
+ srcs: [
+ "allocator.cpp",
+ ],
+ header_libs: [
+ "vulkan_headers",
+ ],
+}
+
+cc_library_shared {
+ name: "libvulkan",
+ defaults: ["libvulkan_defaults"],
+ llndk: {
+ symbol_file: "libvulkan.map.txt",
+ export_llndk_headers: [
+ "vulkan_headers",
+ ],
+ },
srcs: [
"api.cpp",
@@ -131,6 +154,7 @@ cc_library_shared {
],
static_libs: [
"libgrallocusage",
+ "libvulkanallocator",
"libvulkanflags",
],
}
diff --git a/vulkan/libvulkan/allocator.cpp b/vulkan/libvulkan/allocator.cpp
new file mode 100644
index 0000000000..2ca0586a14
--- /dev/null
+++ b/vulkan/libvulkan/allocator.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "allocator.h"
+
+#include <stdlib.h>
+
+#include <algorithm>
+
+#include <log/log.h>
+
+// #define ENABLE_ALLOC_CALLSTACKS 1
+#if ENABLE_ALLOC_CALLSTACKS
+#include <utils/CallStack.h>
+#define ALOGD_CALLSTACK(...) \
+ do { \
+ ALOGD(__VA_ARGS__); \
+ android::CallStack callstack; \
+ callstack.update(); \
+ callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, " "); \
+ } while (false)
+#else
+#define ALOGD_CALLSTACK(...) \
+ do { \
+ } while (false)
+#endif
+
+namespace vulkan {
+namespace driver {
+
+namespace {
+
+VKAPI_ATTR void* DefaultAllocate(void*,
+ size_t size,
+ size_t alignment,
+ VkSystemAllocationScope) {
+ void* ptr = nullptr;
+ // Vulkan requires 'alignment' to be a power of two, but posix_memalign
+ // additionally requires that it be at least sizeof(void*).
+ int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size);
+ ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment,
+ ret, ptr);
+ return ret == 0 ? ptr : nullptr;
+}
+
+// This function is marked `noinline` so that LLVM can't infer an object size
+// for FORTIFY through it, given that it's abusing malloc_usable_size().
+__attribute__((__noinline__))
+VKAPI_ATTR void* DefaultReallocate(void*,
+ void* ptr,
+ size_t size,
+ size_t alignment,
+ VkSystemAllocationScope) {
+ if (size == 0) {
+ free(ptr);
+ return nullptr;
+ }
+
+ // TODO(b/143295633): Right now we never shrink allocations; if the new
+ // request is smaller than the existing chunk, we just continue using it.
+ // Right now the loader never reallocs, so this doesn't matter. If that
+ // changes, or if this code is copied into some other project, this should
+ // probably have a heuristic to allocate-copy-free when doing so will save
+ // "enough" space.
+ size_t old_size = ptr ? malloc_usable_size(ptr) : 0;
+ if (size <= old_size)
+ return ptr;
+
+ void* new_ptr = nullptr;
+ if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0)
+ return nullptr;
+ if (ptr) {
+ memcpy(new_ptr, ptr, std::min(old_size, size));
+ free(ptr);
+ }
+ return new_ptr;
+}
+
+VKAPI_ATTR void DefaultFree(void*, void* ptr) {
+ ALOGD_CALLSTACK("Free: %p", ptr);
+ free(ptr);
+}
+
+} // anonymous namespace
+
+const VkAllocationCallbacks& GetDefaultAllocator() {
+ static const VkAllocationCallbacks kDefaultAllocCallbacks = {
+ .pUserData = nullptr,
+ .pfnAllocation = DefaultAllocate,
+ .pfnReallocation = DefaultReallocate,
+ .pfnFree = DefaultFree,
+ };
+
+ return kDefaultAllocCallbacks;
+}
+
+} // namespace driver
+} // namespace vulkan
diff --git a/vulkan/libvulkan/allocator.h b/vulkan/libvulkan/allocator.h
new file mode 100644
index 0000000000..9095e921c5
--- /dev/null
+++ b/vulkan/libvulkan/allocator.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vulkan/vulkan.h>
+
+namespace vulkan {
+namespace driver {
+
+const VkAllocationCallbacks& GetDefaultAllocator();
+
+} // namespace driver
+} // namespace vulkan
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 7d0f545774..28c1b5f663 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -50,22 +50,6 @@ using namespace com::android::graphics::libvulkan;
extern "C" android_namespace_t* android_get_exported_namespace(const char*);
-// #define ENABLE_ALLOC_CALLSTACKS 1
-#if ENABLE_ALLOC_CALLSTACKS
-#include <utils/CallStack.h>
-#define ALOGD_CALLSTACK(...) \
- do { \
- ALOGD(__VA_ARGS__); \
- android::CallStack callstack; \
- callstack.update(); \
- callstack.log(LOG_TAG, ANDROID_LOG_DEBUG, " "); \
- } while (false)
-#else
-#define ALOGD_CALLSTACK(...) \
- do { \
- } while (false)
-#endif
-
namespace vulkan {
namespace driver {
@@ -829,54 +813,6 @@ void CreateInfoWrapper::FilterExtension(const char* name) {
}
}
-VKAPI_ATTR void* DefaultAllocate(void*,
- size_t size,
- size_t alignment,
- VkSystemAllocationScope) {
- void* ptr = nullptr;
- // Vulkan requires 'alignment' to be a power of two, but posix_memalign
- // additionally requires that it be at least sizeof(void*).
- int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size);
- ALOGD_CALLSTACK("Allocate: size=%zu align=%zu => (%d) %p", size, alignment,
- ret, ptr);
- return ret == 0 ? ptr : nullptr;
-}
-
-VKAPI_ATTR void* DefaultReallocate(void*,
- void* ptr,
- size_t size,
- size_t alignment,
- VkSystemAllocationScope) {
- if (size == 0) {
- free(ptr);
- return nullptr;
- }
-
- // TODO(b/143295633): Right now we never shrink allocations; if the new
- // request is smaller than the existing chunk, we just continue using it.
- // Right now the loader never reallocs, so this doesn't matter. If that
- // changes, or if this code is copied into some other project, this should
- // probably have a heuristic to allocate-copy-free when doing so will save
- // "enough" space.
- size_t old_size = ptr ? malloc_usable_size(ptr) : 0;
- if (size <= old_size)
- return ptr;
-
- void* new_ptr = nullptr;
- if (posix_memalign(&new_ptr, std::max(alignment, sizeof(void*)), size) != 0)
- return nullptr;
- if (ptr) {
- memcpy(new_ptr, ptr, std::min(old_size, size));
- free(ptr);
- }
- return new_ptr;
-}
-
-VKAPI_ATTR void DefaultFree(void*, void* ptr) {
- ALOGD_CALLSTACK("Free: %p", ptr);
- free(ptr);
-}
-
InstanceData* AllocateInstanceData(const VkAllocationCallbacks& allocator) {
void* data_mem = allocator.pfnAllocation(
allocator.pUserData, sizeof(InstanceData), alignof(InstanceData),
@@ -916,17 +852,6 @@ bool OpenHAL() {
return Hal::Open();
}
-const VkAllocationCallbacks& GetDefaultAllocator() {
- static const VkAllocationCallbacks kDefaultAllocCallbacks = {
- .pUserData = nullptr,
- .pfnAllocation = DefaultAllocate,
- .pfnReallocation = DefaultReallocate,
- .pfnFree = DefaultFree,
- };
-
- return kDefaultAllocCallbacks;
-}
-
PFN_vkVoidFunction GetInstanceProcAddr(VkInstance instance, const char* pName) {
const ProcHook* hook = GetProcHook(pName);
if (!hook)
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 4b855e5999..fa85dd5b55 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -27,6 +27,7 @@
#include <vulkan/vulkan.h>
#include <hardware/hwvulkan.h>
+#include "allocator.h"
#include "api_gen.h"
#include "driver_gen.h"
#include "debug_report.h"
@@ -102,7 +103,6 @@ struct DeviceData {
};
bool OpenHAL();
-const VkAllocationCallbacks& GetDefaultAllocator();
void QueryPresentationProperties(
VkPhysicalDevice physicalDevice,