Merge "Force snapshot update when requested transform changes from invalid to valid" into main
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 07d16f7..a4a22a0 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -22,5 +22,21 @@
{
"name": "SurfaceFlinger_test"
}
+ ],
+ "postsubmit": [
+ {
+ "name": "SurfaceFlinger_test",
+ "keywords": [ "primary-device" ],
+ "options": [
+ // TODO(b/328119950) Known to be broken.
+ {
+ "exclude-filter": "LayerCallbackTest#SetNullBuffer"
+ },
+ // TODO(b/398306512) Flaky on real device.
+ {
+ "exclude-filter": "LayerRenderTypeTransactionTests/LayerRenderTypeTransactionTest#SetRelativeZBasic_BufferQueue/*"
+ }
+ ]
+ }
]
}
diff --git a/cmds/dumpstate/res/default_screenshot.png b/cmds/dumpstate/res/default_screenshot.png
index 10f36aa..1e14306 100644
--- a/cmds/dumpstate/res/default_screenshot.png
+++ b/cmds/dumpstate/res/default_screenshot.png
Binary files differ
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 77e7328..6e6d27d 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -202,26 +202,13 @@
}
bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h,
- sp<GLConsumer>* glConsumer, EGLSurface* surface) {
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- sp<GLConsumer> glc = new GLConsumer(name, GL_TEXTURE_EXTERNAL_OES, false, true);
+ sp<GLConsumer>* glConsumer, EGLSurface* surface) {
+ auto [glc, surf] = GLConsumer::create(name, GL_TEXTURE_EXTERNAL_OES, false, true);
glc->setDefaultBufferSize(w, h);
- glc->getSurface()->setMaxDequeuedBufferCount(2);
glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
+ surf->setMaxDequeuedBufferCount(2);
+ sp<ANativeWindow> anw = surf;
- sp<ANativeWindow> anw = glc->getSurface();
-#else
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
- sp<GLConsumer> glc = new GLConsumer(consumer, name,
- GL_TEXTURE_EXTERNAL_OES, false, true);
- glc->setDefaultBufferSize(w, h);
- producer->setMaxDequeuedBufferCount(2);
- glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
-
- sp<ANativeWindow> anw = new Surface(producer);
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
if (s == EGL_NO_SURFACE) {
fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 36dcbca..b87ef2d 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -25,13 +25,8 @@
name: "idlcli-defaults",
shared_libs: [
"android.hardware.vibrator-V3-ndk",
- "android.hardware.vibrator@1.0",
- "android.hardware.vibrator@1.1",
- "android.hardware.vibrator@1.2",
- "android.hardware.vibrator@1.3",
"libbase",
"libbinder_ndk",
- "libhidlbase",
"liblog",
"libutils",
],
diff --git a/cmds/idlcli/utils.h b/cmds/idlcli/utils.h
index 262f2e5..dc52c57 100644
--- a/cmds/idlcli/utils.h
+++ b/cmds/idlcli/utils.h
@@ -18,7 +18,6 @@
#define FRAMEWORK_NATIVE_CMDS_IDLCLI_UTILS_H_
#include <android/binder_enums.h>
-#include <hidl/HidlSupport.h>
#include <iomanip>
#include <iostream>
diff --git a/cmds/idlcli/vibrator.h b/cmds/idlcli/vibrator.h
index b943495..1a9993e 100644
--- a/cmds/idlcli/vibrator.h
+++ b/cmds/idlcli/vibrator.h
@@ -22,102 +22,30 @@
#include <aidl/android/hardware/vibrator/IVibratorManager.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
-#include <android/hardware/vibrator/1.3/IVibrator.h>
#include "IdlCli.h"
#include "utils.h"
namespace android {
-using hardware::Return;
+using ::aidl::android::hardware::vibrator::IVibrator;
using idlcli::IdlCli;
-static constexpr int NUM_TRIES = 2;
-
-// Creates a Return<R> with STATUS::EX_NULL_POINTER.
-template <class R>
-inline R NullptrStatus() {
- using ::android::hardware::Status;
- return Status::fromExceptionCode(Status::EX_NULL_POINTER);
-}
-
-template <>
-inline ndk::ScopedAStatus NullptrStatus() {
- return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_NULL_POINTER));
-}
-
-template <typename I>
inline auto getService(std::string name) {
- const auto instance = std::string() + I::descriptor + "/" + name;
+ const auto instance = std::string() + IVibrator::descriptor + "/" + name;
auto vibBinder = ndk::SpAIBinder(AServiceManager_checkService(instance.c_str()));
- return I::fromBinder(vibBinder);
+ return IVibrator::fromBinder(vibBinder);
}
-template <>
-inline auto getService<android::hardware::vibrator::V1_0::IVibrator>(std::string name) {
- return android::hardware::vibrator::V1_0::IVibrator::getService(name);
-}
-
-template <>
-inline auto getService<android::hardware::vibrator::V1_1::IVibrator>(std::string name) {
- return android::hardware::vibrator::V1_1::IVibrator::getService(name);
-}
-
-template <>
-inline auto getService<android::hardware::vibrator::V1_2::IVibrator>(std::string name) {
- return android::hardware::vibrator::V1_2::IVibrator::getService(name);
-}
-
-template <>
-inline auto getService<android::hardware::vibrator::V1_3::IVibrator>(std::string name) {
- return android::hardware::vibrator::V1_3::IVibrator::getService(name);
-}
-
-template <typename I>
-using shared_ptr = std::invoke_result_t<decltype(getService<I>)&, std::string>;
-
-template <typename I>
-class HalWrapper {
-public:
- static std::unique_ptr<HalWrapper> Create() {
- // Assume that if getService returns a nullptr, HAL is not available on the
- // device.
- const auto name = IdlCli::Get().getName();
- auto hal = getService<I>(name.empty() ? "default" : name);
- return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr;
- }
-
- template <class R, class... Args0, class... Args1>
- R call(R (I::*fn)(Args0...), Args1&&... args1) {
- return (*mHal.*fn)(std::forward<Args1>(args1)...);
- }
-
-private:
- HalWrapper(shared_ptr<I>&& hal) : mHal(std::move(hal)) {}
-
-private:
- shared_ptr<I> mHal;
-};
-
-template <typename I>
static auto getHal() {
- static auto sHalWrapper = HalWrapper<I>::Create();
- return sHalWrapper.get();
-}
-
-template <class R, class I, class... Args0, class... Args1>
-R halCall(R (I::*fn)(Args0...), Args1&&... args1) {
- auto hal = getHal<I>();
- return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>();
+ // Assume that if getService returns a nullptr, HAL is not available on the device.
+ const auto name = IdlCli::Get().getName();
+ return getService(name.empty() ? "default" : name);
}
namespace idlcli {
namespace vibrator {
-namespace V1_0 = ::android::hardware::vibrator::V1_0;
-namespace V1_1 = ::android::hardware::vibrator::V1_1;
-namespace V1_2 = ::android::hardware::vibrator::V1_2;
-namespace V1_3 = ::android::hardware::vibrator::V1_3;
namespace aidl = ::aidl::android::hardware::vibrator;
class VibratorCallback : public aidl::BnVibratorCallback {
diff --git a/cmds/idlcli/vibrator/CommandAlwaysOnDisable.cpp b/cmds/idlcli/vibrator/CommandAlwaysOnDisable.cpp
index 9afa300..cae6909 100644
--- a/cmds/idlcli/vibrator/CommandAlwaysOnDisable.cpp
+++ b/cmds/idlcli/vibrator/CommandAlwaysOnDisable.cpp
@@ -51,21 +51,17 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::alwaysOnDisable, mId);
-
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ auto status = hal->alwaysOnDisable(mId);
- return ret;
+ std::cout << "Status: " << status.getDescription() << std::endl;
+
+ return status.isOk() ? OK : ERROR;
}
int32_t mId;
diff --git a/cmds/idlcli/vibrator/CommandAlwaysOnEnable.cpp b/cmds/idlcli/vibrator/CommandAlwaysOnEnable.cpp
index bb7f9f2..410ca52 100644
--- a/cmds/idlcli/vibrator/CommandAlwaysOnEnable.cpp
+++ b/cmds/idlcli/vibrator/CommandAlwaysOnEnable.cpp
@@ -72,21 +72,17 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::alwaysOnEnable, mId, mEffect, mStrength);
-
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ auto status = hal->alwaysOnEnable(mId, mEffect, mStrength);
- return ret;
+ std::cout << "Status: " << status.getDescription() << std::endl;
+
+ return status.isOk() ? OK : ERROR;
}
int32_t mId;
diff --git a/cmds/idlcli/vibrator/CommandCompose.cpp b/cmds/idlcli/vibrator/CommandCompose.cpp
index eb9008b..41acb98 100644
--- a/cmds/idlcli/vibrator/CommandCompose.cpp
+++ b/cmds/idlcli/vibrator/CommandCompose.cpp
@@ -89,7 +89,7 @@
}
Status doMain(Args && /*args*/) override {
- auto hal = getHal<aidl::IVibrator>();
+ auto hal = getHal();
if (!hal) {
return UNAVAILABLE;
@@ -104,7 +104,7 @@
callback = ndk::SharedRefBase::make<VibratorCallback>();
}
- auto status = hal->call(&aidl::IVibrator::compose, mComposite, callback);
+ auto status = hal->compose(mComposite, callback);
if (status.isOk() && callback) {
callback->waitForComplete();
diff --git a/cmds/idlcli/vibrator/CommandComposePwle.cpp b/cmds/idlcli/vibrator/CommandComposePwle.cpp
index b8308ce..5f6bf86 100644
--- a/cmds/idlcli/vibrator/CommandComposePwle.cpp
+++ b/cmds/idlcli/vibrator/CommandComposePwle.cpp
@@ -163,7 +163,7 @@
}
Status doMain(Args && /*args*/) override {
- auto hal = getHal<aidl::IVibrator>();
+ auto hal = getHal();
if (!hal) {
return UNAVAILABLE;
@@ -178,7 +178,7 @@
callback = ndk::SharedRefBase::make<VibratorCallback>();
}
- auto status = hal->call(&aidl::IVibrator::composePwle, mCompositePwle, callback);
+ auto status = hal->composePwle(mCompositePwle, callback);
if (status.isOk() && callback) {
callback->waitForComplete();
diff --git a/cmds/idlcli/vibrator/CommandComposePwleV2.cpp b/cmds/idlcli/vibrator/CommandComposePwleV2.cpp
index 6d3cf84..bd682ea 100644
--- a/cmds/idlcli/vibrator/CommandComposePwleV2.cpp
+++ b/cmds/idlcli/vibrator/CommandComposePwleV2.cpp
@@ -108,7 +108,7 @@
}
Status doMain(Args&& /*args*/) override {
- auto hal = getHal<aidl::IVibrator>();
+ auto hal = getHal();
if (!hal) {
return UNAVAILABLE;
@@ -123,7 +123,7 @@
callback = ndk::SharedRefBase::make<VibratorCallback>();
}
- auto status = hal->call(&aidl::IVibrator::composePwleV2, mCompositePwle, callback);
+ auto status = hal->composePwleV2(mCompositePwle, callback);
if (status.isOk() && callback) {
callback->waitForComplete();
diff --git a/cmds/idlcli/vibrator/CommandGetBandwidthAmplitudeMap.cpp b/cmds/idlcli/vibrator/CommandGetBandwidthAmplitudeMap.cpp
index aa01a11..44115e9 100644
--- a/cmds/idlcli/vibrator/CommandGetBandwidthAmplitudeMap.cpp
+++ b/cmds/idlcli/vibrator/CommandGetBandwidthAmplitudeMap.cpp
@@ -44,29 +44,38 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- std::vector<float> bandwidthAmplitude;
- float frequencyMinimumHz;
- float frequencyResolutionHz;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status =
- hal->call(&aidl::IVibrator::getBandwidthAmplitudeMap, &bandwidthAmplitude);
- statusStr = status.getDescription();
- ret = (status.isOk() ? OK : ERROR);
-
- status = hal->call(&aidl::IVibrator::getFrequencyMinimum, &frequencyMinimumHz);
- ret = (status.isOk() ? OK : ERROR);
-
- status =
- hal->call(&aidl::IVibrator::getFrequencyResolution, &frequencyResolutionHz);
- ret = (status.isOk() ? OK : ERROR);
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ std::vector<float> bandwidthAmplitude;
+ float frequencyMinimumHz;
+ float frequencyResolutionHz;
+
+ auto status = hal->getBandwidthAmplitudeMap(&bandwidthAmplitude);
+
+ if (!status.isOk()) {
+ std::cout << "Status: " << status.getDescription() << std::endl;
+ return ERROR;
+ }
+
+ status = hal->getFrequencyMinimum(&frequencyMinimumHz);
+
+ if (!status.isOk()) {
+ std::cout << "Status: " << status.getDescription() << std::endl;
+ return ERROR;
+ }
+
+ status = hal->getFrequencyResolution(&frequencyResolutionHz);
+
+ if (!status.isOk()) {
+ std::cout << "Status: " << status.getDescription() << std::endl;
+ return ERROR;
+ }
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Bandwidth Amplitude Map: " << std::endl;
float frequency = frequencyMinimumHz;
for (auto &e : bandwidthAmplitude) {
@@ -74,7 +83,7 @@
frequency += frequencyResolutionHz;
}
- return ret;
+ return OK;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetCapabilities.cpp b/cmds/idlcli/vibrator/CommandGetCapabilities.cpp
index 303a989..507d871 100644
--- a/cmds/idlcli/vibrator/CommandGetCapabilities.cpp
+++ b/cmds/idlcli/vibrator/CommandGetCapabilities.cpp
@@ -42,22 +42,19 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- int32_t cap;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getCapabilities, &cap);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ int32_t cap;
+ auto status = hal->getCapabilities(&cap);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Capabilities: " << std::bitset<32>(cap) << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp b/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp
index 10508bd..1c1eb3c 100644
--- a/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp
+++ b/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp
@@ -44,22 +44,19 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- int32_t maxDelayMs;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getCompositionDelayMax, &maxDelayMs);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ int32_t maxDelayMs;
+ auto status = hal->getCompositionDelayMax(&maxDelayMs);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Max Delay: " << maxDelayMs << " ms" << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp b/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp
index 900cb18..cfd4c53 100644
--- a/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp
+++ b/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp
@@ -44,22 +44,19 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- int32_t maxSize;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getCompositionSizeMax, &maxSize);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ int32_t maxSize;
+ auto status = hal->getCompositionSizeMax(&maxSize);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Max Size: " << maxSize << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetFrequencyMinimum.cpp b/cmds/idlcli/vibrator/CommandGetFrequencyMinimum.cpp
index 504c648..2a61446 100644
--- a/cmds/idlcli/vibrator/CommandGetFrequencyMinimum.cpp
+++ b/cmds/idlcli/vibrator/CommandGetFrequencyMinimum.cpp
@@ -44,22 +44,19 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- float frequencyMinimumHz;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getFrequencyMinimum, &frequencyMinimumHz);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ float frequencyMinimumHz;
+ auto status = hal->getFrequencyMinimum(&frequencyMinimumHz);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Minimum Frequency: " << frequencyMinimumHz << " Hz" << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetFrequencyResolution.cpp b/cmds/idlcli/vibrator/CommandGetFrequencyResolution.cpp
index de35838..157d6bf 100644
--- a/cmds/idlcli/vibrator/CommandGetFrequencyResolution.cpp
+++ b/cmds/idlcli/vibrator/CommandGetFrequencyResolution.cpp
@@ -44,23 +44,19 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- float frequencyResolutionHz;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status =
- hal->call(&aidl::IVibrator::getFrequencyResolution, &frequencyResolutionHz);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ float frequencyResolutionHz;
+ auto status = hal->getFrequencyResolution(&frequencyResolutionHz);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Frequency Resolution: " << frequencyResolutionHz << " Hz" << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetFrequencyToOutputAccelerationMap.cpp b/cmds/idlcli/vibrator/CommandGetFrequencyToOutputAccelerationMap.cpp
index 2edd0ca..2eb4510 100644
--- a/cmds/idlcli/vibrator/CommandGetFrequencyToOutputAccelerationMap.cpp
+++ b/cmds/idlcli/vibrator/CommandGetFrequencyToOutputAccelerationMap.cpp
@@ -46,26 +46,22 @@
}
Status doMain(Args&& /*args*/) override {
- std::string statusStr;
- std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getFrequencyToOutputAccelerationMap,
- &frequencyToOutputAccelerationMap);
- statusStr = status.getDescription();
- ret = (status.isOk() ? OK : ERROR);
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ std::vector<FrequencyAccelerationMapEntry> frequencyToOutputAccelerationMap;
+ auto status = hal->getFrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Frequency to Output Amplitude Map: " << std::endl;
for (auto& entry : frequencyToOutputAccelerationMap) {
std::cout << entry.frequencyHz << " " << entry.maxOutputAccelerationGs << std::endl;
}
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetPrimitiveDuration.cpp b/cmds/idlcli/vibrator/CommandGetPrimitiveDuration.cpp
index 460d39e..c957f6b 100644
--- a/cmds/idlcli/vibrator/CommandGetPrimitiveDuration.cpp
+++ b/cmds/idlcli/vibrator/CommandGetPrimitiveDuration.cpp
@@ -57,22 +57,19 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- int32_t duration;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getPrimitiveDuration, mPrimitive, &duration);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ int32_t duration;
+ auto status = hal->getPrimitiveDuration(mPrimitive, &duration);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Duration: " << duration << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
CompositePrimitive mPrimitive;
diff --git a/cmds/idlcli/vibrator/CommandGetPwleCompositionSizeMax.cpp b/cmds/idlcli/vibrator/CommandGetPwleCompositionSizeMax.cpp
index b2c3551..c1b0278 100644
--- a/cmds/idlcli/vibrator/CommandGetPwleCompositionSizeMax.cpp
+++ b/cmds/idlcli/vibrator/CommandGetPwleCompositionSizeMax.cpp
@@ -44,22 +44,19 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- int32_t maxSize;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getPwleCompositionSizeMax, &maxSize);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ int32_t maxSize;
+ auto status = hal->getPwleCompositionSizeMax(&maxSize);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Max Size: " << maxSize << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetPwlePrimitiveDurationMax.cpp b/cmds/idlcli/vibrator/CommandGetPwlePrimitiveDurationMax.cpp
index 9081973..ed00ba0 100644
--- a/cmds/idlcli/vibrator/CommandGetPwlePrimitiveDurationMax.cpp
+++ b/cmds/idlcli/vibrator/CommandGetPwlePrimitiveDurationMax.cpp
@@ -44,22 +44,19 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- int32_t maxDurationMs;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getPwlePrimitiveDurationMax, &maxDurationMs);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ int32_t maxDurationMs;
+ auto status = hal->getPwlePrimitiveDurationMax(&maxDurationMs);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Primitive duration max: " << maxDurationMs << " ms" << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetPwleV2CompositionSizeMax.cpp b/cmds/idlcli/vibrator/CommandGetPwleV2CompositionSizeMax.cpp
index cca072c..f780b8b 100644
--- a/cmds/idlcli/vibrator/CommandGetPwleV2CompositionSizeMax.cpp
+++ b/cmds/idlcli/vibrator/CommandGetPwleV2CompositionSizeMax.cpp
@@ -44,22 +44,19 @@
}
Status doMain(Args&& /*args*/) override {
- std::string statusStr;
- int32_t maxSize;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getPwleV2CompositionSizeMax, &maxSize);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ int32_t maxSize;
+ auto status = hal->getPwleV2CompositionSizeMax(&maxSize);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Max Size: " << maxSize << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMaxMillis.cpp b/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMaxMillis.cpp
index dbbfe1a..e84e969 100644
--- a/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMaxMillis.cpp
+++ b/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMaxMillis.cpp
@@ -44,23 +44,19 @@
}
Status doMain(Args&& /*args*/) override {
- std::string statusStr;
- int32_t maxDurationMs;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getPwleV2PrimitiveDurationMaxMillis,
- &maxDurationMs);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ int32_t maxDurationMs;
+ auto status = hal->getPwleV2PrimitiveDurationMaxMillis(&maxDurationMs);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Primitive duration max: " << maxDurationMs << " ms" << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMinMillis.cpp b/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMinMillis.cpp
index 09225c4..448fd2a 100644
--- a/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMinMillis.cpp
+++ b/cmds/idlcli/vibrator/CommandGetPwleV2PrimitiveDurationMinMillis.cpp
@@ -44,23 +44,19 @@
}
Status doMain(Args&& /*args*/) override {
- std::string statusStr;
- int32_t minDurationMs;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getPwleV2PrimitiveDurationMinMillis,
- &minDurationMs);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ int32_t minDurationMs;
+ auto status = hal->getPwleV2PrimitiveDurationMinMillis(&minDurationMs);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Primitive duration min: " << minDurationMs << " ms" << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetQFactor.cpp b/cmds/idlcli/vibrator/CommandGetQFactor.cpp
index a2681e9..e04bad9 100644
--- a/cmds/idlcli/vibrator/CommandGetQFactor.cpp
+++ b/cmds/idlcli/vibrator/CommandGetQFactor.cpp
@@ -42,22 +42,19 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- float qFactor;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getQFactor, &qFactor);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ float qFactor;
+ auto status = hal->getQFactor(&qFactor);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Q Factor: " << qFactor << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp b/cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp
index 81a6391..e222ea6 100644
--- a/cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp
+++ b/cmds/idlcli/vibrator/CommandGetResonantFrequency.cpp
@@ -44,22 +44,19 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- float resonantFrequencyHz;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getResonantFrequency, &resonantFrequencyHz);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ float resonantFrequencyHz;
+ auto status = hal->getResonantFrequency(&resonantFrequencyHz);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Resonant Frequency: " << resonantFrequencyHz << " Hz" << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetSupportedAlwaysOnEffects.cpp b/cmds/idlcli/vibrator/CommandGetSupportedAlwaysOnEffects.cpp
index edfcd91..9b05540 100644
--- a/cmds/idlcli/vibrator/CommandGetSupportedAlwaysOnEffects.cpp
+++ b/cmds/idlcli/vibrator/CommandGetSupportedAlwaysOnEffects.cpp
@@ -44,25 +44,22 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- std::vector<Effect> effects;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getSupportedAlwaysOnEffects, &effects);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ std::vector<Effect> effects;
+ auto status = hal->getSupportedAlwaysOnEffects(&effects);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Effects:" << std::endl;
for (auto &e : effects) {
std::cout << " " << toString(e) << std::endl;
}
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetSupportedBraking.cpp b/cmds/idlcli/vibrator/CommandGetSupportedBraking.cpp
index b326e07..f95f682 100644
--- a/cmds/idlcli/vibrator/CommandGetSupportedBraking.cpp
+++ b/cmds/idlcli/vibrator/CommandGetSupportedBraking.cpp
@@ -44,25 +44,22 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- std::vector<Braking> braking;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getSupportedBraking, &braking);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ std::vector<Braking> braking;
+ auto status = hal->getSupportedBraking(&braking);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Braking Mechanisms:" << std::endl;
for (auto &e : braking) {
std::cout << " " << toString(e) << std::endl;
}
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetSupportedEffects.cpp b/cmds/idlcli/vibrator/CommandGetSupportedEffects.cpp
index 7658f22..05de1b8 100644
--- a/cmds/idlcli/vibrator/CommandGetSupportedEffects.cpp
+++ b/cmds/idlcli/vibrator/CommandGetSupportedEffects.cpp
@@ -44,25 +44,22 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- std::vector<Effect> effects;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getSupportedEffects, &effects);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ std::vector<Effect> effects;
+ auto status = hal->getSupportedEffects(&effects);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Effects:" << std::endl;
for (auto &e : effects) {
std::cout << " " << toString(e) << std::endl;
}
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandGetSupportedPrimitives.cpp b/cmds/idlcli/vibrator/CommandGetSupportedPrimitives.cpp
index d101681..0f33f0f 100644
--- a/cmds/idlcli/vibrator/CommandGetSupportedPrimitives.cpp
+++ b/cmds/idlcli/vibrator/CommandGetSupportedPrimitives.cpp
@@ -44,25 +44,22 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- std::vector<CompositePrimitive> primitives;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::getSupportedPrimitives, &primitives);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ std::vector<CompositePrimitive> primitives;
+ auto status = hal->getSupportedPrimitives(&primitives);
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Primitives:" << std::endl;
for (auto &e : primitives) {
std::cout << " " << toString(e) << std::endl;
}
- return ret;
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandOff.cpp b/cmds/idlcli/vibrator/CommandOff.cpp
index cedb9fe..e55b44a 100644
--- a/cmds/idlcli/vibrator/CommandOff.cpp
+++ b/cmds/idlcli/vibrator/CommandOff.cpp
@@ -42,24 +42,17 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::off);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else if (auto hal = getHal<V1_0::IVibrator>()) {
- auto status = hal->call(&V1_0::IVibrator::off);
- statusStr = toString(status);
- ret = status.isOk() && status == V1_0::Status::OK ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ auto status = hal->off();
- return ret;
+ std::cout << "Status: " << status.getDescription() << std::endl;
+
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandOn.cpp b/cmds/idlcli/vibrator/CommandOn.cpp
index 8212fc1..856c219 100644
--- a/cmds/idlcli/vibrator/CommandOn.cpp
+++ b/cmds/idlcli/vibrator/CommandOn.cpp
@@ -67,34 +67,27 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- Status ret;
- std::shared_ptr<VibratorCallback> callback;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- ABinderProcess_setThreadPoolMaxThreadCount(1);
- ABinderProcess_startThreadPool();
-
- int32_t cap;
- hal->call(&aidl::IVibrator::getCapabilities, &cap);
-
- if (mBlocking && (cap & aidl::IVibrator::CAP_ON_CALLBACK)) {
- callback = ndk::SharedRefBase::make<VibratorCallback>();
- }
-
- auto status = hal->call(&aidl::IVibrator::on, mDuration, callback);
-
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else if (auto hal = getHal<V1_0::IVibrator>()) {
- auto status = hal->call(&V1_0::IVibrator::on, mDuration);
- statusStr = toString(status);
- ret = status.isOk() && status == V1_0::Status::OK ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- if (ret == OK && mBlocking) {
+ std::shared_ptr<VibratorCallback> callback;
+
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+
+ int32_t cap;
+ hal->getCapabilities(&cap);
+
+ if (mBlocking && (cap & aidl::IVibrator::CAP_ON_CALLBACK)) {
+ callback = ndk::SharedRefBase::make<VibratorCallback>();
+ }
+
+ auto status = hal->on(mDuration, callback);
+
+ if (status.isOk() && mBlocking) {
if (callback) {
callback->waitForComplete();
} else {
@@ -102,9 +95,9 @@
}
}
- std::cout << "Status: " << statusStr << std::endl;
+ std::cout << "Status: " << status.getDescription() << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
bool mBlocking;
diff --git a/cmds/idlcli/vibrator/CommandPerform.cpp b/cmds/idlcli/vibrator/CommandPerform.cpp
index c897686..0a354e2 100644
--- a/cmds/idlcli/vibrator/CommandPerform.cpp
+++ b/cmds/idlcli/vibrator/CommandPerform.cpp
@@ -28,34 +28,6 @@
namespace vibrator {
-/*
- * The following static asserts are only relevant here because the argument
- * parser uses a single implementation for determining the string names.
- */
-static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
- static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
-static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
- static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
-static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
- static_cast<uint8_t>(aidl::EffectStrength::STRONG));
-static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
- static_cast<uint8_t>(aidl::Effect::CLICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
- static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) == static_cast<uint8_t>(aidl::Effect::TICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) == static_cast<uint8_t>(aidl::Effect::THUD));
-static_assert(static_cast<uint8_t>(V1_3::Effect::POP) == static_cast<uint8_t>(aidl::Effect::POP));
-static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
- static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
-static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
- static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
-static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
- static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
-static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
- static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
-static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
- static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
-
using aidl::Effect;
using aidl::EffectStrength;
@@ -107,61 +79,31 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- uint32_t lengthMs;
- Status ret;
- std::shared_ptr<VibratorCallback> callback;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- ABinderProcess_setThreadPoolMaxThreadCount(1);
- ABinderProcess_startThreadPool();
-
- int32_t cap;
- hal->call(&aidl::IVibrator::getCapabilities, &cap);
-
- if (mBlocking && (cap & aidl::IVibrator::CAP_PERFORM_CALLBACK)) {
- callback = ndk::SharedRefBase::make<VibratorCallback>();
- }
-
- int32_t aidlLengthMs;
- auto status = hal->call(&aidl::IVibrator::perform, mEffect, mStrength, callback,
- &aidlLengthMs);
-
- statusStr = status.getDescription();
- lengthMs = static_cast<uint32_t>(aidlLengthMs);
- ret = status.isOk() ? OK : ERROR;
- } else {
- Return<void> hidlRet;
- V1_0::Status status;
- auto callback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) {
- status = retStatus;
- lengthMs = retLengthMs;
- };
-
- if (auto hal = getHal<V1_3::IVibrator>()) {
- hidlRet =
- hal->call(&V1_3::IVibrator::perform_1_3, static_cast<V1_3::Effect>(mEffect),
- static_cast<V1_0::EffectStrength>(mStrength), callback);
- } else if (auto hal = getHal<V1_2::IVibrator>()) {
- hidlRet =
- hal->call(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(mEffect),
- static_cast<V1_0::EffectStrength>(mStrength), callback);
- } else if (auto hal = getHal<V1_1::IVibrator>()) {
- hidlRet = hal->call(&V1_1::IVibrator::perform_1_1,
- static_cast<V1_1::Effect_1_1>(mEffect),
- static_cast<V1_0::EffectStrength>(mStrength), callback);
- } else if (auto hal = getHal<V1_0::IVibrator>()) {
- hidlRet = hal->call(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(mEffect),
- static_cast<V1_0::EffectStrength>(mStrength), callback);
- } else {
- return UNAVAILABLE;
- }
-
- statusStr = toString(status);
- ret = hidlRet.isOk() && status == V1_0::Status::OK ? OK : ERROR;
+ if (!hal) {
+ return UNAVAILABLE;
}
- if (ret == OK && mBlocking) {
+ uint32_t lengthMs;
+ std::shared_ptr<VibratorCallback> callback;
+
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+
+ int32_t cap;
+ hal->getCapabilities(&cap);
+
+ if (mBlocking && (cap & aidl::IVibrator::CAP_PERFORM_CALLBACK)) {
+ callback = ndk::SharedRefBase::make<VibratorCallback>();
+ }
+
+ int32_t aidlLengthMs;
+ auto status = hal->perform(mEffect, mStrength, callback, &aidlLengthMs);
+
+ lengthMs = static_cast<uint32_t>(aidlLengthMs);
+
+ if (status.isOk() && mBlocking) {
if (callback) {
callback->waitForComplete();
} else {
@@ -169,10 +111,10 @@
}
}
- std::cout << "Status: " << statusStr << std::endl;
+ std::cout << "Status: " << status.getDescription() << std::endl;
std::cout << "Length: " << lengthMs << std::endl;
- return ret;
+ return status.isOk() ? OK : ERROR;
}
bool mBlocking;
diff --git a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
index 8b8058c..8050723 100644
--- a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
+++ b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
@@ -50,25 +50,17 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::setAmplitude,
- static_cast<float>(mAmplitude) / UINT8_MAX);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else if (auto hal = getHal<V1_0::IVibrator>()) {
- auto status = hal->call(&V1_0::IVibrator::setAmplitude, mAmplitude);
- statusStr = toString(status);
- ret = status.isOk() && status == V1_0::Status::OK ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ auto status = hal->setAmplitude(static_cast<float>(mAmplitude) / UINT8_MAX);
- return ret;
+ std::cout << "Status: " << status.getDescription() << std::endl;
+
+ return status.isOk() ? OK : ERROR;
}
uint8_t mAmplitude;
diff --git a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp b/cmds/idlcli/vibrator/CommandSetExternalControl.cpp
index 1795793..8f8d4b7 100644
--- a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp
+++ b/cmds/idlcli/vibrator/CommandSetExternalControl.cpp
@@ -48,24 +48,17 @@
}
Status doMain(Args && /*args*/) override {
- std::string statusStr;
- Status ret;
+ auto hal = getHal();
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::setExternalControl, mEnable);
- statusStr = status.getDescription();
- ret = status.isOk() ? OK : ERROR;
- } else if (auto hal = getHal<V1_3::IVibrator>()) {
- auto status = hal->call(&V1_3::IVibrator::setExternalControl, mEnable);
- statusStr = toString(status);
- ret = status.isOk() && status == V1_0::Status::OK ? OK : ERROR;
- } else {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Status: " << statusStr << std::endl;
+ auto status = hal->setExternalControl(mEnable);
- return ret;
+ std::cout << "Status: " << status.getDescription() << std::endl;
+
+ return status.isOk() ? OK : ERROR;
}
bool mEnable;
diff --git a/cmds/idlcli/vibrator/CommandSupportsAmplitudeControl.cpp b/cmds/idlcli/vibrator/CommandSupportsAmplitudeControl.cpp
index cdc529a..31ee954 100644
--- a/cmds/idlcli/vibrator/CommandSupportsAmplitudeControl.cpp
+++ b/cmds/idlcli/vibrator/CommandSupportsAmplitudeControl.cpp
@@ -42,15 +42,22 @@
}
Status doMain(Args && /*args*/) override {
- auto ret = halCall(&V1_0::IVibrator::supportsAmplitudeControl);
+ auto hal = getHal();
- if (!ret.isOk()) {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Result: " << std::boolalpha << ret << std::endl;
+ int32_t cap;
- return OK;
+ auto status = hal->getCapabilities(&cap);
+
+ bool hasAmplitudeControl = cap & IVibrator::CAP_AMPLITUDE_CONTROL;
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
+ std::cout << "Result: " << std::boolalpha << hasAmplitudeControl << std::endl;
+
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/idlcli/vibrator/CommandSupportsExternalControl.cpp b/cmds/idlcli/vibrator/CommandSupportsExternalControl.cpp
index ed15d76..f0c542c 100644
--- a/cmds/idlcli/vibrator/CommandSupportsExternalControl.cpp
+++ b/cmds/idlcli/vibrator/CommandSupportsExternalControl.cpp
@@ -42,15 +42,22 @@
}
Status doMain(Args && /*args*/) override {
- auto ret = halCall(&V1_3::IVibrator::supportsExternalControl);
+ auto hal = getHal();
- if (!ret.isOk()) {
+ if (!hal) {
return UNAVAILABLE;
}
- std::cout << "Result: " << std::boolalpha << ret << std::endl;
+ int32_t cap;
- return OK;
+ auto status = hal->getCapabilities(&cap);
+
+ bool hasExternalControl = cap & IVibrator::CAP_EXTERNAL_CONTROL;
+
+ std::cout << "Status: " << status.getDescription() << std::endl;
+ std::cout << "Result: " << std::boolalpha << hasExternalControl << std::endl;
+
+ return status.isOk() ? OK : ERROR;
}
};
diff --git a/cmds/installd/TEST_MAPPING b/cmds/installd/TEST_MAPPING
index fc4cfc9..d53c94b 100644
--- a/cmds/installd/TEST_MAPPING
+++ b/cmds/installd/TEST_MAPPING
@@ -18,10 +18,6 @@
{
"name": "run_dex2oat_test"
},
- // AdoptableHostTest moves packages, part of which is handled by installd
- {
- "name": "AdoptableHostTest"
- },
{
"name": "CtsUsesLibraryHostTestCases"
},
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index cd8ca89..f320504 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -119,12 +119,24 @@
}
prebuilt_etc {
+ name: "android.hardware.nfc.ese.prebuilt.xml",
+ src: "android.hardware.nfc.ese.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.nfc.hce.prebuilt.xml",
src: "android.hardware.nfc.hce.xml",
defaults: ["frameworks_native_data_etc_defaults"],
}
prebuilt_etc {
+ name: "android.hardware.nfc.hcef.prebuilt.xml",
+ src: "android.hardware.nfc.hcef.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.reboot_escrow.prebuilt.xml",
src: "android.hardware.reboot_escrow.xml",
defaults: ["frameworks_native_data_etc_defaults"],
@@ -317,6 +329,12 @@
}
prebuilt_etc {
+ name: "android.hardware.telephony.messaging.prebuilt.xml",
+ src: "android.hardware.telephony.messaging.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.thread_network.prebuilt.xml",
src: "android.hardware.thread_network.xml",
defaults: ["frameworks_native_data_etc_defaults"],
@@ -505,6 +523,12 @@
}
prebuilt_etc {
+ name: "com.nxp.mifare.prebuilt.xml",
+ src: "com.nxp.mifare.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "go_handheld_core_hardware.prebuilt.xml",
src: "go_handheld_core_hardware.xml",
defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/data/etc/android.hardware.telephony.messaging.xml b/data/etc/android.hardware.telephony.messaging.xml
new file mode 100644
index 0000000..0e96123
--- /dev/null
+++ b/data/etc/android.hardware.telephony.messaging.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Feature for devices with messaging. -->
+<permissions>
+ <feature name="android.hardware.telephony" />
+ <feature name="android.hardware.telephony.radio.access" />
+ <feature name="android.hardware.telephony.subscription" />
+ <feature name="android.hardware.telephony.messaging" />
+</permissions>
diff --git a/include/OWNERS b/include/OWNERS
index c98e87a..7f847e8 100644
--- a/include/OWNERS
+++ b/include/OWNERS
@@ -1,5 +1,4 @@
alecmouri@google.com
-alexeykuzmin@google.com
dangittik@google.com
jreck@google.com
lajos@google.com
diff --git a/include/android/system_health.h b/include/android/system_health.h
index bdb1413..4494e32 100644
--- a/include/android/system_health.h
+++ b/include/android/system_health.h
@@ -316,8 +316,6 @@
/**
* Gets the range of the calculation window size for CPU headroom.
*
- * In API version 36, the range will be a superset of [50, 10000].
- *
* Available since API level 36.
*
* @param outMinMillis Non-null output pointer to be set to the minimum window size in milliseconds.
@@ -332,8 +330,6 @@
/**
* Gets the range of the calculation window size for GPU headroom.
*
- * In API version 36, the range will be a superset of [50, 10000].
- *
* Available since API level 36.
*
* @param outMinMillis Non-null output pointer to be set to the minimum window size in milliseconds.
diff --git a/include/input/DisplayTopologyGraph.h b/include/input/DisplayTopologyGraph.h
index 3ae865a..9fc080d 100644
--- a/include/input/DisplayTopologyGraph.h
+++ b/include/input/DisplayTopologyGraph.h
@@ -46,6 +46,8 @@
DisplayTopologyPosition position;
// The offset in DP of the adjacent display, relative to the source display.
float offsetDp;
+
+ std::string dump() const;
};
/**
@@ -55,6 +57,9 @@
ui::LogicalDisplayId primaryDisplayId = ui::LogicalDisplayId::INVALID;
std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>> graph;
std::unordered_map<ui::LogicalDisplayId, int> displaysDensity;
+
+ bool isValid() const;
+ std::string dump() const;
};
} // namespace android
diff --git a/include/input/InputFlags.h b/include/input/InputFlags.h
index 0e194ea..16e754e 100644
--- a/include/input/InputFlags.h
+++ b/include/input/InputFlags.h
@@ -22,9 +22,28 @@
public:
/**
* Check if connected displays feature is enabled, either via the feature flag or settings
- * override.
+ * override. Developer setting override allows enabling all the "desktop experiences" features
+ * including input related connected_displays_cursor flag.
+ *
+ * The developer settings override is prioritised over aconfig flags. Any tests that require
+ * applicable aconfig flags to be disabled with SCOPED_FLAG_OVERRIDE also need this developer
+ * option to be reset locally.
+ *
+ * Also note the developer setting override is only applicable to the desktop experiences
+ * related features.
+ *
+ * To enable only the input flag run:
+ * adb shell aflags enable com.android.input.flags.connected_displays_cursor
+ * To override this flag and enable all "desktop experiences" features run:
+ * adb shell aflags enable com.android.window.flags.enable_desktop_mode_through_dev_option
+ * adb shell setprop persist.wm.debug.desktop_experience_devopts 1
*/
static bool connectedDisplaysCursorEnabled();
+
+ /**
+ * Check if both connectedDisplaysCursor and associatedDisplayCursorBugfix is enabled.
+ */
+ static bool connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled();
};
} // namespace android
diff --git a/libs/attestation/OWNERS b/libs/attestation/OWNERS
index 4dbb0ea..76811f2 100644
--- a/libs/attestation/OWNERS
+++ b/libs/attestation/OWNERS
@@ -1,2 +1 @@
-chaviw@google.com
-svv@google.com
\ No newline at end of file
+svv@google.com
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index fb00d4f..ea5343a 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -827,6 +827,7 @@
// so we restrict its visibility to the Trusty-specific packages.
visibility: [
":__subpackages__",
+ "//hardware/interfaces/security/see:__subpackages__",
"//system/core/trusty:__subpackages__",
"//vendor:__subpackages__",
],
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index 7c0319a..b1c8994 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -130,7 +130,13 @@
bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) {
sp<ProcessState> self = ProcessState::selfOrNull();
- if (!self || self->getThreadPoolMaxTotalThreadCount() <= 0) {
+ // Should not cache if process state could not be found, or if thread pool
+ // max could is not greater than zero.
+ if (!self) {
+ ALOGW("Service retrieved before binder threads started. If they are to be started, "
+ "consider starting binder threads earlier.");
+ return false;
+ } else if (self->getThreadPoolMaxTotalThreadCount() <= 0) {
ALOGW("Thread Pool max thread count is 0. Cannot cache binder as linkToDeath cannot be "
"implemented. serviceName: %s",
serviceName.c_str());
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 16023ff..1f3a45a 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -188,7 +188,9 @@
}
status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
- return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) -> status_t {
+ return setupClient([&, fd = std::move(fd),
+ request = std::move(request)](const std::vector<uint8_t>& sessionId,
+ bool incoming) mutable -> status_t {
if (!fd.ok()) {
fd = request();
if (!fd.ok()) return BAD_VALUE;
@@ -476,8 +478,10 @@
return server;
}
-status_t RpcSession::setupClient(const std::function<status_t(const std::vector<uint8_t>& sessionId,
- bool incoming)>& connectAndInit) {
+template <typename Fn,
+ typename /* = std::enable_if_t<std::is_invocable_r_v<
+ status_t, Fn, const std::vector<uint8_t>&, bool>> */>
+status_t RpcSession::setupClient(Fn&& connectAndInit) {
{
RpcMutexLockGuard _l(mMutex);
LOG_ALWAYS_FATAL_IF(mStartedSetup, "Must only setup session once");
diff --git a/libs/binder/RpcTransportTipcAndroid.cpp b/libs/binder/RpcTransportTipcAndroid.cpp
index 3819fb6..14c0bde 100644
--- a/libs/binder/RpcTransportTipcAndroid.cpp
+++ b/libs/binder/RpcTransportTipcAndroid.cpp
@@ -21,6 +21,7 @@
#include <log/log.h>
#include <poll.h>
#include <trusty/tipc.h>
+#include <type_traits>
#include "FdTrigger.h"
#include "RpcState.h"
@@ -32,6 +33,9 @@
namespace android {
+// Corresponds to IPC_MAX_MSG_HANDLES in the Trusty kernel
+constexpr size_t kMaxTipcHandles = 8;
+
// RpcTransport for writing Trusty IPC clients in Android.
class RpcTransportTipcAndroid : public RpcTransport {
public:
@@ -78,12 +82,28 @@
FdTrigger* fdTrigger, iovec* iovs, int niovs,
const std::optional<SmallFunction<status_t()>>& altPoll,
const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override {
+ bool sentFds = false;
auto writeFn = [&](iovec* iovs, size_t niovs) -> ssize_t {
- // TODO: send ancillaryFds. For now, we just abort if anyone tries
- // to send any.
- LOG_ALWAYS_FATAL_IF(ancillaryFds != nullptr && !ancillaryFds->empty(),
- "File descriptors are not supported on Trusty yet");
- return TEMP_FAILURE_RETRY(tipc_send(mSocket.fd.get(), iovs, niovs, nullptr, 0));
+ trusty_shm shms[kMaxTipcHandles] = {{0}};
+ ssize_t shm_count = 0;
+
+ if (!sentFds && ancillaryFds != nullptr && !ancillaryFds->empty()) {
+ if (ancillaryFds->size() > kMaxTipcHandles) {
+ ALOGE("Too many file descriptors for TIPC: %zu", ancillaryFds->size());
+ errno = EINVAL;
+ return -1;
+ }
+ for (const auto& fdVariant : *ancillaryFds) {
+ shms[shm_count++] = {std::visit([](const auto& fd) { return fd.get(); },
+ fdVariant),
+ TRUSTY_SEND_SECURE_OR_SHARE};
+ }
+ }
+
+ auto ret = TEMP_FAILURE_RETRY(tipc_send(mSocket.fd.get(), iovs, niovs,
+ (shm_count == 0) ? nullptr : shms, shm_count));
+ sentFds |= ret >= 0;
+ return ret;
};
status_t status = interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, writeFn,
diff --git a/libs/binder/aidl/android/content/pm/OWNERS b/libs/binder/aidl/android/content/pm/OWNERS
index 3100518..2617a16 100644
--- a/libs/binder/aidl/android/content/pm/OWNERS
+++ b/libs/binder/aidl/android/content/pm/OWNERS
@@ -1,5 +1,4 @@
+michaelwr@google.com
narayan@google.com
patb@google.com
-svetoslavganov@google.com
-toddke@google.com
-patb@google.com
\ No newline at end of file
+schfan@google.com
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index af37bf2..c9f92da 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -25,6 +25,7 @@
#include <map>
#include <optional>
+#include <type_traits>
#include <vector>
namespace android {
@@ -291,9 +292,14 @@
// join on thread passed to preJoinThreadOwnership
static void join(sp<RpcSession>&& session, PreJoinSetupResult&& result);
- [[nodiscard]] status_t setupClient(
- const std::function<status_t(const std::vector<uint8_t>& sessionId, bool incoming)>&
- connectAndInit);
+ // This is a workaround to support move-only functors.
+ // TODO: use std::move_only_function when it becomes available.
+ template <typename Fn,
+ // Fn must be a callable type taking (const std::vector<uint8_t>&, bool) and returning
+ // status_t
+ typename = std::enable_if_t<
+ std::is_invocable_r_v<status_t, Fn, const std::vector<uint8_t>&, bool>>>
+ [[nodiscard]] status_t setupClient(Fn&& connectAndInit);
[[nodiscard]] status_t setupSocketClient(const RpcSocketAddress& address);
[[nodiscard]] status_t setupOneSocketConnection(const RpcSocketAddress& address,
const std::vector<uint8_t>& sessionId,
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index 48c0ea6..1949cbb 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -134,9 +134,14 @@
//
// param will be passed to requestFd. Callers can use param to pass contexts to
// the requestFd function.
+//
+// paramDeleteFd will be called when requestFd and param are no longer in use.
+// Callers can pass a function deleting param if necessary. Callers can set
+// paramDeleteFd to null if callers doesn't need to clean up param.
AIBinder* ARpcSession_setupPreconnectedClient(ARpcSession* session,
int (*requestFd)(void* param),
- void* param);
+ void* param,
+ void (*paramDeleteFd)(void* param));
// Sets the file descriptor transport mode for this session.
void ARpcSession_setFileDescriptorTransportMode(ARpcSession* session,
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index 64b1be2..8177fb0 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -248,9 +248,18 @@
#endif // __TRUSTY__
AIBinder* ARpcSession_setupPreconnectedClient(ARpcSession* handle, int (*requestFd)(void* param),
- void* param) {
+ void* param, void (*paramDeleteFd)(void* param)) {
auto session = handleToStrongPointer<RpcSession>(handle);
- auto request = [=] { return unique_fd{requestFd(param)}; };
+ auto deleter = [=](void* param) {
+ if (paramDeleteFd) {
+ paramDeleteFd(param);
+ }
+ };
+ // TODO: use unique_ptr once setupPreconnectedClient uses std::move_only_function.
+ std::shared_ptr<void> sharedParam(param, deleter);
+ auto request = [=, sharedParam = std::move(sharedParam)] {
+ return unique_fd{requestFd(sharedParam.get())};
+ };
if (status_t status = session->setupPreconnectedClient(unique_fd{}, request); status != OK) {
ALOGE("Failed to set up preconnected client. error: %s", statusToString(status).c_str());
return nullptr;
diff --git a/libs/binder/rust/rpcbinder/src/session.rs b/libs/binder/rust/rpcbinder/src/session.rs
index 09688a2..411b9de 100644
--- a/libs/binder/rust/rpcbinder/src/session.rs
+++ b/libs/binder/rust/rpcbinder/src/session.rs
@@ -195,11 +195,13 @@
/// take ownership of) file descriptors already connected to it.
pub fn setup_preconnected_client<T: FromIBinder + ?Sized>(
&self,
- mut request_fd: impl FnMut() -> Option<RawFd>,
+ request_fd: impl FnMut() -> Option<RawFd>,
) -> Result<Strong<T>, StatusCode> {
- // Double reference the factory because trait objects aren't FFI safe.
- let mut request_fd_ref: RequestFd = &mut request_fd;
- let param = &mut request_fd_ref as *mut RequestFd as *mut c_void;
+ // Trait objects aren't FFI safe, so *mut c_void can't be converted back to
+ // *mut dyn FnMut() -> Option<RawFd>>. Double box the factory to make it possible to get
+ // the factory from *mut c_void (to *mut Box<dyn<...>>) in the callbacks.
+ let request_fd_box: Box<dyn FnMut() -> Option<RawFd>> = Box::new(request_fd);
+ let param = Box::into_raw(Box::new(request_fd_box)) as *mut c_void;
// SAFETY: AIBinder returned by RpcPreconnectedClient has correct reference count, and the
// ownership can be safely taken by new_spibinder. RpcPreconnectedClient does not take ownership
@@ -209,6 +211,7 @@
self.as_ptr(),
Some(request_fd_wrapper),
param,
+ Some(param_delete_fd_wrapper),
))
};
Self::get_interface(service)
@@ -225,13 +228,18 @@
}
}
-type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>;
-
unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
- let request_fd_ptr = param as *mut RequestFd;
+ let request_fd_ptr = param as *mut Box<dyn FnMut() -> Option<RawFd>>;
// SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
// BinderFdFactory reference, with param being a properly aligned non-null pointer to an
// initialized instance.
let request_fd = unsafe { request_fd_ptr.as_mut().unwrap() };
request_fd().unwrap_or(-1)
}
+
+unsafe extern "C" fn param_delete_fd_wrapper(param: *mut c_void) {
+ // SAFETY: This is only ever called by RpcPreconnectedClient, with param being the
+ // pointer returned from Box::into_raw.
+ let request_fd_box = unsafe { Box::from_raw(param as *mut Box<dyn FnMut() -> Option<RawFd>>) };
+ drop(request_fd_box);
+}
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index cac054e..457eaa5 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -109,6 +109,9 @@
"libcutils",
"libutils",
],
+ header_libs: [
+ "libaidl_transactions",
+ ],
local_include_dirs: ["include_random_parcel"],
export_include_dirs: ["include_random_parcel"],
}
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index 02e69cc..11aa768 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -13,6 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#include <aidl/transaction_ids.h>
#include <fuzzbinder/libbinder_driver.h>
#include <fuzzbinder/random_parcel.h>
@@ -31,6 +33,28 @@
fuzzService(std::vector<sp<IBinder>>{binder}, std::move(provider));
}
+uint32_t getCode(FuzzedDataProvider& provider) {
+ if (provider.ConsumeBool()) {
+ return provider.ConsumeIntegral<uint32_t>();
+ }
+
+ // Most of the AIDL services will have small set of transaction codes.
+ if (provider.ConsumeBool()) {
+ return provider.ConsumeIntegralInRange<uint32_t>(0, 100);
+ }
+
+ if (provider.ConsumeBool()) {
+ return provider.PickValueInArray<uint32_t>(
+ {IBinder::DUMP_TRANSACTION, IBinder::PING_TRANSACTION,
+ IBinder::SHELL_COMMAND_TRANSACTION, IBinder::INTERFACE_TRANSACTION,
+ IBinder::SYSPROPS_TRANSACTION, IBinder::EXTENSION_TRANSACTION,
+ IBinder::TWEET_TRANSACTION, IBinder::LIKE_TRANSACTION});
+ }
+
+ return provider.ConsumeIntegralInRange<uint32_t>(aidl::kLastMetaMethodId,
+ aidl::kFirstMetaMethodId);
+}
+
void fuzzService(const std::vector<sp<IBinder>>& binders, FuzzedDataProvider&& provider) {
RandomParcelOptions options{
.extraBinders = binders,
@@ -61,16 +85,7 @@
}
while (provider.remaining_bytes() > 0) {
- // Most of the AIDL services will have small set of transaction codes.
- // TODO(b/295942369) : Add remaining transact codes from IBinder.h
- uint32_t code = provider.ConsumeBool() ? provider.ConsumeIntegral<uint32_t>()
- : provider.ConsumeBool()
- ? provider.ConsumeIntegralInRange<uint32_t>(0, 100)
- : provider.PickValueInArray<uint32_t>(
- {IBinder::DUMP_TRANSACTION, IBinder::PING_TRANSACTION,
- IBinder::SHELL_COMMAND_TRANSACTION, IBinder::INTERFACE_TRANSACTION,
- IBinder::SYSPROPS_TRANSACTION, IBinder::EXTENSION_TRANSACTION,
- IBinder::TWEET_TRANSACTION, IBinder::LIKE_TRANSACTION});
+ uint32_t code = getCode(provider);
uint32_t flags = provider.ConsumeIntegral<uint32_t>();
Parcel data;
// for increased fuzz coverage
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
index 583ad01..127676b 100644
--- a/libs/binder/trusty/include/binder/RpcServerTrusty.h
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -94,9 +94,8 @@
static sp<RpcServer> makeRpcServer(std::unique_ptr<RpcTransportCtx> ctx) {
auto rpcServer = sp<RpcServer>::make(std::move(ctx));
- // TODO(b/266741352): follow-up to prevent needing this in the future
- // Trusty needs to be set to the latest stable version that is in prebuilts there.
- LOG_ALWAYS_FATAL_IF(!rpcServer->setProtocolVersion(0));
+ // By default we use the latest stable version.
+ LOG_ALWAYS_FATAL_IF(!rpcServer->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION));
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 451383a..12e347e 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,6 +27,13 @@
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;
@@ -53,6 +60,8 @@
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/binder/trusty/rust/binder_rpc_unstable_bindgen/rules.mk b/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/rules.mk
index ef1b7c3..40fc218 100644
--- a/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/rules.mk
+++ b/libs/binder/trusty/rust/binder_rpc_unstable_bindgen/rules.mk
@@ -30,6 +30,8 @@
trusty/user/base/lib/libstdc++-trusty \
trusty/user/base/lib/trusty-sys \
+MODULE_SRCDEPS := $(LIBBINDER_DIR)/include_rpc_unstable/binder_rpc_unstable.hpp
+
MODULE_BINDGEN_SRC_HEADER := $(LOCAL_DIR)/BinderBindings.hpp
MODULE_BINDGEN_FLAGS += \
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index a9bd11e..43ee33e 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -101,7 +101,7 @@
"android.hardware.automotive.remoteaccess.IRemoteAccess",
"android.hardware.automotive.vehicle.IVehicle",
"android.hardware.biometrics.face.IBiometricsFace",
- "android.hardware.biometrics.fingerprint.IBiometricsFingerprint",
+ "android.hardware.biometrics.fingerprint.IFingerprint",
"android.hardware.camera.provider.ICameraProvider",
"android.hardware.drm.IDrmFactory",
"android.hardware.graphics.allocator.IAllocator",
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 626581c..03e6456 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -639,7 +639,7 @@
// List of ANGLE features to override (enabled or disable).
// The list of overrides is loaded and parsed by GpuService.
void GraphicsEnv::updateAngleFeatureOverrides() {
- if (!graphicsenv_flags::feature_overrides()) {
+ if (!graphicsenv_flags::angle_feature_overrides()) {
return;
}
@@ -654,7 +654,7 @@
void GraphicsEnv::getAngleFeatureOverrides(std::vector<const char*>& enabled,
std::vector<const char*>& disabled) {
- if (!graphicsenv_flags::feature_overrides()) {
+ if (!graphicsenv_flags::angle_feature_overrides()) {
return;
}
diff --git a/libs/graphicsenv/graphicsenv_flags.aconfig b/libs/graphicsenv/graphicsenv_flags.aconfig
index ac66362..efa4bca 100644
--- a/libs/graphicsenv/graphicsenv_flags.aconfig
+++ b/libs/graphicsenv/graphicsenv_flags.aconfig
@@ -2,8 +2,8 @@
container: "system"
flag {
- name: "feature_overrides"
- namespace: "core_graphics"
- description: "This flag controls the Feature Overrides in GraphicsEnv."
+ name: "angle_feature_overrides"
+ namespace: "gpu"
+ description: "This flag controls the ANGLE Feature Overrides in GraphicsEnv."
bug: "372694741"
}
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 5ab31db..b5fa321 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -281,6 +281,7 @@
"SurfaceControl.cpp",
"SurfaceComposerClient.cpp",
"SyncFeatures.cpp",
+ "TransactionState.cpp",
"VsyncEventData.cpp",
"view/Surface.cpp",
"WindowInfosListenerReporter.cpp",
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 310f781..1aae13c 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -197,15 +197,15 @@
mUpdateDestinationFrame(updateDestinationFrame) {
createBufferQueue(&mProducer, &mConsumer);
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- mBufferItemConsumer = new BLASTBufferItemConsumer(mProducer, mConsumer,
- GraphicBuffer::USAGE_HW_COMPOSER |
- GraphicBuffer::USAGE_HW_TEXTURE,
- 1, false, this);
+ mBufferItemConsumer = sp<BLASTBufferItemConsumer>::make(mProducer, mConsumer,
+ GraphicBuffer::USAGE_HW_COMPOSER |
+ GraphicBuffer::USAGE_HW_TEXTURE,
+ 1, false, this);
#else
- mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
- GraphicBuffer::USAGE_HW_COMPOSER |
- GraphicBuffer::USAGE_HW_TEXTURE,
- 1, false, this);
+ mBufferItemConsumer = sp<BLASTBufferItemConsumer>::make(mConsumer,
+ GraphicBuffer::USAGE_HW_COMPOSER |
+ GraphicBuffer::USAGE_HW_TEXTURE,
+ 1, false, this);
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
// since the adapter is in the client process, set dequeue timeout
// explicitly so that dequeueBuffer will block
@@ -637,7 +637,8 @@
bufferItem.mScalingMode, crop);
auto releaseBufferCallback = makeReleaseBufferCallbackThunk();
- sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
+ sp<Fence> fence =
+ bufferItem.mFence ? sp<Fence>::make(bufferItem.mFence->dup()) : Fence::NO_FENCE;
nsecs_t dequeueTime = -1;
{
@@ -936,15 +937,22 @@
: Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {}
void allocateBuffers() override {
+ ATRACE_CALL();
uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth;
uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight;
auto gbp = getIGraphicBufferProducer();
- std::thread ([reqWidth, reqHeight, gbp=getIGraphicBufferProducer(),
- reqFormat=mReqFormat, reqUsage=mReqUsage] () {
+ std::thread allocateThread([reqWidth, reqHeight, gbp = getIGraphicBufferProducer(),
+ reqFormat = mReqFormat, reqUsage = mReqUsage]() {
+ if (com_android_graphics_libgui_flags_allocate_buffer_priority()) {
+ androidSetThreadName("allocateBuffers");
+ pid_t tid = gettid();
+ androidSetThreadPriority(tid, ANDROID_PRIORITY_DISPLAY);
+ }
+
gbp->allocateBuffers(reqWidth, reqHeight,
reqFormat, reqUsage);
-
- }).detach();
+ });
+ allocateThread.detach();
}
status_t setFrameRate(float frameRate, int8_t compatibility,
@@ -1014,7 +1022,7 @@
if (includeSurfaceControlHandle && mSurfaceControl) {
scHandle = mSurfaceControl->getHandle();
}
- return new BBQSurface(mProducer, true, scHandle, this);
+ return sp<BBQSurface>::make(mProducer, true, scHandle, this);
}
void BLASTBufferQueue::mergeWithNextTransaction(SurfaceComposerClient::Transaction* t,
@@ -1120,10 +1128,10 @@
class AsyncProducerListener : public BnProducerListener {
private:
const sp<IProducerListener> mListener;
+ AsyncProducerListener(const sp<IProducerListener>& listener) : mListener(listener) {}
+ friend class sp<AsyncProducerListener>;
public:
- AsyncProducerListener(const sp<IProducerListener>& listener) : mListener(listener) {}
-
void onBufferReleased() override {
AsyncWorker::getInstance().post([listener = mListener]() { listener->onBufferReleased(); });
}
@@ -1177,7 +1185,7 @@
return BufferQueueProducer::connect(listener, api, producerControlledByApp, output);
}
- return BufferQueueProducer::connect(new AsyncProducerListener(listener), api,
+ return BufferQueueProducer::connect(sp<AsyncProducerListener>::make(listener), api,
producerControlledByApp, output);
}
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 3b2d337..9dcd5dc 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -215,14 +215,14 @@
FlattenableUtils::read(buffer, size, flags);
if (flags & 1) {
- mGraphicBuffer = new GraphicBuffer();
+ mGraphicBuffer = sp<GraphicBuffer>::make();
status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count);
if (err) return err;
size -= FlattenableUtils::align<4>(buffer);
}
if (flags & 2) {
- mFence = new Fence();
+ mFence = sp<Fence>::make();
status_t err = mFence->unflatten(buffer, size, fds, count);
if (err) return err;
size -= FlattenableUtils::align<4>(buffer);
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 8566419..4926ceb 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "BufferItemConsumer"
//#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <utils/Errors.h>
#include <utils/Log.h>
#include <inttypes.h>
@@ -24,6 +25,7 @@
#include <com_android_graphics_libgui_flags.h>
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
+#include <gui/Surface.h>
#include <ui/BufferQueueDefs.h>
#include <ui/GraphicBuffer.h>
@@ -35,6 +37,30 @@
namespace android {
+std::tuple<sp<BufferItemConsumer>, sp<Surface>> BufferItemConsumer::create(
+ uint64_t consumerUsage, int bufferCount, bool controlledByApp,
+ bool isConsumerSurfaceFlinger) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ sp<BufferItemConsumer> bufferItemConsumer =
+ sp<BufferItemConsumer>::make(consumerUsage, bufferCount, controlledByApp,
+ isConsumerSurfaceFlinger);
+ return {bufferItemConsumer, bufferItemConsumer->getSurface()};
+#else
+ sp<IGraphicBufferProducer> igbp;
+ sp<IGraphicBufferConsumer> igbc;
+ BufferQueue::createBufferQueue(&igbp, &igbc, isConsumerSurfaceFlinger);
+ sp<BufferItemConsumer> bufferItemConsumer =
+ sp<BufferItemConsumer>::make(igbc, consumerUsage, bufferCount, controlledByApp);
+ return {bufferItemConsumer, sp<Surface>::make(igbp, controlledByApp)};
+#endif
+}
+
+sp<BufferItemConsumer> BufferItemConsumer::create(const sp<IGraphicBufferConsumer>& consumer,
+ uint64_t consumerUsage, int bufferCount,
+ bool controlledByApp) {
+ return sp<BufferItemConsumer>::make(consumer, consumerUsage, bufferCount, controlledByApp);
+}
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
BufferItemConsumer::BufferItemConsumer(uint64_t consumerUsage, int bufferCount,
bool controlledByApp, bool isConsumerSurfaceFlinger)
@@ -107,13 +133,36 @@
return OK;
}
+status_t BufferItemConsumer::attachBuffer(const sp<GraphicBuffer>& buffer) {
+ if (!buffer) {
+ BI_LOGE("BufferItemConsumer::attachBuffer no input buffer specified.");
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mMutex);
+
+ int slot = INVALID_BUFFER_SLOT;
+ status_t status = mConsumer->attachBuffer(&slot, buffer);
+ if (status != OK) {
+ BI_LOGE("BufferItemConsumer::attachBuffer unable to attach buffer %d", status);
+ return status;
+ }
+
+ mSlots[slot] = {
+ .mGraphicBuffer = buffer,
+ .mFence = nullptr,
+ .mFrameNumber = 0,
+ };
+
+ return OK;
+}
+
status_t BufferItemConsumer::releaseBuffer(const BufferItem &item,
const sp<Fence>& releaseFence) {
Mutex::Autolock _l(mMutex);
return releaseBufferSlotLocked(item.mSlot, item.mGraphicBuffer, releaseFence);
}
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
status_t BufferItemConsumer::releaseBuffer(const sp<GraphicBuffer>& buffer,
const sp<Fence>& releaseFence) {
Mutex::Autolock _l(mMutex);
@@ -129,7 +178,6 @@
return releaseBufferSlotLocked(slotIndex, buffer, releaseFence);
}
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
status_t BufferItemConsumer::releaseBufferSlotLocked(int slotIndex, const sp<GraphicBuffer>& buffer,
const sp<Fence>& releaseFence) {
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index f1374e2..f21ac18 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -125,15 +125,16 @@
LOG_ALWAYS_FATAL_IF(outConsumer == nullptr,
"BufferQueue: outConsumer must not be NULL");
- sp<BufferQueueCore> core(new BufferQueueCore());
+ sp<BufferQueueCore> core = sp<BufferQueueCore>::make();
LOG_ALWAYS_FATAL_IF(core == nullptr,
"BufferQueue: failed to create BufferQueueCore");
- sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));
+ sp<IGraphicBufferProducer> producer =
+ sp<BufferQueueProducer>::make(core, consumerIsSurfaceFlinger);
LOG_ALWAYS_FATAL_IF(producer == nullptr,
"BufferQueue: failed to create BufferQueueProducer");
- sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
+ sp<IGraphicBufferConsumer> consumer = sp<BufferQueueConsumer>::make(core);
LOG_ALWAYS_FATAL_IF(consumer == nullptr,
"BufferQueue: failed to create BufferQueueConsumer");
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 270bfbd..4681c9e 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -14,10 +14,6 @@
* limitations under the License.
*/
-#include <inttypes.h>
-#include <pwd.h>
-#include <sys/types.h>
-
#define LOG_TAG "BufferQueueConsumer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
@@ -48,6 +44,11 @@
#include <com_android_graphics_libgui_flags.h>
+#include <inttypes.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <optional>
+
namespace android {
// Macros for include BufferQueueCore information in log messages
@@ -767,11 +768,15 @@
return NO_ERROR;
}
+status_t BufferQueueConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+ return setMaxAcquiredBufferCount(maxAcquiredBuffers, std::nullopt);
+}
+
status_t BufferQueueConsumer::setMaxAcquiredBufferCount(
- int maxAcquiredBuffers) {
+ int maxAcquiredBuffers, std::optional<OnBufferReleasedCallback> onBuffersReleasedCallback) {
ATRACE_FORMAT("%s(%d)", __func__, maxAcquiredBuffers);
- sp<IConsumerListener> listener;
+ std::optional<OnBufferReleasedCallback> callback;
{ // Autolock scope
std::unique_lock<std::mutex> lock(mCore->mMutex);
@@ -833,13 +838,20 @@
BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
VALIDATE_CONSISTENCY();
- if (delta < 0 && mCore->mBufferReleasedCbEnabled) {
- listener = mCore->mConsumerListener;
+ if (delta < 0) {
+ if (onBuffersReleasedCallback) {
+ callback = std::move(onBuffersReleasedCallback);
+ } else if (mCore->mBufferReleasedCbEnabled) {
+ callback = [listener = mCore->mConsumerListener]() {
+ listener->onBuffersReleased();
+ };
+ }
}
}
+
// Call back without lock held
- if (listener != nullptr) {
- listener->onBuffersReleased();
+ if (callback) {
+ (*callback)();
}
return NO_ERROR;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index c241482..5961b41 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -693,11 +693,11 @@
.requestorName = {mConsumerName.c_str(), mConsumerName.size()},
.extras = std::move(tempOptions),
};
- sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest);
+ sp<GraphicBuffer> graphicBuffer = sp<GraphicBuffer>::make(allocRequest);
#else
sp<GraphicBuffer> graphicBuffer =
- new GraphicBuffer(width, height, format, BQ_LAYER_COUNT, usage,
- {mConsumerName.c_str(), mConsumerName.size()});
+ sp<GraphicBuffer>::make(width, height, format, BQ_LAYER_COUNT, usage,
+ std::string{mConsumerName.c_str(), mConsumerName.size()});
#endif
status_t error = graphicBuffer->initCheck();
@@ -1464,7 +1464,7 @@
#ifndef NO_BINDER
if (IInterface::asBinder(listener)->remoteBinder() != nullptr) {
status = IInterface::asBinder(listener)->linkToDeath(
- static_cast<IBinder::DeathRecipient*>(this));
+ sp<IBinder::DeathRecipient>::fromExisting(this));
if (status != NO_ERROR) {
BQ_LOGE("connect: linkToDeath failed: %s (%d)",
strerror(-status), status);
@@ -1553,8 +1553,7 @@
IInterface::asBinder(mCore->mLinkedToDeath);
// This can fail if we're here because of the death
// notification, but we just ignore it
- token->unlinkToDeath(
- static_cast<IBinder::DeathRecipient*>(this));
+ token->unlinkToDeath(static_cast<IBinder::DeathRecipient*>(this));
}
#endif
mCore->mSharedBufferSlot =
@@ -1685,11 +1684,11 @@
#endif
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
- sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest);
+ sp<GraphicBuffer> graphicBuffer = sp<GraphicBuffer>::make(allocRequest);
#else
- sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
- allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
- allocUsage, allocName);
+ sp<GraphicBuffer> graphicBuffer =
+ sp<GraphicBuffer>::make(allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
+ allocUsage, allocName);
#endif
status_t result = graphicBuffer->initCheck();
diff --git a/libs/gui/BufferReleaseChannel.cpp b/libs/gui/BufferReleaseChannel.cpp
index e9cb013..4f495d0 100644
--- a/libs/gui/BufferReleaseChannel.cpp
+++ b/libs/gui/BufferReleaseChannel.cpp
@@ -108,7 +108,7 @@
status_t BufferReleaseChannel::Message::unflatten(void const*& buffer, size_t& size,
int const*& fds, size_t& count) {
- releaseFence = new Fence();
+ releaseFence = sp<Fence>::make();
if (status_t err = releaseFence->unflatten(buffer, size, fds, count); err != OK) {
return err;
}
@@ -344,4 +344,4 @@
return STATUS_OK;
}
-} // namespace android::gui
\ No newline at end of file
+} // namespace android::gui
diff --git a/libs/gui/Choreographer.cpp b/libs/gui/Choreographer.cpp
index fb3e0f1..80a3543 100644
--- a/libs/gui/Choreographer.cpp
+++ b/libs/gui/Choreographer.cpp
@@ -20,6 +20,7 @@
#include <gui/Choreographer.h>
#include <gui/TraceUtils.h>
#include <jni.h>
+#include <utils/Looper.h>
#undef LOG_TAG
#define LOG_TAG "AChoreographer"
@@ -100,7 +101,7 @@
return nullptr;
}
}
- return gChoreographer.get();
+ return gChoreographer;
}
Choreographer::Choreographer(const sp<Looper>& looper, const sp<IBinder>& layerHandle)
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 67de742..5b89c6e 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -31,6 +31,7 @@
#include <gui/BufferItem.h>
#include <gui/BufferQueue.h>
#include <gui/ConsumerBase.h>
+#include <gui/IConsumerListener.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
@@ -68,8 +69,8 @@
#endif
mAbandoned(false),
mConsumer(bufferQueue),
- mPrevFinalReleaseFence(Fence::NO_FENCE) {
- initialize(controlledByApp);
+ mPrevFinalReleaseFence(Fence::NO_FENCE),
+ mIsControlledByApp(controlledByApp) {
}
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
@@ -79,11 +80,11 @@
mSlots(BufferQueueDefs::NUM_BUFFER_SLOTS),
#endif
mAbandoned(false),
- mPrevFinalReleaseFence(Fence::NO_FENCE) {
+ mPrevFinalReleaseFence(Fence::NO_FENCE),
+ mIsControlledByApp(controlledByApp) {
sp<IGraphicBufferProducer> producer;
BufferQueue::createBufferQueue(&producer, &mConsumer, consumerIsSurfaceFlinger);
mSurface = sp<Surface>::make(producer, controlledByApp);
- initialize(controlledByApp);
}
ConsumerBase::ConsumerBase(const sp<IGraphicBufferProducer>& producer,
@@ -95,24 +96,27 @@
mAbandoned(false),
mConsumer(consumer),
mSurface(sp<Surface>::make(producer, controlledByApp)),
- mPrevFinalReleaseFence(Fence::NO_FENCE) {
- initialize(controlledByApp);
+ mPrevFinalReleaseFence(Fence::NO_FENCE),
+ mIsControlledByApp(controlledByApp) {
}
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
-void ConsumerBase::initialize(bool controlledByApp) {
+void ConsumerBase::onFirstRef() {
+ ConsumerListener::onFirstRef();
+ initialize();
+}
+
+void ConsumerBase::initialize() {
// Choose a name using the PID and a process-unique ID.
mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
- // Note that we can't create an sp<...>(this) in a ctor that will not keep a
- // reference once the ctor ends, as that would cause the refcount of 'this'
- // dropping to 0 at the end of the ctor. Since all we need is a wp<...>
- // that's what we create.
- wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);
- sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);
+ // Here we depend on an sp/wp having been created for `this`. For this
+ // reason, initialize() cannot be called from a ctor.
+ wp<ConsumerListener> listener = wp<ConsumerListener>::fromExisting(this);
+ sp<IConsumerListener> proxy = sp<BufferQueue::ProxyConsumerListener>::make(listener);
- status_t err = mConsumer->consumerConnect(proxy, controlledByApp);
+ status_t err = mConsumer->consumerConnect(proxy, mIsControlledByApp);
if (err != NO_ERROR) {
CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)",
strerror(-err), err);
@@ -260,7 +264,10 @@
void ConsumerBase::onBuffersReleased() {
Mutex::Autolock lock(mMutex);
+ onBuffersReleasedLocked();
+}
+void ConsumerBase::onBuffersReleasedLocked() {
CB_LOGV("onBuffersReleased");
if (mAbandoned) {
@@ -477,10 +484,10 @@
CB_LOGE("setMaxAcquiredBufferCount: ConsumerBase is abandoned!");
return NO_INIT;
}
- return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers);
+ return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers,
+ {[this]() { onBuffersReleasedLocked(); }});
}
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
status_t ConsumerBase::setConsumerIsProtected(bool isProtected) {
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
@@ -489,7 +496,6 @@
}
return mConsumer->setConsumerIsProtected(isProtected);
}
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
sp<NativeHandle> ConsumerBase::getSidebandStream() const {
Mutex::Autolock _l(mMutex);
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 23b432e..ecbceb7 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -20,7 +20,11 @@
#include <com_android_graphics_libgui_flags.h>
#include <gui/BufferItem.h>
+#include <gui/BufferQueue.h>
#include <gui/CpuConsumer.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
#include <utils/Log.h>
#define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__)
@@ -31,6 +35,28 @@
namespace android {
+std::tuple<sp<CpuConsumer>, sp<Surface>> CpuConsumer::create(size_t maxLockedBuffers,
+ bool controlledByApp,
+ bool isConsumerSurfaceFlinger) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ sp<CpuConsumer> consumer =
+ sp<CpuConsumer>::make(maxLockedBuffers, controlledByApp, isConsumerSurfaceFlinger);
+ return {consumer, consumer->getSurface()};
+#else
+ sp<IGraphicBufferProducer> igbp;
+ sp<IGraphicBufferConsumer> igbc;
+ BufferQueue::createBufferQueue(&igbp, &igbc, isConsumerSurfaceFlinger);
+
+ return {sp<CpuConsumer>::make(igbc, maxLockedBuffers, controlledByApp),
+ sp<Surface>::make(igbp, controlledByApp)};
+#endif
+}
+
+sp<CpuConsumer> CpuConsumer::create(const sp<IGraphicBufferConsumer>& bq, size_t maxLockedBuffers,
+ bool controlledByApp) {
+ return sp<CpuConsumer>::make(bq, maxLockedBuffers, controlledByApp);
+}
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
CpuConsumer::CpuConsumer(size_t maxLockedBuffers, bool controlledByApp,
bool isConsumerSurfaceFlinger)
@@ -230,7 +256,7 @@
return err;
}
- sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+ sp<Fence> fence(fenceFd >= 0 ? sp<Fence>::make(fenceFd) : Fence::NO_FENCE);
addReleaseFenceLocked(ab.mSlot, ab.mGraphicBuffer, fence);
releaseBufferLocked(ab.mSlot, ab.mGraphicBuffer);
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 052b8ed..2c5770d 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -37,6 +37,7 @@
#include <gui/DebugEGLImageTracker.h>
#include <gui/GLConsumer.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
@@ -101,6 +102,50 @@
return hasIt;
}
+std::tuple<sp<GLConsumer>, sp<Surface>> GLConsumer::create(uint32_t tex, uint32_t textureTarget,
+ bool useFenceSync,
+ bool isControlledByApp) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ sp<GLConsumer> consumer =
+ sp<GLConsumer>::make(tex, textureTarget, useFenceSync, isControlledByApp);
+ return {consumer, consumer->getSurface()};
+#else
+ sp<IGraphicBufferProducer> igbp;
+ sp<IGraphicBufferConsumer> igbc;
+ BufferQueue::createBufferQueue(&igbp, &igbc);
+
+ return {sp<GLConsumer>::make(igbc, tex, textureTarget, useFenceSync, isControlledByApp),
+ sp<Surface>::make(igbp, isControlledByApp)};
+#endif
+}
+
+std::tuple<sp<GLConsumer>, sp<Surface>> GLConsumer::create(uint32_t textureTarget,
+ bool useFenceSync,
+ bool isControlledByApp) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ sp<GLConsumer> consumer = sp<GLConsumer>::make(textureTarget, useFenceSync, isControlledByApp);
+ return {consumer, consumer->getSurface()};
+#else
+ sp<IGraphicBufferProducer> igbp;
+ sp<IGraphicBufferConsumer> igbc;
+ BufferQueue::createBufferQueue(&igbp, &igbc);
+
+ return {sp<GLConsumer>::make(igbc, textureTarget, useFenceSync, isControlledByApp),
+ sp<Surface>::make(igbp, isControlledByApp)};
+#endif
+}
+
+sp<GLConsumer> GLConsumer::create(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
+ uint32_t textureTarget, bool useFenceSync,
+ bool isControlledByApp) {
+ return sp<GLConsumer>::make(bq, tex, textureTarget, useFenceSync, isControlledByApp);
+}
+
+sp<GLConsumer> GLConsumer::create(const sp<IGraphicBufferConsumer>& bq, uint32_t textureTarget,
+ bool useFenceSync, bool isControlledByApp) {
+ return sp<GLConsumer>::make(bq, textureTarget, useFenceSync, isControlledByApp);
+}
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
GLConsumer::GLConsumer(uint32_t tex, uint32_t texTarget, bool useFenceSync, bool isControlledByApp)
: ConsumerBase(isControlledByApp, /* isConsumerSurfaceFlinger */ false),
@@ -333,7 +378,7 @@
}
if (mReleasedTexImage == nullptr) {
- mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
+ mReleasedTexImage = sp<EglImage>::make(getDebugTexImageBuffer());
}
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
@@ -365,10 +410,10 @@
if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) {
// The first time, create the debug texture in case the application
// continues to use it.
- sp<GraphicBuffer> buffer = new GraphicBuffer(
- kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
- DEFAULT_USAGE_FLAGS | GraphicBuffer::USAGE_SW_WRITE_RARELY,
- "[GLConsumer debug texture]");
+ sp<GraphicBuffer> buffer =
+ sp<GraphicBuffer>::make(kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
+ DEFAULT_USAGE_FLAGS | GraphicBuffer::USAGE_SW_WRITE_RARELY,
+ "[GLConsumer debug texture]");
uint32_t* bits;
buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
uint32_t stride = buffer->getStride();
@@ -400,7 +445,7 @@
// replaces any old EglImage with a new one (using the new buffer).
if (item->mGraphicBuffer != nullptr) {
int slot = item->mSlot;
- mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
+ mEglSlots[slot].mEglImage = sp<EglImage>::make(item->mGraphicBuffer);
}
return NO_ERROR;
@@ -737,7 +782,7 @@
"fd: %#x", eglGetError());
return UNKNOWN_ERROR;
}
- sp<Fence> fence(new Fence(fenceFd));
+ sp<Fence> fence = sp<Fence>::make(fenceFd);
status_t err = addReleaseFenceLocked(mCurrentTexture,
mCurrentTextureImage->graphicBuffer(), fence);
if (err != OK) {
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 9f71eb1..1d1910e 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -104,7 +104,7 @@
}
bool nonNull = reply.readInt32();
if (nonNull) {
- *buf = new GraphicBuffer();
+ *buf = sp<GraphicBuffer>::make();
result = reply.read(**buf);
if(result != NO_ERROR) {
(*buf).clear();
@@ -197,7 +197,7 @@
}
*buf = reply.readInt32();
- *fence = new Fence();
+ *fence = sp<Fence>::make();
result = reply.read(**fence);
if (result != NO_ERROR) {
fence->clear();
@@ -293,7 +293,7 @@
if (result == NO_ERROR) {
bool nonNull = reply.readInt32();
if (nonNull) {
- *outBuffer = new GraphicBuffer;
+ *outBuffer = sp<GraphicBuffer>::make();
result = reply.read(**outBuffer);
if (result != NO_ERROR) {
outBuffer->clear();
@@ -302,7 +302,7 @@
}
nonNull = reply.readInt32();
if (nonNull) {
- *outFence = new Fence;
+ *outFence = sp<Fence>::make();
result = reply.read(**outFence);
if (result != NO_ERROR) {
outBuffer->clear();
@@ -640,7 +640,7 @@
bool hasBuffer = reply.readBool();
sp<GraphicBuffer> buffer;
if (hasBuffer) {
- buffer = new GraphicBuffer();
+ buffer = sp<GraphicBuffer>::make();
result = reply.read(*buffer);
if (result == NO_ERROR) {
result = reply.read(outTransformMatrix, sizeof(float) * 16);
@@ -650,7 +650,7 @@
ALOGE("getLastQueuedBuffer failed to read buffer: %d", result);
return result;
}
- sp<Fence> fence(new Fence);
+ sp<Fence> fence = sp<Fence>::make();
result = reply.read(*fence);
if (result != NO_ERROR) {
ALOGE("getLastQueuedBuffer failed to read fence: %d", result);
@@ -687,7 +687,7 @@
}
sp<GraphicBuffer> buffer;
if (hasBuffer) {
- buffer = new GraphicBuffer();
+ buffer = sp<GraphicBuffer>::make();
result = reply.read(*buffer);
if (result == NO_ERROR) {
result = reply.read(*outRect);
@@ -700,7 +700,7 @@
ALOGE("getLastQueuedBuffer failed to read buffer: %d", result);
return result;
}
- sp<Fence> fence(new Fence);
+ sp<Fence> fence = sp<Fence>::make();
result = reply.read(*fence);
if (result != NO_ERROR) {
ALOGE("getLastQueuedBuffer failed to read fence: %d", result);
@@ -1232,7 +1232,7 @@
}
case ATTACH_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
- sp<GraphicBuffer> buffer = new GraphicBuffer();
+ sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make();
status_t result = data.read(*buffer.get());
int slot = 0;
if (result == NO_ERROR) {
@@ -1250,7 +1250,7 @@
return result;
}
for (sp<GraphicBuffer>& buffer : buffers) {
- buffer = new GraphicBuffer();
+ buffer = sp<GraphicBuffer>::make();
result = data.read(*buffer.get());
if (result != NO_ERROR) {
return result;
@@ -1306,7 +1306,7 @@
case CANCEL_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
int buf = data.readInt32();
- sp<Fence> fence = new Fence();
+ sp<Fence> fence = sp<Fence>::make();
status_t result = data.read(*fence.get());
if (result == NO_ERROR) {
result = cancelBuffer(buf, fence);
diff --git a/libs/gui/IGraphicBufferProducerFlattenables.cpp b/libs/gui/IGraphicBufferProducerFlattenables.cpp
index 8b2e2dd..393e1c3 100644
--- a/libs/gui/IGraphicBufferProducerFlattenables.cpp
+++ b/libs/gui/IGraphicBufferProducerFlattenables.cpp
@@ -105,7 +105,7 @@
: std::nullopt;
#endif // COM_ANDROID_GRAPHICS_LIBUI_FLAGS_APPLY_PICTURE_PROFILES
- fence = new Fence();
+ fence = sp<Fence>::make();
status_t result = fence->unflatten(buffer, size, fds, count);
if (result != NO_ERROR) {
return result;
@@ -228,7 +228,7 @@
FlattenableUtils::read(fBuffer, size, result);
int32_t isBufferNull = 0;
FlattenableUtils::read(fBuffer, size, isBufferNull);
- buffer = new GraphicBuffer();
+ buffer = sp<GraphicBuffer>::make();
if (!isBufferNull) {
status_t status = buffer->unflatten(fBuffer, size, fds, count);
if (status != NO_ERROR) {
@@ -323,7 +323,7 @@
FlattenableUtils::read(buffer, size, slot);
FlattenableUtils::read(buffer, size, bufferAge);
- fence = new Fence();
+ fence = sp<Fence>::make();
status_t status = fence->unflatten(buffer, size, fds, count);
if (status != NO_ERROR) {
return status;
@@ -395,7 +395,7 @@
FlattenableUtils::read(buffer, size, slot);
- fence = new Fence();
+ fence = sp<Fence>::make();
return fence->unflatten(buffer, size, fds, count);
}
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 83fc827..ed28e79 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -92,7 +92,7 @@
if (err != NO_ERROR) return err;
if (hasFence) {
- gpuCompositionDoneFence = new Fence();
+ gpuCompositionDoneFence = sp<Fence>::make();
err = input->read(*gpuCompositionDoneFence);
if (err != NO_ERROR) return err;
}
@@ -157,7 +157,7 @@
SAFE_PARCEL(input->readBool, &hasFence);
if (hasFence) {
- previousReleaseFence = new Fence();
+ previousReleaseFence = sp<Fence>::make();
SAFE_PARCEL(input->read, *previousReleaseFence);
}
bool hasTransformHint = false;
@@ -216,7 +216,7 @@
return err;
}
if (hasFence) {
- presentFence = new Fence();
+ presentFence = sp<Fence>::make();
err = input->read(*presentFence);
if (err != NO_ERROR) {
return err;
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index ebfc62f..ad95d1a 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -55,6 +55,28 @@
using gui::FocusRequest;
using gui::WindowInfoHandle;
+namespace {
+bool isSameWindowHandle(const sp<WindowInfoHandle>& lhs, const sp<WindowInfoHandle>& rhs) {
+ if (lhs == rhs) {
+ return true;
+ }
+
+ if (!lhs || !rhs) {
+ return false;
+ }
+
+ return *lhs->getInfo() == *rhs->getInfo();
+};
+
+bool isSameSurfaceControl(const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs) {
+ if (lhs == rhs) {
+ return true;
+ }
+
+ return SurfaceControl::isSameSurface(lhs, rhs);
+};
+} // namespace
+
layer_state_t::layer_state_t()
: surface(nullptr),
layerId(-1),
@@ -73,7 +95,6 @@
transformToDisplayInverse(false),
crop({0, 0, -1, -1}),
dataspace(ui::Dataspace::UNKNOWN),
- surfaceDamageRegion(),
api(-1),
colorTransform(mat4()),
bgColor(0),
@@ -117,19 +138,21 @@
SAFE_PARCEL(output.writeFloat, crop.left);
SAFE_PARCEL(output.writeFloat, crop.bottom);
SAFE_PARCEL(output.writeFloat, crop.right);
- SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, relativeLayerSurfaceControl);
- SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, parentSurfaceControlForChild);
+ SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output,
+ mNotDefCmpState.relativeLayerSurfaceControl);
+ SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output,
+ mNotDefCmpState.parentSurfaceControlForChild);
SAFE_PARCEL(output.writeFloat, color.r);
SAFE_PARCEL(output.writeFloat, color.g);
SAFE_PARCEL(output.writeFloat, color.b);
SAFE_PARCEL(output.writeFloat, color.a);
- SAFE_PARCEL(windowInfoHandle->writeToParcel, &output);
- SAFE_PARCEL(output.write, transparentRegion);
+ SAFE_PARCEL(mNotDefCmpState.windowInfoHandle->writeToParcel, &output);
+ SAFE_PARCEL(output.write, mNotDefCmpState.transparentRegion);
SAFE_PARCEL(output.writeUint32, bufferTransform);
SAFE_PARCEL(output.writeBool, transformToDisplayInverse);
SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dataspace));
SAFE_PARCEL(output.write, hdrMetadata);
- SAFE_PARCEL(output.write, surfaceDamageRegion);
+ SAFE_PARCEL(output.write, mNotDefCmpState.surfaceDamageRegion);
SAFE_PARCEL(output.writeInt32, api);
if (sidebandStream) {
@@ -241,8 +264,10 @@
SAFE_PARCEL(input.readFloat, &crop.bottom);
SAFE_PARCEL(input.readFloat, &crop.right);
- SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &relativeLayerSurfaceControl);
- SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &parentSurfaceControlForChild);
+ SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input,
+ &mNotDefCmpState.relativeLayerSurfaceControl);
+ SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input,
+ &mNotDefCmpState.parentSurfaceControlForChild);
float tmpFloat = 0;
SAFE_PARCEL(input.readFloat, &tmpFloat);
@@ -254,9 +279,9 @@
SAFE_PARCEL(input.readFloat, &tmpFloat);
color.a = tmpFloat;
- SAFE_PARCEL(windowInfoHandle->readFromParcel, &input);
+ SAFE_PARCEL(mNotDefCmpState.windowInfoHandle->readFromParcel, &input);
- SAFE_PARCEL(input.read, transparentRegion);
+ SAFE_PARCEL(input.read, mNotDefCmpState.transparentRegion);
SAFE_PARCEL(input.readUint32, &bufferTransform);
SAFE_PARCEL(input.readBool, &transformToDisplayInverse);
@@ -265,7 +290,7 @@
dataspace = static_cast<ui::Dataspace>(tmpUint32);
SAFE_PARCEL(input.read, hdrMetadata);
- SAFE_PARCEL(input.read, surfaceDamageRegion);
+ SAFE_PARCEL(input.read, mNotDefCmpState.surfaceDamageRegion);
SAFE_PARCEL(input.readInt32, &api);
bool tmpBool = false;
@@ -583,7 +608,7 @@
}
if (other.what & eTransparentRegionChanged) {
what |= eTransparentRegionChanged;
- transparentRegion = other.transparentRegion;
+ mNotDefCmpState.transparentRegion = other.mNotDefCmpState.transparentRegion;
}
if (other.what & eFlagsChanged) {
what |= eFlagsChanged;
@@ -615,11 +640,13 @@
what |= eRelativeLayerChanged;
what &= ~eLayerChanged;
z = other.z;
- relativeLayerSurfaceControl = other.relativeLayerSurfaceControl;
+ mNotDefCmpState.relativeLayerSurfaceControl =
+ other.mNotDefCmpState.relativeLayerSurfaceControl;
}
if (other.what & eReparent) {
what |= eReparent;
- parentSurfaceControlForChild = other.parentSurfaceControlForChild;
+ mNotDefCmpState.parentSurfaceControlForChild =
+ other.mNotDefCmpState.parentSurfaceControlForChild;
}
if (other.what & eBufferTransformChanged) {
what |= eBufferTransformChanged;
@@ -665,7 +692,7 @@
}
if (other.what & eSurfaceDamageRegionChanged) {
what |= eSurfaceDamageRegionChanged;
- surfaceDamageRegion = other.surfaceDamageRegion;
+ mNotDefCmpState.surfaceDamageRegion = other.mNotDefCmpState.surfaceDamageRegion;
}
if (other.what & eApiChanged) {
what |= eApiChanged;
@@ -684,7 +711,8 @@
}
if (other.what & eInputInfoChanged) {
what |= eInputInfoChanged;
- windowInfoHandle = new WindowInfoHandle(*other.windowInfoHandle);
+ mNotDefCmpState.windowInfoHandle =
+ sp<WindowInfoHandle>::make(*other.mNotDefCmpState.windowInfoHandle);
}
if (other.what & eBackgroundColorChanged) {
what |= eBackgroundColorChanged;
@@ -807,7 +835,8 @@
CHECK_DIFF(diff, eAlphaChanged, other, color.a);
CHECK_DIFF(diff, eMatrixChanged, other, matrix);
if (other.what & eTransparentRegionChanged &&
- (!transparentRegion.hasSameRects(other.transparentRegion))) {
+ (!mNotDefCmpState.transparentRegion.hasSameRects(
+ other.mNotDefCmpState.transparentRegion))) {
diff |= eTransparentRegionChanged;
}
if (other.what & eFlagsChanged) {
@@ -824,8 +853,8 @@
diff &= ~eLayerChanged;
}
if (other.what & eReparent &&
- !SurfaceControl::isSameSurface(parentSurfaceControlForChild,
- other.parentSurfaceControlForChild)) {
+ !SurfaceControl::isSameSurface(mNotDefCmpState.parentSurfaceControlForChild,
+ other.mNotDefCmpState.parentSurfaceControlForChild)) {
diff |= eReparent;
}
CHECK_DIFF(diff, eBufferTransformChanged, other, bufferTransform);
@@ -839,7 +868,8 @@
CHECK_DIFF(diff, eCachingHintChanged, other, cachingHint);
CHECK_DIFF(diff, eHdrMetadataChanged, other, hdrMetadata);
if (other.what & eSurfaceDamageRegionChanged &&
- (!surfaceDamageRegion.hasSameRects(other.surfaceDamageRegion))) {
+ (!mNotDefCmpState.surfaceDamageRegion.hasSameRects(
+ other.mNotDefCmpState.surfaceDamageRegion))) {
diff |= eSurfaceDamageRegionChanged;
}
CHECK_DIFF(diff, eApiChanged, other, api);
@@ -901,6 +931,38 @@
SAFE_PARCEL(input.readFloat, &dsdy);
return NO_ERROR;
}
+void layer_state_t::updateTransparentRegion(const Region& transparentRegion) {
+ what |= eTransparentRegionChanged;
+ mNotDefCmpState.transparentRegion = transparentRegion;
+}
+void layer_state_t::updateSurfaceDamageRegion(const Region& surfaceDamageRegion) {
+ what |= eSurfaceDamageRegionChanged;
+ mNotDefCmpState.surfaceDamageRegion = surfaceDamageRegion;
+}
+void layer_state_t::updateRelativeLayer(const sp<SurfaceControl>& relativeTo, int32_t z) {
+ what |= layer_state_t::eRelativeLayerChanged;
+ what &= ~layer_state_t::eLayerChanged;
+ mNotDefCmpState.relativeLayerSurfaceControl = relativeTo;
+ this->z = z;
+}
+void layer_state_t::updateParentLayer(const sp<SurfaceControl>& newParent) {
+ what |= layer_state_t::eReparent;
+ mNotDefCmpState.parentSurfaceControlForChild =
+ newParent ? newParent->getParentingLayer() : nullptr;
+}
+void layer_state_t::updateInputWindowInfo(sp<gui::WindowInfoHandle>&& info) {
+ what |= eInputInfoChanged;
+ mNotDefCmpState.windowInfoHandle = std::move(info);
+}
+
+bool layer_state_t::NotDefaultComparableState::operator==(
+ const NotDefaultComparableState& rhs) const {
+ return transparentRegion.hasSameRects(rhs.transparentRegion) &&
+ surfaceDamageRegion.hasSameRects(rhs.surfaceDamageRegion) &&
+ isSameWindowHandle(windowInfoHandle, rhs.windowInfoHandle) &&
+ isSameSurfaceControl(relativeLayerSurfaceControl, rhs.relativeLayerSurfaceControl) &&
+ isSameSurfaceControl(parentSurfaceControlForChild, rhs.parentSurfaceControlForChild);
+}
// ------------------------------- InputWindowCommands ----------------------------------------
@@ -1001,13 +1063,13 @@
bool tmpBool = false;
SAFE_PARCEL(input->readBool, &tmpBool);
if (tmpBool) {
- buffer = new GraphicBuffer();
+ buffer = sp<GraphicBuffer>::make();
SAFE_PARCEL(input->read, *buffer);
}
SAFE_PARCEL(input->readBool, &tmpBool);
if (tmpBool) {
- acquireFence = new Fence();
+ acquireFence = sp<Fence>::make();
SAFE_PARCEL(input->read, *acquireFence);
}
@@ -1034,8 +1096,8 @@
}
status_t TrustedPresentationListener::writeToParcel(Parcel* parcel) const {
- SAFE_PARCEL(parcel->writeStrongBinder, callbackInterface);
- SAFE_PARCEL(parcel->writeInt32, callbackId);
+ SAFE_PARCEL(parcel->writeStrongBinder, mState.callbackInterface);
+ SAFE_PARCEL(parcel->writeInt32, mState.callbackId);
return NO_ERROR;
}
@@ -1043,9 +1105,9 @@
sp<IBinder> tmpBinder = nullptr;
SAFE_PARCEL(parcel->readNullableStrongBinder, &tmpBinder);
if (tmpBinder) {
- callbackInterface = checked_interface_cast<ITransactionCompletedListener>(tmpBinder);
+ mState.callbackInterface = checked_interface_cast<ITransactionCompletedListener>(tmpBinder);
}
- SAFE_PARCEL(parcel->readInt32, &callbackId);
+ SAFE_PARCEL(parcel->readInt32, &mState.callbackId);
return NO_ERROR;
}
diff --git a/libs/gui/ScreenCaptureResults.cpp b/libs/gui/ScreenCaptureResults.cpp
index 2de023e..30b5785 100644
--- a/libs/gui/ScreenCaptureResults.cpp
+++ b/libs/gui/ScreenCaptureResults.cpp
@@ -18,6 +18,7 @@
#include <private/gui/ParcelUtils.h>
#include <ui/FenceResult.h>
+#include <ui/GraphicBuffer.h>
namespace android::gui {
@@ -54,7 +55,7 @@
bool hasGraphicBuffer;
SAFE_PARCEL(parcel->readBool, &hasGraphicBuffer);
if (hasGraphicBuffer) {
- buffer = new GraphicBuffer();
+ buffer = sp<GraphicBuffer>::make();
SAFE_PARCEL(parcel->read, *buffer);
}
@@ -79,7 +80,7 @@
bool hasGainmap;
SAFE_PARCEL(parcel->readBool, &hasGainmap);
if (hasGainmap) {
- optionalGainMap = new GraphicBuffer();
+ optionalGainMap = sp<GraphicBuffer>::make();
SAFE_PARCEL(parcel->read, *optionalGainMap);
}
SAFE_PARCEL(parcel->readFloat, &hdrSdrRatio);
diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp
index 653b91b..848ae7a 100644
--- a/libs/gui/StreamSplitter.cpp
+++ b/libs/gui/StreamSplitter.cpp
@@ -47,7 +47,7 @@
return BAD_VALUE;
}
- sp<StreamSplitter> splitter(new StreamSplitter(inputQueue));
+ sp<StreamSplitter> splitter = sp<StreamSplitter>::make(inputQueue);
status_t status = splitter->mInput->consumerConnect(splitter, false);
if (status == NO_ERROR) {
splitter->mInput->setConsumerName(String8("StreamSplitter"));
@@ -82,7 +82,7 @@
Mutex::Autolock lock(mMutex);
IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
- sp<OutputListener> listener(new OutputListener(this, outputQueue));
+ sp<OutputListener> listener = sp<OutputListener>::make(this, outputQueue);
IInterface::asBinder(outputQueue)->linkToDeath(listener);
status_t status = outputQueue->connect(listener, NATIVE_WINDOW_API_CPU,
/* producerControlledByApp */ false, &queueBufferOutput);
@@ -140,7 +140,7 @@
// Initialize our reference count for this buffer
mBuffers.add(bufferItem.mGraphicBuffer->getId(),
- new BufferTracker(bufferItem.mGraphicBuffer));
+ sp<BufferTracker>::make(bufferItem.mGraphicBuffer));
IGraphicBufferProducer::QueueBufferInput queueInput(
bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp,
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index ec23365..63dcfbc 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -509,7 +509,7 @@
if (result != OK) {
return result;
}
- sp<Fence> fence(new Fence(fenceFd));
+ sp<Fence> fence = sp<Fence>::make(fenceFd);
int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
if (waitResult != OK) {
ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d",
@@ -979,7 +979,7 @@
}
return OK;
}
- sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+ sp<Fence> fence(fenceFd >= 0 ? sp<Fence>::make(fenceFd) : Fence::NO_FENCE);
mGraphicBufferProducer->cancelBuffer(i, fence);
if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot == i) {
@@ -1017,7 +1017,7 @@
ALOGE("%s: cannot find slot number for cancelled buffer", __FUNCTION__);
badSlotResult = slot;
} else {
- sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+ sp<Fence> fence(fenceFd >= 0 ? sp<Fence>::make(fenceFd) : Fence::NO_FENCE);
cancelBufferInputs[numBuffersCancelled].slot = slot;
cancelBufferInputs[numBuffersCancelled++].fence = fence;
}
@@ -1078,7 +1078,7 @@
Rect crop(Rect::EMPTY_RECT);
mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
- sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+ sp<Fence> fence(fenceFd >= 0 ? sp<Fence>::make(fenceFd) : Fence::NO_FENCE);
IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
static_cast<android_dataspace>(mDataSpace), crop, mScalingMode,
mTransform ^ mStickyTransform, fence, mStickyTransform,
@@ -2092,7 +2092,7 @@
}
int Surface::connect(int api) {
- static sp<SurfaceListener> listener = new StubSurfaceListener();
+ static sp<SurfaceListener> listener = sp<StubSurfaceListener>::make();
return connect(api, listener);
}
@@ -2104,7 +2104,7 @@
mReportRemovedBuffers = reportBufferRemoval;
if (listener != nullptr) {
- mListenerProxy = new ProducerListenerProxy(this, listener);
+ mListenerProxy = sp<ProducerListenerProxy>::make(this, listener);
}
int err =
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index df57b27..e407a63 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -123,7 +123,7 @@
explicit DeathObserver(ComposerService& mgr) : mComposerService(mgr) { }
};
- mDeathObserver = new DeathObserver(*const_cast<ComposerService*>(this));
+ mDeathObserver = sp<DeathObserver>::make(*const_cast<ComposerService*>(this));
IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver);
return true;
}
@@ -170,7 +170,7 @@
explicit DeathObserver(ComposerServiceAIDL& mgr) : mComposerService(mgr) {}
};
- mDeathObserver = new DeathObserver(*const_cast<ComposerServiceAIDL*>(this));
+ mDeathObserver = sp<DeathObserver>::make(*const_cast<ComposerServiceAIDL*>(this));
IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver);
return true;
}
@@ -202,7 +202,7 @@
DefaultComposerClient& dc = DefaultComposerClient::getInstance();
Mutex::Autolock _l(dc.mLock);
if (dc.mClient == nullptr) {
- dc.mClient = new SurfaceComposerClient;
+ dc.mClient = sp<SurfaceComposerClient>::make();
}
return dc.mClient;
}
@@ -399,7 +399,7 @@
sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() {
std::lock_guard<std::mutex> lock(sListenerInstanceMutex);
if (sInstance == nullptr) {
- sInstance = new TransactionCompletedListener;
+ sInstance = sp<TransactionCompletedListener>::make();
}
return sInstance;
}
@@ -691,7 +691,7 @@
std::scoped_lock<std::mutex> lock(mMutex);
mTrustedPresentationCallbacks[id] =
std::tuple<TrustedPresentationCallback, void*>(tpc, context);
- return new SurfaceComposerClient::PresentationCallbackRAII(this, id);
+ return sp<SurfaceComposerClient::PresentationCallbackRAII>::make(this, id);
}
void TransactionCompletedListener::clearTrustedPresentationCallback(int id) {
@@ -743,7 +743,7 @@
*/
class BufferCache : public Singleton<BufferCache> {
public:
- BufferCache() : token(new BBinder()) {}
+ BufferCache() : token(sp<BBinder>::make()) {}
sp<IBinder> getToken() {
return IInterface::asBinder(TransactionCompletedListener::getIInstance());
@@ -1357,7 +1357,7 @@
return binderStatus;
}
-sp<IBinder> SurfaceComposerClient::Transaction::sApplyToken = new BBinder();
+sp<IBinder> SurfaceComposerClient::Transaction::sApplyToken = sp<BBinder>::make();
std::mutex SurfaceComposerClient::Transaction::sApplyTokenMutex;
@@ -1391,11 +1391,16 @@
// ---------------------------------------------------------------------------
sp<IBinder> SurfaceComposerClient::createVirtualDisplay(const std::string& displayName,
- bool isSecure, const std::string& uniqueId,
+ bool isSecure, bool optimizeForPower,
+ const std::string& uniqueId,
float requestedRefreshRate) {
+ const gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy = optimizeForPower
+ ? gui::ISurfaceComposer::OptimizationPolicy::optimizeForPower
+ : gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance;
sp<IBinder> display = nullptr;
binder::Status status =
ComposerServiceAIDL::getComposerService()->createVirtualDisplay(displayName, isSecure,
+ optimizationPolicy,
uniqueId,
requestedRefreshRate,
&display);
@@ -1523,11 +1528,7 @@
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eRelativeLayerChanged;
- s->what &= ~layer_state_t::eLayerChanged;
- s->relativeLayerSurfaceControl = relativeTo;
- s->z = z;
-
+ s->updateRelativeLayer(relativeTo, z);
registerSurfaceControlForCallback(sc);
return *this;
}
@@ -1557,9 +1558,7 @@
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eTransparentRegionChanged;
- s->transparentRegion = transparentRegion;
-
+ s->updateTransparentRegion(transparentRegion);
registerSurfaceControlForCallback(sc);
return *this;
}
@@ -1721,9 +1720,7 @@
if (SurfaceControl::isSameSurface(sc, newParent)) {
return *this;
}
- s->what |= layer_state_t::eReparent;
- s->parentSurfaceControlForChild = newParent ? newParent->getParentingLayer() : nullptr;
-
+ s->updateParentLayer(newParent);
registerSurfaceControlForCallback(sc);
return *this;
}
@@ -2009,9 +2006,7 @@
mStatus = BAD_INDEX;
return *this;
}
- s->what |= layer_state_t::eSurfaceDamageRegionChanged;
- s->surfaceDamageRegion = surfaceDamageRegion;
-
+ s->updateSurfaceDamageRegion(surfaceDamageRegion);
registerSurfaceControlForCallback(sc);
return *this;
}
@@ -2130,21 +2125,20 @@
mStatus = BAD_INDEX;
return *this;
}
- s->windowInfoHandle = std::move(info);
- s->what |= layer_state_t::eInputInfoChanged;
+ s->updateInputWindowInfo(std::move(info));
return *this;
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFocusedWindow(
const FocusRequest& request) {
- mInputWindowCommands.focusRequests.push_back(request);
+ mInputWindowCommands.addFocusRequest(request);
return *this;
}
SurfaceComposerClient::Transaction&
SurfaceComposerClient::Transaction::addWindowInfosReportedListener(
sp<gui::IWindowInfosReportedListener> windowInfosReportedListener) {
- mInputWindowCommands.windowInfosReportedListeners.insert(windowInfosReportedListener);
+ mInputWindowCommands.addWindowInfosReportedListener(windowInfosReportedListener);
return *this;
}
@@ -2364,10 +2358,6 @@
return *this;
}
-bool SurfaceComposerClient::flagEdgeExtensionEffectUseShader() {
- return com::android::graphics::libgui::flags::edge_extension_shader();
-}
-
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setEdgeExtensionEffect(
const sp<SurfaceControl>& sc, const gui::EdgeExtensionParameters& effect) {
layer_state_t* s = getLayerState(sc);
@@ -2572,8 +2562,9 @@
}
s->what |= layer_state_t::eTrustedPresentationInfoChanged;
s->trustedPresentationThresholds = thresholds;
- s->trustedPresentationListener.callbackInterface = TransactionCompletedListener::getIInstance();
- s->trustedPresentationListener.callbackId = sc->getLayerId();
+ s->trustedPresentationListener.configure(
+ {.callbackInterface = TransactionCompletedListener::getIInstance(),
+ .callbackId = sc->getLayerId()});
return *this;
}
@@ -2589,8 +2580,7 @@
}
s->what |= layer_state_t::eTrustedPresentationInfoChanged;
s->trustedPresentationThresholds = TrustedPresentationThresholds();
- s->trustedPresentationListener.callbackInterface = nullptr;
- s->trustedPresentationListener.callbackId = -1;
+ s->trustedPresentationListener.clear();
return *this;
}
@@ -2683,9 +2673,9 @@
}
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
- *outSurface = new SurfaceControl(this, result.handle, result.layerId,
- toString(result.layerName), w, h, format,
- result.transformHint, flags);
+ *outSurface = sp<SurfaceControl>::make(this, result.handle, result.layerId,
+ toString(result.layerName), w, h, format,
+ result.transformHint, flags);
}
}
return err;
@@ -2701,7 +2691,8 @@
const binder::Status status = mClient->mirrorSurface(mirrorFromHandle, &result);
const status_t err = statusTFromBinderStatus(status);
if (err == NO_ERROR) {
- return new SurfaceControl(this, result.handle, result.layerId, toString(result.layerName));
+ return sp<SurfaceControl>::make(this, result.handle, result.layerId,
+ toString(result.layerName));
}
return nullptr;
}
@@ -2711,7 +2702,8 @@
const binder::Status status = mClient->mirrorDisplay(displayId.value, &result);
const status_t err = statusTFromBinderStatus(status);
if (err == NO_ERROR) {
- return new SurfaceControl(this, result.handle, result.layerId, toString(result.layerName));
+ return sp<SurfaceControl>::make(this, result.handle, result.layerId,
+ toString(result.layerName));
}
return nullptr;
}
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index b735418..1eb9b87 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -269,10 +269,11 @@
SAFE_PARCEL(parcel.readUint32, &format);
// We aren't the original owner of the surface.
- *outSurfaceControl = new SurfaceControl(new SurfaceComposerClient(
- interface_cast<ISurfaceComposerClient>(client)),
- handle.get(), layerId, layerName, width, height, format,
- transformHint);
+ *outSurfaceControl =
+ sp<SurfaceControl>::make(sp<SurfaceComposerClient>::make(
+ interface_cast<ISurfaceComposerClient>(client)),
+ handle, layerId, layerName, width, height, format,
+ transformHint);
return NO_ERROR;
}
diff --git a/libs/gui/TEST_MAPPING b/libs/gui/TEST_MAPPING
index a590c86..14d6df6 100644
--- a/libs/gui/TEST_MAPPING
+++ b/libs/gui/TEST_MAPPING
@@ -60,5 +60,34 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "libgui_test",
+ "keywords": [ "primary-device" ],
+ "options": [
+ // TODO(b/397776630): Failing on real devices.
+ {
+ "exclude-filter": "InputSurfacesTest#input_respects_scaled_touchable_region_overflow"
+ },
+ // TODO(b/233363648): Failing on real devices.
+ {
+ "exclude-filter": "SurfaceTextureGLTest#TexturingFromCpuFilledYV12BufferNpot"
+ },
+ {
+ "exclude-filter": "SurfaceTextureGLTest#TexturingFromCpuFilledYV12BufferPow2"
+ },
+ {
+ "exclude-filter": "SurfaceTextureGLTest#TexturingFromCpuFilledYV12BufferWithCrop"
+ },
+ // TODO(b/233363648): Flaky on real devices.
+ {
+ "exclude-filter": "SurfaceTextureGLToGLTest#EglMakeCurrentBeforeConsumerDeathUnrefsBuffers"
+ },
+ {
+ "exclude-filter": "SurfaceTextureGLToGLTest#EglMakeCurrentAfterConsumerDeathUnrefsBuffers"
+ }
+ ]
+ }
]
}
diff --git a/libs/gui/TransactionState.cpp b/libs/gui/TransactionState.cpp
new file mode 100644
index 0000000..9e09bc2
--- /dev/null
+++ b/libs/gui/TransactionState.cpp
@@ -0,0 +1,263 @@
+/*
+ * 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 "TransactionState"
+#include <gui/LayerState.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/TransactionState.h>
+#include <private/gui/ParcelUtils.h>
+#include <algorithm>
+
+namespace android {
+
+status_t TransactionState::writeToParcel(Parcel* parcel) const {
+ SAFE_PARCEL(parcel->writeUint64, mId);
+ SAFE_PARCEL(parcel->writeUint32, mFlags);
+ SAFE_PARCEL(parcel->writeInt64, mDesiredPresentTime);
+ SAFE_PARCEL(parcel->writeBool, mIsAutoTimestamp);
+ SAFE_PARCEL(parcel->writeParcelable, mFrameTimelineInfo);
+ SAFE_PARCEL(parcel->writeStrongBinder, mApplyToken);
+ SAFE_PARCEL(parcel->writeBool, mMayContainBuffer);
+ SAFE_PARCEL(parcel->writeBool, mLogCallPoints);
+
+ SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mDisplayStates.size()));
+ for (auto const& displayState : mDisplayStates) {
+ displayState.write(*parcel);
+ }
+ SAFE_PARCEL(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);
+ }
+
+ SAFE_PARCEL(parcel->writeBool, mHasListenerCallbacks);
+ SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mListenerCallbacks.size()));
+ for (const auto& [listener, callbackIds] : mListenerCallbacks) {
+ SAFE_PARCEL(parcel->writeStrongBinder, listener);
+ SAFE_PARCEL(parcel->writeParcelableVector, callbackIds);
+ }
+
+ return NO_ERROR;
+}
+
+status_t TransactionState::readFromParcel(const Parcel* parcel) {
+ SAFE_PARCEL(parcel->readUint64, &mId);
+ SAFE_PARCEL(parcel->readUint32, &mFlags);
+ SAFE_PARCEL(parcel->readInt64, &mDesiredPresentTime);
+ SAFE_PARCEL(parcel->readBool, &mIsAutoTimestamp);
+ SAFE_PARCEL(parcel->readParcelable, &mFrameTimelineInfo);
+ SAFE_PARCEL(parcel->readNullableStrongBinder, &mApplyToken);
+ SAFE_PARCEL(parcel->readBool, &mMayContainBuffer);
+ SAFE_PARCEL(parcel->readBool, &mLogCallPoints);
+
+ uint32_t count;
+ SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize())
+ mDisplayStates.clear();
+ mDisplayStates.reserve(count);
+ for (size_t i = 0; i < count; i++) {
+ DisplayState displayState;
+ if (displayState.read(*parcel) == BAD_VALUE) {
+ return BAD_VALUE;
+ }
+ mDisplayStates.emplace_back(std::move(displayState));
+ }
+
+ SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize())
+ mComposerStates.clear();
+ mComposerStates.reserve(count);
+ for (size_t i = 0; i < count; i++) {
+ ComposerState composerState;
+ if (composerState.read(*parcel) == BAD_VALUE) {
+ return BAD_VALUE;
+ }
+ mComposerStates.emplace_back(std::move(composerState));
+ }
+
+ if (status_t status = mInputWindowCommands.read(*parcel) != NO_ERROR) {
+ return status;
+ }
+
+ SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize())
+ mUncacheBuffers.clear();
+ mUncacheBuffers.reserve(count);
+ for (size_t i = 0; i < count; i++) {
+ client_cache_t client_cache;
+ sp<IBinder> tmpBinder;
+ SAFE_PARCEL(parcel->readStrongBinder, &tmpBinder);
+ client_cache.token = tmpBinder;
+ SAFE_PARCEL(parcel->readUint64, &client_cache.id);
+ mUncacheBuffers.emplace_back(std::move(client_cache));
+ }
+
+ SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize())
+ mMergedTransactionIds.clear();
+ mMergedTransactionIds.resize(count);
+ for (size_t i = 0; i < count; i++) {
+ SAFE_PARCEL(parcel->readUint64, &mMergedTransactionIds[i]);
+ }
+
+ SAFE_PARCEL(parcel->readBool, &mHasListenerCallbacks);
+ SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize());
+ mListenerCallbacks.clear();
+ mListenerCallbacks.reserve(count);
+ for (uint32_t i = 0; i < count; i++) {
+ sp<IBinder> tmpBinder;
+ SAFE_PARCEL(parcel->readStrongBinder, &tmpBinder);
+ std::vector<CallbackId> callbackIds;
+ SAFE_PARCEL(parcel->readParcelableVector, &callbackIds);
+ mListenerCallbacks.emplace_back(tmpBinder, callbackIds);
+ }
+
+ return NO_ERROR;
+}
+
+void TransactionState::merge(TransactionState&& other,
+ const std::function<void(layer_state_t&)>& onBufferOverwrite) {
+ 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) {
+ onBufferOverwrite(it->state);
+ }
+ it->state.merge(otherState.state);
+ } else {
+ mComposerStates.push_back(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.push_back(state);
+ }
+ }
+
+ for (const auto& cacheId : other.mUncacheBuffers) {
+ mUncacheBuffers.push_back(cacheId);
+ }
+
+ mInputWindowCommands.merge(other.mInputWindowCommands);
+ // TODO(b/385156191) Consider merging desired present time.
+ mFlags |= other.mFlags;
+ mMayContainBuffer |= other.mMayContainBuffer;
+ mLogCallPoints |= other.mLogCallPoints;
+
+ // mApplyToken is explicitly not merged. Token should be set before applying the transactions to
+ // make synchronization decisions a bit simpler.
+ mergeFrameTimelineInfo(other.mFrameTimelineInfo);
+ other.clear();
+}
+
+// copied from FrameTimelineInfo::merge()
+void TransactionState::mergeFrameTimelineInfo(const FrameTimelineInfo& other) {
+ // When merging vsync Ids we take the oldest valid one
+ if (mFrameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID &&
+ other.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
+ if (other.vsyncId > mFrameTimelineInfo.vsyncId) {
+ mFrameTimelineInfo = other;
+ }
+ } else if (mFrameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) {
+ mFrameTimelineInfo = other;
+ }
+}
+
+void TransactionState::clear() {
+ mComposerStates.clear();
+ mDisplayStates.clear();
+ mListenerCallbacks.clear();
+ mHasListenerCallbacks = false;
+ mInputWindowCommands.clear();
+ mUncacheBuffers.clear();
+ mDesiredPresentTime = 0;
+ mIsAutoTimestamp = true;
+ mApplyToken = nullptr;
+ mFrameTimelineInfo = {};
+ mMergedTransactionIds.clear();
+ mFlags = 0;
+ mMayContainBuffer = false;
+ mLogCallPoints = false;
+}
+
+layer_state_t* TransactionState::getLayerState(const sp<SurfaceControl>& 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.push_back(s);
+
+ return &mComposerStates.back().state;
+}
+
+DisplayState& TransactionState::getDisplayState(const sp<IBinder>& 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.push_back(s);
+ return mDisplayStates.back();
+}
+
+}; // namespace android
diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp
index 91c9a85..d633f9f 100644
--- a/libs/gui/WindowInfosListenerReporter.cpp
+++ b/libs/gui/WindowInfosListenerReporter.cpp
@@ -15,6 +15,7 @@
*/
#include <android/gui/ISurfaceComposer.h>
+#include <android/gui/IWindowInfosListener.h>
#include <gui/AidlUtil.h>
#include <gui/WindowInfosListenerReporter.h>
#include "gui/WindowInfosUpdate.h"
@@ -27,7 +28,7 @@
using gui::aidl_utils::statusTFromBinderStatus;
sp<WindowInfosListenerReporter> WindowInfosListenerReporter::getInstance() {
- static sp<WindowInfosListenerReporter> sInstance = new WindowInfosListenerReporter;
+ static sp<WindowInfosListenerReporter> sInstance = sp<WindowInfosListenerReporter>::make();
return sInstance;
}
@@ -116,7 +117,8 @@
std::scoped_lock lock(mListenersMutex);
if (!mWindowInfosListeners.empty()) {
gui::WindowInfosListenerInfo listenerInfo;
- composerService->addWindowInfosListener(this, &listenerInfo);
+ composerService->addWindowInfosListener(sp<gui::IWindowInfosListener>::fromExisting(this),
+ &listenerInfo);
mWindowInfosPublisher = std::move(listenerInfo.windowInfosPublisher);
mListenerId = listenerInfo.listenerId;
}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index da47ee2..9b2f089 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -67,6 +67,11 @@
frameRateOverride = 1 << 1,
}
+ enum OptimizationPolicy {
+ optimizeForPower = 0,
+ optimizeForPerformance = 1,
+ }
+
/**
* Signal that we're done booting.
* Requires ACCESS_SURFACE_FLINGER permission
@@ -97,6 +102,10 @@
* The name of the virtual display.
* isSecure
* Whether this virtual display is secure.
+ * optimizationPolicy
+ * Whether to optimize for power or performance. Displays that are optimizing for power may
+ * be dependent on a different display that optimizes for performance when they are on,
+ * which will guarantee performance for all of the other displays.
* uniqueId
* The unique ID for the display.
* requestedRefreshRate
@@ -108,7 +117,7 @@
* requires ACCESS_SURFACE_FLINGER permission.
*/
@nullable IBinder createVirtualDisplay(@utf8InCpp String displayName, boolean isSecure,
- @utf8InCpp String uniqueId, float requestedRefreshRate);
+ OptimizationPolicy optimizationPolicy, @utf8InCpp String uniqueId, float requestedRefreshRate);
/**
* Destroy a virtual display.
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
index fd8ffe1..b1a23b3 100644
--- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -971,7 +971,7 @@
// H2BGraphicBufferProducer
status_t H2BGraphicBufferProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
- *buf = new GraphicBuffer();
+ *buf = sp<GraphicBuffer>::make();
status_t fnStatus;
status_t transStatus = toStatusT(mBase->requestBuffer(
static_cast<int32_t>(slot),
@@ -999,7 +999,7 @@
uint32_t h, ::android::PixelFormat format,
uint64_t usage, uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
- *fence = new Fence();
+ *fence = sp<Fence>::make();
status_t fnStatus;
status_t transStatus = toStatusT(mBase->dequeueBuffer(
w, h, static_cast<PixelFormat>(format), uint32_t(usage),
@@ -1035,8 +1035,8 @@
status_t H2BGraphicBufferProducer::detachNextBuffer(
sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
- *outBuffer = new GraphicBuffer();
- *outFence = new Fence();
+ *outBuffer = sp<GraphicBuffer>::make();
+ *outFence = sp<Fence>::make();
status_t fnStatus;
status_t transStatus = toStatusT(mBase->detachNextBuffer(
[&fnStatus, outBuffer, outFence] (
@@ -1127,8 +1127,8 @@
status_t H2BGraphicBufferProducer::connect(
const sp<IProducerListener>& listener, int api,
bool producerControlledByApp, QueueBufferOutput* output) {
- sp<HProducerListener> tListener = listener == nullptr ?
- nullptr : new B2HProducerListener(listener);
+ sp<HProducerListener> tListener =
+ listener == nullptr ? nullptr : sp<B2HProducerListener>::make(listener);
status_t fnStatus;
status_t transStatus = toStatusT(mBase->connect(
tListener, static_cast<int32_t>(api), producerControlledByApp,
@@ -1205,13 +1205,13 @@
hidl_handle const& fence,
hidl_array<float, 16> const& transformMatrix) {
fnStatus = toStatusT(status);
- *outBuffer = new GraphicBuffer();
+ *outBuffer = sp<GraphicBuffer>::make();
if (!convertTo(outBuffer->get(), buffer)) {
ALOGE("H2BGraphicBufferProducer::getLastQueuedBuffer - "
"Invalid output buffer");
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
- *outFence = new Fence();
+ *outFence = sp<Fence>::make();
if (!convertTo(outFence->get(), fence)) {
ALOGE("H2BGraphicBufferProducer::getLastQueuedBuffer - "
"Invalid output fence");
diff --git a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
index c76d771..4384bd5 100644
--- a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
@@ -272,7 +272,7 @@
HConnectionType hConnectionType,
bool producerControlledByApp,
connect_cb _hidl_cb) {
- sp<BProducerListener> bListener = new H2BProducerListener(hListener);
+ sp<BProducerListener> bListener = sp<H2BProducerListener>::make(hListener);
int bConnectionType{};
if (!bListener || !h2b(hConnectionType, &bConnectionType)) {
_hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{});
diff --git a/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
index ae00a26..7121bb7 100644
--- a/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
@@ -325,7 +325,7 @@
}
sp<HProducerListener> hListener = nullptr;
if (listener && listener->needsReleaseNotify()) {
- hListener = new B2HProducerListener(listener);
+ hListener = sp<B2HProducerListener>::make(listener);
if (!hListener) {
LOG(ERROR) << "connect: failed to wrap listener.";
return UNKNOWN_ERROR;
diff --git a/libs/gui/bufferqueue/2.0/types.cpp b/libs/gui/bufferqueue/2.0/types.cpp
index cbd6cad..c245766 100644
--- a/libs/gui/bufferqueue/2.0/types.cpp
+++ b/libs/gui/bufferqueue/2.0/types.cpp
@@ -147,13 +147,13 @@
bool h2b(native_handle_t const* from, sp<BFence>* to) {
if (!from || from->numFds == 0) {
- *to = new ::android::Fence();
+ *to = sp<::android::Fence>::make();
return true;
}
if (from->numFds != 1 || from->numInts != 0) {
return false;
}
- *to = new BFence(dup(from->data[0]));
+ *to = sp<BFence>::make(dup(from->data[0]));
return true;
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index cdc2150..db1b9fb 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -46,21 +46,6 @@
class BLASTBufferItemConsumer : public BufferItemConsumer {
public:
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- BLASTBufferItemConsumer(const sp<IGraphicBufferProducer>& producer,
- const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
- int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq)
- : BufferItemConsumer(producer, consumer, consumerUsage, bufferCount, controlledByApp),
-#else
- BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
- int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq)
- : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- mBLASTBufferQueue(std::move(bbq)),
- mCurrentlyConnected(false),
- mPreviouslyConnected(false) {
- }
-
void onDisconnect() override EXCLUDES(mMutex);
void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) override EXCLUDES(mMutex);
@@ -81,6 +66,23 @@
#endif
private:
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ BLASTBufferItemConsumer(const sp<IGraphicBufferProducer>& producer,
+ const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
+ int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq)
+ : BufferItemConsumer(producer, consumer, consumerUsage, bufferCount, controlledByApp),
+#else
+ BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
+ int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq)
+ : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ mBLASTBufferQueue(std::move(bbq)),
+ mCurrentlyConnected(false),
+ mPreviouslyConnected(false) {
+ }
+
+ friend class sp<BLASTBufferItemConsumer>;
+
const wp<BLASTBufferQueue> mBLASTBufferQueue;
uint64_t mCurrentFrameNumber GUARDED_BY(mMutex) = 0;
@@ -94,8 +96,6 @@
class BLASTBufferQueue : public ConsumerBase::FrameAvailableListener {
public:
- BLASTBufferQueue(const std::string& name, bool updateDestinationFrame = true);
-
sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
return mProducer;
}
@@ -158,8 +158,13 @@
void onFirstRef() override;
private:
+ // Not public to ensure construction via sp<>::make().
+ BLASTBufferQueue(const std::string& name, bool updateDestinationFrame = true);
+
+ friend class sp<BLASTBufferQueue>;
friend class BLASTBufferQueueHelper;
friend class BBQBufferQueueProducer;
+ friend class TestBLASTBufferQueue;
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
friend class BBQBufferQueueCore;
#endif
diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h
index 6810eda..fc31f46 100644
--- a/libs/gui/include/gui/BufferItemConsumer.h
+++ b/libs/gui/include/gui/BufferItemConsumer.h
@@ -47,6 +47,16 @@
enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT };
enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE };
+ static std::tuple<sp<BufferItemConsumer>, sp<Surface>> create(
+ uint64_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS,
+ bool controlledByApp = false, bool isConsumerSurfaceFlinger = false);
+
+ static sp<BufferItemConsumer> create(const sp<IGraphicBufferConsumer>& consumer,
+ uint64_t consumerUsage,
+ int bufferCount = DEFAULT_MAX_BUFFERS,
+ bool controlledByApp = false)
+ __attribute((deprecated("Prefer ctors that create their own surface and consumer.")));
+
// Create a new buffer item consumer. The consumerUsage parameter determines
// the consumer usage flags passed to the graphics allocator. The
// bufferCount parameter specifies how many buffers can be locked for user
@@ -86,6 +96,14 @@
status_t acquireBuffer(BufferItem* item, nsecs_t presentWhen,
bool waitForFence = true);
+ // Transfer ownership of a buffer to the BufferQueue. On NO_ERROR, the buffer
+ // is considered as if it were acquired. Buffer must not be null.
+ //
+ // Returns
+ // - BAD_VALUE if buffer is null
+ // - INVALID_OPERATION if too many buffers have already been acquired
+ status_t attachBuffer(const sp<GraphicBuffer>& buffer);
+
// Returns an acquired buffer to the queue, allowing it to be reused. Since
// only a fixed number of buffers may be acquired at a time, old buffers
// must be released by calling releaseBuffer to ensure new buffers can be
@@ -95,10 +113,8 @@
status_t releaseBuffer(const BufferItem &item,
const sp<Fence>& releaseFence = Fence::NO_FENCE);
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
status_t releaseBuffer(const sp<GraphicBuffer>& buffer,
const sp<Fence>& releaseFence = Fence::NO_FENCE);
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
protected:
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
index ab1231a..ba6a6a7 100644
--- a/libs/gui/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -122,7 +122,10 @@
// setMaxAcquiredBufferCount sets the maximum number of buffers that can
// be acquired by the consumer at one time (default 1). This call will
// fail if a producer is connected to the BufferQueue.
- virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
+ virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) override;
+ virtual status_t setMaxAcquiredBufferCount(
+ int maxAcquiredBuffers,
+ std::optional<OnBufferReleasedCallback> onBuffersReleasedCallback) override;
// setConsumerName sets the name used in logging
status_t setConsumerName(const String8& name) override;
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index 2e347c9..d2215ef 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -123,9 +123,7 @@
// See IGraphicBufferConsumer::setMaxAcquiredBufferCount
status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
status_t setConsumerIsProtected(bool isProtected);
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
// See IGraphicBufferConsumer::getSidebandStream
sp<NativeHandle> getSidebandStream() const;
@@ -141,7 +139,8 @@
ConsumerBase(const ConsumerBase&);
void operator=(const ConsumerBase&);
- void initialize(bool controlledByApp);
+ // Requires `this` to be sp/wp so must not be called from ctor.
+ void initialize();
protected:
// ConsumerBase constructs a new ConsumerBase object to consume image
@@ -192,6 +191,8 @@
#endif
virtual int getSlotForBufferLocked(const sp<GraphicBuffer>& buffer);
+ virtual void onBuffersReleasedLocked();
+
virtual status_t detachBufferLocked(int slotIndex);
// freeBufferLocked frees up the given buffer slot. If the slot has been
@@ -254,6 +255,10 @@
const sp<GraphicBuffer> graphicBuffer,
EGLDisplay display = EGL_NO_DISPLAY, EGLSyncKHR eglFence = EGL_NO_SYNC_KHR);
#endif
+ // Required to complete initialization, so `final` lest overrides forget to
+ // delegate.
+ void onFirstRef() override final;
+
// returns true iff the slot still has the graphicBuffer in it.
bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer);
@@ -329,6 +334,8 @@
// releaseBufferLocked.
sp<Fence> mPrevFinalReleaseFence;
+ const bool mIsControlledByApp;
+
// mMutex is the mutex used to prevent concurrent access to the member
// variables of ConsumerBase objects. It must be locked whenever the
// member variables are accessed or when any of the *Locked methods are
diff --git a/libs/gui/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h
index 2bba61b..995cdfb 100644
--- a/libs/gui/include/gui/CpuConsumer.h
+++ b/libs/gui/include/gui/CpuConsumer.h
@@ -31,6 +31,7 @@
class BufferQueue;
class GraphicBuffer;
class String8;
+class Surface;
/**
* CpuConsumer is a BufferQueue consumer endpoint that allows direct CPU
@@ -92,6 +93,13 @@
// Create a new CPU consumer. The maxLockedBuffers parameter specifies
// how many buffers can be locked for user access at the same time.
+ static std::tuple<sp<CpuConsumer>, sp<Surface>> create(size_t maxLockedBuffers,
+ bool controlledByApp = false,
+ bool isConsumerSurfaceFlinger = false);
+ static sp<CpuConsumer> create(const sp<IGraphicBufferConsumer>& bq, size_t maxLockedBuffers,
+ bool controlledByApp = false)
+ __attribute((deprecated("Prefer ctors that create their own surface and consumer.")));
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
CpuConsumer(size_t maxLockedBuffers, bool controlledByApp = false,
bool isConsumerSurfaceFlinger = false);
@@ -100,8 +108,8 @@
bool controlledByApp = false)
__attribute((deprecated("Prefer ctors that create their own surface and consumer.")));
#else
- CpuConsumer(const sp<IGraphicBufferConsumer>& bq,
- size_t maxLockedBuffers, bool controlledByApp = false);
+ CpuConsumer(const sp<IGraphicBufferConsumer>& bq, size_t maxLockedBuffers,
+ bool controlledByApp = false);
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
// Gets the next graphics buffer from the producer and locks it for CPU use,
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index dbf707f..254d8ac 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -83,6 +83,20 @@
// If the constructor without the tex parameter is used, the GLConsumer is
// created in a detached state, and attachToContext must be called before
// calls to updateTexImage.
+ static std::tuple<sp<GLConsumer>, sp<Surface>> create(uint32_t tex, uint32_t textureTarget,
+ bool useFenceSync,
+ bool isControlledByApp);
+ static std::tuple<sp<GLConsumer>, sp<Surface>> create(uint32_t textureTarget, bool useFenceSync,
+ bool isControlledByApp);
+ static sp<GLConsumer> create(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
+ uint32_t textureTarget, bool useFenceSync, bool isControlledByApp)
+ __attribute((deprecated(
+ "Prefer create functions that create their own surface and consumer.")));
+ static sp<GLConsumer> create(const sp<IGraphicBufferConsumer>& bq, uint32_t textureTarget,
+ bool useFenceSync, bool isControlledByApp)
+ __attribute((deprecated(
+ "Prefer create functions that create their own surface and consumer.")));
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
GLConsumer(uint32_t tex, uint32_t textureTarget, bool useFenceSync, bool isControlledByApp);
diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h
index 8272a59..8066b07 100644
--- a/libs/gui/include/gui/IGraphicBufferConsumer.h
+++ b/libs/gui/include/gui/IGraphicBufferConsumer.h
@@ -243,6 +243,9 @@
// maxAcquiredBuffers must be (inclusive) between 1 and MAX_MAX_ACQUIRED_BUFFERS. It also cannot
// cause the maxBufferCount value to be exceeded.
//
+ // If called with onBuffersReleasedCallback, that call back will be called in lieu of
+ // IConsumerListener::onBuffersReleased.
+ //
// Return of a value other than NO_ERROR means an error has occurred:
// * NO_INIT - the BufferQueue has been abandoned
// * BAD_VALUE - one of the below conditions occurred:
@@ -253,6 +256,11 @@
// * INVALID_OPERATION - attempting to call this after a producer connected.
virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0;
+ using OnBufferReleasedCallback = std::function<void(void)>;
+ virtual status_t setMaxAcquiredBufferCount(
+ int maxAcquiredBuffers,
+ std::optional<OnBufferReleasedCallback> onBuffersReleasedCallback) = 0;
+
// setConsumerName sets the name used in logging
virtual status_t setConsumerName(const String8& name) = 0;
diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h
index 7ee291d..6381db2 100644
--- a/libs/gui/include/gui/LayerMetadata.h
+++ b/libs/gui/include/gui/LayerMetadata.h
@@ -44,6 +44,10 @@
LayerMetadata& operator=(const LayerMetadata& other);
LayerMetadata& operator=(LayerMetadata&& other);
+ // Note: `default` is not feasible because Parcelable does not provide ==.
+ bool operator==(const LayerMetadata& rhs) const { return mMap == rhs.mMap; }
+ bool operator!=(const LayerMetadata&) const = default;
+
// Merges other into this LayerMetadata. If eraseEmpty is true, any entries in
// in this whose keys are paired with empty values in other will be erased.
bool merge(const LayerMetadata& other, bool eraseEmpty = false);
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index c2680a4..369d3d1 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -17,9 +17,9 @@
#ifndef ANDROID_SF_LAYER_STATE_H
#define ANDROID_SF_LAYER_STATE_H
-
#include <stdint.h>
#include <sys/types.h>
+#include <span>
#include <android/gui/DisplayCaptureArgs.h>
#include <android/gui/IWindowInfosReportedListener.h>
@@ -69,21 +69,39 @@
uint64_t id;
bool operator==(const client_cache_t& other) const { return id == other.id; }
+ bool operator!=(const client_cache_t&) const = default;
bool isValid() const { return token != nullptr; }
};
class TrustedPresentationListener : public Parcelable {
public:
- sp<ITransactionCompletedListener> callbackInterface;
- int callbackId = -1;
+ struct State {
+ sp<ITransactionCompletedListener> callbackInterface;
+ int callbackId = -1;
+ bool operator==(const State&) const = default;
+ bool operator!=(const State&) const = default;
+ };
void invoke(bool presentedWithinThresholds) {
- callbackInterface->onTrustedPresentationChanged(callbackId, presentedWithinThresholds);
+ mState.callbackInterface->onTrustedPresentationChanged(mState.callbackId,
+ presentedWithinThresholds);
+ }
+ void configure(State&& state) { mState = std::move(state); }
+ const sp<ITransactionCompletedListener>& getCallback() { return mState.callbackInterface; }
+ void clear() {
+ mState.callbackInterface = nullptr;
+ mState.callbackId = -1;
}
status_t writeToParcel(Parcel* parcel) const;
status_t readFromParcel(const Parcel* parcel);
+
+ bool operator==(const TrustedPresentationListener& rhs) const { return mState == rhs.mState; }
+ bool operator!=(const TrustedPresentationListener&) const = default;
+
+private:
+ State mState;
};
class BufferData : public Parcelable {
@@ -309,6 +327,32 @@
bool hasValidBuffer() const;
void sanitize(int32_t permissions);
+ void updateTransparentRegion(const Region& transparentRegion);
+ const Region& getTransparentRegion() const { return mNotDefCmpState.transparentRegion; }
+ void updateSurfaceDamageRegion(const Region& surfaceDamageRegion);
+ const Region& getSurfaceDamageRegion() const { return mNotDefCmpState.surfaceDamageRegion; }
+ // Do not update state flags. Used to set up test state.
+ void setSurfaceDamageRegion(Region&& surfaceDamageRegion) {
+ mNotDefCmpState.surfaceDamageRegion = std::move(surfaceDamageRegion);
+ }
+ void updateRelativeLayer(const sp<SurfaceControl>& relativeTo, int32_t z);
+ void updateParentLayer(const sp<SurfaceControl>& newParent);
+ void updateInputWindowInfo(sp<gui::WindowInfoHandle>&& info);
+ const gui::WindowInfo& getWindowInfo() const {
+ return *mNotDefCmpState.windowInfoHandle->getInfo();
+ }
+ gui::WindowInfo* editWindowInfo() { return mNotDefCmpState.windowInfoHandle->editInfo(); }
+
+ const sp<SurfaceControl>& getParentSurfaceControlForChild() const {
+ return mNotDefCmpState.parentSurfaceControlForChild;
+ }
+ const sp<SurfaceControl>& getRelativeLayerSurfaceControl() const {
+ return mNotDefCmpState.relativeLayerSurfaceControl;
+ }
+
+ bool operator==(const layer_state_t&) const = default;
+ bool operator!=(const layer_state_t&) const = default;
+
struct matrix22_t {
float dsdx{0};
float dtdx{0};
@@ -337,28 +381,20 @@
float clientDrawnCornerRadius;
uint32_t backgroundBlurRadius;
- sp<SurfaceControl> relativeLayerSurfaceControl;
-
- sp<SurfaceControl> parentSurfaceControlForChild;
-
half4 color;
// non POD must be last. see write/read
- Region transparentRegion;
uint32_t bufferTransform;
bool transformToDisplayInverse;
FloatRect crop;
std::shared_ptr<BufferData> bufferData = nullptr;
ui::Dataspace dataspace;
HdrMetadata hdrMetadata;
- Region surfaceDamageRegion;
int32_t api;
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
std::vector<BlurRegion> blurRegions;
- sp<gui::WindowInfoHandle> windowInfoHandle = sp<gui::WindowInfoHandle>::make();
-
LayerMetadata metadata;
// The following refer to the alpha, and dataspace, respectively of
@@ -444,6 +480,18 @@
std::shared_ptr<gui::BufferReleaseChannel::ProducerEndpoint> bufferReleaseChannel;
std::shared_ptr<gui::DisplayLuts> luts;
+
+protected:
+ struct NotDefaultComparableState {
+ Region transparentRegion;
+ Region surfaceDamageRegion;
+ sp<gui::WindowInfoHandle> windowInfoHandle = sp<gui::WindowInfoHandle>::make();
+ sp<SurfaceControl> relativeLayerSurfaceControl;
+ sp<SurfaceControl> parentSurfaceControlForChild;
+
+ bool operator==(const NotDefaultComparableState& rhs) const;
+ bool operator!=(const NotDefaultComparableState& rhs) const = default;
+ } mNotDefCmpState;
};
class ComposerState {
@@ -451,6 +499,9 @@
layer_state_t state;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
+
+ bool operator==(const ComposerState&) const = default;
+ bool operator!=(const ComposerState&) const = default;
};
struct DisplayState {
@@ -516,20 +567,35 @@
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
+
+ bool operator==(const DisplayState&) const = default;
+ bool operator!=(const DisplayState&) const = default;
};
struct InputWindowCommands {
- std::vector<gui::FocusRequest> focusRequests;
- std::unordered_set<sp<gui::IWindowInfosReportedListener>,
- SpHash<gui::IWindowInfosReportedListener>>
- windowInfosReportedListeners;
-
+ using Listener = gui::IWindowInfosReportedListener;
+ using ListenerSet = std::unordered_set<sp<Listener>, SpHash<Listener>>;
// Merges the passed in commands and returns true if there were any changes.
bool merge(const InputWindowCommands& other);
bool empty() const;
void clear();
+ void addFocusRequest(const gui::FocusRequest& request) { focusRequests.push_back(request); }
+ void addWindowInfosReportedListener(const sp<Listener>& listener) {
+ windowInfosReportedListeners.insert(listener);
+ }
+ ListenerSet&& releaseListeners() { return std::move(windowInfosReportedListeners); }
+
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
+
+ std::span<const gui::FocusRequest> getFocusRequests() const { return focusRequests; }
+ const ListenerSet& getListeners() const { return windowInfosReportedListeners; }
+ bool operator==(const InputWindowCommands&) const = default;
+ bool operator!=(const InputWindowCommands&) const = default;
+
+private:
+ std::vector<gui::FocusRequest> focusRequests;
+ ListenerSet windowInfosReportedListeners;
};
static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
diff --git a/libs/gui/include/gui/StreamSplitter.h b/libs/gui/include/gui/StreamSplitter.h
index 28237b6..8176f75 100644
--- a/libs/gui/include/gui/StreamSplitter.h
+++ b/libs/gui/include/gui/StreamSplitter.h
@@ -153,6 +153,8 @@
size_t mReleaseCount;
};
+ friend class sp<StreamSplitter>;
+
// Only called from createSplitter
explicit StreamSplitter(const sp<IGraphicBufferConsumer>& inputQueue);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 60f16ae..4fda8de 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -345,8 +345,6 @@
static std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>
getDisplayDecorationSupport(const sp<IBinder>& displayToken);
- static bool flagEdgeExtensionEffectUseShader();
-
/**
* Returns how many picture profiles are supported by the display.
*
@@ -396,6 +394,7 @@
static const std::string kEmpty;
static sp<IBinder> createVirtualDisplay(const std::string& displayName, bool isSecure,
+ bool optimizeForPower = true,
const std::string& uniqueId = kEmpty,
float requestedRefreshRate = 0);
diff --git a/libs/gui/include/gui/TransactionState.h b/libs/gui/include/gui/TransactionState.h
new file mode 100644
index 0000000..4358227
--- /dev/null
+++ b/libs/gui/include/gui/TransactionState.h
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <android/gui/FrameTimelineInfo.h>
+#include <binder/Parcelable.h>
+#include <gui/LayerState.h>
+
+namespace android {
+
+// Class to store all the transaction data and the parcelling logic
+class TransactionState {
+public:
+ explicit TransactionState() = default;
+ TransactionState(TransactionState const& other) = default;
+ status_t writeToParcel(Parcel* parcel) const;
+ status_t readFromParcel(const Parcel* parcel);
+ layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
+ DisplayState& getDisplayState(const sp<IBinder>& token);
+
+ // Returns the current id of the transaction.
+ // The id is updated every time the transaction is applied.
+ uint64_t getId() const { return mId; }
+ std::vector<uint64_t> getMergedTransactionIds() const { return mMergedTransactionIds; }
+ void enableDebugLogCallPoints() { mLogCallPoints = true; }
+ void merge(TransactionState&& other,
+ const std::function<void(layer_state_t&)>& onBufferOverwrite);
+
+ // copied from FrameTimelineInfo::merge()
+ void mergeFrameTimelineInfo(const FrameTimelineInfo& other);
+ void clear();
+ bool operator==(const TransactionState& rhs) const = default;
+ bool operator!=(const TransactionState& rhs) const = default;
+
+ uint64_t mId = 0;
+ std::vector<uint64_t> mMergedTransactionIds;
+ uint32_t mFlags = 0;
+ // The vsync id provided by Choreographer.getVsyncId and the input event id
+ gui::FrameTimelineInfo mFrameTimelineInfo;
+ // 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;
+ // If not null, transactions will be queued up using this token otherwise a common token
+ // per process will be used.
+ sp<IBinder> mApplyToken;
+ // 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;
+ // Prints debug logs when enabled.
+ bool mLogCallPoints = false;
+
+ std::vector<DisplayState> mDisplayStates;
+ std::vector<ComposerState> mComposerStates;
+ InputWindowCommands mInputWindowCommands;
+ std::vector<client_cache_t> mUncacheBuffers;
+ // Note: mHasListenerCallbacks can be true even if mListenerCallbacks is
+ // empty.
+ bool mHasListenerCallbacks = false;
+ std::vector<ListenerCallbacks> mListenerCallbacks;
+
+private:
+ // We keep track of the last MAX_MERGE_HISTORY_LENGTH merged transaction ids.
+ // Ordered most recently merged to least recently merged.
+ static constexpr size_t MAX_MERGE_HISTORY_LENGTH = 10u;
+};
+
+}; // namespace android
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 420dc21..9ac49c0 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -268,6 +268,7 @@
bool overlaps(const WindowInfo* other) const;
bool operator==(const WindowInfo& inputChannel) const;
+ bool operator!=(const WindowInfo&) const = default;
status_t writeToParcel(android::Parcel* parcel) const override;
@@ -319,6 +320,9 @@
status_t readFromParcel(const android::Parcel* parcel);
status_t writeToParcel(android::Parcel* parcel) const;
+ bool operator==(const WindowInfoHandle& rhs) const { return mInfo == rhs.mInfo; }
+ bool operator!=(const WindowInfoHandle&) const = default;
+
protected:
virtual ~WindowInfoHandle();
diff --git a/libs/gui/include/gui/mock/GraphicBufferConsumer.h b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
index 24d26b1..18a7e12 100644
--- a/libs/gui/include/gui/mock/GraphicBufferConsumer.h
+++ b/libs/gui/include/gui/mock/GraphicBufferConsumer.h
@@ -47,6 +47,7 @@
MOCK_METHOD2(setDefaultBufferSize, status_t(uint32_t, uint32_t));
MOCK_METHOD1(setMaxBufferCount, status_t(int));
MOCK_METHOD1(setMaxAcquiredBufferCount, status_t(int));
+ MOCK_METHOD2(setMaxAcquiredBufferCount, status_t(int, std::optional<OnBufferReleasedCallback>));
MOCK_METHOD1(setConsumerName, status_t(const String8&));
MOCK_METHOD1(setDefaultBufferFormat, status_t(PixelFormat));
MOCK_METHOD1(setDefaultBufferDataSpace, status_t(android_dataspace));
diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig
index 90d91ac..2c3222d 100644
--- a/libs/gui/libgui_flags.aconfig
+++ b/libs/gui/libgui_flags.aconfig
@@ -77,14 +77,6 @@
} # wb_stream_splitter
flag {
- name: "edge_extension_shader"
- namespace: "windowing_frontend"
- description: "Enable edge extension via shader"
- bug: "322036393"
- is_fixed_read_only: true
-} # edge_extension_shader
-
-flag {
name: "buffer_release_channel"
namespace: "window_surfaces"
description: "Enable BufferReleaseChannel to optimize buffer releases"
@@ -150,3 +142,14 @@
bug: "340934031"
is_fixed_read_only: true
} # wb_media_migration
+
+flag {
+ name: "allocate_buffer_priority"
+ namespace: "wear_system_health"
+ description: "Boost priority for buffer allocation"
+ bug: "399701430"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+ is_fixed_read_only: true
+} # allocate_buffer_priority
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 87051a7..e20345d 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -90,6 +90,7 @@
"testserver/TestServerClient.cpp",
"testserver/TestServerHost.cpp",
"TextureRenderer.cpp",
+ "TransactionState_test.cpp",
"VsyncEventData_test.cpp",
"WindowInfo_test.cpp",
],
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index e6ee89f..b861c6d 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -114,8 +114,8 @@
class BLASTBufferQueueHelper {
public:
BLASTBufferQueueHelper(const sp<SurfaceControl>& sc, int width, int height) {
- mBlastBufferQueueAdapter = new TestBLASTBufferQueue("TestBLASTBufferQueue", sc, width,
- height, PIXEL_FORMAT_RGBA_8888);
+ mBlastBufferQueueAdapter = sp<TestBLASTBufferQueue>::make("TestBLASTBufferQueue", sc, width,
+ height, PIXEL_FORMAT_RGBA_8888);
}
void update(const sp<SurfaceControl>& sc, int width, int height) {
diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp
index 6453885..80eea26 100644
--- a/libs/gui/tests/BufferItemConsumer_test.cpp
+++ b/libs/gui/tests/BufferItemConsumer_test.cpp
@@ -24,6 +24,7 @@
#include <gui/Surface.h>
#include <ui/BufferQueueDefs.h>
#include <ui/GraphicBuffer.h>
+#include <utils/Errors.h>
#include <unordered_set>
@@ -62,14 +63,15 @@
void SetUp() override {
mBuffers.resize(BufferQueueDefs::NUM_BUFFER_SLOTS);
- mBIC = new BufferItemConsumer(kUsage, kMaxLockedBuffers, true);
+ sp<Surface> surface;
+ std::tie(mBIC, surface) = BufferItemConsumer::create(kUsage, kMaxLockedBuffers, true);
String8 name("BufferItemConsumer_Under_Test");
mBIC->setName(name);
mBFL = new BufferFreedListener(this);
mBIC->setBufferFreedListener(mBFL);
sp<IProducerListener> producerListener = new TrackingProducerListener(this);
- mProducer = mBIC->getSurface()->getIGraphicBufferProducer();
+ mProducer = surface->getIGraphicBufferProducer();
IGraphicBufferProducer::QueueBufferOutput bufferOutput;
ASSERT_EQ(NO_ERROR,
mProducer->connect(producerListener, NATIVE_WINDOW_API_CPU,
@@ -234,6 +236,38 @@
ASSERT_EQ(1, GetFreedBufferCount());
}
+TEST_F(BufferItemConsumerTest, ResizeAcquireCount) {
+ EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers + 1));
+ EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers + 2));
+ EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers - 1));
+ EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers - 2));
+ EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers + 1));
+ EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers - 1));
+}
+
+TEST_F(BufferItemConsumerTest, AttachBuffer) {
+ ASSERT_EQ(OK, mBIC->setMaxAcquiredBufferCount(1));
+
+ int slot;
+ DequeueBuffer(&slot);
+ QueueBuffer(slot);
+ AcquireBuffer(&slot);
+
+ sp<GraphicBuffer> newBuffer1 = sp<GraphicBuffer>::make(kWidth, kHeight, kFormat, kUsage);
+ sp<GraphicBuffer> newBuffer2 = sp<GraphicBuffer>::make(kWidth, kHeight, kFormat, kUsage);
+
+ // For some reason, you can attach an extra buffer?
+ // b/400973991 to investigate
+ EXPECT_EQ(OK, mBIC->attachBuffer(newBuffer1));
+ EXPECT_EQ(INVALID_OPERATION, mBIC->attachBuffer(newBuffer2));
+
+ ReleaseBuffer(slot);
+
+ EXPECT_EQ(OK, mBIC->attachBuffer(newBuffer2));
+ EXPECT_EQ(OK, mBIC->releaseBuffer(newBuffer1, Fence::NO_FENCE));
+ EXPECT_EQ(OK, mBIC->releaseBuffer(newBuffer2, Fence::NO_FENCE));
+}
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
// Test that delete BufferItemConsumer triggers onBufferFreed.
TEST_F(BufferItemConsumerTest, DetachBufferWithBuffer) {
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 9476930..482cfde 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -66,10 +66,9 @@
test_info->name(),
params.width, params.height,
params.maxLockedBuffers, params.format);
- mCC = new CpuConsumer(params.maxLockedBuffers);
+ std::tie(mCC, mSTC) = CpuConsumer::create(params.maxLockedBuffers);
String8 name("CpuConsumer_Under_Test");
mCC->setName(name);
- mSTC = mCC->getSurface();
mANW = mSTC;
}
diff --git a/libs/gui/tests/MultiTextureConsumer_test.cpp b/libs/gui/tests/MultiTextureConsumer_test.cpp
index 2428bb3..7ae6f40 100644
--- a/libs/gui/tests/MultiTextureConsumer_test.cpp
+++ b/libs/gui/tests/MultiTextureConsumer_test.cpp
@@ -34,8 +34,8 @@
virtual void SetUp() {
GLTest::SetUp();
- mGlConsumer = new GLConsumer(TEX_ID, GLConsumer::TEXTURE_EXTERNAL, true, false);
- mSurface = mGlConsumer->getSurface();
+ std::tie(mGlConsumer, mSurface) =
+ GLConsumer::create(TEX_ID, GLConsumer::TEXTURE_EXTERNAL, true, false);
mANW = mSurface.get();
}
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 59d05b6..d3434ea 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -40,8 +40,7 @@
}
virtual void SetUp() {
- mST = new GLConsumer(123, GLConsumer::TEXTURE_EXTERNAL, true, false);
- mSTC = mST->getSurface();
+ std::tie(mST, mSTC) = GLConsumer::create(123, GLConsumer::TEXTURE_EXTERNAL, true, false);
mANW = mSTC;
// We need a valid GL context so we can test updateTexImage()
@@ -727,8 +726,7 @@
ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
- sp<GLConsumer> st(new GLConsumer(i, GLConsumer::TEXTURE_EXTERNAL, true, false));
- sp<Surface> stc = st->getSurface();
+ auto [st, stc] = GLConsumer::create(i, GLConsumer::TEXTURE_EXTERNAL, true, false);
mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
static_cast<ANativeWindow*>(stc.get()), nullptr);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
diff --git a/libs/gui/tests/SurfaceTextureGL.h b/libs/gui/tests/SurfaceTextureGL.h
index 1309635..eb31cd1 100644
--- a/libs/gui/tests/SurfaceTextureGL.h
+++ b/libs/gui/tests/SurfaceTextureGL.h
@@ -38,8 +38,7 @@
void SetUp() {
GLTest::SetUp();
- mST = new GLConsumer(TEX_ID, GLConsumer::TEXTURE_EXTERNAL, true, false);
- mSTC = mST->getSurface();
+ std::tie(mST, mSTC) = GLConsumer::create(TEX_ID, GLConsumer::TEXTURE_EXTERNAL, true, false);
mANW = mSTC;
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), TEST_PRODUCER_USAGE_BITS));
mTextureRenderer = new TextureRenderer(TEX_ID, mST);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 98d1329..e7690e2 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -294,9 +294,7 @@
TEST_F(SurfaceTest, QueryConsumerUsage) {
const int TEST_USAGE_FLAGS =
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
- sp<BufferItemConsumer> c = new BufferItemConsumer(TEST_USAGE_FLAGS);
-
- sp<Surface> s = c->getSurface();
+ auto [c, s] = BufferItemConsumer::create(TEST_USAGE_FLAGS);
sp<ANativeWindow> anw(s);
int flags = -1;
@@ -309,10 +307,8 @@
TEST_F(SurfaceTest, QueryDefaultBuffersDataSpace) {
const android_dataspace TEST_DATASPACE = HAL_DATASPACE_V0_SRGB;
- sp<CpuConsumer> cpuConsumer = new CpuConsumer(1);
+ auto [cpuConsumer, s] = CpuConsumer::create(1);
cpuConsumer->setDefaultBufferDataSpace(TEST_DATASPACE);
-
- sp<Surface> s = cpuConsumer->getSurface();
sp<ANativeWindow> anw(s);
android_dataspace dataSpace;
@@ -325,8 +321,7 @@
}
TEST_F(SurfaceTest, SettingGenerationNumber) {
- sp<CpuConsumer> cpuConsumer = new CpuConsumer(1);
- sp<Surface> surface = cpuConsumer->getSurface();
+ auto [cpuConsumer, surface] = CpuConsumer::create(1);
sp<ANativeWindow> window(surface);
// Allocate a buffer with a generation number of 0
@@ -692,10 +687,11 @@
return binder::Status::ok();
}
- binder::Status createVirtualDisplay(const std::string& /*displayName*/, bool /*isSecure*/,
- const std::string& /*uniqueId*/,
- float /*requestedRefreshRate*/,
- sp<IBinder>* /*outDisplay*/) override {
+ binder::Status createVirtualDisplay(
+ const std::string& /*displayName*/, bool /*isSecure*/,
+ gui::ISurfaceComposer::OptimizationPolicy /*optimizationPolicy*/,
+ const std::string& /*uniqueId*/, float /*requestedRefreshRate*/,
+ sp<IBinder>* /*outDisplay*/) override {
return binder::Status::ok();
}
@@ -2180,8 +2176,7 @@
const int BUFFER_COUNT = 16;
const int BATCH_SIZE = 8;
- sp<CpuConsumer> cpuConsumer = new CpuConsumer(1);
- sp<Surface> surface = cpuConsumer->getSurface();
+ auto [cpuConsumer, surface] = CpuConsumer::create(1);
sp<ANativeWindow> window(surface);
sp<StubSurfaceListener> listener = new StubSurfaceListener();
@@ -2229,8 +2224,7 @@
const int BUFFER_COUNT = 16;
const int BATCH_SIZE = 8;
- sp<CpuConsumer> cpuConsumer = new CpuConsumer(1);
- sp<Surface> surface = cpuConsumer->getSurface();
+ auto [cpuConsumer, surface] = CpuConsumer::create(1);
sp<ANativeWindow> window(surface);
sp<StubSurfaceListener> listener = new StubSurfaceListener();
@@ -2377,8 +2371,7 @@
sp<IGraphicBufferConsumer> bqConsumer;
BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
- sp<BufferItemConsumer> consumer = sp<BufferItemConsumer>::make(bqConsumer, 3);
- sp<Surface> surface = sp<Surface>::make(bqProducer);
+ auto [consumer, surface] = BufferItemConsumer::create(3);
sp<ImmediateReleaseConsumerListener> consumerListener =
sp<ImmediateReleaseConsumerListener>::make(consumer);
consumer->setFrameAvailableListener(consumerListener);
diff --git a/libs/gui/tests/TransactionState_test.cpp b/libs/gui/tests/TransactionState_test.cpp
new file mode 100644
index 0000000..179b264
--- /dev/null
+++ b/libs/gui/tests/TransactionState_test.cpp
@@ -0,0 +1,284 @@
+/*
+ * 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.
+ */
+
+#include <gmock/gmock.h>
+
+#include <gtest/gtest.h>
+#include <unordered_map>
+#include "android/gui/FocusRequest.h"
+#include "binder/Binder.h"
+#include "binder/Parcel.h"
+#include "gtest/gtest.h"
+#include "gui/LayerState.h"
+#include "gui/WindowInfo.h"
+
+#include "gui/TransactionState.h"
+
+namespace android {
+
+void sprintf(std::string& out, const char* format, ...) {
+ va_list arg_list;
+ va_start(arg_list, format);
+
+ int len = vsnprintf(nullptr, 0, format, arg_list);
+ if (len < 0) {
+ va_end(arg_list);
+ }
+ std::string line(len, '\0');
+ int written = vsnprintf(line.data(), len + 1, format, arg_list);
+ if (written != len) {
+ va_end(arg_list);
+ }
+ line.pop_back();
+ out += line;
+ va_end(arg_list);
+}
+
+constexpr std::string dump_struct(auto& x) {
+ std::string s;
+#if __has_builtin(__builtin_dump_struct)
+ __builtin_dump_struct(&x, sprintf, s);
+#else
+ (void)x;
+#endif
+ return s;
+}
+
+void PrintTo(const TransactionState& state, ::std::ostream* os) {
+ *os << dump_struct(state);
+ *os << state.mFrameTimelineInfo.toString();
+ for (auto mergedId : state.mMergedTransactionIds) {
+ *os << mergedId << ",";
+ }
+}
+
+void PrintTo(const ComposerState& state, ::std::ostream* os) {
+ *os << dump_struct(state.state);
+ *os << state.state.getWindowInfo();
+}
+
+// In case EXPECT_EQ fails, this function is useful to pinpoint exactly which
+// field did not compare ==.
+void Compare(const TransactionState& s1, const TransactionState& s2) {
+ EXPECT_EQ(s1.mId, s2.mId);
+ EXPECT_EQ(s1.mMergedTransactionIds, s2.mMergedTransactionIds);
+ EXPECT_EQ(s1.mFlags, s2.mFlags);
+ EXPECT_EQ(s1.mFrameTimelineInfo, s2.mFrameTimelineInfo);
+ EXPECT_EQ(s1.mDesiredPresentTime, s2.mDesiredPresentTime);
+ EXPECT_EQ(s1.mIsAutoTimestamp, s2.mIsAutoTimestamp);
+ EXPECT_EQ(s1.mApplyToken, s2.mApplyToken);
+ EXPECT_EQ(s1.mMayContainBuffer, s2.mMayContainBuffer);
+ EXPECT_EQ(s1.mLogCallPoints, s2.mLogCallPoints);
+ EXPECT_EQ(s1.mDisplayStates.size(), s2.mDisplayStates.size());
+ EXPECT_THAT(s1.mDisplayStates, ::testing::ContainerEq(s2.mDisplayStates));
+ EXPECT_EQ(s1.mComposerStates.size(), s2.mComposerStates.size());
+ EXPECT_EQ(s1.mComposerStates, s2.mComposerStates);
+ EXPECT_EQ(s1.mInputWindowCommands, s2.mInputWindowCommands);
+ EXPECT_EQ(s1.mUncacheBuffers, s2.mUncacheBuffers);
+ EXPECT_EQ(s1.mHasListenerCallbacks, s2.mHasListenerCallbacks);
+ EXPECT_EQ(s1.mListenerCallbacks.size(), s2.mListenerCallbacks.size());
+ EXPECT_EQ(s1.mListenerCallbacks, s2.mListenerCallbacks);
+}
+
+std::unique_ptr<std::unordered_map<int, sp<BBinder>>> createTokenMap(size_t maxSize) {
+ auto result = std::make_unique<std::unordered_map<int, sp<BBinder>>>();
+ for (size_t i = 0; i < maxSize; ++i) {
+ result->emplace(i, sp<BBinder>::make());
+ }
+ return result;
+}
+
+constexpr size_t kMaxComposerStates = 2;
+ComposerState createComposerStateForTest(size_t i) {
+ static const auto* const sLayerHandle = createTokenMap(kMaxComposerStates).release();
+
+ ComposerState state;
+ state.state.what = layer_state_t::eFlagsChanged;
+ state.state.surface = sLayerHandle->at(i);
+ state.state.layerId = i;
+ state.state.flags = 20 * i;
+ return state;
+}
+
+constexpr size_t kMaxDisplayStates = 5;
+DisplayState createDisplayStateForTest(size_t i) {
+ static const auto* const sDisplayTokens = createTokenMap(kMaxDisplayStates).release();
+
+ DisplayState displayState;
+ displayState.what = DisplayState::eFlagsChanged;
+ displayState.token = sDisplayTokens->at(i);
+ displayState.flags = 20 * i;
+ return displayState;
+}
+
+TransactionState createTransactionStateForTest() {
+ static sp<BBinder> sApplyToken = sp<BBinder>::make();
+
+ TransactionState state;
+ state.mId = 123;
+ state.mMergedTransactionIds.push_back(15);
+ state.mMergedTransactionIds.push_back(0);
+ state.mFrameTimelineInfo.vsyncId = 14;
+ state.mDesiredPresentTime = 11;
+ state.mIsAutoTimestamp = true;
+ state.mApplyToken = sApplyToken;
+ for (size_t i = 0; i < kMaxDisplayStates; i++) {
+ state.mDisplayStates.push_back(createDisplayStateForTest(i));
+ }
+ for (size_t i = 0; i < kMaxComposerStates; i++) {
+ state.mComposerStates.push_back(createComposerStateForTest(i));
+ }
+ static const auto* const sFocusRequestTokens = createTokenMap(5).release();
+ for (int i = 0; i < 5; i++) {
+ gui::FocusRequest request;
+ request.token = sFocusRequestTokens->at(i);
+ request.timestamp = i;
+ state.mInputWindowCommands.addFocusRequest(request);
+ }
+ static const auto* const sCacheToken = createTokenMap(5).release();
+ for (int i = 0; i < 5; i++) {
+ client_cache_t cache;
+ cache.token = sCacheToken->at(i);
+ cache.id = i;
+ state.mUncacheBuffers.emplace_back(std::move(cache));
+ }
+ static const auto* const sListenerCallbacks = []() {
+ auto* callbacks = new std::vector<ListenerCallbacks>();
+ for (int i = 0; i < 5; i++) {
+ callbacks->emplace_back(sp<BBinder>::make(),
+ std::unordered_set<CallbackId, CallbackIdHash>{});
+ }
+ return callbacks;
+ }();
+ state.mHasListenerCallbacks = true;
+ state.mListenerCallbacks = *sListenerCallbacks;
+ return state;
+}
+
+TransactionState createEmptyTransaction(uint64_t id) {
+ TransactionState state;
+ state.mId = id;
+ return state;
+}
+
+TEST(TransactionStateTest, parcel) {
+ TransactionState state = createTransactionStateForTest();
+ Parcel p;
+ state.writeToParcel(&p);
+ p.setDataPosition(0);
+ TransactionState parcelledState;
+ parcelledState.readFromParcel(&p);
+ EXPECT_EQ(state, parcelledState);
+};
+
+TEST(TransactionStateTest, parcelDisplayState) {
+ DisplayState state = createDisplayStateForTest(0);
+ Parcel p;
+ state.write(p);
+ p.setDataPosition(0);
+ DisplayState parcelledState;
+ parcelledState.read(p);
+ EXPECT_EQ(state, parcelledState);
+};
+
+TEST(TransactionStateTest, parcelLayerState) {
+ ComposerState state = createComposerStateForTest(0);
+ Parcel p;
+ state.write(p);
+ p.setDataPosition(0);
+ ComposerState parcelledState;
+ parcelledState.read(p);
+ EXPECT_EQ(state, parcelledState);
+};
+
+TEST(TransactionStateTest, parcelEmptyState) {
+ TransactionState state;
+ Parcel p;
+ state.writeToParcel(&p);
+ p.setDataPosition(0);
+ TransactionState parcelledState;
+ state.readFromParcel(&p);
+ EXPECT_EQ(state, parcelledState);
+};
+
+TEST(TransactionStateTest, mergeLayerState) {
+ ComposerState composerState = createComposerStateForTest(0);
+ ComposerState update;
+ update.state.surface = composerState.state.surface;
+ update.state.layerId = 0;
+ update.state.what = layer_state_t::eAlphaChanged;
+ update.state.color.a = .42;
+ composerState.state.merge(update.state);
+
+ ComposerState expectedMergedState = createComposerStateForTest(0);
+ expectedMergedState.state.what |= layer_state_t::eAlphaChanged;
+ expectedMergedState.state.color.a = .42;
+ EXPECT_EQ(composerState, expectedMergedState);
+};
+
+TEST(TransactionStateTest, merge) {
+ // Setup.
+ static constexpr uint64_t kUpdateTransactionId = 200;
+
+ TransactionState state = createTransactionStateForTest();
+
+ TransactionState update;
+ update.mId = kUpdateTransactionId;
+ {
+ ComposerState composerState;
+ composerState.state.surface = state.mComposerStates[0].state.surface;
+ composerState.state.what = layer_state_t::eAlphaChanged;
+ composerState.state.color.a = .42;
+ update.mComposerStates.push_back(composerState);
+ }
+ {
+ ComposerState composerState;
+ composerState.state.surface = state.mComposerStates[1].state.surface;
+ composerState.state.what = layer_state_t::eBufferChanged;
+ update.mComposerStates.push_back(composerState);
+ }
+ int32_t overrwiteLayerId = -1;
+ // Mutation.
+ state.merge(std::move(update),
+ [&overrwiteLayerId](layer_state_t ls) { overrwiteLayerId = ls.layerId; });
+ // Assertions.
+ EXPECT_EQ(1, overrwiteLayerId);
+ EXPECT_EQ(update, createEmptyTransaction(update.getId()));
+
+ TransactionState expectedMergedState = createTransactionStateForTest();
+ expectedMergedState.mMergedTransactionIds
+ .insert(expectedMergedState.mMergedTransactionIds.begin(), kUpdateTransactionId);
+ expectedMergedState.mComposerStates.at(0).state.what |= layer_state_t::eAlphaChanged;
+ expectedMergedState.mComposerStates.at(0).state.color.a = .42;
+ expectedMergedState.mComposerStates.at(1).state.what |= layer_state_t::eBufferChanged;
+ auto inputCommands = expectedMergedState.mInputWindowCommands;
+
+ // desired present time is not merged.
+ expectedMergedState.mDesiredPresentTime = state.mDesiredPresentTime;
+
+ EXPECT_EQ(state.mComposerStates[0], expectedMergedState.mComposerStates[0]);
+ EXPECT_EQ(state.mInputWindowCommands, expectedMergedState.mInputWindowCommands);
+ EXPECT_EQ(state, expectedMergedState);
+};
+
+TEST(TransactionStateTest, clear) {
+ TransactionState state = createTransactionStateForTest();
+ state.clear();
+ TransactionState emptyState = createEmptyTransaction(state.getId());
+ EXPECT_EQ(state, emptyState);
+};
+
+} // namespace android
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index ff26184..52e0276 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -225,6 +225,7 @@
srcs: [
"AccelerationCurve.cpp",
"CoordinateFilter.cpp",
+ "DisplayTopologyGraph.cpp",
"Input.cpp",
"InputConsumer.cpp",
"InputConsumerNoResampling.cpp",
@@ -270,6 +271,7 @@
shared_libs: [
"android.companion.virtualdevice.flags-aconfig-cc",
+ "com.android.window.flags.window-aconfig_flags_c_lib",
"libPlatformProperties",
"libaconfig_storage_read_api_cc",
"libbase",
diff --git a/libs/input/DisplayTopologyGraph.cpp b/libs/input/DisplayTopologyGraph.cpp
new file mode 100644
index 0000000..934f2e8
--- /dev/null
+++ b/libs/input/DisplayTopologyGraph.cpp
@@ -0,0 +1,144 @@
+/*
+ * 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 LOG_TAG "DisplayTopologyValidator"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <ftl/enum.h>
+#include <input/DisplayTopologyGraph.h>
+#include <input/PrintTools.h>
+#include <ui/LogicalDisplayId.h>
+
+#include <algorithm>
+
+#define INDENT " "
+
+namespace android {
+
+namespace {
+
+DisplayTopologyPosition getOppositePosition(DisplayTopologyPosition position) {
+ switch (position) {
+ case DisplayTopologyPosition::LEFT:
+ return DisplayTopologyPosition::RIGHT;
+ case DisplayTopologyPosition::TOP:
+ return DisplayTopologyPosition::BOTTOM;
+ case DisplayTopologyPosition::RIGHT:
+ return DisplayTopologyPosition::LEFT;
+ case DisplayTopologyPosition::BOTTOM:
+ return DisplayTopologyPosition::TOP;
+ }
+}
+
+bool validatePrimaryDisplay(const android::DisplayTopologyGraph& displayTopologyGraph) {
+ return displayTopologyGraph.primaryDisplayId != ui::LogicalDisplayId::INVALID &&
+ displayTopologyGraph.graph.contains(displayTopologyGraph.primaryDisplayId);
+}
+
+bool validateTopologyGraph(const android::DisplayTopologyGraph& displayTopologyGraph) {
+ for (const auto& [sourceDisplay, adjacentDisplays] : displayTopologyGraph.graph) {
+ for (const DisplayTopologyAdjacentDisplay& adjacentDisplay : adjacentDisplays) {
+ const auto adjacentGraphIt = displayTopologyGraph.graph.find(adjacentDisplay.displayId);
+ if (adjacentGraphIt == displayTopologyGraph.graph.end()) {
+ LOG(ERROR) << "Missing adjacent display in topology graph: "
+ << adjacentDisplay.displayId << " for source " << sourceDisplay;
+ return false;
+ }
+ const auto reverseEdgeIt =
+ std::find_if(adjacentGraphIt->second.begin(), adjacentGraphIt->second.end(),
+ [sourceDisplay](const DisplayTopologyAdjacentDisplay&
+ reverseAdjacentDisplay) {
+ return sourceDisplay == reverseAdjacentDisplay.displayId;
+ });
+ if (reverseEdgeIt == adjacentGraphIt->second.end()) {
+ LOG(ERROR) << "Missing reverse edge in topology graph for: " << sourceDisplay
+ << " -> " << adjacentDisplay.displayId;
+ return false;
+ }
+ DisplayTopologyPosition expectedPosition =
+ getOppositePosition(adjacentDisplay.position);
+ if (reverseEdgeIt->position != expectedPosition) {
+ LOG(ERROR) << "Unexpected reverse edge for: " << sourceDisplay << " -> "
+ << adjacentDisplay.displayId
+ << " expected position: " << ftl::enum_string(expectedPosition)
+ << " actual " << ftl::enum_string(reverseEdgeIt->position);
+ return false;
+ }
+ if (reverseEdgeIt->offsetDp != -adjacentDisplay.offsetDp) {
+ LOG(ERROR) << "Unexpected reverse edge offset: " << sourceDisplay << " -> "
+ << adjacentDisplay.displayId
+ << " expected offset: " << -adjacentDisplay.offsetDp << " actual "
+ << reverseEdgeIt->offsetDp;
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool validateDensities(const android::DisplayTopologyGraph& displayTopologyGraph) {
+ for (const auto& [sourceDisplay, adjacentDisplays] : displayTopologyGraph.graph) {
+ if (!displayTopologyGraph.displaysDensity.contains(sourceDisplay)) {
+ LOG(ERROR) << "Missing density value in topology graph for display: " << sourceDisplay;
+ return false;
+ }
+ }
+ return true;
+}
+
+std::string logicalDisplayIdToString(const ui::LogicalDisplayId& displayId) {
+ return base::StringPrintf("displayId(%d)", displayId.val());
+}
+
+std::string adjacentDisplayToString(const DisplayTopologyAdjacentDisplay& adjacentDisplay) {
+ return adjacentDisplay.dump();
+}
+
+std::string adjacentDisplayVectorToString(
+ const std::vector<DisplayTopologyAdjacentDisplay>& adjacentDisplays) {
+ return dumpVector(adjacentDisplays, adjacentDisplayToString);
+}
+
+} // namespace
+
+std::string DisplayTopologyAdjacentDisplay::dump() const {
+ std::string dump;
+ dump += base::StringPrintf("DisplayTopologyAdjacentDisplay: {displayId: %d, position: %s, "
+ "offsetDp: %f}",
+ displayId.val(), ftl::enum_string(position).c_str(), offsetDp);
+ return dump;
+}
+
+bool DisplayTopologyGraph::isValid() const {
+ return validatePrimaryDisplay(*this) && validateTopologyGraph(*this) &&
+ validateDensities(*this);
+}
+
+std::string DisplayTopologyGraph::dump() const {
+ std::string dump;
+ dump += base::StringPrintf("PrimaryDisplayId: %d\n", primaryDisplayId.val());
+ dump += base::StringPrintf("TopologyGraph:\n");
+ dump += addLinePrefix(dumpMap(graph, logicalDisplayIdToString, adjacentDisplayVectorToString),
+ INDENT);
+ dump += "\n";
+ dump += base::StringPrintf("DisplaysDensity:\n");
+ dump += addLinePrefix(dumpMap(displaysDensity, logicalDisplayIdToString), INDENT);
+ dump += "\n";
+ return dump;
+}
+
+} // namespace android
diff --git a/libs/input/InputFlags.cpp b/libs/input/InputFlags.cpp
index 555b138..6aa9ae6 100644
--- a/libs/input/InputFlags.cpp
+++ b/libs/input/InputFlags.cpp
@@ -18,6 +18,7 @@
#include <android-base/logging.h>
#include <com_android_input_flags.h>
+#include <com_android_window_flags.h>
#include <cutils/properties.h>
#include <string>
@@ -25,6 +26,9 @@
namespace android {
bool InputFlags::connectedDisplaysCursorEnabled() {
+ if (!com::android::window::flags::enable_desktop_mode_through_dev_option()) {
+ return com::android::input::flags::connected_displays_cursor();
+ }
static std::optional<bool> cachedDevOption;
if (!cachedDevOption.has_value()) {
char value[PROPERTY_VALUE_MAX];
@@ -39,4 +43,9 @@
return com::android::input::flags::connected_displays_cursor();
}
+bool InputFlags::connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled() {
+ return connectedDisplaysCursorEnabled() &&
+ com::android::input::flags::connected_displays_associated_display_cursor_bugfix();
+}
+
} // namespace android
\ No newline at end of file
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 9d387fe..983bbde 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -26,13 +26,6 @@
}
flag {
- name: "remove_input_channel_from_windowstate"
- namespace: "input"
- description: "Do not store a copy of input channel inside WindowState."
- bug: "323450804"
-}
-
-flag {
name: "enable_input_event_tracing"
namespace: "input"
description: "Set to true to enable input event tracing, including always-on tracing on non-user builds"
@@ -61,13 +54,6 @@
}
flag {
- name: "enable_touchpad_typing_palm_rejection"
- namespace: "input"
- description: "Enabling additional touchpad palm rejection will disable the tap to click while the user is typing on a physical keyboard"
- bug: "301055381"
-}
-
-flag {
name: "enable_v2_touchpad_typing_palm_rejection"
namespace: "input"
description: "In addition to touchpad palm rejection v1, v2 will also cancel ongoing move gestures while typing and add delay in re-enabling the tap to click."
@@ -127,13 +113,6 @@
}
flag {
- name: "hide_pointer_indicators_for_secure_windows"
- namespace: "input"
- description: "Hide touch and pointer indicators if a secure window is present on display"
- bug: "325252005"
-}
-
-flag {
name: "enable_keyboard_classifier"
namespace: "input"
description: "Keyboard classifier that classifies all keyboards into alphabetic or non-alphabetic"
@@ -148,13 +127,6 @@
}
flag {
- name: "include_relative_axis_values_for_captured_touchpads"
- namespace: "input"
- description: "Include AXIS_RELATIVE_X and AXIS_RELATIVE_Y values when reporting touches from captured touchpads."
- bug: "330522990"
-}
-
-flag {
name: "enable_per_device_input_latency_metrics"
namespace: "input"
description: "Capture input latency metrics on a per device granular level using histograms."
@@ -267,3 +239,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_display_topology_validation"
+ namespace: "input"
+ description: "Set to true to enable display topology validation"
+ bug: "401219231"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/libs/math/OWNERS b/libs/math/OWNERS
index 82ae422..08f0c5f 100644
--- a/libs/math/OWNERS
+++ b/libs/math/OWNERS
@@ -1,5 +1,4 @@
mathias@google.com
-randolphs@google.com
romainguy@google.com
sumir@google.com
jreck@google.com
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 24c2c74..89a97de 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -238,13 +238,17 @@
}
AChoreographer* AChoreographer_create() {
- Choreographer* choreographer = new Choreographer(nullptr);
+ // Increments default strongRef count on construction, will be decremented on
+ // function exit.
+ auto choreographer = sp<Choreographer>::make(nullptr);
status_t result = choreographer->initialize();
if (result != OK) {
ALOGW("Failed to initialize");
return nullptr;
}
- return Choreographer_to_AChoreographer(choreographer);
+ // Will be decremented and destroyed by AChoreographer_destroy
+ choreographer->incStrong((void*)AChoreographer_create);
+ return Choreographer_to_AChoreographer(choreographer.get());
}
void AChoreographer_destroy(AChoreographer* choreographer) {
@@ -252,7 +256,7 @@
return;
}
- delete AChoreographer_to_Choreographer(choreographer);
+ AChoreographer_to_Choreographer(choreographer)->decStrong((void*)AChoreographer_create);
}
int AChoreographer_getFd(const AChoreographer* choreographer) {
diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp
index 937ff02..51d0c81 100644
--- a/libs/nativewindow/tests/ANativeWindowTest.cpp
+++ b/libs/nativewindow/tests/ANativeWindowTest.cpp
@@ -50,14 +50,9 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGV("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- mItemConsumer = new BufferItemConsumer(GRALLOC_USAGE_SW_READ_OFTEN);
- mWindow = new TestableSurface(mItemConsumer->getSurface()->getIGraphicBufferProducer());
-#else
- BufferQueue::createBufferQueue(&mProducer, &mConsumer);
- mItemConsumer = new BufferItemConsumer(mConsumer, GRALLOC_USAGE_SW_READ_OFTEN);
- mWindow = new TestableSurface(mProducer);
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ sp<Surface> surface;
+ std::tie(mItemConsumer, surface) = BufferItemConsumer::create(GRALLOC_USAGE_SW_READ_OFTEN);
+ mWindow = new TestableSurface(surface->getIGraphicBufferProducer());
const int success = native_window_api_connect(mWindow.get(), NATIVE_WINDOW_API_CPU);
EXPECT_EQ(0, success);
}
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index 9f64d2c..f43694e 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -803,8 +803,7 @@
drawClippedLayers(renderengine, display, dstTexture, texture);
}
- if (com::android::graphics::libgui::flags::edge_extension_shader() &&
- config.cacheEdgeExtension) {
+ if (config.cacheEdgeExtension) {
SFTRACE_NAME("cacheEdgeExtension");
drawEdgeExtensionLayers(renderengine, display, dstTexture, texture);
drawEdgeExtensionLayers(renderengine, p3Display, dstTexture, texture);
diff --git a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp
index 4164c4b..f007427 100644
--- a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp
+++ b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp
@@ -58,9 +58,6 @@
)");
EdgeExtensionShaderFactory::EdgeExtensionShaderFactory() {
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- return;
- }
mResult = std::make_unique<SkRuntimeEffect::Result>(SkRuntimeEffect::MakeForShader(edgeShader));
LOG_ALWAYS_FATAL_IF(!mResult->errorText.isEmpty(),
"EdgeExtensionShaderFactory compilation "
diff --git a/services/surfaceflinger/Utils/RingBuffer.h b/libs/ui/include/ui/RingBuffer.h
similarity index 93%
rename from services/surfaceflinger/Utils/RingBuffer.h
rename to libs/ui/include/ui/RingBuffer.h
index 215472b..31d5a95 100644
--- a/services/surfaceflinger/Utils/RingBuffer.h
+++ b/libs/ui/include/ui/RingBuffer.h
@@ -19,7 +19,7 @@
#include <stddef.h>
#include <array>
-namespace android::utils {
+namespace android::ui {
template <class T, size_t SIZE>
class RingBuffer {
@@ -31,8 +31,8 @@
~RingBuffer() = default;
constexpr size_t capacity() const { return SIZE; }
-
size_t size() const { return mCount; }
+ bool isFull() const { return size() == capacity(); }
T& next() {
mHead = static_cast<size_t>(mHead + 1) % SIZE;
@@ -67,4 +67,4 @@
size_t mCount = 0;
};
-} // namespace android::utils
+} // namespace android::ui
diff --git a/libs/ui/include_types/ui/HdrRenderTypeUtils.h b/libs/ui/include_types/ui/HdrRenderTypeUtils.h
index 70c50f0..98018d9 100644
--- a/libs/ui/include_types/ui/HdrRenderTypeUtils.h
+++ b/libs/ui/include_types/ui/HdrRenderTypeUtils.h
@@ -36,7 +36,7 @@
*/
inline HdrRenderType getHdrRenderType(ui::Dataspace dataspace,
std::optional<ui::PixelFormat> pixelFormat,
- float hdrSdrRatio = 1.f) {
+ float hdrSdrRatio = 1.f, bool hasHdrMetadata = false) {
const auto transfer = dataspace & HAL_DATASPACE_TRANSFER_MASK;
const auto range = dataspace & HAL_DATASPACE_RANGE_MASK;
@@ -49,7 +49,8 @@
HAL_DATASPACE_RANGE_EXTENDED);
if ((dataspace == BT2020_LINEAR_EXT || dataspace == ui::Dataspace::V0_SCRGB) &&
- pixelFormat.has_value() && pixelFormat.value() == ui::PixelFormat::RGBA_FP16) {
+ pixelFormat.has_value() && pixelFormat.value() == ui::PixelFormat::RGBA_FP16 &&
+ hasHdrMetadata) {
return HdrRenderType::GENERIC_HDR;
}
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 2d8a1e3..2b11786 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -144,6 +144,17 @@
}
cc_test {
+ name: "RingBuffer_test",
+ test_suites: ["device-tests"],
+ shared_libs: ["libui"],
+ srcs: ["RingBuffer_test.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+cc_test {
name: "Size_test",
test_suites: ["device-tests"],
shared_libs: ["libui"],
diff --git a/libs/ui/tests/RingBuffer_test.cpp b/libs/ui/tests/RingBuffer_test.cpp
new file mode 100644
index 0000000..9839492
--- /dev/null
+++ b/libs/ui/tests/RingBuffer_test.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <ui/RingBuffer.h>
+
+namespace android::ui {
+
+TEST(RingBuffer, basic) {
+ RingBuffer<int, 5> rb;
+
+ rb.next() = 1;
+ ASSERT_EQ(1, rb.size());
+ ASSERT_EQ(1, rb.back());
+ ASSERT_EQ(1, rb.front());
+
+ rb.next() = 2;
+ ASSERT_EQ(2, rb.size());
+ ASSERT_EQ(2, rb.back());
+ ASSERT_EQ(1, rb.front());
+ ASSERT_EQ(1, rb[-1]);
+
+ rb.next() = 3;
+ ASSERT_EQ(3, rb.size());
+ ASSERT_EQ(3, rb.back());
+ ASSERT_EQ(1, rb.front());
+ ASSERT_EQ(2, rb[-1]);
+ ASSERT_EQ(1, rb[-2]);
+
+ rb.next() = 4;
+ ASSERT_EQ(4, rb.size());
+ ASSERT_EQ(4, rb.back());
+ ASSERT_EQ(1, rb.front());
+ ASSERT_EQ(3, rb[-1]);
+ ASSERT_EQ(2, rb[-2]);
+ ASSERT_EQ(1, rb[-3]);
+
+ rb.next() = 5;
+ ASSERT_EQ(5, rb.size());
+ ASSERT_EQ(5, rb.back());
+ ASSERT_EQ(1, rb.front());
+ ASSERT_EQ(4, rb[-1]);
+ ASSERT_EQ(3, rb[-2]);
+ ASSERT_EQ(2, rb[-3]);
+ ASSERT_EQ(1, rb[-4]);
+
+ rb.next() = 6;
+ ASSERT_EQ(5, rb.size());
+ ASSERT_EQ(6, rb.back());
+ ASSERT_EQ(2, rb.front());
+ ASSERT_EQ(5, rb[-1]);
+ ASSERT_EQ(4, rb[-2]);
+ ASSERT_EQ(3, rb[-3]);
+ ASSERT_EQ(2, rb[-4]);
+}
+
+} // namespace android::ui
\ No newline at end of file
diff --git a/opengl/libs/EGL/MultifileBlobCache.cpp b/opengl/libs/EGL/MultifileBlobCache.cpp
index 04c525e..7faf361 100644
--- a/opengl/libs/EGL/MultifileBlobCache.cpp
+++ b/opengl/libs/EGL/MultifileBlobCache.cpp
@@ -356,7 +356,7 @@
// If we're going to be over the cache limit, kick off a trim to clear space
if (getTotalSize() + fileSize > mMaxTotalSize || getTotalEntries() + 1 > mMaxTotalEntries) {
- ALOGV("SET: Cache is full, calling trimCache to clear space");
+ ALOGW("SET: Cache is full, calling trimCache to clear space");
trimCache();
}
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 0dd9f19..efc34f6 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -146,7 +146,7 @@
}
}
- if (graphicsenv_flags::feature_overrides()) {
+ if (graphicsenv_flags::angle_feature_overrides()) {
// Get the list of ANGLE features to enable from Global.Settings.
const auto& eglFeatures = GraphicsEnv::getInstance().getAngleEglFeatures();
for (const std::string& eglFeature : eglFeatures) {
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 25ee21f..46327df 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -147,7 +147,7 @@
}
FeatureOverrides GpuService::getFeatureOverrides() {
- if (!graphicsenv_flags::feature_overrides()) {
+ if (!graphicsenv_flags::angle_feature_overrides()) {
FeatureOverrides featureOverrides;
return featureOverrides;
}
@@ -183,7 +183,7 @@
ALOGV(" arg[%zu]: '%s'", i, String8(args[i]).c_str());
if (!args.empty()) {
- if (graphicsenv_flags::feature_overrides()) {
+ if (graphicsenv_flags::angle_feature_overrides()) {
if (args[0] == String16("featureOverrides"))
return cmdFeatureOverrides(out, err);
}
@@ -267,7 +267,7 @@
"GPU Service commands:\n"
" vkjson dump Vulkan properties as JSON\n"
" vkprofiles print support for select Vulkan profiles\n");
- if (graphicsenv_flags::feature_overrides()) {
+ if (graphicsenv_flags::angle_feature_overrides()) {
fprintf(outs,
" featureOverrides update and output gpuservice's feature overrides\n");
}
diff --git a/services/gpuservice/feature_override/Android.bp b/services/gpuservice/feature_override/Android.bp
index 3b5407b..842a0c4 100644
--- a/services/gpuservice/feature_override/Android.bp
+++ b/services/gpuservice/feature_override/Android.bp
@@ -69,6 +69,7 @@
name: "libfeatureoverride",
defaults: [
"libfeatureoverride_deps",
+ "libvkjson_deps",
],
srcs: [
":feature_config_proto_definitions",
@@ -85,6 +86,9 @@
cppflags: [
"-Wno-sign-compare",
],
+ static_libs: [
+ "libvkjson",
+ ],
export_include_dirs: ["include"],
proto: {
type: "lite",
diff --git a/services/gpuservice/feature_override/FeatureOverrideParser.cpp b/services/gpuservice/feature_override/FeatureOverrideParser.cpp
index a16bfa8..26ff84a 100644
--- a/services/gpuservice/feature_override/FeatureOverrideParser.cpp
+++ b/services/gpuservice/feature_override/FeatureOverrideParser.cpp
@@ -23,8 +23,10 @@
#include <sys/stat.h>
#include <vector>
+#include <android-base/macros.h>
#include <graphicsenv/FeatureOverrides.h>
#include <log/log.h>
+#include <vkjson.h>
#include "feature_config.pb.h"
@@ -35,13 +37,53 @@
featureOverrides.mPackageFeatures.clear();
}
+bool
+gpuVendorIdMatches(const VkJsonInstance &vkJsonInstance,
+ const uint32_t &configVendorId) {
+ if (vkJsonInstance.devices.empty()) {
+ return false;
+ }
+
+ // Always match the TEST Vendor ID
+ if (configVendorId == feature_override::GpuVendorID::VENDOR_ID_TEST) {
+ return true;
+ }
+
+ // Always assume one GPU device.
+ uint32_t vendorID = vkJsonInstance.devices.front().properties.vendorID;
+
+ return vendorID == configVendorId;
+}
+
+bool
+conditionsMet(const VkJsonInstance &vkJsonInstance,
+ const android::FeatureConfig &featureConfig) {
+ bool gpuVendorIdMatch = false;
+
+ if (featureConfig.mGpuVendorIDs.empty()) {
+ gpuVendorIdMatch = true;
+ } else {
+ for (const auto &gpuVendorID: featureConfig.mGpuVendorIDs) {
+ if (gpuVendorIdMatches(vkJsonInstance, gpuVendorID)) {
+ gpuVendorIdMatch = true;
+ break;
+ }
+ }
+ }
+
+ return gpuVendorIdMatch;
+}
+
void initFeatureConfig(android::FeatureConfig &featureConfig,
const feature_override::FeatureConfig &featureConfigProto) {
featureConfig.mFeatureName = featureConfigProto.feature_name();
featureConfig.mEnabled = featureConfigProto.enabled();
+ for (const auto &gpuVendorIdProto: featureConfigProto.gpu_vendor_ids()) {
+ featureConfig.mGpuVendorIDs.emplace_back(static_cast<uint32_t>(gpuVendorIdProto));
+ }
}
-feature_override::FeatureOverrideProtos readFeatureConfigProtos(std::string configFilePath) {
+feature_override::FeatureOverrideProtos readFeatureConfigProtos(const std::string &configFilePath) {
feature_override::FeatureOverrideProtos overridesProtos;
std::ifstream protobufBinaryFile(configFilePath.c_str());
@@ -78,9 +120,15 @@
bool FeatureOverrideParser::shouldReloadFeatureOverrides() const {
std::string configFilePath = getFeatureOverrideFilePath();
+
+ std::ifstream configFile(configFilePath);
+ if (!configFile.good()) {
+ return false;
+ }
+
struct stat fileStat{};
- if (stat(getFeatureOverrideFilePath().c_str(), &fileStat) != 0) {
- ALOGE("Error getting file information for '%s': %s", getFeatureOverrideFilePath().c_str(),
+ if (stat(configFilePath.c_str(), &fileStat) != 0) {
+ ALOGE("Error getting file information for '%s': %s", configFilePath.c_str(),
strerror(errno));
// stat'ing the file failed, so return false since reading it will also likely fail.
return false;
@@ -100,12 +148,22 @@
// Clear out the stale values before adding the newly parsed data.
resetFeatureOverrides(mFeatureOverrides);
+ if (overridesProtos.global_features().empty() &&
+ overridesProtos.package_features().empty()) {
+ // No overrides to parse.
+ return;
+ }
+
+ const VkJsonInstance vkJsonInstance = VkJsonGetInstance();
+
// Global feature overrides.
for (const auto &featureConfigProto: overridesProtos.global_features()) {
FeatureConfig featureConfig;
initFeatureConfig(featureConfig, featureConfigProto);
- mFeatureOverrides.mGlobalFeatures.emplace_back(featureConfig);
+ if (conditionsMet(vkJsonInstance, featureConfig)) {
+ mFeatureOverrides.mGlobalFeatures.emplace_back(featureConfig);
+ }
}
// App-specific feature overrides.
@@ -122,7 +180,9 @@
FeatureConfig featureConfig;
initFeatureConfig(featureConfig, featureConfigProto);
- featureConfigs.emplace_back(featureConfig);
+ if (conditionsMet(vkJsonInstance, featureConfig)) {
+ featureConfigs.emplace_back(featureConfig);
+ }
}
mFeatureOverrides.mPackageFeatures[packageName] = featureConfigs;
diff --git a/services/gpuservice/feature_override/proto/feature_config.proto b/services/gpuservice/feature_override/proto/feature_config.proto
index 4d4bf28..f285187 100644
--- a/services/gpuservice/feature_override/proto/feature_config.proto
+++ b/services/gpuservice/feature_override/proto/feature_config.proto
@@ -21,14 +21,43 @@
option optimize_for = LITE_RUNTIME;
/**
+ * GPU Vendor IDs.
+ * Taken from: external/angle/src/libANGLE/renderer/driver_utils.h
+ */
+enum GpuVendorID
+{
+ // Test ID matches every GPU Vendor ID.
+ VENDOR_ID_TEST = 0;
+ VENDOR_ID_AMD = 0x1002;
+ VENDOR_ID_ARM = 0x13B5;
+ // Broadcom devices won't use PCI, but this is their Vulkan vendor id.
+ VENDOR_ID_BROADCOM = 0x14E4;
+ VENDOR_ID_GOOGLE = 0x1AE0;
+ VENDOR_ID_INTEL = 0x8086;
+ VENDOR_ID_MESA = 0x10005;
+ VENDOR_ID_MICROSOFT = 0x1414;
+ VENDOR_ID_NVIDIA = 0x10DE;
+ VENDOR_ID_POWERVR = 0x1010;
+ // This is Qualcomm PCI Vendor ID.
+ // Android doesn't have a PCI bus, but all we need is a unique id.
+ VENDOR_ID_QUALCOMM = 0x5143;
+ VENDOR_ID_SAMSUNG = 0x144D;
+ VENDOR_ID_VIVANTE = 0x9999;
+ VENDOR_ID_VMWARE = 0x15AD;
+ VENDOR_ID_VIRTIO = 0x1AF4;
+}
+
+/**
* Feature Configuration
* feature_name: Feature name (see external/angle/include/platform/autogen/FeaturesVk_autogen.h).
* enabled: Either enable or disable the feature.
+ * gpu_vendor_ids: The GPU architectures this FeatureConfig applies to, if any.
*/
message FeatureConfig
{
string feature_name = 1;
bool enabled = 2;
+ repeated GpuVendorID gpu_vendor_ids = 3;
}
/**
diff --git a/services/gpuservice/tests/unittests/FeatureOverrideParserTest.cpp b/services/gpuservice/tests/unittests/FeatureOverrideParserTest.cpp
index 65a1b58..66556cd 100644
--- a/services/gpuservice/tests/unittests/FeatureOverrideParserTest.cpp
+++ b/services/gpuservice/tests/unittests/FeatureOverrideParserTest.cpp
@@ -70,14 +70,14 @@
};
testing::AssertionResult validateFeatureConfigTestTxtpbSizes(FeatureOverrides overrides) {
- size_t expectedGlobalFeaturesSize = 1;
+ size_t expectedGlobalFeaturesSize = 3;
if (overrides.mGlobalFeatures.size() != expectedGlobalFeaturesSize) {
return testing::AssertionFailure()
<< "overrides.mGlobalFeatures.size(): " << overrides.mGlobalFeatures.size()
<< ", expected: " << expectedGlobalFeaturesSize;
}
- size_t expectedPackageFeaturesSize = 1;
+ size_t expectedPackageFeaturesSize = 3;
if (overrides.mPackageFeatures.size() != expectedPackageFeaturesSize) {
return testing::AssertionFailure()
<< "overrides.mPackageFeatures.size(): " << overrides.mPackageFeatures.size()
@@ -133,6 +133,96 @@
EXPECT_TRUE(validateGlobalOverrides1(overrides));
}
+testing::AssertionResult validateGlobalOverrides2(FeatureOverrides overrides) {
+ const int kTestFeatureIndex = 1;
+ const std::string expectedFeatureName = "globalOverrides2";
+ const FeatureConfig &cfg = overrides.mGlobalFeatures[kTestFeatureIndex];
+
+ if (cfg.mFeatureName != expectedFeatureName) {
+ return testing::AssertionFailure()
+ << "cfg.mFeatureName: " << cfg.mFeatureName
+ << ", expected: " << expectedFeatureName;
+ }
+
+ bool expectedEnabled = true;
+ if (cfg.mEnabled != expectedEnabled) {
+ return testing::AssertionFailure()
+ << "cfg.mEnabled: " << cfg.mEnabled
+ << ", expected: " << expectedEnabled;
+ }
+
+ std::vector<uint32_t> expectedGpuVendorIDs = {
+ 0, // GpuVendorID::VENDOR_ID_TEST
+ 0x13B5, // GpuVendorID::VENDOR_ID_ARM
+ };
+ if (cfg.mGpuVendorIDs.size() != expectedGpuVendorIDs.size()) {
+ return testing::AssertionFailure()
+ << "cfg.mGpuVendorIDs.size(): " << cfg.mGpuVendorIDs.size()
+ << ", expected: " << expectedGpuVendorIDs.size();
+ }
+ for (int i = 0; i < expectedGpuVendorIDs.size(); i++) {
+ if (cfg.mGpuVendorIDs[i] != expectedGpuVendorIDs[i]) {
+ std::stringstream msg;
+ msg << "cfg.mGpuVendorIDs[" << i << "]: 0x" << std::hex << cfg.mGpuVendorIDs[i]
+ << ", expected: 0x" << std::hex << expectedGpuVendorIDs[i];
+ return testing::AssertionFailure() << msg.str();
+ }
+ }
+
+ return testing::AssertionSuccess();
+}
+
+TEST_F(FeatureOverrideParserTest, globalOverrides2) {
+ FeatureOverrides overrides = mFeatureOverrideParser.getFeatureOverrides();
+
+ EXPECT_TRUE(validateGlobalOverrides2(overrides));
+}
+
+testing::AssertionResult validateGlobalOverrides3(FeatureOverrides overrides) {
+ const int kTestFeatureIndex = 2;
+ const std::string expectedFeatureName = "globalOverrides3";
+ const FeatureConfig &cfg = overrides.mGlobalFeatures[kTestFeatureIndex];
+
+ if (cfg.mFeatureName != expectedFeatureName) {
+ return testing::AssertionFailure()
+ << "cfg.mFeatureName: " << cfg.mFeatureName
+ << ", expected: " << expectedFeatureName;
+ }
+
+ bool expectedEnabled = true;
+ if (cfg.mEnabled != expectedEnabled) {
+ return testing::AssertionFailure()
+ << "cfg.mEnabled: " << cfg.mEnabled
+ << ", expected: " << expectedEnabled;
+ }
+
+ std::vector<uint32_t> expectedGpuVendorIDs = {
+ 0, // GpuVendorID::VENDOR_ID_TEST
+ 0x8086, // GpuVendorID::VENDOR_ID_INTEL
+ };
+ if (cfg.mGpuVendorIDs.size() != expectedGpuVendorIDs.size()) {
+ return testing::AssertionFailure()
+ << "cfg.mGpuVendorIDs.size(): " << cfg.mGpuVendorIDs.size()
+ << ", expected: " << expectedGpuVendorIDs.size();
+ }
+ for (int i = 0; i < expectedGpuVendorIDs.size(); i++) {
+ if (cfg.mGpuVendorIDs[i] != expectedGpuVendorIDs[i]) {
+ std::stringstream msg;
+ msg << "cfg.mGpuVendorIDs[" << i << "]: 0x" << std::hex << cfg.mGpuVendorIDs[i]
+ << ", expected: 0x" << std::hex << expectedGpuVendorIDs[i];
+ return testing::AssertionFailure() << msg.str();
+ }
+ }
+
+ return testing::AssertionSuccess();
+}
+
+TEST_F(FeatureOverrideParserTest, globalOverrides3) {
+FeatureOverrides overrides = mFeatureOverrideParser.getFeatureOverrides();
+
+EXPECT_TRUE(validateGlobalOverrides3(overrides));
+}
+
testing::AssertionResult validatePackageOverrides1(FeatureOverrides overrides) {
const std::string expectedTestPackageName = "com.gpuservice_unittest.packageOverrides1";
@@ -155,6 +245,12 @@
const std::string expectedFeatureName = "packageOverrides1";
const FeatureConfig &cfg = features[0];
+ if (cfg.mFeatureName != expectedFeatureName) {
+ return testing::AssertionFailure()
+ << "cfg.mFeatureName: " << cfg.mFeatureName
+ << ", expected: " << expectedFeatureName;
+ }
+
bool expectedEnabled = true;
if (cfg.mEnabled != expectedEnabled) {
return testing::AssertionFailure()
@@ -193,6 +289,160 @@
return testing::AssertionSuccess();
}
+testing::AssertionResult validatePackageOverrides2(FeatureOverrides overrides) {
+ const std::string expectedPackageName = "com.gpuservice_unittest.packageOverrides2";
+
+ if (!overrides.mPackageFeatures.count(expectedPackageName)) {
+ return testing::AssertionFailure()
+ << "overrides.mPackageFeatures missing expected package: " << expectedPackageName;
+ }
+
+ const std::vector<FeatureConfig>& features = overrides.mPackageFeatures[expectedPackageName];
+
+ size_t expectedFeaturesSize = 1;
+ if (features.size() != expectedFeaturesSize) {
+ return testing::AssertionFailure()
+ << "features.size(): " << features.size()
+ << ", expectedFeaturesSize: " << expectedFeaturesSize;
+ }
+
+ const std::string expectedFeatureName = "packageOverrides2";
+ const FeatureConfig &cfg = features[0];
+
+ if (cfg.mFeatureName != expectedFeatureName) {
+ return testing::AssertionFailure()
+ << "cfg.mFeatureName: " << cfg.mFeatureName
+ << ", expected: " << expectedFeatureName;
+ }
+
+ bool expectedEnabled = false;
+ if (cfg.mEnabled != expectedEnabled) {
+ return testing::AssertionFailure()
+ << "cfg.mEnabled: " << cfg.mEnabled
+ << ", expected: " << expectedEnabled;
+ }
+
+ std::vector<uint32_t> expectedGpuVendorIDs = {
+ 0, // GpuVendorID::VENDOR_ID_TEST
+ 0x8086, // GpuVendorID::VENDOR_ID_INTEL
+ };
+ if (cfg.mGpuVendorIDs.size() != expectedGpuVendorIDs.size()) {
+ return testing::AssertionFailure()
+ << "cfg.mGpuVendorIDs.size(): " << cfg.mGpuVendorIDs.size()
+ << ", expected: " << expectedGpuVendorIDs.size();
+ }
+ for (int i = 0; i < expectedGpuVendorIDs.size(); i++) {
+ if (cfg.mGpuVendorIDs[i] != expectedGpuVendorIDs[i]) {
+ std::stringstream msg;
+ msg << "cfg.mGpuVendorIDs[" << i << "]: 0x" << std::hex << cfg.mGpuVendorIDs[i]
+ << ", expected: 0x" << std::hex << expectedGpuVendorIDs[i];
+ return testing::AssertionFailure() << msg.str();
+ }
+ }
+
+ return testing::AssertionSuccess();
+}
+
+TEST_F(FeatureOverrideParserTest, packageOverrides2) {
+ FeatureOverrides overrides = mFeatureOverrideParser.getFeatureOverrides();
+
+ EXPECT_TRUE(validatePackageOverrides2(overrides));
+}
+
+testing::AssertionResult validatePackageOverrides3(FeatureOverrides overrides) {
+ const std::string expectedPackageName = "com.gpuservice_unittest.packageOverrides3";
+
+ if (!overrides.mPackageFeatures.count(expectedPackageName)) {
+ return testing::AssertionFailure()
+ << "overrides.mPackageFeatures missing expected package: " << expectedPackageName;
+ }
+
+ const std::vector<FeatureConfig>& features = overrides.mPackageFeatures[expectedPackageName];
+
+ size_t expectedFeaturesSize = 2;
+ if (features.size() != expectedFeaturesSize) {
+ return testing::AssertionFailure()
+ << "features.size(): " << features.size()
+ << ", expectedFeaturesSize: " << expectedFeaturesSize;
+ }
+
+ std::string expectedFeatureName = "packageOverrides3_1";
+ const FeatureConfig &cfg_1 = features[0];
+
+ if (cfg_1.mFeatureName != expectedFeatureName) {
+ return testing::AssertionFailure()
+ << "cfg.mFeatureName: " << cfg_1.mFeatureName
+ << ", expected: " << expectedFeatureName;
+ }
+
+ bool expectedEnabled = false;
+ if (cfg_1.mEnabled != expectedEnabled) {
+ return testing::AssertionFailure()
+ << "cfg.mEnabled: " << cfg_1.mEnabled
+ << ", expected: " << expectedEnabled;
+ }
+
+ std::vector<uint32_t> expectedGpuVendorIDs = {
+ 0, // GpuVendorID::VENDOR_ID_TEST
+ 0x13B5, // GpuVendorID::VENDOR_ID_ARM
+ };
+ if (cfg_1.mGpuVendorIDs.size() != expectedGpuVendorIDs.size()) {
+ return testing::AssertionFailure()
+ << "cfg.mGpuVendorIDs.size(): " << cfg_1.mGpuVendorIDs.size()
+ << ", expected: " << expectedGpuVendorIDs.size();
+ }
+ for (int i = 0; i < expectedGpuVendorIDs.size(); i++) {
+ if (cfg_1.mGpuVendorIDs[i] != expectedGpuVendorIDs[i]) {
+ std::stringstream msg;
+ msg << "cfg.mGpuVendorIDs[" << i << "]: 0x" << std::hex << cfg_1.mGpuVendorIDs[i]
+ << ", expected: 0x" << std::hex << expectedGpuVendorIDs[i];
+ return testing::AssertionFailure() << msg.str();
+ }
+ }
+
+ expectedFeatureName = "packageOverrides3_2";
+ const FeatureConfig &cfg_2 = features[1];
+
+ if (cfg_2.mFeatureName != expectedFeatureName) {
+ return testing::AssertionFailure()
+ << "cfg.mFeatureName: " << cfg_2.mFeatureName
+ << ", expected: " << expectedFeatureName;
+ }
+
+ expectedEnabled = true;
+ if (cfg_2.mEnabled != expectedEnabled) {
+ return testing::AssertionFailure()
+ << "cfg.mEnabled: " << cfg_2.mEnabled
+ << ", expected: " << expectedEnabled;
+ }
+
+ expectedGpuVendorIDs = {
+ 0, // GpuVendorID::VENDOR_ID_TEST
+ 0x8086, // GpuVendorID::VENDOR_ID_INTEL
+ };
+ if (cfg_2.mGpuVendorIDs.size() != expectedGpuVendorIDs.size()) {
+ return testing::AssertionFailure()
+ << "cfg.mGpuVendorIDs.size(): " << cfg_2.mGpuVendorIDs.size()
+ << ", expected: " << expectedGpuVendorIDs.size();
+ }
+ for (int i = 0; i < expectedGpuVendorIDs.size(); i++) {
+ if (cfg_2.mGpuVendorIDs[i] != expectedGpuVendorIDs[i]) {
+ std::stringstream msg;
+ msg << "cfg.mGpuVendorIDs[" << i << "]: 0x" << std::hex << cfg_2.mGpuVendorIDs[i]
+ << ", expected: 0x" << std::hex << expectedGpuVendorIDs[i];
+ return testing::AssertionFailure() << msg.str();
+ }
+ }
+
+ return testing::AssertionSuccess();
+}
+
+TEST_F(FeatureOverrideParserTest, packageOverrides3) {
+FeatureOverrides overrides = mFeatureOverrideParser.getFeatureOverrides();
+
+EXPECT_TRUE(validatePackageOverrides3(overrides));
+}
+
TEST_F(FeatureOverrideParserTest, forceFileRead) {
FeatureOverrides overrides = mFeatureOverrideParser.getFeatureOverrides();
diff --git a/services/gpuservice/tests/unittests/data/feature_config_test.txtpb b/services/gpuservice/tests/unittests/data/feature_config_test.txtpb
index 726779e..44a6f78 100644
--- a/services/gpuservice/tests/unittests/data/feature_config_test.txtpb
+++ b/services/gpuservice/tests/unittests/data/feature_config_test.txtpb
@@ -22,6 +22,22 @@
{
feature_name: "globalOverrides1"
enabled: False
+ },
+ {
+ feature_name: "globalOverrides2"
+ enabled: True
+ gpu_vendor_ids: [
+ VENDOR_ID_TEST, # Match every GPU Vendor ID, so the feature isn't dropped when parsed.
+ VENDOR_ID_ARM
+ ]
+ },
+ {
+ feature_name: "globalOverrides3"
+ enabled: True
+ gpu_vendor_ids: [
+ VENDOR_ID_TEST, # Match every GPU Vendor ID, so the feature isn't dropped when parsed.
+ VENDOR_ID_INTEL
+ ]
}
]
@@ -36,5 +52,39 @@
enabled: True
}
]
+ },
+ {
+ package_name: "com.gpuservice_unittest.packageOverrides2"
+ feature_configs: [
+ {
+ feature_name: "packageOverrides2"
+ enabled: False
+ gpu_vendor_ids: [
+ VENDOR_ID_TEST, # Match every GPU Vendor ID, so the feature isn't dropped when parsed.
+ VENDOR_ID_INTEL
+ ]
+ }
+ ]
+ },
+ {
+ package_name: "com.gpuservice_unittest.packageOverrides3"
+ feature_configs: [
+ {
+ feature_name: "packageOverrides3_1"
+ enabled: False
+ gpu_vendor_ids: [
+ VENDOR_ID_TEST, # Match every GPU Vendor ID, so the feature isn't dropped when parsed.
+ VENDOR_ID_ARM
+ ]
+ },
+ {
+ feature_name: "packageOverrides3_2"
+ enabled: True
+ gpu_vendor_ids: [
+ VENDOR_ID_TEST, # Match every GPU Vendor ID, so the feature isn't dropped when parsed.
+ VENDOR_ID_INTEL
+ ]
+ }
+ ]
}
]
diff --git a/services/gpuservice/vts/OWNERS b/services/gpuservice/vts/OWNERS
index a63de1c..13a089f 100644
--- a/services/gpuservice/vts/OWNERS
+++ b/services/gpuservice/vts/OWNERS
@@ -1,8 +1,5 @@
# Bug component: 653544
kocdemir@google.com
paulthomson@google.com
-pbaiget@google.com
-lfy@google.com
chrisforbes@google.com
-lpy@google.com
alecmouri@google.com
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp
index 21f4f2c..98f0f34 100644
--- a/services/inputflinger/PointerChoreographer.cpp
+++ b/services/inputflinger/PointerChoreographer.cpp
@@ -31,6 +31,7 @@
#include "PointerChoreographer.h"
#define INDENT " "
+#define INDENT2 " "
namespace android {
@@ -132,7 +133,7 @@
}),
mNextListener(listener),
mPolicy(policy),
- mDefaultMouseDisplayId(ui::LogicalDisplayId::DEFAULT),
+ mCurrentMouseDisplayId(ui::LogicalDisplayId::INVALID),
mNotifiedPointerDisplayId(ui::LogicalDisplayId::INVALID),
mShowTouchesEnabled(false),
mStylusPointerIconEnabled(false),
@@ -361,7 +362,7 @@
LOG(FATAL) << "A cursor already exists on destination display"
<< destinationViewport.displayId;
}
- mDefaultMouseDisplayId = destinationViewport.displayId;
+ mCurrentMouseDisplayId = destinationViewport.displayId;
auto pcNode = mMousePointersByDisplay.extract(sourceDisplayId);
pcNode.key() = destinationViewport.displayId;
mMousePointersByDisplay.insert(std::move(pcNode));
@@ -535,9 +536,6 @@
}
void PointerChoreographer::onControllerAddedOrRemovedLocked() {
- if (!com::android::input::flags::hide_pointer_indicators_for_secure_windows()) {
- return;
- }
bool requireListener = !mTouchPointersByDevice.empty() || !mMousePointersByDisplay.empty() ||
!mDrawingTabletPointersByDevice.empty() || !mStylusPointersByDevice.empty();
@@ -602,15 +600,21 @@
}
void PointerChoreographer::setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph) {
- std::scoped_lock _l(getLock());
- mTopology = displayTopologyGraph;
+ PointerDisplayChange pointerDisplayChange;
+ { // acquire lock
+ std::scoped_lock _l(getLock());
+ mTopology = displayTopologyGraph;
- // make primary display default mouse display, if it was not set
- // or the existing display was removed
- if (mDefaultMouseDisplayId == ui::LogicalDisplayId::INVALID ||
- mTopology.graph.find(mDefaultMouseDisplayId) != mTopology.graph.end()) {
- mDefaultMouseDisplayId = mTopology.primaryDisplayId;
- }
+ // make primary display default mouse display, if it was not set or
+ // the existing display was removed
+ if (mCurrentMouseDisplayId == ui::LogicalDisplayId::INVALID ||
+ mTopology.graph.find(mCurrentMouseDisplayId) == mTopology.graph.end()) {
+ mCurrentMouseDisplayId = mTopology.primaryDisplayId;
+ pointerDisplayChange = updatePointerControllersLocked();
+ }
+ } // release lock
+
+ notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
}
void PointerChoreographer::dump(std::string& dump) {
@@ -644,6 +648,8 @@
std::string pointerControllerDump = addLinePrefix(drawingTabletController->dump(), INDENT);
dump += INDENT + std::to_string(deviceId) + " : " + pointerControllerDump;
}
+ dump += INDENT "DisplayTopologyGraph:\n";
+ dump += addLinePrefix(mTopology.dump(), INDENT2);
dump += "\n";
}
@@ -659,7 +665,25 @@
ui::LogicalDisplayId PointerChoreographer::getTargetMouseDisplayLocked(
ui::LogicalDisplayId associatedDisplayId) const {
- return associatedDisplayId.isValid() ? associatedDisplayId : mDefaultMouseDisplayId;
+ if (!InputFlags::connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled()) {
+ if (associatedDisplayId.isValid()) {
+ return associatedDisplayId;
+ }
+ return mCurrentMouseDisplayId.isValid() ? mCurrentMouseDisplayId
+ : ui::LogicalDisplayId::DEFAULT;
+ }
+ // Associated display is not included in the topology, return this associated display.
+ if (associatedDisplayId.isValid() &&
+ mTopology.graph.find(associatedDisplayId) == mTopology.graph.end()) {
+ return associatedDisplayId;
+ }
+ if (mCurrentMouseDisplayId.isValid()) {
+ return mCurrentMouseDisplayId;
+ }
+ if (mTopology.primaryDisplayId.isValid()) {
+ return mTopology.primaryDisplayId;
+ }
+ return ui::LogicalDisplayId::DEFAULT;
}
std::pair<ui::LogicalDisplayId, PointerControllerInterface&>
@@ -768,7 +792,8 @@
PointerChoreographer::calculatePointerDisplayChangeToNotify() {
ui::LogicalDisplayId displayIdToNotify = ui::LogicalDisplayId::INVALID;
vec2 cursorPosition = {0, 0};
- if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
+ if (const auto it =
+ mMousePointersByDisplay.find(getTargetMouseDisplayLocked(mCurrentMouseDisplayId));
it != mMousePointersByDisplay.end()) {
const auto& pointerController = it->second;
// Use the displayId from the pointerController, because it accurately reflects whether
@@ -785,12 +810,16 @@
}
void PointerChoreographer::setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) {
+ if (InputFlags::connectedDisplaysCursorEnabled()) {
+ // In connected displays scenario, default mouse display will only be updated from topology.
+ return;
+ }
PointerDisplayChange pointerDisplayChange;
{ // acquire lock
std::scoped_lock _l(getLock());
- mDefaultMouseDisplayId = displayId;
+ mCurrentMouseDisplayId = displayId;
pointerDisplayChange = updatePointerControllersLocked();
} // release lock
diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h
index 2435125..67bdca1 100644
--- a/services/inputflinger/PointerChoreographer.h
+++ b/services/inputflinger/PointerChoreographer.h
@@ -231,7 +231,12 @@
std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mDrawingTabletPointersByDevice
GUARDED_BY(getLock());
- ui::LogicalDisplayId mDefaultMouseDisplayId GUARDED_BY(getLock());
+ // In connected displays scenario, this tracks the latest display the cursor is at, within the
+ // DisplayTopology. By default, this will be set to topology primary display, and updated when
+ // mouse crossed to another display.
+ // In non-connected displays scenario, this will be treated as the default display cursor
+ // will be on, when mouse doesn't have associated display.
+ ui::LogicalDisplayId mCurrentMouseDisplayId GUARDED_BY(getLock());
ui::LogicalDisplayId mNotifiedPointerDisplayId GUARDED_BY(getLock());
std::vector<InputDeviceInfo> mInputDeviceInfos GUARDED_BY(getLock());
std::set<DeviceId> mMouseDevices GUARDED_BY(getLock());
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index ba75071..888fcfb 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -5222,6 +5222,11 @@
} else {
dump += "Displays: <none>\n";
}
+ dump += StringPrintf("mMaximumObscuringOpacityForTouch: %f\n",
+ mMaximumObscuringOpacityForTouch);
+ dump += "DisplayTopologyGraph:\n";
+ dump += addLinePrefix(mTopology.dump(), INDENT);
+ dump += "\n";
return dump;
}
@@ -7553,9 +7558,10 @@
return;
}
- // TODO(b/383092013): This is currently not accounting for the "topology group" concept.
- // Proper implementation requires looking tghrough all the displays in the topology group.
- const auto cursorStateIt = mCursorStateByDisplay.find(displayId);
+ // DisplayId for the Cursor state may not be same as supplied displayId if display is part of
+ // topology. Instead we should to check from the topology's primary display.
+ const auto cursorStateIt =
+ mCursorStateByDisplay.find(mWindowInfos.getPrimaryDisplayId(displayId));
if (cursorStateIt != mCursorStateByDisplay.end()) {
f(cursorStateIt->second);
}
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 845cab0..58df692 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -32,6 +32,7 @@
#include <unistd.h>
#include <utils/Errors.h>
#include <utils/Thread.h>
+#include <string>
#include "InputDevice.h"
#include "include/gestures.h"
@@ -945,7 +946,10 @@
void InputReader::dump(std::string& dump) {
std::scoped_lock _l(mLock);
+ dumpLocked(dump);
+}
+void InputReader::dumpLocked(std::string& dump) {
mEventHub->dump(dump);
dump += "\n";
@@ -1032,6 +1036,12 @@
InputReader::ContextImpl::ContextImpl(InputReader* reader)
: mReader(reader), mIdGenerator(IdGenerator::Source::INPUT_READER) {}
+std::string InputReader::ContextImpl::dump() {
+ std::string dump;
+ mReader->dumpLocked(dump);
+ return dump;
+}
+
void InputReader::ContextImpl::updateGlobalMetaState() {
// lock is already held by the input loop
mReader->updateGlobalMetaStateLocked();
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 0d6e102..6a25937 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -21,6 +21,7 @@
#include <utils/Mutex.h>
#include <memory>
+#include <string>
#include <unordered_map>
#include <vector>
@@ -142,6 +143,7 @@
public:
explicit ContextImpl(InputReader* reader);
+ std::string dump() REQUIRES(mReader->mLock) override;
// lock is already held by the input loop
void updateGlobalMetaState() NO_THREAD_SAFETY_ANALYSIS override;
int32_t getGlobalMetaState() NO_THREAD_SAFETY_ANALYSIS override;
@@ -216,6 +218,8 @@
// The input device that produced a new gesture most recently.
DeviceId mLastUsedDeviceId GUARDED_BY(mLock){ReservedInputDeviceId::INVALID_INPUT_DEVICE_ID};
+ void dumpLocked(std::string& dump) REQUIRES(mLock);
+
// low-level input event decoding and device management
[[nodiscard]] std::list<NotifyArgs> processEventsLocked(const RawEvent* rawEvents, size_t count)
REQUIRES(mLock);
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index 20ed74f..f38fd7b 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -20,6 +20,7 @@
#include <input/KeyboardClassifier.h>
#include "NotifyArgs.h"
+#include <string>
#include <vector>
namespace android {
@@ -39,6 +40,8 @@
InputReaderContext() {}
virtual ~InputReaderContext() {}
+ virtual std::string dump() = 0;
+
virtual void updateGlobalMetaState() = 0;
virtual int32_t getGlobalMetaState() = 0;
diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
index dd46bbc..d796af1 100644
--- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
+++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
@@ -25,8 +25,6 @@
#include <linux/input-event-codes.h>
#include <log/log_main.h>
-namespace input_flags = com::android::input::flags;
-
namespace android {
namespace {
@@ -119,15 +117,10 @@
}
void CapturedTouchpadEventConverter::populateMotionRanges(InputDeviceInfo& info) const {
- if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
- tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_X,
- AMOTION_EVENT_AXIS_RELATIVE_X, ABS_MT_POSITION_X);
- tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_Y,
- AMOTION_EVENT_AXIS_RELATIVE_Y, ABS_MT_POSITION_Y);
- } else {
- tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X);
- tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y);
- }
+ tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_X,
+ AMOTION_EVENT_AXIS_RELATIVE_X, ABS_MT_POSITION_X);
+ tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_Y,
+ AMOTION_EVENT_AXIS_RELATIVE_Y, ABS_MT_POSITION_Y);
tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MAJOR, ABS_MT_TOUCH_MAJOR);
tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MINOR, ABS_MT_TOUCH_MINOR);
tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOOL_MAJOR, ABS_MT_WIDTH_MAJOR);
@@ -213,13 +206,11 @@
}
out.push_back(
makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, coords, properties));
- if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
- // For any further events we send from this sync, the pointers won't have moved relative
- // to the positions we just reported in this MOVE event, so zero out the relative axes.
- for (PointerCoords& pointer : coords) {
- pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
- pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
- }
+ // For any further events we send from this sync, the pointers won't have moved relative to
+ // the positions we just reported in this MOVE event, so zero out the relative axes.
+ for (PointerCoords& pointer : coords) {
+ pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
+ pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
}
}
@@ -275,9 +266,7 @@
/*flags=*/cancel ? AMOTION_EVENT_FLAG_CANCELED : 0));
freePointerIdForSlot(slotNumber);
- if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
- mPreviousCoordsForSlotNumber.erase(slotNumber);
- }
+ mPreviousCoordsForSlotNumber.erase(slotNumber);
coords.erase(coords.begin() + indexToRemove);
properties.erase(properties.begin() + indexToRemove);
// Now that we've removed some coords and properties, we might have to update the slot
@@ -336,15 +325,13 @@
coords.clear();
coords.setAxisValue(AMOTION_EVENT_AXIS_X, slot.getX());
coords.setAxisValue(AMOTION_EVENT_AXIS_Y, slot.getY());
- if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
- if (auto it = mPreviousCoordsForSlotNumber.find(slotNumber);
- it != mPreviousCoordsForSlotNumber.end()) {
- auto [oldX, oldY] = it->second;
- coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, slot.getX() - oldX);
- coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, slot.getY() - oldY);
- }
- mPreviousCoordsForSlotNumber[slotNumber] = std::make_pair(slot.getX(), slot.getY());
+ if (auto it = mPreviousCoordsForSlotNumber.find(slotNumber);
+ it != mPreviousCoordsForSlotNumber.end()) {
+ auto [oldX, oldY] = it->second;
+ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, slot.getX() - oldX);
+ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, slot.getY() - oldY);
}
+ mPreviousCoordsForSlotNumber[slotNumber] = std::make_pair(slot.getX(), slot.getY());
coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, slot.getTouchMajor());
coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, slot.getTouchMinor());
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 8deff6b..4d36db8 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -24,6 +24,8 @@
#include <cinttypes>
#include <cmath>
#include <cstddef>
+#include <sstream>
+#include <string>
#include <tuple>
#include <math.h>
@@ -138,6 +140,40 @@
*outY = y;
}
+std::ostream& operator<<(std::ostream& out, const RawPointerData::Pointer& p) {
+ out << "id=" << p.id << ", x=" << p.x << ", y=" << p.y << ", pressure=" << p.pressure
+ << ", touchMajor=" << p.touchMajor << ", touchMinor=" << p.touchMinor
+ << ", toolMajor=" << p.toolMajor << ", toolMinor=" << p.toolMinor
+ << ", orientation=" << p.orientation << ", tiltX=" << p.tiltX << ", tiltY=" << p.tiltY
+ << ", distance=" << p.distance << ", toolType=" << ftl::enum_string(p.toolType)
+ << ", isHovering=" << p.isHovering;
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const RawPointerData& data) {
+ out << data.pointerCount << " pointers:\n";
+ for (uint32_t i = 0; i < data.pointerCount; i++) {
+ out << INDENT << "[" << i << "]: " << data.pointers[i] << std::endl;
+ }
+ out << "ID bits: hovering = 0x" << std::hex << std::setfill('0') << std::setw(8)
+ << data.hoveringIdBits.value << ", touching = 0x" << std::setfill('0') << std::setw(8)
+ << data.touchingIdBits.value << ", canceled = 0x" << std::setfill('0') << std::setw(8)
+ << data.canceledIdBits.value << std::dec;
+ return out;
+}
+
+// --- TouchInputMapper::RawState ---
+
+std::ostream& operator<<(std::ostream& out, const TouchInputMapper::RawState& state) {
+ out << "When: " << state.when << std::endl;
+ out << "Read time: " << state.readTime << std::endl;
+ out << "Button state: 0x" << std::setfill('0') << std::setw(8) << std::hex << state.buttonState
+ << std::dec << std::endl;
+ out << "Raw pointer data:" << std::endl;
+ out << addLinePrefix(streamableToString(state.rawPointerData), INDENT);
+ return out;
+}
+
// --- TouchInputMapper ---
TouchInputMapper::TouchInputMapper(InputDeviceContext& deviceContext,
@@ -232,20 +268,8 @@
dump += StringPrintf(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
dump += StringPrintf(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState);
- dump += StringPrintf(INDENT3 "Last Raw Touch: pointerCount=%d\n",
- mLastRawState.rawPointerData.pointerCount);
- for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) {
- const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i];
- dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
- "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
- "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, "
- "toolType=%s, isHovering=%s\n",
- i, pointer.id, pointer.x, pointer.y, pointer.pressure,
- pointer.touchMajor, pointer.touchMinor, pointer.toolMajor,
- pointer.toolMinor, pointer.orientation, pointer.tiltX, pointer.tiltY,
- pointer.distance, ftl::enum_string(pointer.toolType).c_str(),
- toString(pointer.isHovering));
- }
+ dump += INDENT3 "Last Raw Touch:\n";
+ dump += addLinePrefix(streamableToString(mLastRawState), INDENT4) + "\n";
dump += StringPrintf(INDENT3 "Last Cooked Button State: 0x%08x\n",
mLastCookedState.buttonState);
@@ -1476,6 +1500,22 @@
last.rawPointerData.touchingIdBits.value, next.rawPointerData.touchingIdBits.value,
last.rawPointerData.hoveringIdBits.value, next.rawPointerData.hoveringIdBits.value,
next.rawPointerData.canceledIdBits.value);
+ if (debugRawEvents() && last.rawPointerData.pointerCount == 0 &&
+ next.rawPointerData.pointerCount == 1) {
+ // Dump a bunch of info to try to debug b/396796958.
+ // TODO(b/396796958): remove this debug dump.
+ ALOGD("pointerCount went from 0 to 1. last:\n%s",
+ addLinePrefix(streamableToString(last), INDENT).c_str());
+ ALOGD("next:\n%s", addLinePrefix(streamableToString(next), INDENT).c_str());
+ ALOGD("InputReader dump:");
+ // The dump is too long to simply add as a format parameter in one log message, so we have
+ // to split it by line and log them individually.
+ std::istringstream stream(mDeviceContext.getContext()->dump());
+ std::string line;
+ while (std::getline(stream, line, '\n')) {
+ ALOGD(INDENT "%s", line.c_str());
+ }
+ }
if (!next.rawPointerData.touchingIdBits.isEmpty() &&
!next.rawPointerData.hoveringIdBits.isEmpty() &&
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 4ef0be8..45fc6bf 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -348,6 +348,8 @@
inline void clear() { *this = RawState(); }
};
+ friend std::ostream& operator<<(std::ostream& out, const RawState& state);
+
struct CookedState {
// Cooked pointer sample data.
CookedPointerData cookedPointerData{};
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index 480e276..3255877 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -39,9 +39,6 @@
namespace {
-// This will disable the tap to click while the user is typing on a physical keyboard
-const bool ENABLE_TOUCHPAD_PALM_REJECTION = input_flags::enable_touchpad_typing_palm_rejection();
-
// In addition to v1, v2 will also cancel ongoing move gestures while typing and add delay in
// re-enabling the tap to click.
const bool ENABLE_TOUCHPAD_PALM_REJECTION_V2 =
@@ -226,8 +223,7 @@
if (!mIsHoverCancelled) {
// handleFling calls hoverMove with zero delta on FLING_TAP_DOWN. Don't enable tap to click
// for this case as subsequent handleButtonsChange may choose to ignore this tap.
- if ((ENABLE_TOUCHPAD_PALM_REJECTION || ENABLE_TOUCHPAD_PALM_REJECTION_V2) &&
- (std::abs(deltaX) > 0 || std::abs(deltaY) > 0)) {
+ if (std::abs(deltaX) > 0 || std::abs(deltaY) > 0) {
enableTapToClick(when);
}
}
@@ -278,7 +274,7 @@
// return early to prevent this tap
return out;
}
- } else if (ENABLE_TOUCHPAD_PALM_REJECTION && mReaderContext.isPreventingTouchpadTaps()) {
+ } else if (mReaderContext.isPreventingTouchpadTaps()) {
enableTapToClick(when);
if (gesture.details.buttons.is_tap) {
// return early to prevent this tap
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 18d47f6..677cf1e 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -52,6 +52,7 @@
"AnrTracker_test.cpp",
"CapturedTouchpadEventConverter_test.cpp",
"CursorInputMapper_test.cpp",
+ "DisplayTopologyGraph_test.cpp",
"EventHub_test.cpp",
"FakeEventHub.cpp",
"FakeInputReaderPolicy.cpp",
diff --git a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
index 353011a..c6246d9 100644
--- a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
+++ b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
@@ -33,8 +33,6 @@
#include "TestEventMatchers.h"
#include "TestInputListener.h"
-namespace input_flags = com::android::input::flags;
-
namespace android {
using testing::AllOf;
@@ -50,8 +48,6 @@
mReader(mFakeEventHub, mFakePolicy, mFakeListener),
mDevice(newDevice()),
mDeviceContext(*mDevice, EVENTHUB_ID) {
- input_flags::include_relative_axis_values_for_captured_touchpads(true);
-
const size_t slotCount = 8;
mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_SLOT, 0, slotCount - 1, 0, 0, 0);
mAccumulator.configure(mDeviceContext, slotCount, /*usingSlotsProtocol=*/true);
diff --git a/services/inputflinger/tests/DisplayTopologyGraph_test.cpp b/services/inputflinger/tests/DisplayTopologyGraph_test.cpp
new file mode 100644
index 0000000..fd2f21c
--- /dev/null
+++ b/services/inputflinger/tests/DisplayTopologyGraph_test.cpp
@@ -0,0 +1,120 @@
+/*
+ * 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 <gtest/gtest.h>
+#include <input/DisplayTopologyGraph.h>
+
+#include <string>
+#include <string_view>
+#include <tuple>
+
+namespace android {
+
+namespace {
+
+constexpr ui::LogicalDisplayId DISPLAY_ID_1{1};
+constexpr ui::LogicalDisplayId DISPLAY_ID_2{2};
+constexpr int DENSITY_MEDIUM = 160;
+
+} // namespace
+
+using DisplayTopologyGraphTestFixtureParam =
+ std::tuple<std::string_view /*name*/, DisplayTopologyGraph, bool /*isValid*/>;
+
+class DisplayTopologyGraphTestFixture
+ : public testing::Test,
+ public testing::WithParamInterface<DisplayTopologyGraphTestFixtureParam> {};
+
+TEST_P(DisplayTopologyGraphTestFixture, DisplayTopologyGraphTest) {
+ const auto& [_, displayTopology, isValid] = GetParam();
+ EXPECT_EQ(isValid, displayTopology.isValid());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DisplayTopologyGraphTest, DisplayTopologyGraphTestFixture,
+ testing::Values(
+ std::make_tuple(
+ "InvalidPrimaryDisplay",
+ DisplayTopologyGraph{.primaryDisplayId = ui::LogicalDisplayId::INVALID,
+ .graph = {},
+ .displaysDensity = {}},
+ false),
+ std::make_tuple("PrimaryDisplayNotInGraph",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {},
+ .displaysDensity = {}},
+ false),
+ std::make_tuple("DisplayDensityMissing",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {{DISPLAY_ID_1, {}}},
+ .displaysDensity = {}},
+ false),
+ std::make_tuple("ValidSingleDisplayTopology",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {{DISPLAY_ID_1, {}}},
+ .displaysDensity = {{DISPLAY_ID_1,
+ DENSITY_MEDIUM}}},
+ true),
+ std::make_tuple(
+ "MissingReverseEdge",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {{DISPLAY_ID_1,
+ {{DISPLAY_ID_2,
+ DisplayTopologyPosition::TOP, 0}}}},
+ .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM},
+ {DISPLAY_ID_2, DENSITY_MEDIUM}}},
+ false),
+ std::make_tuple(
+ "IncorrectReverseEdgeDirection",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {{DISPLAY_ID_1,
+ {{DISPLAY_ID_2,
+ DisplayTopologyPosition::TOP, 0}}},
+ {DISPLAY_ID_2,
+ {{DISPLAY_ID_1,
+ DisplayTopologyPosition::TOP, 0}}}},
+ .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM},
+ {DISPLAY_ID_2, DENSITY_MEDIUM}}},
+ false),
+ std::make_tuple(
+ "IncorrectReverseEdgeOffset",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {{DISPLAY_ID_1,
+ {{DISPLAY_ID_2,
+ DisplayTopologyPosition::TOP, 10}}},
+ {DISPLAY_ID_2,
+ {{DISPLAY_ID_1,
+ DisplayTopologyPosition::BOTTOM, 20}}}},
+ .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM},
+ {DISPLAY_ID_2, DENSITY_MEDIUM}}},
+ false),
+ std::make_tuple(
+ "ValidMultiDisplayTopology",
+ DisplayTopologyGraph{.primaryDisplayId = DISPLAY_ID_1,
+ .graph = {{DISPLAY_ID_1,
+ {{DISPLAY_ID_2,
+ DisplayTopologyPosition::TOP, 10}}},
+ {DISPLAY_ID_2,
+ {{DISPLAY_ID_1,
+ DisplayTopologyPosition::BOTTOM, -10}}}},
+ .displaysDensity = {{DISPLAY_ID_1, DENSITY_MEDIUM},
+ {DISPLAY_ID_2, DENSITY_MEDIUM}}},
+ true)),
+ [](const testing::TestParamInfo<DisplayTopologyGraphTestFixtureParam>& p) {
+ return std::string{std::get<0>(p.param)};
+ });
+
+} // namespace android
diff --git a/services/inputflinger/tests/FakeInputDispatcherPolicy.cpp b/services/inputflinger/tests/FakeInputDispatcherPolicy.cpp
index c4257a8..dcb148f 100644
--- a/services/inputflinger/tests/FakeInputDispatcherPolicy.cpp
+++ b/services/inputflinger/tests/FakeInputDispatcherPolicy.cpp
@@ -198,10 +198,6 @@
ASSERT_EQ(token, *receivedToken);
}
-void FakeInputDispatcherPolicy::setInterceptKeyTimeout(std::chrono::milliseconds timeout) {
- mInterceptKeyTimeout = timeout;
-}
-
std::chrono::nanoseconds FakeInputDispatcherPolicy::getKeyWaitingForEventsTimeout() {
return 500ms;
}
@@ -210,8 +206,9 @@
mStaleEventTimeout = timeout;
}
-void FakeInputDispatcherPolicy::setConsumeKeyBeforeDispatching(bool consumeKeyBeforeDispatching) {
- mConsumeKeyBeforeDispatching = consumeKeyBeforeDispatching;
+void FakeInputDispatcherPolicy::setInterceptKeyBeforeDispatchingResult(
+ std::variant<nsecs_t, inputdispatcher::KeyEntry::InterceptKeyResult> result) {
+ mInterceptKeyBeforeDispatchingResult = result;
}
void FakeInputDispatcherPolicy::assertFocusedDisplayNotified(ui::LogicalDisplayId expectedDisplay) {
@@ -404,7 +401,9 @@
void FakeInputDispatcherPolicy::interceptKeyBeforeQueueing(const KeyEvent& inputEvent, uint32_t&) {
if (inputEvent.getAction() == AKEY_EVENT_ACTION_UP) {
// Clear intercept state when we handled the event.
- mInterceptKeyTimeout = 0ms;
+ if (std::holds_alternative<nsecs_t>(mInterceptKeyBeforeDispatchingResult)) {
+ mInterceptKeyBeforeDispatchingResult = nsecs_t(0);
+ }
}
}
@@ -414,17 +413,20 @@
std::variant<nsecs_t, inputdispatcher::KeyEntry::InterceptKeyResult>
FakeInputDispatcherPolicy::interceptKeyBeforeDispatching(const sp<IBinder>&, const KeyEvent&,
uint32_t) {
- if (mConsumeKeyBeforeDispatching) {
- return inputdispatcher::KeyEntry::InterceptKeyResult::SKIP;
+ if (std::holds_alternative<inputdispatcher::KeyEntry::InterceptKeyResult>(
+ mInterceptKeyBeforeDispatchingResult)) {
+ return mInterceptKeyBeforeDispatchingResult;
}
- nsecs_t delay = std::chrono::nanoseconds(mInterceptKeyTimeout).count();
+ nsecs_t delay =
+ std::chrono::nanoseconds(std::get<nsecs_t>(mInterceptKeyBeforeDispatchingResult))
+ .count();
if (delay == 0) {
return inputdispatcher::KeyEntry::InterceptKeyResult::CONTINUE;
}
// Clear intercept state so we could dispatch the event in next wake.
- mInterceptKeyTimeout = 0ms;
+ mInterceptKeyBeforeDispatchingResult = nsecs_t(0);
return delay;
}
diff --git a/services/inputflinger/tests/FakeInputDispatcherPolicy.h b/services/inputflinger/tests/FakeInputDispatcherPolicy.h
index c387eac..b151686 100644
--- a/services/inputflinger/tests/FakeInputDispatcherPolicy.h
+++ b/services/inputflinger/tests/FakeInputDispatcherPolicy.h
@@ -96,10 +96,6 @@
void assertDropTargetEquals(const InputDispatcherInterface& dispatcher,
const sp<IBinder>& targetToken);
void assertNotifyInputChannelBrokenWasCalled(const sp<IBinder>& token);
- /**
- * Set policy timeout. A value of zero means next key will not be intercepted.
- */
- void setInterceptKeyTimeout(std::chrono::milliseconds timeout);
std::chrono::nanoseconds getKeyWaitingForEventsTimeout() override;
void setStaleEventTimeout(std::chrono::nanoseconds timeout);
void assertUserActivityNotPoked();
@@ -116,7 +112,12 @@
void setUnhandledKeyHandler(std::function<std::optional<KeyEvent>(const KeyEvent&)> handler);
void assertUnhandledKeyReported(int32_t keycode);
void assertUnhandledKeyNotReported();
- void setConsumeKeyBeforeDispatching(bool consumeKeyBeforeDispatching);
+ /**
+ * Set policy timeout or the interception result.
+ * A timeout value of zero means next key will not be intercepted.
+ */
+ void setInterceptKeyBeforeDispatchingResult(
+ std::variant<nsecs_t, inputdispatcher::KeyEntry::InterceptKeyResult> result);
void assertFocusedDisplayNotified(ui::LogicalDisplayId expectedDisplay);
private:
@@ -145,11 +146,10 @@
std::condition_variable mNotifyUserActivity;
std::queue<UserActivityPokeEvent> mUserActivityPokeEvents;
- std::chrono::milliseconds mInterceptKeyTimeout = 0ms;
-
std::chrono::nanoseconds mStaleEventTimeout = 1000ms;
- bool mConsumeKeyBeforeDispatching = false;
+ std::variant<nsecs_t, inputdispatcher::KeyEntry::InterceptKeyResult>
+ mInterceptKeyBeforeDispatchingResult;
BlockingQueue<std::pair<int32_t /*deviceId*/, std::set<gui::Uid>>> mNotifiedInteractions;
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index 914f5ab..35310a5 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -42,8 +42,6 @@
namespace {
-const auto TOUCHPAD_PALM_REJECTION =
- ACONFIG_FLAG(input_flags, enable_touchpad_typing_palm_rejection);
const auto TOUCHPAD_PALM_REJECTION_V2 =
ACONFIG_FLAG(input_flags, enable_v2_touchpad_typing_palm_rejection);
@@ -1461,7 +1459,6 @@
}
TEST_F_WITH_FLAGS(GestureConverterTest, TapWithTapToClickDisabled,
- REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION),
REQUIRES_FLAGS_DISABLED(TOUCHPAD_PALM_REJECTION_V2)) {
nsecs_t currentTime = ARBITRARY_GESTURE_TIME;
@@ -1574,8 +1571,7 @@
ASSERT_THAT(args, Each(VariantWith<NotifyMotionArgs>(WithRelativeMotion(0.f, 0.f))));
}
-TEST_F_WITH_FLAGS(GestureConverterTest, ClickWithTapToClickDisabled,
- REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) {
+TEST_F(GestureConverterTest, ClickWithTapToClickDisabled) {
// Click should still produce button press/release events
mReader->getContext()->setPreventingTouchpadTaps(true);
@@ -1644,8 +1640,7 @@
ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps());
}
-TEST_F_WITH_FLAGS(GestureConverterTest, MoveEnablesTapToClick,
- REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) {
+TEST_F(GestureConverterTest, MoveEnablesTapToClick) {
// initially disable tap-to-click
mReader->getContext()->setPreventingTouchpadTaps(true);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 1778f6d..835b677 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -5491,7 +5491,8 @@
generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ui::LogicalDisplayId::DEFAULT);
const std::chrono::milliseconds interceptKeyTimeout = 50ms;
const nsecs_t injectTime = keyArgs.eventTime;
- mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout);
+ mFakePolicy->setInterceptKeyBeforeDispatchingResult(
+ std::chrono::nanoseconds(interceptKeyTimeout).count());
mDispatcher->notifyKey(keyArgs);
// The dispatching time should be always greater than or equal to intercept key timeout.
window->consumeKeyDown(ui::LogicalDisplayId::DEFAULT);
@@ -5519,7 +5520,7 @@
// Set a value that's significantly larger than the default consumption timeout. If the
// implementation is correct, the actual value doesn't matter; it won't slow down the test.
- mFakePolicy->setInterceptKeyTimeout(600ms);
+ mFakePolicy->setInterceptKeyBeforeDispatchingResult(std::chrono::nanoseconds(600ms).count());
mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ui::LogicalDisplayId::DEFAULT));
// Window should receive key event immediately when same key up.
window->consumeKeyUp(ui::LogicalDisplayId::DEFAULT);
@@ -7438,7 +7439,8 @@
window->consumeFocusEvent(true);
- mFakePolicy->setConsumeKeyBeforeDispatching(true);
+ mFakePolicy->setInterceptKeyBeforeDispatchingResult(
+ inputdispatcher::KeyEntry::InterceptKeyResult::SKIP);
mDispatcher->notifyKey(
KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
@@ -7464,7 +7466,8 @@
window->consumeFocusEvent(true);
- mFakePolicy->setConsumeKeyBeforeDispatching(true);
+ mFakePolicy->setInterceptKeyBeforeDispatchingResult(
+ inputdispatcher::KeyEntry::InterceptKeyResult::SKIP);
mDispatcher->notifyKey(
KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).keyCode(AKEYCODE_A).build());
@@ -9307,6 +9310,24 @@
mWindow->assertNoEvents();
}
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterFocusedWindowChanged) {
+ sp<FakeWindowHandle> anotherWindow =
+ sp<FakeWindowHandle>::make(mApp, mDispatcher, "AnotherWindow",
+ ui::LogicalDisplayId::DEFAULT);
+ anotherWindow->setFocusable(true);
+ mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *anotherWindow->getInfo()}, {}, 0, 0});
+
+ sendAndConsumeKeyDown(/*deviceId=*/1);
+ expectKeyRepeatOnce(/*repeatCount=*/1);
+ expectKeyRepeatOnce(/*repeatCount=*/2);
+ setFocusedWindow(anotherWindow);
+ anotherWindow->consumeFocusEvent(true);
+
+ // Window should receive key up event with cancel.
+ mWindow->consumeKeyUp(ui::LogicalDisplayId::DEFAULT, AKEY_EVENT_FLAG_CANCELED);
+ anotherWindow->assertNoEvents();
+}
+
TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
sendAndConsumeKeyDown(/*deviceId=*/1);
expectKeyRepeatOnce(/*repeatCount=*/1);
@@ -15403,4 +15424,47 @@
mWindowOnSecondDisplay->assertNoEvents();
}
+using InputDispatcherConnectedDisplayPointerInWindowTest = InputDispatcherConnectedDisplayTest;
+
+TEST_F(InputDispatcherConnectedDisplayPointerInWindowTest, MouseOnWindowOnPrimaryDisplay) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
+ .build());
+
+ mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+ mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+ mWindowOnSecondDisplay->assertNoEvents();
+
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(mWindow->getToken(), DISPLAY_ID, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(mSpyWindow->getToken(), DISPLAY_ID, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(mWindowOnSecondDisplay->getToken(),
+ SECOND_DISPLAY_ID, DEVICE_ID, /*pointerId=*/0));
+}
+
+TEST_F(InputDispatcherConnectedDisplayPointerInWindowTest, MouseOnWindowOnNonPrimaryDisplay) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
+ .displayId(SECOND_DISPLAY_ID)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
+ .build());
+
+ mWindow->assertNoEvents();
+ mSpyWindow->assertNoEvents();
+ mWindowOnSecondDisplay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(mWindow->getToken(), DISPLAY_ID, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(mSpyWindow->getToken(), DISPLAY_ID, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(mWindowOnSecondDisplay->getToken(),
+ SECOND_DISPLAY_ID, DEVICE_ID, /*pointerId=*/0));
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h
index 06d60ce..d4e4bb0 100644
--- a/services/inputflinger/tests/InterfaceMocks.h
+++ b/services/inputflinger/tests/InterfaceMocks.h
@@ -50,6 +50,8 @@
class MockInputReaderContext : public InputReaderContext {
public:
+ std::string dump() override { return "(dump from MockInputReaderContext)"; }
+
MOCK_METHOD(void, updateGlobalMetaState, (), (override));
MOCK_METHOD(int32_t, getGlobalMetaState, (), (override));
diff --git a/services/inputflinger/tests/KeyboardInputMapper_test.cpp b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
index 17acdd4..d4b15bc 100644
--- a/services/inputflinger/tests/KeyboardInputMapper_test.cpp
+++ b/services/inputflinger/tests/KeyboardInputMapper_test.cpp
@@ -176,16 +176,22 @@
return std::get<NotifyKeyArgs>(args.front());
}
- void testDPadKeyRotation(int32_t originalEvdevCode, int32_t originalKeyCode,
- int32_t rotatedKeyCode, ui::LogicalDisplayId displayId = DISPLAY_ID) {
- std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_KEY, originalEvdevCode, 1);
+ std::list<NotifyArgs> processKeyAndSync(nsecs_t when, int32_t code, int32_t value) {
+ std::list<NotifyArgs> argsList = process(when, EV_KEY, code, value);
+ argsList += process(when, EV_SYN, SYN_REPORT, 0);
+ return argsList;
+ }
+
+ void testDPadKeyRotation(int32_t originalEvdevCode, int32_t rotatedKeyCode,
+ ui::LogicalDisplayId displayId = DISPLAY_ID) {
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, originalEvdevCode, 1);
NotifyKeyArgs args = expectSingleKeyArg(argsList);
ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
ASSERT_EQ(originalEvdevCode, args.scanCode);
ASSERT_EQ(rotatedKeyCode, args.keyCode);
ASSERT_EQ(displayId, args.displayId);
- argsList = process(ARBITRARY_TIME, EV_KEY, originalEvdevCode, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME, originalEvdevCode, 0);
args = expectSingleKeyArg(argsList);
ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
ASSERT_EQ(originalEvdevCode, args.scanCode);
@@ -205,23 +211,16 @@
.With(Args<0>(when))
.Times(keyCodes.size());
for (int32_t keyCode : keyCodes) {
- process(when, EV_KEY, keyCode, 1);
- process(when, EV_SYN, SYN_REPORT, 0);
- process(when, EV_KEY, keyCode, 0);
- process(when, EV_SYN, SYN_REPORT, 0);
+ processKeyAndSync(when, keyCode, 1);
+ processKeyAndSync(when, keyCode, 0);
}
}
TEST_F(KeyboardInputMapperUnitTest, RepeatEventsDiscarded) {
std::list<NotifyArgs> args;
- args += process(ARBITRARY_TIME, EV_KEY, KEY_0, 1);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
-
- args += process(ARBITRARY_TIME, EV_KEY, KEY_0, 2);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
-
- args += process(ARBITRARY_TIME, EV_KEY, KEY_0, 0);
- args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+ args += processKeyAndSync(ARBITRARY_TIME, KEY_0, 1);
+ args += processKeyAndSync(ARBITRARY_TIME, KEY_0, 2);
+ args += processKeyAndSync(ARBITRARY_TIME, KEY_0, 0);
EXPECT_THAT(args,
ElementsAre(VariantWith<NotifyKeyArgs>(AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN),
@@ -241,7 +240,7 @@
ASSERT_EQ(AMETA_NONE, mMapper->getMetaState());
// Key down by evdev code.
- std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_KEY, KEY_HOME, 1);
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_HOME, 1);
NotifyKeyArgs args = expectSingleKeyArg(argsList);
ASSERT_EQ(DEVICE_ID, args.deviceId);
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
@@ -255,7 +254,7 @@
ASSERT_EQ(ARBITRARY_TIME, args.downTime);
// Key up by evdev code.
- argsList = process(ARBITRARY_TIME + 1, EV_KEY, KEY_HOME, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_HOME, 0);
args = expectSingleKeyArg(argsList);
ASSERT_EQ(DEVICE_ID, args.deviceId);
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
@@ -271,6 +270,7 @@
// Key down by usage code.
argsList = process(ARBITRARY_TIME, EV_MSC, MSC_SCAN, USAGE_A);
argsList += process(ARBITRARY_TIME, EV_KEY, 0, 1);
+ argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
args = expectSingleKeyArg(argsList);
ASSERT_EQ(DEVICE_ID, args.deviceId);
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
@@ -284,8 +284,9 @@
ASSERT_EQ(ARBITRARY_TIME, args.downTime);
// Key up by usage code.
- argsList = process(ARBITRARY_TIME, EV_MSC, MSC_SCAN, USAGE_A);
+ argsList = process(ARBITRARY_TIME + 1, EV_MSC, MSC_SCAN, USAGE_A);
argsList += process(ARBITRARY_TIME + 1, EV_KEY, 0, 0);
+ argsList += process(ARBITRARY_TIME + 1, EV_SYN, SYN_REPORT, 0);
args = expectSingleKeyArg(argsList);
ASSERT_EQ(DEVICE_ID, args.deviceId);
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
@@ -307,6 +308,7 @@
// Key down with unknown scan code or usage code.
std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_MSC, MSC_SCAN, USAGE_UNKNOWN);
argsList += process(ARBITRARY_TIME, EV_KEY, KEY_UNKNOWN, 1);
+ argsList += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
NotifyKeyArgs args = expectSingleKeyArg(argsList);
ASSERT_EQ(DEVICE_ID, args.deviceId);
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
@@ -320,8 +322,9 @@
ASSERT_EQ(ARBITRARY_TIME, args.downTime);
// Key up with unknown scan code or usage code.
- argsList = process(ARBITRARY_TIME, EV_MSC, MSC_SCAN, USAGE_UNKNOWN);
+ argsList = process(ARBITRARY_TIME + 1, EV_MSC, MSC_SCAN, USAGE_UNKNOWN);
argsList += process(ARBITRARY_TIME + 1, EV_KEY, KEY_UNKNOWN, 0);
+ argsList += process(ARBITRARY_TIME + 1, EV_SYN, SYN_REPORT, 0);
args = expectSingleKeyArg(argsList);
ASSERT_EQ(DEVICE_ID, args.deviceId);
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
@@ -343,10 +346,12 @@
// Key down
std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, /*readTime=*/12, EV_KEY, KEY_HOME, 1);
+ argsList += process(ARBITRARY_TIME, /*readTime=*/12, EV_SYN, SYN_REPORT, 0);
ASSERT_EQ(12, expectSingleKeyArg(argsList).readTime);
// Key up
- argsList = process(ARBITRARY_TIME, /*readTime=*/15, EV_KEY, KEY_HOME, 1);
+ argsList = process(ARBITRARY_TIME, /*readTime=*/15, EV_KEY, KEY_HOME, 0);
+ argsList += process(ARBITRARY_TIME, /*readTime=*/15, EV_SYN, SYN_REPORT, 0);
ASSERT_EQ(15, expectSingleKeyArg(argsList).readTime);
}
@@ -360,22 +365,22 @@
ASSERT_EQ(AMETA_NONE, mMapper->getMetaState());
// Metakey down.
- std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_KEY, KEY_LEFTSHIFT, 1);
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_LEFTSHIFT, 1);
ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, expectSingleKeyArg(argsList).metaState);
ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mMapper->getMetaState());
// Key down.
- argsList = process(ARBITRARY_TIME + 1, EV_KEY, KEY_A, 1);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_A, 1);
ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, expectSingleKeyArg(argsList).metaState);
ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mMapper->getMetaState());
// Key up.
- argsList = process(ARBITRARY_TIME + 2, EV_KEY, KEY_A, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 2, KEY_A, 0);
ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, expectSingleKeyArg(argsList).metaState);
ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mMapper->getMetaState());
// Metakey up.
- argsList = process(ARBITRARY_TIME + 3, EV_KEY, KEY_LEFTSHIFT, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 3, KEY_LEFTSHIFT, 0);
ASSERT_EQ(AMETA_NONE, expectSingleKeyArg(argsList).metaState);
ASSERT_EQ(AMETA_NONE, mMapper->getMetaState());
}
@@ -387,11 +392,10 @@
addKeyByEvdevCode(KEY_LEFT, AKEYCODE_DPAD_LEFT);
setDisplayOrientation(ui::Rotation::Rotation90);
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
- ASSERT_NO_FATAL_FAILURE(
- testDPadKeyRotation(KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_UP, AKEYCODE_DPAD_UP));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_RIGHT, AKEYCODE_DPAD_RIGHT));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_DOWN, AKEYCODE_DPAD_DOWN));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_LEFT, AKEYCODE_DPAD_LEFT));
}
TEST_F(KeyboardInputMapperUnitTest, Process_WhenOrientationAware_ShouldRotateDPad) {
@@ -405,43 +409,40 @@
AINPUT_SOURCE_KEYBOARD);
setDisplayOrientation(ui::ROTATION_0);
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
- ASSERT_NO_FATAL_FAILURE(
- testDPadKeyRotation(KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_UP, AKEYCODE_DPAD_UP));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_RIGHT, AKEYCODE_DPAD_RIGHT));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_DOWN, AKEYCODE_DPAD_DOWN));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_LEFT, AKEYCODE_DPAD_LEFT));
setDisplayOrientation(ui::ROTATION_90);
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_UP, AKEYCODE_DPAD_LEFT));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_RIGHT, AKEYCODE_DPAD_UP));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_DOWN, AKEYCODE_DPAD_RIGHT));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_LEFT, AKEYCODE_DPAD_DOWN));
setDisplayOrientation(ui::ROTATION_180);
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN));
- ASSERT_NO_FATAL_FAILURE(
- testDPadKeyRotation(KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_LEFT));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_UP));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_RIGHT));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_UP, AKEYCODE_DPAD_DOWN));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_RIGHT, AKEYCODE_DPAD_LEFT));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_DOWN, AKEYCODE_DPAD_UP));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_LEFT, AKEYCODE_DPAD_RIGHT));
setDisplayOrientation(ui::ROTATION_270);
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT));
- ASSERT_NO_FATAL_FAILURE(
- testDPadKeyRotation(KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_DOWN));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_LEFT));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_UP));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_UP, AKEYCODE_DPAD_RIGHT));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_RIGHT, AKEYCODE_DPAD_DOWN));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_DOWN, AKEYCODE_DPAD_LEFT));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(KEY_LEFT, AKEYCODE_DPAD_UP));
// Special case: if orientation changes while key is down, we still emit the same keycode
// in the key up as we did in the key down.
setDisplayOrientation(ui::ROTATION_270);
- std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_KEY, KEY_UP, 1);
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_UP, 1);
NotifyKeyArgs args = expectSingleKeyArg(argsList);
ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
ASSERT_EQ(KEY_UP, args.scanCode);
ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode);
setDisplayOrientation(ui::ROTATION_180);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_UP, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_UP, 0);
args = expectSingleKeyArg(argsList);
ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
ASSERT_EQ(KEY_UP, args.scanCode);
@@ -454,9 +455,9 @@
addKeyByEvdevCode(KEY_UP, AKEYCODE_DPAD_UP);
// Display id should be LogicalDisplayId::INVALID without any display configuration.
- std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_KEY, KEY_UP, 1);
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_UP, 1);
ASSERT_GT(argsList.size(), 0u);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_UP, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_UP, 0);
ASSERT_GT(argsList.size(), 0u);
ASSERT_EQ(ui::LogicalDisplayId::INVALID, std::get<NotifyKeyArgs>(argsList.front()).displayId);
}
@@ -474,9 +475,9 @@
// ^--- already checked by the previous test
setDisplayOrientation(ui::ROTATION_0);
- std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_KEY, KEY_UP, 1);
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_UP, 1);
ASSERT_GT(argsList.size(), 0u);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_UP, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_UP, 0);
ASSERT_GT(argsList.size(), 0u);
ASSERT_EQ(DISPLAY_ID, std::get<NotifyKeyArgs>(argsList.front()).displayId);
@@ -487,9 +488,9 @@
argsList = mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
InputReaderConfiguration::Change::DISPLAY_INFO);
ASSERT_EQ(0u, argsList.size());
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_UP, 1);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_UP, 1);
ASSERT_GT(argsList.size(), 0u);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_UP, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_UP, 0);
ASSERT_GT(argsList.size(), 0u);
ASSERT_EQ(newDisplayId, std::get<NotifyKeyArgs>(argsList.front()).displayId);
}
@@ -565,48 +566,48 @@
ASSERT_FALSE(scrollLockLed);
// Toggle caps lock on.
- std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 1);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_CAPSLOCK, 1);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_CAPSLOCK, 0);
ASSERT_TRUE(capsLockLed);
ASSERT_FALSE(numLockLed);
ASSERT_FALSE(scrollLockLed);
ASSERT_EQ(AMETA_CAPS_LOCK_ON, mMapper->getMetaState());
// Toggle num lock on.
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 1);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_NUMLOCK, 1);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_NUMLOCK, 0);
ASSERT_TRUE(capsLockLed);
ASSERT_TRUE(numLockLed);
ASSERT_FALSE(scrollLockLed);
ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mMapper->getMetaState());
// Toggle caps lock off.
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 1);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_CAPSLOCK, 1);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_CAPSLOCK, 0);
ASSERT_FALSE(capsLockLed);
ASSERT_TRUE(numLockLed);
ASSERT_FALSE(scrollLockLed);
ASSERT_EQ(AMETA_NUM_LOCK_ON, mMapper->getMetaState());
// Toggle scroll lock on.
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_SCROLLLOCK, 1);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_SCROLLLOCK, 0);
ASSERT_FALSE(capsLockLed);
ASSERT_TRUE(numLockLed);
ASSERT_TRUE(scrollLockLed);
ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mMapper->getMetaState());
// Toggle num lock off.
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 1);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_NUMLOCK, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_NUMLOCK, 1);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_NUMLOCK, 0);
ASSERT_FALSE(capsLockLed);
ASSERT_FALSE(numLockLed);
ASSERT_TRUE(scrollLockLed);
ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mMapper->getMetaState());
// Toggle scroll lock off.
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_SCROLLLOCK, 1);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_SCROLLLOCK, 0);
ASSERT_FALSE(capsLockLed);
ASSERT_FALSE(numLockLed);
ASSERT_FALSE(scrollLockLed);
@@ -618,8 +619,8 @@
addKeyByEvdevCode(KEY_HOME, AKEYCODE_HOME, POLICY_FLAG_WAKE);
addKeyByUsageCode(USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE);
- // Key down by scan code.
- std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_KEY, KEY_HOME, 1);
+ // Key down by evdev code.
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_HOME, 1);
NotifyKeyArgs args = expectSingleKeyArg(argsList);
ASSERT_EQ(DEVICE_ID, args.deviceId);
ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
@@ -685,37 +686,168 @@
addKeyByEvdevCode(KEY_LEFT, AKEYCODE_DPAD_LEFT, POLICY_FLAG_GESTURE);
// Key down
- std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_KEY, KEY_LEFT, 1);
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_LEFT, 1);
ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_KEEP_TOUCH_MODE,
expectSingleKeyArg(argsList).flags);
}
-TEST_F_WITH_FLAGS(KeyboardInputMapperUnitTest, WakeBehavior_AlphabeticKeyboard,
- REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
- enable_alphabetic_keyboard_wake))) {
- // For internal alphabetic devices, keys will trigger wake on key down.
+// --- KeyboardInputMapperUnitTest_WakeFlagOverride ---
+
+class KeyboardInputMapperUnitTest_WakeFlagOverride : public KeyboardInputMapperUnitTest {
+protected:
+ virtual void SetUp() override {
+ SetUp(/*wakeFlag=*/com::android::input::flags::enable_alphabetic_keyboard_wake());
+ }
+
+ void SetUp(bool wakeFlag) {
+ mWakeFlagInitialValue = com::android::input::flags::enable_alphabetic_keyboard_wake();
+ com::android::input::flags::enable_alphabetic_keyboard_wake(wakeFlag);
+ KeyboardInputMapperUnitTest::SetUp();
+ }
+
+ void TearDown() override {
+ com::android::input::flags::enable_alphabetic_keyboard_wake(mWakeFlagInitialValue);
+ KeyboardInputMapperUnitTest::TearDown();
+ }
+
+ bool mWakeFlagInitialValue;
+};
+
+// --- KeyboardInputMapperUnitTest_NonAlphabeticKeyboard_WakeFlagEnabled ---
+
+class KeyboardInputMapperUnitTest_NonAlphabeticKeyboard_WakeFlagEnabled
+ : public KeyboardInputMapperUnitTest_WakeFlagOverride {
+protected:
+ void SetUp() override {
+ KeyboardInputMapperUnitTest_WakeFlagOverride::SetUp(/*wakeFlag=*/true);
+ }
+};
+
+TEST_F(KeyboardInputMapperUnitTest_NonAlphabeticKeyboard_WakeFlagEnabled,
+ NonAlphabeticDevice_WakeBehavior) {
+ // For internal non-alphabetic devices keys will not trigger wake.
addKeyByEvdevCode(KEY_A, AKEYCODE_A);
addKeyByEvdevCode(KEY_HOME, AKEYCODE_HOME);
addKeyByEvdevCode(KEY_PLAYPAUSE, AKEYCODE_MEDIA_PLAY_PAUSE);
- std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_KEY, KEY_A, 1);
- ASSERT_EQ(POLICY_FLAG_WAKE, expectSingleKeyArg(argsList).policyFlags);
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_A, 1);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
- argsList = process(ARBITRARY_TIME + 1, EV_KEY, KEY_A, 0);
- ASSERT_EQ(uint32_t(0), expectSingleKeyArg(argsList).policyFlags);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_A, 0);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_HOME, 1);
- ASSERT_EQ(POLICY_FLAG_WAKE, expectSingleKeyArg(argsList).policyFlags);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_HOME, 1);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
- argsList = process(ARBITRARY_TIME + 1, EV_KEY, KEY_HOME, 0);
- ASSERT_EQ(uint32_t(0), expectSingleKeyArg(argsList).policyFlags);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_HOME, 0);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_PLAYPAUSE, 1);
- ASSERT_EQ(POLICY_FLAG_WAKE, expectSingleKeyArg(argsList).policyFlags);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_PLAYPAUSE, 1);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
- argsList = process(ARBITRARY_TIME + 1, EV_KEY, KEY_PLAYPAUSE, 0);
- ASSERT_EQ(uint32_t(0), expectSingleKeyArg(argsList).policyFlags);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_PLAYPAUSE, 0);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
+}
+
+// --- KeyboardInputMapperUnitTest_AlphabeticKeyboard_WakeFlagEnabled ---
+
+class KeyboardInputMapperUnitTest_AlphabeticKeyboard_WakeFlagEnabled
+ : public KeyboardInputMapperUnitTest_WakeFlagOverride {
+protected:
+ void SetUp() override {
+ KeyboardInputMapperUnitTest_WakeFlagOverride::SetUp(/*wakeFlag=*/true);
+
+ ON_CALL((*mDevice), getKeyboardType).WillByDefault(Return(KeyboardType::ALPHABETIC));
+ }
+};
+
+TEST_F(KeyboardInputMapperUnitTest_AlphabeticKeyboard_WakeFlagEnabled, WakeBehavior) {
+ // For internal alphabetic devices, keys will trigger wake on key down when
+ // flag is enabled.
+ addKeyByEvdevCode(KEY_A, AKEYCODE_A);
+ addKeyByEvdevCode(KEY_HOME, AKEYCODE_HOME);
+ addKeyByEvdevCode(KEY_PLAYPAUSE, AKEYCODE_MEDIA_PLAY_PAUSE);
+
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_A, 1);
+ EXPECT_THAT(argsList,
+ ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(POLICY_FLAG_WAKE))));
+
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_A, 0);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
+
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_HOME, 1);
+ EXPECT_THAT(argsList,
+ ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(POLICY_FLAG_WAKE))));
+
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_HOME, 0);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
+
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_PLAYPAUSE, 1);
+ EXPECT_THAT(argsList,
+ ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(POLICY_FLAG_WAKE))));
+
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_PLAYPAUSE, 0);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
+}
+
+TEST_F(KeyboardInputMapperUnitTest_AlphabeticKeyboard_WakeFlagEnabled, WakeBehavior_UnknownKey) {
+ // For internal alphabetic devices, unknown keys will trigger wake on key down when
+ // flag is enabled.
+
+ const int32_t USAGE_UNKNOWN = 0x07ffff;
+ EXPECT_CALL(mMockEventHub, mapKey(EVENTHUB_ID, KEY_UNKNOWN, USAGE_UNKNOWN, _, _, _, _))
+ .WillRepeatedly(Return(NAME_NOT_FOUND));
+
+ // Key down with unknown scan code or usage code.
+ std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_MSC, MSC_SCAN, USAGE_UNKNOWN);
+ argsList += process(ARBITRARY_TIME, EV_KEY, KEY_UNKNOWN, 1);
+ EXPECT_THAT(argsList,
+ ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(POLICY_FLAG_WAKE))));
+
+ // Key up with unknown scan code or usage code.
+ argsList = process(ARBITRARY_TIME, EV_MSC, MSC_SCAN, USAGE_UNKNOWN);
+ argsList += process(ARBITRARY_TIME + 1, EV_KEY, KEY_UNKNOWN, 0);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
+}
+
+// --- KeyboardInputMapperUnitTest_AlphabeticDevice_AlphabeticKeyboardWakeDisabled ---
+
+class KeyboardInputMapperUnitTest_AlphabeticKeyboard_WakeFlagDisabled
+ : public KeyboardInputMapperUnitTest_WakeFlagOverride {
+protected:
+ void SetUp() override {
+ KeyboardInputMapperUnitTest_WakeFlagOverride::SetUp(/*wakeFlag=*/false);
+
+ ON_CALL((*mDevice), getKeyboardType).WillByDefault(Return(KeyboardType::ALPHABETIC));
+ }
+};
+
+TEST_F(KeyboardInputMapperUnitTest_AlphabeticKeyboard_WakeFlagDisabled, WakeBehavior) {
+ // For internal alphabetic devices, keys will not trigger wake when flag is
+ // disabled.
+
+ addKeyByEvdevCode(KEY_A, AKEYCODE_A);
+ addKeyByEvdevCode(KEY_HOME, AKEYCODE_HOME);
+ addKeyByEvdevCode(KEY_PLAYPAUSE, AKEYCODE_MEDIA_PLAY_PAUSE);
+
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_A, 1);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
+
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_A, 0);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
+
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_HOME, 1);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
+
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_HOME, 0);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
+
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_PLAYPAUSE, 1);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
+
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_PLAYPAUSE, 0);
+ EXPECT_THAT(argsList, ElementsAre(VariantWith<NotifyKeyArgs>(WithPolicyFlags(0U))));
}
// --- KeyboardInputMapperTest ---
@@ -730,28 +862,33 @@
}
const std::string UNIQUE_ID = "local:0";
- void testDPadKeyRotation(KeyboardInputMapper& mapper, int32_t originalScanCode,
- int32_t originalKeyCode, int32_t rotatedKeyCode,
+ void testDPadKeyRotation(KeyboardInputMapper& mapper, int32_t originalEvdevCode,
+ int32_t rotatedKeyCode,
ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID);
+
+ void processKeyAndSync(InputMapper& mapper, nsecs_t when, nsecs_t readTime, int32_t code,
+ int32_t value) {
+ process(mapper, when, readTime, EV_KEY, code, value);
+ process(mapper, when, readTime, EV_SYN, SYN_REPORT, 0);
+ }
};
void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper& mapper,
- int32_t originalScanCode, int32_t originalKeyCode,
- int32_t rotatedKeyCode,
+ int32_t originalEvdevCode, int32_t rotatedKeyCode,
ui::LogicalDisplayId displayId) {
NotifyKeyArgs args;
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, originalScanCode, 1);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, originalEvdevCode, 1);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
- ASSERT_EQ(originalScanCode, args.scanCode);
+ ASSERT_EQ(originalEvdevCode, args.scanCode);
ASSERT_EQ(rotatedKeyCode, args.keyCode);
ASSERT_EQ(displayId, args.displayId);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, originalScanCode, 0);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, originalEvdevCode, 0);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
- ASSERT_EQ(originalScanCode, args.scanCode);
+ ASSERT_EQ(originalEvdevCode, args.scanCode);
ASSERT_EQ(rotatedKeyCode, args.keyCode);
ASSERT_EQ(displayId, args.displayId);
}
@@ -819,23 +956,19 @@
ASSERT_TRUE(device2->isEnabled());
// Test pad key events
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, DISPLAY_ID));
ASSERT_NO_FATAL_FAILURE(
- testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, DISPLAY_ID));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
- AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
- AKEYCODE_DPAD_DOWN, DISPLAY_ID));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
- AKEYCODE_DPAD_LEFT, DISPLAY_ID));
+ testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_UP, AKEYCODE_DPAD_UP, newDisplayId));
ASSERT_NO_FATAL_FAILURE(
- testDPadKeyRotation(mapper2, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, newDisplayId));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
- AKEYCODE_DPAD_RIGHT, newDisplayId));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_DOWN, AKEYCODE_DPAD_DOWN,
- AKEYCODE_DPAD_DOWN, newDisplayId));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_LEFT, AKEYCODE_DPAD_LEFT,
- AKEYCODE_DPAD_LEFT, newDisplayId));
+ testDPadKeyRotation(mapper2, KEY_RIGHT, AKEYCODE_DPAD_RIGHT, newDisplayId));
+ ASSERT_NO_FATAL_FAILURE(
+ testDPadKeyRotation(mapper2, KEY_DOWN, AKEYCODE_DPAD_DOWN, newDisplayId));
+ ASSERT_NO_FATAL_FAILURE(
+ testDPadKeyRotation(mapper2, KEY_LEFT, AKEYCODE_DPAD_LEFT, newDisplayId));
}
TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleAfterReattach) {
@@ -857,20 +990,20 @@
ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
// Toggle caps lock on.
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, KEY_CAPSLOCK, 1);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, KEY_CAPSLOCK, 0);
ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper.getMetaState());
// Toggle num lock on.
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, KEY_NUMLOCK, 1);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, KEY_NUMLOCK, 0);
ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper.getMetaState());
// Toggle scroll lock on.
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, KEY_SCROLLLOCK, 1);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, KEY_SCROLLLOCK, 0);
ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper.getMetaState());
@@ -937,16 +1070,16 @@
ASSERT_EQ(AMETA_NONE, mapper.getMetaState());
// Toggle caps lock on.
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, KEY_CAPSLOCK, 1);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, KEY_CAPSLOCK, 0);
// Toggle num lock on.
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, KEY_NUMLOCK, 1);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, KEY_NUMLOCK, 0);
// Toggle scroll lock on.
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, KEY_SCROLLLOCK, 1);
+ processKeyAndSync(mapper, ARBITRARY_TIME, READ_TIME, KEY_SCROLLLOCK, 0);
ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper.getMetaState());
mReader->resetLockedModifierState();
@@ -996,40 +1129,40 @@
ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
// Toggle num lock on and off.
- process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
- process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
+ processKeyAndSync(mapper1, ARBITRARY_TIME, READ_TIME, KEY_NUMLOCK, 1);
+ processKeyAndSync(mapper1, ARBITRARY_TIME, READ_TIME, KEY_NUMLOCK, 0);
ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper1.getMetaState());
ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper2.getMetaState());
- process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 1);
- process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_NUMLOCK, 0);
+ processKeyAndSync(mapper1, ARBITRARY_TIME, READ_TIME, KEY_NUMLOCK, 1);
+ processKeyAndSync(mapper1, ARBITRARY_TIME, READ_TIME, KEY_NUMLOCK, 0);
ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_NUML));
ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
// Toggle caps lock on and off.
- process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
- process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+ processKeyAndSync(mapper1, ARBITRARY_TIME, READ_TIME, KEY_CAPSLOCK, 1);
+ processKeyAndSync(mapper1, ARBITRARY_TIME, READ_TIME, KEY_CAPSLOCK, 0);
ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper1.getMetaState());
ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper2.getMetaState());
- process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 1);
- process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_CAPSLOCK, 0);
+ processKeyAndSync(mapper1, ARBITRARY_TIME, READ_TIME, KEY_CAPSLOCK, 1);
+ processKeyAndSync(mapper1, ARBITRARY_TIME, READ_TIME, KEY_CAPSLOCK, 0);
ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_CAPSL));
ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
// Toggle scroll lock on and off.
- process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
- process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+ processKeyAndSync(mapper1, ARBITRARY_TIME, READ_TIME, KEY_SCROLLLOCK, 1);
+ processKeyAndSync(mapper1, ARBITRARY_TIME, READ_TIME, KEY_SCROLLLOCK, 0);
ASSERT_TRUE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper1.getMetaState());
ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper2.getMetaState());
- process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 1);
- process(mapper1, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_SCROLLLOCK, 0);
+ processKeyAndSync(mapper1, ARBITRARY_TIME, READ_TIME, KEY_SCROLLLOCK, 1);
+ processKeyAndSync(mapper1, ARBITRARY_TIME, READ_TIME, KEY_SCROLLLOCK, 0);
ASSERT_FALSE(mFakeEventHub->getLedState(EVENTHUB_ID, LED_SCROLLL));
ASSERT_EQ(AMETA_NONE, mapper1.getMetaState());
ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
@@ -1048,10 +1181,10 @@
KeyboardInputMapper& keyboardMapper =
constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD);
- process(keyboardMapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 1);
+ processKeyAndSync(keyboardMapper, ARBITRARY_TIME, 0, KEY_HOME, 1);
ASSERT_NO_FATAL_FAILURE(
mFakeListener->assertNotifyKeyWasCalled(WithSource(AINPUT_SOURCE_KEYBOARD)));
- process(keyboardMapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 0);
+ processKeyAndSync(keyboardMapper, ARBITRARY_TIME, 0, KEY_HOME, 0);
ASSERT_NO_FATAL_FAILURE(
mFakeListener->assertNotifyKeyWasCalled(WithSource(AINPUT_SOURCE_KEYBOARD)));
@@ -1059,10 +1192,10 @@
KeyboardInputMapper& dpadMapper =
constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_DPAD);
for (auto* mapper : {&keyboardMapper, &dpadMapper}) {
- process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 1);
+ processKeyAndSync(*mapper, ARBITRARY_TIME, 0, KEY_HOME, 1);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD)));
- process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 0);
+ processKeyAndSync(*mapper, ARBITRARY_TIME, 0, KEY_HOME, 0);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD)));
}
@@ -1071,10 +1204,10 @@
KeyboardInputMapper& gamepadMapper =
constructAndAddMapper<KeyboardInputMapper>(AINPUT_SOURCE_GAMEPAD);
for (auto* mapper : {&keyboardMapper, &dpadMapper, &gamepadMapper}) {
- process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 1);
+ processKeyAndSync(*mapper, ARBITRARY_TIME, 0, KEY_HOME, 1);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD | AINPUT_SOURCE_GAMEPAD)));
- process(*mapper, ARBITRARY_TIME, 0, EV_KEY, KEY_HOME, 0);
+ processKeyAndSync(*mapper, ARBITRARY_TIME, 0, KEY_HOME, 0);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(
WithSource(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD | AINPUT_SOURCE_GAMEPAD)));
}
@@ -1119,22 +1252,22 @@
addKeyByEvdevCode(KEY_PLAY, AKEYCODE_MEDIA_PLAY);
addKeyByEvdevCode(KEY_PLAYPAUSE, AKEYCODE_MEDIA_PLAY_PAUSE, POLICY_FLAG_WAKE);
- std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_KEY, KEY_HOME, 1);
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_HOME, 1);
ASSERT_EQ(POLICY_FLAG_WAKE, expectSingleKeyArg(argsList).policyFlags);
- argsList = process(ARBITRARY_TIME + 1, EV_KEY, KEY_HOME, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_HOME, 0);
ASSERT_EQ(uint32_t(0), expectSingleKeyArg(argsList).policyFlags);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_PLAY, 1);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_PLAY, 1);
ASSERT_EQ(POLICY_FLAG_WAKE, expectSingleKeyArg(argsList).policyFlags);
- argsList = process(ARBITRARY_TIME + 1, EV_KEY, KEY_PLAY, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_PLAY, 0);
ASSERT_EQ(uint32_t(0), expectSingleKeyArg(argsList).policyFlags);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_PLAYPAUSE, 1);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_PLAYPAUSE, 1);
ASSERT_EQ(POLICY_FLAG_WAKE, expectSingleKeyArg(argsList).policyFlags);
- argsList = process(ARBITRARY_TIME + 1, EV_KEY, KEY_PLAYPAUSE, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_PLAYPAUSE, 0);
ASSERT_EQ(POLICY_FLAG_WAKE, expectSingleKeyArg(argsList).policyFlags);
}
@@ -1145,16 +1278,16 @@
addKeyByEvdevCode(KEY_PLAY, AKEYCODE_MEDIA_PLAY);
addKeyByEvdevCode(KEY_PLAYPAUSE, AKEYCODE_MEDIA_PLAY_PAUSE, POLICY_FLAG_WAKE);
- std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_KEY, KEY_PLAY, 1);
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_PLAY, 1);
ASSERT_EQ(uint32_t(0), expectSingleKeyArg(argsList).policyFlags);
- argsList = process(ARBITRARY_TIME + 1, EV_KEY, KEY_PLAY, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_PLAY, 0);
ASSERT_EQ(uint32_t(0), expectSingleKeyArg(argsList).policyFlags);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_PLAYPAUSE, 1);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_PLAYPAUSE, 1);
ASSERT_EQ(POLICY_FLAG_WAKE, expectSingleKeyArg(argsList).policyFlags);
- argsList = process(ARBITRARY_TIME + 1, EV_KEY, KEY_PLAYPAUSE, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_PLAYPAUSE, 0);
ASSERT_EQ(POLICY_FLAG_WAKE, expectSingleKeyArg(argsList).policyFlags);
}
@@ -1169,22 +1302,22 @@
mMapper = createInputMapper<KeyboardInputMapper>(*mDeviceContext, mReaderConfiguration,
AINPUT_SOURCE_KEYBOARD);
- std::list<NotifyArgs> argsList = process(ARBITRARY_TIME, EV_KEY, KEY_HOME, 1);
+ std::list<NotifyArgs> argsList = processKeyAndSync(ARBITRARY_TIME, KEY_HOME, 1);
ASSERT_EQ(POLICY_FLAG_WAKE, expectSingleKeyArg(argsList).policyFlags);
- argsList = process(ARBITRARY_TIME + 1, EV_KEY, KEY_HOME, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_HOME, 0);
ASSERT_EQ(POLICY_FLAG_WAKE, expectSingleKeyArg(argsList).policyFlags);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_DOWN, 1);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_DOWN, 1);
ASSERT_EQ(uint32_t(0), expectSingleKeyArg(argsList).policyFlags);
- argsList = process(ARBITRARY_TIME + 1, EV_KEY, KEY_DOWN, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_DOWN, 0);
ASSERT_EQ(uint32_t(0), expectSingleKeyArg(argsList).policyFlags);
- argsList = process(ARBITRARY_TIME, EV_KEY, KEY_PLAY, 1);
+ argsList = processKeyAndSync(ARBITRARY_TIME, KEY_PLAY, 1);
ASSERT_EQ(POLICY_FLAG_WAKE, expectSingleKeyArg(argsList).policyFlags);
- argsList = process(ARBITRARY_TIME + 1, EV_KEY, KEY_PLAY, 0);
+ argsList = processKeyAndSync(ARBITRARY_TIME + 1, KEY_PLAY, 0);
ASSERT_EQ(POLICY_FLAG_WAKE, expectSingleKeyArg(argsList).policyFlags);
}
diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp
index 99db8fe..2b469c5 100644
--- a/services/inputflinger/tests/PointerChoreographer_test.cpp
+++ b/services/inputflinger/tests/PointerChoreographer_test.cpp
@@ -24,6 +24,7 @@
#include "FakePointerController.h"
#include "InterfaceMocks.h"
#include "NotifyArgsBuilders.h"
+#include "ScopedFlagOverride.h"
#include "TestEventMatchers.h"
#include "TestInputListener.h"
@@ -114,6 +115,10 @@
}) {}
class PointerChoreographerTest : public testing::Test {
+public:
+ static constexpr int DENSITY_MEDIUM = 160;
+ static constexpr int DENSITY_HIGH = 320;
+
protected:
TestInputListener mTestListener;
sp<gui::WindowInfosListener> mRegisteredWindowInfoListener;
@@ -124,9 +129,6 @@
mInjectedInitialWindowInfos};
void SetUp() override {
- // flag overrides
- input_flags::hide_pointer_indicators_for_secure_windows(true);
-
ON_CALL(mMockPolicy, createPointerController).WillByDefault([this](ControllerType type) {
std::shared_ptr<FakePointerController> pc = std::make_shared<FakePointerController>();
EXPECT_FALSE(pc->isPointerShown());
@@ -140,6 +142,22 @@
});
}
+ void setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) {
+ if (input_flags::connected_displays_cursor()) {
+ // setDefaultMouseDisplayId is no-op if connected displays are enabled, mouse display is
+ // set based on primary display of the topology.
+ // Setting topology with the primary display should have same effect as calling
+ // setDefaultMouseDisplayId without topology.
+ // For this reason in tests we mock this behavior by creating topology with a single
+ // display.
+ mChoreographer.setDisplayTopology({.primaryDisplayId = displayId,
+ .graph{{displayId, {}}},
+ .displaysDensity = {{displayId, DENSITY_MEDIUM}}});
+ } else {
+ mChoreographer.setDefaultMouseDisplayId(displayId);
+ }
+ }
+
std::shared_ptr<FakePointerController> assertPointerControllerCreated(
ControllerType expectedType) {
EXPECT_FALSE(mCreatedControllers.empty()) << "No PointerController was created";
@@ -292,7 +310,7 @@
TEST_F(PointerChoreographerTest, SetsDefaultMouseViewportForPointerController) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// For a mouse event without a target display, default viewport should be set for
// the PointerController.
@@ -309,7 +327,7 @@
WhenDefaultMouseDisplayChangesSetsDefaultMouseViewportForPointerController) {
// Set one display as a default mouse display and emit mouse event to create PointerController.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -320,7 +338,7 @@
// Change default mouse display. Existing PointerController should be removed and a new one
// should be created.
- mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
+ setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
assertPointerControllerRemoved(firstDisplayPc);
auto secondDisplayPc = assertPointerControllerCreated(ControllerType::MOUSE);
@@ -329,7 +347,7 @@
}
TEST_F(PointerChoreographerTest, CallsNotifyPointerDisplayIdChanged) {
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
@@ -340,8 +358,19 @@
assertPointerDisplayIdNotified(DISPLAY_ID);
}
+TEST_F(PointerChoreographerTest, NoDefaultMouseSetFallbackToDefaultDisplayId) {
+ mChoreographer.setDisplayViewports(createViewports({ui::LogicalDisplayId::DEFAULT}));
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
+ ui::LogicalDisplayId::INVALID)}});
+ assertPointerControllerCreated(ControllerType::MOUSE);
+
+ assertPointerDisplayIdNotified(ui::LogicalDisplayId::DEFAULT);
+}
+
TEST_F(PointerChoreographerTest, WhenViewportIsSetLaterCallsNotifyPointerDisplayIdChanged) {
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -354,7 +383,7 @@
}
TEST_F(PointerChoreographerTest, WhenMouseIsRemovedCallsNotifyPointerDisplayIdChanged) {
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
@@ -373,7 +402,7 @@
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
// Set one viewport as a default mouse display ID.
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -382,7 +411,7 @@
assertPointerDisplayIdNotified(DISPLAY_ID);
// Set another viewport as a default mouse display ID. The mouse is moved to the other display.
- mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
+ setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
assertPointerControllerRemoved(firstDisplayPc);
assertPointerControllerCreated(ControllerType::MOUSE);
@@ -391,7 +420,7 @@
TEST_F(PointerChoreographerTest, MouseMovesPointerAndReturnsNewArgs) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -421,7 +450,7 @@
TEST_F(PointerChoreographerTest, AbsoluteMouseMovesPointerAndReturnsNewArgs) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -457,7 +486,7 @@
AssociatedMouseMovesPointerOnAssociatedDisplayAndDoesNotMovePointerOnDefaultDisplay) {
// Add two displays and set one to default.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// Add two devices, one unassociated and the other associated with non-default mouse display.
mChoreographer.notifyInputDevicesChanged(
@@ -496,7 +525,7 @@
TEST_F(PointerChoreographerTest, DoesNotMovePointerForMouseRelativeSource) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -543,7 +572,7 @@
TEST_F(PointerChoreographerTest, WhenPointerCaptureEnabledHidesPointer) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -562,7 +591,7 @@
TEST_F(PointerChoreographerTest, MultipleMiceConnectionAndRemoval) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// A mouse is connected, and the pointer is shown.
mChoreographer.notifyInputDevicesChanged(
@@ -599,7 +628,7 @@
TEST_F(PointerChoreographerTest, UnrelatedChangeDoesNotUnfadePointer) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -628,7 +657,7 @@
TEST_F(PointerChoreographerTest, DisabledMouseConnected) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
InputDeviceInfo mouseDeviceInfo =
generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID);
// Disable this mouse device.
@@ -641,7 +670,7 @@
TEST_F(PointerChoreographerTest, MouseDeviceDisableLater) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
InputDeviceInfo mouseDeviceInfo =
generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID);
@@ -660,7 +689,7 @@
TEST_F(PointerChoreographerTest, MultipleEnabledAndDisabledMiceConnectionAndRemoval) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
InputDeviceInfo disabledMouseDeviceInfo =
generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID);
disabledMouseDeviceInfo.setEnabled(false);
@@ -1011,7 +1040,7 @@
TEST_F(PointerChoreographerTest, StylusHoverEnterFadesMouseOnDisplay) {
// Make sure there are PointerControllers for a mouse and a stylus.
mChoreographer.setStylusPointerIconEnabled(true);
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
@@ -1406,7 +1435,7 @@
TEST_F(PointerChoreographerTest, SetsDefaultTouchpadViewportForPointerController) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// For a touchpad event without a target display, default viewport should be set for
// the PointerController.
@@ -1422,7 +1451,7 @@
WhenDefaultTouchpadDisplayChangesSetsDefaultTouchpadViewportForPointerController) {
// Set one display as a default touchpad display and create PointerController.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1431,7 +1460,7 @@
firstDisplayPc->assertViewportSet(DISPLAY_ID);
// Change default mouse display. Existing PointerController should be removed.
- mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
+ setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
assertPointerControllerRemoved(firstDisplayPc);
auto secondDisplayPc = assertPointerControllerCreated(ControllerType::MOUSE);
@@ -1439,7 +1468,7 @@
}
TEST_F(PointerChoreographerTest, TouchpadCallsNotifyPointerDisplayIdChanged) {
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
@@ -1451,7 +1480,7 @@
}
TEST_F(PointerChoreographerTest, WhenViewportIsSetLaterTouchpadCallsNotifyPointerDisplayIdChanged) {
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1464,7 +1493,7 @@
}
TEST_F(PointerChoreographerTest, WhenTouchpadIsRemovedCallsNotifyPointerDisplayIdChanged) {
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
@@ -1484,7 +1513,7 @@
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
// Set one viewport as a default mouse display ID.
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1494,7 +1523,7 @@
// Set another viewport as a default mouse display ID. ui::LogicalDisplayId::INVALID will be
// notified before a touchpad event.
- mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
+ setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
assertPointerControllerRemoved(firstDisplayPc);
assertPointerControllerCreated(ControllerType::MOUSE);
@@ -1503,7 +1532,7 @@
TEST_F(PointerChoreographerTest, TouchpadMovesPointerAndReturnsNewArgs) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1533,7 +1562,7 @@
TEST_F(PointerChoreographerTest, TouchpadAddsPointerPositionToTheCoords) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1610,7 +1639,7 @@
AssociatedTouchpadMovesPointerOnAssociatedDisplayAndDoesNotMovePointerOnDefaultDisplay) {
// Add two displays and set one to default.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// Add two devices, one unassociated and the other associated with non-default mouse display.
mChoreographer.notifyInputDevicesChanged(
@@ -1651,7 +1680,7 @@
TEST_F(PointerChoreographerTest, DoesNotMovePointerForTouchpadSource) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1688,7 +1717,7 @@
TEST_F(PointerChoreographerTest, WhenPointerCaptureEnabledTouchpadHidesPointer) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1708,7 +1737,7 @@
TEST_F(PointerChoreographerTest, SetsPointerIconForMouse) {
// Make sure there is a PointerController.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -1724,7 +1753,7 @@
TEST_F(PointerChoreographerTest, DoesNotSetMousePointerIconForWrongDisplayId) {
// Make sure there is a PointerController.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -1741,7 +1770,7 @@
TEST_F(PointerChoreographerTest, DoesNotSetPointerIconForWrongDeviceId) {
// Make sure there is a PointerController.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -1758,7 +1787,7 @@
TEST_F(PointerChoreographerTest, SetsCustomPointerIconForMouse) {
// Make sure there is a PointerController.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -1782,7 +1811,7 @@
TEST_F(PointerChoreographerTest, SetsPointerIconForMouseOnTwoDisplays) {
// Make sure there are two PointerControllers on different displays.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
@@ -1806,7 +1835,7 @@
TEST_F(PointerChoreographerTest, A11yPointerMotionFilterMouse) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -1840,7 +1869,7 @@
TEST_F(PointerChoreographerTest, A11yPointerMotionFilterTouchpad) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -2077,10 +2106,7 @@
pc->assertSkipScreenshotFlagNotChanged();
}
-TEST_F_WITH_FLAGS(
- PointerChoreographerTest, HidesPointerScreenshotForExistingPrivacySensitiveWindows,
- REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
- hide_pointer_indicators_for_secure_windows))) {
+TEST_F(PointerChoreographerTest, HidesPointerScreenshotForExistingPrivacySensitiveWindows) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
// Add a first mouse device
@@ -2238,7 +2264,7 @@
// Make sure there are PointerControllers for a mouse and a stylus.
mChoreographer.setStylusPointerIconEnabled(true);
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
@@ -2273,7 +2299,7 @@
TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerOnDisplay) {
// Make sure there are two PointerControllers on different displays.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
@@ -2327,7 +2353,7 @@
TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerWhenDeviceConnected) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// Hide the pointer on the display, and then connect the mouse.
mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
@@ -2344,7 +2370,7 @@
TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForTouchpad) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// Hide the pointer on the display.
mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
@@ -2393,7 +2419,7 @@
TEST_F(PointerChoreographerTest, DrawingTabletCanReportMouseEvent) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
@@ -2420,7 +2446,7 @@
TEST_F(PointerChoreographerTest, MultipleDrawingTabletsReportMouseEvents) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// First drawing tablet is added
mChoreographer.notifyInputDevicesChanged(
@@ -2468,7 +2494,7 @@
TEST_F(PointerChoreographerTest, MouseAndDrawingTabletReportMouseEvents) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// Mouse and drawing tablet connected
mChoreographer.notifyInputDevicesChanged(
@@ -2712,15 +2738,29 @@
metaKeyCombinationDoesNotHidePointer(*pc, AKEYCODE_A, AKEYCODE_META_RIGHT);
}
-using PointerChoreographerDisplayTopologyTestFixtureParam =
+class PointerChoreographerDisplayTopologyTests : public PointerChoreographerTest {
+protected:
+ DisplayViewport createViewport(ui::LogicalDisplayId displayId, int32_t width, int32_t height,
+ ui::Rotation orientation) {
+ DisplayViewport viewport;
+ viewport.displayId = displayId;
+ viewport.logicalRight = width;
+ viewport.logicalBottom = height;
+ viewport.orientation = orientation;
+ return viewport;
+ }
+};
+
+using PointerChoreographerDisplayTopologyCursorTestFixtureParam =
std::tuple<std::string_view /*name*/, int32_t /*source device*/,
ControllerType /*PointerController*/, ToolType /*pointer tool type*/,
vec2 /*source position*/, vec2 /*hover move X/Y*/,
ui::LogicalDisplayId /*destination display*/, vec2 /*destination position*/>;
-class PointerChoreographerDisplayTopologyTestFixture
- : public PointerChoreographerTest,
- public testing::WithParamInterface<PointerChoreographerDisplayTopologyTestFixtureParam> {
+class PointerChoreographerDisplayTopologyCursorTestFixture
+ : public PointerChoreographerDisplayTopologyTests,
+ public testing::WithParamInterface<
+ PointerChoreographerDisplayTopologyCursorTestFixtureParam> {
public:
static constexpr ui::LogicalDisplayId DISPLAY_CENTER_ID = ui::LogicalDisplayId{10};
static constexpr ui::LogicalDisplayId DISPLAY_TOP_ID = ui::LogicalDisplayId{20};
@@ -2730,13 +2770,6 @@
static constexpr ui::LogicalDisplayId DISPLAY_TOP_RIGHT_CORNER_ID = ui::LogicalDisplayId{60};
static constexpr ui::LogicalDisplayId DISPLAY_HIGH_DENSITY_ID = ui::LogicalDisplayId{70};
- static constexpr int DENSITY_MEDIUM = 160;
- static constexpr int DENSITY_HIGH = 320;
-
- PointerChoreographerDisplayTopologyTestFixture() {
- com::android::input::flags::connected_displays_cursor(true);
- }
-
protected:
// Note: viewport size is in pixels and offsets in topology are in dp
std::vector<DisplayViewport> mViewports{
@@ -2769,34 +2802,24 @@
{DISPLAY_LEFT_ID, DENSITY_MEDIUM},
{DISPLAY_TOP_RIGHT_CORNER_ID, DENSITY_MEDIUM},
{DISPLAY_HIGH_DENSITY_ID, DENSITY_HIGH}}};
-
-private:
- DisplayViewport createViewport(ui::LogicalDisplayId displayId, int32_t width, int32_t height,
- ui::Rotation orientation) {
- DisplayViewport viewport;
- viewport.displayId = displayId;
- viewport.logicalRight = width;
- viewport.logicalBottom = height;
- viewport.orientation = orientation;
- return viewport;
- }
};
-TEST_P(PointerChoreographerDisplayTopologyTestFixture, PointerChoreographerDisplayTopologyTest) {
+TEST_P(PointerChoreographerDisplayTopologyCursorTestFixture,
+ PointerChoreographerDisplayTopologyTest) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+
const auto& [_, device, pointerControllerType, pointerToolType, initialPosition, hoverMove,
destinationDisplay, destinationPosition] = GetParam();
mChoreographer.setDisplayViewports(mViewports);
- mChoreographer.setDefaultMouseDisplayId(
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID);
+ setDefaultMouseDisplayId(DISPLAY_CENTER_ID);
mChoreographer.setDisplayTopology(mTopology);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, device, ui::LogicalDisplayId::INVALID)}});
auto pc = assertPointerControllerCreated(pointerControllerType);
- ASSERT_EQ(PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- pc->getDisplayId());
+ ASSERT_EQ(DISPLAY_CENTER_ID, pc->getDisplayId());
// Set initial position of the PointerController.
pc->setPosition(initialPosition.x, initialPosition.y);
@@ -2828,92 +2851,320 @@
}
INSTANTIATE_TEST_SUITE_P(
- PointerChoreographerTest, PointerChoreographerDisplayTopologyTestFixture,
+ PointerChoreographerTest, PointerChoreographerDisplayTopologyCursorTestFixture,
testing::Values(
// Note: Upon viewport transition cursor will be positioned at the boundary of the
// destination, as we drop any unconsumed delta.
- std::make_tuple("PrimaryDisplayIsDefault", AINPUT_SOURCE_MOUSE,
- ControllerType::MOUSE, ToolType::MOUSE,
- vec2(50, 50) /* initial x/y */, vec2(0, 0) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- vec2(50, 50) /* destination x/y */),
- std::make_tuple("UnchangedDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
- ToolType::MOUSE, vec2(50, 50) /* initial x/y */,
- vec2(25, 25) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- vec2(75, 75) /* destination x/y */),
- std::make_tuple("TransitionToRightDisplay", AINPUT_SOURCE_MOUSE,
- ControllerType::MOUSE, ToolType::MOUSE,
- vec2(50, 50) /* initial x/y */, vec2(100, 25) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_RIGHT_ID,
- vec2(0,
- 50 + 25 - 10) /* Left edge: (0, source + delta - offset) */),
+ std::make_tuple(
+ "PrimaryDisplayIsDefault", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
+ ToolType::MOUSE, vec2(50, 50) /* initial x/y */, vec2(0, 0) /* delta x/y */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID,
+ vec2(50, 50) /* destination x/y */),
+ std::make_tuple(
+ "UnchangedDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
+ ToolType::MOUSE, vec2(50, 50) /* initial x/y */,
+ vec2(25, 25) /* delta x/y */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID,
+ vec2(75, 75) /* destination x/y */),
+ std::make_tuple(
+ "TransitionToRightDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
+ ToolType::MOUSE, vec2(50, 50) /* initial x/y */,
+ vec2(100, 25) /* delta x/y */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_RIGHT_ID,
+ vec2(0, 50 + 25 - 10) /* Left edge: (0, source + delta - offset) */),
std::make_tuple(
"TransitionToLeftDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
ToolType::MOUSE, vec2(50, 50) /* initial x/y */,
vec2(-100, 25) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_LEFT_ID,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_LEFT_ID,
vec2(90, 50 + 25 - 10) /* Right edge: (width, source + delta - offset*/),
- std::make_tuple("TransitionToTopDisplay",
- AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
- ToolType::FINGER, vec2(50, 50) /* initial x/y */,
- vec2(25, -100) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_TOP_ID,
- vec2(50 + 25 - 50,
- 90) /* Bottom edge: (source + delta - offset, height) */),
- std::make_tuple("TransitionToBottomDisplay",
- AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
- ToolType::FINGER, vec2(50, 50) /* initial x/y */,
- vec2(25, 100) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_BOTTOM_ID,
- vec2(50 + 25 - 10, 0) /* Top edge: (source + delta - offset, 0) */),
+ std::make_tuple(
+ "TransitionToTopDisplay", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
+ ControllerType::MOUSE, ToolType::FINGER, vec2(50, 50) /* initial x/y */,
+ vec2(25, -100) /* delta x/y */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_TOP_ID,
+ vec2(50 + 25 - 50,
+ 90) /* Bottom edge: (source + delta - offset, height) */),
+ std::make_tuple(
+ "TransitionToBottomDisplay", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
+ ControllerType::MOUSE, ToolType::FINGER, vec2(50, 50) /* initial x/y */,
+ vec2(25, 100) /* delta x/y */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_BOTTOM_ID,
+ vec2(50 + 25 - 10, 0) /* Top edge: (source + delta - offset, 0) */),
// move towards 25 dp gap between DISPLAY_HIGH_DENSITY_ID and DISPLAY_TOP_ID
- std::make_tuple("NoTransitionAtTopOffset", AINPUT_SOURCE_MOUSE,
- ControllerType::MOUSE, ToolType::MOUSE,
- vec2(35, 50) /* initial x/y */, vec2(0, -100) /* Move Up */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- vec2(35, 0) /* Top edge */),
- std::make_tuple("NoTransitionAtRightOffset", AINPUT_SOURCE_MOUSE,
- ControllerType::MOUSE, ToolType::MOUSE,
- vec2(95, 5) /* initial x/y */, vec2(100, 0) /* Move Right */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- vec2(99, 5) /* Top edge */),
- std::make_tuple("NoTransitionAtBottomOffset",
- AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
- ToolType::FINGER, vec2(5, 95) /* initial x/y */,
- vec2(0, 100) /* Move Down */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- vec2(5, 99) /* Bottom edge */),
- std::make_tuple("NoTransitionAtLeftOffset",
- AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
- ToolType::FINGER, vec2(5, 5) /* initial x/y */,
- vec2(-100, 0) /* Move Left */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- vec2(0, 5) /* Left edge */),
std::make_tuple(
- "TransitionAtTopRightCorner", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
- ControllerType::MOUSE, ToolType::FINGER, vec2(95, 5) /* initial x/y */,
- vec2(10, -10) /* Move diagonally to top right corner */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_TOP_RIGHT_CORNER_ID,
- vec2(0, 90) /* bottom left corner */),
+ "NoTransitionAtTopOffset", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
+ ToolType::MOUSE, vec2(35, 50) /* initial x/y */,
+ vec2(0, -100) /* Move Up */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID,
+ vec2(35, 0) /* Top edge */),
std::make_tuple(
- "TransitionToHighDpDisplay", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
- ControllerType::MOUSE, ToolType::MOUSE, vec2(20, 20) /* initial x/y */,
- vec2(0, -50) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_HIGH_DENSITY_ID,
- /* Bottom edge: ((source + delta - offset) * density, height) */
- vec2((20 + 0 + 75) * 2, 200))),
- [](const testing::TestParamInfo<PointerChoreographerDisplayTopologyTestFixtureParam>& p) {
- return std::string{std::get<0>(p.param)};
- });
+ "NoTransitionAtRightOffset", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
+ ToolType::MOUSE, vec2(95, 5) /* initial x/y */,
+ vec2(100, 0) /* Move Right */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID,
+ vec2(99, 5) /* Top edge */),
+ std::make_tuple(
+ "NoTransitionAtBottomOffset", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
+ ControllerType::MOUSE, ToolType::FINGER, vec2(5, 95) /* initial x/y */,
+ vec2(0, 100) /* Move Down */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID,
+ vec2(5, 99) /* Bottom edge */),
+ std::make_tuple(
+ "NoTransitionAtLeftOffset", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
+ ControllerType::MOUSE, ToolType::FINGER, vec2(5, 5) /* initial x/y */,
+ vec2(-100, 0) /* Move Left */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID,
+ vec2(0, 5) /* Left edge */),
+ std::make_tuple("TransitionAtTopRightCorner",
+ AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
+ ToolType::FINGER, vec2(95, 5) /* initial x/y */,
+ vec2(10, -10) /* Move diagonally to top right corner */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::
+ DISPLAY_TOP_RIGHT_CORNER_ID,
+ vec2(0, 90) /* bottom left corner */),
+ std::make_tuple("TransitionToHighDpDisplay",
+ AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
+ ToolType::MOUSE, vec2(20, 20) /* initial x/y */,
+ vec2(0, -50) /* delta x/y */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::
+ DISPLAY_HIGH_DENSITY_ID,
+ /* Bottom edge: ((source + delta - offset) * density, height) */
+ vec2((20 + 0 + 75) * 2, 200))),
+ [](const testing::TestParamInfo<PointerChoreographerDisplayTopologyCursorTestFixtureParam>&
+ p) { return std::string{std::get<0>(p.param)}; });
+
+class PointerChoreographerDisplayTopologyDefaultMouseDisplayTests
+ : public PointerChoreographerDisplayTopologyTests {
+protected:
+ static constexpr ui::LogicalDisplayId FIRST_DISPLAY_ID = ui::LogicalDisplayId{10};
+ static constexpr ui::LogicalDisplayId SECOND_DISPLAY_ID = ui::LogicalDisplayId{20};
+ static constexpr ui::LogicalDisplayId THIRD_DISPLAY_ID = ui::LogicalDisplayId{30};
+
+ DisplayViewport createViewport(ui::LogicalDisplayId displayId) {
+ return PointerChoreographerDisplayTopologyTests::createViewport(displayId, /*width=*/100,
+ /*height=*/100,
+ ui::ROTATION_0);
+ }
+
+ void setDisplayTopologyWithDisplays(
+ ui::LogicalDisplayId primaryDisplayId,
+ const std::vector<ui::LogicalDisplayId>& adjacentDisplays = {}) {
+ // Prepare a topology with all display connected from left to right.
+ ui::LogicalDisplayId previousDisplay = primaryDisplayId;
+
+ std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>>
+ topologyGraph;
+ topologyGraph[primaryDisplayId] = {};
+
+ std::unordered_map<ui::LogicalDisplayId, int> displaysDensity;
+ displaysDensity[primaryDisplayId] = DENSITY_MEDIUM;
+
+ for (ui::LogicalDisplayId adjacentDisplayId : adjacentDisplays) {
+ topologyGraph[previousDisplay].push_back({.displayId = adjacentDisplayId,
+ .position = DisplayTopologyPosition::RIGHT,
+ .offsetDp = 0.0f});
+ topologyGraph[adjacentDisplayId].push_back({.displayId = previousDisplay,
+ .position = DisplayTopologyPosition::LEFT,
+ .offsetDp = 0.0f});
+
+ displaysDensity[adjacentDisplayId] = DENSITY_MEDIUM;
+ }
+
+ mChoreographer.setDisplayTopology({primaryDisplayId, topologyGraph, displaysDensity});
+ }
+};
+
+TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
+ UnrelatedTopologyUpdatesDoNotChangeCursorDisplay) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+
+ // Set first display as primary display and emit mouse event to create PointerController.
+ mChoreographer.setDisplayViewports({createViewport(FIRST_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID);
+
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
+ ui::LogicalDisplayId::INVALID)}});
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(FIRST_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ // Add another display keeping the primary display unchanged
+ mChoreographer.setDisplayViewports(
+ {createViewport(FIRST_DISPLAY_ID), createViewport(SECOND_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID,
+ /*adjacentDisplays=*/{SECOND_DISPLAY_ID});
+
+ assertPointerControllerNotCreated();
+ pc->assertViewportSet(FIRST_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ // Move cursor to second display and add a third display
+ auto pointerBuilder = PointerBuilder(/*id=*/0, ToolType::MOUSE)
+ .axis(AMOTION_EVENT_AXIS_RELATIVE_X, /*x=*/100)
+ .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, /*y=*/0);
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(pointerBuilder)
+ .deviceId(DEVICE_ID)
+ .displayId(ui::LogicalDisplayId::INVALID)
+ .build());
+
+ assertPointerControllerNotCreated();
+ pc->assertViewportSet(SECOND_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ mChoreographer.setDisplayViewports({createViewport(FIRST_DISPLAY_ID),
+ createViewport(SECOND_DISPLAY_ID),
+ createViewport(THIRD_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID, /*adjacentDisplays=*/
+ {SECOND_DISPLAY_ID, THIRD_DISPLAY_ID});
+
+ assertPointerControllerNotCreated();
+ pc->assertViewportSet(SECOND_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ // Change the primary display to the third display
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/THIRD_DISPLAY_ID, /*adjacentDisplays=*/
+ {SECOND_DISPLAY_ID, THIRD_DISPLAY_ID});
+
+ assertPointerControllerNotCreated();
+ pc->assertViewportSet(SECOND_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
+ PrimaryDisplayIsFallbackOnPointerDisplayRemoved) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+
+ // Add two displays and move cursor to the secondary display
+ mChoreographer.setDisplayViewports(
+ {createViewport(FIRST_DISPLAY_ID), createViewport(SECOND_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID,
+ /*adjacentDisplays=*/{SECOND_DISPLAY_ID});
+
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
+ ui::LogicalDisplayId::INVALID)}});
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(FIRST_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ auto pointerBuilder = PointerBuilder(/*id=*/0, ToolType::MOUSE)
+ .axis(AMOTION_EVENT_AXIS_RELATIVE_X, /*x=*/100)
+ .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, /*y=*/0);
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(pointerBuilder)
+ .deviceId(DEVICE_ID)
+ .displayId(ui::LogicalDisplayId::INVALID)
+ .build());
+
+ assertPointerControllerNotCreated();
+ pc->assertViewportSet(SECOND_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ // Remove the secondary display
+ mChoreographer.setDisplayViewports({createViewport(FIRST_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID);
+
+ assertPointerControllerRemoved(pc);
+ pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(FIRST_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
+ UsePrimaryDisplayIfAssociatedDisplayIsInTopology) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+ SCOPED_FLAG_OVERRIDE(connected_displays_associated_display_cursor_bugfix, true);
+
+ // Add two displays
+ mChoreographer.setDisplayViewports(
+ {createViewport(FIRST_DISPLAY_ID), createViewport(SECOND_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/SECOND_DISPLAY_ID,
+ /*adjacentDisplays=*/{FIRST_DISPLAY_ID});
+
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, FIRST_DISPLAY_ID)}});
+
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(SECOND_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
+ AllowCrossingDisplayEvenWithAssociatedDisplaySet) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+ SCOPED_FLAG_OVERRIDE(connected_displays_associated_display_cursor_bugfix, true);
+
+ // Add two displays
+ mChoreographer.setDisplayViewports(
+ {createViewport(FIRST_DISPLAY_ID), createViewport(SECOND_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID,
+ /*adjacentDisplays=*/{SECOND_DISPLAY_ID});
+
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, SECOND_DISPLAY_ID)}});
+
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(FIRST_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ // Move cursor to the secondary display
+ auto pointerBuilder = PointerBuilder(/*id=*/0, ToolType::MOUSE)
+ .axis(AMOTION_EVENT_AXIS_RELATIVE_X, /*x=*/100)
+ .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, /*y=*/0);
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(pointerBuilder)
+ .deviceId(DEVICE_ID)
+ .displayId(ui::LogicalDisplayId::INVALID)
+ .build());
+
+ assertPointerControllerNotCreated();
+ pc->assertViewportSet(SECOND_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
+ AddAssociatedDisplayCursorOutsideOfDisplayTopology) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+ SCOPED_FLAG_OVERRIDE(connected_displays_associated_display_cursor_bugfix, true);
+
+ // Add three displays, with only first and second display in DisplayTopolgoy
+ mChoreographer.setDisplayViewports({createViewport(FIRST_DISPLAY_ID),
+ createViewport(SECOND_DISPLAY_ID),
+ createViewport(THIRD_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID,
+ /*adjacentDisplays=*/{SECOND_DISPLAY_ID});
+
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
+ ui::LogicalDisplayId::INVALID)}});
+
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(FIRST_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ // Adds a new mouse associated with third display
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/1, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, THIRD_DISPLAY_ID)}});
+
+ pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(THIRD_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+}
class PointerChoreographerWindowInfoListenerTest : public testing::Test {};
-TEST_F_WITH_FLAGS(
- PointerChoreographerWindowInfoListenerTest,
- doesNotCrashIfListenerCalledAfterPointerChoreographerDestroyed,
- REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::input::flags,
- hide_pointer_indicators_for_secure_windows))) {
+TEST_F(PointerChoreographerWindowInfoListenerTest,
+ doesNotCrashIfListenerCalledAfterPointerChoreographerDestroyed) {
sp<android::gui::WindowInfosListener> registeredListener;
sp<android::gui::WindowInfosListener> localListenerCopy;
{
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index bba7389..9a59039 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -360,6 +360,7 @@
std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp)
: mEventHub(eventHub), mPolicy(sp<FuzzInputReaderPolicy>::make(fdp)), mFdp(fdp) {}
~FuzzInputReaderContext() {}
+ std::string dump() { return "(dump from FuzzInputReaderContext)"; }
void updateGlobalMetaState() override {}
int32_t getGlobalMetaState() { return mFdp->ConsumeIntegral<int32_t>(); }
void disableVirtualKeysUntil(nsecs_t time) override {}
diff --git a/services/sensorservice/sensorservice_flags.aconfig b/services/sensorservice/sensorservice_flags.aconfig
index 452b428..6308973 100644
--- a/services/sensorservice/sensorservice_flags.aconfig
+++ b/services/sensorservice/sensorservice_flags.aconfig
@@ -37,4 +37,14 @@
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "disable_vndk_forged_name"
+ namespace: "sensors"
+ description: "When this flag is enabled, sensor manager will not use forged name to determine if an access is from VNDK"
+ bug: "398253250"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
\ No newline at end of file
diff --git a/services/stats/OWNERS b/services/stats/OWNERS
index a599619..791b711 100644
--- a/services/stats/OWNERS
+++ b/services/stats/OWNERS
@@ -1,6 +1,5 @@
jeffreyhuang@google.com
joeo@google.com
-jtnguyen@google.com
muhammadq@google.com
ruchirr@google.com
singhtejinder@google.com
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index dea3290..efddc85 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -104,7 +104,7 @@
void detectDisallowedCompositionTypeChange(
aidl::android::hardware::graphics::composer3::Composition from,
aidl::android::hardware::graphics::composer3::Composition to) const;
- bool isClientCompositionForced(bool isPeekingThrough, bool isCached) const;
+ bool isClientCompositionForced(bool isPeekingThrough) const;
void updateLuts(const LayerFECompositionState&,
const std::optional<std::vector<std::optional<LutProperties>>>& properties);
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index f934cb2..e42b9b1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -253,7 +253,6 @@
std::unordered_map<size_t, size_t> mFinalLayerCounts;
size_t mCachedSetCreationCount = 0;
size_t mCachedSetCreationCost = 0;
- std::unordered_map<size_t, size_t> mInvalidatedCachedSetAges;
};
} // namespace compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
index d9018bc..dc84195 100644
--- a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
@@ -38,7 +38,8 @@
lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow &&
lhs.backgroundBlurRadius == rhs.backgroundBlurRadius &&
lhs.stretchEffect == rhs.stretchEffect &&
- lhs.edgeExtensionEffect == rhs.edgeExtensionEffect;
+ lhs.edgeExtensionEffect == rhs.edgeExtensionEffect &&
+ lhs.whitePointNits == rhs.whitePointNits;
}
inline bool equalIgnoringBuffer(const renderengine::Buffer& lhs, const renderengine::Buffer& rhs) {
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index de1d13a..b30cf20 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1389,7 +1389,8 @@
// or complex GPU shaders and it's expensive. We boost the GPU frequency so that
// GPU composition can finish in time. We must reset GPU frequency afterwards,
// because high frequency consumes extra battery.
- const bool expensiveRenderingExpected =
+ const bool expensiveBlurs = mLayerRequestingBackgroundBlur != nullptr;
+ const bool expensiveRenderingExpected = expensiveBlurs ||
std::any_of(clientCompositionLayers.begin(), clientCompositionLayers.end(),
[outputDataspace =
clientCompositionDisplay.outputDataspace](const auto& layer) {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index cf2d8c2..ea36011 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -369,8 +369,11 @@
layerFEState->buffer->getPixelFormat()))
: std::nullopt;
- auto hdrRenderType =
- getHdrRenderType(outputState.dataspace, pixelFormat, layerFEState->desiredHdrSdrRatio);
+ // prefer querying this from gralloc instead to catch 2094-10 metadata
+ const bool hasHdrMetadata = layerFEState->hdrMetadata.validTypes != 0;
+
+ auto hdrRenderType = getHdrRenderType(outputState.dataspace, pixelFormat,
+ layerFEState->desiredHdrSdrRatio, hasHdrMetadata);
// Determine the output dependent dataspace for this layer. If it is
// colorspace agnostic, it just uses the dataspace chosen for the output to
@@ -393,8 +396,8 @@
}
// re-get HdrRenderType after the dataspace gets changed.
- hdrRenderType =
- getHdrRenderType(state.dataspace, pixelFormat, layerFEState->desiredHdrSdrRatio);
+ hdrRenderType = getHdrRenderType(state.dataspace, pixelFormat, layerFEState->desiredHdrSdrRatio,
+ hasHdrMetadata);
// For hdr content, treat the white point as the display brightness - HDR content should not be
// boosted or dimmed.
@@ -416,12 +419,20 @@
state.dimmingRatio = std::min(idealizedMaxHeadroom / deviceHeadroom, 1.0f);
state.whitePointNits = getOutput().getState().displayBrightnessNits * state.dimmingRatio;
} else {
+ const bool isLayerFp16 = pixelFormat && *pixelFormat == ui::PixelFormat::RGBA_FP16;
float layerBrightnessNits = getOutput().getState().sdrWhitePointNits;
// RANGE_EXTENDED can "self-promote" to HDR, but is still rendered for a particular
// range that we may need to re-adjust to the current display conditions
+ // Do NOT do this when we may render fp16 to an fp16 client target, to avoid applying
+ // and additional gain to the layer. This is because the fp16 client target should
+ // already be adapted to remap 1.0 to the SDR white point in the panel's luminance
+ // space.
if (hdrRenderType == HdrRenderType::DISPLAY_HDR) {
- layerBrightnessNits *= layerFEState->currentHdrSdrRatio;
+ if (!FlagManager::getInstance().fp16_client_target() || !isLayerFp16) {
+ layerBrightnessNits *= layerFEState->currentHdrSdrRatio;
+ }
}
+
state.dimmingRatio =
std::clamp(layerBrightnessNits / getOutput().getState().displayBrightnessNits, 0.f,
1.f);
@@ -865,8 +876,7 @@
bool isPeekingThrough, bool skipLayer) {
auto& outputDependentState = editState();
- bool isCached = !skipLayer && outputDependentState.overrideInfo.buffer;
- if (isClientCompositionForced(isPeekingThrough, isCached)) {
+ if (isClientCompositionForced(isPeekingThrough)) {
// If we are forcing client composition, we need to tell the HWC
requestedCompositionType = Composition::CLIENT;
}
@@ -956,12 +966,9 @@
}
}
-bool OutputLayer::isClientCompositionForced(bool isPeekingThrough, bool isCached) const {
- // If this layer was flattened into a CachedSet then it is not necessary for
- // the GPU to compose it.
- bool requiresClientDrawnRoundedCorners = !isCached && getLayerFE().hasRoundedCorners();
+bool OutputLayer::isClientCompositionForced(bool isPeekingThrough) const {
return getState().forceClientComposition ||
- (!isPeekingThrough && requiresClientDrawnRoundedCorners);
+ (!isPeekingThrough && getLayerFE().hasRoundedCorners());
}
void OutputLayer::applyDeviceCompositionTypeChange(Composition compositionType) {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 783209c..2081cd5 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -243,17 +243,9 @@
mCurrentGeometry = hash;
mLastGeometryUpdate = now;
-
- for (const CachedSet& cachedSet : mLayers) {
- if (cachedSet.getLayerCount() > 1) {
- ++mInvalidatedCachedSetAges[cachedSet.getAge()];
- }
- }
-
mLayers.clear();
if (mNewCachedSet) {
- ++mInvalidatedCachedSetAges[mNewCachedSet->getAge()];
mNewCachedSet = std::nullopt;
}
}
@@ -312,7 +304,6 @@
mNewCachedSet->getFirstLayer().getState()->getId() == (*incomingLayerIter)->getId()) {
if (mNewCachedSet->hasBufferUpdate()) {
ALOGV("[%s] Dropping new cached set", __func__);
- ++mInvalidatedCachedSetAges[0];
mNewCachedSet = std::nullopt;
} else if (mNewCachedSet->hasReadyBuffer()) {
ALOGV("[%s] Found ready buffer", __func__);
@@ -325,6 +316,7 @@
priorBlurLayer == (*incomingLayerIter)->getOutputLayer();
OutputLayer::CompositionState& state =
(*incomingLayerIter)->getOutputLayer()->editState();
+
state.overrideInfo = {
.buffer = mNewCachedSet->getBuffer(),
.acquireFence = mNewCachedSet->getDrawFence(),
@@ -338,10 +330,6 @@
};
++incomingLayerIter;
}
-
- if (currentLayerIter->getLayerCount() > 1) {
- ++mInvalidatedCachedSetAges[currentLayerIter->getAge()];
- }
++currentLayerIter;
skipCount -= layerCount;
@@ -378,9 +366,9 @@
};
++incomingLayerIter;
}
+ priorBlurLayer = currentLayerIter->getBlurLayer();
} else if (currentLayerIter->getLayerCount() > 1) {
// Break the current layer into its constituent layers
- ++mInvalidatedCachedSetAges[currentLayerIter->getAge()];
for (CachedSet& layer : currentLayerIter->decompose()) {
bool disableBlur =
priorBlurLayer && priorBlurLayer == (*incomingLayerIter)->getOutputLayer();
@@ -400,8 +388,8 @@
currentLayerIter->updateAge(now);
merged.emplace_back(*currentLayerIter);
++incomingLayerIter;
+ priorBlurLayer = currentLayerIter->getBlurLayer();
}
- priorBlurLayer = currentLayerIter->getBlurLayer();
++currentLayerIter;
}
diff --git a/services/surfaceflinger/Display/DisplayModeController.cpp b/services/surfaceflinger/Display/DisplayModeController.cpp
index a086aee..87a677c 100644
--- a/services/surfaceflinger/Display/DisplayModeController.cpp
+++ b/services/surfaceflinger/Display/DisplayModeController.cpp
@@ -97,9 +97,7 @@
const bool force = desiredModeOpt->force;
desiredModeOpt = std::move(desiredMode);
desiredModeOpt->emitEvent |= emitEvent;
- if (FlagManager::getInstance().connected_display()) {
- desiredModeOpt->force |= force;
- }
+ desiredModeOpt->force |= force;
return DesiredModeAction::None;
}
@@ -191,7 +189,7 @@
// cleared until the next `SF::initiateDisplayModeChanges`. However, the desired mode has been
// consumed at this point, so clear the `force` flag to prevent an endless loop of
// `initiateModeChange`.
- if (FlagManager::getInstance().connected_display()) {
+ {
std::scoped_lock lock(displayPtr->desiredModeLock);
if (displayPtr->desiredModeOpt) {
displayPtr->desiredModeOpt->force = false;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index e8b09b0..b396544 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -51,6 +51,17 @@
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)
@@ -169,8 +180,7 @@
}
void DisplayDevice::setPowerMode(hal::PowerMode mode) {
- // TODO(b/241285876): Skip this for virtual displays.
- if (mode == hal::PowerMode::OFF || mode == hal::PowerMode::ON) {
+ if (!isVirtual() && (mode == hal::PowerMode::OFF || mode == hal::PowerMode::ON)) {
if (mStagedBrightness && mBrightness != mStagedBrightness) {
getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
mBrightness = *mStagedBrightness;
@@ -283,6 +293,7 @@
dumper.dump("name"sv, '"' + mDisplayName + '"');
dumper.dump("powerMode"sv, mPowerMode);
+ dumper.dump("optimizationPolicy"sv, mOptimizationPolicy);
if (mRefreshRateSelector) {
mRefreshRateSelector->dump(dumper);
@@ -305,6 +316,15 @@
mCompositionDisplay->setSecure(secure);
}
+gui::ISurfaceComposer::OptimizationPolicy DisplayDevice::getOptimizationPolicy() const {
+ return mOptimizationPolicy;
+}
+
+void DisplayDevice::setOptimizationPolicy(
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy) {
+ mOptimizationPolicy = optimizationPolicy;
+}
+
const Rect DisplayDevice::getBounds() const {
return mCompositionDisplay->getState().displaySpace.getBoundsAsRect();
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index b5a543a..02522a3 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -93,6 +93,11 @@
bool isSecure() const;
void setSecure(bool secure);
+ // The optimization policy influences whether this display is optimized for power or
+ // performance.
+ gui::ISurfaceComposer::OptimizationPolicy getOptimizationPolicy() const;
+ void setOptimizationPolicy(gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy);
+
int getWidth() const;
int getHeight() const;
ui::Size getSize() const { return {getWidth(), getHeight()}; }
@@ -236,6 +241,9 @@
// TODO(b/182939859): Remove special cases for primary display.
const bool mIsPrimary;
+ gui::ISurfaceComposer::OptimizationPolicy mOptimizationPolicy =
+ gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance;
+
uint32_t mFlags = 0;
// Requested refresh rate in fps, supported only for virtual displays.
@@ -283,11 +291,16 @@
std::string displayName;
std::string uniqueId;
bool isSecure = false;
+
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy =
+ gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance;
bool isProtected = false;
// Refer to DisplayDevice::mRequestedRefreshRate, for virtual display only
Fps requestedRefreshRate;
int32_t maxLayerPictureProfiles = 0;
bool hasPictureProcessing = false;
+ hardware::graphics::composer::hal::PowerMode initialPowerMode{
+ hardware::graphics::composer::hal::PowerMode::OFF};
private:
static std::atomic<int32_t> sNextSequenceId;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 01f382f..8d16a6b 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -439,11 +439,8 @@
// FIXME (b/319505580): At least the first config set on an external display must be
// `setActiveConfig`, so skip over the block that calls `setActiveConfigWithConstraints`
// for simplicity.
- const bool connected_display = FlagManager::getInstance().connected_display();
-
if (isVsyncPeriodSwitchSupported() &&
- (!connected_display ||
- getConnectionType().value_opt() != ui::DisplayConnectionType::External)) {
+ getConnectionType().value_opt() != ui::DisplayConnectionType::External) {
Hwc2::IComposerClient::VsyncPeriodChangeConstraints hwc2Constraints;
hwc2Constraints.desiredTimeNanos = constraints.desiredTimeNanos;
hwc2Constraints.seamlessRequired = constraints.seamlessRequired;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 545ed19..14088a6 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -145,7 +145,7 @@
case HotplugEvent::Disconnected:
return onHotplugDisconnect(hwcDisplayId);
case HotplugEvent::LinkUnstable:
- return {};
+ return onHotplugLinkTrainingFailure(hwcDisplayId);
}
}
@@ -1245,6 +1245,16 @@
return DisplayIdentificationInfo{.id = *displayId};
}
+std::optional<DisplayIdentificationInfo> HWComposer::onHotplugLinkTrainingFailure(
+ hal::HWDisplayId hwcDisplayId) {
+ const auto displayId = toPhysicalDisplayId(hwcDisplayId);
+ if (!displayId) {
+ LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display");
+ return {};
+ }
+ return DisplayIdentificationInfo{.id = *displayId};
+}
+
void HWComposer::loadCapabilities() {
static_assert(sizeof(hal::Capability) == sizeof(int32_t), "Capability size has changed");
auto capabilities = mComposer->getCapabilities();
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 2c0aa3d..472411c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -544,6 +544,7 @@
std::optional<DisplayIdentificationInfo> onHotplugConnect(hal::HWDisplayId);
std::optional<DisplayIdentificationInfo> onHotplugDisconnect(hal::HWDisplayId);
+ std::optional<DisplayIdentificationInfo> onHotplugLinkTrainingFailure(hal::HWDisplayId);
bool shouldIgnoreHotplugConnect(hal::HWDisplayId, uint8_t port,
bool hasDisplayIdentificationData) const;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 1f0d5d0..964a970 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -41,7 +41,7 @@
if (forceFullDamage) {
outSurfaceDamageRegion = Region::INVALID_REGION;
} else {
- outSurfaceDamageRegion = requested.surfaceDamageRegion;
+ outSurfaceDamageRegion = requested.getSurfaceDamageRegion();
}
}
@@ -376,7 +376,7 @@
updateSurfaceDamage(requested, requested.hasReadyFrame(), forceFullDamage, surfaceDamage);
if (forceUpdate || requested.what & layer_state_t::eTransparentRegionChanged) {
- transparentRegionHint = requested.transparentRegion;
+ transparentRegionHint = requested.getTransparentRegion();
}
if (forceUpdate || requested.what & layer_state_t::eFlagsChanged) {
layerOpaqueFlagSet =
@@ -448,15 +448,7 @@
}
if (forceUpdate || requested.what & layer_state_t::eInputInfoChanged) {
- if (requested.windowInfoHandle) {
- inputInfo = *requested.windowInfoHandle->getInfo();
- } else {
- inputInfo = {};
- // b/271132344 revisit this and see if we can always use the layers uid/pid
- inputInfo.name = requested.name;
- inputInfo.ownerUid = requested.ownerUid;
- inputInfo.ownerPid = requested.ownerPid;
- }
+ inputInfo = requested.getWindowInfo();
inputInfo.id = static_cast<int32_t>(uniqueSequence);
touchCropId = requested.touchCropId;
}
@@ -548,7 +540,7 @@
case Composition::INVALID:
return 'i';
case Composition::SOLID_COLOR:
- return 'e';
+ return 'c';
case Composition::CURSOR:
return 'u';
case Composition::SIDEBAND:
@@ -556,7 +548,7 @@
case Composition::DISPLAY_DECORATION:
return 'a';
case Composition::REFRESH_RATE_INDICATOR:
- return 'f';
+ return 'r';
case Composition::CLIENT:
case Composition::DEVICE:
break;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 86ef6ca..28a6031 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -1090,7 +1090,7 @@
snapshot.transformedBounds = snapshot.geomLayerTransform.transform(snapshot.geomLayerBounds);
const Rect geomLayerBoundsWithoutTransparentRegion =
RequestedLayerState::reduce(Rect(snapshot.geomLayerBounds),
- requested.transparentRegion);
+ requested.getTransparentRegion());
snapshot.transformedBoundsWithoutTransparentRegion =
snapshot.geomLayerTransform.transform(geomLayerBoundsWithoutTransparentRegion);
snapshot.parentTransform = parentSnapshot.geomLayerTransform;
@@ -1098,7 +1098,7 @@
if (requested.potentialCursor) {
// Subtract the transparent region and snap to the bounds
const Rect bounds = RequestedLayerState::reduce(Rect(snapshot.croppedBufferSize),
- requested.transparentRegion);
+ requested.getTransparentRegion());
snapshot.cursorFrame = snapshot.geomLayerTransform.transform(bounds);
}
}
@@ -1132,22 +1132,14 @@
const Args& args) {
using InputConfig = gui::WindowInfo::InputConfig;
- if (requested.windowInfoHandle) {
- snapshot.inputInfo = *requested.windowInfoHandle->getInfo();
- } else {
- snapshot.inputInfo = {};
- // b/271132344 revisit this and see if we can always use the layers uid/pid
- snapshot.inputInfo.name = requested.name;
- snapshot.inputInfo.ownerUid = gui::Uid{requested.ownerUid};
- snapshot.inputInfo.ownerPid = gui::Pid{requested.ownerPid};
- }
+ snapshot.inputInfo = requested.getWindowInfo();
snapshot.touchCropId = requested.touchCropId;
snapshot.inputInfo.id = static_cast<int32_t>(snapshot.uniqueSequence);
snapshot.inputInfo.displayId =
ui::LogicalDisplayId{static_cast<int32_t>(snapshot.outputFilter.layerStack.id)};
snapshot.inputInfo.touchOcclusionMode = requested.hasInputInfo()
- ? requested.windowInfoHandle->getInfo()->touchOcclusionMode
+ ? requested.getWindowInfo().touchOcclusionMode
: parentSnapshot.inputInfo.touchOcclusionMode;
snapshot.inputInfo.canOccludePresentation = parentSnapshot.inputInfo.canOccludePresentation ||
(requested.flags & layer_state_t::eCanOccludePresentation);
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 9a36bf0..621fd6c 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -63,8 +63,11 @@
metadata.merge(args.metadata);
changes |= RequestedLayerState::Changes::Metadata;
handleAlive = true;
- // TODO: b/305254099 remove once we don't pass invisible windows to input
- windowInfoHandle = nullptr;
+ // b/271132344 revisit this and see if we can always use the layers uid/pid
+ auto* windowInfo = editWindowInfo();
+ windowInfo->name = name;
+ windowInfo->ownerPid = ownerPid;
+ windowInfo->ownerUid = ownerUid;
if (parentId != UNASSIGNED_LAYER_ID) {
canBeRoot = false;
}
@@ -105,7 +108,7 @@
currentHdrSdrRatio = 1.f;
dataspaceRequested = false;
hdrMetadata.validTypes = 0;
- surfaceDamageRegion = Region::INVALID_REGION;
+ mNotDefCmpState.surfaceDamageRegion = Region::INVALID_REGION;
cornerRadius = 0.0f;
clientDrawnCornerRadius = 0.0f;
backgroundBlurRadius = 0;
@@ -279,7 +282,7 @@
if (clientState.what & layer_state_t::eReparent) {
changes |= RequestedLayerState::Changes::Parent;
parentId = resolvedComposerState.parentId;
- parentSurfaceControlForChild = nullptr;
+ mNotDefCmpState.parentSurfaceControlForChild = nullptr;
// Once a layer has be reparented, it cannot be placed at the root. It sounds odd
// but thats the existing logic and until we make this behavior more explicit, we need
// to maintain this logic.
@@ -289,7 +292,7 @@
changes |= RequestedLayerState::Changes::RelativeParent;
relativeParentId = resolvedComposerState.relativeParentId;
isRelativeOf = true;
- relativeLayerSurfaceControl = nullptr;
+ mNotDefCmpState.relativeLayerSurfaceControl = nullptr;
}
if ((clientState.what & layer_state_t::eLayerChanged ||
(clientState.what & layer_state_t::eReparent && parentId == UNASSIGNED_LAYER_ID)) &&
@@ -305,7 +308,7 @@
}
if (clientState.what & layer_state_t::eInputInfoChanged) {
touchCropId = resolvedComposerState.touchCropId;
- windowInfoHandle->editInfo()->touchableRegionCropHandle.clear();
+ editWindowInfo()->touchableRegionCropHandle.clear();
}
if (clientState.what & layer_state_t::eStretchChanged) {
stretchEffect.sanitize();
@@ -563,12 +566,9 @@
}
bool RequestedLayerState::hasInputInfo() const {
- if (!windowInfoHandle) {
- return false;
- }
- const auto windowInfo = windowInfoHandle->getInfo();
- return windowInfo->token != nullptr ||
- windowInfo->inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
+ const auto& windowInfo = getWindowInfo();
+ return windowInfo.token != nullptr ||
+ windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
}
bool RequestedLayerState::needsInputInfo() const {
@@ -580,13 +580,9 @@
return true;
}
- if (!windowInfoHandle) {
- return false;
- }
-
- const auto windowInfo = windowInfoHandle->getInfo();
- return windowInfo->token != nullptr ||
- windowInfo->inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
+ const auto& windowInfo = getWindowInfo();
+ return windowInfo.token != nullptr ||
+ windowInfo.inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
}
bool RequestedLayerState::hasBufferOrSidebandStream() const {
diff --git a/services/surfaceflinger/HdrLayerInfoReporter.h b/services/surfaceflinger/HdrLayerInfoReporter.h
index 614f33f..758b111 100644
--- a/services/surfaceflinger/HdrLayerInfoReporter.h
+++ b/services/surfaceflinger/HdrLayerInfoReporter.h
@@ -19,11 +19,11 @@
#include <android-base/thread_annotations.h>
#include <android/gui/IHdrLayerInfoListener.h>
#include <binder/IBinder.h>
+#include <ui/RingBuffer.h>
#include <utils/Timers.h>
#include <unordered_map>
-#include "Utils/RingBuffer.h"
#include "WpHash.h"
namespace android {
@@ -102,7 +102,7 @@
EventHistoryEntry(const HdrLayerInfo& info) : info(info) { timestamp = systemTime(); }
};
- utils::RingBuffer<EventHistoryEntry, 32> mHdrInfoHistory;
+ ui::RingBuffer<EventHistoryEntry, 32> mHdrInfoHistory;
};
} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6af0f59..081bb22 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -288,7 +288,7 @@
bool leaveState);
inline bool hasTrustedPresentationListener() {
- return mTrustedPresentationListener.callbackInterface != nullptr;
+ return mTrustedPresentationListener.getCallback() != nullptr;
}
// Sets the masked bits.
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 44cd319..84b1a73 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -447,7 +447,7 @@
}
layerInfo->set_type("Layer");
- LayerProtoHelper::writeToProto(requestedState.transparentRegion,
+ LayerProtoHelper::writeToProto(requestedState.getTransparentRegion(),
[&]() { return layerInfo->mutable_transparent_region(); });
layerInfo->set_layer_stack(snapshot.outputFilter.layerStack.id);
diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp
index cd7210c..788448d 100644
--- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp
+++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp
@@ -515,7 +515,7 @@
}
void PowerAdvisor::setExpectedPresentTime(TimePoint expectedPresentTime) {
- mExpectedPresentTimes.append(expectedPresentTime);
+ mExpectedPresentTimes.next() = expectedPresentTime;
}
void PowerAdvisor::setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) {
@@ -532,7 +532,7 @@
}
void PowerAdvisor::setCommitStart(TimePoint commitStartTime) {
- mCommitStartTimes.append(commitStartTime);
+ mCommitStartTimes.next() = commitStartTime;
}
void PowerAdvisor::setCompositeEnd(TimePoint compositeEndTime) {
@@ -579,7 +579,7 @@
}
// Tracks when we finish presenting to hwc
- TimePoint estimatedHwcEndTime = mCommitStartTimes[0];
+ TimePoint estimatedHwcEndTime = mCommitStartTimes.back();
// How long we spent this frame not doing anything, waiting for fences or vsync
Duration idleDuration = 0ns;
@@ -643,13 +643,13 @@
// Also add the frame delay duration since the target did not move while we were delayed
Duration totalDuration = mFrameDelayDuration +
std::max(estimatedHwcEndTime, estimatedGpuEndTime.value_or(TimePoint{0ns})) -
- mCommitStartTimes[0];
+ mCommitStartTimes.back();
Duration totalDurationWithoutGpu =
- mFrameDelayDuration + estimatedHwcEndTime - mCommitStartTimes[0];
+ mFrameDelayDuration + estimatedHwcEndTime - mCommitStartTimes.back();
// We finish SurfaceFlinger when post-composition finishes, so add that in here
Duration flingerDuration =
- estimatedFlingerEndTime + mLastPostcompDuration - mCommitStartTimes[0];
+ estimatedFlingerEndTime + mLastPostcompDuration - mCommitStartTimes.back();
Duration estimatedGpuDuration = firstGpuTimeline.has_value()
? estimatedGpuEndTime.value_or(TimePoint{0ns}) - firstGpuTimeline->startTime
: Duration::fromNs(0);
@@ -661,7 +661,7 @@
hal::WorkDuration duration{
.timeStampNanos = TimePoint::now().ns(),
.durationNanos = combinedDuration.ns(),
- .workPeriodStartTimestampNanos = mCommitStartTimes[0].ns(),
+ .workPeriodStartTimestampNanos = mCommitStartTimes.back().ns(),
.cpuDurationNanos = supportsGpuReporting() ? cpuDuration.ns() : 0,
.gpuDurationNanos = supportsGpuReporting() ? estimatedGpuDuration.ns() : 0,
};
diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h
index 540a9df..b97160a 100644
--- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h
+++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h
@@ -23,6 +23,7 @@
#include <ui/DisplayId.h>
#include <ui/FenceTime.h>
+#include <ui/RingBuffer.h>
#include <utils/Mutex.h>
// FMQ library in IPower does questionable conversions
@@ -247,27 +248,6 @@
std::optional<GpuTimeline> estimateGpuTiming(std::optional<TimePoint> previousEndTime);
};
- template <class T, size_t N>
- class RingBuffer {
- std::array<T, N> elements = {};
- size_t mIndex = 0;
- size_t numElements = 0;
-
- public:
- void append(T item) {
- mIndex = (mIndex + 1) % N;
- numElements = std::min(N, numElements + 1);
- elements[mIndex] = item;
- }
- bool isFull() const { return numElements == N; }
- // Allows access like [0] == current, [-1] = previous, etc..
- T& operator[](int offset) {
- size_t positiveOffset =
- static_cast<size_t>((offset % static_cast<int>(N)) + static_cast<int>(N));
- return elements[(mIndex + positiveOffset) % N];
- }
- };
-
// Filter and sort the display ids by a given property
std::vector<DisplayId> getOrderedDisplayIds(
std::optional<TimePoint> DisplayTimingData::*sortBy);
@@ -287,9 +267,9 @@
// Last frame's post-composition duration
Duration mLastPostcompDuration{0ns};
// Buffer of recent commit start times
- RingBuffer<TimePoint, 2> mCommitStartTimes;
+ ui::RingBuffer<TimePoint, 2> mCommitStartTimes;
// Buffer of recent expected present times
- RingBuffer<TimePoint, 2> mExpectedPresentTimes;
+ ui::RingBuffer<TimePoint, 2> mExpectedPresentTimes;
// Most recent present fence time, provided by SF after composition engine finishes presenting
TimePoint mLastPresentFenceTime;
// Most recent composition engine present end time, returned with the present fence from SF
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 4da76f6..e587178 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -986,7 +986,7 @@
if (const auto pacesetterOpt = pacesetterDisplayLocked()) {
const Display& pacesetter = *pacesetterOpt;
- if (!FlagManager::getInstance().connected_display() || params.toggleIdleTimer) {
+ if (params.toggleIdleTimer) {
pacesetter.selectorPtr->setIdleTimerCallbacks(
{.platform = {.onReset = [this] { idleTimerCallback(TimerState::Reset); },
.onExpired = [this] { idleTimerCallback(TimerState::Expired); }},
@@ -1018,7 +1018,7 @@
}
void Scheduler::demotePacesetterDisplay(PromotionParams params) {
- if (!FlagManager::getInstance().connected_display() || params.toggleIdleTimer) {
+ if (params.toggleIdleTimer) {
// No need to lock for reads on kMainThreadContext.
if (const auto pacesetterPtr =
FTL_FAKE_GUARD(mDisplayLock, pacesetterSelectorPtrLocked())) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 3fdddac..81389e7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -386,7 +386,7 @@
// a deadlock where the main thread joins with the timer thread as the timer thread waits to
// lock a mutex held by the main thread.
struct PromotionParams {
- // Whether to stop and start the idle timer. Ignored unless connected_display flag is set.
+ // Whether to stop and start the idle timer.
bool toggleIdleTimer;
};
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index b9c79df..bb04d12 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -208,7 +208,8 @@
auto it = mRateMap.find(idealPeriod());
// Calculated slope over the period of time can become outdated as the new timestamps are
// stored. Using idealPeriod instead provides a rate which is valid at all the times.
- auto const currentPeriod = FlagManager::getInstance().vsync_predictor_recovery()
+ auto const currentPeriod =
+ mDisplayModePtr->getVrrConfig() && FlagManager::getInstance().vsync_predictor_recovery()
? idealPeriod()
: it->second.slope;
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
index 813d4de..ff461d2 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
@@ -24,6 +24,7 @@
#include <ui/DisplayId.h>
#include <ui/Fence.h>
#include <ui/FenceTime.h>
+#include <ui/RingBuffer.h>
#include <scheduler/Features.h>
#include <scheduler/FrameTime.h>
@@ -34,7 +35,6 @@
// TODO(b/185536303): Pull to FTL.
#include "../../../TracedOrdinal.h"
#include "../../../Utils/Dumper.h"
-#include "../../../Utils/RingBuffer.h"
namespace android::scheduler {
@@ -108,7 +108,7 @@
std::pair<bool /* wouldBackpressure */, PresentFence> expectedSignaledPresentFence(
Period vsyncPeriod, Period minFramePeriod) const;
std::array<PresentFence, 2> mPresentFencesLegacy;
- utils::RingBuffer<PresentFence, 5> mPresentFences;
+ ui::RingBuffer<PresentFence, 5> mPresentFences;
FrameTime mLastSignaledFrameTime;
diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp
index 7123905..af6d4d3 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.cpp
+++ b/services/surfaceflinger/ScreenCaptureOutput.cpp
@@ -209,6 +209,7 @@
}
compositionengine::LayerFE::LayerSettings fillLayer;
+ fillLayer.name = "ScreenCaptureFillLayer";
fillLayer.source.buffer.buffer = nullptr;
fillLayer.source.solidColor = half3(0.0f, 0.0f, 0.0f);
fillLayer.geometry.boundaries =
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 98abd10..0029bfc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -384,6 +384,7 @@
bool SurfaceFlinger::hasSyncFramework;
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
int64_t SurfaceFlinger::minAcquiredBuffers = 1;
+std::optional<int64_t> SurfaceFlinger::maxAcquiredBuffersOpt;
uint32_t SurfaceFlinger::maxGraphicsWidth;
uint32_t SurfaceFlinger::maxGraphicsHeight;
bool SurfaceFlinger::useContextPriority;
@@ -452,6 +453,7 @@
maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2);
minAcquiredBuffers =
SurfaceFlingerProperties::min_acquired_buffers().value_or(minAcquiredBuffers);
+ maxAcquiredBuffersOpt = SurfaceFlingerProperties::max_acquired_buffers();
maxGraphicsWidth = std::max(max_graphics_width(0), 0);
maxGraphicsHeight = std::max(max_graphics_height(0), 0);
@@ -576,9 +578,10 @@
mScheduler->run();
}
-sp<IBinder> SurfaceFlinger::createVirtualDisplay(const std::string& displayName, bool isSecure,
- const std::string& uniqueId,
- float requestedRefreshRate) {
+sp<IBinder> SurfaceFlinger::createVirtualDisplay(
+ const std::string& displayName, bool isSecure,
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy, const std::string& uniqueId,
+ float requestedRefreshRate) {
// SurfaceComposerAIDL checks for some permissions, but adding an additional check here.
// This is to ensure that only root, system, and graphics can request to create a secure
// display. Secure displays can show secure content so we add an additional restriction on it.
@@ -588,6 +591,8 @@
return nullptr;
}
+ ALOGD("Creating virtual display: %s", displayName.c_str());
+
class DisplayToken : public BBinder {
sp<SurfaceFlinger> flinger;
virtual ~DisplayToken() {
@@ -611,6 +616,9 @@
// Set display as protected when marked as secure to ensure no behavior change
// TODO (b/314820005): separate as a different arg when creating the display.
state.isProtected = isSecure;
+ state.optimizationPolicy = optimizationPolicy;
+ // Virtual displays start in ON mode.
+ state.initialPowerMode = hal::PowerMode::ON;
state.displayName = displayName;
state.uniqueId = uniqueId;
state.requestedRefreshRate = Fps::fromValue(requestedRefreshRate);
@@ -632,6 +640,9 @@
ALOGE("%s: Invalid operation on physical display", __func__);
return INVALID_OPERATION;
}
+
+ ALOGD("Destroying virtual display: %s", state.displayName.c_str());
+
mCurrentState.displays.removeItemsAt(index);
setTransactionFlags(eDisplayTransactionNeeded);
return NO_ERROR;
@@ -1009,9 +1020,8 @@
mPowerAdvisor->init();
if (base::GetBoolProperty("service.sf.prime_shader_cache"s, true)) {
- if (setSchedFifo(false) != NO_ERROR) {
- ALOGW("Can't set SCHED_OTHER for primeCache");
- }
+ constexpr const char* kWhence = "primeCache";
+ setSchedFifo(false, kWhence);
mRenderEnginePrimeCacheFuture.callOnce([this] {
renderengine::PrimeCacheConfig config;
@@ -1047,9 +1057,7 @@
return getRenderEngine().primeCache(config);
});
- if (setSchedFifo(true) != NO_ERROR) {
- ALOGW("Can't set SCHED_FIFO after primeCache");
- }
+ setSchedFifo(true, kWhence);
}
// Avoid blocking the main thread on `init` to set properties.
@@ -2286,8 +2294,7 @@
void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp,
std::optional<hal::VsyncPeriodNanos> vsyncPeriod) {
- if (FlagManager::getInstance().connected_display() && timestamp < 0 &&
- vsyncPeriod.has_value()) {
+ if (timestamp < 0 && vsyncPeriod.has_value()) {
if (mIsHdcpViaNegVsync && vsyncPeriod.value() == ~1) {
const int32_t value = static_cast<int32_t>(-timestamp);
// one byte is good enough to encode android.hardware.drm.HdcpLevel
@@ -2339,9 +2346,19 @@
return;
}
- if (event == DisplayHotplugEvent::ERROR_LINK_UNSTABLE &&
- !FlagManager::getInstance().display_config_error_hal()) {
- return;
+ if (event == DisplayHotplugEvent::ERROR_LINK_UNSTABLE) {
+ if (!FlagManager::getInstance().display_config_error_hal()) {
+ return;
+ }
+ {
+ std::lock_guard<std::mutex> lock(mHotplugMutex);
+ mPendingHotplugEvents.push_back(
+ HotplugEvent{hwcDisplayId, HWComposer::HotplugEvent::LinkUnstable});
+ }
+ if (mScheduler) {
+ mScheduler->scheduleConfigure();
+ }
+ // do not return to also report the error.
}
// TODO(b/311403559): use enum type instead of int
@@ -3554,9 +3571,8 @@
std::vector<HWComposer::HWCDisplayMode> hwcModes;
std::optional<hal::HWConfigId> activeModeHwcIdOpt;
- const bool isExternalDisplay = FlagManager::getInstance().connected_display() &&
- getHwComposer().getDisplayConnectionType(displayId) ==
- ui::DisplayConnectionType::External;
+ const bool isExternalDisplay = getHwComposer().getDisplayConnectionType(displayId) ==
+ ui::DisplayConnectionType::External;
int attempt = 0;
constexpr int kMaxAttempts = 3;
@@ -3719,11 +3735,12 @@
const auto displayId = info->id;
const ftl::Concat displayString("display ", displayId.value, "(HAL ID ", hwcDisplayId,
')');
-
- if (event == HWComposer::HotplugEvent::Connected) {
+ // TODO: b/393126541 - replace if with switch as all cases are handled.
+ if (event == HWComposer::HotplugEvent::Connected ||
+ event == HWComposer::HotplugEvent::LinkUnstable) {
const auto activeModeIdOpt =
processHotplugConnect(displayId, hwcDisplayId, std::move(*info),
- displayString.c_str());
+ displayString.c_str(), event);
if (!activeModeIdOpt) {
mScheduler->dispatchHotplugError(
static_cast<int32_t>(DisplayHotplugEvent::ERROR_UNKNOWN));
@@ -3749,7 +3766,7 @@
LOG_ALWAYS_FATAL_IF(!snapshotOpt);
mDisplayModeController.registerDisplay(*snapshotOpt, *activeModeIdOpt, config);
- } else {
+ } else { // event == HWComposer::HotplugEvent::Disconnected
// Unregister before destroying the DisplaySnapshot below.
mDisplayModeController.unregisterDisplay(displayId);
@@ -3764,7 +3781,8 @@
std::optional<DisplayModeId> SurfaceFlinger::processHotplugConnect(PhysicalDisplayId displayId,
hal::HWDisplayId hwcDisplayId,
DisplayIdentificationInfo&& info,
- const char* displayString) {
+ const char* displayString,
+ HWComposer::HotplugEvent event) {
auto [displayModes, activeMode] = loadDisplayModes(displayId);
if (!activeMode) {
ALOGE("Failed to hotplug %s", displayString);
@@ -3799,6 +3817,9 @@
state.physical->port = port;
ALOGI("Reconnecting %s", displayString);
return activeModeId;
+ } else if (event == HWComposer::HotplugEvent::LinkUnstable) {
+ ALOGE("Failed to reconnect unknown %s", displayString);
+ return std::nullopt;
}
const sp<IBinder> token = sp<BBinder>::make();
@@ -3899,7 +3920,12 @@
getPhysicalDisplayOrientation(compositionDisplay->getId(), creationArgs.isPrimary);
ALOGV("Display Orientation: %s", toCString(creationArgs.physicalOrientation));
- creationArgs.initialPowerMode = state.isVirtual() ? hal::PowerMode::ON : hal::PowerMode::OFF;
+ if (FlagManager::getInstance().correct_virtual_display_power_state()) {
+ creationArgs.initialPowerMode = state.initialPowerMode;
+ } else {
+ creationArgs.initialPowerMode =
+ state.isVirtual() ? hal::PowerMode::ON : hal::PowerMode::OFF;
+ }
creationArgs.requestedRefreshRate = state.requestedRefreshRate;
@@ -3927,6 +3953,7 @@
display->setProjection(state.orientation, state.layerStackSpaceRect,
state.orientedDisplaySpaceRect);
display->setDisplayName(state.displayName);
+ display->setOptimizationPolicy(state.optimizationPolicy);
display->setFlags(state.flags);
return display;
@@ -3972,6 +3999,8 @@
// Virtual displays without a surface are dormant:
// they have external state (layer stack, projection,
// etc.) but no internal state (i.e. a DisplayDevice).
+ ALOGD("Not adding dormant virtual display with token %p: %s", displayToken.unsafe_get(),
+ state.displayName.c_str());
return;
}
@@ -4046,13 +4075,16 @@
incRefreshableDisplays();
}
+ if (FlagManager::getInstance().correct_virtual_display_power_state()) {
+ applyOptimizationPolicy(__func__);
+ }
+
mDisplays.try_emplace(displayToken, std::move(display));
// For an external display, loadDisplayModes already attempted to select the same mode
// as DM, but SF still needs to be updated to match.
// TODO (b/318534874): Let DM decide the initial mode.
- if (const auto& physical = state.physical;
- mScheduler && physical && FlagManager::getInstance().connected_display()) {
+ if (const auto& physical = state.physical; mScheduler && physical) {
const bool isInternalDisplay = mPhysicalDisplays.get(physical->id)
.transform(&PhysicalDisplay::isInternal)
.value_or(false);
@@ -4103,6 +4135,10 @@
// not be accessible.
}));
}
+
+ if (FlagManager::getInstance().correct_virtual_display_power_state()) {
+ applyOptimizationPolicy(__func__);
+ }
}
void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
@@ -4136,7 +4172,7 @@
if (currentState.physical) {
const auto display = getDisplayDeviceLocked(displayToken);
if (!mSkipPowerOnForQuiescent) {
- setPowerModeInternal(display, hal::PowerMode::ON);
+ setPhysicalDisplayPowerMode(display, hal::PowerMode::ON);
}
if (display->getPhysicalId() == mActiveDisplayId) {
@@ -4320,20 +4356,19 @@
std::move(displayInfos),
ftl::to_underlying(vsyncId),
frameTime.ns()},
- std::move(
- inputWindowCommands.windowInfosReportedListeners),
+ std::move(inputWindowCommands.releaseListeners()),
/* forceImmediateCall= */ visibleWindowsChanged ||
- !inputWindowCommands.focusRequests.empty());
+ !inputWindowCommands.getFocusRequests().empty());
} else {
// If there are listeners but no changes to input windows, call the listeners
// immediately.
- for (const auto& listener : inputWindowCommands.windowInfosReportedListeners) {
+ for (const auto& listener : inputWindowCommands.getListeners()) {
if (IInterface::asBinder(listener)->isBinderAlive()) {
listener->onWindowInfosReported();
}
}
}
- for (const auto& focusRequest : inputWindowCommands.focusRequests) {
+ for (const auto& focusRequest : inputWindowCommands.getFocusRequests()) {
inputFlinger->setFocusedWindow(focusRequest);
}
}});
@@ -5060,16 +5095,16 @@
mBufferCountTracker.increment(resolvedState.layerId);
}
if (resolvedState.state.what & layer_state_t::eReparent) {
- resolvedState.parentId =
- getLayerIdFromSurfaceControl(resolvedState.state.parentSurfaceControlForChild);
+ resolvedState.parentId = getLayerIdFromSurfaceControl(
+ resolvedState.state.getParentSurfaceControlForChild());
}
if (resolvedState.state.what & layer_state_t::eRelativeLayerChanged) {
- resolvedState.relativeParentId =
- getLayerIdFromSurfaceControl(resolvedState.state.relativeLayerSurfaceControl);
+ resolvedState.relativeParentId = getLayerIdFromSurfaceControl(
+ resolvedState.state.getRelativeLayerSurfaceControl());
}
if (resolvedState.state.what & layer_state_t::eInputInfoChanged) {
wp<IBinder>& touchableRegionCropHandle =
- resolvedState.state.windowInfoHandle->editInfo()->touchableRegionCropHandle;
+ resolvedState.state.editWindowInfo()->touchableRegionCropHandle;
resolvedState.touchCropId =
LayerHandle::getLayerId(touchableRegionCropHandle.promote());
}
@@ -5628,7 +5663,7 @@
// In case of a restart, ensure all displays are off.
for (const auto& [id, display] : mPhysicalDisplays) {
- setPowerModeInternal(getDisplayDeviceLocked(id), hal::PowerMode::OFF);
+ setPhysicalDisplayPowerMode(getDisplayDeviceLocked(id), hal::PowerMode::OFF);
}
// Power on all displays. The primary display is first, so becomes the active display. Also,
@@ -5637,13 +5672,14 @@
// Additionally, do not turn on displays if the boot should be quiescent.
if (!mSkipPowerOnForQuiescent) {
for (const auto& [id, display] : mPhysicalDisplays) {
- setPowerModeInternal(getDisplayDeviceLocked(id), hal::PowerMode::ON);
+ setPhysicalDisplayPowerMode(getDisplayDeviceLocked(id), hal::PowerMode::ON);
}
}
}
}
-void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
+void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& display,
+ hal::PowerMode mode) {
if (display->isVirtual()) {
// TODO(b/241285876): This code path should not be reachable, so enforce this at compile
// time.
@@ -5652,7 +5688,7 @@
}
const auto displayId = display->getPhysicalId();
- ALOGD("Setting power mode %d on display %s", mode, to_string(displayId).c_str());
+ ALOGD("Setting power mode %d on physical display %s", mode, to_string(displayId).c_str());
const auto currentMode = display->getPowerMode();
if (currentMode == mode) {
@@ -5695,15 +5731,10 @@
}
if (displayId == mActiveDisplayId) {
- // TODO(b/281692563): Merge the syscalls. For now, keep uclamp in a separate syscall and
- // set it before SCHED_FIFO due to b/190237315.
- if (setSchedAttr(true) != NO_ERROR) {
- ALOGW("Failed to set uclamp.min after powering on active display: %s",
- strerror(errno));
- }
- if (setSchedFifo(true) != NO_ERROR) {
- ALOGW("Failed to set SCHED_FIFO after powering on active display: %s",
- strerror(errno));
+ if (FlagManager::getInstance().correct_virtual_display_power_state()) {
+ applyOptimizationPolicy("setPhysicalDisplayPowerMode(ON)");
+ } else {
+ disablePowerOptimizations("setPhysicalDisplayPowerMode(ON)");
}
}
@@ -5731,13 +5762,10 @@
if (const auto display = getActivatableDisplay()) {
onActiveDisplayChangedLocked(activeDisplay.get(), *display);
} else {
- if (setSchedFifo(false) != NO_ERROR) {
- ALOGW("Failed to set SCHED_OTHER after powering off active display: %s",
- strerror(errno));
- }
- if (setSchedAttr(false) != NO_ERROR) {
- ALOGW("Failed set uclamp.min after powering off active display: %s",
- strerror(errno));
+ if (FlagManager::getInstance().correct_virtual_display_power_state()) {
+ applyOptimizationPolicy("setPhysicalDisplayPowerMode(OFF)");
+ } else {
+ enablePowerOptimizations("setPhysicalDisplayPowerMode(OFF)");
}
if (currentModeNotDozeSuspend) {
@@ -5799,21 +5827,96 @@
mScheduler->setDisplayPowerMode(displayId, mode);
- ALOGD("Finished setting power mode %d on display %s", mode, to_string(displayId).c_str());
+ ALOGD("Finished setting power mode %d on physical display %s", mode,
+ to_string(displayId).c_str());
+}
+
+void SurfaceFlinger::setVirtualDisplayPowerMode(const sp<DisplayDevice>& display,
+ hal::PowerMode mode) {
+ if (!display->isVirtual()) {
+ ALOGE("%s: Invalid operation on physical display", __func__);
+ return;
+ }
+
+ const auto displayId = display->getVirtualId();
+ ALOGD("Setting power mode %d on virtual display %s %s", mode, to_string(displayId).c_str(),
+ display->getDisplayName().c_str());
+
+ display->setPowerMode(static_cast<hal::PowerMode>(mode));
+
+ applyOptimizationPolicy(__func__);
+
+ ALOGD("Finished setting power mode %d on virtual display %s", mode,
+ 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);
+
+ // 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);
+}
+
+void SurfaceFlinger::applyOptimizationPolicy(const char* whence) {
+ if (shouldOptimizeForPerformance()) {
+ disablePowerOptimizations(whence);
+ } else {
+ enablePowerOptimizations(whence);
+ }
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
- auto future = mScheduler->schedule([=, this]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(
- kMainThreadContext) {
+ auto future = mScheduler->schedule([=, this]() FTL_FAKE_GUARD(kMainThreadContext) {
mSkipPowerOnForQuiescent = false;
- const auto display = getDisplayDeviceLocked(displayToken);
+ const auto display = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(displayToken));
if (!display) {
- ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
- displayToken.get());
+ Mutex::Autolock lock(mStateLock);
+ const ssize_t index = mCurrentState.displays.indexOfKey(displayToken);
+ if (index >= 0) {
+ auto& state = mCurrentState.displays.editValueFor(displayToken);
+ if (state.isVirtual()) {
+ ALOGD("Setting power mode %d for a dormant virtual display with token %p", mode,
+ displayToken.get());
+ state.initialPowerMode = static_cast<hal::PowerMode>(mode);
+ return;
+ }
+ }
+ ALOGE("Failed to set power mode %d for display token %p", mode, displayToken.get());
} else if (display->isVirtual()) {
- ALOGW("Attempt to set power mode %d for virtual display", mode);
+ if (FlagManager::getInstance().correct_virtual_display_power_state()) {
+ ftl::FakeGuard guard(mStateLock);
+ setVirtualDisplayPowerMode(display, static_cast<hal::PowerMode>(mode));
+ } else {
+ ALOGW("Attempt to set power mode %d for virtual display", mode);
+ }
} else {
- setPowerModeInternal(display, static_cast<hal::PowerMode>(mode));
+ ftl::FakeGuard guard(mStateLock);
+ setPhysicalDisplayPowerMode(display, static_cast<hal::PowerMode>(mode));
}
});
@@ -7201,7 +7304,7 @@
return PERMISSION_DENIED;
}
-status_t SurfaceFlinger::setSchedFifo(bool enabled) {
+void SurfaceFlinger::setSchedFifo(bool enabled, const char* whence) {
static constexpr int kFifoPriority = 2;
static constexpr int kOtherPriority = 0;
@@ -7216,19 +7319,19 @@
}
if (sched_setscheduler(0, sched_policy, ¶m) != 0) {
- return -errno;
+ const char* kPolicy[] = {"SCHED_OTHER", "SCHED_FIFO"};
+ ALOGW("%s: Failed to set %s: %s", whence, kPolicy[sched_policy == SCHED_FIFO],
+ strerror(errno));
}
-
- return NO_ERROR;
}
-status_t SurfaceFlinger::setSchedAttr(bool enabled) {
+void SurfaceFlinger::setSchedAttr(bool enabled, const char* whence) {
static const unsigned int kUclampMin =
base::GetUintProperty<unsigned int>("ro.surface_flinger.uclamp.min"s, 0U);
if (!kUclampMin) {
// uclamp.min set to 0 (default), skip setting
- return NO_ERROR;
+ return;
}
sched_attr attr = {};
@@ -7239,10 +7342,9 @@
attr.sched_util_max = 1024;
if (syscall(__NR_sched_setattr, 0, &attr, 0)) {
- return -errno;
+ const char* kAction[] = {"disable", "enable"};
+ ALOGW("%s: Failed to %s uclamp.min: %s", whence, kAction[enabled], strerror(errno));
}
-
- return NO_ERROR;
}
namespace {
@@ -7823,15 +7925,16 @@
// Otherwise for seamless transitions it's important to match the current
// display state as the buffer will be shown under these same conditions, and we
// want to avoid any flickers.
- if (captureResults.capturedHdrLayers && !enableLocalTonemapping &&
- args.sdrWhitePointNits > 1.0f && !args.seamlessTransition) {
- // Restrict the amount of HDR "headroom" in the screenshot to avoid
- // over-dimming the SDR portion. 2.0 chosen by experimentation
- constexpr float kMaxScreenshotHeadroom = 2.0f;
- // TODO: Aim to update displayBrightnessNits earlier in screenshot
- // path so ScreenshotArgs can be passed as const
- args.displayBrightnessNits = std::min(args.sdrWhitePointNits * kMaxScreenshotHeadroom,
- args.displayBrightnessNits);
+ if (captureResults.capturedHdrLayers) {
+ if (!enableLocalTonemapping && args.sdrWhitePointNits > 1.0f && !args.seamlessTransition) {
+ // Restrict the amount of HDR "headroom" in the screenshot to avoid
+ // over-dimming the SDR portion. 2.0 chosen by experimentation
+ constexpr float kMaxScreenshotHeadroom = 2.0f;
+ // TODO: Aim to update displayBrightnessNits earlier in screenshot
+ // path so ScreenshotArgs can be passed as const
+ args.displayBrightnessNits = std::min(args.sdrWhitePointNits * kMaxScreenshotHeadroom,
+ args.displayBrightnessNits);
+ }
} else {
args.displayBrightnessNits = args.sdrWhitePointNits;
}
@@ -8239,11 +8342,13 @@
int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate,
std::chrono::nanoseconds presentLatency) {
- auto pipelineDepth = presentLatency.count() / refreshRate.getPeriodNsecs();
+ int64_t pipelineDepth = presentLatency.count() / refreshRate.getPeriodNsecs();
if (presentLatency.count() % refreshRate.getPeriodNsecs()) {
pipelineDepth++;
}
- return std::max(minAcquiredBuffers, static_cast<int64_t>(pipelineDepth - 1));
+ const int64_t maxAcquiredBuffers =
+ std::min(pipelineDepth - 1, maxAcquiredBuffersOpt.value_or(pipelineDepth - 1));
+ return std::max(minAcquiredBuffers, maxAcquiredBuffers);
}
status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const {
@@ -8361,10 +8466,6 @@
void SurfaceFlinger::updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t connectedLevel,
int32_t maxLevel) {
- if (!FlagManager::getInstance().connected_display()) {
- return;
- }
-
Mutex::Autolock lock(mStateLock);
const auto idOpt = getHwComposer().toPhysicalDisplayId(hwcDisplayId);
@@ -8748,16 +8849,16 @@
}
}
-binder::Status SurfaceComposerAIDL::createVirtualDisplay(const std::string& displayName,
- bool isSecure, const std::string& uniqueId,
- float requestedRefreshRate,
- sp<IBinder>* outDisplay) {
+binder::Status SurfaceComposerAIDL::createVirtualDisplay(
+ const std::string& displayName, bool isSecure,
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy, const std::string& uniqueId,
+ float requestedRefreshRate, sp<IBinder>* outDisplay) {
status_t status = checkAccessPermission();
if (status != OK) {
return binderStatusFromStatusT(status);
}
- *outDisplay =
- mFlinger->createVirtualDisplay(displayName, isSecure, uniqueId, requestedRefreshRate);
+ *outDisplay = mFlinger->createVirtualDisplay(displayName, isSecure, optimizationPolicy,
+ uniqueId, requestedRefreshRate);
return binder::Status::ok();
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3f454ba..37f362f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -211,11 +211,9 @@
SurfaceFlinger(surfaceflinger::Factory&, SkipInitializationTag) ANDROID_API;
explicit SurfaceFlinger(surfaceflinger::Factory&) ANDROID_API;
- // set main thread scheduling policy
- static status_t setSchedFifo(bool enabled) ANDROID_API;
-
- // set main thread scheduling attributes
- static status_t setSchedAttr(bool enabled);
+ // Set scheduling policy and attributes of main thread.
+ static void setSchedFifo(bool enabled, const char* whence);
+ static void setSchedAttr(bool enabled, const char* whence);
static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; }
@@ -240,6 +238,11 @@
// ISurfaceComposer.getMaxAcquiredBufferCount().
static int64_t minAcquiredBuffers;
+ // Controls the maximum acquired buffers SurfaceFlinger will suggest via
+ // ISurfaceComposer.getMaxAcquiredBufferCount().
+ // Value is set through ro.surface_flinger.max_acquired_buffers.
+ static std::optional<int64_t> maxAcquiredBuffersOpt;
+
// Controls the maximum width and height in pixels that the graphics pipeline can support for
// GPU fallback composition. For example, 8k devices with 4k GPUs, or 4k devices with 2k GPUs.
static uint32_t maxGraphicsWidth;
@@ -531,6 +534,7 @@
// ISurfaceComposer implementation:
sp<IBinder> createVirtualDisplay(const std::string& displayName, bool isSecure,
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy,
const std::string& uniqueId,
float requestedRefreshRate = 0.0f);
status_t destroyVirtualDisplay(const sp<IBinder>& displayToken);
@@ -729,8 +733,24 @@
void applyActiveMode(PhysicalDisplayId) REQUIRES(kMainThreadContext);
// Called on the main thread in response to setPowerMode()
- void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
+ void setPhysicalDisplayPowerMode(const sp<DisplayDevice>& display, hal::PowerMode mode)
REQUIRES(mStateLock, kMainThreadContext);
+ 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);
+
+ // Enables or disables power optimizations depending on whether there are displays that should
+ // be optimized for performance.
+ void applyOptimizationPolicy(const char* whence) 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.
@@ -1067,7 +1087,8 @@
// Returns the active mode ID, or nullopt on hotplug failure.
std::optional<DisplayModeId> processHotplugConnect(PhysicalDisplayId, hal::HWDisplayId,
DisplayIdentificationInfo&&,
- const char* displayString)
+ const char* displayString,
+ HWComposer::HotplugEvent event)
REQUIRES(mStateLock, kMainThreadContext);
void processHotplugDisconnect(PhysicalDisplayId, const char* displayString)
REQUIRES(mStateLock, kMainThreadContext);
@@ -1564,9 +1585,11 @@
const sp<IBinder>& layerHandle,
sp<gui::IDisplayEventConnection>* outConnection) override;
binder::Status createConnection(sp<gui::ISurfaceComposerClient>* outClient) override;
- binder::Status createVirtualDisplay(const std::string& displayName, bool isSecure,
- const std::string& uniqueId, float requestedRefreshRate,
- sp<IBinder>* outDisplay) override;
+ binder::Status createVirtualDisplay(
+ const std::string& displayName, bool isSecure,
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy,
+ const std::string& uniqueId, float requestedRefreshRate,
+ sp<IBinder>* outDisplay) override;
binder::Status destroyVirtualDisplay(const sp<IBinder>& displayToken) override;
binder::Status getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) override;
binder::Status getPhysicalDisplayToken(int64_t displayId, sp<IBinder>* outDisplay) override;
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 2676ca6..3297c16 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -139,7 +139,8 @@
colorProto->set_b(layer.color.b);
}
if (layer.what & layer_state_t::eTransparentRegionChanged) {
- LayerProtoHelper::writeToProto(layer.transparentRegion, proto.mutable_transparent_region());
+ LayerProtoHelper::writeToProto(layer.getTransparentRegion(),
+ proto.mutable_transparent_region());
}
if (layer.what & layer_state_t::eBufferTransformChanged) {
proto.set_transform(layer.bufferTransform);
@@ -191,33 +192,30 @@
}
if (layer.what & layer_state_t::eInputInfoChanged) {
- if (layer.windowInfoHandle) {
- const gui::WindowInfo* inputInfo = layer.windowInfoHandle->getInfo();
- perfetto::protos::LayerState_WindowInfo* windowInfoProto =
- proto.mutable_window_info_handle();
- windowInfoProto->set_layout_params_flags(inputInfo->layoutParamsFlags.get());
- windowInfoProto->set_layout_params_type(
- static_cast<int32_t>(inputInfo->layoutParamsType));
- windowInfoProto->set_input_config(inputInfo->inputConfig.get());
- LayerProtoHelper::writeToProto(inputInfo->touchableRegion,
- windowInfoProto->mutable_touchable_region());
- windowInfoProto->set_surface_inset(inputInfo->surfaceInset);
- windowInfoProto->set_focusable(
- !inputInfo->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE));
- windowInfoProto->set_has_wallpaper(inputInfo->inputConfig.test(
- gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
- windowInfoProto->set_global_scale_factor(inputInfo->globalScaleFactor);
- perfetto::protos::Transform* transformProto = windowInfoProto->mutable_transform();
- transformProto->set_dsdx(inputInfo->transform.dsdx());
- transformProto->set_dtdx(inputInfo->transform.dtdx());
- transformProto->set_dtdy(inputInfo->transform.dtdy());
- transformProto->set_dsdy(inputInfo->transform.dsdy());
- transformProto->set_tx(inputInfo->transform.tx());
- transformProto->set_ty(inputInfo->transform.ty());
- windowInfoProto->set_replace_touchable_region_with_crop(
- inputInfo->replaceTouchableRegionWithCrop);
- windowInfoProto->set_crop_layer_id(resolvedComposerState.touchCropId);
- }
+ const gui::WindowInfo* inputInfo = &layer.getWindowInfo();
+ perfetto::protos::LayerState_WindowInfo* windowInfoProto =
+ proto.mutable_window_info_handle();
+ windowInfoProto->set_layout_params_flags(inputInfo->layoutParamsFlags.get());
+ windowInfoProto->set_layout_params_type(static_cast<int32_t>(inputInfo->layoutParamsType));
+ windowInfoProto->set_input_config(inputInfo->inputConfig.get());
+ LayerProtoHelper::writeToProto(inputInfo->touchableRegion,
+ windowInfoProto->mutable_touchable_region());
+ windowInfoProto->set_surface_inset(inputInfo->surfaceInset);
+ windowInfoProto->set_focusable(
+ !inputInfo->inputConfig.test(gui::WindowInfo::InputConfig::NOT_FOCUSABLE));
+ windowInfoProto->set_has_wallpaper(inputInfo->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER));
+ windowInfoProto->set_global_scale_factor(inputInfo->globalScaleFactor);
+ perfetto::protos::Transform* transformProto = windowInfoProto->mutable_transform();
+ transformProto->set_dsdx(inputInfo->transform.dsdx());
+ transformProto->set_dtdx(inputInfo->transform.dtdx());
+ transformProto->set_dtdy(inputInfo->transform.dtdy());
+ transformProto->set_dsdy(inputInfo->transform.dsdy());
+ transformProto->set_tx(inputInfo->transform.tx());
+ transformProto->set_ty(inputInfo->transform.ty());
+ windowInfoProto->set_replace_touchable_region_with_crop(
+ inputInfo->replaceTouchableRegionWithCrop);
+ windowInfoProto->set_crop_layer_id(resolvedComposerState.touchCropId);
}
if (layer.what & layer_state_t::eBackgroundColorChanged) {
proto.set_bg_color_alpha(layer.bgColor.a);
@@ -410,7 +408,9 @@
layer.color.b = colorProto.b();
}
if (proto.what() & layer_state_t::eTransparentRegionChanged) {
- LayerProtoHelper::readFromProto(proto.transparent_region(), layer.transparentRegion);
+ Region transparentRegion;
+ LayerProtoHelper::readFromProto(proto.transparent_region(), transparentRegion);
+ layer.updateTransparentRegion(transparentRegion);
}
if (proto.what() & layer_state_t::eBufferTransformChanged) {
layer.bufferTransform = proto.transform();
@@ -486,7 +486,7 @@
windowInfoProto.replace_touchable_region_with_crop();
resolvedComposerState.touchCropId = windowInfoProto.crop_layer_id();
- layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
+ *layer.editWindowInfo() = inputInfo;
}
if (proto.what() & layer_state_t::eBackgroundColorChanged) {
layer.bgColor.a = proto.bg_color_alpha();
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index 5cf4244..84d837c 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -102,11 +102,10 @@
QueuedTransactionState transaction = parser.fromProto(entry.transactions(j));
for (auto& resolvedComposerState : transaction.states) {
if (resolvedComposerState.state.what & layer_state_t::eInputInfoChanged) {
- if (!resolvedComposerState.state.windowInfoHandle->getInfo()->inputConfig.test(
+ if (!resolvedComposerState.state.getWindowInfo().inputConfig.test(
gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL)) {
// create a fake token since the FE expects a valid token
- resolvedComposerState.state.windowInfoHandle->editInfo()->token =
- sp<BBinder>::make();
+ resolvedComposerState.state.editWindowInfo()->token = sp<BBinder>::make();
}
}
}
diff --git a/services/surfaceflinger/common/Android.bp b/services/surfaceflinger/common/Android.bp
index 8786f6e..13f6577 100644
--- a/services/surfaceflinger/common/Android.bp
+++ b/services/surfaceflinger/common/Android.bp
@@ -16,9 +16,9 @@
],
shared_libs: [
"libSurfaceFlingerProp",
- "server_configurable_flags",
"libaconfig_storage_read_api_cc",
"libtracing_perfetto",
+ "server_configurable_flags",
],
static_libs: [
"librenderengine_includes",
@@ -37,11 +37,12 @@
"libsurfaceflinger_common_defaults",
],
static_libs: [
- "libsurfaceflingerflags",
"aconfig_hardware_flags_c_lib",
+ "android.companion.virtualdevice.flags-aconfig-cc",
"android.os.flags-aconfig-cc",
"android.server.display.flags-aconfig-cc",
"libguiflags_no_apex",
+ "libsurfaceflingerflags",
],
}
@@ -51,44 +52,47 @@
"libsurfaceflinger_common_defaults",
],
static_libs: [
- "libsurfaceflingerflags_test",
"aconfig_hardware_flags_c_lib",
+ "android.companion.virtualdevice.flags-aconfig-cc",
"android.os.flags-aconfig-cc-test",
"android.server.display.flags-aconfig-cc",
"libguiflags_no_apex",
+ "libsurfaceflingerflags_test",
],
}
cc_defaults {
name: "libsurfaceflinger_common_deps",
shared_libs: [
- "server_configurable_flags",
"libaconfig_storage_read_api_cc",
"libtracing_perfetto",
+ "server_configurable_flags",
],
static_libs: [
- "libsurfaceflinger_common",
- "libsurfaceflingerflags",
"aconfig_hardware_flags_c_lib",
+ "android.companion.virtualdevice.flags-aconfig-cc",
"android.os.flags-aconfig-cc",
"android.server.display.flags-aconfig-cc",
"libguiflags_no_apex",
+ "libsurfaceflinger_common",
+ "libsurfaceflingerflags",
],
}
cc_defaults {
name: "libsurfaceflinger_common_test_deps",
shared_libs: [
- "server_configurable_flags",
"libaconfig_storage_read_api_cc",
"libtracing_perfetto",
+ "server_configurable_flags",
],
static_libs: [
- "libsurfaceflinger_common_test",
- "libsurfaceflingerflags_test",
"aconfig_hardware_flags_c_lib",
+ "android.companion.virtualdevice.flags-aconfig-cc",
"android.os.flags-aconfig-cc-test",
"android.server.display.flags-aconfig-cc",
"libguiflags_no_apex",
+ "libsurfaceflinger_common_test",
+ "libsurfaceflingerflags_test",
],
}
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index abde524..42fa436 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -26,8 +26,9 @@
#include <server_configurable_flags/get_flags.h>
#include <cinttypes>
-#include <android_os.h>
+#include <android_companion_virtualdevice_flags.h>
#include <android_hardware_flags.h>
+#include <android_os.h>
#include <com_android_graphics_libgui_flags.h>
#include <com_android_graphics_surfaceflinger_flags.h>
#include <com_android_server_display_feature_flags.h>
@@ -125,6 +126,7 @@
DUMP_ACONFIG_FLAG(adpf_gpu_sf);
DUMP_ACONFIG_FLAG(adpf_native_session_manager);
DUMP_ACONFIG_FLAG(adpf_use_fmq_channel);
+ DUMP_ACONFIG_FLAG(correct_virtual_display_power_state);
DUMP_ACONFIG_FLAG(graphite_renderengine_preview_rollout);
DUMP_ACONFIG_FLAG(increase_missed_frame_jank_threshold);
DUMP_ACONFIG_FLAG(refresh_rate_overlay_on_external_display);
@@ -139,7 +141,6 @@
DUMP_ACONFIG_FLAG(begone_bright_hlg);
DUMP_ACONFIG_FLAG(cache_when_source_crop_layer_only_moved);
DUMP_ACONFIG_FLAG(commit_not_composited);
- DUMP_ACONFIG_FLAG(connected_display);
DUMP_ACONFIG_FLAG(connected_display_hdr);
DUMP_ACONFIG_FLAG(correct_dpi_with_display_size);
DUMP_ACONFIG_FLAG(deprecate_frame_tracker);
@@ -252,7 +253,6 @@
/// Trunk stable readonly flags ///
FLAG_MANAGER_ACONFIG_FLAG(adpf_fmq_sf, "")
FLAG_MANAGER_ACONFIG_FLAG(arr_setframerate_gte_enum, "debug.sf.arr_setframerate_gte_enum")
-FLAG_MANAGER_ACONFIG_FLAG(connected_display, "")
FLAG_MANAGER_ACONFIG_FLAG(enable_small_area_detection, "")
FLAG_MANAGER_ACONFIG_FLAG(stable_edid_ids, "debug.sf.stable_edid_ids")
FLAG_MANAGER_ACONFIG_FLAG(frame_rate_category_mrr, "debug.sf.frame_rate_category_mrr")
@@ -309,6 +309,8 @@
/// Trunk stable server (R/W) flags from outside SurfaceFlinger ///
FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(adpf_use_fmq_channel, "", android::os)
+FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(correct_virtual_display_power_state, "",
+ android::companion::virtualdevice::flags)
/// Trunk stable readonly flags from outside SurfaceFlinger ///
FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(idle_screen_refresh_rate_timeout, "",
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 6295c5b..dd7042d 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -60,6 +60,7 @@
bool adpf_native_session_manager() const;
bool adpf_use_fmq_channel() const;
bool adpf_use_fmq_channel_fixed() const;
+ bool correct_virtual_display_power_state() const;
bool graphite_renderengine_preview_rollout() const;
bool increase_missed_frame_jank_threshold() const;
bool refresh_rate_overlay_on_external_display() const;
@@ -74,7 +75,6 @@
bool begone_bright_hlg() const;
bool cache_when_source_crop_layer_only_moved() const;
bool commit_not_composited() const;
- bool connected_display() const;
bool connected_display_hdr() const;
bool correct_dpi_with_display_size() const;
bool deprecate_frame_tracker() const;
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 73dfa9f..4afcd00 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -77,7 +77,7 @@
}
}
-int main(int, char**) {
+int main() {
signal(SIGPIPE, SIG_IGN);
hardware::configureRpcThreadpool(1 /* maxThreads */,
@@ -91,9 +91,7 @@
// Set uclamp.min setting on all threads, maybe an overkill but we want
// to cover important threads like RenderEngine.
- if (SurfaceFlinger::setSchedAttr(true) != NO_ERROR) {
- ALOGW("Failed to set uclamp.min during boot: %s", strerror(errno));
- }
+ SurfaceFlinger::setSchedAttr(true, __func__);
// The binder threadpool we start will inherit sched policy and priority
// of (this) creating thread. We want the binder thread pool to have
@@ -160,14 +158,8 @@
startDisplayService(); // dependency on SF getting registered above
- if (SurfaceFlinger::setSchedFifo(true) != NO_ERROR) {
- ALOGW("Failed to set SCHED_FIFO during boot: %s", strerror(errno));
- }
-
- // run surface flinger in this thread
+ SurfaceFlinger::setSchedFifo(true, __func__);
flinger->run();
-
- return 0;
}
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 0ad5ac9..bfafb65 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -483,6 +483,16 @@
prop_name: "ro.surface_flinger.min_acquired_buffers"
}
+# Defines the maximum acquired buffers SurfaceFlinger will suggest via
+# ISurfaceComposer.getMaxAcquiredBufferCount().
+prop {
+ api_name: "max_acquired_buffers"
+ type: Long
+ scope: Public
+ access: Readonly
+ prop_name: "ro.surface_flinger.max_acquired_buffers"
+}
+
# When enabled, SurfaceFlinger will attempt to clear the per-layer HAL buffer cache slots for
# buffers when they are evicted from the app cache by using additional setLayerBuffer commands.
# Ideally, this behavior would always be enabled to reduce graphics memory consumption. However,
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index 0017300..e2ac233 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -82,6 +82,11 @@
prop_name: "ro.surface_flinger.ignore_hdr_camera_layers"
}
prop {
+ api_name: "max_acquired_buffers"
+ type: Long
+ prop_name: "ro.surface_flinger.max_acquired_buffers"
+ }
+ prop {
api_name: "max_frame_buffer_acquired_buffers"
type: Long
prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers"
diff --git a/services/surfaceflinger/tests/AndroidTest.xml b/services/surfaceflinger/tests/AndroidTest.xml
index 000628f..ad43cdc 100644
--- a/services/surfaceflinger/tests/AndroidTest.xml
+++ b/services/surfaceflinger/tests/AndroidTest.xml
@@ -19,6 +19,9 @@
<option name="push" value="SurfaceFlinger_test->/data/local/tmp/SurfaceFlinger_test" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="screen-always-on" value="on" />
+ </target_preparer>
<option name="test-suite-tag" value="apct" />
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index c95c875..c91f1ea 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -48,7 +48,11 @@
ui::DisplayMode displayMode;
SurfaceComposerClient::getActiveDisplayMode(displayToken, &displayMode);
- const ui::Size& resolution = displayMode.resolution;
+ ui::Size resolution = displayMode.resolution;
+ if (displayState.orientation == ui::Rotation::Rotation90 ||
+ displayState.orientation == ui::Rotation::Rotation270) {
+ std::swap(resolution.width, resolution.height);
+ }
sp<IBinder> vDisplay;
@@ -93,8 +97,8 @@
#else
t.setDisplaySurface(vDisplay, producer);
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- t.setDisplayProjection(vDisplay, displayState.orientation,
- Rect(displayState.layerStackSpaceRect), Rect(resolution));
+ t.setDisplayProjection(vDisplay, ui::Rotation::Rotation0, Rect(resolution),
+ Rect(resolution));
t.setDisplayLayerStack(vDisplay, layerStack);
t.setLayerStack(mirrorSc, layerStack);
t.apply();
diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
index 7910e77..82390ac 100644
--- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
+++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
@@ -265,9 +265,8 @@
transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.windowInfoHandle =
- sp<gui::WindowInfoHandle>::make();
- auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
+ auto inputInfo = transactions.back().states.front().state.editWindowInfo();
+ *inputInfo = {};
inputInfo->touchableRegion = region;
inputInfo->token = sp<BBinder>::make();
mLifecycleManager.applyTransactions(transactions);
@@ -280,9 +279,8 @@
transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.windowInfoHandle =
- sp<gui::WindowInfoHandle>::make();
- auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
+ auto inputInfo = transactions.back().states.front().state.editWindowInfo();
+ *inputInfo = {};
if (!inputInfo->token) {
inputInfo->token = sp<BBinder>::make();
}
@@ -299,9 +297,8 @@
transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.windowInfoHandle =
- sp<gui::WindowInfoHandle>::make();
- auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
+ auto inputInfo = transactions.back().states.front().state.editWindowInfo();
+ *inputInfo = {};
inputInfo->touchableRegion = region;
inputInfo->replaceTouchableRegionWithCrop = replaceTouchableRegionWithCrop;
transactions.back().states.front().touchCropId = touchCropId;
@@ -455,9 +452,8 @@
transactions.emplace_back();
transactions.back().states.push_back({});
- transactions.back().states.front().state.what = layer_state_t::eSurfaceDamageRegionChanged;
transactions.back().states.front().layerId = id;
- transactions.back().states.front().state.surfaceDamageRegion = damageRegion;
+ transactions.back().states.front().state.updateSurfaceDamageRegion(damageRegion);
mLifecycleManager.applyTransactions(transactions);
}
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 9ece312..c342e1e 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -468,7 +468,7 @@
layer.externalTexture = buffer;
layer.bufferData->acquireFence = Fence::NO_FENCE;
layer.dataspace = ui::Dataspace::UNKNOWN;
- layer.surfaceDamageRegion = Region(Rect(LayerProperties::HEIGHT, LayerProperties::WIDTH));
+ layer.setSurfaceDamageRegion(Region(Rect(LayerProperties::HEIGHT, LayerProperties::WIDTH)));
Mock::VerifyAndClear(test->mRenderEngine);
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 7f9296f..4322af7 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -114,7 +114,11 @@
// Test instances
TestableSurfaceFlinger mFlinger;
+
sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make();
+ sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
+ sp<compositionengine::mock::DisplaySurface>::make();
+
sp<GraphicBuffer> mBuffer =
sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888,
GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN);
@@ -294,6 +298,7 @@
injector.setSecure(static_cast<bool>(SECURE));
injector.setNativeWindow(test->mNativeWindow);
+ injector.setDisplaySurface(test->mDisplaySurface);
// Creating a DisplayDevice requires getting default dimensions from the
// native window along with some other initial setup.
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index d29e441..07356b9 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -1676,8 +1676,8 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
transactions.back().states.front().layerId = 3;
- transactions.back().states.front().state.windowInfoHandle = sp<gui::WindowInfoHandle>::make();
- auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
+ auto inputInfo = transactions.back().states.front().state.editWindowInfo();
+ *inputInfo = {};
inputInfo->token = sp<BBinder>::make();
mLifecycleManager.applyTransactions(transactions);
@@ -1705,8 +1705,8 @@
transactions.back().states.push_back({});
transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
transactions.back().states.front().layerId = 3;
- transactions.back().states.front().state.windowInfoHandle = sp<gui::WindowInfoHandle>::make();
- auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
+ auto inputInfo = transactions.back().states.front().state.editWindowInfo();
+ *inputInfo = {};
inputInfo->token = sp<BBinder>::make();
hideLayer(3);
mLifecycleManager.applyTransactions(transactions);
@@ -1913,9 +1913,6 @@
}
TEST_F(LayerSnapshotTest, edgeExtensionPropagatesInHierarchy) {
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
- }
setCrop(1, Rect(0, 0, 20, 20));
setBuffer(1221,
std::make_shared<renderengine::mock::FakeExternalTexture>(20 /* width */,
@@ -1954,9 +1951,6 @@
TEST_F(LayerSnapshotTest, leftEdgeExtensionIncreaseBoundSizeWithinCrop) {
// The left bound is extended when shifting to the right
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
- }
setCrop(1, Rect(0, 0, 20, 20));
const int texSize = 10;
setBuffer(1221,
@@ -1976,9 +1970,6 @@
TEST_F(LayerSnapshotTest, rightEdgeExtensionIncreaseBoundSizeWithinCrop) {
// The right bound is extended when shifting to the left
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
- }
const int crop = 20;
setCrop(1, Rect(0, 0, crop, crop));
const int texSize = 10;
@@ -1999,9 +1990,6 @@
TEST_F(LayerSnapshotTest, topEdgeExtensionIncreaseBoundSizeWithinCrop) {
// The top bound is extended when shifting to the bottom
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
- }
setCrop(1, Rect(0, 0, 20, 20));
const int texSize = 10;
setBuffer(1221,
@@ -2021,9 +2009,6 @@
TEST_F(LayerSnapshotTest, bottomEdgeExtensionIncreaseBoundSizeWithinCrop) {
// The bottom bound is extended when shifting to the top
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
- }
const int crop = 20;
setCrop(1, Rect(0, 0, crop, crop));
const int texSize = 10;
@@ -2044,9 +2029,6 @@
TEST_F(LayerSnapshotTest, multipleEdgeExtensionIncreaseBoundSizeWithinCrop) {
// The left bound is extended when shifting to the right
- if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
- GTEST_SKIP() << "Skipping test because edge_extension_shader is off";
- }
const int crop = 20;
setCrop(1, Rect(0, 0, crop, crop));
const int texSize = 10;
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 1fc874d..49c35e2 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -143,7 +143,7 @@
kDisplay1Mode60->getId()));
// TODO(b/241285191): Restore once VsyncSchedule::getPendingHardwareVsyncState is called by
- // Scheduler::setDisplayPowerMode rather than SF::setPowerModeInternal.
+ // Scheduler::setDisplayPowerMode rather than SF::setPhysicalDisplayPowerMode.
#if 0
// Hardware VSYNC should be disabled for newly registered displays.
EXPECT_CALL(mSchedulerCallback, requestHardwareVsync(kDisplayId2, false)).Times(1);
@@ -254,18 +254,43 @@
}
TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) {
- EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 30ms));
- EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(90_Hz, 30ms));
- EXPECT_EQ(3, mFlinger.calculateMaxAcquiredBufferCount(120_Hz, 30ms));
+ struct TestCase {
+ Fps refreshRate;
+ std::chrono::nanoseconds presentLatency;
+ int expectedBufferCount;
+ };
- EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 40ms));
+ const auto verifyTestCases = [&](std::vector<TestCase> tests) {
+ for (const auto testCase : tests) {
+ EXPECT_EQ(testCase.expectedBufferCount,
+ mFlinger.calculateMaxAcquiredBufferCount(testCase.refreshRate,
+ testCase.presentLatency));
+ }
+ };
- EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms));
+ std::vector<TestCase> testCases{{60_Hz, 30ms, 1},
+ {90_Hz, 30ms, 2},
+ {120_Hz, 30ms, 3},
+ {60_Hz, 40ms, 2},
+ {60_Hz, 10ms, 1}};
+ verifyTestCases(testCases);
const auto savedMinAcquiredBuffers = mFlinger.mutableMinAcquiredBuffers();
mFlinger.mutableMinAcquiredBuffers() = 2;
- EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms));
+ verifyTestCases({{60_Hz, 10ms, 2}});
mFlinger.mutableMinAcquiredBuffers() = savedMinAcquiredBuffers;
+
+ const auto savedMaxAcquiredBuffers = mFlinger.mutableMaxAcquiredBuffers();
+ mFlinger.mutableMaxAcquiredBuffers() = 2;
+ testCases = {{60_Hz, 30ms, 1},
+ {90_Hz, 30ms, 2},
+ {120_Hz, 30ms, 2}, // max buffers allowed is 2
+ {60_Hz, 40ms, 2},
+ {60_Hz, 10ms, 1}};
+ verifyTestCases(testCases);
+ mFlinger.mutableMaxAcquiredBuffers() = 3; // max buffers allowed is 3
+ verifyTestCases({{120_Hz, 30ms, 3}});
+ mFlinger.mutableMaxAcquiredBuffers() = savedMaxAcquiredBuffers;
}
MATCHER(Is120Hz, "") {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
index aadff76..aa5b786 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
@@ -141,7 +141,11 @@
// --------------------------------------------------------------------
// Invocation
- sp<IBinder> displayToken = mFlinger.createVirtualDisplay(kDisplayName, false, kUniqueId);
+ sp<IBinder> displayToken =
+ mFlinger.createVirtualDisplay(kDisplayName, false,
+ gui::ISurfaceComposer::OptimizationPolicy::
+ optimizeForPower,
+ kUniqueId);
// --------------------------------------------------------------------
// Postconditions
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index a506873..3f710fd 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -171,16 +171,22 @@
static constexpr DisplayModeId kModeId90{1};
static constexpr DisplayModeId kModeId120{2};
static constexpr DisplayModeId kModeId90_4K{3};
+ static constexpr DisplayModeId kModeId60_8K{4};
static inline const DisplayModePtr kMode60 = createDisplayMode(kModeId60, 60_Hz, 0);
static inline const DisplayModePtr kMode90 = createDisplayMode(kModeId90, 90_Hz, 1);
static inline const DisplayModePtr kMode120 = createDisplayMode(kModeId120, 120_Hz, 2);
static constexpr ui::Size kResolution4K{3840, 2160};
+ static constexpr ui::Size kResolution8K{7680, 4320};
+
static inline const DisplayModePtr kMode90_4K =
createDisplayMode(kModeId90_4K, 90_Hz, 3, kResolution4K);
+ static inline const DisplayModePtr kMode60_8K =
+ createDisplayMode(kModeId60_8K, 60_Hz, 4, kResolution8K);
- static inline const DisplayModes kModes = makeModes(kMode60, kMode90, kMode120, kMode90_4K);
+ static inline const DisplayModes kModes =
+ makeModes(kMode60, kMode90, kMode120, kMode90_4K, kMode60_8K);
};
void DisplayModeSwitchingTest::setupScheduler(
@@ -326,6 +332,8 @@
}
TEST_F(DisplayModeSwitchingTest, changeResolutionWithoutRefreshRequired) {
+ SET_FLAG_FOR_TEST(flags::synced_resolution_switch, false);
+
EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_EQ(NO_ERROR,
@@ -360,9 +368,45 @@
EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId90_4K));
}
-TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) {
- SET_FLAG_FOR_TEST(flags::connected_display, true);
+TEST_F(DisplayModeSwitchingTest, changeResolutionSynced) {
+ SET_FLAG_FOR_TEST(flags::synced_resolution_switch, true);
+ EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId60));
+
+ // PrimaryDisplayVariant has a 4K size, so switch to 8K.
+ EXPECT_EQ(NO_ERROR,
+ mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
+ mock::createDisplayModeSpecs(kModeId60_8K,
+ 60_Hz)));
+
+ EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId60_8K));
+
+ // The mode should not be set until the commit that resizes the display.
+ mFlinger.commit();
+ EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId60_8K));
+ mFlinger.commit();
+ EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId60_8K));
+
+ // Set the display size to match the resolution.
+ DisplayState state;
+ state.what = DisplayState::eDisplaySizeChanged;
+ state.token = mDisplay->getDisplayToken().promote();
+ state.width = static_cast<uint32_t>(kResolution8K.width);
+ state.height = static_cast<uint32_t>(kResolution8K.height);
+
+ // The next commit should set the mode and resize the framebuffer.
+ const VsyncPeriodChangeTimeline timeline{.refreshRequired = false};
+ EXPECT_CALL(*mDisplaySurface, resizeBuffers(kResolution8K));
+ EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId60_8K);
+
+ constexpr bool kModeset = true;
+ mFlinger.setDisplayStateLocked(state);
+ mFlinger.configureAndCommit(kModeset);
+
+ EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId60_8K));
+}
+
+TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) {
const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
EXPECT_TRUE(innerDisplay->isPoweredOn());
@@ -371,8 +415,8 @@
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
- mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::OFF);
- mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::ON);
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
@@ -402,8 +446,8 @@
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60));
- mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::OFF);
- mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::ON);
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60));
@@ -427,8 +471,6 @@
}
TEST_F(DisplayModeSwitchingTest, innerAndOuterDisplay) {
- SET_FLAG_FOR_TEST(flags::connected_display, true);
-
const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
EXPECT_TRUE(innerDisplay->isPoweredOn());
@@ -437,8 +479,8 @@
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
- mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::ON);
- mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::ON);
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
@@ -480,7 +522,7 @@
EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId90));
// Power off the display before the mode has been set.
- mFlinger.setPowerModeInternal(mDisplay, hal::PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mDisplay, hal::PowerMode::OFF);
const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90);
@@ -497,8 +539,6 @@
}
TEST_F(DisplayModeSwitchingTest, powerOffDuringConcurrentModeSet) {
- SET_FLAG_FOR_TEST(flags::connected_display, true);
-
const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
EXPECT_TRUE(innerDisplay->isPoweredOn());
@@ -507,8 +547,8 @@
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
- mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::ON);
- mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::ON);
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId120));
@@ -525,7 +565,7 @@
EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60));
// Power off the outer display before the mode has been set.
- mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::OFF);
const VsyncPeriodChangeTimeline timeline{.refreshRequired = true};
EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId90);
@@ -542,8 +582,8 @@
EXPECT_THAT(innerDisplay, ModeSettledTo(&dmc(), kModeId90));
EXPECT_THAT(outerDisplay, ModeSettledTo(&dmc(), kModeId60));
- mFlinger.setPowerModeInternal(innerDisplay, hal::PowerMode::OFF);
- mFlinger.setPowerModeInternal(outerDisplay, hal::PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(innerDisplay, hal::PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(outerDisplay, hal::PowerMode::ON);
EXPECT_EQ(NO_ERROR,
mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(),
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
index 19f8deb..fde2749 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_FoldableTest.cpp
@@ -38,30 +38,30 @@
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
// ...and should still be after powering on.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
}
TEST_F(FoldableTest, promotesPacesetterOnFoldUnfold) {
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
// The outer display should become the pacesetter after folding.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
// The inner display should become the pacesetter after unfolding.
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF);
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
}
TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOn) {
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
// The inner display should stay the pacesetter if both are powered on.
// TODO(b/255635821): The pacesetter should depend on the displays' refresh rates.
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
// The outer display should become the pacesetter if designated.
@@ -74,20 +74,20 @@
}
TEST_F(FoldableTest, promotesPacesetterOnConcurrentPowerOff) {
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
// The outer display should become the pacesetter if the inner display powers off.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
// The outer display should stay the pacesetter if both are powered on.
// TODO(b/255635821): The pacesetter should depend on the displays' refresh rates.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
// The inner display should become the pacesetter if the outer display powers off.
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::OFF);
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kInnerDisplayId);
}
@@ -114,8 +114,8 @@
.Times(0);
// The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to
- // ISchedulerCallback::requestHardwareVsync are expected during setPowerModeInternal.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode.
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
EXPECT_TRUE(mInnerDisplay->isPoweredOn());
EXPECT_FALSE(mOuterDisplay->isPoweredOn());
@@ -133,10 +133,10 @@
.Times(1);
// The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to
- // ISchedulerCallback::requestHardwareVsync are expected during setPowerModeInternal.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode.
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
EXPECT_FALSE(mInnerDisplay->isPoweredOn());
EXPECT_TRUE(mOuterDisplay->isPoweredOn());
@@ -154,9 +154,9 @@
.Times(1);
// The injected VsyncSchedule uses TestableScheduler::mockRequestHardwareVsync, so no calls to
- // ISchedulerCallback::requestHardwareVsync are expected during setPowerModeInternal.
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ // ISchedulerCallback::requestHardwareVsync are expected during setPhysicalDisplayPowerMode.
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
EXPECT_TRUE(mInnerDisplay->isPoweredOn());
EXPECT_TRUE(mOuterDisplay->isPoweredOn());
@@ -173,8 +173,8 @@
EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kOuterDisplayId, true))
.Times(1);
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
}
TEST_F(FoldableTest, disableVsyncOnPowerOffPacesetter) {
@@ -192,10 +192,10 @@
EXPECT_CALL(mFlinger.scheduler()->mockRequestHardwareVsync, Call(kInnerDisplayId, false))
.Times(1);
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
- mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(mOuterDisplay, PowerMode::ON);
- mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(mInnerDisplay, PowerMode::OFF);
// Other display is now the pacesetter.
ASSERT_EQ(mFlinger.scheduler()->pacesetterDisplayId(), kOuterDisplayId);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
index b0cda0f..49972b0 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp
@@ -224,8 +224,6 @@
}
TEST_F(HotplugTest, rejectsHotplugIfFailedToLoadDisplayModes) {
- SET_FLAG_FOR_TEST(flags::connected_display, true);
-
// Inject a primary display.
PrimaryDisplayVariant::injectHwcDisplay(this);
@@ -263,8 +261,6 @@
}
TEST_F(HotplugTest, rejectsHotplugOnActivePortsDuplicate) {
- SET_FLAG_FOR_TEST(flags::connected_display, true);
-
// Inject a primary display.
PrimaryDisplayVariant::injectHwcDisplay(this);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp
similarity index 88%
rename from services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
rename to services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp
index fed7b2e..f2fbbdd 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp
@@ -315,7 +315,7 @@
EventThreadNotSupportedVariant, DispSyncNotSupportedVariant,
TransitionVariant>;
-class SetPowerModeInternalTest : public DisplayTransactionTest {
+class SetPhysicalDisplayPowerModeTest : public DisplayTransactionTest {
public:
template <typename Case>
void transitionDisplayCommon();
@@ -331,7 +331,7 @@
struct PowerModeInitialVSyncEnabled<PowerMode::DOZE> : public std::true_type {};
template <typename Case>
-void SetPowerModeInternalTest::transitionDisplayCommon() {
+void SetPhysicalDisplayPowerModeTest::transitionDisplayCommon() {
// --------------------------------------------------------------------
// Preconditions
@@ -353,7 +353,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.setPowerModeInternal(display, Case::Transition::TARGET_POWER_MODE);
+ mFlinger.setPhysicalDisplayPowerMode(display, Case::Transition::TARGET_POWER_MODE);
// --------------------------------------------------------------------
// Postconditions
@@ -361,7 +361,7 @@
Case::Transition::verifyPostconditions(this);
}
-TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfNoChange) {
+TEST_F(SetPhysicalDisplayPowerModeTest, setPhysicalDisplayPowerModeDoesNothingIfNoChange) {
using Case = SimplePrimaryDisplayCase;
// --------------------------------------------------------------------
@@ -378,7 +378,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::ON);
+ mFlinger.setPhysicalDisplayPowerMode(display.mutableDisplayDevice(), PowerMode::ON);
// --------------------------------------------------------------------
// Postconditions
@@ -386,7 +386,7 @@
EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
}
-TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, setPhysicalDisplayPowerModeDoesNothingIfVirtualDisplay) {
using Case = HwcVirtualDisplayCase;
// --------------------------------------------------------------------
@@ -408,7 +408,7 @@
// --------------------------------------------------------------------
// Invocation
- mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::OFF);
+ mFlinger.setPhysicalDisplayPowerMode(display.mutableDisplayDevice(), PowerMode::OFF);
// --------------------------------------------------------------------
// Postconditions
@@ -416,88 +416,88 @@
EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOffToOnPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToOnVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOffToDozeSuspendPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToOffPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToOffVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToOffPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozePrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToDozePrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozePrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToDozePrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeToOnPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeToOnVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToOnPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToDozeSuspendPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownPrimaryDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToUnknownPrimaryDisplay) {
transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToUnknownVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOffToOnExternalDisplay) {
SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToOnVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOffToDozeSuspendExternalDisplay) {
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToOffExternalDisplay) {
SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToOffVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToOffExternalDisplay) {
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToDozeExternalDisplay) {
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozeExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToDozeExternalDisplay) {
SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeToOnExternalDisplay) {
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeToOnVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromDozeSuspendToOnExternalDisplay) {
SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToDozeSuspendExternalDisplay) {
SET_FLAG_FOR_TEST(flags::multithreaded_present, true);
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
}
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownExternalDisplay) {
+TEST_F(SetPhysicalDisplayPowerModeTest, transitionsDisplayFromOnToUnknownExternalDisplay) {
transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToUnknownVariant>>();
}
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 41f2b6e..a3ee08f 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -337,9 +337,9 @@
mFlinger->configure();
}
- void configureAndCommit() {
+ void configureAndCommit(bool modeset = false) {
configure();
- commitTransactionsLocked(eDisplayTransactionNeeded);
+ commitTransactionsLocked(eDisplayTransactionNeeded, modeset);
}
void commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime,
@@ -399,12 +399,16 @@
float requestedRefreshRate = 0.0f) {
static const std::string kTestId =
"virtual:libsurfaceflinger_unittest:TestableSurfaceFlinger";
- return mFlinger->createVirtualDisplay(displayName, isSecure, kTestId, requestedRefreshRate);
+ return mFlinger
+ ->createVirtualDisplay(displayName, isSecure,
+ gui::ISurfaceComposer::OptimizationPolicy::optimizeForPower,
+ kTestId, requestedRefreshRate);
}
auto createVirtualDisplay(const std::string& displayName, bool isSecure,
+ gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy,
const std::string& uniqueId, float requestedRefreshRate = 0.0f) {
- return mFlinger->createVirtualDisplay(displayName, isSecure, uniqueId,
+ return mFlinger->createVirtualDisplay(displayName, isSecure, optimizationPolicy, uniqueId,
requestedRefreshRate);
}
@@ -429,11 +433,14 @@
dispSurface, producer);
}
- void commitTransactionsLocked(uint32_t transactionFlags) {
+ void commitTransactionsLocked(uint32_t transactionFlags, bool modeset = false) {
Mutex::Autolock lock(mFlinger->mStateLock);
ftl::FakeGuard guard(kMainThreadContext);
mFlinger->processDisplayChangesLocked();
mFlinger->commitTransactionsLocked(transactionFlags);
+ if (modeset) {
+ mFlinger->initiateDisplayModeChanges();
+ }
}
void onComposerHalHotplugEvent(hal::HWDisplayId hwcDisplayId, DisplayHotplugEvent event) {
@@ -455,9 +462,9 @@
}
// Allow reading display state without locking, as if called on the SF main thread.
- auto setPowerModeInternal(const sp<DisplayDevice>& display,
- hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS {
- return mFlinger->setPowerModeInternal(display, mode);
+ auto setPhysicalDisplayPowerMode(const sp<DisplayDevice>& display,
+ hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->setPhysicalDisplayPowerMode(display, mode);
}
auto renderScreenImpl(const sp<DisplayDevice> display, const Rect sourceCrop,
@@ -713,6 +720,7 @@
}
auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; }
+ auto& mutableMaxAcquiredBuffers() { return SurfaceFlinger::maxAcquiredBuffersOpt; }
auto& mutableLayerSnapshotBuilder() NO_THREAD_SAFETY_ANALYSIS {
return mFlinger->mLayerSnapshotBuilder;
}
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index a221d5e..ccf6a9c 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -444,40 +444,8 @@
}
}
-TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept_withPredictorRecovery) {
- SET_FLAG_FOR_TEST(flags::vsync_predictor_recovery, true);
- std::vector<nsecs_t> const simulatedVsyncs{
- 158929578733000,
- 158929306806205, // oldest TS in ringbuffer
- 158929650879052,
- 158929661969209,
- 158929684198847,
- 158929695268171,
- 158929706370359,
- };
- auto const idealPeriod = 11111111;
- auto const expectedPeriod = 11079563;
- auto const expectedIntercept = 1335662;
-
- tracker.setDisplayModePtr(displayMode(idealPeriod));
- for (auto const& timestamp : simulatedVsyncs) {
- tracker.addVsyncTimestamp(timestamp);
- }
-
- auto [slope, intercept] = tracker.getVSyncPredictionModel();
- EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
- EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
-
- // (timePoint - oldestTS) % expectedPeriod works out to be: 894272
- // (timePoint - oldestTS) / expectedPeriod works out to be: 38.08
- auto const timePoint = 158929728723871;
- auto const prediction = tracker.nextAnticipatedVSyncTimeFrom(timePoint);
- EXPECT_THAT(prediction, Ge(timePoint));
-}
-
// See b/145667109, and comment in prod code under test.
TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) {
- SET_FLAG_FOR_TEST(flags::vsync_predictor_recovery, false);
std::vector<nsecs_t> const simulatedVsyncs{
158929578733000,
158929306806205, // oldest TS in ringbuffer
diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp
index 4735ae5..ed03cfc 100644
--- a/services/vibratorservice/Android.bp
+++ b/services/vibratorservice/Android.bp
@@ -42,14 +42,9 @@
shared_libs: [
"libbinder_ndk",
- "libhidlbase",
"liblog",
"libutils",
"android.hardware.vibrator-V3-ndk",
- "android.hardware.vibrator@1.0",
- "android.hardware.vibrator@1.1",
- "android.hardware.vibrator@1.2",
- "android.hardware.vibrator@1.3",
],
cflags: [
diff --git a/services/vibratorservice/VibratorHalController.cpp b/services/vibratorservice/VibratorHalController.cpp
index 283a5f0..302e3e1 100644
--- a/services/vibratorservice/VibratorHalController.cpp
+++ b/services/vibratorservice/VibratorHalController.cpp
@@ -18,8 +18,6 @@
#include <aidl/android/hardware/vibrator/IVibrator.h>
#include <android/binder_manager.h>
-#include <android/hardware/vibrator/1.3/IVibrator.h>
-#include <hardware/vibrator.h>
#include <utils/Log.h>
@@ -31,15 +29,10 @@
using aidl::android::hardware::vibrator::CompositePrimitive;
using aidl::android::hardware::vibrator::Effect;
using aidl::android::hardware::vibrator::EffectStrength;
+using aidl::android::hardware::vibrator::IVibrator;
using std::chrono::milliseconds;
-namespace V1_0 = android::hardware::vibrator::V1_0;
-namespace V1_1 = android::hardware::vibrator::V1_1;
-namespace V1_2 = android::hardware::vibrator::V1_2;
-namespace V1_3 = android::hardware::vibrator::V1_3;
-namespace Aidl = aidl::android::hardware::vibrator;
-
namespace android {
namespace vibrator {
@@ -53,9 +46,9 @@
return nullptr;
}
- auto serviceName = std::string(Aidl::IVibrator::descriptor) + "/default";
+ auto serviceName = std::string(IVibrator::descriptor) + "/default";
if (AServiceManager_isDeclared(serviceName.c_str())) {
- std::shared_ptr<Aidl::IVibrator> hal = Aidl::IVibrator::fromBinder(
+ std::shared_ptr<IVibrator> hal = IVibrator::fromBinder(
ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
if (hal) {
ALOGV("Successfully connected to Vibrator HAL AIDL service.");
@@ -63,30 +56,9 @@
}
}
- sp<V1_0::IVibrator> halV1_0 = V1_0::IVibrator::getService();
- if (halV1_0 == nullptr) {
- ALOGV("Vibrator HAL service not available.");
- gHalExists = false;
- return nullptr;
- }
-
- sp<V1_3::IVibrator> halV1_3 = V1_3::IVibrator::castFrom(halV1_0);
- if (halV1_3) {
- ALOGV("Successfully connected to Vibrator HAL v1.3 service.");
- return std::make_shared<HidlHalWrapperV1_3>(std::move(scheduler), halV1_3);
- }
- sp<V1_2::IVibrator> halV1_2 = V1_2::IVibrator::castFrom(halV1_0);
- if (halV1_2) {
- ALOGV("Successfully connected to Vibrator HAL v1.2 service.");
- return std::make_shared<HidlHalWrapperV1_2>(std::move(scheduler), halV1_2);
- }
- sp<V1_1::IVibrator> halV1_1 = V1_1::IVibrator::castFrom(halV1_0);
- if (halV1_1) {
- ALOGV("Successfully connected to Vibrator HAL v1.1 service.");
- return std::make_shared<HidlHalWrapperV1_1>(std::move(scheduler), halV1_1);
- }
- ALOGV("Successfully connected to Vibrator HAL v1.0 service.");
- return std::make_shared<HidlHalWrapperV1_0>(std::move(scheduler), halV1_0);
+ ALOGV("Vibrator HAL service not available.");
+ gHalExists = false;
+ return nullptr;
}
// -------------------------------------------------------------------------------------------------
diff --git a/services/vibratorservice/VibratorHalWrapper.cpp b/services/vibratorservice/VibratorHalWrapper.cpp
index 536a6b3..5d4c17d 100644
--- a/services/vibratorservice/VibratorHalWrapper.cpp
+++ b/services/vibratorservice/VibratorHalWrapper.cpp
@@ -17,7 +17,6 @@
#define LOG_TAG "VibratorHalWrapper"
#include <aidl/android/hardware/vibrator/IVibrator.h>
-#include <android/hardware/vibrator/1.3/IVibrator.h>
#include <hardware/vibrator.h>
#include <cmath>
@@ -33,32 +32,18 @@
using aidl::android::hardware::vibrator::Effect;
using aidl::android::hardware::vibrator::EffectStrength;
using aidl::android::hardware::vibrator::FrequencyAccelerationMapEntry;
+using aidl::android::hardware::vibrator::IVibrator;
using aidl::android::hardware::vibrator::PrimitivePwle;
using aidl::android::hardware::vibrator::VendorEffect;
using std::chrono::milliseconds;
-namespace V1_0 = android::hardware::vibrator::V1_0;
-namespace V1_1 = android::hardware::vibrator::V1_1;
-namespace V1_2 = android::hardware::vibrator::V1_2;
-namespace V1_3 = android::hardware::vibrator::V1_3;
-namespace Aidl = aidl::android::hardware::vibrator;
-
namespace android {
namespace vibrator {
// -------------------------------------------------------------------------------------------------
-template <class T>
-bool isStaticCastValid(Effect effect) {
- T castEffect = static_cast<T>(effect);
- auto iter = hardware::hidl_enum_range<T>();
- return castEffect >= *iter.begin() && castEffect <= *std::prev(iter.end());
-}
-
-// -------------------------------------------------------------------------------------------------
-
Info HalWrapper::getInfo() {
getCapabilities();
getPrimitiveDurations();
@@ -261,7 +246,7 @@
if (!result.isOk()) {
return;
}
- std::shared_ptr<Aidl::IVibrator> newHandle = result.value();
+ std::shared_ptr<IVibrator> newHandle = result.value();
if (newHandle) {
std::lock_guard<std::mutex> lock(mHandleMutex);
mHandle = std::move(newHandle);
@@ -514,219 +499,13 @@
frequencyToOutputAccelerationMap);
}
-std::shared_ptr<Aidl::IVibrator> AidlHalWrapper::getHal() {
+std::shared_ptr<IVibrator> AidlHalWrapper::getHal() {
std::lock_guard<std::mutex> lock(mHandleMutex);
return mHandle;
}
// -------------------------------------------------------------------------------------------------
-template <typename I>
-HalResult<void> HidlHalWrapper<I>::ping() {
- return HalResultFactory::fromReturn(getHal()->ping());
-}
-
-template <typename I>
-void HidlHalWrapper<I>::tryReconnect() {
- sp<I> newHandle = I::tryGetService();
- if (newHandle) {
- std::lock_guard<std::mutex> lock(mHandleMutex);
- mHandle = std::move(newHandle);
- }
-}
-
-template <typename I>
-HalResult<void> HidlHalWrapper<I>::on(milliseconds timeout,
- const std::function<void()>& completionCallback) {
- auto status = getHal()->on(timeout.count());
- auto ret = HalResultFactory::fromStatus(status.withDefault(V1_0::Status::UNKNOWN_ERROR));
- if (ret.isOk()) {
- mCallbackScheduler->schedule(completionCallback, timeout);
- }
- return ret;
-}
-
-template <typename I>
-HalResult<void> HidlHalWrapper<I>::off() {
- auto status = getHal()->off();
- return HalResultFactory::fromStatus(status.withDefault(V1_0::Status::UNKNOWN_ERROR));
-}
-
-template <typename I>
-HalResult<void> HidlHalWrapper<I>::setAmplitude(float amplitude) {
- uint8_t amp = static_cast<uint8_t>(amplitude * std::numeric_limits<uint8_t>::max());
- auto status = getHal()->setAmplitude(amp);
- return HalResultFactory::fromStatus(status.withDefault(V1_0::Status::UNKNOWN_ERROR));
-}
-
-template <typename I>
-HalResult<void> HidlHalWrapper<I>::setExternalControl(bool) {
- ALOGV("Skipped setExternalControl because Vibrator HAL does not support it");
- return HalResult<void>::unsupported();
-}
-
-template <typename I>
-HalResult<void> HidlHalWrapper<I>::alwaysOnEnable(int32_t, Effect, EffectStrength) {
- ALOGV("Skipped alwaysOnEnable because Vibrator HAL AIDL is not available");
- return HalResult<void>::unsupported();
-}
-
-template <typename I>
-HalResult<void> HidlHalWrapper<I>::alwaysOnDisable(int32_t) {
- ALOGV("Skipped alwaysOnDisable because Vibrator HAL AIDL is not available");
- return HalResult<void>::unsupported();
-}
-
-template <typename I>
-HalResult<Capabilities> HidlHalWrapper<I>::getCapabilitiesInternal() {
- hardware::Return<bool> result = getHal()->supportsAmplitudeControl();
- Capabilities capabilities =
- result.withDefault(false) ? Capabilities::AMPLITUDE_CONTROL : Capabilities::NONE;
- return HalResultFactory::fromReturn<Capabilities>(std::move(result), capabilities);
-}
-
-template <typename I>
-template <typename T>
-HalResult<milliseconds> HidlHalWrapper<I>::performInternal(
- perform_fn<T> performFn, sp<I> handle, T effect, EffectStrength strength,
- const std::function<void()>& completionCallback) {
- V1_0::Status status;
- int32_t lengthMs;
- auto effectCallback = [&status, &lengthMs](V1_0::Status retStatus, uint32_t retLengthMs) {
- status = retStatus;
- lengthMs = retLengthMs;
- };
-
- V1_0::EffectStrength effectStrength = static_cast<V1_0::EffectStrength>(strength);
- auto result = std::invoke(performFn, handle, effect, effectStrength, effectCallback);
- milliseconds length = milliseconds(lengthMs);
-
- auto ret = HalResultFactory::fromReturn<milliseconds>(std::move(result), status, length);
- if (ret.isOk()) {
- mCallbackScheduler->schedule(completionCallback, length);
- }
-
- return ret;
-}
-
-template <typename I>
-sp<I> HidlHalWrapper<I>::getHal() {
- std::lock_guard<std::mutex> lock(mHandleMutex);
- return mHandle;
-}
-
-// -------------------------------------------------------------------------------------------------
-
-HalResult<milliseconds> HidlHalWrapperV1_0::performEffect(
- Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
- if (isStaticCastValid<V1_0::Effect>(effect)) {
- return performInternal(&V1_0::IVibrator::perform, getHal(),
- static_cast<V1_0::Effect>(effect), strength, completionCallback);
- }
-
- ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
- Aidl::toString(effect).c_str());
- return HalResult<milliseconds>::unsupported();
-}
-
-// -------------------------------------------------------------------------------------------------
-
-HalResult<milliseconds> HidlHalWrapperV1_1::performEffect(
- Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
- if (isStaticCastValid<V1_0::Effect>(effect)) {
- return performInternal(&V1_1::IVibrator::perform, getHal(),
- static_cast<V1_0::Effect>(effect), strength, completionCallback);
- }
- if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
- return performInternal(&V1_1::IVibrator::perform_1_1, getHal(),
- static_cast<V1_1::Effect_1_1>(effect), strength, completionCallback);
- }
-
- ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
- Aidl::toString(effect).c_str());
- return HalResult<milliseconds>::unsupported();
-}
-
-// -------------------------------------------------------------------------------------------------
-
-HalResult<milliseconds> HidlHalWrapperV1_2::performEffect(
- Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
- if (isStaticCastValid<V1_0::Effect>(effect)) {
- return performInternal(&V1_2::IVibrator::perform, getHal(),
- static_cast<V1_0::Effect>(effect), strength, completionCallback);
- }
- if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
- return performInternal(&V1_2::IVibrator::perform_1_1, getHal(),
- static_cast<V1_1::Effect_1_1>(effect), strength, completionCallback);
- }
- if (isStaticCastValid<V1_2::Effect>(effect)) {
- return performInternal(&V1_2::IVibrator::perform_1_2, getHal(),
- static_cast<V1_2::Effect>(effect), strength, completionCallback);
- }
-
- ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
- Aidl::toString(effect).c_str());
- return HalResult<milliseconds>::unsupported();
-}
-
-// -------------------------------------------------------------------------------------------------
-
-HalResult<void> HidlHalWrapperV1_3::setExternalControl(bool enabled) {
- auto result = getHal()->setExternalControl(static_cast<uint32_t>(enabled));
- return HalResultFactory::fromStatus(result.withDefault(V1_0::Status::UNKNOWN_ERROR));
-}
-
-HalResult<milliseconds> HidlHalWrapperV1_3::performEffect(
- Effect effect, EffectStrength strength, const std::function<void()>& completionCallback) {
- if (isStaticCastValid<V1_0::Effect>(effect)) {
- return performInternal(&V1_3::IVibrator::perform, getHal(),
- static_cast<V1_0::Effect>(effect), strength, completionCallback);
- }
- if (isStaticCastValid<V1_1::Effect_1_1>(effect)) {
- return performInternal(&V1_3::IVibrator::perform_1_1, getHal(),
- static_cast<V1_1::Effect_1_1>(effect), strength, completionCallback);
- }
- if (isStaticCastValid<V1_2::Effect>(effect)) {
- return performInternal(&V1_3::IVibrator::perform_1_2, getHal(),
- static_cast<V1_2::Effect>(effect), strength, completionCallback);
- }
- if (isStaticCastValid<V1_3::Effect>(effect)) {
- return performInternal(&V1_3::IVibrator::perform_1_3, getHal(),
- static_cast<V1_3::Effect>(effect), strength, completionCallback);
- }
-
- ALOGV("Skipped performEffect because Vibrator HAL does not support effect %s",
- Aidl::toString(effect).c_str());
- return HalResult<milliseconds>::unsupported();
-}
-
-HalResult<Capabilities> HidlHalWrapperV1_3::getCapabilitiesInternal() {
- Capabilities capabilities = Capabilities::NONE;
-
- sp<V1_3::IVibrator> hal = getHal();
- auto amplitudeResult = hal->supportsAmplitudeControl();
- if (!amplitudeResult.isOk()) {
- return HalResultFactory::fromReturn<Capabilities>(std::move(amplitudeResult), capabilities);
- }
-
- auto externalControlResult = hal->supportsExternalControl();
- if (amplitudeResult.withDefault(false)) {
- capabilities |= Capabilities::AMPLITUDE_CONTROL;
- }
- if (externalControlResult.withDefault(false)) {
- capabilities |= Capabilities::EXTERNAL_CONTROL;
-
- if (amplitudeResult.withDefault(false)) {
- capabilities |= Capabilities::EXTERNAL_AMPLITUDE_CONTROL;
- }
- }
-
- return HalResultFactory::fromReturn<Capabilities>(std::move(externalControlResult),
- capabilities);
-}
-
-// -------------------------------------------------------------------------------------------------
-
}; // namespace vibrator
}; // namespace android
diff --git a/services/vibratorservice/VibratorManagerHalController.cpp b/services/vibratorservice/VibratorManagerHalController.cpp
index 494f88f..31b6ed0 100644
--- a/services/vibratorservice/VibratorManagerHalController.cpp
+++ b/services/vibratorservice/VibratorManagerHalController.cpp
@@ -20,7 +20,10 @@
#include <vibratorservice/VibratorManagerHalController.h>
-namespace Aidl = aidl::android::hardware::vibrator;
+using aidl::android::hardware::vibrator::IVibrationSession;
+using aidl::android::hardware::vibrator::IVibrator;
+using aidl::android::hardware::vibrator::IVibratorManager;
+using aidl::android::hardware::vibrator::VibrationSessionConfig;
namespace android {
@@ -29,9 +32,9 @@
std::shared_ptr<ManagerHalWrapper> connectManagerHal(std::shared_ptr<CallbackScheduler> scheduler) {
static bool gHalExists = true;
if (gHalExists) {
- auto serviceName = std::string(Aidl::IVibratorManager::descriptor) + "/default";
+ auto serviceName = std::string(IVibratorManager::descriptor) + "/default";
if (AServiceManager_isDeclared(serviceName.c_str())) {
- std::shared_ptr<Aidl::IVibratorManager> hal = Aidl::IVibratorManager::fromBinder(
+ std::shared_ptr<IVibratorManager> hal = IVibratorManager::fromBinder(
ndk::SpAIBinder(AServiceManager_checkService(serviceName.c_str())));
if (hal) {
ALOGV("Successfully connected to VibratorManager HAL AIDL service.");
@@ -41,6 +44,7 @@
}
}
+ ALOGV("VibratorManager HAL service not available.");
gHalExists = false;
return std::make_shared<LegacyManagerHalWrapper>();
}
@@ -150,10 +154,10 @@
return apply(cancelSyncedFn, "cancelSynced");
}
-HalResult<std::shared_ptr<Aidl::IVibrationSession>> ManagerHalController::startSession(
- const std::vector<int32_t>& ids, const Aidl::VibrationSessionConfig& config,
+HalResult<std::shared_ptr<IVibrationSession>> ManagerHalController::startSession(
+ const std::vector<int32_t>& ids, const VibrationSessionConfig& config,
const std::function<void()>& completionCallback) {
- hal_fn<std::shared_ptr<Aidl::IVibrationSession>> startSessionFn =
+ hal_fn<std::shared_ptr<IVibrationSession>> startSessionFn =
[&](std::shared_ptr<ManagerHalWrapper> hal) {
return hal->startSession(ids, config, completionCallback);
};
diff --git a/services/vibratorservice/VibratorManagerHalWrapper.cpp b/services/vibratorservice/VibratorManagerHalWrapper.cpp
index 3db8ff8..bab3f58 100644
--- a/services/vibratorservice/VibratorManagerHalWrapper.cpp
+++ b/services/vibratorservice/VibratorManagerHalWrapper.cpp
@@ -20,7 +20,10 @@
#include <vibratorservice/VibratorManagerHalWrapper.h>
-namespace Aidl = aidl::android::hardware::vibrator;
+using aidl::android::hardware::vibrator::IVibrationSession;
+using aidl::android::hardware::vibrator::IVibrator;
+using aidl::android::hardware::vibrator::IVibratorManager;
+using aidl::android::hardware::vibrator::VibrationSessionConfig;
namespace android {
@@ -41,10 +44,9 @@
return HalResult<void>::unsupported();
}
-HalResult<std::shared_ptr<Aidl::IVibrationSession>> ManagerHalWrapper::startSession(
- const std::vector<int32_t>&, const Aidl::VibrationSessionConfig&,
- const std::function<void()>&) {
- return HalResult<std::shared_ptr<Aidl::IVibrationSession>>::unsupported();
+HalResult<std::shared_ptr<IVibrationSession>> ManagerHalWrapper::startSession(
+ const std::vector<int32_t>&, const VibrationSessionConfig&, const std::function<void()>&) {
+ return HalResult<std::shared_ptr<IVibrationSession>>::unsupported();
}
HalResult<void> ManagerHalWrapper::clearSessions() {
@@ -87,11 +89,11 @@
std::shared_ptr<HalWrapper> AidlManagerHalWrapper::connectToVibrator(
int32_t vibratorId, std::shared_ptr<CallbackScheduler> callbackScheduler) {
- std::function<HalResult<std::shared_ptr<Aidl::IVibrator>>()> reconnectFn = [=, this]() {
- std::shared_ptr<Aidl::IVibrator> vibrator;
+ std::function<HalResult<std::shared_ptr<IVibrator>>()> reconnectFn = [=, this]() {
+ std::shared_ptr<IVibrator> vibrator;
auto status = this->getHal()->getVibrator(vibratorId, &vibrator);
- return HalResultFactory::fromStatus<std::shared_ptr<Aidl::IVibrator>>(std::move(status),
- vibrator);
+ return HalResultFactory::fromStatus<std::shared_ptr<IVibrator>>(std::move(status),
+ vibrator);
};
auto result = reconnectFn();
if (!result.isOk()) {
@@ -110,8 +112,8 @@
}
void AidlManagerHalWrapper::tryReconnect() {
- auto aidlServiceName = std::string(Aidl::IVibratorManager::descriptor) + "/default";
- std::shared_ptr<Aidl::IVibratorManager> newHandle = Aidl::IVibratorManager::fromBinder(
+ auto aidlServiceName = std::string(IVibratorManager::descriptor) + "/default";
+ std::shared_ptr<IVibratorManager> newHandle = IVibratorManager::fromBinder(
ndk::SpAIBinder(AServiceManager_checkService(aidlServiceName.c_str())));
if (newHandle) {
std::lock_guard<std::mutex> lock(mHandleMutex);
@@ -198,15 +200,14 @@
return HalResultFactory::fromStatus(getHal()->triggerSynced(cb));
}
-HalResult<std::shared_ptr<Aidl::IVibrationSession>> AidlManagerHalWrapper::startSession(
- const std::vector<int32_t>& ids, const Aidl::VibrationSessionConfig& config,
+HalResult<std::shared_ptr<IVibrationSession>> AidlManagerHalWrapper::startSession(
+ const std::vector<int32_t>& ids, const VibrationSessionConfig& config,
const std::function<void()>& completionCallback) {
auto cb = ndk::SharedRefBase::make<HalCallbackWrapper>(completionCallback);
- std::shared_ptr<Aidl::IVibrationSession> session;
+ std::shared_ptr<IVibrationSession> session;
auto status = getHal()->startSession(ids, config, cb, &session);
- return HalResultFactory::fromStatus<std::shared_ptr<Aidl::IVibrationSession>>(std::move(status),
- std::move(
- session));
+ return HalResultFactory::fromStatus<std::shared_ptr<IVibrationSession>>(std::move(status),
+ std::move(session));
}
HalResult<void> AidlManagerHalWrapper::cancelSynced() {
@@ -227,7 +228,7 @@
return HalResultFactory::fromStatus(getHal()->clearSessions());
}
-std::shared_ptr<Aidl::IVibratorManager> AidlManagerHalWrapper::getHal() {
+std::shared_ptr<IVibratorManager> AidlManagerHalWrapper::getHal() {
std::lock_guard<std::mutex> lock(mHandleMutex);
return mHandle;
}
diff --git a/services/vibratorservice/benchmarks/Android.bp b/services/vibratorservice/benchmarks/Android.bp
index 915d6c7..6fc5cf3 100644
--- a/services/vibratorservice/benchmarks/Android.bp
+++ b/services/vibratorservice/benchmarks/Android.bp
@@ -29,15 +29,10 @@
],
shared_libs: [
"libbinder_ndk",
- "libhidlbase",
"liblog",
"libutils",
"libvibratorservice",
"android.hardware.vibrator-V3-ndk",
- "android.hardware.vibrator@1.0",
- "android.hardware.vibrator@1.1",
- "android.hardware.vibrator@1.2",
- "android.hardware.vibrator@1.3",
],
cflags: [
"-Wall",
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 9a39ad4..0652278 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -22,7 +22,6 @@
#include <android-base/thread_annotations.h>
#include <android/binder_manager.h>
-#include <android/hardware/vibrator/1.3/IVibrator.h>
#include <binder/IServiceManager.h>
#include <vibratorservice/VibratorCallbackScheduler.h>
@@ -105,26 +104,6 @@
: fromFailedStatus<T>(std::move(status));
}
- template <typename T>
- static HalResult<T> fromStatus(hardware::vibrator::V1_0::Status&& status, T data) {
- return (status == hardware::vibrator::V1_0::Status::OK)
- ? HalResult<T>::ok(std::move(data))
- : fromFailedStatus<T>(std::move(status));
- }
-
- template <typename T, typename R>
- static HalResult<T> fromReturn(hardware::Return<R>&& ret, T data) {
- return ret.isOk() ? HalResult<T>::ok(std::move(data))
- : fromFailedReturn<T, R>(std::move(ret));
- }
-
- template <typename T, typename R>
- static HalResult<T> fromReturn(hardware::Return<R>&& ret,
- hardware::vibrator::V1_0::Status status, T data) {
- return ret.isOk() ? fromStatus<T>(std::move(status), std::move(data))
- : fromFailedReturn<T, R>(std::move(ret));
- }
-
static HalResult<void> fromStatus(status_t status) {
return (status == android::OK) ? HalResult<void>::ok()
: fromFailedStatus<void>(std::move(status));
@@ -134,17 +113,6 @@
return status.isOk() ? HalResult<void>::ok() : fromFailedStatus<void>(std::move(status));
}
- static HalResult<void> fromStatus(hardware::vibrator::V1_0::Status&& status) {
- return (status == hardware::vibrator::V1_0::Status::OK)
- ? HalResult<void>::ok()
- : fromFailedStatus<void>(std::move(status));
- }
-
- template <typename R>
- static HalResult<void> fromReturn(hardware::Return<R>&& ret) {
- return ret.isOk() ? HalResult<void>::ok() : fromFailedReturn<void, R>(std::move(ret));
- }
-
private:
template <typename T>
static HalResult<T> fromFailedStatus(status_t status) {
@@ -166,23 +134,6 @@
}
return HalResult<T>::failed(status.getMessage());
}
-
- template <typename T>
- static HalResult<T> fromFailedStatus(hardware::vibrator::V1_0::Status&& status) {
- switch (status) {
- case hardware::vibrator::V1_0::Status::UNSUPPORTED_OPERATION:
- return HalResult<T>::unsupported();
- default:
- auto msg = "android::hardware::vibrator::V1_0::Status = " + toString(status);
- return HalResult<T>::failed(msg.c_str());
- }
- }
-
- template <typename T, typename R>
- static HalResult<T> fromFailedReturn(hardware::Return<R>&& ret) {
- return ret.isDeadObject() ? HalResult<T>::transactionFailed(ret.description().c_str())
- : HalResult<T>::failed(ret.description().c_str());
- }
};
// -------------------------------------------------------------------------------------------------
@@ -548,108 +499,6 @@
std::shared_ptr<IVibrator> getHal();
};
-// Wrapper for the HDIL Vibrator HALs.
-template <typename I>
-class HidlHalWrapper : public HalWrapper {
-public:
- HidlHalWrapper(std::shared_ptr<CallbackScheduler> scheduler, sp<I> handle)
- : HalWrapper(std::move(scheduler)), mHandle(std::move(handle)) {}
- virtual ~HidlHalWrapper() = default;
-
- HalResult<void> ping() override final;
- void tryReconnect() override final;
-
- HalResult<void> on(std::chrono::milliseconds timeout,
- const std::function<void()>& completionCallback) override final;
- HalResult<void> off() override final;
-
- HalResult<void> setAmplitude(float amplitude) override final;
- virtual HalResult<void> setExternalControl(bool enabled) override;
-
- HalResult<void> alwaysOnEnable(int32_t id, HalWrapper::Effect effect,
- HalWrapper::EffectStrength strength) override final;
- HalResult<void> alwaysOnDisable(int32_t id) override final;
-
-protected:
- std::mutex mHandleMutex;
- sp<I> mHandle GUARDED_BY(mHandleMutex);
-
- virtual HalResult<Capabilities> getCapabilitiesInternal() override;
-
- template <class T>
- using perform_fn =
- hardware::Return<void> (I::*)(T, hardware::vibrator::V1_0::EffectStrength,
- hardware::vibrator::V1_0::IVibrator::perform_cb);
-
- template <class T>
- HalResult<std::chrono::milliseconds> performInternal(
- perform_fn<T> performFn, sp<I> handle, T effect, HalWrapper::EffectStrength strength,
- const std::function<void()>& completionCallback);
-
- sp<I> getHal();
-};
-
-// Wrapper for the HDIL Vibrator HAL v1.0.
-class HidlHalWrapperV1_0 : public HidlHalWrapper<hardware::vibrator::V1_0::IVibrator> {
-public:
- HidlHalWrapperV1_0(std::shared_ptr<CallbackScheduler> scheduler,
- sp<hardware::vibrator::V1_0::IVibrator> handle)
- : HidlHalWrapper<hardware::vibrator::V1_0::IVibrator>(std::move(scheduler),
- std::move(handle)) {}
- virtual ~HidlHalWrapperV1_0() = default;
-
- HalResult<std::chrono::milliseconds> performEffect(
- HalWrapper::Effect effect, HalWrapper::EffectStrength strength,
- const std::function<void()>& completionCallback) override final;
-};
-
-// Wrapper for the HDIL Vibrator HAL v1.1.
-class HidlHalWrapperV1_1 : public HidlHalWrapper<hardware::vibrator::V1_1::IVibrator> {
-public:
- HidlHalWrapperV1_1(std::shared_ptr<CallbackScheduler> scheduler,
- sp<hardware::vibrator::V1_1::IVibrator> handle)
- : HidlHalWrapper<hardware::vibrator::V1_1::IVibrator>(std::move(scheduler),
- std::move(handle)) {}
- virtual ~HidlHalWrapperV1_1() = default;
-
- HalResult<std::chrono::milliseconds> performEffect(
- HalWrapper::Effect effect, HalWrapper::EffectStrength strength,
- const std::function<void()>& completionCallback) override final;
-};
-
-// Wrapper for the HDIL Vibrator HAL v1.2.
-class HidlHalWrapperV1_2 : public HidlHalWrapper<hardware::vibrator::V1_2::IVibrator> {
-public:
- HidlHalWrapperV1_2(std::shared_ptr<CallbackScheduler> scheduler,
- sp<hardware::vibrator::V1_2::IVibrator> handle)
- : HidlHalWrapper<hardware::vibrator::V1_2::IVibrator>(std::move(scheduler),
- std::move(handle)) {}
- virtual ~HidlHalWrapperV1_2() = default;
-
- HalResult<std::chrono::milliseconds> performEffect(
- HalWrapper::Effect effect, HalWrapper::EffectStrength strength,
- const std::function<void()>& completionCallback) override final;
-};
-
-// Wrapper for the HDIL Vibrator HAL v1.3.
-class HidlHalWrapperV1_3 : public HidlHalWrapper<hardware::vibrator::V1_3::IVibrator> {
-public:
- HidlHalWrapperV1_3(std::shared_ptr<CallbackScheduler> scheduler,
- sp<hardware::vibrator::V1_3::IVibrator> handle)
- : HidlHalWrapper<hardware::vibrator::V1_3::IVibrator>(std::move(scheduler),
- std::move(handle)) {}
- virtual ~HidlHalWrapperV1_3() = default;
-
- HalResult<void> setExternalControl(bool enabled) override final;
-
- HalResult<std::chrono::milliseconds> performEffect(
- HalWrapper::Effect effect, HalWrapper::EffectStrength strength,
- const std::function<void()>& completionCallback) override final;
-
-protected:
- HalResult<Capabilities> getCapabilitiesInternal() override final;
-};
-
// -------------------------------------------------------------------------------------------------
}; // namespace vibrator
diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp
index 92527eb..038248e 100644
--- a/services/vibratorservice/test/Android.bp
+++ b/services/vibratorservice/test/Android.bp
@@ -29,10 +29,6 @@
"VibratorCallbackSchedulerTest.cpp",
"VibratorHalControllerTest.cpp",
"VibratorHalWrapperAidlTest.cpp",
- "VibratorHalWrapperHidlV1_0Test.cpp",
- "VibratorHalWrapperHidlV1_1Test.cpp",
- "VibratorHalWrapperHidlV1_2Test.cpp",
- "VibratorHalWrapperHidlV1_3Test.cpp",
"VibratorManagerHalControllerTest.cpp",
"VibratorManagerHalWrapperAidlTest.cpp",
"VibratorManagerHalWrapperLegacyTest.cpp",
@@ -45,15 +41,10 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "libhidlbase",
"liblog",
"libvibratorservice",
"libutils",
"android.hardware.vibrator-V3-ndk",
- "android.hardware.vibrator@1.0",
- "android.hardware.vibrator@1.1",
- "android.hardware.vibrator@1.2",
- "android.hardware.vibrator@1.3",
],
static_libs: [
"libgmock",
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
deleted file mode 100644
index 04dbe4e..0000000
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_0Test.cpp
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- * Copyright (C) 2020 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 "VibratorHalWrapperHidlV1_0Test"
-
-#include <aidl/android/hardware/vibrator/IVibrator.h>
-#include <android/persistable_bundle_aidl.h>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <utils/Log.h>
-#include <thread>
-
-#include <vibratorservice/VibratorCallbackScheduler.h>
-#include <vibratorservice/VibratorHalWrapper.h>
-
-#include "test_mocks.h"
-#include "test_utils.h"
-
-namespace V1_0 = android::hardware::vibrator::V1_0;
-
-using aidl::android::hardware::vibrator::Braking;
-using aidl::android::hardware::vibrator::CompositeEffect;
-using aidl::android::hardware::vibrator::CompositePrimitive;
-using aidl::android::hardware::vibrator::CompositePwleV2;
-using aidl::android::hardware::vibrator::Effect;
-using aidl::android::hardware::vibrator::EffectStrength;
-using aidl::android::hardware::vibrator::IVibrator;
-using aidl::android::hardware::vibrator::PrimitivePwle;
-using aidl::android::hardware::vibrator::PwleV2Primitive;
-using aidl::android::hardware::vibrator::VendorEffect;
-using aidl::android::os::PersistableBundle;
-
-using namespace android;
-using namespace std::chrono_literals;
-using namespace testing;
-
-// -------------------------------------------------------------------------------------------------
-
-class MockIVibratorV1_0 : public V1_0::IVibrator {
-public:
- MOCK_METHOD(hardware::Return<void>, ping, (), (override));
- MOCK_METHOD(hardware::Return<V1_0::Status>, on, (uint32_t timeoutMs), (override));
- MOCK_METHOD(hardware::Return<V1_0::Status>, off, (), (override));
- MOCK_METHOD(hardware::Return<bool>, supportsAmplitudeControl, (), (override));
- MOCK_METHOD(hardware::Return<V1_0::Status>, setAmplitude, (uint8_t amplitude), (override));
- MOCK_METHOD(hardware::Return<void>, perform,
- (V1_0::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
-};
-
-// -------------------------------------------------------------------------------------------------
-
-class VibratorHalWrapperHidlV1_0Test : public Test {
-public:
- void SetUp() override {
- mMockHal = new StrictMock<MockIVibratorV1_0>();
- mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
- mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_0>(mMockScheduler, mMockHal);
- ASSERT_NE(mWrapper, nullptr);
- }
-
-protected:
- std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
- std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
- sp<StrictMock<MockIVibratorV1_0>> mMockHal = nullptr;
-};
-
-// -------------------------------------------------------------------------------------------------
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestPing) {
- EXPECT_CALL(*mMockHal.get(), ping())
- .Times(Exactly(2))
- .WillOnce([]() { return hardware::Return<void>(); })
- .WillRepeatedly([]() {
- return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
- });
-
- ASSERT_TRUE(mWrapper->ping().isOk());
- ASSERT_TRUE(mWrapper->ping().isFailed());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestOn) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(1))))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](uint32_t) { return hardware::Return<V1_0::Status>(V1_0::Status::OK); });
- EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(1ms)))
- .Times(Exactly(1))
- .WillRepeatedly(vibrator::TriggerSchedulerCallback());
- EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(10))))
- .Times(Exactly(1))
- .WillRepeatedly([](uint32_t) {
- return hardware::Return<V1_0::Status>(V1_0::Status::UNSUPPORTED_OPERATION);
- });
- EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(11))))
- .Times(Exactly(1))
- .WillRepeatedly([](uint32_t) {
- return hardware::Return<V1_0::Status>(V1_0::Status::BAD_VALUE);
- });
- EXPECT_CALL(*mMockHal.get(), on(Eq(static_cast<uint32_t>(12))))
- .Times(Exactly(1))
- .WillRepeatedly([](uint32_t) {
- return hardware::Return<V1_0::Status>(hardware::Status::fromExceptionCode(-1));
- });
- }
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
-
- ASSERT_TRUE(mWrapper->on(1ms, callback).isOk());
- ASSERT_EQ(1, *callbackCounter.get());
-
- ASSERT_TRUE(mWrapper->on(10ms, callback).isUnsupported());
- ASSERT_TRUE(mWrapper->on(11ms, callback).isFailed());
- ASSERT_TRUE(mWrapper->on(12ms, callback).isFailed());
-
- // Callback not triggered for unsupported and on failure
- ASSERT_EQ(1, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestOff) {
- EXPECT_CALL(*mMockHal.get(), off())
- .Times(Exactly(4))
- .WillOnce([]() { return hardware::Return<V1_0::Status>(V1_0::Status::OK); })
- .WillOnce([]() {
- return hardware::Return<V1_0::Status>(V1_0::Status::UNSUPPORTED_OPERATION);
- })
- .WillOnce([]() { return hardware::Return<V1_0::Status>(V1_0::Status::BAD_VALUE); })
- .WillRepeatedly([]() {
- return hardware::Return<V1_0::Status>(hardware::Status::fromExceptionCode(-1));
- });
-
- ASSERT_TRUE(mWrapper->off().isOk());
- ASSERT_TRUE(mWrapper->off().isUnsupported());
- ASSERT_TRUE(mWrapper->off().isFailed());
- ASSERT_TRUE(mWrapper->off().isFailed());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestSetAmplitude) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(static_cast<uint8_t>(1))))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](uint8_t) { return hardware::Return<V1_0::Status>(V1_0::Status::OK); });
- EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(static_cast<uint8_t>(2))))
- .Times(Exactly(1))
- .WillRepeatedly([](uint8_t) {
- return hardware::Return<V1_0::Status>(V1_0::Status::UNSUPPORTED_OPERATION);
- });
- EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(static_cast<uint8_t>(3))))
- .Times(Exactly(1))
- .WillRepeatedly([](uint8_t) {
- return hardware::Return<V1_0::Status>(V1_0::Status::BAD_VALUE);
- });
- EXPECT_CALL(*mMockHal.get(), setAmplitude(Eq(static_cast<uint8_t>(4))))
- .Times(Exactly(1))
- .WillRepeatedly([](uint8_t) {
- return hardware::Return<V1_0::Status>(hardware::Status::fromExceptionCode(-1));
- });
- }
-
- auto maxAmplitude = std::numeric_limits<uint8_t>::max();
- ASSERT_TRUE(mWrapper->setAmplitude(1.0f / maxAmplitude).isOk());
- ASSERT_TRUE(mWrapper->setAmplitude(2.0f / maxAmplitude).isUnsupported());
- ASSERT_TRUE(mWrapper->setAmplitude(3.0f / maxAmplitude).isFailed());
- ASSERT_TRUE(mWrapper->setAmplitude(4.0f / maxAmplitude).isFailed());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestSetExternalControlUnsupported) {
- ASSERT_TRUE(mWrapper->setExternalControl(true).isUnsupported());
- ASSERT_TRUE(mWrapper->setExternalControl(false).isUnsupported());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestAlwaysOnEnableUnsupported) {
- ASSERT_TRUE(mWrapper->alwaysOnEnable(1, Effect::CLICK, EffectStrength::LIGHT).isUnsupported());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestAlwaysOnDisableUnsupported) {
- ASSERT_TRUE(mWrapper->alwaysOnDisable(1).isUnsupported());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoDoesNotCacheFailedResult) {
- EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
- .Times(Exactly(2))
- .WillOnce([]() {
- return hardware::Return<bool>(hardware::Status::fromExceptionCode(-1));
- })
- .WillRepeatedly([]() { return hardware::Return<bool>(true); });
-
- ASSERT_TRUE(mWrapper->getInfo().capabilities.isFailed());
-
- vibrator::Info info = mWrapper->getInfo();
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, info.capabilities.value());
- ASSERT_TRUE(info.supportedEffects.isUnsupported());
- ASSERT_TRUE(info.supportedBraking.isUnsupported());
- ASSERT_TRUE(info.supportedPrimitives.isUnsupported());
- ASSERT_TRUE(info.primitiveDurations.isUnsupported());
- ASSERT_TRUE(info.primitiveDelayMax.isUnsupported());
- ASSERT_TRUE(info.pwlePrimitiveDurationMax.isUnsupported());
- ASSERT_TRUE(info.compositionSizeMax.isUnsupported());
- ASSERT_TRUE(info.pwleSizeMax.isUnsupported());
- ASSERT_TRUE(info.minFrequency.isUnsupported());
- ASSERT_TRUE(info.resonantFrequency.isUnsupported());
- ASSERT_TRUE(info.frequencyResolution.isUnsupported());
- ASSERT_TRUE(info.qFactor.isUnsupported());
- ASSERT_TRUE(info.maxAmplitudes.isUnsupported());
- ASSERT_TRUE(info.maxEnvelopeEffectSize.isUnsupported());
- ASSERT_TRUE(info.minEnvelopeEffectControlPointDuration.isUnsupported());
- ASSERT_TRUE(info.maxEnvelopeEffectControlPointDuration.isUnsupported());
- ASSERT_TRUE(info.frequencyToOutputAccelerationMap.isUnsupported());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoWithoutAmplitudeControl) {
- EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillRepeatedly([]() {
- return hardware::Return<bool>(false);
- });
-
- ASSERT_EQ(vibrator::Capabilities::NONE, mWrapper->getInfo().capabilities.value());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestGetInfoCachesResult) {
- EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillRepeatedly([]() {
- return hardware::Return<bool>(true);
- });
-
- std::vector<std::thread> threads;
- for (int i = 0; i < 10; i++) {
- threads.push_back(
- std::thread([&]() { ASSERT_TRUE(mWrapper->getInfo().capabilities.isOk()); }));
- }
- std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
-
- vibrator::Info info = mWrapper->getInfo();
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, info.capabilities.value());
- ASSERT_TRUE(info.supportedEffects.isUnsupported());
- ASSERT_TRUE(info.supportedBraking.isUnsupported());
- ASSERT_TRUE(info.supportedPrimitives.isUnsupported());
- ASSERT_TRUE(info.primitiveDurations.isUnsupported());
- ASSERT_TRUE(info.minFrequency.isUnsupported());
- ASSERT_TRUE(info.resonantFrequency.isUnsupported());
- ASSERT_TRUE(info.frequencyResolution.isUnsupported());
- ASSERT_TRUE(info.qFactor.isUnsupported());
- ASSERT_TRUE(info.maxAmplitudes.isUnsupported());
- ASSERT_TRUE(info.maxEnvelopeEffectSize.isUnsupported());
- ASSERT_TRUE(info.minEnvelopeEffectControlPointDuration.isUnsupported());
- ASSERT_TRUE(info.maxEnvelopeEffectControlPointDuration.isUnsupported());
- ASSERT_TRUE(info.frequencyToOutputAccelerationMap.isUnsupported());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformEffect) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(),
- perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_0::perform_cb cb) {
- cb(V1_0::Status::OK, 10);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
- .Times(Exactly(1))
- .WillRepeatedly(vibrator::TriggerSchedulerCallback());
- EXPECT_CALL(*mMockHal.get(),
- perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::MEDIUM), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_0::perform_cb cb) {
- cb(V1_0::Status::UNSUPPORTED_OPERATION, 10);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockHal.get(),
- perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::STRONG), _))
- .Times(Exactly(2))
- .WillOnce([](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_0::perform_cb cb) {
- cb(V1_0::Status::BAD_VALUE, 10);
- return hardware::Return<void>();
- })
- .WillRepeatedly(
- [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_0::perform_cb) {
- return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
- });
- }
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
-
- auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(10ms, result.value());
- ASSERT_EQ(1, *callbackCounter.get());
-
- result = mWrapper->performEffect(Effect::CLICK, EffectStrength::MEDIUM, callback);
- ASSERT_TRUE(result.isUnsupported());
-
- result = mWrapper->performEffect(Effect::CLICK, EffectStrength::STRONG, callback);
- ASSERT_TRUE(result.isFailed());
-
- result = mWrapper->performEffect(Effect::CLICK, EffectStrength::STRONG, callback);
- ASSERT_TRUE(result.isFailed());
-
- // Callback not triggered for unsupported and on failure
- ASSERT_EQ(1, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformEffectUnsupported) {
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
- // Using TICK that is only available in v1.1
- auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
- ASSERT_TRUE(result.isUnsupported());
- // No callback is triggered.
- ASSERT_EQ(0, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformVendorEffectUnsupported) {
- PersistableBundle vendorData; // empty
- VendorEffect vendorEffect;
- vendorEffect.vendorData = vendorData;
- vendorEffect.strength = EffectStrength::LIGHT;
- vendorEffect.scale = 1.0f;
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
-
- ASSERT_TRUE(mWrapper->performVendorEffect(vendorEffect, callback).isUnsupported());
-
- // No callback is triggered.
- ASSERT_EQ(0, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformComposedEffectUnsupported) {
- std::vector<CompositeEffect> emptyEffects, singleEffect, multipleEffects;
- singleEffect.push_back(
- vibrator::TestFactory::createCompositeEffect(CompositePrimitive::CLICK, 10ms, 0.0f));
- multipleEffects.push_back(
- vibrator::TestFactory::createCompositeEffect(CompositePrimitive::SPIN, 100ms, 0.5f));
- multipleEffects.push_back(
- vibrator::TestFactory::createCompositeEffect(CompositePrimitive::THUD, 1000ms, 1.0f));
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
-
- ASSERT_TRUE(mWrapper->performComposedEffect(singleEffect, callback).isUnsupported());
- ASSERT_TRUE(mWrapper->performComposedEffect(multipleEffects, callback).isUnsupported());
-
- // No callback is triggered.
- ASSERT_EQ(0, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestPerformPwleEffectUnsupported) {
- std::vector<PrimitivePwle> emptyPrimitives, multiplePrimitives;
- multiplePrimitives.push_back(vibrator::TestFactory::createActivePwle(0, 1, 0, 1, 10ms));
- multiplePrimitives.push_back(vibrator::TestFactory::createBrakingPwle(Braking::NONE, 100ms));
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
-
- ASSERT_TRUE(mWrapper->performPwleEffect(emptyPrimitives, callback).isUnsupported());
- ASSERT_TRUE(mWrapper->performPwleEffect(multiplePrimitives, callback).isUnsupported());
-
- // No callback is triggered.
- ASSERT_EQ(0, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_0Test, TestComposePwleV2Unsupported) {
- CompositePwleV2 composite;
- composite.pwlePrimitives = {
- PwleV2Primitive(/*amplitude=*/0.2, /*frequency=*/50, /*time=*/100),
- PwleV2Primitive(/*amplitude=*/0.5, /*frequency=*/150, /*time=*/100),
- PwleV2Primitive(/*amplitude=*/0.8, /*frequency=*/250, /*time=*/100),
- };
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
-
- ASSERT_TRUE(mWrapper->composePwleV2(composite, callback).isUnsupported());
-
- // No callback is triggered.
- ASSERT_EQ(0, *callbackCounter.get());
-}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp
deleted file mode 100644
index b0a6537..0000000
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_1Test.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2020 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 "VibratorHalWrapperHidlV1_1Test"
-
-#include <aidl/android/hardware/vibrator/IVibrator.h>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <utils/Log.h>
-
-#include <vibratorservice/VibratorCallbackScheduler.h>
-#include <vibratorservice/VibratorHalWrapper.h>
-
-#include "test_mocks.h"
-#include "test_utils.h"
-
-namespace V1_0 = android::hardware::vibrator::V1_0;
-namespace V1_1 = android::hardware::vibrator::V1_1;
-
-using aidl::android::hardware::vibrator::Effect;
-using aidl::android::hardware::vibrator::EffectStrength;
-
-using namespace android;
-using namespace std::chrono_literals;
-using namespace testing;
-
-// -------------------------------------------------------------------------------------------------
-
-class MockIVibratorV1_1 : public V1_1::IVibrator {
-public:
- MOCK_METHOD(hardware::Return<V1_0::Status>, on, (uint32_t timeoutMs), (override));
- MOCK_METHOD(hardware::Return<V1_0::Status>, off, (), (override));
- MOCK_METHOD(hardware::Return<bool>, supportsAmplitudeControl, (), (override));
- MOCK_METHOD(hardware::Return<V1_0::Status>, setAmplitude, (uint8_t amplitude), (override));
- MOCK_METHOD(hardware::Return<void>, perform,
- (V1_0::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
- MOCK_METHOD(hardware::Return<void>, perform_1_1,
- (V1_1::Effect_1_1 effect, V1_0::EffectStrength strength, perform_cb cb),
- (override));
-};
-
-// -------------------------------------------------------------------------------------------------
-
-class VibratorHalWrapperHidlV1_1Test : public Test {
-public:
- void SetUp() override {
- mMockHal = new StrictMock<MockIVibratorV1_1>();
- mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
- mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_1>(mMockScheduler, mMockHal);
- ASSERT_NE(mWrapper, nullptr);
- }
-
-protected:
- std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
- std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
- sp<StrictMock<MockIVibratorV1_1>> mMockHal = nullptr;
-};
-
-// -------------------------------------------------------------------------------------------------
-
-TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectV1_0) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(),
- perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_1::perform_cb cb) {
- cb(V1_0::Status::OK, 10);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
- .Times(Exactly(1))
- .WillRepeatedly(vibrator::TriggerSchedulerCallback());
- }
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
- auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
-
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(10ms, result.value());
- ASSERT_EQ(1, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectV1_1) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(),
- perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly([](V1_1::Effect_1_1, V1_0::EffectStrength,
- MockIVibratorV1_1::perform_cb cb) {
- cb(V1_0::Status::OK, 10);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
- .Times(Exactly(1))
- .WillRepeatedly(vibrator::TriggerSchedulerCallback());
- EXPECT_CALL(*mMockHal.get(),
- perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::MEDIUM), _))
- .Times(Exactly(1))
- .WillRepeatedly([](V1_1::Effect_1_1, V1_0::EffectStrength,
- MockIVibratorV1_1::perform_cb cb) {
- cb(V1_0::Status::UNSUPPORTED_OPERATION, 0);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockHal.get(),
- perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::STRONG), _))
- .Times(Exactly(2))
- .WillOnce([](V1_1::Effect_1_1, V1_0::EffectStrength,
- MockIVibratorV1_1::perform_cb cb) {
- cb(V1_0::Status::BAD_VALUE, 0);
- return hardware::Return<void>();
- })
- .WillRepeatedly(
- [](V1_1::Effect_1_1, V1_0::EffectStrength, MockIVibratorV1_1::perform_cb) {
- return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
- });
- }
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
-
- auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(10ms, result.value());
- ASSERT_EQ(1, *callbackCounter.get());
-
- result = mWrapper->performEffect(Effect::TICK, EffectStrength::MEDIUM, callback);
- ASSERT_TRUE(result.isUnsupported());
-
- result = mWrapper->performEffect(Effect::TICK, EffectStrength::STRONG, callback);
- ASSERT_TRUE(result.isFailed());
-
- result = mWrapper->performEffect(Effect::TICK, EffectStrength::STRONG, callback);
- ASSERT_TRUE(result.isFailed());
-
- // Callback not triggered for unsupported and on failure
- ASSERT_EQ(1, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_1Test, TestPerformEffectUnsupported) {
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
- // Using THUD that is only available in v1.2
- auto result = mWrapper->performEffect(Effect::THUD, EffectStrength::LIGHT, callback);
- ASSERT_TRUE(result.isUnsupported());
- // No callback is triggered.
- ASSERT_EQ(0, *callbackCounter.get());
-}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp
deleted file mode 100644
index dfe3fa0..0000000
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_2Test.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2020 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 "VibratorHalWrapperHidlV1_2Test"
-
-#include <aidl/android/hardware/vibrator/IVibrator.h>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <utils/Log.h>
-
-#include <vibratorservice/VibratorCallbackScheduler.h>
-#include <vibratorservice/VibratorHalWrapper.h>
-
-#include "test_mocks.h"
-#include "test_utils.h"
-
-namespace V1_0 = android::hardware::vibrator::V1_0;
-namespace V1_1 = android::hardware::vibrator::V1_1;
-namespace V1_2 = android::hardware::vibrator::V1_2;
-
-using aidl::android::hardware::vibrator::Effect;
-using aidl::android::hardware::vibrator::EffectStrength;
-
-using namespace android;
-using namespace std::chrono_literals;
-using namespace testing;
-
-// -------------------------------------------------------------------------------------------------
-
-class MockIVibratorV1_2 : public V1_2::IVibrator {
-public:
- MOCK_METHOD(hardware::Return<V1_0::Status>, on, (uint32_t timeoutMs), (override));
- MOCK_METHOD(hardware::Return<V1_0::Status>, off, (), (override));
- MOCK_METHOD(hardware::Return<bool>, supportsAmplitudeControl, (), (override));
- MOCK_METHOD(hardware::Return<V1_0::Status>, setAmplitude, (uint8_t amplitude), (override));
- MOCK_METHOD(hardware::Return<void>, perform,
- (V1_0::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
- MOCK_METHOD(hardware::Return<void>, perform_1_1,
- (V1_1::Effect_1_1 effect, V1_0::EffectStrength strength, perform_cb cb),
- (override));
- MOCK_METHOD(hardware::Return<void>, perform_1_2,
- (V1_2::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
-};
-
-// -------------------------------------------------------------------------------------------------
-
-class VibratorHalWrapperHidlV1_2Test : public Test {
-public:
- void SetUp() override {
- mMockHal = new StrictMock<MockIVibratorV1_2>();
- mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
- mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_2>(mMockScheduler, mMockHal);
- ASSERT_NE(mWrapper, nullptr);
- }
-
-protected:
- std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
- std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
- sp<StrictMock<MockIVibratorV1_2>> mMockHal = nullptr;
-};
-
-// -------------------------------------------------------------------------------------------------
-
-TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_0) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(),
- perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
- cb(V1_0::Status::OK, 10);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
- .Times(Exactly(1))
- .WillRepeatedly(vibrator::TriggerSchedulerCallback());
- }
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
- auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
-
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(10ms, result.value());
- ASSERT_EQ(1, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_1) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(),
- perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly([](V1_1::Effect_1_1, V1_0::EffectStrength,
- MockIVibratorV1_2::perform_cb cb) {
- cb(V1_0::Status::OK, 10);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
- .Times(Exactly(1))
- .WillRepeatedly(vibrator::TriggerSchedulerCallback());
- }
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
- auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
-
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(10ms, result.value());
- ASSERT_EQ(1, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectV1_2) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(),
- perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
- cb(V1_0::Status::OK, 10);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
- .Times(Exactly(1))
- .WillRepeatedly(vibrator::TriggerSchedulerCallback());
- EXPECT_CALL(*mMockHal.get(),
- perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::MEDIUM), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
- cb(V1_0::Status::UNSUPPORTED_OPERATION, 10);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockHal.get(),
- perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::STRONG), _))
- .Times(Exactly(2))
- .WillOnce([](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb cb) {
- cb(V1_0::Status::BAD_VALUE, 10);
- return hardware::Return<void>();
- })
- .WillRepeatedly(
- [](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_2::perform_cb) {
- return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
- });
- }
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
-
- auto result = mWrapper->performEffect(Effect::THUD, EffectStrength::LIGHT, callback);
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(10ms, result.value());
- ASSERT_EQ(1, *callbackCounter.get());
-
- result = mWrapper->performEffect(Effect::THUD, EffectStrength::MEDIUM, callback);
- ASSERT_TRUE(result.isUnsupported());
-
- result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
- ASSERT_TRUE(result.isFailed());
-
- result = mWrapper->performEffect(Effect::THUD, EffectStrength::STRONG, callback);
- ASSERT_TRUE(result.isFailed());
-
- // Callback not triggered for unsupported and on failure
- ASSERT_EQ(1, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_2Test, TestPerformEffectUnsupported) {
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
- // Using TEXTURE_TICK that is only available in v1.3
- auto result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::LIGHT, callback);
- ASSERT_TRUE(result.isUnsupported());
- // No callback is triggered.
- ASSERT_EQ(0, *callbackCounter.get());
-}
diff --git a/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp b/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
deleted file mode 100644
index 8624332..0000000
--- a/services/vibratorservice/test/VibratorHalWrapperHidlV1_3Test.cpp
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (C) 2020 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 "VibratorHalWrapperHidlV1_3Test"
-
-#include <aidl/android/hardware/vibrator/IVibrator.h>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <utils/Log.h>
-#include <thread>
-
-#include <vibratorservice/VibratorCallbackScheduler.h>
-#include <vibratorservice/VibratorHalWrapper.h>
-
-#include "test_mocks.h"
-#include "test_utils.h"
-
-namespace V1_0 = android::hardware::vibrator::V1_0;
-namespace V1_1 = android::hardware::vibrator::V1_1;
-namespace V1_2 = android::hardware::vibrator::V1_2;
-namespace V1_3 = android::hardware::vibrator::V1_3;
-
-using aidl::android::hardware::vibrator::Effect;
-using aidl::android::hardware::vibrator::EffectStrength;
-using aidl::android::hardware::vibrator::IVibrator;
-
-using namespace android;
-using namespace std::chrono_literals;
-using namespace testing;
-
-// -------------------------------------------------------------------------------------------------
-
-class MockIVibratorV1_3 : public V1_3::IVibrator {
-public:
- MOCK_METHOD(hardware::Return<V1_0::Status>, on, (uint32_t timeoutMs), (override));
- MOCK_METHOD(hardware::Return<V1_0::Status>, off, (), (override));
- MOCK_METHOD(hardware::Return<bool>, supportsAmplitudeControl, (), (override));
- MOCK_METHOD(hardware::Return<bool>, supportsExternalControl, (), (override));
- MOCK_METHOD(hardware::Return<V1_0::Status>, setAmplitude, (uint8_t amplitude), (override));
- MOCK_METHOD(hardware::Return<V1_0::Status>, setExternalControl, (bool enabled), (override));
- MOCK_METHOD(hardware::Return<void>, perform,
- (V1_0::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
- MOCK_METHOD(hardware::Return<void>, perform_1_1,
- (V1_1::Effect_1_1 effect, V1_0::EffectStrength strength, perform_cb cb),
- (override));
- MOCK_METHOD(hardware::Return<void>, perform_1_2,
- (V1_2::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
- MOCK_METHOD(hardware::Return<void>, perform_1_3,
- (V1_3::Effect effect, V1_0::EffectStrength strength, perform_cb cb), (override));
-};
-
-// -------------------------------------------------------------------------------------------------
-
-class VibratorHalWrapperHidlV1_3Test : public Test {
-public:
- void SetUp() override {
- mMockHal = new StrictMock<MockIVibratorV1_3>();
- mMockScheduler = std::make_shared<StrictMock<vibrator::MockCallbackScheduler>>();
- mWrapper = std::make_unique<vibrator::HidlHalWrapperV1_3>(mMockScheduler, mMockHal);
- ASSERT_NE(mWrapper, nullptr);
- }
-
-protected:
- std::shared_ptr<StrictMock<vibrator::MockCallbackScheduler>> mMockScheduler = nullptr;
- std::unique_ptr<vibrator::HalWrapper> mWrapper = nullptr;
- sp<StrictMock<MockIVibratorV1_3>> mMockHal = nullptr;
-};
-
-// -------------------------------------------------------------------------------------------------
-
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestSetExternalControl) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(), setExternalControl(Eq(true)))
- .Times(Exactly(2))
- .WillOnce([]() { return hardware::Return<V1_0::Status>(V1_0::Status::OK); })
- .WillRepeatedly([]() {
- return hardware::Return<V1_0::Status>(V1_0::Status::UNSUPPORTED_OPERATION);
- });
- EXPECT_CALL(*mMockHal.get(), setExternalControl(Eq(false)))
- .Times(Exactly(2))
- .WillOnce([]() { return hardware::Return<V1_0::Status>(V1_0::Status::BAD_VALUE); })
- .WillRepeatedly([]() {
- return hardware::Return<V1_0::Status>(hardware::Status::fromExceptionCode(-1));
- });
- }
-
- ASSERT_TRUE(mWrapper->setExternalControl(true).isOk());
- ASSERT_TRUE(mWrapper->setExternalControl(true).isUnsupported());
- ASSERT_TRUE(mWrapper->setExternalControl(false).isFailed());
- ASSERT_TRUE(mWrapper->setExternalControl(false).isFailed());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoSuccessful) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
- .Times(Exactly(1))
- .WillRepeatedly([]() { return hardware::Return<bool>(true); });
- EXPECT_CALL(*mMockHal.get(), supportsExternalControl()).Times(Exactly(1)).WillOnce([]() {
- return hardware::Return<bool>(true);
- });
- }
-
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL | vibrator::Capabilities::EXTERNAL_CONTROL |
- vibrator::Capabilities::EXTERNAL_AMPLITUDE_CONTROL,
- mWrapper->getInfo().capabilities.value());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoOnlyAmplitudeControl) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillOnce([]() {
- return hardware::Return<bool>(true);
- });
- EXPECT_CALL(*mMockHal.get(), supportsExternalControl()).Times(Exactly(1)).WillOnce([]() {
- return hardware::Return<bool>(false);
- });
- }
-
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, mWrapper->getInfo().capabilities.value());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoOnlyExternalControl) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl()).Times(Exactly(1)).WillOnce([]() {
- return hardware::Return<bool>(false);
- });
- EXPECT_CALL(*mMockHal.get(), supportsExternalControl()).Times(Exactly(1)).WillOnce([]() {
- return hardware::Return<bool>(true);
- });
- }
-
- ASSERT_EQ(vibrator::Capabilities::EXTERNAL_CONTROL, mWrapper->getInfo().capabilities.value());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoNoCapabilities) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
- .Times(Exactly(1))
- .WillRepeatedly([]() { return hardware::Return<bool>(false); });
- EXPECT_CALL(*mMockHal.get(), supportsExternalControl()).Times(Exactly(1)).WillOnce([]() {
- return hardware::Return<bool>(false);
- });
- }
-
- ASSERT_EQ(vibrator::Capabilities::NONE, mWrapper->getInfo().capabilities.value());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoFailed) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
- .Times(Exactly(1))
- .WillRepeatedly([]() {
- return hardware::Return<bool>(hardware::Status::fromExceptionCode(-1));
- });
-
- EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
- .Times(Exactly(1))
- .WillRepeatedly([]() { return hardware::Return<bool>(true); });
- EXPECT_CALL(*mMockHal.get(), supportsExternalControl())
- .Times(Exactly(1))
- .WillRepeatedly([]() {
- return hardware::Return<bool>(hardware::Status::fromExceptionCode(-1));
- });
- }
-
- ASSERT_TRUE(mWrapper->getInfo().capabilities.isFailed());
- ASSERT_TRUE(mWrapper->getInfo().capabilities.isFailed());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoCachesResult) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
- .Times(Exactly(1))
- .WillRepeatedly([]() { return hardware::Return<bool>(true); });
- EXPECT_CALL(*mMockHal.get(), supportsExternalControl()).Times(Exactly(1)).WillOnce([]() {
- return hardware::Return<bool>(false);
- });
- }
-
- std::vector<std::thread> threads;
- for (int i = 0; i < 10; i++) {
- threads.push_back(
- std::thread([&]() { ASSERT_TRUE(mWrapper->getInfo().capabilities.isOk()); }));
- }
- std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
-
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, mWrapper->getInfo().capabilities.value());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestGetInfoDoesNotCacheFailedResult) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
- .Times(Exactly(1))
- .WillRepeatedly([]() {
- return hardware::Return<bool>(hardware::Status::fromExceptionCode(-1));
- });
-
- EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
- .Times(Exactly(1))
- .WillRepeatedly([]() { return hardware::Return<bool>(true); });
- EXPECT_CALL(*mMockHal.get(), supportsExternalControl())
- .Times(Exactly(1))
- .WillRepeatedly([]() {
- return hardware::Return<bool>(hardware::Status::fromExceptionCode(-1));
- });
-
- EXPECT_CALL(*mMockHal.get(), supportsAmplitudeControl())
- .Times(Exactly(1))
- .WillRepeatedly([]() { return hardware::Return<bool>(true); });
- EXPECT_CALL(*mMockHal.get(), supportsExternalControl())
- .Times(Exactly(1))
- .WillRepeatedly([]() { return hardware::Return<bool>(false); });
- }
-
- // Call to supportsAmplitudeControl failed.
- ASSERT_TRUE(mWrapper->getInfo().capabilities.isFailed());
-
- // Call to supportsExternalControl failed.
- ASSERT_TRUE(mWrapper->getInfo().capabilities.isFailed());
-
- // Returns successful result from third call.
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, mWrapper->getInfo().capabilities.value());
-
- // Returns cached successful result.
- ASSERT_EQ(vibrator::Capabilities::AMPLITUDE_CONTROL, mWrapper->getInfo().capabilities.value());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_0) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(),
- perform(Eq(V1_0::Effect::CLICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_0::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
- cb(V1_0::Status::OK, 10);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
- .Times(Exactly(1))
- .WillRepeatedly(vibrator::TriggerSchedulerCallback());
- }
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
- auto result = mWrapper->performEffect(Effect::CLICK, EffectStrength::LIGHT, callback);
-
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(10ms, result.value());
- ASSERT_EQ(1, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_1) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(),
- perform_1_1(Eq(V1_1::Effect_1_1::TICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly([](V1_1::Effect_1_1, V1_0::EffectStrength,
- MockIVibratorV1_3::perform_cb cb) {
- cb(V1_0::Status::OK, 10);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
- .Times(Exactly(1))
- .WillRepeatedly(vibrator::TriggerSchedulerCallback());
- }
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
- auto result = mWrapper->performEffect(Effect::TICK, EffectStrength::LIGHT, callback);
-
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(10ms, result.value());
- ASSERT_EQ(1, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_2) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(),
- perform_1_2(Eq(V1_2::Effect::THUD), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_2::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
- cb(V1_0::Status::OK, 10);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
- .Times(Exactly(1))
- .WillRepeatedly(vibrator::TriggerSchedulerCallback());
- }
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
- auto result = mWrapper->performEffect(Effect::THUD, EffectStrength::LIGHT, callback);
-
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(10ms, result.value());
- ASSERT_EQ(1, *callbackCounter.get());
-}
-
-TEST_F(VibratorHalWrapperHidlV1_3Test, TestPerformEffectV1_3) {
- {
- InSequence seq;
- EXPECT_CALL(*mMockHal.get(),
- perform_1_3(Eq(V1_3::Effect::TEXTURE_TICK), Eq(V1_0::EffectStrength::LIGHT), _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_3::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
- cb(V1_0::Status::OK, 10);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockScheduler.get(), schedule(_, Eq(10ms)))
- .Times(Exactly(1))
- .WillRepeatedly(vibrator::TriggerSchedulerCallback());
- EXPECT_CALL(*mMockHal.get(),
- perform_1_3(Eq(V1_3::Effect::TEXTURE_TICK), Eq(V1_0::EffectStrength::MEDIUM),
- _))
- .Times(Exactly(1))
- .WillRepeatedly(
- [](V1_3::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
- cb(V1_0::Status::UNSUPPORTED_OPERATION, 0);
- return hardware::Return<void>();
- });
- EXPECT_CALL(*mMockHal.get(),
- perform_1_3(Eq(V1_3::Effect::TEXTURE_TICK), Eq(V1_0::EffectStrength::STRONG),
- _))
- .Times(Exactly(2))
- .WillOnce([](V1_3::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb cb) {
- cb(V1_0::Status::BAD_VALUE, 0);
- return hardware::Return<void>();
- })
- .WillRepeatedly(
- [](V1_3::Effect, V1_0::EffectStrength, MockIVibratorV1_3::perform_cb) {
- return hardware::Return<void>(hardware::Status::fromExceptionCode(-1));
- });
- }
-
- std::unique_ptr<int32_t> callbackCounter = std::make_unique<int32_t>();
- auto callback = vibrator::TestFactory::createCountingCallback(callbackCounter.get());
-
- auto result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::LIGHT, callback);
- ASSERT_TRUE(result.isOk());
- ASSERT_EQ(10ms, result.value());
- ASSERT_EQ(1, *callbackCounter.get());
-
- result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::MEDIUM, callback);
- ASSERT_TRUE(result.isUnsupported());
-
- result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::STRONG, callback);
- ASSERT_TRUE(result.isFailed());
-
- result = mWrapper->performEffect(Effect::TEXTURE_TICK, EffectStrength::STRONG, callback);
- ASSERT_TRUE(result.isFailed());
-
- // Callback not triggered for unsupported and on failure
- ASSERT_EQ(1, *callbackCounter.get());
-}
diff --git a/vulkan/tests/libvulkan_test.cpp b/vulkan/tests/libvulkan_test.cpp
index 7c9ef7d..7e4bfd8 100644
--- a/vulkan/tests/libvulkan_test.cpp
+++ b/vulkan/tests/libvulkan_test.cpp
@@ -58,6 +58,7 @@
const char* extensions[] = {
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
+ VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
@@ -164,7 +165,8 @@
<< "No physical device found that supports present to the surface!";
}
- void createDeviceAndGetQueue(std::vector<const char*>& layers) {
+ void createDeviceAndGetQueue(std::vector<const char*>& layers,
+ std::vector<const char*> inExtensions = {}) {
ASSERT_NE((void*)VK_NULL_HANDLE, mPhysicalDev);
ASSERT_NE(UINT32_MAX, mPresentQueueFamily);
@@ -182,12 +184,14 @@
deviceInfo.enabledLayerCount = layers.size();
deviceInfo.ppEnabledLayerNames = layers.data();
- const char* extensions[] = {
+ std::vector<const char*> extensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
};
- deviceInfo.enabledExtensionCount =
- sizeof(extensions) / sizeof(extensions[0]);
- deviceInfo.ppEnabledExtensionNames = extensions;
+ for (auto extension : inExtensions) {
+ extensions.push_back(extension);
+ }
+ deviceInfo.enabledExtensionCount = extensions.size();
+ deviceInfo.ppEnabledExtensionNames = extensions.data();
VkResult res =
vkCreateDevice(mPhysicalDev, &deviceInfo, nullptr, &mDevice);
@@ -436,6 +440,168 @@
} // namespace
+// Passing state in these tests requires global state. Wrap each test in an
+// anonymous namespace to prevent conflicting names.
+namespace {
+
+static bool g_returnNotSupportedOnce = true;
+
+VKAPI_ATTR VkResult VKAPI_CALL
+Hook_GetPhysicalDeviceImageFormatProperties2_NotSupportedOnce(
+ VkPhysicalDevice /*physicalDevice*/,
+ const VkPhysicalDeviceImageFormatInfo2* /*pImageFormatInfo*/,
+ VkImageFormatProperties2* /*pImageFormatProperties*/) {
+ if (g_returnNotSupportedOnce) {
+ g_returnNotSupportedOnce = false;
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+ return VK_SUCCESS;
+}
+
+TEST_F(AImageReaderVulkanSwapchainTest, SurfaceFormats2KHR_IgnoreNotSupported) {
+ // BUG: 357903074
+ // Verify that vkGetPhysicalDeviceSurfaceFormats2KHR properly
+ // ignores VK_ERROR_FORMAT_NOT_SUPPORTED and continues enumerating formats.
+ std::vector<const char*> instanceLayers;
+ createVulkanInstance(instanceLayers);
+ createAImageReader(640, 480, AIMAGE_FORMAT_PRIVATE, 3);
+ getANativeWindowFromReader();
+ createVulkanSurface();
+ pickPhysicalDeviceAndQueueFamily();
+
+ auto& pdevDispatchTable = vulkan::driver::GetData(mPhysicalDev).driver;
+ pdevDispatchTable.GetPhysicalDeviceImageFormatProperties2 =
+ Hook_GetPhysicalDeviceImageFormatProperties2_NotSupportedOnce;
+
+ PFN_vkGetPhysicalDeviceSurfaceFormats2KHR
+ pfnGetPhysicalDeviceSurfaceFormats2KHR =
+ reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormats2KHR>(
+ vkGetInstanceProcAddr(mVkInstance,
+ "vkGetPhysicalDeviceSurfaceFormats2KHR"));
+ ASSERT_NE(nullptr, pfnGetPhysicalDeviceSurfaceFormats2KHR)
+ << "Could not get pointer to vkGetPhysicalDeviceSurfaceFormats2KHR";
+
+ VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo2{};
+ surfaceInfo2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
+ surfaceInfo2.pNext = nullptr;
+ surfaceInfo2.surface = mSurface;
+
+ uint32_t formatCount = 0;
+ VkResult res = pfnGetPhysicalDeviceSurfaceFormats2KHR(
+ mPhysicalDev, &surfaceInfo2, &formatCount, nullptr);
+
+ // If the loader never tries a second format, it might fail or 0-out the
+ // formatCount. The patch ensures it continues to the next format rather
+ // than bailing out on the first NOT_SUPPORTED.
+ ASSERT_EQ(VK_SUCCESS, res)
+ << "vkGetPhysicalDeviceSurfaceFormats2KHR failed unexpectedly";
+ ASSERT_GT(formatCount, 0U)
+ << "No surface formats found; the loader may have bailed early.";
+
+ std::vector<VkSurfaceFormat2KHR> formats(formatCount);
+ for (auto& f : formats) {
+ f.sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR;
+ f.pNext = nullptr;
+ }
+ res = pfnGetPhysicalDeviceSurfaceFormats2KHR(mPhysicalDev, &surfaceInfo2,
+ &formatCount, formats.data());
+ ASSERT_EQ(VK_SUCCESS, res) << "Failed to retrieve surface formats";
+
+ LOGI(
+ "SurfaceFormats2KHR_IgnoreNotSupported test: found %u formats after "
+ "ignoring NOT_SUPPORTED",
+ formatCount);
+
+ cleanUpSwapchainForTest();
+}
+
+} // namespace
+
+namespace {
+
+TEST_F(AImageReaderVulkanSwapchainTest, MutableFormatSwapchainTest) {
+ // Test swapchain with mutable format extension
+ std::vector<const char*> instanceLayers;
+ std::vector<const char*> deviceLayers;
+ std::vector<const char*> deviceExtensions = {
+ VK_KHR_SWAPCHAIN_EXTENSION_NAME,
+ VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME,
+ VK_KHR_MAINTENANCE2_EXTENSION_NAME,
+ VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME};
+
+ createVulkanInstance(instanceLayers);
+ createAImageReader(640, 480, AIMAGE_FORMAT_PRIVATE, 3);
+ getANativeWindowFromReader();
+ createVulkanSurface();
+ pickPhysicalDeviceAndQueueFamily();
+ createDeviceAndGetQueue(deviceLayers, deviceExtensions);
+
+ ASSERT_NE((VkDevice)VK_NULL_HANDLE, mDevice);
+ ASSERT_NE((VkSurfaceKHR)VK_NULL_HANDLE, mSurface);
+
+ VkSurfaceCapabilitiesKHR surfaceCaps{};
+ VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(mPhysicalDev, mSurface,
+ &surfaceCaps));
+
+ uint32_t formatCount = 0;
+ vkGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDev, mSurface, &formatCount,
+ nullptr);
+ ASSERT_GT(formatCount, 0U);
+ std::vector<VkSurfaceFormatKHR> formats(formatCount);
+ vkGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDev, mSurface, &formatCount,
+ formats.data());
+
+ VkFormat viewFormats[2] = {formats[0].format, formats[0].format};
+ if (formatCount > 1) {
+ viewFormats[1] = formats[1].format;
+ }
+
+ VkImageFormatListCreateInfoKHR formatList{};
+ formatList.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
+ formatList.viewFormatCount = 2;
+ formatList.pViewFormats = viewFormats;
+
+ VkSwapchainCreateInfoKHR swapchainInfo{};
+ swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ swapchainInfo.pNext = &formatList;
+ swapchainInfo.surface = mSurface;
+ swapchainInfo.minImageCount = surfaceCaps.minImageCount + 1;
+ swapchainInfo.imageFormat = formats[0].format;
+ swapchainInfo.imageColorSpace = formats[0].colorSpace;
+ swapchainInfo.imageExtent = surfaceCaps.currentExtent;
+ swapchainInfo.imageArrayLayers = 1;
+ swapchainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ swapchainInfo.preTransform = surfaceCaps.currentTransform;
+ swapchainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
+ swapchainInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR;
+ swapchainInfo.clipped = VK_TRUE;
+
+ swapchainInfo.flags = VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR;
+
+ uint32_t queueFamilyIndices[] = {mPresentQueueFamily};
+ swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ swapchainInfo.queueFamilyIndexCount = 1;
+ swapchainInfo.pQueueFamilyIndices = queueFamilyIndices;
+
+ VkResult res =
+ vkCreateSwapchainKHR(mDevice, &swapchainInfo, nullptr, &mSwapchain);
+ if (res == VK_SUCCESS) {
+ LOGI("Mutable format swapchain created successfully");
+
+ uint32_t imageCount = 0;
+ vkGetSwapchainImagesKHR(mDevice, mSwapchain, &imageCount, nullptr);
+ ASSERT_GT(imageCount, 0U);
+ } else {
+ LOGI(
+ "Mutable format swapchain creation failed (extension may not be "
+ "supported)");
+ }
+
+ cleanUpSwapchainForTest();
+}
+
+} // namespace
+
} // namespace libvulkantest
} // namespace android
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 8c0cce2..18fef2b 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -986,6 +986,13 @@
template <typename Visitor>
inline bool Iterate(Visitor* visitor,
+ VkJsonExtImage2DViewOf3DFeatures* features) {
+ return visitor->Visit("image2DViewOf3DFeaturesEXT",
+ &features->image_2D_view_of_3D_features_EXT);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
VkJsonExtShaderFloat16Int8Features* features) {
return visitor->Visit("shaderFloat16Int8FeaturesKHR",
&features->shader_float16_int8_features_khr);
@@ -1093,6 +1100,13 @@
template <typename Visitor>
inline bool Iterate(Visitor* visitor,
+ VkPhysicalDeviceImage2DViewOf3DFeaturesEXT* features) {
+ return visitor->Visit("image2DViewOf3D", &features->image2DViewOf3D) &&
+ visitor->Visit("sampler2DViewOf3D", &features->sampler2DViewOf3D);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
VkPhysicalDeviceShaderFloat16Int8FeaturesKHR* features) {
return visitor->Visit("shaderFloat16", &features->shaderFloat16) &&
visitor->Visit("shaderInt8", &features->shaderInt8);
@@ -1241,6 +1255,10 @@
ret &= visitor->Visit("VK_KHR_variable_pointers",
&device->ext_variable_pointer_features);
}
+ if (device->ext_image_2d_view_of_3d_features.reported) {
+ ret &= visitor->Visit("VK_EXT_image_2d_view_of_3d",
+ &device->ext_image_2d_view_of_3d_features);
+ }
if (device->ext_shader_float16_int8_features.reported) {
ret &= visitor->Visit("VK_KHR_shader_float16_int8",
&device->ext_shader_float16_int8_features);
diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h
index 5818c73..87a76c1 100644
--- a/vulkan/vkjson/vkjson.h
+++ b/vulkan/vkjson/vkjson.h
@@ -58,6 +58,16 @@
VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features_khr;
};
+struct VkJsonExtImage2DViewOf3DFeatures {
+ VkJsonExtImage2DViewOf3DFeatures() {
+ reported = false;
+ memset(&image_2D_view_of_3D_features_EXT, 0,
+ sizeof(VkPhysicalDeviceImage2DViewOf3DFeaturesEXT));
+ }
+ bool reported;
+ VkPhysicalDeviceImage2DViewOf3DFeaturesEXT image_2D_view_of_3D_features_EXT;
+};
+
struct VkJsonExtShaderFloat16Int8Features {
VkJsonExtShaderFloat16Int8Features() {
reported = false;
@@ -115,6 +125,7 @@
VkPhysicalDeviceFeatures features;
VkJsonExtDriverProperties ext_driver_properties;
VkJsonExtVariablePointerFeatures ext_variable_pointer_features;
+ VkJsonExtImage2DViewOf3DFeatures ext_image_2d_view_of_3d_features;
VkJsonExtShaderFloat16Int8Features ext_shader_float16_int8_features;
VkPhysicalDeviceMemoryProperties memory;
std::vector<VkQueueFamilyProperties> queues;
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index 32bc50b..04bb446 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -103,6 +103,16 @@
features.pNext =
&device.ext_variable_pointer_features.variable_pointer_features_khr;
}
+ if (HasExtension("VK_EXT_image_2d_view_of_3d", device.extensions)) {
+ device.ext_image_2d_view_of_3d_features.reported = true;
+ device.ext_image_2d_view_of_3d_features.image_2D_view_of_3D_features_EXT
+ .sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT;
+ device.ext_image_2d_view_of_3d_features.image_2D_view_of_3D_features_EXT
+ .pNext = features.pNext;
+ features.pNext = &device.ext_image_2d_view_of_3d_features
+ .image_2D_view_of_3D_features_EXT;
+ }
if (HasExtension("VK_KHR_shader_float16_int8", device.extensions)) {
device.ext_shader_float16_int8_features.reported = true;
device.ext_shader_float16_int8_features.shader_float16_int8_features_khr