From 5614ca04327d6c1db2dbaccee20f9c52fa4a95e4 Mon Sep 17 00:00:00 2001 From: tangcheng Date: Thu, 7 Apr 2022 14:26:05 +0800 Subject: [PATCH 0001/1187] Fix libgui cts crash bug While enabling #define LOG_NDEBUG 0, run camera cts test command: run cts -m CtsCameraTestCases -t android.hardware.camera2.cts.MultiViewTest#testSharedSurfaceImageReaderSwitch the libgui will crash due to nullptr, fix this by add nullptr judgement when pointing to the Graphicbuffer handle Bug: 228349805 Signed-off-by: tangcheng Change-Id: I69a84bdb5208b16df88f5f09f45c1a93ad2afe01 --- libs/gui/BufferQueueProducer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 5fe5e71db9..2d56dd37c2 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -606,7 +606,8 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp* ou BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x", *outSlot, mSlots[*outSlot].mFrameNumber, - mSlots[*outSlot].mGraphicBuffer->handle, returnFlags); + mSlots[*outSlot].mGraphicBuffer != nullptr ? + mSlots[*outSlot].mGraphicBuffer->handle : nullptr, returnFlags); if (outBufferAge) { *outBufferAge = mCore->mBufferAge; -- GitLab From ad07441030340f3c455ab52252f9a625b829f2c4 Mon Sep 17 00:00:00 2001 From: Zixuan Qu Date: Wed, 23 Nov 2022 19:20:58 +0000 Subject: [PATCH 0002/1187] Make VelocityControl::getParameters() const. Bug: None Test: Presubmit Change-Id: Ie9951171ef42f7b3fc0eb3349c605d7f850082e2 --- include/input/VelocityControl.h | 2 +- libs/input/VelocityControl.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/input/VelocityControl.h b/include/input/VelocityControl.h index f3c201e7c4..b78f63e1ae 100644 --- a/include/input/VelocityControl.h +++ b/include/input/VelocityControl.h @@ -88,7 +88,7 @@ public: VelocityControl(); /* Gets the various parameters. */ - VelocityControlParameters& getParameters(); + const VelocityControlParameters& getParameters() const; /* Sets the various parameters. */ void setParameters(const VelocityControlParameters& parameters); diff --git a/libs/input/VelocityControl.cpp b/libs/input/VelocityControl.cpp index 5c008b1158..0b5f8e5091 100644 --- a/libs/input/VelocityControl.cpp +++ b/libs/input/VelocityControl.cpp @@ -37,7 +37,7 @@ VelocityControl::VelocityControl() { reset(); } -VelocityControlParameters& VelocityControl::getParameters() { +const VelocityControlParameters& VelocityControl::getParameters() const{ return mParameters; } -- GitLab From 1f204c6f27bb6115734e6d0b2e6261498a2ae806 Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Fri, 3 Feb 2023 22:01:09 +0000 Subject: [PATCH 0003/1187] Change name of the fake service manager Change the name of the class and the exported include directory to make it more obvious when this fake service manager is being used. Test: m Bug: 259548383 Change-Id: I98205c49babd2e91a8f3f643de9f3eccca302c9c --- libs/fakeservicemanager/Android.bp | 6 ++-- ...viceManager.cpp => FakeServiceManager.cpp} | 34 +++++++++---------- ...{ServiceManager.h => FakeServiceManager.h} | 4 +-- libs/fakeservicemanager/test_sm.cpp | 26 +++++++------- services/sensorservice/aidl/fuzzer/fuzzer.cpp | 4 +-- 5 files changed, 37 insertions(+), 37 deletions(-) rename libs/fakeservicemanager/{ServiceManager.cpp => FakeServiceManager.cpp} (65%) rename libs/fakeservicemanager/include/fakeservicemanager/{ServiceManager.h => FakeServiceManager.h} (96%) diff --git a/libs/fakeservicemanager/Android.bp b/libs/fakeservicemanager/Android.bp index 29924ff500..96dcce11ea 100644 --- a/libs/fakeservicemanager/Android.bp +++ b/libs/fakeservicemanager/Android.bp @@ -11,7 +11,7 @@ cc_defaults { name: "fakeservicemanager_defaults", host_supported: true, srcs: [ - "ServiceManager.cpp", + "FakeServiceManager.cpp", ], shared_libs: [ @@ -28,7 +28,7 @@ cc_defaults { cc_library { name: "libfakeservicemanager", defaults: ["fakeservicemanager_defaults"], - export_include_dirs: ["include/fakeservicemanager"], + export_include_dirs: ["include"], } cc_test_host { @@ -38,5 +38,5 @@ cc_test_host { "test_sm.cpp", ], static_libs: ["libgmock"], - local_include_dirs: ["include/fakeservicemanager"], + local_include_dirs: ["include"], } diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/FakeServiceManager.cpp similarity index 65% rename from libs/fakeservicemanager/ServiceManager.cpp rename to libs/fakeservicemanager/FakeServiceManager.cpp index 1109ad8594..3272bbc1aa 100644 --- a/libs/fakeservicemanager/ServiceManager.cpp +++ b/libs/fakeservicemanager/FakeServiceManager.cpp @@ -14,18 +14,18 @@ * limitations under the License. */ -#include "ServiceManager.h" +#include "fakeservicemanager/FakeServiceManager.h" namespace android { -ServiceManager::ServiceManager() {} +FakeServiceManager::FakeServiceManager() {} -sp ServiceManager::getService( const String16& name) const { +sp FakeServiceManager::getService( const String16& name) const { // Servicemanager is single-threaded and cannot block. This method exists for legacy reasons. return checkService(name); } -sp ServiceManager::checkService( const String16& name) const { +sp FakeServiceManager::checkService( const String16& name) const { auto it = mNameToService.find(name); if (it == mNameToService.end()) { return nullptr; @@ -33,7 +33,7 @@ sp ServiceManager::checkService( const String16& name) const { return it->second; } -status_t ServiceManager::addService(const String16& name, const sp& service, +status_t FakeServiceManager::addService(const String16& name, const sp& service, bool /*allowIsolated*/, int /*dumpsysFlags*/) { if (service == nullptr) { @@ -43,7 +43,7 @@ status_t ServiceManager::addService(const String16& name, const sp& ser return NO_ERROR; } -Vector ServiceManager::listServices(int /*dumpsysFlags*/) { +Vector FakeServiceManager::listServices(int /*dumpsysFlags*/) { Vector services; for (auto const& [name, service] : mNameToService) { (void) service; @@ -52,19 +52,19 @@ Vector ServiceManager::listServices(int /*dumpsysFlags*/) { return services; } -IBinder* ServiceManager::onAsBinder() { +IBinder* FakeServiceManager::onAsBinder() { return nullptr; } -sp ServiceManager::waitForService(const String16& name) { +sp FakeServiceManager::waitForService(const String16& name) { return checkService(name); } -bool ServiceManager::isDeclared(const String16& name) { +bool FakeServiceManager::isDeclared(const String16& name) { return mNameToService.find(name) != mNameToService.end(); } -Vector ServiceManager::getDeclaredInstances(const String16& name) { +Vector FakeServiceManager::getDeclaredInstances(const String16& name) { Vector out; const String16 prefix = name + String16("/"); for (const auto& [registeredName, service] : mNameToService) { @@ -76,38 +76,38 @@ Vector ServiceManager::getDeclaredInstances(const String16& name) { return out; } -std::optional ServiceManager::updatableViaApex(const String16& name) { +std::optional FakeServiceManager::updatableViaApex(const String16& name) { (void)name; return std::nullopt; } -Vector ServiceManager::getUpdatableNames(const String16& apexName) { +Vector FakeServiceManager::getUpdatableNames(const String16& apexName) { (void)apexName; return {}; } -std::optional ServiceManager::getConnectionInfo( +std::optional FakeServiceManager::getConnectionInfo( const String16& name) { (void)name; return std::nullopt; } -status_t ServiceManager::registerForNotifications(const String16&, +status_t FakeServiceManager::registerForNotifications(const String16&, const sp&) { return INVALID_OPERATION; } -status_t ServiceManager::unregisterForNotifications(const String16&, +status_t FakeServiceManager::unregisterForNotifications(const String16&, const sp&) { return INVALID_OPERATION; } -std::vector ServiceManager::getServiceDebugInfo() { +std::vector FakeServiceManager::getServiceDebugInfo() { std::vector ret; return ret; } -void ServiceManager::clear() { +void FakeServiceManager::clear() { mNameToService.clear(); } } // namespace android diff --git a/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h similarity index 96% rename from libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h rename to libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h index ba6bb7d95b..97add24ac8 100644 --- a/libs/fakeservicemanager/include/fakeservicemanager/ServiceManager.h +++ b/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h @@ -28,9 +28,9 @@ namespace android { * A local host simple implementation of IServiceManager, that does not * communicate over binder. */ -class ServiceManager : public IServiceManager { +class FakeServiceManager : public IServiceManager { public: - ServiceManager(); + FakeServiceManager(); sp getService( const String16& name) const override; diff --git a/libs/fakeservicemanager/test_sm.cpp b/libs/fakeservicemanager/test_sm.cpp index 8682c1c795..6fc21c65d1 100644 --- a/libs/fakeservicemanager/test_sm.cpp +++ b/libs/fakeservicemanager/test_sm.cpp @@ -21,14 +21,14 @@ #include #include -#include "ServiceManager.h" +#include "fakeservicemanager/FakeServiceManager.h" using android::sp; using android::BBinder; using android::IBinder; using android::OK; using android::status_t; -using android::ServiceManager; +using android::FakeServiceManager; using android::String16; using android::IServiceManager; using testing::ElementsAre; @@ -45,19 +45,19 @@ static sp getBinder() { } TEST(AddService, HappyHappy) { - auto sm = new ServiceManager(); + auto sm = new FakeServiceManager(); EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK); } TEST(AddService, SadNullBinder) { - auto sm = new ServiceManager(); + auto sm = new FakeServiceManager(); EXPECT_EQ(sm->addService(String16("foo"), nullptr, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), android::UNEXPECTED_NULL); } TEST(AddService, HappyOverExistingService) { - auto sm = new ServiceManager(); + auto sm = new FakeServiceManager(); EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK); EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/, @@ -65,7 +65,7 @@ TEST(AddService, HappyOverExistingService) { } TEST(AddService, HappyClearAddedService) { - auto sm = new ServiceManager(); + auto sm = new FakeServiceManager(); EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK); EXPECT_NE(sm->getService(String16("foo")), nullptr); @@ -74,7 +74,7 @@ TEST(AddService, HappyClearAddedService) { } TEST(GetService, HappyHappy) { - auto sm = new ServiceManager(); + auto sm = new FakeServiceManager(); sp service = getBinder(); EXPECT_EQ(sm->addService(String16("foo"), service, false /*allowIsolated*/, @@ -84,13 +84,13 @@ TEST(GetService, HappyHappy) { } TEST(GetService, NonExistant) { - auto sm = new ServiceManager(); + auto sm = new FakeServiceManager(); EXPECT_EQ(sm->getService(String16("foo")), nullptr); } TEST(ListServices, AllServices) { - auto sm = new ServiceManager(); + auto sm = new FakeServiceManager(); EXPECT_EQ(sm->addService(String16("sd"), getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK); @@ -109,13 +109,13 @@ TEST(ListServices, AllServices) { } TEST(WaitForService, NonExistant) { - auto sm = new ServiceManager(); + auto sm = new FakeServiceManager(); EXPECT_EQ(sm->waitForService(String16("foo")), nullptr); } TEST(WaitForService, HappyHappy) { - auto sm = new ServiceManager(); + auto sm = new FakeServiceManager(); sp service = getBinder(); EXPECT_EQ(sm->addService(String16("foo"), service, false /*allowIsolated*/, @@ -125,13 +125,13 @@ TEST(WaitForService, HappyHappy) { } TEST(IsDeclared, NonExistant) { - auto sm = new ServiceManager(); + auto sm = new FakeServiceManager(); EXPECT_FALSE(sm->isDeclared(String16("foo"))); } TEST(IsDeclared, HappyHappy) { - auto sm = new ServiceManager(); + auto sm = new FakeServiceManager(); sp service = getBinder(); EXPECT_EQ(sm->addService(String16("foo"), service, false /*allowIsolated*/, diff --git a/services/sensorservice/aidl/fuzzer/fuzzer.cpp b/services/sensorservice/aidl/fuzzer/fuzzer.cpp index 1b63d76953..ee8ceb354c 100644 --- a/services/sensorservice/aidl/fuzzer/fuzzer.cpp +++ b/services/sensorservice/aidl/fuzzer/fuzzer.cpp @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include @@ -29,7 +29,7 @@ using ndk::SharedRefBase; [[clang::no_destroy]] static std::once_flag gSmOnce; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - static android::sp fakeServiceManager = new android::ServiceManager(); + static android::sp fakeServiceManager = new android::FakeServiceManager(); std::call_once(gSmOnce, [&] { setDefaultServiceManager(fakeServiceManager); }); fakeServiceManager->clear(); -- GitLab From 957985be86bb17f227ff0c8aefbed7d1d1fe54fe Mon Sep 17 00:00:00 2001 From: Brian Lindahl Date: Tue, 31 Jan 2023 15:42:47 -0700 Subject: [PATCH 0004/1187] Increase frame history size when SF buffer queue size changes While the existing frame history size is sufficient for graphics, the buffer queue sizes for video playback are much larger (more pipelined) so in order for accurate frame tracking of video frames, increase the frame event history size based on the buffer queue size (pipeline size), so that buffer queue producers can always track all frames that have been queued. Bug: 234833109 Test: atest DecoderRenderTest Change-Id: Ida587a239a03f74ebb099d8634ff722a500fcdda --- libs/gui/BLASTBufferQueue.cpp | 45 ++++++- libs/gui/BufferQueueProducer.cpp | 9 ++ libs/gui/FrameTimestamps.cpp | 115 ++++++++++++++++-- libs/gui/bufferqueue/1.0/Conversion.cpp | 15 +-- .../1.0/H2BGraphicBufferProducer.cpp | 5 +- libs/gui/include/gui/BLASTBufferQueue.h | 5 + libs/gui/include/gui/BufferQueueProducer.h | 5 + libs/gui/include/gui/FrameTimestamps.h | 15 ++- 8 files changed, 187 insertions(+), 27 deletions(-) diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 60603ba50a..948611218b 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -133,6 +133,11 @@ void BLASTBufferItemConsumer::onSidebandStreamChanged() { } } +void BLASTBufferItemConsumer::resizeFrameEventHistory(size_t newSize) { + Mutex::Autolock lock(mMutex); + mFrameEventHistory.resize(newSize); +} + BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinationFrame) : mSurfaceControl(nullptr), mSize(1, 1), @@ -1036,8 +1041,9 @@ public: // can be non-blocking when the producer is in the client process. class BBQBufferQueueProducer : public BufferQueueProducer { public: - BBQBufferQueueProducer(const sp& core) - : BufferQueueProducer(core, false /* consumerIsSurfaceFlinger*/) {} + BBQBufferQueueProducer(const sp& core, wp bbq) + : BufferQueueProducer(core, false /* consumerIsSurfaceFlinger*/), + mBLASTBufferQueue(std::move(bbq)) {} status_t connect(const sp& listener, int api, bool producerControlledByApp, QueueBufferOutput* output) override { @@ -1049,6 +1055,26 @@ public: producerControlledByApp, output); } + // We want to resize the frame history when changing the size of the buffer queue + status_t setMaxDequeuedBufferCount(int maxDequeuedBufferCount) override { + int maxBufferCount; + status_t status = BufferQueueProducer::setMaxDequeuedBufferCount(maxDequeuedBufferCount, + &maxBufferCount); + // if we can't determine the max buffer count, then just skip growing the history size + if (status == OK) { + size_t newFrameHistorySize = maxBufferCount + 2; // +2 because triple buffer rendering + // optimize away resizing the frame history unless it will grow + if (newFrameHistorySize > FrameEventHistory::INITIAL_MAX_FRAME_HISTORY) { + sp bbq = mBLASTBufferQueue.promote(); + if (bbq != nullptr) { + ALOGV("increasing frame history size to %zu", newFrameHistorySize); + bbq->resizeFrameEventHistory(newFrameHistorySize); + } + } + } + return status; + } + int query(int what, int* value) override { if (what == NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER) { *value = 1; @@ -1056,6 +1082,9 @@ public: } return BufferQueueProducer::query(what, value); } + +private: + const wp mBLASTBufferQueue; }; // Similar to BufferQueue::createBufferQueue but creates an adapter specific bufferqueue producer. @@ -1070,7 +1099,7 @@ void BLASTBufferQueue::createBufferQueue(sp* outProducer sp core(new BufferQueueCore()); LOG_ALWAYS_FATAL_IF(core == nullptr, "BLASTBufferQueue: failed to create BufferQueueCore"); - sp producer(new BBQBufferQueueProducer(core)); + sp producer(new BBQBufferQueueProducer(core, this)); LOG_ALWAYS_FATAL_IF(producer == nullptr, "BLASTBufferQueue: failed to create BBQBufferQueueProducer"); @@ -1083,6 +1112,16 @@ void BLASTBufferQueue::createBufferQueue(sp* outProducer *outConsumer = consumer; } +void BLASTBufferQueue::resizeFrameEventHistory(size_t newSize) { + // This can be null during creation of the buffer queue, but resizing won't do anything at that + // point in time, so just ignore. This can go away once the class relationships and lifetimes of + // objects are cleaned up with a major refactor of BufferQueue as a whole. + if (mBufferItemConsumer != nullptr) { + std::unique_lock _lock{mMutex}; + mBufferItemConsumer->resizeFrameEventHistory(newSize); + } +} + PixelFormat BLASTBufferQueue::convertBufferFormat(PixelFormat& format) { PixelFormat convertedFormat = format; switch (format) { diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 5fe5e71db9..9eb1a9f526 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -119,6 +119,12 @@ status_t BufferQueueProducer::requestBuffer(int slot, sp* buf) { status_t BufferQueueProducer::setMaxDequeuedBufferCount( int maxDequeuedBuffers) { + int maxBufferCount; + return setMaxDequeuedBufferCount(maxDequeuedBuffers, &maxBufferCount); +} + +status_t BufferQueueProducer::setMaxDequeuedBufferCount(int maxDequeuedBuffers, + int* maxBufferCount) { ATRACE_CALL(); BQ_LOGV("setMaxDequeuedBufferCount: maxDequeuedBuffers = %d", maxDequeuedBuffers); @@ -134,6 +140,8 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount( return NO_INIT; } + *maxBufferCount = mCore->getMaxBufferCountLocked(); + if (maxDequeuedBuffers == mCore->mMaxDequeuedBufferCount) { return NO_ERROR; } @@ -183,6 +191,7 @@ status_t BufferQueueProducer::setMaxDequeuedBufferCount( return BAD_VALUE; } mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers; + *maxBufferCount = mCore->getMaxBufferCountLocked(); VALIDATE_CONSISTENCY(); if (delta < 0) { listener = mCore->mConsumerListener; diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp index e2ea3f9ab1..f3eb4e83aa 100644 --- a/libs/gui/FrameTimestamps.cpp +++ b/libs/gui/FrameTimestamps.cpp @@ -168,10 +168,11 @@ struct FrameNumberEqual { } // namespace -const size_t FrameEventHistory::MAX_FRAME_HISTORY = +const size_t FrameEventHistory::INITIAL_MAX_FRAME_HISTORY = sysprop::LibGuiProperties::frame_event_history_size().value_or(8); -FrameEventHistory::FrameEventHistory() : mFrames(std::vector(MAX_FRAME_HISTORY)) {} +FrameEventHistory::FrameEventHistory() + : mFrames(std::vector(INITIAL_MAX_FRAME_HISTORY)) {} FrameEventHistory::~FrameEventHistory() = default; @@ -227,7 +228,6 @@ void FrameEventHistory::dump(std::string& outString) const { } } - // ============================================================================ // ProducerFrameEventHistory // ============================================================================ @@ -273,6 +273,13 @@ void ProducerFrameEventHistory::applyDelta( const FrameEventHistoryDelta& delta) { mCompositorTiming = delta.mCompositorTiming; + // Deltas should have enough reserved capacity for the consumer-side, therefore if there's a + // different capacity, we re-sized on the consumer side and now need to resize on the producer + // side. + if (delta.mDeltas.capacity() > mFrames.capacity()) { + resize(delta.mDeltas.capacity()); + } + for (auto& d : delta.mDeltas) { // Avoid out-of-bounds access. if (CC_UNLIKELY(d.mIndex >= mFrames.size())) { @@ -349,13 +356,48 @@ std::shared_ptr ProducerFrameEventHistory::createFenceTime( return std::make_shared(fence); } +void ProducerFrameEventHistory::resize(size_t newSize) { + // we don't want to drop events by resizing too small, so don't resize in the negative direction + if (newSize <= mFrames.size()) { + return; + } + + // This algorithm for resizing needs to be the same as ConsumerFrameEventHistory::resize, + // because the indexes need to match when communicating the FrameEventDeltas. + + // We need to find the oldest frame, because that frame needs to move to index 0 in the new + // frame history. + size_t oldestFrameIndex = 0; + size_t oldestFrameNumber = INT32_MAX; + for (size_t i = 0; i < mFrames.size(); ++i) { + if (mFrames[i].frameNumber < oldestFrameNumber && mFrames[i].valid) { + oldestFrameNumber = mFrames[i].frameNumber; + oldestFrameIndex = i; + } + } + + // move the existing frame information into a new vector, so that the oldest frames are at + // index 0, and the latest frames are at the end of the vector + std::vector newFrames(newSize); + size_t oldI = oldestFrameIndex; + size_t newI = 0; + do { + if (mFrames[oldI].valid) { + newFrames[newI++] = std::move(mFrames[oldI]); + } + oldI = (oldI + 1) % mFrames.size(); + } while (oldI != oldestFrameIndex); + + mFrames = std::move(newFrames); + mAcquireOffset = 0; // this is just a hint, so setting this to anything is fine +} // ============================================================================ // ConsumerFrameEventHistory // ============================================================================ ConsumerFrameEventHistory::ConsumerFrameEventHistory() - : mFramesDirty(std::vector(MAX_FRAME_HISTORY)) {} + : mFramesDirty(std::vector(INITIAL_MAX_FRAME_HISTORY)) {} ConsumerFrameEventHistory::~ConsumerFrameEventHistory() = default; @@ -489,6 +531,36 @@ void ConsumerFrameEventHistory::getAndResetDelta( } } +void ConsumerFrameEventHistory::resize(size_t newSize) { + // we don't want to drop events by resizing too small, so don't resize in the negative direction + if (newSize <= mFrames.size()) { + return; + } + + // This algorithm for resizing needs to be the same as ProducerFrameEventHistory::resize, + // because the indexes need to match when communicating the FrameEventDeltas. + + // move the existing frame information into a new vector, so that the oldest frames are at + // index 0, and the latest frames are towards the end of the vector + std::vector newFrames(newSize); + std::vector newFramesDirty(newSize); + size_t oldestFrameIndex = mQueueOffset; + size_t oldI = oldestFrameIndex; + size_t newI = 0; + do { + if (mFrames[oldI].valid) { + newFrames[newI] = std::move(mFrames[oldI]); + newFramesDirty[newI] = mFramesDirty[oldI]; + newI += 1; + } + oldI = (oldI + 1) % mFrames.size(); + } while (oldI != oldestFrameIndex); + + mFrames = std::move(newFrames); + mFramesDirty = std::move(newFramesDirty); + mQueueOffset = newI; + mCompositionOffset = 0; // this is just a hint, so setting this to anything is fine +} // ============================================================================ // FrameEventsDelta @@ -558,8 +630,7 @@ status_t FrameEventsDelta::flatten(void*& buffer, size_t& size, int*& fds, return NO_MEMORY; } - if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY || - mIndex > std::numeric_limits::max()) { + if (mIndex >= UINT8_MAX || mIndex < 0) { return BAD_VALUE; } @@ -601,7 +672,7 @@ status_t FrameEventsDelta::unflatten(void const*& buffer, size_t& size, uint16_t temp16 = 0; FlattenableUtils::read(buffer, size, temp16); mIndex = temp16; - if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY) { + if (mIndex >= UINT8_MAX) { return BAD_VALUE; } uint8_t temp8 = 0; @@ -627,6 +698,25 @@ status_t FrameEventsDelta::unflatten(void const*& buffer, size_t& size, return NO_ERROR; } +uint64_t FrameEventsDelta::getFrameNumber() const { + return mFrameNumber; +} + +bool FrameEventsDelta::getLatchTime(nsecs_t* latchTime) const { + if (mLatchTime == FrameEvents::TIMESTAMP_PENDING) { + return false; + } + *latchTime = mLatchTime; + return true; +} + +bool FrameEventsDelta::getDisplayPresentFence(sp* fence) const { + if (mDisplayPresentFence.fence == Fence::NO_FENCE) { + return false; + } + *fence = mDisplayPresentFence.fence; + return true; +} // ============================================================================ // FrameEventHistoryDelta @@ -665,7 +755,7 @@ size_t FrameEventHistoryDelta::getFdCount() const { status_t FrameEventHistoryDelta::flatten( void*& buffer, size_t& size, int*& fds, size_t& count) const { - if (mDeltas.size() > FrameEventHistory::MAX_FRAME_HISTORY) { + if (mDeltas.size() > UINT8_MAX) { return BAD_VALUE; } if (size < getFlattenedSize()) { @@ -695,7 +785,7 @@ status_t FrameEventHistoryDelta::unflatten( uint32_t deltaCount = 0; FlattenableUtils::read(buffer, size, deltaCount); - if (deltaCount > FrameEventHistory::MAX_FRAME_HISTORY) { + if (deltaCount > UINT8_MAX) { return BAD_VALUE; } mDeltas.resize(deltaCount); @@ -708,5 +798,12 @@ status_t FrameEventHistoryDelta::unflatten( return NO_ERROR; } +std::vector::const_iterator FrameEventHistoryDelta::begin() const { + return mDeltas.begin(); +} + +std::vector::const_iterator FrameEventHistoryDelta::end() const { + return mDeltas.end(); +} } // namespace android diff --git a/libs/gui/bufferqueue/1.0/Conversion.cpp b/libs/gui/bufferqueue/1.0/Conversion.cpp index 55462c3b1f..96679549b2 100644 --- a/libs/gui/bufferqueue/1.0/Conversion.cpp +++ b/libs/gui/bufferqueue/1.0/Conversion.cpp @@ -725,12 +725,7 @@ status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t, // These were written as uint8_t for alignment. uint8_t temp = 0; FlattenableUtils::read(buffer, size, temp); - size_t index = static_cast(temp); - if (index >= ::android::FrameEventHistory::MAX_FRAME_HISTORY) { - return BAD_VALUE; - } - t->index = static_cast(index); - + t->index = static_cast(temp); FlattenableUtils::read(buffer, size, temp); t->addPostCompositeCalled = static_cast(temp); FlattenableUtils::read(buffer, size, temp); @@ -786,8 +781,7 @@ status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t, status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t, void*& buffer, size_t& size, int*& fds, size_t numFds) { // Check that t.index is within a valid range. - if (t.index >= static_cast(FrameEventHistory::MAX_FRAME_HISTORY) - || t.index > std::numeric_limits::max()) { + if (t.index > UINT8_MAX || t.index < 0) { return BAD_VALUE; } @@ -887,8 +881,7 @@ status_t unflatten( uint32_t deltaCount = 0; FlattenableUtils::read(buffer, size, deltaCount); - if (static_cast(deltaCount) > - ::android::FrameEventHistory::MAX_FRAME_HISTORY) { + if (deltaCount > UINT8_MAX) { return BAD_VALUE; } t->deltas.resize(deltaCount); @@ -919,7 +912,7 @@ status_t unflatten( status_t flatten( HGraphicBufferProducer::FrameEventHistoryDelta const& t, void*& buffer, size_t& size, int*& fds, size_t& numFds) { - if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) { + if (t.deltas.size() > UINT8_MAX) { return BAD_VALUE; } if (size < getFlattenedSize(t)) { diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp index cee1b811a4..f684874aec 100644 --- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp +++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp @@ -725,8 +725,7 @@ inline status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t, std::vector* nh, void*& buffer, size_t& size, int*& fds, size_t numFds) { // Check that t.index is within a valid range. - if (t.index >= static_cast(FrameEventHistory::MAX_FRAME_HISTORY) - || t.index > std::numeric_limits::max()) { + if (t.index > UINT8_MAX || t.index < 0) { return BAD_VALUE; } @@ -829,7 +828,7 @@ inline status_t flatten( HGraphicBufferProducer::FrameEventHistoryDelta const& t, std::vector >* nh, void*& buffer, size_t& size, int*& fds, size_t& numFds) { - if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) { + if (t.deltas.size() > UINT8_MAX) { return BAD_VALUE; } if (size < getFlattenedSize(t)) { diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index c93ab86770..515363a4cd 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -54,6 +54,8 @@ public: nsecs_t dequeueReadyTime) REQUIRES(mMutex); void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect); + void resizeFrameEventHistory(size_t newSize); + protected: void onSidebandStreamChanged() override REQUIRES(mMutex); @@ -123,6 +125,7 @@ public: private: friend class BLASTBufferQueueHelper; + friend class BBQBufferQueueProducer; // can't be copied BLASTBufferQueue& operator = (const BLASTBufferQueue& rhs); @@ -130,6 +133,8 @@ private: void createBufferQueue(sp* outProducer, sp* outConsumer); + void resizeFrameEventHistory(size_t newSize); + status_t acquireNextBufferLocked( const std::optional transaction) REQUIRES(mMutex); Rect computeCrop(const BufferItem& item) REQUIRES(mMutex); diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index 0ad3075a4d..1d13dab623 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -202,6 +202,11 @@ public: // See IGraphicBufferProducer::setAutoPrerotation virtual status_t setAutoPrerotation(bool autoPrerotation); +protected: + // see IGraphicsBufferProducer::setMaxDequeuedBufferCount, but with the ability to retrieve the + // total maximum buffer count for the buffer queue (dequeued AND acquired) + status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers, int* maxBufferCount); + private: // This is required by the IBinder::DeathRecipient interface virtual void binderDied(const wp& who); diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h index c08a9b1b6c..3d1be4d2eb 100644 --- a/libs/gui/include/gui/FrameTimestamps.h +++ b/libs/gui/include/gui/FrameTimestamps.h @@ -97,9 +97,11 @@ public: void checkFencesForCompletion(); void dump(std::string& outString) const; - static const size_t MAX_FRAME_HISTORY; + static const size_t INITIAL_MAX_FRAME_HISTORY; protected: + void resize(size_t newSize); + std::vector mFrames; CompositorTiming mCompositorTiming; @@ -138,6 +140,8 @@ protected: virtual std::shared_ptr createFenceTime( const sp& fence) const; + void resize(size_t newSize); + size_t mAcquireOffset{0}; // The consumer updates it's timelines in Layer and SurfaceFlinger since @@ -208,6 +212,8 @@ public: void getAndResetDelta(FrameEventHistoryDelta* delta); + void resize(size_t newSize); + private: void getFrameDelta(FrameEventHistoryDelta* delta, const std::vector::iterator& frame); @@ -250,6 +256,10 @@ public: status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); + uint64_t getFrameNumber() const; + bool getLatchTime(nsecs_t* latchTime) const; + bool getDisplayPresentFence(sp* fence) const; + private: static constexpr size_t minFlattenedSize(); @@ -310,6 +320,9 @@ public: status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); + std::vector::const_iterator begin() const; + std::vector::const_iterator end() const; + private: static constexpr size_t minFlattenedSize(); -- GitLab From 58af6edfa252d6571bec16c52640c2118d5c5c07 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Mon, 13 Feb 2023 15:24:20 -0500 Subject: [PATCH 0005/1187] Add tests for VsyncSchedule Follow-on to I54a1304a3428968134cc707b24d5b325927c31df. This is somewhat covered by existing unit tests, but add more thorough tests just for VsyncSchedule. Include thread_annotations.h to fix build. Update MockSchedulerCallback to include the new interface header. Bug: 241286146 Test: this Change-Id: I79e14d67fea896752f0afaba00adc6d47efc3c71 --- .../surfaceflinger/Scheduler/VsyncSchedule.h | 3 + .../surfaceflinger/tests/unittests/Android.bp | 1 + .../tests/unittests/VsyncScheduleTest.cpp | 215 ++++++++++++++++++ .../unittests/mock/MockSchedulerCallback.h | 2 +- 4 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 services/surfaceflinger/tests/unittests/VsyncScheduleTest.cpp diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h index d88f1d1f0b..f16b5b2577 100644 --- a/services/surfaceflinger/Scheduler/VsyncSchedule.h +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ namespace android { class EventThreadTest; +class VsyncScheduleTest; } namespace android::fuzz { @@ -96,6 +98,7 @@ public: private: friend class TestableScheduler; friend class android::EventThreadTest; + friend class android::VsyncScheduleTest; friend class android::fuzz::SchedulerFuzzer; using TrackerPtr = std::unique_ptr; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 87c3c65a74..c0eb51e260 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -133,6 +133,7 @@ cc_test { "VSyncPredictorTest.cpp", "VSyncReactorTest.cpp", "VsyncConfigurationTest.cpp", + "VsyncScheduleTest.cpp", ], } diff --git a/services/surfaceflinger/tests/unittests/VsyncScheduleTest.cpp b/services/surfaceflinger/tests/unittests/VsyncScheduleTest.cpp new file mode 100644 index 0000000000..652d3132f9 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/VsyncScheduleTest.cpp @@ -0,0 +1,215 @@ +/* + * Copyright 2023 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. + */ + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include +#include +#include +#include + +#include +#include "Scheduler/VsyncSchedule.h" +#include "ThreadContext.h" +#include "mock/MockSchedulerCallback.h" +#include "mock/MockVSyncDispatch.h" +#include "mock/MockVSyncTracker.h" +#include "mock/MockVsyncController.h" + +using testing::_; + +namespace android { + +class VsyncScheduleTest : public testing::Test { +protected: + VsyncScheduleTest(); + ~VsyncScheduleTest() override; + + scheduler::mock::SchedulerCallback mCallback; + const std::unique_ptr mVsyncSchedule = + std::unique_ptr( + new scheduler::VsyncSchedule(std::make_unique(), + std::make_unique(), + std::make_unique())); + + mock::VsyncController& getController() { + return *static_cast(&mVsyncSchedule->getController()); + } +}; + +VsyncScheduleTest::VsyncScheduleTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); +} + +VsyncScheduleTest::~VsyncScheduleTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); +} + +namespace { + +using namespace testing; + +TEST_F(VsyncScheduleTest, InitiallyDisallowed) { + ASSERT_FALSE(mVsyncSchedule->isHardwareVsyncAllowed(false /* makeAllowed */)); +} + +TEST_F(VsyncScheduleTest, EnableDoesNothingWhenDisallowed) { + EXPECT_CALL(mCallback, setVsyncEnabled(_)).Times(0); + + mVsyncSchedule->enableHardwareVsync(mCallback); +} + +TEST_F(VsyncScheduleTest, DisableDoesNothingWhenDisallowed) { + EXPECT_CALL(mCallback, setVsyncEnabled(_)).Times(0); + + mVsyncSchedule->disableHardwareVsync(mCallback, false /* disallow */); +} + +TEST_F(VsyncScheduleTest, MakeAllowed) { + ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); +} + +TEST_F(VsyncScheduleTest, DisableDoesNothingWhenDisabled) { + ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); + EXPECT_CALL(mCallback, setVsyncEnabled(_)).Times(0); + + mVsyncSchedule->disableHardwareVsync(mCallback, false /* disallow */); +} + +TEST_F(VsyncScheduleTest, EnableWorksWhenDisabled) { + ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); + EXPECT_CALL(mCallback, setVsyncEnabled(true)); + + mVsyncSchedule->enableHardwareVsync(mCallback); +} + +TEST_F(VsyncScheduleTest, EnableWorksOnce) { + ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); + EXPECT_CALL(mCallback, setVsyncEnabled(true)); + + mVsyncSchedule->enableHardwareVsync(mCallback); + + EXPECT_CALL(mCallback, setVsyncEnabled(_)).Times(0); + mVsyncSchedule->enableHardwareVsync(mCallback); +} + +TEST_F(VsyncScheduleTest, AllowedIsSticky) { + ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); + ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(false /* makeAllowed */)); +} + +TEST_F(VsyncScheduleTest, EnableDisable) { + ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); + EXPECT_CALL(mCallback, setVsyncEnabled(true)); + + mVsyncSchedule->enableHardwareVsync(mCallback); + + EXPECT_CALL(mCallback, setVsyncEnabled(false)); + mVsyncSchedule->disableHardwareVsync(mCallback, false /* disallow */); +} + +TEST_F(VsyncScheduleTest, StartPeriodTransition) { + // Note: startPeriodTransition is only called when hardware vsyncs are + // allowed. + ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); + + const Period period = (60_Hz).getPeriod(); + + EXPECT_CALL(mCallback, setVsyncEnabled(true)); + EXPECT_CALL(getController(), startPeriodTransition(period.ns())); + + mVsyncSchedule->startPeriodTransition(mCallback, period); +} + +TEST_F(VsyncScheduleTest, StartPeriodTransitionAlreadyEnabled) { + ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); + mVsyncSchedule->enableHardwareVsync(mCallback); + + const Period period = (60_Hz).getPeriod(); + + EXPECT_CALL(mCallback, setVsyncEnabled(_)).Times(0); + EXPECT_CALL(getController(), startPeriodTransition(period.ns())); + + mVsyncSchedule->startPeriodTransition(mCallback, period); +} + +TEST_F(VsyncScheduleTest, AddResyncSampleDisallowed) { + const Period period = (60_Hz).getPeriod(); + const auto timestamp = TimePoint::now(); + + EXPECT_CALL(mCallback, setVsyncEnabled(_)).Times(0); + EXPECT_CALL(getController(), addHwVsyncTimestamp(_, _, _)).Times(0); + + mVsyncSchedule->addResyncSample(mCallback, timestamp, period); +} + +TEST_F(VsyncScheduleTest, AddResyncSampleDisabled) { + ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); + const Period period = (60_Hz).getPeriod(); + const auto timestamp = TimePoint::now(); + + EXPECT_CALL(mCallback, setVsyncEnabled(_)).Times(0); + EXPECT_CALL(getController(), addHwVsyncTimestamp(_, _, _)).Times(0); + + mVsyncSchedule->addResyncSample(mCallback, timestamp, period); +} + +TEST_F(VsyncScheduleTest, AddResyncSampleReturnsTrue) { + ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); + mVsyncSchedule->enableHardwareVsync(mCallback); + + const Period period = (60_Hz).getPeriod(); + const auto timestamp = TimePoint::now(); + + EXPECT_CALL(mCallback, setVsyncEnabled(_)).Times(0); + EXPECT_CALL(getController(), + addHwVsyncTimestamp(timestamp.ns(), std::optional(period.ns()), _)) + .WillOnce(Return(true)); + + mVsyncSchedule->addResyncSample(mCallback, timestamp, period); +} + +TEST_F(VsyncScheduleTest, AddResyncSampleReturnsFalse) { + ASSERT_TRUE(mVsyncSchedule->isHardwareVsyncAllowed(true /* makeAllowed */)); + mVsyncSchedule->enableHardwareVsync(mCallback); + + const Period period = (60_Hz).getPeriod(); + const auto timestamp = TimePoint::now(); + + EXPECT_CALL(mCallback, setVsyncEnabled(false)); + EXPECT_CALL(getController(), + addHwVsyncTimestamp(timestamp.ns(), std::optional(period.ns()), _)) + .WillOnce(Return(false)); + + mVsyncSchedule->addResyncSample(mCallback, timestamp, period); +} + +TEST_F(VsyncScheduleTest, PendingState) FTL_FAKE_GUARD(kMainThreadContext) { + ASSERT_FALSE(mVsyncSchedule->getPendingHardwareVsyncState()); + mVsyncSchedule->setPendingHardwareVsyncState(true); + ASSERT_TRUE(mVsyncSchedule->getPendingHardwareVsyncState()); + + mVsyncSchedule->setPendingHardwareVsyncState(false); + ASSERT_FALSE(mVsyncSchedule->getPendingHardwareVsyncState()); +} + +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h index 7d4b159e5e..103beb5fc0 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h +++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h @@ -18,7 +18,7 @@ #include -#include "Scheduler/Scheduler.h" +#include "Scheduler/ISchedulerCallback.h" namespace android::scheduler::mock { -- GitLab From d5418b67bf2d25ffc72f4a8d1222ddc7fc2829f1 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 7 Feb 2023 09:38:56 -0800 Subject: [PATCH 0006/1187] Remove DisplayInfo not found log This log is spamming our test runs. It hasn't been very useful historically, since we havent seen it in real usage. We can bring back this log after setInputWindows is removed. Bug: 198444055 Test: m inputflinger_tests && $ANDROID_HOST_OUT/nativetest64/inputflinger_tests/inputflinger_tests Change-Id: Ica9fbbe4393b2ed9d09c506f681995cb9c550515 --- services/inputflinger/dispatcher/InputDispatcher.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 9d5bbbdd11..3a77e1bb58 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2741,7 +2741,8 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowHa if (displayInfoIt != mDisplayInfos.end()) { inputTarget.displayTransform = displayInfoIt->second.transform; } else { - ALOGE("DisplayInfo not found for window on display: %d", windowInfo->displayId); + // DisplayInfo not found for this window on display windowInfo->displayId. + // TODO(b/198444055): Make this an error message after 'setInputWindows' API is removed. } inputTargets.push_back(inputTarget); it = inputTargets.end() - 1; -- GitLab From 51c1f5a726db43fed7ef7e2a4e57c91d1bd8beb4 Mon Sep 17 00:00:00 2001 From: Vladimir Komsiyski Date: Thu, 19 Jan 2023 18:25:43 +0100 Subject: [PATCH 0007/1187] Native runtime sensors direct connection support. When a direct channel is (un-)registered or configured, notify the runtime sensor callback instead of the HAL and pass the shared memory region to it. The SensorDirectConnection object is tied to a deviceId and may only be configured for sensors of that device. Only ashmem direct channel type is supported for runtime sensors. Bug: 266042170 Test: atest CtsSensorTestCases Change-Id: Ie1a628650bd94b6d81e95d3b9f8f25fcf445666c --- libs/sensor/ISensorServer.cpp | 9 +- libs/sensor/SensorManager.cpp | 8 +- libs/sensor/include/sensor/ISensorServer.h | 3 +- libs/sensor/include/sensor/SensorManager.h | 2 + .../sensorservice/SensorDirectConnection.cpp | 34 ++++---- .../sensorservice/SensorDirectConnection.h | 7 +- services/sensorservice/SensorService.cpp | 84 +++++++++++++++++-- services/sensorservice/SensorService.h | 12 ++- 8 files changed, 130 insertions(+), 29 deletions(-) diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp index 2278d391b5..1fb8e5bf44 100644 --- a/libs/sensor/ISensorServer.cpp +++ b/libs/sensor/ISensorServer.cpp @@ -131,10 +131,12 @@ public: } virtual sp createSensorDirectConnection(const String16& opPackageName, - uint32_t size, int32_t type, int32_t format, const native_handle_t *resource) { + int deviceId, uint32_t size, int32_t type, int32_t format, + const native_handle_t *resource) { Parcel data, reply; data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); data.writeString16(opPackageName); + data.writeInt32(deviceId); data.writeUint32(size); data.writeInt32(type); data.writeInt32(format); @@ -229,6 +231,7 @@ status_t BnSensorServer::onTransact( case CREATE_SENSOR_DIRECT_CONNECTION: { CHECK_INTERFACE(ISensorServer, data, reply); const String16& opPackageName = data.readString16(); + const int deviceId = data.readInt32(); uint32_t size = data.readUint32(); int32_t type = data.readInt32(); int32_t format = data.readInt32(); @@ -238,8 +241,8 @@ status_t BnSensorServer::onTransact( return BAD_VALUE; } native_handle_set_fdsan_tag(resource); - sp ch = - createSensorDirectConnection(opPackageName, size, type, format, resource); + sp ch = createSensorDirectConnection( + opPackageName, deviceId, size, type, format, resource); native_handle_close_with_tag(resource); native_handle_delete(resource); reply->writeStrongBinder(IInterface::asBinder(ch)); diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp index 27482768f2..b6f09e0ac7 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -300,6 +300,12 @@ bool SensorManager::isDataInjectionEnabled() { int SensorManager::createDirectChannel( size_t size, int channelType, const native_handle_t *resourceHandle) { + static constexpr int DEFAULT_DEVICE_ID = 0; + return createDirectChannel(DEFAULT_DEVICE_ID, size, channelType, resourceHandle); +} + +int SensorManager::createDirectChannel( + int deviceId, size_t size, int channelType, const native_handle_t *resourceHandle) { Mutex::Autolock _l(mLock); if (assertStateLocked() != NO_ERROR) { return NO_INIT; @@ -312,7 +318,7 @@ int SensorManager::createDirectChannel( } sp conn = - mSensorServer->createSensorDirectConnection(mOpPackageName, + mSensorServer->createSensorDirectConnection(mOpPackageName, deviceId, static_cast(size), static_cast(channelType), SENSOR_DIRECT_FMT_SENSORS_EVENT, resourceHandle); diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h index 3295196ac4..58157280b1 100644 --- a/libs/sensor/include/sensor/ISensorServer.h +++ b/libs/sensor/include/sensor/ISensorServer.h @@ -50,7 +50,8 @@ public: virtual int32_t isDataInjectionEnabled() = 0; virtual sp createSensorDirectConnection(const String16& opPackageName, - uint32_t size, int32_t type, int32_t format, const native_handle_t *resource) = 0; + int deviceId, uint32_t size, int32_t type, int32_t format, + const native_handle_t *resource) = 0; virtual int setOperationParameter( int32_t handle, int32_t type, const Vector &floats, const Vector &ints) = 0; diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h index 0798da292a..bff45a74c8 100644 --- a/libs/sensor/include/sensor/SensorManager.h +++ b/libs/sensor/include/sensor/SensorManager.h @@ -65,6 +65,8 @@ public: String8 packageName = String8(""), int mode = 0, String16 attributionTag = String16("")); bool isDataInjectionEnabled(); int createDirectChannel(size_t size, int channelType, const native_handle_t *channelData); + int createDirectChannel( + int deviceId, size_t size, int channelType, const native_handle_t *channelData); void destroyDirectChannel(int channelNativeHandle); int configureDirectChannel(int channelNativeHandle, int sensorHandle, int rateLevel); int setOperationParameter(int handle, int type, const Vector &floats, const Vector &ints); diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp index 4ac9651a7b..4fff8bb1b4 100644 --- a/services/sensorservice/SensorDirectConnection.cpp +++ b/services/sensorservice/SensorDirectConnection.cpp @@ -28,10 +28,10 @@ using util::ProtoOutputStream; SensorService::SensorDirectConnection::SensorDirectConnection(const sp& service, uid_t uid, const sensors_direct_mem_t *mem, int32_t halChannelHandle, - const String16& opPackageName) + const String16& opPackageName, int deviceId) : mService(service), mUid(uid), mMem(*mem), mHalChannelHandle(halChannelHandle), - mOpPackageName(opPackageName), mDestroyed(false) { + mOpPackageName(opPackageName), mDeviceId(deviceId), mDestroyed(false) { mUserId = multiuser_get_user_id(mUid); ALOGD_IF(DEBUG_CONNECTIONS, "Created SensorDirectConnection"); } @@ -180,8 +180,7 @@ int32_t SensorService::SensorDirectConnection::configureChannel(int handle, int }; Mutex::Autolock _l(mConnectionLock); - SensorDevice& dev(SensorDevice::getInstance()); - int ret = dev.configureDirectChannel(handle, getHalChannelHandle(), &config); + int ret = configure(handle, &config); if (rateLevel == SENSOR_DIRECT_RATE_STOP) { if (ret == NO_ERROR) { @@ -224,7 +223,6 @@ void SensorService::SensorDirectConnection::capRates() { std::unordered_map& existingConnections = (!temporarilyStopped) ? mActivated : mActivatedBackup; - SensorDevice& dev(SensorDevice::getInstance()); for (auto &i : existingConnections) { int handle = i.first; int rateLevel = i.second; @@ -239,8 +237,8 @@ void SensorService::SensorDirectConnection::capRates() { // Only reconfigure the channel if it's ongoing if (!temporarilyStopped) { // Stopping before reconfiguring is the well-tested path in CTS - dev.configureDirectChannel(handle, getHalChannelHandle(), &stopConfig); - dev.configureDirectChannel(handle, getHalChannelHandle(), &capConfig); + configure(handle, &stopConfig); + configure(handle, &capConfig); } } } @@ -258,7 +256,6 @@ void SensorService::SensorDirectConnection::uncapRates() { const struct sensors_direct_cfg_t stopConfig = { .rate_level = SENSOR_DIRECT_RATE_STOP }; - SensorDevice& dev(SensorDevice::getInstance()); for (auto &i : mMicRateBackup) { int handle = i.first; int rateLevel = i.second; @@ -273,13 +270,23 @@ void SensorService::SensorDirectConnection::uncapRates() { // Only reconfigure the channel if it's ongoing if (!temporarilyStopped) { // Stopping before reconfiguring is the well-tested path in CTS - dev.configureDirectChannel(handle, getHalChannelHandle(), &stopConfig); - dev.configureDirectChannel(handle, getHalChannelHandle(), &config); + configure(handle, &stopConfig); + configure(handle, &config); } } mMicRateBackup.clear(); } +int SensorService::SensorDirectConnection::configure( + int handle, const sensors_direct_cfg_t* config) { + if (mDeviceId == RuntimeSensor::DEFAULT_DEVICE_ID) { + SensorDevice& dev(SensorDevice::getInstance()); + return dev.configureDirectChannel(handle, getHalChannelHandle(), config); + } else { + return mService->configureRuntimeSensorDirectChannel(handle, this, config); + } +} + void SensorService::SensorDirectConnection::stopAll(bool backupRecord) { Mutex::Autolock _l(mConnectionLock); stopAllLocked(backupRecord); @@ -290,9 +297,8 @@ void SensorService::SensorDirectConnection::stopAllLocked(bool backupRecord) { .rate_level = SENSOR_DIRECT_RATE_STOP }; - SensorDevice& dev(SensorDevice::getInstance()); for (auto &i : mActivated) { - dev.configureDirectChannel(i.first, getHalChannelHandle(), &config); + configure(i.first, &config); } if (backupRecord && mActivatedBackup.empty()) { @@ -306,8 +312,6 @@ void SensorService::SensorDirectConnection::recoverAll() { if (!mActivatedBackup.empty()) { stopAllLocked(false); - SensorDevice& dev(SensorDevice::getInstance()); - // recover list of report from backup ALOG_ASSERT(mActivated.empty(), "mActivated must be empty if mActivatedBackup was non-empty"); @@ -319,7 +323,7 @@ void SensorService::SensorDirectConnection::recoverAll() { struct sensors_direct_cfg_t config = { .rate_level = i.second }; - dev.configureDirectChannel(i.first, getHalChannelHandle(), &config); + configure(i.first, &config); } } } diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h index d39a073f98..bfaf811330 100644 --- a/services/sensorservice/SensorDirectConnection.h +++ b/services/sensorservice/SensorDirectConnection.h @@ -39,7 +39,7 @@ class SensorService::SensorDirectConnection: public BnSensorEventConnection { public: SensorDirectConnection(const sp& service, uid_t uid, const sensors_direct_mem_t *mem, int32_t halChannelHandle, - const String16& opPackageName); + const String16& opPackageName, int deviceId); void dump(String8& result) const; void dump(util::ProtoOutputStream* proto) const; uid_t getUid() const { return mUid; } @@ -53,6 +53,7 @@ public: void onSensorAccessChanged(bool hasAccess); void onMicSensorAccessChanged(bool isMicToggleOn); userid_t getUserId() const { return mUserId; } + int getDeviceId() const { return mDeviceId; } protected: virtual ~SensorDirectConnection(); @@ -68,6 +69,9 @@ protected: private: bool hasSensorAccess() const; + // Sends the configuration to the relevant sensor device. + int configure(int handle, const sensors_direct_cfg_t* config); + // Stops all active sensor direct report requests. // // If backupRecord is true, stopped requests can be recovered @@ -95,6 +99,7 @@ private: const sensors_direct_mem_t mMem; const int32_t mHalChannelHandle; const String16 mOpPackageName; + const int mDeviceId; mutable Mutex mConnectionLock; std::unordered_map mActivated; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 3a0329cd09..0fb3cadc63 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -181,7 +181,7 @@ int SensorService::registerRuntimeSensor( handle, sensor.type, sensor.name); sp runtimeSensorCallback( - new RuntimeSensorCallbackProxy(std::move(callback))); + new RuntimeSensorCallbackProxy(callback)); sensor_t runtimeSensor = sensor; // force the handle to be consistent runtimeSensor.handle = handle; @@ -193,11 +193,15 @@ int SensorService::registerRuntimeSensor( return mSensors.getNonSensor().getHandle(); } + if (mRuntimeSensorCallbacks.find(deviceId) == mRuntimeSensorCallbacks.end()) { + mRuntimeSensorCallbacks.emplace(deviceId, callback); + } return handle; } status_t SensorService::unregisterRuntimeSensor(int handle) { ALOGI("Unregistering runtime sensor handle 0x%x disconnected", handle); + int deviceId = getDeviceIdFromHandle(handle); { Mutex::Autolock _l(mLock); if (!unregisterDynamicSensorLocked(handle)) { @@ -210,6 +214,20 @@ status_t SensorService::unregisterRuntimeSensor(int handle) { for (const sp& connection : connLock.getActiveConnections()) { connection->removeSensor(handle); } + + // If this was the last sensor for this device, remove its callback. + bool deviceHasSensors = false; + mSensors.forEachEntry( + [&deviceId, &deviceHasSensors] (const SensorServiceUtil::SensorList::Entry& e) -> bool { + if (e.deviceId == deviceId) { + deviceHasSensors = true; + return false; // stop iterating + } + return true; + }); + if (!deviceHasSensors) { + mRuntimeSensorCallbacks.erase(deviceId); + } return OK; } @@ -1517,7 +1535,7 @@ int SensorService::isDataInjectionEnabled() { } sp SensorService::createSensorDirectConnection( - const String16& opPackageName, uint32_t size, int32_t type, int32_t format, + const String16& opPackageName, int deviceId, uint32_t size, int32_t type, int32_t format, const native_handle *resource) { resetTargetSdkVersionCache(opPackageName); ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); @@ -1593,14 +1611,25 @@ sp SensorService::createSensorDirectConnection( native_handle_set_fdsan_tag(clone); sp conn; - SensorDevice& dev(SensorDevice::getInstance()); - int channelHandle = dev.registerDirectChannel(&mem); + int channelHandle = 0; + if (deviceId == RuntimeSensor::DEFAULT_DEVICE_ID) { + SensorDevice& dev(SensorDevice::getInstance()); + channelHandle = dev.registerDirectChannel(&mem); + } else { + auto runtimeSensorCallback = mRuntimeSensorCallbacks.find(deviceId); + if (runtimeSensorCallback == mRuntimeSensorCallbacks.end()) { + ALOGE("Runtime sensor callback for deviceId %d not found", deviceId); + } else { + int fd = dup(clone->data[0]); + channelHandle = runtimeSensorCallback->second->onDirectChannelCreated(fd); + } + } if (channelHandle <= 0) { ALOGE("SensorDevice::registerDirectChannel returns %d", channelHandle); } else { mem.handle = clone; - conn = new SensorDirectConnection(this, uid, &mem, channelHandle, opPackageName); + conn = new SensorDirectConnection(this, uid, &mem, channelHandle, opPackageName, deviceId); } if (conn == nullptr) { @@ -1614,6 +1643,24 @@ sp SensorService::createSensorDirectConnection( return conn; } +int SensorService::configureRuntimeSensorDirectChannel( + int sensorHandle, const SensorDirectConnection* c, const sensors_direct_cfg_t* config) { + int deviceId = c->getDeviceId(); + int sensorDeviceId = getDeviceIdFromHandle(sensorHandle); + if (sensorDeviceId != c->getDeviceId()) { + ALOGE("Cannot configure direct channel created for device %d with a sensor that belongs" + "to device %d", c->getDeviceId(), sensorDeviceId); + return BAD_VALUE; + } + auto runtimeSensorCallback = mRuntimeSensorCallbacks.find(deviceId); + if (runtimeSensorCallback == mRuntimeSensorCallbacks.end()) { + ALOGE("Runtime sensor callback for deviceId %d not found", deviceId); + return BAD_VALUE; + } + return runtimeSensorCallback->second->onDirectChannelConfigured( + c->getHalChannelHandle(), sensorHandle, config->rate_level); +} + int SensorService::setOperationParameter( int32_t handle, int32_t type, const Vector &floats, const Vector &ints) { @@ -1769,8 +1816,18 @@ void SensorService::cleanupConnection(SensorEventConnection* c) { void SensorService::cleanupConnection(SensorDirectConnection* c) { Mutex::Autolock _l(mLock); - SensorDevice& dev(SensorDevice::getInstance()); - dev.unregisterDirectChannel(c->getHalChannelHandle()); + int deviceId = c->getDeviceId(); + if (deviceId == RuntimeSensor::DEFAULT_DEVICE_ID) { + SensorDevice& dev(SensorDevice::getInstance()); + dev.unregisterDirectChannel(c->getHalChannelHandle()); + } else { + auto runtimeSensorCallback = mRuntimeSensorCallbacks.find(deviceId); + if (runtimeSensorCallback != mRuntimeSensorCallbacks.end()) { + runtimeSensorCallback->second->onDirectChannelDestroyed(c->getHalChannelHandle()); + } else { + ALOGE("Runtime sensor callback for deviceId %d not found", deviceId); + } + } mConnectionHolder.removeDirectConnection(c); } @@ -1848,6 +1905,19 @@ std::shared_ptr SensorService::getSensorInterfaceFromHandle(int return mSensors.getInterface(handle); } +int SensorService::getDeviceIdFromHandle(int handle) const { + int deviceId = RuntimeSensor::DEFAULT_DEVICE_ID; + mSensors.forEachEntry( + [&deviceId, handle] (const SensorServiceUtil::SensorList::Entry& e) -> bool { + if (e.si->getSensor().getHandle() == handle) { + deviceId = e.deviceId; + return false; // stop iterating + } + return true; + }); + return deviceId; +} + status_t SensorService::enable(const sp& connection, int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags, const String16& opPackageName) { diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 3f6a895b52..fe72a69f15 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -154,6 +154,10 @@ public: virtual status_t onConfigurationChanged(int handle, bool enabled, int64_t samplingPeriodNanos, int64_t batchReportLatencyNanos) = 0; + virtual int onDirectChannelCreated(int fd) = 0; + virtual void onDirectChannelDestroyed(int channelHandle) = 0; + virtual int onDirectChannelConfigured(int channelHandle, int sensorHandle, + int rateLevel) = 0; }; static char const* getServiceName() ANDROID_API { return "sensorservice"; } @@ -187,6 +191,9 @@ public: status_t unregisterRuntimeSensor(int handle) ANDROID_API; status_t sendRuntimeSensorEvent(const sensors_event_t& event) ANDROID_API; + int configureRuntimeSensorDirectChannel(int sensorHandle, const SensorDirectConnection* c, + const sensors_direct_cfg_t* config); + // Returns true if a sensor should be throttled according to our rate-throttling rules. static bool isSensorInCappedSet(int sensorType); @@ -370,7 +377,8 @@ private: int requestedMode, const String16& opPackageName, const String16& attributionTag); virtual int isDataInjectionEnabled(); virtual sp createSensorDirectConnection(const String16& opPackageName, - uint32_t size, int32_t type, int32_t format, const native_handle *resource); + int deviceId, uint32_t size, int32_t type, int32_t format, + const native_handle *resource); virtual int setOperationParameter( int32_t handle, int32_t type, const Vector &floats, const Vector &ints); virtual status_t dump(int fd, const Vector& args); @@ -380,6 +388,7 @@ private: String8 getSensorStringType(int handle) const; bool isVirtualSensor(int handle) const; std::shared_ptr getSensorInterfaceFromHandle(int handle) const; + int getDeviceIdFromHandle(int handle) const; bool isWakeUpSensor(int type) const; void recordLastValueLocked(sensors_event_t const* buffer, size_t count); static void sortEventBuffer(sensors_event_t* buffer, size_t count); @@ -517,6 +526,7 @@ private: std::unordered_map mRecentEvent; Mode mCurrentOperatingMode; std::queue mRuntimeSensorEventQueue; + std::unordered_map> mRuntimeSensorCallbacks; // true if the head tracker sensor type is currently restricted to system usage only // (can only be unrestricted for testing, via shell cmd) -- GitLab From fb281c53240c3e2420a20cf0ea071198e963ed3d Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sat, 11 Feb 2023 14:24:19 -0500 Subject: [PATCH 0008/1187] SF: Deduplicate mock scheduler setup in tests Extract TestableSurfaceFlinger::setupMockScheduler, and add an option to customize the PhysicalDisplayId of the injected RefreshRateSelector (and its display modes), so that tests can later inject a DisplayDevice with a matching ID. Remove the DisplayModesVariant with two display modes, as the few tests that used it are unrelated to scheduling and will later be decoupled entirely. Bug: 259436835 Bug: 241285191 Test: libsurfaceflinger_unittest Change-Id: Ie58b6947201a1911342e7bcd5ea64dd8702aaa57 --- .../Tracing/tools/LayerTraceGenerator.cpp | 47 +++++----- .../tests/unittests/CompositionTest.cpp | 33 +------ .../unittests/DisplayTransactionTest.cpp | 14 +-- .../unittests/DisplayTransactionTestHelpers.h | 4 +- .../tests/unittests/FpsReporterTest.cpp | 33 +------ .../FrameRateSelectionPriorityTest.cpp | 38 +-------- .../tests/unittests/GameModeTest.cpp | 33 +------ .../tests/unittests/LayerTestUtils.cpp | 40 +-------- .../tests/unittests/LayerTestUtils.h | 4 +- .../SurfaceFlinger_DisplayModeSwitching.cpp | 4 +- .../SurfaceFlinger_PowerHintTest.cpp | 36 +------- ...linger_UpdateLayerMetadataSnapshotTest.cpp | 32 +------ .../tests/unittests/TestableSurfaceFlinger.h | 85 +++++++++++++------ .../unittests/TransactionApplicationTest.cpp | 37 +------- .../unittests/TransactionFrameTracerTest.cpp | 33 +------ .../unittests/TransactionSurfaceFrameTest.cpp | 33 +------ .../TunnelModeEnabledReporterTest.cpp | 34 +------- 17 files changed, 110 insertions(+), 430 deletions(-) diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp index ab98dbfe2f..31f4723915 100644 --- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp +++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp @@ -191,29 +191,20 @@ bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, return false; } - Factory mFactory; - sp flinger = sp::make(mFactory); - TestableSurfaceFlinger mFlinger(flinger); - mFlinger.setupRenderEngine( + Factory factory; + sp flingerPtr = sp::make(factory); + TestableSurfaceFlinger flinger(flingerPtr); + flinger.setupRenderEngine( std::make_unique>()); - mock::VsyncController* mVsyncController = new testing::NiceMock(); - mock::VSyncTracker* mVSyncTracker = new testing::NiceMock(); - mock::EventThread* mEventThread = new testing::NiceMock(); - mock::EventThread* mSFEventThread = new testing::NiceMock(); - mFlinger.setupScheduler(std::unique_ptr(mVsyncController), - std::unique_ptr(mVSyncTracker), - std::unique_ptr(mEventThread), - std::unique_ptr(mSFEventThread), - TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp, - TestableSurfaceFlinger::kOneDisplayMode, true /* useNiceMock */); - - Hwc2::mock::Composer* mComposer = new testing::NiceMock(); - mFlinger.setupComposer(std::unique_ptr(mComposer)); - mFlinger.mutableMaxRenderTargetSize() = 16384; - - flinger->setLayerTracingFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS); - flinger->setLayerTraceSize(512 * 1024); // 512MB buffer size - flinger->startLayerTracing(traceFile.entry(0).elapsed_realtime_nanos()); + flinger.setupMockScheduler({.useNiceMock = true}); + + Hwc2::mock::Composer* composerPtr = new testing::NiceMock(); + flinger.setupComposer(std::unique_ptr(composerPtr)); + flinger.mutableMaxRenderTargetSize() = 16384; + + flingerPtr->setLayerTracingFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS); + flingerPtr->setLayerTraceSize(512 * 1024); // 512MB buffer size + flingerPtr->startLayerTracing(traceFile.entry(0).elapsed_realtime_nanos()); std::unique_ptr mapper = std::make_unique(); TraceGenFlingerDataMapper* dataMapper = mapper.get(); @@ -234,7 +225,7 @@ bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, parser.fromProto(entry.added_layers(j), tracingArgs); gui::CreateSurfaceResult outResult; - LayerCreationArgs args(mFlinger.flinger(), nullptr /* client */, tracingArgs.name, + LayerCreationArgs args(flinger.flinger(), nullptr /* client */, tracingArgs.name, tracingArgs.flags, LayerMetadata(), std::make_optional(tracingArgs.layerId)); @@ -247,10 +238,10 @@ bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, } else if (tracingArgs.parentId != -1) { parentHandle = dataMapper->getLayerHandle(tracingArgs.parentId); } - mFlinger.createLayer(args, parentHandle, outResult); + flinger.createLayer(args, parentHandle, outResult); } else { sp mirrorFromHandle = dataMapper->getLayerHandle(tracingArgs.mirrorFromId); - mFlinger.mirrorLayer(args, mirrorFromHandle, outResult); + flinger.mirrorLayer(args, mirrorFromHandle, outResult); } LOG_ALWAYS_FATAL_IF(outResult.layerId != tracingArgs.layerId, "Could not create layer expected:%d actual:%d", tracingArgs.layerId, @@ -261,19 +252,19 @@ bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, for (int j = 0; j < entry.transactions_size(); j++) { // apply transactions TransactionState transaction = parser.fromProto(entry.transactions(j)); - mFlinger.setTransactionStateInternal(transaction); + flinger.setTransactionStateInternal(transaction); } const auto frameTime = TimePoint::fromNs(entry.elapsed_realtime_nanos()); const auto vsyncId = VsyncId{entry.vsync_id()}; - mFlinger.commit(frameTime, vsyncId); + flinger.commit(frameTime, vsyncId); for (int j = 0; j < entry.removed_layer_handles_size(); j++) { dataMapper->mLayerHandles.erase(entry.removed_layer_handles(j)); } } - flinger->stopLayerTracing(outputLayersTracePath); + flingerPtr->stopLayerTracing(outputLayersTracePath); ALOGD("End of generating trace file. File written to %s", outputLayersTracePath); dataMapper->mLayerHandles.clear(); return true; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 0416e93f1e..17ef6ff5e1 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -99,7 +99,7 @@ public: ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - setupScheduler(); + mFlinger.setupMockScheduler({.displayId = DEFAULT_DISPLAY_ID}); EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _)) .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0))); @@ -122,36 +122,6 @@ public: ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } - void setupScheduler() { - auto eventThread = std::make_unique(); - auto sfEventThread = std::make_unique(); - - EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(eventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(sfEventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - auto vsyncController = std::make_unique(); - auto vsyncTracker = std::make_unique(); - - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - EXPECT_CALL(*vsyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - - mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), - std::move(eventThread), std::move(sfEventThread), - TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp, - TestableSurfaceFlinger::kTwoDisplayModes); - } - void setupForceGeometryDirty() { // TODO: This requires the visible region and other related // state to be set, and is problematic for BufferLayers since they are @@ -176,7 +146,6 @@ public: bool mDisplayOff = false; TestableSurfaceFlinger mFlinger; sp mDisplay; - sp mExternalDisplay; sp mDisplaySurface = sp::make(); sp mNativeWindow = sp::make(); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index e0b508aa73..52dc695a93 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -29,9 +29,7 @@ using testing::SetArgPointee; using android::hardware::graphics::composer::hal::HWDisplayId; -using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; - -DisplayTransactionTest::DisplayTransactionTest() { +DisplayTransactionTest::DisplayTransactionTest(bool withMockScheduler) { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); @@ -48,7 +46,10 @@ DisplayTransactionTest::DisplayTransactionTest() { return nullptr; }); - injectMockScheduler(); + if (withMockScheduler) { + injectMockScheduler(PhysicalDisplayId::fromPort(0)); + } + mFlinger.setupRenderEngine(std::unique_ptr(mRenderEngine)); injectMockComposer(0); @@ -61,7 +62,9 @@ DisplayTransactionTest::~DisplayTransactionTest() { mFlinger.resetScheduler(nullptr); } -void DisplayTransactionTest::injectMockScheduler() { +void DisplayTransactionTest::injectMockScheduler(PhysicalDisplayId displayId) { + LOG_ALWAYS_FATAL_IF(mFlinger.scheduler()); + EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*mEventThread, createEventConnection(_, _)) .WillOnce(Return(sp::make(mEventThread, @@ -78,6 +81,7 @@ void DisplayTransactionTest::injectMockScheduler() { std::unique_ptr(mVSyncTracker), std::unique_ptr(mEventThread), std::unique_ptr(mSFEventThread), + TestableSurfaceFlinger::DefaultDisplayMode{displayId}, TestableSurfaceFlinger::SchedulerCallbackImpl::kMock); } diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index 223f4db889..66aa2041de 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -85,7 +85,7 @@ public: // -------------------------------------------------------------------- // Mock/Fake injection - void injectMockScheduler(); + void injectMockScheduler(PhysicalDisplayId); void injectMockComposer(int virtualDisplayCount); void injectFakeBufferQueueFactory(); void injectFakeNativeWindowSurfaceFactory(); @@ -139,7 +139,7 @@ public: surfaceflinger::mock::NativeWindowSurface* mNativeWindowSurface = nullptr; protected: - DisplayTransactionTest(); + DisplayTransactionTest(bool withMockScheduler = true); }; constexpr int32_t DEFAULT_VSYNC_PERIOD = 16'666'667; diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp index 1cd9e49051..f695b096a7 100644 --- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp @@ -29,9 +29,7 @@ #include "TestableSurfaceFlinger.h" #include "fake/FakeClock.h" #include "mock/DisplayHardware/MockComposer.h" -#include "mock/MockEventThread.h" #include "mock/MockFrameTimeline.h" -#include "mock/MockVsyncController.h" namespace android { @@ -47,7 +45,6 @@ using testing::UnorderedElementsAre; using android::Hwc2::IComposer; using android::Hwc2::IComposerClient; -using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; using gui::LayerMetadata; struct TestableFpsListener : public gui::BnFpsListener { @@ -77,7 +74,6 @@ protected: static constexpr uint32_t LAYER_FLAGS = 0; static constexpr int32_t PRIORITY_UNSET = -1; - void setupScheduler(); sp createBufferStateLayer(LayerMetadata metadata); TestableSurfaceFlinger mFlinger; @@ -102,7 +98,7 @@ FpsReporterTest::FpsReporterTest() { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - setupScheduler(); + mFlinger.setupMockScheduler(); mFlinger.setupComposer(std::make_unique()); mFpsListener = sp::make(); @@ -120,33 +116,6 @@ sp FpsReporterTest::createBufferStateLayer(LayerMetadata metadata = {}) { return sp::make(args); } -void FpsReporterTest::setupScheduler() { - auto eventThread = std::make_unique(); - auto sfEventThread = std::make_unique(); - - EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(eventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(sfEventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - auto vsyncController = std::make_unique(); - auto vsyncTracker = std::make_unique(); - - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - EXPECT_CALL(*vsyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), - std::move(eventThread), std::move(sfEventThread)); -} - namespace { TEST_F(FpsReporterTest, callsListeners) { diff --git a/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp index ac63a0edbd..1c9aee7443 100644 --- a/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp @@ -24,8 +24,6 @@ #include "Layer.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" -#include "mock/MockEventThread.h" -#include "mock/MockVsyncController.h" namespace android { @@ -38,8 +36,6 @@ using testing::SetArgPointee; using android::Hwc2::IComposer; using android::Hwc2::IComposerClient; -using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; - /** * This class covers all the test that are related to refresh rate selection. */ @@ -56,7 +52,6 @@ protected: static constexpr uint32_t LAYER_FLAGS = 0; static constexpr int32_t PRIORITY_UNSET = -1; - void setupScheduler(); sp createBufferStateLayer(); sp createEffectLayer(); @@ -76,7 +71,7 @@ RefreshRateSelectionTest::RefreshRateSelectionTest() { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - setupScheduler(); + mFlinger.setupMockScheduler(); mFlinger.setupComposer(std::make_unique()); } @@ -108,37 +103,8 @@ void RefreshRateSelectionTest::commitTransaction(Layer* layer) { layer->commitTransaction(c); } -void RefreshRateSelectionTest::setupScheduler() { - auto eventThread = std::make_unique(); - auto sfEventThread = std::make_unique(); - - EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(eventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(sfEventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - auto vsyncController = std::make_unique(); - auto vsyncTracker = std::make_unique(); - - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - EXPECT_CALL(*vsyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), - std::move(eventThread), std::move(sfEventThread)); -} - namespace { -/* ------------------------------------------------------------------------ - * Test cases - */ + TEST_F(RefreshRateSelectionTest, testPriorityOnBufferStateLayers) { mParent = createBufferStateLayer(); mChild = createBufferStateLayer(); diff --git a/services/surfaceflinger/tests/unittests/GameModeTest.cpp b/services/surfaceflinger/tests/unittests/GameModeTest.cpp index 29aa7171ba..1b5c6e70f8 100644 --- a/services/surfaceflinger/tests/unittests/GameModeTest.cpp +++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp @@ -25,15 +25,13 @@ #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" -#include "mock/MockEventThread.h" -#include "mock/MockVsyncController.h" namespace android { using testing::_; using testing::Mock; using testing::Return; -using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; + using gui::GameMode; using gui::LayerMetadata; @@ -43,7 +41,7 @@ public: const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - setupScheduler(); + mFlinger.setupMockScheduler(); setupComposer(); } @@ -59,33 +57,6 @@ public: return sp::make(args); } - void setupScheduler() { - auto eventThread = std::make_unique(); - auto sfEventThread = std::make_unique(); - - EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(eventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(sfEventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - auto vsyncController = std::make_unique(); - auto vsyncTracker = std::make_unique(); - - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - EXPECT_CALL(*vsyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), - std::move(eventThread), std::move(sfEventThread)); - } - void setupComposer() { mComposer = new Hwc2::mock::Composer(); mFlinger.setupComposer(std::unique_ptr(mComposer)); diff --git a/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp b/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp index ee42e19c34..803e807d7b 100644 --- a/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp +++ b/services/surfaceflinger/tests/unittests/LayerTestUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright 2022 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. @@ -16,15 +16,8 @@ #include "LayerTestUtils.h" -#include "mock/MockEventThread.h" - namespace android { -using testing::_; -using testing::Return; - -using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; - sp BufferStateLayerFactory::createLayer(TestableSurfaceFlinger& flinger) { sp client; LayerCreationArgs args(flinger.flinger(), client, "buffer-state-layer", LAYER_FLAGS, @@ -44,36 +37,7 @@ std::string PrintToStringParamName( } BaseLayerTest::BaseLayerTest() { - setupScheduler(); -} - -void BaseLayerTest::setupScheduler() { - auto eventThread = std::make_unique(); - auto sfEventThread = std::make_unique(); - - EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(eventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(sfEventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - auto vsyncController = std::make_unique(); - auto vsyncTracker = std::make_unique(); - - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - EXPECT_CALL(*vsyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), - std::move(eventThread), std::move(sfEventThread), - TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp, - TestableSurfaceFlinger::kTwoDisplayModes); + mFlinger.setupMockScheduler(); } } // namespace android diff --git a/services/surfaceflinger/tests/unittests/LayerTestUtils.h b/services/surfaceflinger/tests/unittests/LayerTestUtils.h index ab446fafeb..0773d9081e 100644 --- a/services/surfaceflinger/tests/unittests/LayerTestUtils.h +++ b/services/surfaceflinger/tests/unittests/LayerTestUtils.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright 2022 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. @@ -63,8 +63,6 @@ class BaseLayerTest : public ::testing::TestWithParam(mRenderEngine)); @@ -99,36 +95,6 @@ void SurfaceFlingerPowerHintTest::SetUp() { .inject(); } -void SurfaceFlingerPowerHintTest::setupScheduler() { - auto eventThread = std::make_unique(); - auto sfEventThread = std::make_unique(); - - EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(eventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(sfEventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - auto vsyncController = std::make_unique(); - auto vsyncTracker = std::make_unique(); - - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - EXPECT_CALL(*vsyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - - mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), - std::move(eventThread), std::move(sfEventThread), - TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp, - TestableSurfaceFlinger::kTwoDisplayModes); -} - TEST_F(SurfaceFlingerPowerHintTest, sendDurationsIncludingHwcWaitTime) { ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true)); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp index fed6a1ae56..0e5f1ea789 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp @@ -3,47 +3,17 @@ #include #include "TestableSurfaceFlinger.h" -#include "mock/MockEventThread.h" -#include "mock/MockVsyncController.h" namespace android { using testing::_; using testing::Return; -using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; class SurfaceFlingerUpdateLayerMetadataSnapshotTest : public testing::Test { public: - SurfaceFlingerUpdateLayerMetadataSnapshotTest() { setupScheduler(); } + SurfaceFlingerUpdateLayerMetadataSnapshotTest() { mFlinger.setupMockScheduler(); } protected: - void setupScheduler() { - auto eventThread = std::make_unique(); - auto sfEventThread = std::make_unique(); - - EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(eventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(sfEventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - auto vsyncController = std::make_unique(); - auto vsyncTracker = std::make_unique(); - - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - EXPECT_CALL(*vsyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), - std::move(eventThread), std::move(sfEventThread)); - } - sp createLayer(const char* name, LayerMetadata& inOutlayerMetadata) { LayerCreationArgs args = LayerCreationArgs{mFlinger.flinger(), nullptr, name, 0, inOutlayerMetadata}; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 282c87eb8a..f2c9508391 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -47,14 +48,12 @@ #include "TestableScheduler.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/DisplayHardware/MockDisplayMode.h" +#include "mock/MockEventThread.h" #include "mock/MockFrameTimeline.h" #include "mock/MockFrameTracer.h" #include "mock/MockSchedulerCallback.h" namespace android { - -class EventThread; - namespace renderengine { class RenderEngine; @@ -151,6 +150,11 @@ public: CreateCompositionEngineFunction mCreateCompositionEngine; }; +struct MockSchedulerOptions { + PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(0); + bool useNiceMock = false; +}; + } // namespace surfaceflinger::test class TestableSurfaceFlinger { @@ -189,38 +193,31 @@ public: enum class SchedulerCallbackImpl { kNoOp, kMock }; - static constexpr struct OneDisplayMode { - } kOneDisplayMode; - - static constexpr struct TwoDisplayModes { - } kTwoDisplayModes; + struct DefaultDisplayMode { + // The ID of the injected RefreshRateSelector and its default display mode. + PhysicalDisplayId displayId; + }; - using RefreshRateSelectorPtr = std::shared_ptr; + using RefreshRateSelectorPtr = scheduler::Scheduler::RefreshRateSelectorPtr; - using DisplayModesVariant = - std::variant; + using DisplayModesVariant = std::variant; void setupScheduler(std::unique_ptr vsyncController, std::unique_ptr vsyncTracker, std::unique_ptr appEventThread, std::unique_ptr sfEventThread, + DisplayModesVariant modesVariant, SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp, - DisplayModesVariant modesVariant = kOneDisplayMode, bool useNiceMock = false) { - RefreshRateSelectorPtr selectorPtr; - if (std::holds_alternative(modesVariant)) { - selectorPtr = std::move(std::get(modesVariant)); - } else { - constexpr DisplayModeId kModeId60{0}; - DisplayModes modes = makeModes(mock::createDisplayMode(kModeId60, 60_Hz)); - - if (std::holds_alternative(modesVariant)) { - constexpr DisplayModeId kModeId90{1}; - modes.try_emplace(kModeId90, mock::createDisplayMode(kModeId90, 90_Hz)); - } - - selectorPtr = std::make_shared(modes, kModeId60); - } + RefreshRateSelectorPtr selectorPtr = ftl::match( + modesVariant, + [](DefaultDisplayMode arg) { + constexpr DisplayModeId kModeId60{0}; + return std::make_shared( + makeModes(mock::createDisplayMode(arg.displayId, kModeId60, 60_Hz)), + kModeId60); + }, + [](RefreshRateSelectorPtr selectorPtr) { return selectorPtr; }); const auto fps = selectorPtr->getActiveMode().fps; mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps); @@ -260,6 +257,37 @@ public: resetScheduler(mScheduler); } + void setupMockScheduler(test::MockSchedulerOptions options = {}) { + using testing::_; + using testing::Return; + + auto eventThread = makeMock(options.useNiceMock); + auto sfEventThread = makeMock(options.useNiceMock); + + EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*eventThread, createEventConnection(_, _)) + .WillOnce(Return(sp::make(eventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); + + EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); + EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) + .WillOnce(Return(sp::make(sfEventThread.get(), + mock::EventThread::kCallingUid, + ResyncCallback()))); + + auto vsyncController = makeMock(options.useNiceMock); + auto vsyncTracker = makeMock(options.useNiceMock); + + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, currentPeriod()) + .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), + std::move(sfEventThread), DefaultDisplayMode{options.displayId}, + SchedulerCallbackImpl::kNoOp, options.useNiceMock); + } + void resetScheduler(scheduler::Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); } scheduler::TestableScheduler& mutableScheduler() { return *mScheduler; } @@ -910,6 +938,11 @@ public: }; private: + template + static std::unique_ptr makeMock(bool useNiceMock) { + return useNiceMock ? std::make_unique>() : std::make_unique(); + } + static constexpr VsyncId kVsyncId{123}; surfaceflinger::test::Factory mFactory; diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 981e9d2e8f..e4b3cb908f 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -33,15 +33,12 @@ #include "FrontEnd/TransactionHandler.h" #include "TestableSurfaceFlinger.h" #include "TransactionState.h" -#include "mock/MockEventThread.h" -#include "mock/MockVsyncController.h" namespace android { using testing::_; using testing::Return; -using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; using frontend::TransactionHandler; constexpr nsecs_t TRANSACTION_TIMEOUT = s2ns(5); @@ -52,7 +49,9 @@ public: ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - setupScheduler(); + mFlinger.setupComposer(std::make_unique()); + mFlinger.setupMockScheduler(); + mFlinger.flinger()->addTransactionReadyFilters(); } ~TransactionApplicationTest() { @@ -61,38 +60,8 @@ public: ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } - void setupScheduler() { - auto eventThread = std::make_unique(); - auto sfEventThread = std::make_unique(); - - EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(eventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(sfEventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - EXPECT_CALL(*mVSyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); - - mFlinger.setupComposer(std::make_unique()); - mFlinger.setupScheduler(std::unique_ptr(mVsyncController), - std::unique_ptr(mVSyncTracker), - std::move(eventThread), std::move(sfEventThread)); - mFlinger.flinger()->addTransactionReadyFilters(); - } - TestableSurfaceFlinger mFlinger; - mock::VsyncController* mVsyncController = new mock::VsyncController(); - mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker(); - struct TransactionInfo { Vector states; Vector displays; diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index 1173d1c876..764d19be0b 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -28,15 +28,13 @@ #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" -#include "mock/MockEventThread.h" -#include "mock/MockVsyncController.h" namespace android { using testing::_; using testing::Mock; using testing::Return; -using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; + using PresentState = frametimeline::SurfaceFrame::PresentState; class TransactionFrameTracerTest : public testing::Test { @@ -45,7 +43,7 @@ public: const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - setupScheduler(); + mFlinger.setupMockScheduler(); mFlinger.setupComposer(std::make_unique()); mFlinger.setupRenderEngine(std::unique_ptr(mRenderEngine)); } @@ -68,33 +66,6 @@ public: layer->commitTransaction(c); } - void setupScheduler() { - auto eventThread = std::make_unique(); - auto sfEventThread = std::make_unique(); - - EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(eventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(sfEventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - auto vsyncController = std::make_unique(); - auto vsyncTracker = std::make_unique(); - - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - EXPECT_CALL(*vsyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), - std::move(eventThread), std::move(sfEventThread)); - } - TestableSurfaceFlinger mFlinger; renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index ae03db43a7..e2c64917dc 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -28,15 +28,13 @@ #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockComposer.h" -#include "mock/MockEventThread.h" -#include "mock/MockVsyncController.h" namespace android { using testing::_; using testing::Mock; using testing::Return; -using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; + using PresentState = frametimeline::SurfaceFrame::PresentState; class TransactionSurfaceFrameTest : public testing::Test { @@ -45,7 +43,7 @@ public: const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - setupScheduler(); + mFlinger.setupMockScheduler(); mFlinger.setupComposer(std::make_unique()); mFlinger.setupRenderEngine(std::unique_ptr(mRenderEngine)); } @@ -67,33 +65,6 @@ public: layer->commitTransaction(c); } - void setupScheduler() { - auto eventThread = std::make_unique(); - auto sfEventThread = std::make_unique(); - - EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(eventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(sfEventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - auto vsyncController = std::make_unique(); - auto vsyncTracker = std::make_unique(); - - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - EXPECT_CALL(*vsyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), - std::move(eventThread), std::move(sfEventThread)); - } - TestableSurfaceFlinger mFlinger; renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); diff --git a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp index da87f1db17..108151ec65 100644 --- a/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/TunnelModeEnabledReporterTest.cpp @@ -25,7 +25,6 @@ #include "TestableSurfaceFlinger.h" #include "TunnelModeEnabledReporter.h" #include "mock/DisplayHardware/MockComposer.h" -#include "mock/MockEventThread.h" namespace android { @@ -36,8 +35,6 @@ using testing::Return; using android::Hwc2::IComposer; using android::Hwc2::IComposerClient; -using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; - constexpr int DEFAULT_SIDEBAND_STREAM = 51; struct TestableTunnelModeEnabledListener : public gui::BnTunnelModeEnabledListener { @@ -61,8 +58,6 @@ protected: static constexpr uint32_t HEIGHT = 100; static constexpr uint32_t LAYER_FLAGS = 0; - void setupScheduler(); - void setupComposer(uint32_t virtualDisplayCount); sp createBufferStateLayer(LayerMetadata metadata); TestableSurfaceFlinger mFlinger; @@ -80,7 +75,7 @@ TunnelModeEnabledReporterTest::TunnelModeEnabledReporterTest() { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - setupScheduler(); + mFlinger.setupMockScheduler(); mFlinger.setupComposer(std::make_unique()); mFlinger.flinger()->mTunnelModeEnabledReporter = mTunnelModeEnabledReporter; mTunnelModeEnabledReporter->dispatchTunnelModeEnabled(false); @@ -100,33 +95,6 @@ sp TunnelModeEnabledReporterTest::createBufferStateLayer(LayerMetadata me return sp::make(args); } -void TunnelModeEnabledReporterTest::setupScheduler() { - auto eventThread = std::make_unique(); - auto sfEventThread = std::make_unique(); - - EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*eventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(eventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); - EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(sfEventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); - - auto vsyncController = std::make_unique(); - auto vsyncTracker = std::make_unique(); - - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - EXPECT_CALL(*vsyncTracker, currentPeriod()) - .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); - EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); - mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker), - std::move(eventThread), std::move(sfEventThread)); -} - namespace { TEST_F(TunnelModeEnabledReporterTest, callsAddedListeners) { -- GitLab From 36cface18f0eb2d5fe4d479110695ef053a0f402 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sat, 11 Feb 2023 16:23:34 -0500 Subject: [PATCH 0009/1187] SF: Remove unused property of test DisplayVariant Bug: 241285876 Test: m libsurfaceflinger_unittest Change-Id: If5f4a7b44812a6a9b2fcc5ba423de14596b717f2 --- .../unittests/DisplayTransactionTestHelpers.h | 69 ++++++++----------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index 66aa2041de..23a8bd1274 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -158,7 +158,6 @@ constexpr int POWER_MODE_LEET = 1337; // An out of range power mode value #define BOOL_SUBSTITUTE(TYPENAME) enum class TYPENAME : bool { FALSE = false, TRUE = true }; BOOL_SUBSTITUTE(Async); -BOOL_SUBSTITUTE(Critical); BOOL_SUBSTITUTE(Primary); BOOL_SUBSTITUTE(Secure); BOOL_SUBSTITUTE(Virtual); @@ -238,8 +237,8 @@ struct HwcDisplayIdGetter> { // 1) PhysicalDisplayIdType<...> for generated ID of physical display backed by HWC. // 2) HalVirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC. // 3) GpuVirtualDisplayIdType for virtual display without HWC backing. -template +template struct DisplayVariant { using DISPLAY_ID = DisplayIdGetter; using CONNECTION_TYPE = DisplayConnectionTypeGetter; @@ -255,9 +254,6 @@ struct DisplayVariant { static constexpr Virtual VIRTUAL = IsPhysicalDisplayId{} ? Virtual::FALSE : Virtual::TRUE; - // When creating native window surfaces for the framebuffer, whether those should be critical - static constexpr Critical CRITICAL = critical; - // When creating native window surfaces for the framebuffer, whether those should be async static constexpr Async ASYNC = async; @@ -486,17 +482,16 @@ constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY = constexpr int PHYSICAL_DISPLAY_FLAGS = 0x1; -template +template struct PhysicalDisplayVariant - : DisplayVariant, width, height, critical, - Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY, - GRALLOC_USAGE_PHYSICAL_DISPLAY, PHYSICAL_DISPLAY_FLAGS>, - HwcDisplayVariant< - PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL, - DisplayVariant, width, height, critical, - Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY, - GRALLOC_USAGE_PHYSICAL_DISPLAY, PHYSICAL_DISPLAY_FLAGS>, - PhysicalDisplay> {}; + : DisplayVariant, width, height, Async::FALSE, + Secure::TRUE, PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY, + PHYSICAL_DISPLAY_FLAGS>, + HwcDisplayVariant, width, height, + Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY, + GRALLOC_USAGE_PHYSICAL_DISPLAY, PHYSICAL_DISPLAY_FLAGS>, + PhysicalDisplay> {}; template struct PrimaryDisplay { @@ -525,15 +520,9 @@ struct TertiaryDisplay { static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid; }; -// A primary display is a physical display that is critical -using PrimaryDisplayVariant = - PhysicalDisplayVariant, 3840, 2160, Critical::TRUE>; - -// An external display is physical display that is not critical. -using ExternalDisplayVariant = - PhysicalDisplayVariant, 1920, 1280, Critical::FALSE>; - -using TertiaryDisplayVariant = PhysicalDisplayVariant; +using PrimaryDisplayVariant = PhysicalDisplayVariant, 3840, 2160>; +using ExternalDisplayVariant = PhysicalDisplayVariant, 1920, 1280>; +using TertiaryDisplayVariant = PhysicalDisplayVariant; // A virtual display not supported by the HWC. constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0; @@ -542,12 +531,11 @@ constexpr int VIRTUAL_DISPLAY_FLAGS = 0x0; template struct NonHwcVirtualDisplayVariant - : DisplayVariant { - using Base = DisplayVariant; + : DisplayVariant { + using Base = DisplayVariant; static void injectHwcDisplay(DisplayTransactionTest*) {} @@ -589,17 +577,14 @@ constexpr uint32_t GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY = GRALLOC_USAGE_HW_COMPOSER template struct HwcVirtualDisplayVariant - : DisplayVariant, width, height, Critical::FALSE, Async::TRUE, - secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY, - VIRTUAL_DISPLAY_FLAGS>, - HwcDisplayVariant< - HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID, DisplayType::VIRTUAL, - DisplayVariant, width, height, Critical::FALSE, - Async::TRUE, secure, Primary::FALSE, - GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY, VIRTUAL_DISPLAY_FLAGS>> { - using Base = DisplayVariant, width, height, Critical::FALSE, - Async::TRUE, secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER, - VIRTUAL_DISPLAY_FLAGS>; + : DisplayVariant, width, height, Async::TRUE, secure, + Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY, VIRTUAL_DISPLAY_FLAGS>, + HwcDisplayVariant, width, height, Async::TRUE, + secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY, + VIRTUAL_DISPLAY_FLAGS>> { + using Base = DisplayVariant, width, height, Async::TRUE, secure, + Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER, VIRTUAL_DISPLAY_FLAGS>; using Self = HwcVirtualDisplayVariant; static std::shared_ptr injectCompositionDisplay( -- GitLab From aa73cf5ade78f45dac0ba6feb03f0501b7b80ead Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sat, 11 Feb 2023 16:45:36 -0500 Subject: [PATCH 0010/1187] SF: Clean up FakeDisplayDeviceInjector TODO Split the double-duty setDisplayModes API. Bug: 241285876 Test: libsurfaceflinger_unittest Change-Id: Id52a824d22c9a89b650a9c50d0093b95ecfd9123 --- .../Scheduler/RefreshRateSelector.h | 3 ++- .../SurfaceFlinger_DisplayModeSwitching.cpp | 2 +- .../tests/unittests/TestableSurfaceFlinger.h | 16 ++++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h index 4f5842a67a..5052e6e257 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -32,7 +32,6 @@ #include #include "DisplayHardware/DisplayMode.h" -#include "DisplayHardware/HWComposer.h" #include "Scheduler/OneShotTimer.h" #include "Scheduler/StrongTyping.h" #include "ThreadContext.h" @@ -297,6 +296,8 @@ public: RefreshRateSelector(const RefreshRateSelector&) = delete; RefreshRateSelector& operator=(const RefreshRateSelector&) = delete; + const DisplayModes& displayModes() const { return mDisplayModes; } + // Returns whether switching modes (refresh rate or resolution) is possible. // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the modes only // differ in resolution. Once Config::FrameRateOverride::Enabled becomes the default, diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index f436a58238..019502f0fd 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -50,7 +50,7 @@ public: mFlinger.configureAndCommit(); mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this) - .setDisplayModes(kModes, kModeId60, std::move(selectorPtr)) + .setRefreshRateSelector(std::move(selectorPtr)) .inject(); // isVsyncPeriodSwitchSupported should return true, otherwise the SF's HWC proxy diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index f2c9508391..8d30e34128 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -800,16 +800,16 @@ public: return mFlinger.mutableDisplays().get(mDisplayToken)->get(); } - // If `selectorPtr` is nullptr, the injector creates RefreshRateSelector from the `modes`. - // Otherwise, it uses `selectorPtr`, which the caller must create using the same `modes`. - // - // TODO(b/182939859): Once `modes` can be retrieved from RefreshRateSelector, remove - // the `selectorPtr` parameter in favor of an alternative setRefreshRateSelector API. - auto& setDisplayModes( - DisplayModes modes, DisplayModeId activeModeId, - std::shared_ptr selectorPtr = nullptr) { + auto& setDisplayModes(DisplayModes modes, DisplayModeId activeModeId) { mDisplayModes = std::move(modes); mCreationArgs.activeModeId = activeModeId; + mCreationArgs.refreshRateSelector = nullptr; + return *this; + } + + auto& setRefreshRateSelector(RefreshRateSelectorPtr selectorPtr) { + mDisplayModes = selectorPtr->displayModes(); + mCreationArgs.activeModeId = selectorPtr->getActiveMode().modePtr->getId(); mCreationArgs.refreshRateSelector = std::move(selectorPtr); return *this; } -- GitLab From 2839c45cf9c29c11c588e5fdc868c00922f2ae6e Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 16 Feb 2023 01:48:01 +0000 Subject: [PATCH 0011/1187] libbinder: double cost for incorrect wait config If the process is configured incorrectly, waitForService waits for 1s. We'd like to make this an error, but when this was originally introduced, we didn't have functions to understand the threadpool. So, we start by making it a little bit more obvious. Bug: 269503132 Test: N/A Change-Id: I891a0b2ec4cdaff9fcfb6955dc6f08f0e4e3cfd1 --- libs/binder/IServiceManager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 2408307459..d4ef0b73a1 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -412,13 +412,11 @@ sp ServiceManagerShim::waitForService(const String16& name16) // command, so we hang indefinitely. std::unique_lock lock(waiter->mMutex); using std::literals::chrono_literals::operator""s; - waiter->mCv.wait_for(lock, 1s, [&] { - return waiter->mBinder != nullptr; - }); + waiter->mCv.wait_for(lock, 2s, [&] { return waiter->mBinder != nullptr; }); if (waiter->mBinder != nullptr) return waiter->mBinder; } - ALOGW("Waited one second for %s (is service started? Number of threads started in the " + ALOGW("Waited two seconds for %s (is service started? Number of threads started in the " "threadpool: %zu. Are binder threads started and available?)", name.c_str(), ProcessState::self()->getThreadPoolMaxTotalThreadCount()); -- GitLab From 3d21d3afa1056efacf702b74449f9e2e7b5701f1 Mon Sep 17 00:00:00 2001 From: Adam Wright Date: Thu, 16 Feb 2023 19:05:45 +0000 Subject: [PATCH 0012/1187] Revert "SF: pass a render rate to VsyncTracker instead of a divisor" Revert submission 21422016 Reason for revert: DM P0 (b/269561042) Reverted changes: /q/submissionid:21422016 Change-Id: I118dd75ea379673d649d3c75960f18ef45b3749f --- .../surfaceflinger/Scheduler/Scheduler.cpp | 6 +++- .../Scheduler/VSyncPredictor.cpp | 25 ++++--------- .../surfaceflinger/Scheduler/VSyncPredictor.h | 4 +-- .../surfaceflinger/Scheduler/VSyncTracker.h | 9 +++-- .../fuzzer/surfaceflinger_scheduler_fuzzer.h | 2 +- .../unittests/VSyncDispatchRealtimeTest.cpp | 4 +-- .../unittests/VSyncDispatchTimerQueueTest.cpp | 2 +- .../tests/unittests/VSyncPredictorTest.cpp | 36 +++---------------- .../tests/unittests/VSyncReactorTest.cpp | 2 +- .../tests/unittests/mock/MockVSyncTracker.h | 2 +- 10 files changed, 28 insertions(+), 64 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index dab01ba48d..17cdff9518 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -418,7 +418,11 @@ void Scheduler::setRenderRate(Fps renderFrameRate) { ALOGV("%s %s (%s)", __func__, to_string(mode.fps).c_str(), to_string(mode.modePtr->getFps()).c_str()); - mVsyncSchedule->getTracker().setRenderRate(renderFrameRate); + const auto divisor = RefreshRateSelector::getFrameRateDivisor(mode.modePtr->getFps(), mode.fps); + LOG_ALWAYS_FATAL_IF(divisor == 0, "%s <> %s -- not divisors", to_string(mode.fps).c_str(), + to_string(mode.fps).c_str()); + + mVsyncSchedule->getTracker().setDivisor(static_cast(divisor)); } void Scheduler::resync() { diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp index de7b338a21..5a5afd8fa6 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp @@ -272,26 +272,13 @@ nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const { // update the mLastVsyncSequence for reference point mLastVsyncSequence = getVsyncSequenceLocked(timePoint); - const auto renderRatePhase = [&]() REQUIRES(mMutex) -> int { - if (!mRenderRate) return 0; - - const auto divisor = - RefreshRateSelector::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod), - *mRenderRate); - if (divisor <= 1) return 0; - - const int mod = mLastVsyncSequence->seq % divisor; - if (mod == 0) return 0; - - return divisor - mod; - }(); - - if (renderRatePhase == 0) { + const auto mod = mLastVsyncSequence->seq % mDivisor; + if (mod == 0) { return mLastVsyncSequence->vsyncTime; } auto const [slope, intercept] = getVSyncPredictionModelLocked(); - const auto approximateNextVsync = mLastVsyncSequence->vsyncTime + slope * renderRatePhase; + const auto approximateNextVsync = mLastVsyncSequence->vsyncTime + slope * (mDivisor - mod); return nextAnticipatedVSyncTimeFromLocked(approximateNextVsync - slope / 2); } @@ -330,10 +317,10 @@ bool VSyncPredictor::isVSyncInPhaseLocked(nsecs_t timePoint, unsigned divisor) c return vsyncSequence.seq % divisor == 0; } -void VSyncPredictor::setRenderRate(Fps fps) { - ALOGV("%s: %s", __func__, to_string(fps).c_str()); +void VSyncPredictor::setDivisor(unsigned divisor) { + ALOGV("%s: %d", __func__, divisor); std::lock_guard lock(mMutex); - mRenderRate = fps; + mDivisor = divisor; } VSyncPredictor::Model VSyncPredictor::getVSyncPredictionModel() const { diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h index cd5d9ef755..d0e3098c5e 100644 --- a/services/surfaceflinger/Scheduler/VSyncPredictor.h +++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h @@ -67,7 +67,7 @@ public: bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const final EXCLUDES(mMutex); - void setRenderRate(Fps) final EXCLUDES(mMutex); + void setDivisor(unsigned divisor) final EXCLUDES(mMutex); void dump(std::string& result) const final EXCLUDES(mMutex); @@ -106,7 +106,7 @@ private: size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0; std::vector mTimestamps GUARDED_BY(mMutex); - std::optional mRenderRate GUARDED_BY(mMutex); + unsigned mDivisor GUARDED_BY(mMutex) = 1; mutable std::optional mLastVsyncSequence GUARDED_BY(mMutex); }; diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h index bc0e3bcbb2..8d1629faae 100644 --- a/services/surfaceflinger/Scheduler/VSyncTracker.h +++ b/services/surfaceflinger/Scheduler/VSyncTracker.h @@ -80,16 +80,15 @@ public: virtual bool isVSyncInPhase(nsecs_t timePoint, Fps frameRate) const = 0; /* - * Sets a render rate on the tracker. If the render rate is not a divisor - * of the period, the render rate is ignored until the period changes. + * Sets a divisor on the rate (which is a multiplier of the period). * The tracker will continue to track the vsync timeline and expect it * to match the current period, however, nextAnticipatedVSyncTimeFrom will - * return vsyncs according to the render rate set. Setting a render rate is useful + * return vsyncs according to the divisor set. Setting a divisor is useful * when a display is running at 120Hz but the render frame rate is 60Hz. * - * \param [in] Fps The render rate the tracker should operate at. + * \param [in] divisor The rate divisor the tracker should operate at. */ - virtual void setRenderRate(Fps) = 0; + virtual void setDivisor(unsigned divisor) = 0; virtual void dump(std::string& result) const = 0; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h index e6be9a8b21..713b71042a 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.h @@ -100,7 +100,7 @@ public: return true; } - void setRenderRate(Fps) override {} + void setDivisor(unsigned) override {} nsecs_t nextVSyncTime(nsecs_t timePoint) const { if (timePoint % mPeriod == 0) { diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp index 29088349f1..47c2deef51 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp @@ -54,7 +54,7 @@ public: void resetModel() final {} bool needsMoreSamples() const final { return false; } bool isVSyncInPhase(nsecs_t, Fps) const final { return false; } - void setRenderRate(Fps) final {} + void setDivisor(unsigned) final {} void dump(std::string&) const final {} private: @@ -92,7 +92,7 @@ public: void resetModel() final {} bool needsMoreSamples() const final { return false; } bool isVSyncInPhase(nsecs_t, Fps) const final { return false; } - void setRenderRate(Fps) final {} + void setDivisor(unsigned) final {} void dump(std::string&) const final {} private: diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index f143b49e5e..14a2860378 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -55,7 +55,7 @@ public: MOCK_METHOD0(resetModel, void()); MOCK_CONST_METHOD0(needsMoreSamples, bool()); MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, Fps)); - MOCK_METHOD(void, setRenderRate, (Fps), (override)); + MOCK_METHOD(void, setDivisor, (unsigned), (override)); MOCK_CONST_METHOD1(dump, void(std::string&)); nsecs_t nextVSyncTime(nsecs_t timePoint) const { diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp index db531bf194..48d39cf3f5 100644 --- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp @@ -554,7 +554,7 @@ TEST_F(VSyncPredictorTest, robustToDuplicateTimestamps_60hzRealTraceData) { EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError)); } -TEST_F(VSyncPredictorTest, setRenderRateIsRespected) { +TEST_F(VSyncPredictorTest, setDivisorIsRespected) { auto last = mNow; for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) { EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod)); @@ -563,7 +563,7 @@ TEST_F(VSyncPredictorTest, setRenderRateIsRespected) { tracker.addVsyncTimestamp(mNow); } - tracker.setRenderRate(Fps::fromPeriodNsecs(3 * mPeriod)); + tracker.setDivisor(3); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod)); @@ -574,7 +574,7 @@ TEST_F(VSyncPredictorTest, setRenderRateIsRespected) { EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 5100), Eq(mNow + 7 * mPeriod)); } -TEST_F(VSyncPredictorTest, setRenderRateOfDivisorIsInPhase) { +TEST_F(VSyncPredictorTest, setDivisorOfDivosorIsInPhase) { auto last = mNow; for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) { EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod)); @@ -583,44 +583,18 @@ TEST_F(VSyncPredictorTest, setRenderRateOfDivisorIsInPhase) { tracker.addVsyncTimestamp(mNow); } - const auto refreshRate = Fps::fromPeriodNsecs(mPeriod); - - tracker.setRenderRate(refreshRate / 4); + tracker.setDivisor(4); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + 3 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 3 * mPeriod), Eq(mNow + 7 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 7 * mPeriod), Eq(mNow + 11 * mPeriod)); - tracker.setRenderRate(refreshRate / 2); + tracker.setDivisor(2); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + 1 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1 * mPeriod), Eq(mNow + 3 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 3 * mPeriod), Eq(mNow + 5 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 5 * mPeriod), Eq(mNow + 7 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 7 * mPeriod), Eq(mNow + 9 * mPeriod)); EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 9 * mPeriod), Eq(mNow + 11 * mPeriod)); - - tracker.setRenderRate(refreshRate / 6); - EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + 1 * mPeriod)); - EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1 * mPeriod), Eq(mNow + 7 * mPeriod)); -} - -TEST_F(VSyncPredictorTest, setRenderRateIsIgnoredIfNotDivisor) { - auto last = mNow; - for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) { - EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod)); - mNow += mPeriod; - last = mNow; - tracker.addVsyncTimestamp(mNow); - } - - tracker.setRenderRate(Fps::fromPeriodNsecs(3.5f * mPeriod)); - - EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod)); - EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod)); - EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 1100), Eq(mNow + 2 * mPeriod)); - EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 2100), Eq(mNow + 3 * mPeriod)); - EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 3100), Eq(mNow + 4 * mPeriod)); - EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 4100), Eq(mNow + 5 * mPeriod)); - EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 5100), Eq(mNow + 6 * mPeriod)); } } // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp index fb8d989d44..1fb2709f8d 100644 --- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp @@ -50,7 +50,7 @@ public: MOCK_METHOD0(resetModel, void()); MOCK_CONST_METHOD0(needsMoreSamples, bool()); MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, Fps)); - MOCK_METHOD(void, setRenderRate, (Fps), (override)); + MOCK_METHOD(void, setDivisor, (unsigned), (override)); MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h index dcf25e18a8..6893154259 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h +++ b/services/surfaceflinger/tests/unittests/mock/MockVSyncTracker.h @@ -34,7 +34,7 @@ public: MOCK_METHOD0(resetModel, void()); MOCK_CONST_METHOD0(needsMoreSamples, bool()); MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, Fps)); - MOCK_METHOD(void, setRenderRate, (Fps), (override)); + MOCK_METHOD(void, setDivisor, (unsigned), (override)); MOCK_CONST_METHOD1(dump, void(std::string&)); }; -- GitLab From 6b61094a5a3758b0f61b134748e29cd3e84543fd Mon Sep 17 00:00:00 2001 From: Zixuan Qu Date: Mon, 6 Feb 2023 04:52:38 +0000 Subject: [PATCH 0013/1187] Add virtual input device native classes. Add VirtualInputDevice base class and a set of subclasses for each device type. Each virtual input device wraps a fd representing the uinput device and a set of write...event() methods. Most logic are moved from InputController JNI code: see ag/21294055 for reference. Test: atest VirtualInputTest VirtualMouseTest VirtualKeyboardTest VirtualTouchscreenTest VirtualDpadTest Bug: 267515782 Change-Id: Ie3a580acc890ac5af7461f012e05eb9ed3709a5f --- include/input/VirtualInputDevice.h | 97 ++++++++ libs/input/Android.bp | 3 + libs/input/VirtualInputDevice.cpp | 378 +++++++++++++++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 include/input/VirtualInputDevice.h create mode 100644 libs/input/VirtualInputDevice.cpp diff --git a/include/input/VirtualInputDevice.h b/include/input/VirtualInputDevice.h new file mode 100644 index 0000000000..13ffb581b4 --- /dev/null +++ b/include/input/VirtualInputDevice.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2023 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 + +namespace android { + +enum class UinputAction { + RELEASE = 0, + PRESS = 1, + MOVE = 2, + CANCEL = 3, +}; + +class VirtualInputDevice { +public: + VirtualInputDevice(android::base::unique_fd fd); + virtual ~VirtualInputDevice(); + +protected: + const android::base::unique_fd mFd; + bool writeInputEvent(uint16_t type, uint16_t code, int32_t value); + bool writeEvKeyEvent(int32_t androidCode, int32_t androidAction, + const std::map& evKeyCodeMapping, + const std::map& actionMapping); +}; + +class VirtualKeyboard : public VirtualInputDevice { +public: + static const std::map KEY_CODE_MAPPING; + // Expose to share with VirtualDpad. + static const std::map KEY_ACTION_MAPPING; + VirtualKeyboard(android::base::unique_fd fd); + virtual ~VirtualKeyboard() override; + bool writeKeyEvent(int32_t androidKeyCode, int32_t androidAction); +}; + +class VirtualDpad : public VirtualInputDevice { +public: + static const std::map DPAD_KEY_CODE_MAPPING; + VirtualDpad(android::base::unique_fd fd); + virtual ~VirtualDpad() override; + bool writeDpadKeyEvent(int32_t androidKeyCode, int32_t androidAction); +}; + +class VirtualMouse : public VirtualInputDevice { +public: + VirtualMouse(android::base::unique_fd fd); + virtual ~VirtualMouse() override; + bool writeButtonEvent(int32_t androidButtonCode, int32_t androidAction); + // TODO(b/259554911): changing float parameters to int32_t. + bool writeRelativeEvent(float relativeX, float relativeY); + bool writeScrollEvent(float xAxisMovement, float yAxisMovement); + +private: + static const std::map BUTTON_ACTION_MAPPING; + static const std::map BUTTON_CODE_MAPPING; +}; + +class VirtualTouchscreen : public VirtualInputDevice { +public: + VirtualTouchscreen(android::base::unique_fd fd); + virtual ~VirtualTouchscreen() override; + // TODO(b/259554911): changing float parameters to int32_t. + bool writeTouchEvent(int32_t pointerId, int32_t toolType, int32_t action, float locationX, + float locationY, float pressure, float majorAxisSize); + +private: + static const std::map TOUCH_ACTION_MAPPING; + static const std::map TOOL_TYPE_MAPPING; + + /* The set of active touch pointers on this device. + * We only allow pointer id to go up to MAX_POINTERS because the maximum slots of virtual + * touchscreen is set up with MAX_POINTERS. Note that in other cases Android allows pointer id + * to go up to MAX_POINTERS_ID. + */ + std::bitset mActivePointers{}; + bool isValidPointerId(int32_t pointerId, UinputAction uinputAction); + bool handleTouchDown(int32_t pointerId); + bool handleTouchUp(int32_t pointerId); +}; +} // namespace android diff --git a/libs/input/Android.bp b/libs/input/Android.bp index fd4fc16deb..3809b6dd81 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -57,6 +57,7 @@ cc_library { "TouchVideoFrame.cpp", "VelocityControl.cpp", "VelocityTracker.cpp", + "VirtualInputDevice.cpp", "VirtualKeyMap.cpp", ], @@ -124,6 +125,8 @@ cc_library { enabled: false, }, include_dirs: [ + "bionic/libc/kernel/android/uapi/", + "bionic/libc/kernel/uapi", "frameworks/native/libs/arect/include", ], }, diff --git a/libs/input/VirtualInputDevice.cpp b/libs/input/VirtualInputDevice.cpp new file mode 100644 index 0000000000..3c1f2b6b56 --- /dev/null +++ b/libs/input/VirtualInputDevice.cpp @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2023 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 "VirtualInputDevice" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using android::base::unique_fd; + +/** + * Log debug messages about native virtual input devices. + * Enable this via "adb shell setprop log.tag.VirtualInputDevice DEBUG" + */ +static bool isDebug() { + return __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO); +} + +namespace android { +VirtualInputDevice::VirtualInputDevice(unique_fd fd) : mFd(std::move(fd)) {} +VirtualInputDevice::~VirtualInputDevice() { + ioctl(mFd, UI_DEV_DESTROY); +} + +bool VirtualInputDevice::writeInputEvent(uint16_t type, uint16_t code, int32_t value) { + struct input_event ev = {.type = type, .code = code, .value = value}; + return TEMP_FAILURE_RETRY(write(mFd, &ev, sizeof(struct input_event))) == sizeof(ev); +} + +/** Utility method to write keyboard key events or mouse button events. */ +bool VirtualInputDevice::writeEvKeyEvent(int32_t androidCode, int32_t androidAction, + const std::map& evKeyCodeMapping, + const std::map& actionMapping) { + auto evKeyCodeIterator = evKeyCodeMapping.find(androidCode); + if (evKeyCodeIterator == evKeyCodeMapping.end()) { + ALOGE("Unsupported native EV keycode for android code %d", androidCode); + return false; + } + auto actionIterator = actionMapping.find(androidAction); + if (actionIterator == actionMapping.end()) { + return false; + } + if (!writeInputEvent(EV_KEY, static_cast(evKeyCodeIterator->second), + static_cast(actionIterator->second))) { + return false; + } + if (!writeInputEvent(EV_SYN, SYN_REPORT, 0)) { + return false; + } + return true; +} + +// --- VirtualKeyboard --- +const std::map VirtualKeyboard::KEY_ACTION_MAPPING = { + {AKEY_EVENT_ACTION_DOWN, UinputAction::PRESS}, + {AKEY_EVENT_ACTION_UP, UinputAction::RELEASE}, +}; +// Keycode mapping from https://source.android.com/devices/input/keyboard-devices +const std::map VirtualKeyboard::KEY_CODE_MAPPING = { + {AKEYCODE_0, KEY_0}, + {AKEYCODE_1, KEY_1}, + {AKEYCODE_2, KEY_2}, + {AKEYCODE_3, KEY_3}, + {AKEYCODE_4, KEY_4}, + {AKEYCODE_5, KEY_5}, + {AKEYCODE_6, KEY_6}, + {AKEYCODE_7, KEY_7}, + {AKEYCODE_8, KEY_8}, + {AKEYCODE_9, KEY_9}, + {AKEYCODE_A, KEY_A}, + {AKEYCODE_B, KEY_B}, + {AKEYCODE_C, KEY_C}, + {AKEYCODE_D, KEY_D}, + {AKEYCODE_E, KEY_E}, + {AKEYCODE_F, KEY_F}, + {AKEYCODE_G, KEY_G}, + {AKEYCODE_H, KEY_H}, + {AKEYCODE_I, KEY_I}, + {AKEYCODE_J, KEY_J}, + {AKEYCODE_K, KEY_K}, + {AKEYCODE_L, KEY_L}, + {AKEYCODE_M, KEY_M}, + {AKEYCODE_N, KEY_N}, + {AKEYCODE_O, KEY_O}, + {AKEYCODE_P, KEY_P}, + {AKEYCODE_Q, KEY_Q}, + {AKEYCODE_R, KEY_R}, + {AKEYCODE_S, KEY_S}, + {AKEYCODE_T, KEY_T}, + {AKEYCODE_U, KEY_U}, + {AKEYCODE_V, KEY_V}, + {AKEYCODE_W, KEY_W}, + {AKEYCODE_X, KEY_X}, + {AKEYCODE_Y, KEY_Y}, + {AKEYCODE_Z, KEY_Z}, + {AKEYCODE_GRAVE, KEY_GRAVE}, + {AKEYCODE_MINUS, KEY_MINUS}, + {AKEYCODE_EQUALS, KEY_EQUAL}, + {AKEYCODE_LEFT_BRACKET, KEY_LEFTBRACE}, + {AKEYCODE_RIGHT_BRACKET, KEY_RIGHTBRACE}, + {AKEYCODE_BACKSLASH, KEY_BACKSLASH}, + {AKEYCODE_SEMICOLON, KEY_SEMICOLON}, + {AKEYCODE_APOSTROPHE, KEY_APOSTROPHE}, + {AKEYCODE_COMMA, KEY_COMMA}, + {AKEYCODE_PERIOD, KEY_DOT}, + {AKEYCODE_SLASH, KEY_SLASH}, + {AKEYCODE_ALT_LEFT, KEY_LEFTALT}, + {AKEYCODE_ALT_RIGHT, KEY_RIGHTALT}, + {AKEYCODE_CTRL_LEFT, KEY_LEFTCTRL}, + {AKEYCODE_CTRL_RIGHT, KEY_RIGHTCTRL}, + {AKEYCODE_SHIFT_LEFT, KEY_LEFTSHIFT}, + {AKEYCODE_SHIFT_RIGHT, KEY_RIGHTSHIFT}, + {AKEYCODE_META_LEFT, KEY_LEFTMETA}, + {AKEYCODE_META_RIGHT, KEY_RIGHTMETA}, + {AKEYCODE_CAPS_LOCK, KEY_CAPSLOCK}, + {AKEYCODE_SCROLL_LOCK, KEY_SCROLLLOCK}, + {AKEYCODE_NUM_LOCK, KEY_NUMLOCK}, + {AKEYCODE_ENTER, KEY_ENTER}, + {AKEYCODE_TAB, KEY_TAB}, + {AKEYCODE_SPACE, KEY_SPACE}, + {AKEYCODE_DPAD_DOWN, KEY_DOWN}, + {AKEYCODE_DPAD_UP, KEY_UP}, + {AKEYCODE_DPAD_LEFT, KEY_LEFT}, + {AKEYCODE_DPAD_RIGHT, KEY_RIGHT}, + {AKEYCODE_MOVE_END, KEY_END}, + {AKEYCODE_MOVE_HOME, KEY_HOME}, + {AKEYCODE_PAGE_DOWN, KEY_PAGEDOWN}, + {AKEYCODE_PAGE_UP, KEY_PAGEUP}, + {AKEYCODE_DEL, KEY_BACKSPACE}, + {AKEYCODE_FORWARD_DEL, KEY_DELETE}, + {AKEYCODE_INSERT, KEY_INSERT}, + {AKEYCODE_ESCAPE, KEY_ESC}, + {AKEYCODE_BREAK, KEY_PAUSE}, + {AKEYCODE_F1, KEY_F1}, + {AKEYCODE_F2, KEY_F2}, + {AKEYCODE_F3, KEY_F3}, + {AKEYCODE_F4, KEY_F4}, + {AKEYCODE_F5, KEY_F5}, + {AKEYCODE_F6, KEY_F6}, + {AKEYCODE_F7, KEY_F7}, + {AKEYCODE_F8, KEY_F8}, + {AKEYCODE_F9, KEY_F9}, + {AKEYCODE_F10, KEY_F10}, + {AKEYCODE_F11, KEY_F11}, + {AKEYCODE_F12, KEY_F12}, + {AKEYCODE_BACK, KEY_BACK}, + {AKEYCODE_FORWARD, KEY_FORWARD}, + {AKEYCODE_NUMPAD_1, KEY_KP1}, + {AKEYCODE_NUMPAD_2, KEY_KP2}, + {AKEYCODE_NUMPAD_3, KEY_KP3}, + {AKEYCODE_NUMPAD_4, KEY_KP4}, + {AKEYCODE_NUMPAD_5, KEY_KP5}, + {AKEYCODE_NUMPAD_6, KEY_KP6}, + {AKEYCODE_NUMPAD_7, KEY_KP7}, + {AKEYCODE_NUMPAD_8, KEY_KP8}, + {AKEYCODE_NUMPAD_9, KEY_KP9}, + {AKEYCODE_NUMPAD_0, KEY_KP0}, + {AKEYCODE_NUMPAD_ADD, KEY_KPPLUS}, + {AKEYCODE_NUMPAD_SUBTRACT, KEY_KPMINUS}, + {AKEYCODE_NUMPAD_MULTIPLY, KEY_KPASTERISK}, + {AKEYCODE_NUMPAD_DIVIDE, KEY_KPSLASH}, + {AKEYCODE_NUMPAD_DOT, KEY_KPDOT}, + {AKEYCODE_NUMPAD_ENTER, KEY_KPENTER}, + {AKEYCODE_NUMPAD_EQUALS, KEY_KPEQUAL}, + {AKEYCODE_NUMPAD_COMMA, KEY_KPCOMMA}, +}; +VirtualKeyboard::VirtualKeyboard(unique_fd fd) : VirtualInputDevice(std::move(fd)) {} +VirtualKeyboard::~VirtualKeyboard() {} + +bool VirtualKeyboard::writeKeyEvent(int32_t androidKeyCode, int32_t androidAction) { + return writeEvKeyEvent(androidKeyCode, androidAction, KEY_CODE_MAPPING, KEY_ACTION_MAPPING); +} + +// --- VirtualDpad --- +// Dpad keycode mapping from https://source.android.com/devices/input/keyboard-devices +const std::map VirtualDpad::DPAD_KEY_CODE_MAPPING = { + // clang-format off + {AKEYCODE_DPAD_DOWN, KEY_DOWN}, + {AKEYCODE_DPAD_UP, KEY_UP}, + {AKEYCODE_DPAD_LEFT, KEY_LEFT}, + {AKEYCODE_DPAD_RIGHT, KEY_RIGHT}, + {AKEYCODE_DPAD_CENTER, KEY_SELECT}, + {AKEYCODE_BACK, KEY_BACK}, + // clang-format on +}; + +VirtualDpad::VirtualDpad(unique_fd fd) : VirtualInputDevice(std::move(fd)) {} + +VirtualDpad::~VirtualDpad() {} + +bool VirtualDpad::writeDpadKeyEvent(int32_t androidKeyCode, int32_t androidAction) { + return writeEvKeyEvent(androidKeyCode, androidAction, DPAD_KEY_CODE_MAPPING, + VirtualKeyboard::KEY_ACTION_MAPPING); +} + +// --- VirtualMouse --- +const std::map VirtualMouse::BUTTON_ACTION_MAPPING = { + {AMOTION_EVENT_ACTION_BUTTON_PRESS, UinputAction::PRESS}, + {AMOTION_EVENT_ACTION_BUTTON_RELEASE, UinputAction::RELEASE}, +}; + +// Button code mapping from https://source.android.com/devices/input/touch-devices +const std::map VirtualMouse::BUTTON_CODE_MAPPING = { + // clang-format off + {AMOTION_EVENT_BUTTON_PRIMARY, BTN_LEFT}, + {AMOTION_EVENT_BUTTON_SECONDARY, BTN_RIGHT}, + {AMOTION_EVENT_BUTTON_TERTIARY, BTN_MIDDLE}, + {AMOTION_EVENT_BUTTON_BACK, BTN_BACK}, + {AMOTION_EVENT_BUTTON_FORWARD, BTN_FORWARD}, + // clang-format on +}; + +VirtualMouse::VirtualMouse(unique_fd fd) : VirtualInputDevice(std::move(fd)) {} + +VirtualMouse::~VirtualMouse() {} + +bool VirtualMouse::writeButtonEvent(int32_t androidButtonCode, int32_t androidAction) { + return writeEvKeyEvent(androidButtonCode, androidAction, BUTTON_CODE_MAPPING, + BUTTON_ACTION_MAPPING); +} + +bool VirtualMouse::writeRelativeEvent(float relativeX, float relativeY) { + return writeInputEvent(EV_REL, REL_X, relativeX) && writeInputEvent(EV_REL, REL_Y, relativeY) && + writeInputEvent(EV_SYN, SYN_REPORT, 0); +} + +bool VirtualMouse::writeScrollEvent(float xAxisMovement, float yAxisMovement) { + return writeInputEvent(EV_REL, REL_HWHEEL, xAxisMovement) && + writeInputEvent(EV_REL, REL_WHEEL, yAxisMovement) && + writeInputEvent(EV_SYN, SYN_REPORT, 0); +} + +// --- VirtualTouchscreen --- +const std::map VirtualTouchscreen::TOUCH_ACTION_MAPPING = { + {AMOTION_EVENT_ACTION_DOWN, UinputAction::PRESS}, + {AMOTION_EVENT_ACTION_UP, UinputAction::RELEASE}, + {AMOTION_EVENT_ACTION_MOVE, UinputAction::MOVE}, + {AMOTION_EVENT_ACTION_CANCEL, UinputAction::CANCEL}, +}; +// Tool type mapping from https://source.android.com/devices/input/touch-devices +const std::map VirtualTouchscreen::TOOL_TYPE_MAPPING = { + {AMOTION_EVENT_TOOL_TYPE_FINGER, MT_TOOL_FINGER}, + {AMOTION_EVENT_TOOL_TYPE_PALM, MT_TOOL_PALM}, +}; + +VirtualTouchscreen::VirtualTouchscreen(unique_fd fd) : VirtualInputDevice(std::move(fd)) {} + +VirtualTouchscreen::~VirtualTouchscreen() {} + +bool VirtualTouchscreen::isValidPointerId(int32_t pointerId, UinputAction uinputAction) { + if (pointerId < -1 || pointerId >= (int)MAX_POINTERS) { + ALOGE("Virtual touch event has invalid pointer id %d; value must be between -1 and %zu", + pointerId, MAX_POINTERS - 0); + return false; + } + + if (uinputAction == UinputAction::PRESS && mActivePointers.test(pointerId)) { + ALOGE("Repetitive action DOWN event received on a pointer %d that is already down.", + pointerId); + return false; + } + if (uinputAction == UinputAction::RELEASE && !mActivePointers.test(pointerId)) { + ALOGE("PointerId %d action UP received with no prior action DOWN on touchscreen %d.", + pointerId, mFd.get()); + return false; + } + return true; +} + +bool VirtualTouchscreen::writeTouchEvent(int32_t pointerId, int32_t toolType, int32_t action, + float locationX, float locationY, float pressure, + float majorAxisSize) { + auto actionIterator = TOUCH_ACTION_MAPPING.find(action); + if (actionIterator == TOUCH_ACTION_MAPPING.end()) { + return false; + } + UinputAction uinputAction = actionIterator->second; + if (!isValidPointerId(pointerId, uinputAction)) { + return false; + } + if (!writeInputEvent(EV_ABS, ABS_MT_SLOT, pointerId)) { + return false; + } + auto toolTypeIterator = TOOL_TYPE_MAPPING.find(toolType); + if (toolTypeIterator == TOOL_TYPE_MAPPING.end()) { + return false; + } + if (!writeInputEvent(EV_ABS, ABS_MT_TOOL_TYPE, + static_cast(toolTypeIterator->second))) { + return false; + } + if (uinputAction == UinputAction::PRESS && !handleTouchDown(pointerId)) { + return false; + } + if (uinputAction == UinputAction::RELEASE && !handleTouchUp(pointerId)) { + return false; + } + if (!writeInputEvent(EV_ABS, ABS_MT_POSITION_X, locationX)) { + return false; + } + if (!writeInputEvent(EV_ABS, ABS_MT_POSITION_Y, locationY)) { + return false; + } + if (!isnan(pressure)) { + if (!writeInputEvent(EV_ABS, ABS_MT_PRESSURE, pressure)) { + return false; + } + } + if (!isnan(majorAxisSize)) { + if (!writeInputEvent(EV_ABS, ABS_MT_TOUCH_MAJOR, majorAxisSize)) { + return false; + } + } + return writeInputEvent(EV_SYN, SYN_REPORT, 0); +} + +bool VirtualTouchscreen::handleTouchUp(int32_t pointerId) { + if (!writeInputEvent(EV_ABS, ABS_MT_TRACKING_ID, static_cast(-1))) { + return false; + } + // When a pointer is no longer in touch, remove the pointer id from the corresponding + // entry in the unreleased touches map. + mActivePointers.reset(pointerId); + ALOGD_IF(isDebug(), "Pointer %d erased from the touchscreen %d", pointerId, mFd.get()); + + // Only sends the BTN UP event when there's no pointers on the touchscreen. + if (mActivePointers.none()) { + if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast(UinputAction::RELEASE))) { + return false; + } + ALOGD_IF(isDebug(), "No pointers on touchscreen %d, BTN UP event sent.", mFd.get()); + } + return true; +} + +bool VirtualTouchscreen::handleTouchDown(int32_t pointerId) { + // When a new pointer is down on the touchscreen, add the pointer id in the corresponding + // entry in the unreleased touches map. + if (mActivePointers.none()) { + // Only sends the BTN Down event when the first pointer on the touchscreen is down. + if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast(UinputAction::PRESS))) { + return false; + } + ALOGD_IF(isDebug(), "First pointer %d down under touchscreen %d, BTN DOWN event sent", + pointerId, mFd.get()); + } + + mActivePointers.set(pointerId); + ALOGD_IF(isDebug(), "Added pointer %d under touchscreen %d in the map", pointerId, mFd.get()); + if (!writeInputEvent(EV_ABS, ABS_MT_TRACKING_ID, static_cast(pointerId))) { + return false; + } + return true; +} + +} // namespace android -- GitLab From ab67ebfdfee76a350f3176e891ce2138cdee7da3 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 16 Feb 2023 17:48:56 -0800 Subject: [PATCH 0014/1187] Improve crash message when downTime is missing When the crash occurs, let's also dump the state to help debug the issue. Other fixes here include printing more information on host test runs, and removing unused functions. Bug: 211379801 Test: none Change-Id: Iba41e1bfaa00caace9113ca96349bdc8d23ef919 --- services/inputflinger/dispatcher/Entry.cpp | 14 ++++++++++---- .../dispatcher/InputDispatcher.cpp | 18 +++++++++++------- .../inputflinger/dispatcher/InputState.cpp | 4 ---- services/inputflinger/dispatcher/InputState.h | 3 --- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index ce7c882f7d..621543a1ee 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -23,11 +23,17 @@ #include #include -using android::base::GetBoolProperty; using android::base::StringPrintf; namespace android::inputdispatcher { +static const bool DEBUGGABLE = +#if defined(__ANDROID__) + android::base::GetBoolProperty("ro.debuggable", false); +#else + true; +#endif + VerifiedKeyEvent verifiedKeyEventFromKeyEntry(const KeyEntry& entry) { return {{VerifiedInputEvent::Type::KEY, entry.deviceId, entry.eventTime, entry.source, entry.displayId}, @@ -172,7 +178,7 @@ KeyEntry::KeyEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t sou KeyEntry::~KeyEntry() {} std::string KeyEntry::getDescription() const { - if (!GetBoolProperty("ro.debuggable", false)) { + if (!DEBUGGABLE) { return "KeyEvent"; } return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64 ", source=%s, displayId=%" PRId32 @@ -242,7 +248,7 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 MotionEntry::~MotionEntry() {} std::string MotionEntry::getDescription() const { - if (!GetBoolProperty("ro.debuggable", false)) { + if (!DEBUGGABLE) { return "MotionEvent"; } std::string msg; @@ -292,7 +298,7 @@ std::string SensorEntry::getDescription() const { deviceId, inputEventSourceToString(source).c_str(), ftl::enum_string(sensorType).c_str(), accuracy, hwTimestamp); - if (!GetBoolProperty("ro.debuggable", false)) { + if (DEBUGGABLE) { for (size_t i = 0; i < values.size(); i++) { if (i > 0) { msg += ", "; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 9d5bbbdd11..3f0d130ecf 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2191,7 +2191,7 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( ALOGI("Dropping event because a pointer for a different device is already down " "in display %" PRId32, displayId); - // TODO: test multiple simultaneous input streams. + // TODO(b/211379801): test multiple simultaneous input streams. outInjectionResult = InputEventInjectionResult::FAILED; return {}; // wrong device } @@ -2203,7 +2203,7 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( ALOGI("Dropping move event because a pointer for a different device is already active " "in display %" PRId32, displayId); - // TODO: test multiple simultaneous input streams. + // TODO(b/211379801): test multiple simultaneous input streams. outInjectionResult = InputEventInjectionResult::FAILED; return {}; // wrong device } @@ -3048,9 +3048,13 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const MotionEntry& originalMotionEntry = static_cast(*eventEntry); if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) { - LOG_ALWAYS_FATAL_IF(!inputTarget.firstDownTimeInTarget.has_value(), - "Splitting motion events requires a down time to be set for the " - "target"); + if (!inputTarget.firstDownTimeInTarget.has_value()) { + logDispatchStateLocked(); + LOG(FATAL) << "Splitting motion events requires a down time to be set for the " + "target on connection " + << connection->getInputChannelName() << " for " + << originalMotionEntry.getDescription(); + } std::unique_ptr splitMotionEntry = splitMotionEvent(originalMotionEntry, inputTarget.pointerIds, inputTarget.firstDownTimeInTarget.value()); @@ -3931,8 +3935,8 @@ std::unique_ptr InputDispatcher::splitMotionEvent( // in this way. ALOGW("Dropping split motion event because the pointer count is %d but " "we expected there to be %zu pointers. This probably means we received " - "a broken sequence of pointer ids from the input device.", - splitPointerCount, pointerIds.count()); + "a broken sequence of pointer ids from the input device: %s", + splitPointerCount, pointerIds.count(), originalMotionEntry.getDescription().c_str()); return nullptr; } diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index ad5a7fde07..cc9cc4efb2 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -28,10 +28,6 @@ InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerato InputState::~InputState() {} -bool InputState::isNeutral() const { - return mKeyMementos.empty() && mMotionMementos.empty(); -} - bool InputState::isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const { for (const MotionMemento& memento : mMotionMementos) { if (memento.deviceId == deviceId && memento.source == source && diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h index 42d8cc6af3..d788e47429 100644 --- a/services/inputflinger/dispatcher/InputState.h +++ b/services/inputflinger/dispatcher/InputState.h @@ -34,9 +34,6 @@ public: explicit InputState(const IdGenerator& idGenerator); ~InputState(); - // Returns true if there is no state to be canceled. - bool isNeutral() const; - // Returns true if the specified source is known to have received a hover enter // motion event. bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const; -- GitLab From 779d77347689b04c2fef7056b15b4d8e10e9f3d4 Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Fri, 17 Feb 2023 17:12:46 +0000 Subject: [PATCH 0015/1187] Check for malformed Sensor Flattenable Test: libsensorserviceaidl_fuzzer with testcase from bug Bug: 269014004 Change-Id: I0e255c64243c38876fb657cbf942fc1613363216 --- libs/sensor/Sensor.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp index fb895f59b9..b6ea77deb5 100644 --- a/libs/sensor/Sensor.cpp +++ b/libs/sensor/Sensor.cpp @@ -628,7 +628,13 @@ bool Sensor::unflattenString8(void const*& buffer, size_t& size, String8& output return false; } outputString8.setTo(static_cast(buffer), len); + + if (size < FlattenableUtils::align<4>(len)) { + ALOGE("Malformed Sensor String8 field. Should be in a 4-byte aligned buffer but is not."); + return false; + } FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len)); + return true; } -- GitLab From 91e97b8878d3e522347506d54dddb2862e1a36cb Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Fri, 17 Feb 2023 19:35:25 +0000 Subject: [PATCH 0016/1187] Remove some new memory leaks from SensorManager After catching an error in Sensor::unflatten, there are memory leaks caught by the fuzzer in the same test case. Test: libsensorserviceaidl_fuzzer with testcase from bug Bug: 269014004 Change-Id: I509cceb41f56ca117d9475f6f6674244560fe582 --- libs/sensor/ISensorServer.cpp | 12 ++++++++++-- libs/sensor/SensorManager.cpp | 5 +++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp index 2278d391b5..e2aac8c2a3 100644 --- a/libs/sensor/ISensorServer.cpp +++ b/libs/sensor/ISensorServer.cpp @@ -67,7 +67,11 @@ public: v.setCapacity(n); while (n) { n--; - reply.read(s); + if(reply.read(s) != OK) { + ALOGE("Failed to read reply from getSensorList"); + v.clear(); + break; + } v.add(s); } return v; @@ -85,7 +89,11 @@ public: v.setCapacity(n); while (n) { n--; - reply.read(s); + if(reply.read(s) != OK) { + ALOGE("Failed to read reply from getDynamicSensorList"); + v.clear(); + break; + } v.add(s); } return v; diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp index 27482768f2..8e0ea6ce8c 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -166,6 +166,11 @@ status_t SensorManager::assertStateLocked() { mSensors = mSensorServer->getSensorList(mOpPackageName); size_t count = mSensors.size(); + if (count == 0) { + ALOGE("Failed to get Sensor list"); + mSensorServer.clear(); + return UNKNOWN_ERROR; + } mSensorList = static_cast(malloc(count * sizeof(Sensor*))); LOG_ALWAYS_FATAL_IF(mSensorList == nullptr, "mSensorList NULL"); -- GitLab From 91307c641b14624a373b601837e8fc397543c987 Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Fri, 17 Feb 2023 14:55:59 -0700 Subject: [PATCH 0017/1187] EGL BlobCache: Don't check system property during init Trying to isolate why there is a slowdown when multifile is already disabled via config. Test: Boot Bug: b/266725576 Bug: b/268595699 Change-Id: I6dafcc1c5068042f7fb977b0ee012910db7f7419 --- opengl/libs/EGL/egl_cache.cpp | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp index b00ee33374..8140292b34 100644 --- a/opengl/libs/EGL/egl_cache.cpp +++ b/opengl/libs/EGL/egl_cache.cpp @@ -110,38 +110,6 @@ void egl_cache_t::initialize(egl_display_t* display) { } } - // Check the device config to decide whether multifile should be used - if (base::GetBoolProperty("ro.egl.blobcache.multifile", false)) { - mMultifileMode = true; - ALOGV("Using multifile EGL blobcache"); - } - - // Allow forcing the mode for debug purposes - std::string mode = base::GetProperty("debug.egl.blobcache.multifile", ""); - if (mode == "true") { - ALOGV("Forcing multifile cache due to debug.egl.blobcache.multifile == %s", mode.c_str()); - mMultifileMode = true; - } else if (mode == "false") { - ALOGV("Forcing monolithic cache due to debug.egl.blobcache.multifile == %s", mode.c_str()); - mMultifileMode = false; - } - - if (mMultifileMode) { - mCacheByteLimit = static_cast( - base::GetUintProperty("ro.egl.blobcache.multifile_limit", - kMultifileCacheByteLimit)); - - // Check for a debug value - int debugCacheSize = base::GetIntProperty("debug.egl.blobcache.multifile_limit", -1); - if (debugCacheSize >= 0) { - ALOGV("Overriding cache limit %zu with %i from debug.egl.blobcache.multifile_limit", - mCacheByteLimit, debugCacheSize); - mCacheByteLimit = debugCacheSize; - } - - ALOGV("Using multifile EGL blobcache limit of %zu bytes", mCacheByteLimit); - } - mInitialized = true; } -- GitLab From 1588a2e58751a357b32102ab013a7e2ab996efad Mon Sep 17 00:00:00 2001 From: Ambrus Weisz Date: Fri, 16 Dec 2022 17:54:57 +0000 Subject: [PATCH 0018/1187] Reconfigure device in TouchInputMapper when the type is changed. A race condition may occur where the device type change is only propagated after the device is created. In this case the device should be fully reconfigured. BUG: 262887935 Test: CtsHardwareTestCases:android.hardware.input.cts.tests.VirtualNavigationTouchpadTest Change-Id: Iced2e2c5af2a6f33c1299f2d0d1c30ca36a62e3c --- services/inputflinger/reader/InputDevice.cpp | 6 ++++- .../reader/mapper/TouchInputMapper.cpp | 8 +++++-- .../inputflinger/tests/InputMapperTest.cpp | 3 ++- .../inputflinger/tests/InputReader_test.cpp | 23 +++++++++++++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index c598c0a700..eafefe6136 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -277,7 +277,11 @@ std::list InputDevice::configure(nsecs_t when, const InputReaderConf mHasMic = mClasses.test(InputDeviceClass::MIC); if (!isIgnored()) { - if (!changes) { // first time only + // Full configuration should happen the first time configure is called + // and when the device type is changed. Changing a device type can + // affect various other parameters so should result in a + // reconfiguration. + if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_TYPE)) { mConfiguration.clear(); for_each_subdevice([this](InputDeviceContext& context) { PropertyMap configuration; diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 31fdac9ffc..d120e09317 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -293,7 +293,10 @@ std::list TouchInputMapper::configure(nsecs_t when, mConfig = *config; - if (!changes) { // first time only + // Full configuration should happen the first time configure is called and + // when the device type is changed. Changing a device type can affect + // various other parameters so should result in a reconfiguration. + if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_TYPE)) { // Configure basic parameters. configureParameters(); @@ -328,7 +331,8 @@ std::list TouchInputMapper::configure(nsecs_t when, InputReaderConfiguration::CHANGE_POINTER_CAPTURE | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT | InputReaderConfiguration::CHANGE_SHOW_TOUCHES | - InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) { + InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE | + InputReaderConfiguration::CHANGE_DEVICE_TYPE))) { // Configure device sources, display dimensions, orientation and // scaling factors. configureInputDevice(when, &resetNeeded); diff --git a/services/inputflinger/tests/InputMapperTest.cpp b/services/inputflinger/tests/InputMapperTest.cpp index a02ef0548e..ae300066d2 100644 --- a/services/inputflinger/tests/InputMapperTest.cpp +++ b/services/inputflinger/tests/InputMapperTest.cpp @@ -54,7 +54,8 @@ std::list InputMapperTest::configureDevice(uint32_t changes) { if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO | - InputReaderConfiguration::CHANGE_POINTER_CAPTURE))) { + InputReaderConfiguration::CHANGE_POINTER_CAPTURE | + InputReaderConfiguration::CHANGE_DEVICE_TYPE))) { mReader->requestRefreshConfiguration(changes); mReader->loopOnce(); } diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index fe7af80b92..1119f7318a 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -6724,6 +6724,29 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenConfigDisabled_ShouldNotShowDirec ASSERT_FALSE(fakePointerController->isPointerShown()); } +TEST_F(SingleTouchInputMapperTest, WhenDeviceTypeIsChangedToTouchNavigation_updatesDeviceType) { + // Initialize the device without setting device source to touch navigation. + addConfigurationProperty("touch.deviceType", "touchScreen"); + prepareDisplay(ui::ROTATION_0); + prepareButtons(); + prepareAxes(POSITION); + SingleTouchInputMapper& mapper = addMapperAndConfigure(); + + // Ensure that the device is created as a touchscreen, not touch navigation. + ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources()); + + // Add device type association after the device was created. + mFakePolicy->addDeviceTypeAssociation(DEVICE_LOCATION, "touchNavigation"); + + // Send update to the mapper. + std::list unused2 = + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), + InputReaderConfiguration::CHANGE_DEVICE_TYPE /*changes*/); + + // Check whether device type update was successful. + ASSERT_EQ(AINPUT_SOURCE_TOUCH_NAVIGATION, mDevice->getSources()); +} + // --- TouchDisplayProjectionTest --- class TouchDisplayProjectionTest : public SingleTouchInputMapperTest { -- GitLab From 837fab15be20e5960870e69065fda3645ef076ea Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 14 Feb 2023 18:06:51 -0800 Subject: [PATCH 0019/1187] Allow new gestures to cancel current gestures In a previous patch, we chose to ignore new gestures whenever there's currently an active gesture. Generally this is fine to do, but there are some concerns around doing that: 1) This is different from the previous behaviour, and some tests were relying on the previous behaviour. 2) If a test injects an ACTION_DOWN event (globally) and never lifts up the pointer, this would cause all real subsequent events to be rejected. That means a bad test can cause device to get into a bad state. Rather than adding a special case to deal with 2), let's revert to the previous behaviour. Since we are now allowing the new device to take over, and only 1 device can be active at a time (for now), we must reset the touching pointers whenever we have a new gesture starting. That's because the function synthesizeCancelationEventsForAllConnectionsLocked does not modify TouchState. We should also be canceling any of the currently hovering pointers by sending an ACTION_HOVER_EXIT if a touch down occurs. This behaviour was previously inconsistent in the mouse case. Once per-device functionality is enabled, this behaviour will be revisited. Bug: 268683979 Test: m inputflinger_tests && $ANDROID_HOST_OUT/nativetest64/inputflinger_tests/inputflinger_tests Change-Id: I10c7ebde7c108baecb67a865f541253fa6e5f7ef --- .../dispatcher/InputDispatcher.cpp | 42 +- .../inputflinger/dispatcher/TouchState.cpp | 16 +- services/inputflinger/dispatcher/TouchState.h | 1 + .../tests/InputDispatcher_test.cpp | 431 +++++++++++++++++- 4 files changed, 462 insertions(+), 28 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 3f0d130ecf..08ae376df4 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2184,18 +2184,20 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( const bool newGesture = isDown || maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction; const bool isFromMouse = isFromSource(entry.source, AINPUT_SOURCE_MOUSE); + // If pointers are already down, let's finish the current gesture and ignore the new events + // from another device. However, if the new event is a down event, let's cancel the current + // touch and let the new one take over. + if (switchedDevice && wasDown && !isDown) { + LOG(INFO) << "Dropping event because a pointer for device " << oldState->deviceId + << " is already down in display " << displayId << ": " << entry.getDescription(); + // TODO(b/211379801): test multiple simultaneous input streams. + outInjectionResult = InputEventInjectionResult::FAILED; + return {}; // wrong device + } + if (newGesture) { - // If pointers are already down, let's finish the current gesture and ignore the new events - // from another device. - if (switchedDevice && wasDown) { - ALOGI("Dropping event because a pointer for a different device is already down " - "in display %" PRId32, - displayId); - // TODO(b/211379801): test multiple simultaneous input streams. - outInjectionResult = InputEventInjectionResult::FAILED; - return {}; // wrong device - } - tempTouchState.clearWindowsWithoutPointers(); + // If a new gesture is starting, clear the touch state completely. + tempTouchState.reset(); tempTouchState.deviceId = entry.deviceId; tempTouchState.source = entry.source; isSplit = false; @@ -2317,6 +2319,10 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( const bool isDownOrPointerDown = maskedAction == AMOTION_EVENT_ACTION_DOWN || maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN; + // TODO(b/211379801): Currently, even if pointerIds are empty (hover case), we would + // still add a window to the touch state. We should avoid doing that, but some of the + // later checks ("at least one foreground window") rely on this in order to dispatch + // the event properly, so that needs to be updated, possibly by looking at InputTargets. tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds, isDownOrPointerDown ? std::make_optional(entry.eventTime) @@ -2369,10 +2375,9 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( // If the pointer is not currently down, then ignore the event. if (!tempTouchState.isDown()) { - ALOGD_IF(DEBUG_FOCUS, - "Dropping event because the pointer is not down or we previously " - "dropped the pointer down event in display %" PRId32 ": %s", - displayId, entry.getDescription().c_str()); + LOG(INFO) << "Dropping event because the pointer is not down or we previously " + "dropped the pointer down event in display " + << displayId << ": " << entry.getDescription(); outInjectionResult = InputEventInjectionResult::FAILED; return {}; } @@ -2530,7 +2535,6 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( } // Success! Output targets from the touch state. - tempTouchState.clearWindowsWithoutPointers(); for (const TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.pointerIds.none() && !touchedWindow.hasHoveringPointers(entry.deviceId)) { // Windows with hovering pointers are getting persisted inside TouchState. @@ -2570,14 +2574,13 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( } else if (maskedAction == AMOTION_EVENT_ACTION_UP) { // Pointer went up. tempTouchState.removeTouchedPointer(entry.pointerProperties[0].id); - tempTouchState.clearWindowsWithoutPointers(); } else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) { // All pointers up or canceled. tempTouchState.reset(); } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { // First pointer went down. - if (oldState && oldState->isDown()) { - ALOGD("Conflicting pointer actions: Down received while already down."); + if (oldState && (oldState->isDown() || oldState->hasHoveringPointers())) { + ALOGD("Conflicting pointer actions: Down received while already down or hovering."); *outConflictingPointerActions = true; } } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { @@ -2600,6 +2603,7 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( // state was only valid for this one action. if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) { if (displayId >= 0) { + tempTouchState.clearWindowsWithoutPointers(); mTouchStatesByDisplay[displayId] = tempTouchState; } else { mTouchStatesByDisplay.erase(displayId); diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index 425847183e..9c443f14cf 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -35,6 +35,7 @@ void TouchState::removeTouchedPointer(int32_t pointerId) { for (TouchedWindow& touchedWindow : windows) { touchedWindow.removeTouchingPointer(pointerId); } + clearWindowsWithoutPointers(); } void TouchState::removeTouchedPointerFromWindow( @@ -42,6 +43,7 @@ void TouchState::removeTouchedPointerFromWindow( for (TouchedWindow& touchedWindow : windows) { if (touchedWindow.windowHandle == windowHandle) { touchedWindow.removeTouchingPointer(pointerId); + clearWindowsWithoutPointers(); return; } } @@ -51,6 +53,7 @@ void TouchState::clearHoveringPointers() { for (TouchedWindow& touchedWindow : windows) { touchedWindow.clearHoveringPointers(); } + clearWindowsWithoutPointers(); } void TouchState::clearWindowsWithoutPointers() { @@ -135,7 +138,7 @@ void TouchState::cancelPointersForWindowsExcept(std::bitset w.pointerIds &= ~pointerIds; } }); - std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.none(); }); + clearWindowsWithoutPointers(); } /** @@ -164,7 +167,7 @@ void TouchState::cancelPointersForNonPilferingWindows() { w.pilferedPointerIds ^ allPilferedPointerIds; w.pointerIds &= ~pilferedByOtherWindows; }); - std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.none(); }); + clearWindowsWithoutPointers(); } sp TouchState::getFirstForegroundWindowHandle() const { @@ -216,6 +219,11 @@ bool TouchState::isDown() const { [](const TouchedWindow& window) { return window.pointerIds.any(); }); } +bool TouchState::hasHoveringPointers() const { + return std::any_of(windows.begin(), windows.end(), + [](const TouchedWindow& window) { return window.hasHoveringPointers(); }); +} + std::set> TouchState::getWindowsWithHoveringPointer(int32_t hoveringDeviceId, int32_t pointerId) const { std::set> out; @@ -231,9 +239,7 @@ void TouchState::removeHoveringPointer(int32_t hoveringDeviceId, int32_t hoverin for (TouchedWindow& window : windows) { window.removeHoveringPointer(hoveringDeviceId, hoveringPointerId); } - std::erase_if(windows, [](const TouchedWindow& w) { - return w.pointerIds.none() && !w.hasHoveringPointers(); - }); + clearWindowsWithoutPointers(); } std::string TouchState::dump() const { diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 6e965d8c96..a20080f534 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -71,6 +71,7 @@ struct TouchState { const sp& windowHandle) const; // Whether any of the windows are currently being touched bool isDown() const; + bool hasHoveringPointers() const; std::set> getWindowsWithHoveringPointer( int32_t deviceId, int32_t pointerId) const; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index e71cdce498..bd9038d42e 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -58,8 +58,23 @@ static constexpr int32_t SECOND_DEVICE_ID = 2; static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT; static constexpr int32_t SECOND_DISPLAY_ID = 1; +static constexpr int32_t ACTION_DOWN = AMOTION_EVENT_ACTION_DOWN; +static constexpr int32_t ACTION_MOVE = AMOTION_EVENT_ACTION_MOVE; +static constexpr int32_t ACTION_UP = AMOTION_EVENT_ACTION_UP; +static constexpr int32_t ACTION_HOVER_ENTER = AMOTION_EVENT_ACTION_HOVER_ENTER; +static constexpr int32_t ACTION_HOVER_EXIT = AMOTION_EVENT_ACTION_HOVER_EXIT; static constexpr int32_t ACTION_OUTSIDE = AMOTION_EVENT_ACTION_OUTSIDE; static constexpr int32_t ACTION_CANCEL = AMOTION_EVENT_ACTION_CANCEL; +/** + * The POINTER_DOWN(0) is an unusual, but valid, action. It just means that the new pointer in the + * MotionEvent is at the index 0 rather than 1 (or later). That is, the pointer id=0 (which is at + * index 0) is the new pointer going down. The same pointer could have been placed at a different + * index, and the action would become POINTER_1_DOWN, 2, etc..; these would all be valid. In + * general, we try to place pointer id = 0 at the index 0. Of course, this is not possible if + * pointer id=0 leaves but the pointer id=1 remains. + */ +static constexpr int32_t POINTER_0_DOWN = + AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_1_DOWN = AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_2_DOWN = @@ -145,6 +160,10 @@ MATCHER_P(WithDisplayId, displayId, "InputEvent with specified displayId") { return arg.getDisplayId() == displayId; } +MATCHER_P(WithDeviceId, deviceId, "InputEvent with specified deviceId") { + return arg.getDeviceId() == deviceId; +} + MATCHER_P(WithSource, source, "InputEvent with specified source") { *result_listener << "expected source " << inputEventSourceToString(source) << ", but got " << inputEventSourceToString(arg.getSource()); @@ -163,6 +182,10 @@ MATCHER_P2(WithCoords, x, y, "MotionEvent with specified coordinates") { return arg.getX(/*pointerIndex=*/0) == x && arg.getY(/*pointerIndex=*/0) == y; } +MATCHER_P(WithPointerCount, pointerCount, "MotionEvent with specified number of pointers") { + return arg.getPointerCount() == pointerCount; +} + MATCHER_P(WithPointers, pointers, "MotionEvent with specified pointers") { // Build a map for the received pointers, by pointer id std::map actualPointers; @@ -2364,6 +2387,165 @@ TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) { rightWindow->assertNoEvents(); } +/** + * Two windows: a window on the left and a window on the right. + * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains + * down. Then, on the left window, also place second touch pointer down. + * This test tries to reproduce a crash. + * In the buggy implementation, second pointer down on the left window would cause a crash. + */ +TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { + std::shared_ptr application = std::make_shared(); + sp leftWindow = + sp::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + leftWindow->setFrame(Rect(0, 0, 200, 200)); + + sp rightWindow = + sp::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + rightWindow->setFrame(Rect(200, 0, 400, 200)); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow}}}); + + const int32_t touchDeviceId = 4; + const int32_t mouseDeviceId = 6; + NotifyMotionArgs args; + + // Start hovering over the left window + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100)) + .build())); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); + + // Mouse down on left window + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100)) + .build())); + + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId))); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); + + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100)) + .build())); + leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); + + // First touch pointer down on right window + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) + .build())); + leftWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); + + rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + + // Second touch pointer down on left window + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) + .build())); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); + // This MOVE event is not necessary (doesn't carry any new information), but it's there in the + // current implementation. + const std::map expectedPointers{{0, PointF{100, 100}}}; + rightWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithPointers(expectedPointers))); + + leftWindow->assertNoEvents(); + rightWindow->assertNoEvents(); +} + +/** + * On a single window, use two different devices: mouse and touch. + * Touch happens first, with two pointers going down, and then the first pointer leaving. + * Mouse is clicked next, which causes the touch stream to be aborted with ACTION_CANCEL. + * Finally, a second touch pointer goes down again. Ensure the second touch pointer is ignored, + * because the mouse is currently down, and a POINTER_DOWN event from the touchscreen does not + * represent a new gesture. + */ +TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { + std::shared_ptr application = std::make_shared(); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 400, 400)); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + + const int32_t touchDeviceId = 4; + const int32_t mouseDeviceId = 6; + NotifyMotionArgs args; + + // First touch pointer down on right window + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) + .build())); + // Second touch pointer down + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(350).y(100)) + .build())); + // First touch pointer lifts. The second one remains down + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(350).y(100)) + .build())); + window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); + window->consumeMotionEvent(WithMotionAction(POINTER_0_UP)); + + // Mouse down. The touch should be canceled + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(320).y(100)) + .build())); + + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId), + WithPointerCount(2u))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); + + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(320).y(100)) + .build())); + window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); + + // Second touch pointer down. + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(350).y(100)) + .build())); + // The pointer_down event should be ignored + window->assertNoEvents(); +} + /** * This test is similar to the test above, but the sequence of injected events is different. * @@ -2540,6 +2722,182 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { window->assertNoEvents(); } +/** + * A spy window above a window with no input channel. + * Start hovering with a stylus device, and then tap with it. + * Ensure spy window receives the entire sequence. + */ +TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) { + std::shared_ptr application = std::make_shared(); + sp spyWindow = + sp::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); + spyWindow->setFrame(Rect(0, 0, 200, 200)); + spyWindow->setTrustedOverlay(true); + spyWindow->setSpy(true); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setNoInputChannel(true); + window->setFrame(Rect(0, 0, 200, 200)); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, window}}}); + + NotifyMotionArgs args; + + // Start hovering with stylus + mDispatcher->notifyMotion( + &(args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50)) + .build())); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + // Stop hovering + mDispatcher->notifyMotion( + &(args = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50)) + .build())); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); + + // Stylus touches down + mDispatcher->notifyMotion( + &(args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50)) + .build())); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + + // Stylus goes up + mDispatcher->notifyMotion( + &(args = MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50)) + .build())); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP)); + + // Again hover + mDispatcher->notifyMotion( + &(args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50)) + .build())); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + // Stop hovering + mDispatcher->notifyMotion( + &(args = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50)) + .build())); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); + + // No more events + spyWindow->assertNoEvents(); + window->assertNoEvents(); +} + +/** + * Start hovering with a mouse, and then tap with a touch device. Pilfer the touch stream. + * Next, click with the mouse device. Both windows (spy and regular) should receive the new mouse + * ACTION_DOWN event because that's a new gesture, and pilfering should no longer be active. + * While the mouse is down, new move events from the touch device should be ignored. + */ +TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { + std::shared_ptr application = std::make_shared(); + sp spyWindow = + sp::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); + spyWindow->setFrame(Rect(0, 0, 200, 200)); + spyWindow->setTrustedOverlay(true); + spyWindow->setSpy(true); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 200, 200)); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, window}}}); + + const int32_t mouseDeviceId = 7; + const int32_t touchDeviceId = 4; + NotifyMotionArgs args; + + // Hover a bit with mouse first + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100)) + .build())); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); + window->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); + + // Start touching + mDispatcher->notifyMotion( + &(args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .build())); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + + mDispatcher->notifyMotion( + &(args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(55).y(55)) + .build())); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); + window->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); + + // Pilfer the stream + EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken())); + window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); + + mDispatcher->notifyMotion( + &(args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(60).y(60)) + .build())); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); + + // Mouse down + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100)) + .build())); + + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId))); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); + + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100)) + .build())); + spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); + window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); + + // Mouse move! + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(110).y(110)) + .build())); + spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); + window->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); + + // Touch move! + mDispatcher->notifyMotion( + &(args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(65).y(65)) + .build())); + + // No more events + spyWindow->assertNoEvents(); + window->assertNoEvents(); +} + /** * On the display, have a single window, and also an area where there's no window. * First pointer touches the "no window" area of the screen. Second pointer touches the window. @@ -2705,7 +3063,8 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { .x(300) .y(400)) .build())); - windowLeft->consumeMotionDown(ADISPLAY_ID_DEFAULT); + windowLeft->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); + windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, @@ -2750,7 +3109,6 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { .x(900) .y(400)) .build())); - windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // No more events @@ -2758,6 +3116,70 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { windowRight->assertNoEvents(); } +/** + * Put two fingers down (and don't release them) and click the mouse button. + * The clicking of mouse is a new ACTION_DOWN event. Since it's from a different device, the + * currently active gesture should be canceled, and the new one should proceed. + */ +TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) { + std::shared_ptr application = std::make_shared(); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 600, 800)); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + + const int32_t touchDeviceId = 4; + const int32_t mouseDeviceId = 6; + NotifyMotionArgs args; + + // Two pointers down + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) + .build())); + + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) + .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(120).y(120)) + .build())); + window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); + + // Inject a series of mouse events for a mouse click + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(300).y(400)) + .build())); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId), + WithPointerCount(2u))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); + + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(300).y(400)) + .build())); + window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); + + // Try to send more touch events while the mouse is down. Since it's a continuation of an + // already canceled gesture, it should be ignored. + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(101).y(101)) + .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(121).y(121)) + .build())); + window->assertNoEvents(); +} + TEST_F(InputDispatcherTest, HoverWithSpyWindows) { std::shared_ptr application = std::make_shared(); @@ -2940,7 +3362,8 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { .x(300) .y(400)) .build())); - window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); + window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, @@ -2984,7 +3407,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { .x(300) .y(400)) .build())); - window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); + window->assertNoEvents(); } /** -- GitLab From 231446d0f0dce6db16ba158113c09719fa562e9e Mon Sep 17 00:00:00 2001 From: Ryan Savitski Date: Mon, 20 Feb 2023 20:07:50 +0000 Subject: [PATCH 0020/1187] tracefs permissions: fix throttled_rss_stat/enable on user builds throttled_rss_stat is a synthetic event derived from kmem/rss_stat via hitogram/trigger machinery in tracefs. The existing MAC and DAC permissions allow us to do everything except actually enabling/disabling the recording of the synthetic event. userdebug builds work because we fall back onto a generic enable/disable set_event mechanism that is debug-only. From strace on a debuggable build: openat(AT_FDCWD, "/sys/kernel/tracing/events/synthetic/rss_stat_throttled/enable", O_WRONLY|O_CLOEXEC) = -1 EACCES (Permission denied) And the corresponding file permissions: /sys/kernel/tracing/events/synthetic/rss_stat_throttled $ ls -alZ -rw-r--r-- 1 root readtracefs u:object_r:debugfs_tracing:s0 0 2023-02-20 19:26 enable Tested: patched onto an internal branch, flashed panther-user, collected trace with perfetto Bug: 270060883 Change-Id: I6001eec487932ab1fd869231815fbf485b7370bb --- cmds/atrace/atrace.rc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index 2e0c95a5fe..ea5d602625 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -297,8 +297,12 @@ on late-init write /sys/kernel/debug/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size" # allow creating event triggers - chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger + chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger + + # allow enabling rss_stat_throttled + chmod 0666 /sys/kernel/tracing/events/synthetic/rss_stat_throttled/enable + chmod 0666 /sys/kernel/debug/tracing/events/synthetic/rss_stat_throttled/enable on late-init && property:ro.boot.fastboot.boottrace=enabled setprop debug.atrace.tags.enableflags 802922 -- GitLab From 4f18a6e2a6c49ea56a5fd7d4a373ddd7c766ed6f Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Mon, 30 Jan 2023 15:09:30 +0000 Subject: [PATCH 0021/1187] Replace ChromeOS pointer ballistics with Android-specific ones This are the initial curve suggested by UX research, and is still subject to tweaks and changes if I understand correctly. Bug: 265798483 Test: manual Change-Id: Ie45379f8d2340311b1e2f10b1cc04f61efefb0bd --- .../reader/mapper/TouchpadInputMapper.cpp | 81 ++++++++++++++++++- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp index 9f32311e14..8ab6748bfe 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp @@ -16,6 +16,7 @@ #include "../Macros.h" +#include #include #include @@ -30,6 +31,76 @@ namespace android { namespace { +// Describes a segment of the acceleration curve. +struct CurveSegment { + // The maximum pointer speed which this segment should apply. The last segment in a curve should + // always set this to infinity. + double maxPointerSpeedMmPerS; + double slope; + double intercept; +}; + +const std::vector segments = { + {10.922, 3.19, 0}, + {31.750, 4.79, -17.526}, + {98.044, 7.28, -96.52}, + {std::numeric_limits::infinity(), 15.04, -857.758}, +}; + +const std::vector sensitivityFactors = {1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 20}; + +std::vector createAccelerationCurveForSensitivity(int32_t sensitivity, + size_t propertySize) { + LOG_ALWAYS_FATAL_IF(propertySize < 4 * segments.size()); + std::vector output(propertySize, 0); + + // The Gestures library uses functions of the following form to define curve segments, where a, + // b, and c can be specified by us: + // output_speed(input_speed_mm) = a * input_speed_mm ^ 2 + b * input_speed_mm + c + // + // (a, b, and c are also called sqr_, mul_, and int_ in the Gestures library code.) + // + // We are trying to implement the following function, where slope and intercept are the + // parameters specified in the `segments` array above: + // gain(input_speed_mm) = + // 0.64 * (sensitivityFactor / 10) * (slope + intercept / input_speed_mm) + // Where "gain" is a multiplier applied to the input speed to produce the output speed: + // output_speed(input_speed_mm) = input_speed_mm * gain(input_speed_mm) + // + // To put our function in the library's form, we substitute it into the function above: + // output_speed(input_speed_mm) = + // input_speed_mm * (0.64 * (sensitivityFactor / 10) * + // (slope + 25.4 * intercept / input_speed_mm)) + // then expand the brackets so that input_speed_mm cancels out for the intercept term: + // gain(input_speed_mm) = + // 0.64 * (sensitivityFactor / 10) * slope * input_speed_mm + + // 0.64 * (sensitivityFactor / 10) * intercept + // + // This gives us the following parameters for the Gestures library function form: + // a = 0 + // b = 0.64 * (sensitivityFactor / 10) * slope + // c = 0.64 * (sensitivityFactor / 10) * intercept + + double commonFactor = 0.64 * sensitivityFactors[sensitivity + 7] / 10; + + size_t i = 0; + for (CurveSegment seg : segments) { + // The library's curve format consists of four doubles per segment: + // * maximum pointer speed for the segment (mm/s) + // * multiplier for the x² term (a.k.a. "a" or "sqr") + // * multiplier for the x term (a.k.a. "b" or "mul") + // * the intercept (a.k.a. "c" or "int") + // (see struct CurveSegment in the library's AccelFilterInterpreter) + output[i + 0] = seg.maxPointerSpeedMmPerS; + output[i + 1] = 0; + output[i + 2] = commonFactor * seg.slope; + output[i + 3] = commonFactor * seg.intercept; + i += 4; + } + + return output; +} + short getMaxTouchCount(const InputDeviceContext& context) { if (context.hasScanCode(BTN_TOOL_QUINTTAP)) return 5; if (context.hasScanCode(BTN_TOOL_QUADTAP)) return 4; @@ -147,10 +218,12 @@ std::list TouchpadInputMapper::configure(nsecs_t when, mGestureConverter.setOrientation(orientation); } if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCHPAD_SETTINGS)) { - // TODO(b/265798483): load an Android-specific acceleration curve instead of mapping to one - // of five ChromeOS curves. - const int pointerSensitivity = (config->touchpadPointerSpeed + 7) / 3 + 1; - mPropertyProvider.getProperty("Pointer Sensitivity").setIntValues({pointerSensitivity}); + mPropertyProvider.getProperty("Use Custom Touchpad Pointer Accel Curve") + .setBoolValues({true}); + GesturesProp accelCurveProp = mPropertyProvider.getProperty("Pointer Accel Curve"); + accelCurveProp.setRealValues( + createAccelerationCurveForSensitivity(config->touchpadPointerSpeed, + accelCurveProp.getCount())); mPropertyProvider.getProperty("Invert Scrolling") .setBoolValues({config->touchpadNaturalScrollingEnabled}); mPropertyProvider.getProperty("Tap Enable") -- GitLab From ab5a4bc759a82ca54fc008561b1ba4377e52182c Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 21 Feb 2023 11:50:34 -0800 Subject: [PATCH 0022/1187] Add test for HOVER_EXIT when another device is touched When there's currently a hovering pointer, it should be canceled via "HOVER_EXIT" whenever another device touches down (by sending ACTION_DOWN). Bug: 268683979 Test: m inputflinger_tests && $ANDROID_HOST_OUT/nativetest64/inputflinger_tests/inputflinger_tests Change-Id: Ib839c8d6c1f949a5c7f62739b989aa9ec7481058 --- .../tests/InputDispatcher_test.cpp | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index bd9038d42e..cda677e54e 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2490,7 +2490,7 @@ TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { const int32_t mouseDeviceId = 6; NotifyMotionArgs args; - // First touch pointer down on right window + // First touch pointer down mDispatcher->notifyMotion(&( args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) @@ -3439,6 +3439,42 @@ TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) { window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); } +/** + * If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT. + */ +TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) { + std::shared_ptr application = std::make_shared(); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 100, 100)); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + + const int32_t mouseDeviceId = 7; + const int32_t touchDeviceId = 4; + NotifyMotionArgs args; + + // Start hovering with the mouse + mDispatcher->notifyMotion( + &(args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(10).y(10)) + .build())); + window->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); + + // Touch goes down + mDispatcher->notifyMotion( + &(args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .build())); + + window->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); +} + /** * Inject a mouse hover event followed by a tap from touchscreen. * The tap causes a HOVER_EXIT event to be generated because the current event -- GitLab From f06b672b3e433121037398c7255098ed0130c649 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Sun, 29 Jan 2023 14:57:43 -0800 Subject: [PATCH 0023/1187] Ensure channel receives a consistent touch stream Add an event verifier to check the touch streams that are being sent to the input channel. If a stream is inconsistent, crash. For now, only touch streams are being verified. Disable the feature while the bugs are being fixed. Bug: 267082966 Test: m inputflinger_tests && $ANDROID_HOST_OUT/nativetest64/inputflinger_tests/inputflinger_tests Change-Id: Ibb8ab70b0019789c1a17dae0077be6b23d3d9139 --- include/input/InputTransport.h | 2 + include/input/InputVerifier.h | 49 +++++++ libs/input/Android.bp | 1 + libs/input/InputTransport.cpp | 15 +- libs/input/InputVerifier.cpp | 128 ++++++++++++++++++ .../tests/InputDispatcher_test.cpp | 24 +++- 6 files changed, 214 insertions(+), 5 deletions(-) create mode 100644 include/input/InputVerifier.h create mode 100644 libs/input/InputVerifier.cpp diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 1c52792cf6..a1be542d7b 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -444,6 +445,7 @@ public: private: std::shared_ptr mChannel; + InputVerifier mInputVerifier; }; /* diff --git a/include/input/InputVerifier.h b/include/input/InputVerifier.h new file mode 100644 index 0000000000..d4589f53b5 --- /dev/null +++ b/include/input/InputVerifier.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 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 +#include + +namespace android { + +/* + * Crash if the provided touch stream is inconsistent. + * + * TODO(b/211379801): Add support for hover events: + * - No hover move without enter + * - No touching pointers when hover enter + * - No hovering pointers when touching + * - Only 1 hovering pointer max + */ +class InputVerifier { +public: + InputVerifier(const std::string& name); + + void processMovement(int32_t deviceId, int32_t action, uint32_t pointerCount, + const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords, int32_t flags); + +private: + const std::string mName; + std::map> mTouchingPointerIdsByDevice; + void ensureTouchingPointersMatch(int32_t deviceId, uint32_t pointerCount, + const PointerProperties* pointerProperties, + const char* action) const; +}; + +} // namespace android diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 3809b6dd81..48cb72cfb7 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -47,6 +47,7 @@ cc_library { "Input.cpp", "InputDevice.cpp", "InputEventLabels.cpp", + "InputVerifier.cpp", "Keyboard.cpp", "KeyCharacterMap.cpp", "KeyLayoutMap.cpp", diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 9f0a314041..d1cd50ccff 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -76,6 +76,14 @@ static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS; */ static const char* PROPERTY_RESAMPLING_ENABLED = "ro.input.resampling"; +/** + * Crash if the events that are getting sent to the InputPublisher are inconsistent. + * Enable this via "adb shell setprop log.tag.InputTransportVerifyEvents DEBUG" + */ +static bool verifyEvents() { + return __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "VerifyEvents", ANDROID_LOG_INFO); +} + template inline static T min(const T& a, const T& b) { return a < b ? a : b; @@ -492,7 +500,8 @@ base::unique_fd InputChannel::dupFd() const { // --- InputPublisher --- -InputPublisher::InputPublisher(const std::shared_ptr& channel) : mChannel(channel) {} +InputPublisher::InputPublisher(const std::shared_ptr& channel) + : mChannel(channel), mInputVerifier(channel->getName()) {} InputPublisher::~InputPublisher() { } @@ -555,6 +564,10 @@ status_t InputPublisher::publishMotionEvent( mChannel->getName().c_str(), action); ATRACE_NAME(message.c_str()); } + if (verifyEvents()) { + mInputVerifier.processMovement(deviceId, action, pointerCount, pointerProperties, + pointerCoords, flags); + } if (DEBUG_TRANSPORT_ACTIONS) { std::string transformString; transform.dump(transformString, "transform", " "); diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp new file mode 100644 index 0000000000..eb758045cc --- /dev/null +++ b/libs/input/InputVerifier.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2023 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 "InputVerifier" + +#include +#include + +namespace android { + +/** + * Log all of the movements that are sent to this verifier. Helps to identify the streams that lead + * to inconsistent events. + * Enable this via "adb shell setprop log.tag.InputVerifierLogEvents DEBUG" + */ +static bool logEvents() { + return __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "LogEvents", ANDROID_LOG_INFO); +} + +// --- InputVerifier --- + +InputVerifier::InputVerifier(const std::string& name) : mName(name){}; + +void InputVerifier::processMovement(int32_t deviceId, int32_t action, uint32_t pointerCount, + const PointerProperties* pointerProperties, + const PointerCoords* pointerCoords, int32_t flags) { + if (logEvents()) { + LOG(ERROR) << "Processing " << MotionEvent::actionToString(action) << " for device " + << deviceId << " (" << pointerCount << " pointer" + << (pointerCount == 1 ? "" : "s") << ") on " << mName; + } + + switch (MotionEvent::getActionMasked(action)) { + case AMOTION_EVENT_ACTION_DOWN: { + auto [it, inserted] = mTouchingPointerIdsByDevice.insert({deviceId, {}}); + if (!inserted) { + LOG(FATAL) << "Got ACTION_DOWN, but already have touching pointers " << it->second + << " for device " << deviceId << " on " << mName; + } + it->second.set(pointerProperties[0].id); + break; + } + case AMOTION_EVENT_ACTION_POINTER_DOWN: { + auto it = mTouchingPointerIdsByDevice.find(deviceId); + if (it == mTouchingPointerIdsByDevice.end()) { + LOG(FATAL) << "Got POINTER_DOWN, but no touching pointers for device " << deviceId + << " on " << mName; + } + it->second.set(pointerProperties[MotionEvent::getActionIndex(action)].id); + break; + } + case AMOTION_EVENT_ACTION_MOVE: { + ensureTouchingPointersMatch(deviceId, pointerCount, pointerProperties, "MOVE"); + break; + } + case AMOTION_EVENT_ACTION_POINTER_UP: { + auto it = mTouchingPointerIdsByDevice.find(deviceId); + if (it == mTouchingPointerIdsByDevice.end()) { + LOG(FATAL) << "Got POINTER_UP, but no touching pointers for device " << deviceId + << " on " << mName; + } + it->second.reset(pointerProperties[MotionEvent::getActionIndex(action)].id); + break; + } + case AMOTION_EVENT_ACTION_UP: { + auto it = mTouchingPointerIdsByDevice.find(deviceId); + if (it == mTouchingPointerIdsByDevice.end()) { + LOG(FATAL) << "Got ACTION_UP, but no record for deviceId " << deviceId << " on " + << mName; + } + const auto& [_, touchingPointerIds] = *it; + if (touchingPointerIds.count() != 1) { + LOG(FATAL) << "Got ACTION_UP, but we have pointers: " << touchingPointerIds + << " for deviceId " << deviceId << " on " << mName; + } + const int32_t pointerId = pointerProperties[0].id; + if (!touchingPointerIds.test(pointerId)) { + LOG(FATAL) << "Got ACTION_UP, but pointerId " << pointerId + << " is not touching. Touching pointers: " << touchingPointerIds + << " for deviceId " << deviceId << " on " << mName; + } + mTouchingPointerIdsByDevice.erase(it); + break; + } + case AMOTION_EVENT_ACTION_CANCEL: { + if ((flags & AMOTION_EVENT_FLAG_CANCELED) != AMOTION_EVENT_FLAG_CANCELED) { + LOG(FATAL) << "For ACTION_CANCEL, must set FLAG_CANCELED"; + } + ensureTouchingPointersMatch(deviceId, pointerCount, pointerProperties, "CANCEL"); + mTouchingPointerIdsByDevice.erase(deviceId); + break; + } + } +} + +void InputVerifier::ensureTouchingPointersMatch(int32_t deviceId, uint32_t pointerCount, + const PointerProperties* pointerProperties, + const char* action) const { + auto it = mTouchingPointerIdsByDevice.find(deviceId); + if (it == mTouchingPointerIdsByDevice.end()) { + LOG(FATAL) << "Got " << action << ", but no touching pointers for device " << deviceId + << " on " << mName; + } + const auto& [_, touchingPointerIds] = *it; + for (size_t i = 0; i < pointerCount; i++) { + const int32_t pointerId = pointerProperties[i].id; + if (!touchingPointerIds.test(pointerId)) { + LOG(FATAL) << "Got " << action << " for pointerId " << pointerId + << " but the touching pointers are " << touchingPointerIds << " on " + << mName; + } + } +}; + +} // namespace android diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index bd9038d42e..711366dd5d 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2052,8 +2052,17 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {100, 100})) + injectMotionEvent(mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_UP, + AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 1, + AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(100)) + .build(), + INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); @@ -3007,8 +3016,8 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) { window1->assertNoEvents(); // Now move the pointer on the first window - mDispatcher->notifyMotion( - &(args = generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}}))); + mDispatcher->notifyMotion(&( + args = generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}}))); mDispatcher->waitForIdle(); window1->consumeMotionEvent(WithDownTime(downTimeForWindow1)); @@ -5465,6 +5474,13 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID); monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID); + // Lift up the touch from the second display + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID); + monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID); + // Test inject a non-pointer motion event. // If specific a display, it will dispatch to the focused window of particular display, // or it will dispatch to the focused window of focused display. -- GitLab From d8f2f9034cf69eb05b98a0af55321ddb4e6874a8 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 21 Feb 2023 19:13:16 -0800 Subject: [PATCH 0024/1187] Ensure real touch cancels injected events Sometimes, tests inject events globally. If a test is not hermetic (or, it crashes), it may leave the system in an inconsistent state. To the dispatcher, it would look like the virtual device is still down. Currently, we don't subscribe to any injector death notifications (and don't plan on doing so). After this happens, the user may want to interact with the device, so the notifyMotion call would come in. In this test, make sure that the injected event is canceled when the new gesture is started. Bug: 266382436 Test: m inputflinger_tests && $ANDROID_HOST_OUT/nativetest64/inputflinger_tests/inputflinger_tests Change-Id: I9eeacd1e48cb1cd36a55acc8a129a83edd2784fc --- .../tests/InputDispatcher_test.cpp | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index bd9038d42e..6155cdb279 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -105,6 +105,8 @@ static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms; static constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; +using ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID; + struct PointF { float x; float y; @@ -2546,6 +2548,46 @@ TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { window->assertNoEvents(); } +/** + * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event cancels + * the injected event. + */ +TEST_F(InputDispatcherTest, UnfinishedInjectedEvent) { + std::shared_ptr application = std::make_shared(); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 400, 400)); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + + const int32_t touchDeviceId = 4; + NotifyMotionArgs args; + // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after + // completion. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, + MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) + .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) + .x(50) + .y(50)) + .build())); + window->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID))); + + // Now a real touch comes. Rather than crashing or dropping the real event, the injected pointer + // should be canceled and the new gesture should take over. + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) + .build())); + + window->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(VIRTUAL_KEYBOARD_ID))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); +} + /** * This test is similar to the test above, but the sequence of injected events is different. * -- GitLab From be530ebf132c7d85ee7b6160e8799bfaa7d1e31d Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 17 Feb 2023 23:12:52 -0800 Subject: [PATCH 0025/1187] Don't store the departing pointer in InputState Before this CL, InputState stored the pointer that is leaving. This is a problem when the request to cancel the current gesture comes in. To cancel the gesture, the currently stored pointers were used. That means that in a sequence of ACTION_DOWN -> ACTION_POINTER_DOWN -> ACTION_POINTER_UP -> CANCEL, the cancel event would still be produced with two pointers. The correct behaviour to is to cancel the remaining pointer. The solution here skips the addition of the departing pointer to the InputState, and modifies the pointerCount appropriately. Bug: 211379801 Test: m inputflinger_tests && $ANDROID_HOST_OUT/nativetest64/inputflinger_tests/inputflinger_tests --gtest_filter="*CancelAfterPointer0Up*" Change-Id: I8323cc08a974d0ec880b5570f0cd572ee071522a --- .../inputflinger/dispatcher/InputState.cpp | 15 +++++-- .../tests/InputDispatcher_test.cpp | 44 ++++++++++++++++++- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index cc9cc4efb2..94f38131b6 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -247,10 +247,19 @@ void InputState::addMotionMemento(const MotionEntry& entry, int32_t flags, bool } void InputState::MotionMemento::setPointers(const MotionEntry& entry) { - pointerCount = entry.pointerCount; + pointerCount = 0; for (uint32_t i = 0; i < entry.pointerCount; i++) { - pointerProperties[i].copyFrom(entry.pointerProperties[i]); - pointerCoords[i].copyFrom(entry.pointerCoords[i]); + if (MotionEvent::getActionMasked(entry.action) == AMOTION_EVENT_ACTION_POINTER_UP) { + // In POINTER_UP events, the pointer is leaving. Since the action is not stored, + // this departing pointer should not be recorded. + const uint8_t actionIndex = MotionEvent::getActionIndex(entry.action); + if (i == actionIndex) { + continue; + } + } + pointerProperties[pointerCount].copyFrom(entry.pointerProperties[i]); + pointerCoords[pointerCount].copyFrom(entry.pointerCoords[i]); + pointerCount++; } } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index cda677e54e..2d1922ae65 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1944,6 +1944,48 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); } +/** + * Two fingers down on the window, and lift off the first finger. + * Next, cancel the gesture to the window by removing the window. Make sure that the CANCEL event + * contains a single pointer. + */ +TEST_F(InputDispatcherTest, CancelAfterPointer0Up) { + std::shared_ptr application = std::make_shared(); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + NotifyMotionArgs args; + // First touch pointer down on right window + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) + .build())); + // Second touch pointer down + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) + .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(110).y(100)) + .build())); + // First touch pointer lifts. The second one remains down + mDispatcher->notifyMotion(&( + args = MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) + + .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) + .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(110).y(100)) + .build())); + window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); + window->consumeMotionEvent(WithMotionAction(POINTER_0_UP)); + + // Remove the window. The gesture should be canceled + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {}}}); + const std::map expectedPointers{{1, PointF{110, 100}}}; + window->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedPointers))); +} + /** * Same test as WhenForegroundWindowDisappears_WallpaperTouchIsCanceled above, * with the following differences: @@ -2523,7 +2565,7 @@ TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { .build())); window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId), - WithPointerCount(2u))); + WithPointerCount(1u))); window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); mDispatcher->notifyMotion(&( -- GitLab From 4c766ae50ce641672158c19eda4613a5e64baf47 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Thu, 16 Feb 2023 17:46:22 -0600 Subject: [PATCH 0026/1187] Fix WindowInfosListenerTest Fixes a race condition where the WindowInfo vector checked may not contain the updated window on the first pass. Bug: 269522974 Test: atest WindowInfosListenerTest Change-Id: I013955dd1c89858190b519c2980909e2e7e45a24 --- services/surfaceflinger/SurfaceFlinger.cpp | 7 +- services/surfaceflinger/SurfaceFlinger.h | 5 +- .../WindowInfosListenerInvoker.cpp | 1 - .../WindowInfosListenerInvoker.h | 4 +- .../tests/WindowInfosListener_test.cpp | 87 +++++++++++-------- 5 files changed, 60 insertions(+), 44 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5c8579cb4d..e23906f755 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3576,6 +3576,10 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { }); } + if (transactionFlags & eInputInfoUpdateNeeded) { + mUpdateInputInfo = true; + } + doCommitTransactions(); } @@ -7566,8 +7570,9 @@ void SurfaceFlinger::onActiveDisplayChangedLocked(const DisplayDevice* inactiveD } status_t SurfaceFlinger::addWindowInfosListener( - const sp& windowInfosListener) const { + const sp& windowInfosListener) { mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener); + setTransactionFlags(eInputInfoUpdateNeeded); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b41f414f62..03c31bb015 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -162,7 +162,8 @@ enum { eDisplayTransactionNeeded = 0x04, eTransformHintUpdateNeeded = 0x08, eTransactionFlushNeeded = 0x10, - eTransactionMask = 0x1f, + eInputInfoUpdateNeeded = 0x20, + eTransactionMask = 0x3f, }; // Latch Unsignaled buffer behaviours @@ -618,7 +619,7 @@ private: status_t getMaxAcquiredBufferCount(int* buffers) const; - status_t addWindowInfosListener(const sp& windowInfosListener) const; + status_t addWindowInfosListener(const sp& windowInfosListener); status_t removeWindowInfosListener( const sp& windowInfosListener) const; diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index a1313e3a03..292083b9bc 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -17,7 +17,6 @@ #include #include -#include "SurfaceFlinger.h" #include "WindowInfosListenerInvoker.h" namespace android { diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index a1d66a186e..d60a9c4157 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -16,6 +16,8 @@ #pragma once +#include + #include #include #include @@ -49,8 +51,6 @@ private: static constexpr size_t kStaticCapacity = 3; ftl::SmallMap, const sp, kStaticCapacity> mWindowInfosListeners GUARDED_BY(mListenersMutex); - - sp mWindowInfosReportedListener; }; } // namespace android diff --git a/services/surfaceflinger/tests/WindowInfosListener_test.cpp b/services/surfaceflinger/tests/WindowInfosListener_test.cpp index 53c3c3998f..d71486fca7 100644 --- a/services/surfaceflinger/tests/WindowInfosListener_test.cpp +++ b/services/surfaceflinger/tests/WindowInfosListener_test.cpp @@ -18,61 +18,61 @@ #include #include #include -#include "utils/TransactionUtils.h" namespace android { using Transaction = SurfaceComposerClient::Transaction; using gui::DisplayInfo; using gui::WindowInfo; +using WindowInfosPredicate = std::function&)>; + class WindowInfosListenerTest : public ::testing::Test { protected: void SetUp() override { seteuid(AID_SYSTEM); mClient = sp::make(); - mWindowInfosListener = sp::make(); - mClient->addWindowInfosListener(mWindowInfosListener); } - void TearDown() override { - mClient->removeWindowInfosListener(mWindowInfosListener); - seteuid(AID_ROOT); - } + void TearDown() override { seteuid(AID_ROOT); } - struct SyncWindowInfosListener : public gui::WindowInfosListener { + struct WindowInfosListener : public gui::WindowInfosListener { public: + WindowInfosListener(WindowInfosPredicate predicate, std::promise& promise) + : mPredicate(std::move(predicate)), mPromise(promise) {} + void onWindowInfosChanged(const std::vector& windowInfos, const std::vector&) override { - windowInfosPromise.set_value(windowInfos); - } - - std::vector waitForWindowInfos() { - std::future> windowInfosFuture = - windowInfosPromise.get_future(); - std::vector windowInfos = windowInfosFuture.get(); - windowInfosPromise = std::promise>(); - return windowInfos; + if (mPredicate(windowInfos)) { + mPromise.set_value(); + } } private: - std::promise> windowInfosPromise; + WindowInfosPredicate mPredicate; + std::promise& mPromise; }; sp mClient; - sp mWindowInfosListener; + + bool waitForWindowInfosPredicate(WindowInfosPredicate predicate) { + std::promise promise; + auto listener = sp::make(std::move(predicate), promise); + mClient->addWindowInfosListener(listener); + auto future = promise.get_future(); + bool satisfied = future.wait_for(std::chrono::seconds{1}) == std::future_status::ready; + mClient->removeWindowInfosListener(listener); + return satisfied; + } }; std::optional findMatchingWindowInfo(WindowInfo targetWindowInfo, std::vector windowInfos) { - std::optional foundWindowInfo = std::nullopt; for (WindowInfo windowInfo : windowInfos) { if (windowInfo.token == targetWindowInfo.token) { - foundWindowInfo = std::make_optional<>(windowInfo); - break; + return windowInfo; } } - - return foundWindowInfo; + return std::nullopt; } TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { @@ -92,15 +92,17 @@ TEST_F(WindowInfosListenerTest, WindowInfoAddedAndRemoved) { .setInputWindowInfo(surfaceControl, windowInfo) .apply(); - std::vector windowInfos = mWindowInfosListener->waitForWindowInfos(); - std::optional foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); - ASSERT_NE(std::nullopt, foundWindowInfo); + auto windowPresent = [&](const std::vector& windowInfos) { + return findMatchingWindowInfo(windowInfo, windowInfos).has_value(); + }; + ASSERT_TRUE(waitForWindowInfosPredicate(windowPresent)); Transaction().reparent(surfaceControl, nullptr).apply(); - windowInfos = mWindowInfosListener->waitForWindowInfos(); - foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); - ASSERT_EQ(std::nullopt, foundWindowInfo); + auto windowNotPresent = [&](const std::vector& windowInfos) { + return !findMatchingWindowInfo(windowInfo, windowInfos).has_value(); + }; + ASSERT_TRUE(waitForWindowInfosPredicate(windowNotPresent)); } TEST_F(WindowInfosListenerTest, WindowInfoChanged) { @@ -121,19 +123,28 @@ TEST_F(WindowInfosListenerTest, WindowInfoChanged) { .setInputWindowInfo(surfaceControl, windowInfo) .apply(); - std::vector windowInfos = mWindowInfosListener->waitForWindowInfos(); - std::optional foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); - ASSERT_NE(std::nullopt, foundWindowInfo); - ASSERT_TRUE(foundWindowInfo->touchableRegion.isEmpty()); + auto windowIsPresentAndTouchableRegionEmpty = [&](const std::vector& windowInfos) { + auto foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); + if (!foundWindowInfo) { + return false; + } + return foundWindowInfo->touchableRegion.isEmpty(); + }; + ASSERT_TRUE(waitForWindowInfosPredicate(windowIsPresentAndTouchableRegionEmpty)); Rect touchableRegions(0, 0, 50, 50); windowInfo.addTouchableRegion(Rect(0, 0, 50, 50)); Transaction().setInputWindowInfo(surfaceControl, windowInfo).apply(); - windowInfos = mWindowInfosListener->waitForWindowInfos(); - foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); - ASSERT_NE(std::nullopt, foundWindowInfo); - ASSERT_TRUE(foundWindowInfo->touchableRegion.hasSameRects(windowInfo.touchableRegion)); + auto windowIsPresentAndTouchableRegionMatches = + [&](const std::vector& windowInfos) { + auto foundWindowInfo = findMatchingWindowInfo(windowInfo, windowInfos); + if (!foundWindowInfo) { + return false; + } + return foundWindowInfo->touchableRegion.hasSameRects(windowInfo.touchableRegion); + }; + ASSERT_TRUE(waitForWindowInfosPredicate(windowIsPresentAndTouchableRegionMatches)); } } // namespace android -- GitLab From 283c64b190e74e63064524f6eb598654cbe98f4c Mon Sep 17 00:00:00 2001 From: Dichen Zhang Date: Wed, 22 Feb 2023 18:50:13 +0000 Subject: [PATCH 0027/1187] jpegr library: add multi-picture format support test: jpegr_test bug: b/264715926 Change-Id: I1bd299ddc0435e54f7c8554b92b3cd6eb2f6eb2b --- libs/jpegrecoverymap/Android.bp | 2 + .../include/jpegrecoverymap/jpegrutils.h | 65 ++++++-- .../jpegrecoverymap/multipictureformat.h | 76 +++++++++ libs/jpegrecoverymap/jpegr.cpp | 149 ++++++++++++------ libs/jpegrecoverymap/jpegrutils.cpp | 137 ++++++++++++---- libs/jpegrecoverymap/multipictureformat.cpp | 94 +++++++++++ libs/jpegrecoverymap/tests/Android.bp | 1 + libs/jpegrecoverymap/tests/jpegr_test.cpp | 19 ++- 8 files changed, 448 insertions(+), 95 deletions(-) create mode 100644 libs/jpegrecoverymap/include/jpegrecoverymap/multipictureformat.h create mode 100644 libs/jpegrecoverymap/multipictureformat.cpp diff --git a/libs/jpegrecoverymap/Android.bp b/libs/jpegrecoverymap/Android.bp index 78d1912d24..0c03ede9e8 100644 --- a/libs/jpegrecoverymap/Android.bp +++ b/libs/jpegrecoverymap/Android.bp @@ -32,6 +32,7 @@ cc_library { "jpegr.cpp", "recoverymapmath.cpp", "jpegrutils.cpp", + "multipictureformat.cpp", ], shared_libs: [ @@ -40,6 +41,7 @@ cc_library { "libjpegencoder", "libjpegdecoder", "liblog", + "libutils", ], static_libs: ["libskia"], diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h index 581806c54e..41458532b9 100644 --- a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h +++ b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h @@ -18,6 +18,7 @@ #define ANDROID_JPEGRECOVERYMAP_JPEGRUTILS_H #include +#include #include #include @@ -27,6 +28,26 @@ namespace android::jpegrecoverymap { struct jpegr_metadata; +/* + * Mutable data structure. Holds information for metadata. + */ +class DataStruct : public RefBase { +private: + void* data; + int writePos; + int length; + ~DataStruct(); + +public: + DataStruct(int s); + void* getData(); + int getLength(); + int getBytesWritten(); + bool write8(uint8_t value); + bool write16(uint16_t value); + bool write32(uint32_t value); + bool write(const void* src, int size); +}; /* * Helper function used for writing data to destination. @@ -51,12 +72,10 @@ status_t Write(jr_compressed_ptr destination, const void* source, size_t length, bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* metadata); /* - * This method generates XMP metadata. + * This method generates XMP metadata for the primary image. * * below is an example of the XMP metadata that this function generates where * secondary_image_length = 1000 - * max_content_boost = 8.0 - * min_content_boost = 0.5 * * * + * xmlns:Item="http://ns.google.com/photos/1.0/container/item/"> * * * @@ -78,10 +96,7 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* meta * + * Item:Length="1000"/> * * * @@ -90,10 +105,40 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* meta * * * @param secondary_image_length length of secondary image + * @return XMP metadata in type of string + */ +std::string generateXmpForPrimaryImage(int secondary_image_length); + +/* + * This method generates XMP metadata for the recovery map image. + * + * below is an example of the XMP metadata that this function generates where + * max_content_boost = 8.0 + * min_content_boost = 0.5 + * + * + * + * + * + * + * * @param metadata JPEG/R metadata to encode as XMP * @return XMP metadata in type of string */ -std::string generateXmp(int secondary_image_length, jpegr_metadata& metadata); + std::string generateXmpForSecondaryImage(jpegr_metadata& metadata); } // namespace android::jpegrecoverymap #endif //ANDROID_JPEGRECOVERYMAP_JPEGRUTILS_H diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/multipictureformat.h b/libs/jpegrecoverymap/include/jpegrecoverymap/multipictureformat.h new file mode 100644 index 0000000000..7dca91637e --- /dev/null +++ b/libs/jpegrecoverymap/include/jpegrecoverymap/multipictureformat.h @@ -0,0 +1,76 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_JPEGRECOVERYMAP_MULTIPICTUREFORMAT_H +#define ANDROID_JPEGRECOVERYMAP_MULTIPICTUREFORMAT_H + +#include + +namespace android::jpegrecoverymap { +static constexpr uint32_t EndianSwap32(uint32_t value) { + return ((value & 0xFF) << 24) | + ((value & 0xFF00) << 8) | + ((value & 0xFF0000) >> 8) | + (value >> 24); +} +static inline uint16_t EndianSwap16(uint16_t value) { + return static_cast((value >> 8) | ((value & 0xFF) << 8)); +} +#define USE_BIG_ENDIAN true +#if USE_BIG_ENDIAN + #define Endian_SwapBE32(n) EndianSwap32(n) + #define Endian_SwapBE16(n) EndianSwap16(n) +#else + #define Endian_SwapBE32(n) (n) + #define Endian_SwapBE16(n) (n) +#endif + +constexpr size_t kNumPictures = 2; +constexpr size_t kMpEndianSize = 4; +constexpr uint16_t kTagSerializedCount = 3; +constexpr uint32_t kTagSize = 12; + +constexpr uint16_t kTypeLong = 0x4; +constexpr uint16_t kTypeUndefined = 0x7; + +static constexpr uint8_t kMpfSig[] = {'M', 'P', 'F', '\0'}; +constexpr uint8_t kMpLittleEndian[kMpEndianSize] = {0x49, 0x49, 0x2A, 0x00}; +constexpr uint8_t kMpBigEndian[kMpEndianSize] = {0x4D, 0x4D, 0x00, 0x2A}; + +constexpr uint16_t kVersionTag = 0xB000; +constexpr uint16_t kVersionType = kTypeUndefined; +constexpr uint32_t kVersionCount = 4; +constexpr size_t kVersionSize = 4; +constexpr uint8_t kVersionExpected[kVersionSize] = {'0', '1', '0', '0'}; + +constexpr uint16_t kNumberOfImagesTag = 0xB001; +constexpr uint16_t kNumberOfImagesType = kTypeLong; +constexpr uint32_t kNumberOfImagesCount = 1; + +constexpr uint16_t kMPEntryTag = 0xB002; +constexpr uint16_t kMPEntryType = kTypeUndefined; +constexpr uint32_t kMPEntrySize = 16; + +constexpr uint32_t kMPEntryAttributeFormatJpeg = 0x0000000; +constexpr uint32_t kMPEntryAttributeTypePrimary = 0x030000; + +size_t calculateMpfSize(); +sp generateMpf(int primary_image_size, int primary_image_offset, + int secondary_image_size, int secondary_image_offset); + +} // namespace android::jpegrecoverymap + +#endif //ANDROID_JPEGRECOVERYMAP_MULTIPICTUREFORMAT_H diff --git a/libs/jpegrecoverymap/jpegr.cpp b/libs/jpegrecoverymap/jpegr.cpp index 828af2d289..09a4315480 100644 --- a/libs/jpegrecoverymap/jpegr.cpp +++ b/libs/jpegrecoverymap/jpegr.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -105,10 +106,10 @@ static const map< /* Encode API-0 */ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, - jpegr_transfer_function hdr_tf, - jr_compressed_ptr dest, - int quality, - jr_exif_ptr exif) { + jpegr_transfer_function hdr_tf, + jr_compressed_ptr dest, + int quality, + jr_exif_ptr exif) { if (uncompressed_p010_image == nullptr || dest == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } @@ -167,11 +168,11 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, /* Encode API-1 */ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, - jr_uncompressed_ptr uncompressed_yuv_420_image, - jpegr_transfer_function hdr_tf, - jr_compressed_ptr dest, - int quality, - jr_exif_ptr exif) { + jr_uncompressed_ptr uncompressed_yuv_420_image, + jpegr_transfer_function hdr_tf, + jr_compressed_ptr dest, + int quality, + jr_exif_ptr exif) { if (uncompressed_p010_image == nullptr || uncompressed_yuv_420_image == nullptr || dest == nullptr) { @@ -231,10 +232,10 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, /* Encode API-2 */ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, - jr_uncompressed_ptr uncompressed_yuv_420_image, - jr_compressed_ptr compressed_jpeg_image, - jpegr_transfer_function hdr_tf, - jr_compressed_ptr dest) { + jr_uncompressed_ptr uncompressed_yuv_420_image, + jr_compressed_ptr compressed_jpeg_image, + jpegr_transfer_function hdr_tf, + jr_compressed_ptr dest) { if (uncompressed_p010_image == nullptr || uncompressed_yuv_420_image == nullptr || compressed_jpeg_image == nullptr @@ -276,9 +277,9 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, /* Encode API-3 */ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, - jr_compressed_ptr compressed_jpeg_image, - jpegr_transfer_function hdr_tf, - jr_compressed_ptr dest) { + jr_compressed_ptr compressed_jpeg_image, + jpegr_transfer_function hdr_tf, + jr_compressed_ptr dest) { if (uncompressed_p010_image == nullptr || compressed_jpeg_image == nullptr || dest == nullptr) { @@ -327,8 +328,7 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, return NO_ERROR; } -status_t JpegR::getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image, - jr_info_ptr jpegr_info) { +status_t JpegR::getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image, jr_info_ptr jpegr_info) { if (compressed_jpegr_image == nullptr || jpegr_info == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } @@ -349,9 +349,9 @@ status_t JpegR::getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image, /* Decode API */ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, - jr_uncompressed_ptr dest, - jr_exif_ptr exif, - bool request_sdr) { + jr_uncompressed_ptr dest, + jr_exif_ptr exif, + bool request_sdr) { if (compressed_jpegr_image == nullptr || dest == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } @@ -399,8 +399,8 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, uncompressed_yuv_420_image.width = jpeg_decoder.getDecompressedImageWidth(); uncompressed_yuv_420_image.height = jpeg_decoder.getDecompressedImageHeight(); - if (!getMetadataFromXMP(static_cast(jpeg_decoder.getXMPPtr()), - jpeg_decoder.getXMPSize(), &metadata)) { + if (!getMetadataFromXMP(static_cast(recovery_map_decoder.getXMPPtr()), + recovery_map_decoder.getXMPSize(), &metadata)) { return ERROR_JPEGR_DECODE_ERROR; } @@ -409,7 +409,7 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, } status_t JpegR::compressRecoveryMap(jr_uncompressed_ptr uncompressed_recovery_map, - jr_compressed_ptr dest) { + jr_compressed_ptr dest) { if (uncompressed_recovery_map == nullptr || dest == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } @@ -493,10 +493,10 @@ void JobQueue::reset() { } status_t JpegR::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image, - jr_uncompressed_ptr uncompressed_p010_image, - jpegr_transfer_function hdr_tf, - jr_metadata_ptr metadata, - jr_uncompressed_ptr dest) { + jr_uncompressed_ptr uncompressed_p010_image, + jpegr_transfer_function hdr_tf, + jr_metadata_ptr metadata, + jr_uncompressed_ptr dest) { if (uncompressed_yuv_420_image == nullptr || uncompressed_p010_image == nullptr || metadata == nullptr @@ -637,9 +637,9 @@ status_t JpegR::generateRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_ima } status_t JpegR::applyRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image, - jr_uncompressed_ptr uncompressed_recovery_map, - jr_metadata_ptr metadata, - jr_uncompressed_ptr dest) { + jr_uncompressed_ptr uncompressed_recovery_map, + jr_metadata_ptr metadata, + jr_uncompressed_ptr dest) { if (uncompressed_yuv_420_image == nullptr || uncompressed_recovery_map == nullptr || metadata == nullptr @@ -721,8 +721,8 @@ status_t JpegR::applyRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image, } status_t JpegR::extractPrimaryImageAndRecoveryMap(jr_compressed_ptr compressed_jpegr_image, - jr_compressed_ptr primary_image, - jr_compressed_ptr recovery_map) { + jr_compressed_ptr primary_image, + jr_compressed_ptr recovery_map) { if (compressed_jpegr_image == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } @@ -771,7 +771,7 @@ status_t JpegR::extractPrimaryImageAndRecoveryMap(jr_compressed_ptr compressed_j status_t JpegR::extractRecoveryMap(jr_compressed_ptr compressed_jpegr_image, - jr_compressed_ptr dest) { + jr_compressed_ptr dest) { if (compressed_jpegr_image == nullptr || dest == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } @@ -790,11 +790,22 @@ status_t JpegR::extractRecoveryMap(jr_compressed_ptr compressed_jpegr_image, // (Required, XMP package) APP1 (ff e1) // 2 bytes of length (2 + 29 + length of xmp package) // name space ("http://ns.adobe.com/xap/1.0/\0") -// xmp +// XMP +// +// (Required, MPF package) APP2 (ff e2) +// 2 bytes of length +// MPF // // (Required) primary image (without the first two bytes (SOI), may have other packages) // -// (Required) secondary image (the recovery map) +// SOI (ff d8) +// +// (Required, XMP package) APP1 (ff e1) +// 2 bytes of length (2 + 29 + length of xmp package) +// name space ("http://ns.adobe.com/xap/1.0/\0") +// XMP +// +// (Required) secondary image (the recovery map, without the first two bytes (SOI)) // // Metadata versions we are using: // ECMA TR-98 for JFIF marker @@ -802,10 +813,10 @@ status_t JpegR::extractRecoveryMap(jr_compressed_ptr compressed_jpegr_image, // Adobe XMP spec part 3 for XMP marker // ICC v4.3 spec for ICC status_t JpegR::appendRecoveryMap(jr_compressed_ptr compressed_jpeg_image, - jr_compressed_ptr compressed_recovery_map, - jr_exif_ptr exif, - jr_metadata_ptr metadata, - jr_compressed_ptr dest) { + jr_compressed_ptr compressed_recovery_map, + jr_exif_ptr exif, + jr_metadata_ptr metadata, + jr_compressed_ptr dest) { if (compressed_jpeg_image == nullptr || compressed_recovery_map == nullptr || metadata == nullptr @@ -815,6 +826,10 @@ status_t JpegR::appendRecoveryMap(jr_compressed_ptr compressed_jpeg_image, int pos = 0; + const string xmp_primary = generateXmpForPrimaryImage(compressed_recovery_map->length); + const string xmp_secondary = generateXmpForSecondaryImage(*metadata); + + // Begin primary image // Write SOI JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos)); JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kSOI, 1, pos)); @@ -833,13 +848,12 @@ status_t JpegR::appendRecoveryMap(jr_compressed_ptr compressed_jpeg_image, // Prepare and write XMP { - const string xmp = generateXmp(compressed_recovery_map->length, *metadata); const string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator // 2 bytes: representing the length of the package // 29 bytes: length of name space "http://ns.adobe.com/xap/1.0/\0", // x bytes: length of xmp packet - const int length = 2 + nameSpaceLength + xmp.size(); + const int length = 2 + nameSpaceLength + xmp_primary.size(); const uint8_t lengthH = ((length >> 8) & 0xff); const uint8_t lengthL = (length & 0xff); JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos)); @@ -847,15 +861,59 @@ status_t JpegR::appendRecoveryMap(jr_compressed_ptr compressed_jpeg_image, JPEGR_CHECK(Write(dest, &lengthH, 1, pos)); JPEGR_CHECK(Write(dest, &lengthL, 1, pos)); JPEGR_CHECK(Write(dest, (void*)nameSpace.c_str(), nameSpaceLength, pos)); - JPEGR_CHECK(Write(dest, (void*)xmp.c_str(), xmp.size(), pos)); + JPEGR_CHECK(Write(dest, (void*)xmp_primary.c_str(), xmp_primary.size(), pos)); + } + + // Prepare and write MPF + { + const int length = 2 + calculateMpfSize(); + const uint8_t lengthH = ((length >> 8) & 0xff); + const uint8_t lengthL = (length & 0xff); + int primary_image_size = pos + length + compressed_jpeg_image->length; + int secondary_image_offset = primary_image_size; + int secondary_image_size = xmp_secondary.size() + compressed_recovery_map->length; + sp mpf = generateMpf(0, /* primary_image_offset */ + primary_image_size, + secondary_image_offset, + secondary_image_size); + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos)); + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP2, 1, pos)); + JPEGR_CHECK(Write(dest, &lengthH, 1, pos)); + JPEGR_CHECK(Write(dest, &lengthL, 1, pos)); + JPEGR_CHECK(Write(dest, (void*)mpf->getData(), mpf->getLength(), pos)); } // Write primary image JPEGR_CHECK(Write(dest, (uint8_t*)compressed_jpeg_image->data + 2, compressed_jpeg_image->length - 2, pos)); + // Finish primary image + + // Begin secondary image (recovery map) + // Write SOI + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos)); + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kSOI, 1, pos)); + + // Prepare and write XMP + { + const string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; + const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator + // 2 bytes: representing the length of the package + // 29 bytes: length of name space "http://ns.adobe.com/xap/1.0/\0", + // x bytes: length of xmp packet + const int length = 2 + nameSpaceLength + xmp_secondary.size(); + const uint8_t lengthH = ((length >> 8) & 0xff); + const uint8_t lengthL = (length & 0xff); + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos)); + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP1, 1, pos)); + JPEGR_CHECK(Write(dest, &lengthH, 1, pos)); + JPEGR_CHECK(Write(dest, &lengthL, 1, pos)); + JPEGR_CHECK(Write(dest, (void*)nameSpace.c_str(), nameSpaceLength, pos)); + JPEGR_CHECK(Write(dest, (void*)xmp_secondary.c_str(), xmp_secondary.size(), pos)); + } // Write secondary image - JPEGR_CHECK(Write(dest, compressed_recovery_map->data, compressed_recovery_map->length, pos)); + JPEGR_CHECK(Write(dest, + (uint8_t*)compressed_recovery_map->data + 2, compressed_recovery_map->length - 2, pos)); // Set back length dest->length = pos; @@ -864,8 +922,7 @@ status_t JpegR::appendRecoveryMap(jr_compressed_ptr compressed_jpeg_image, return NO_ERROR; } -status_t JpegR::toneMap(jr_uncompressed_ptr src, - jr_uncompressed_ptr dest) { +status_t JpegR::toneMap(jr_uncompressed_ptr src, jr_uncompressed_ptr dest) { if (src == nullptr || dest == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } diff --git a/libs/jpegrecoverymap/jpegrutils.cpp b/libs/jpegrecoverymap/jpegrutils.cpp index 49526c800f..38b78ad19c 100644 --- a/libs/jpegrecoverymap/jpegrutils.cpp +++ b/libs/jpegrecoverymap/jpegrutils.cpp @@ -15,18 +15,19 @@ */ #include +#include #include #include #include #include #include #include +#include using namespace photos_editing_formats::image_io; using namespace std; namespace android::jpegrecoverymap { - /* * Helper function used for generating XMP metadata. * @@ -34,12 +35,62 @@ namespace android::jpegrecoverymap { * @param suffix The suffix part of the name. * @return A name of the form "prefix:suffix". */ -string Name(const string &prefix, const string &suffix) { +static inline string Name(const string &prefix, const string &suffix) { std::stringstream ss; ss << prefix << ":" << suffix; return ss.str(); } +DataStruct::DataStruct(int s) { + data = malloc(s); + length = s; + memset(data, 0, s); + writePos = 0; +} + +DataStruct::~DataStruct() { + if (data != nullptr) { + free(data); + } +} + +void* DataStruct::getData() { + return data; +} + +int DataStruct::getLength() { + return length; +} + +int DataStruct::getBytesWritten() { + return writePos; +} + +bool DataStruct::write8(uint8_t value) { + uint8_t v = value; + return write(&v, 1); +} + +bool DataStruct::write16(uint16_t value) { + uint16_t v = value; + return write(&v, 2); +} +bool DataStruct::write32(uint32_t value) { + uint32_t v = value; + return write(&v, 4); +} + +bool DataStruct::write(const void* src, int size) { + if (writePos + size > length) { + ALOGE("Writing out of boundary: write position: %d, size: %d, capacity: %d", + writePos, size, length); + return false; + } + memcpy((uint8_t*) data + writePos, src, size); + writePos += size; + return true; +} + /* * Helper function used for writing data to destination. */ @@ -58,7 +109,7 @@ class XMPXmlHandler : public XmlHandler { public: XMPXmlHandler() : XmlHandler() { - gContainerItemState = NotStrarted; + state = NotStrarted; } enum ParseState { @@ -70,11 +121,11 @@ public: virtual DataMatchResult StartElement(const XmlTokenContext& context) { string val; if (context.BuildTokenValue(&val)) { - if (!val.compare(gContainerItemName)) { - gContainerItemState = Started; + if (!val.compare(containerName)) { + state = Started; } else { - if (gContainerItemState != Done) { - gContainerItemState = NotStrarted; + if (state != Done) { + state = NotStrarted; } } } @@ -82,8 +133,8 @@ public: } virtual DataMatchResult FinishElement(const XmlTokenContext& context) { - if (gContainerItemState == Started) { - gContainerItemState = Done; + if (state == Started) { + state = Done; lastAttributeName = ""; } return context.GetResult(); @@ -91,7 +142,7 @@ public: virtual DataMatchResult AttributeName(const XmlTokenContext& context) { string val; - if (gContainerItemState == Started) { + if (state == Started) { if (context.BuildTokenValue(&val)) { if (!val.compare(maxContentBoostAttrName)) { lastAttributeName = maxContentBoostAttrName; @@ -107,7 +158,7 @@ public: virtual DataMatchResult AttributeValue(const XmlTokenContext& context) { string val; - if (gContainerItemState == Started) { + if (state == Started) { if (context.BuildTokenValue(&val, true)) { if (!lastAttributeName.compare(maxContentBoostAttrName)) { maxContentBoostStr = val; @@ -120,11 +171,11 @@ public: } bool getMaxContentBoost(float* max_content_boost) { - if (gContainerItemState == Done) { + if (state == Done) { stringstream ss(maxContentBoostStr); float val; if (ss >> val) { - *max_content_boost = val; + *max_content_boost = exp2(val); return true; } else { return false; @@ -135,11 +186,11 @@ public: } bool getMinContentBoost(float* min_content_boost) { - if (gContainerItemState == Done) { + if (state == Done) { stringstream ss(minContentBoostStr); float val; if (ss >> val) { - *min_content_boost = val; + *min_content_boost = exp2(val); return true; } else { return false; @@ -150,13 +201,13 @@ public: } private: - static const string gContainerItemName; + static const string containerName; static const string maxContentBoostAttrName; string maxContentBoostStr; static const string minContentBoostAttrName; string minContentBoostStr; string lastAttributeName; - ParseState gContainerItemState; + ParseState state; }; // GContainer XMP constants - URI and namespace prefix @@ -168,8 +219,7 @@ const string kConDirectory = Name(kContainerPrefix, "Directory"); const string kConItem = Name(kContainerPrefix, "Item"); // GContainer XMP constants - names for XMP handlers -const string XMPXmlHandler::gContainerItemName = kConItem; - +const string XMPXmlHandler::containerName = "rdf:Description"; // Item XMP constants - URI and namespace prefix const string kItemUri = "http://ns.google.com/photos/1.0/container/item/"; const string kItemPrefix = "Item"; @@ -185,17 +235,23 @@ const string kSemanticRecoveryMap = "RecoveryMap"; const string kMimeImageJpeg = "image/jpeg"; // RecoveryMap XMP constants - URI and namespace prefix -const string kRecoveryMapUri = "http://ns.google.com/photos/1.0/recoverymap/"; -const string kRecoveryMapPrefix = "RecoveryMap"; +const string kRecoveryMapUri = "http://ns.adobe.com/hdr-gain-map/1.0/"; +const string kRecoveryMapPrefix = "hdrgm"; // RecoveryMap XMP constants - element and attribute names -const string kMapMaxContentBoost = Name(kRecoveryMapPrefix, "MaxContentBoost"); -const string kMapMinContentBoost = Name(kRecoveryMapPrefix, "MinContentBoost"); const string kMapVersion = Name(kRecoveryMapPrefix, "Version"); +const string kMapGainMapMin = Name(kRecoveryMapPrefix, "GainMapMin"); +const string kMapGainMapMax = Name(kRecoveryMapPrefix, "GainMapMax"); +const string kMapGamma = Name(kRecoveryMapPrefix, "Gamma"); +const string kMapOffsetSdr = Name(kRecoveryMapPrefix, "OffsetSDR"); +const string kMapOffsetHdr = Name(kRecoveryMapPrefix, "OffsetHDR"); +const string kMapHDRCapacityMin = Name(kRecoveryMapPrefix, "HDRCapacityMin"); +const string kMapHDRCapacityMax = Name(kRecoveryMapPrefix, "HDRCapacityMax"); +const string kMapBaseRendition = Name(kRecoveryMapPrefix, "BaseRendition"); // RecoveryMap XMP constants - names for XMP handlers -const string XMPXmlHandler::maxContentBoostAttrName = kMapMaxContentBoost; -const string XMPXmlHandler::minContentBoostAttrName = kMapMinContentBoost; +const string XMPXmlHandler::minContentBoostAttrName = kMapGainMapMin; +const string XMPXmlHandler::maxContentBoostAttrName = kMapGainMapMax; bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* metadata) { string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; @@ -243,7 +299,7 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata* meta return true; } -string generateXmp(int secondary_image_length, jpegr_metadata& metadata) { +string generateXmpForPrimaryImage(int secondary_image_length) { const vector kConDirSeq({kConDirectory, string("rdf:Seq")}); const vector kLiItem({string("rdf:li"), kConItem}); @@ -257,7 +313,6 @@ string generateXmp(int secondary_image_length, jpegr_metadata& metadata) { writer.StartWritingElement("rdf:Description"); writer.WriteXmlns(kContainerPrefix, kContainerUri); writer.WriteXmlns(kItemPrefix, kItemUri); - writer.WriteXmlns(kRecoveryMapPrefix, kRecoveryMapUri); writer.StartWritingElements(kConDirSeq); size_t item_depth = writer.StartWritingElements(kLiItem); writer.WriteAttributeNameAndValue(kItemSemantic, kSemanticPrimary); @@ -267,9 +322,33 @@ string generateXmp(int secondary_image_length, jpegr_metadata& metadata) { writer.WriteAttributeNameAndValue(kItemSemantic, kSemanticRecoveryMap); writer.WriteAttributeNameAndValue(kItemMime, kMimeImageJpeg); writer.WriteAttributeNameAndValue(kItemLength, secondary_image_length); + writer.FinishWriting(); + + return ss.str(); +} + +string generateXmpForSecondaryImage(jpegr_metadata& metadata) { + const vector kConDirSeq({kConDirectory, string("rdf:Seq")}); + const vector kLiItem({string("rdf:li"), kConItem}); + + std::stringstream ss; + photos_editing_formats::image_io::XmlWriter writer(ss); + writer.StartWritingElement("x:xmpmeta"); + writer.WriteXmlns("x", "adobe:ns:meta/"); + writer.WriteAttributeNameAndValue("x:xmptk", "Adobe XMP Core 5.1.2"); + writer.StartWritingElement("rdf:RDF"); + writer.WriteXmlns("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + writer.StartWritingElement("rdf:Description"); + writer.WriteXmlns(kRecoveryMapPrefix, kRecoveryMapUri); writer.WriteAttributeNameAndValue(kMapVersion, metadata.version); - writer.WriteAttributeNameAndValue(kMapMaxContentBoost, metadata.maxContentBoost); - writer.WriteAttributeNameAndValue(kMapMinContentBoost, metadata.minContentBoost); + writer.WriteAttributeNameAndValue(kMapGainMapMin, log2(metadata.minContentBoost)); + writer.WriteAttributeNameAndValue(kMapGainMapMax, log2(metadata.maxContentBoost)); + writer.WriteAttributeNameAndValue(kMapGamma, "1"); + writer.WriteAttributeNameAndValue(kMapOffsetSdr, "0"); + writer.WriteAttributeNameAndValue(kMapOffsetHdr, "0"); + writer.WriteAttributeNameAndValue(kMapHDRCapacityMin, "0"); + writer.WriteAttributeNameAndValue(kMapHDRCapacityMax, "2.3"); + writer.WriteAttributeNameAndValue(kMapBaseRendition, "SDR"); writer.FinishWriting(); return ss.str(); diff --git a/libs/jpegrecoverymap/multipictureformat.cpp b/libs/jpegrecoverymap/multipictureformat.cpp new file mode 100644 index 0000000000..a219aef106 --- /dev/null +++ b/libs/jpegrecoverymap/multipictureformat.cpp @@ -0,0 +1,94 @@ +/* + * Copyright 2023 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 +#include + +namespace android::jpegrecoverymap { +size_t calculateMpfSize() { + return sizeof(kMpfSig) + // Signature + kMpEndianSize + // Endianness + sizeof(uint32_t) + // Index IFD Offset + sizeof(uint16_t) + // Tag count + kTagSerializedCount * kTagSize + // 3 tags at 12 bytes each + sizeof(uint32_t) + // Attribute IFD offset + kNumPictures * kMPEntrySize; // MP Entries for each image +} + +sp generateMpf(int primary_image_size, int primary_image_offset, + int secondary_image_size, int secondary_image_offset) { + size_t mpf_size = calculateMpfSize(); + sp dataStruct = new DataStruct(mpf_size); + + dataStruct->write(static_cast(kMpfSig), sizeof(kMpfSig)); +#if USE_BIG_ENDIAN + dataStruct->write(static_cast(kMpBigEndian), kMpEndianSize); +#else + dataStruct->write(static_cast(kMpLittleEndian), kMpEndianSize); +#endif + + // Set the Index IFD offset be the position after the endianness value and this offset. + constexpr uint32_t indexIfdOffset = + static_cast(kMpEndianSize + sizeof(kMpfSig)); + dataStruct->write32(Endian_SwapBE32(indexIfdOffset)); + + // We will write 3 tags (version, number of images, MP entries). + dataStruct->write16(Endian_SwapBE16(kTagSerializedCount)); + + // Write the version tag. + dataStruct->write16(Endian_SwapBE16(kVersionTag)); + dataStruct->write16(Endian_SwapBE16(kVersionType)); + dataStruct->write32(Endian_SwapBE32(kVersionCount)); + dataStruct->write(kVersionExpected, kVersionSize); + + // Write the number of images. + dataStruct->write16(Endian_SwapBE16(kNumberOfImagesTag)); + dataStruct->write16(Endian_SwapBE16(kNumberOfImagesType)); + dataStruct->write32(Endian_SwapBE32(kNumberOfImagesCount)); + dataStruct->write32(Endian_SwapBE32(kNumPictures)); + + // Write the MP entries. + dataStruct->write16(Endian_SwapBE16(kMPEntryTag)); + dataStruct->write16(Endian_SwapBE16(kMPEntryType)); + dataStruct->write32(Endian_SwapBE32(kMPEntrySize * kNumPictures)); + const uint32_t mpEntryOffset = + static_cast(dataStruct->getBytesWritten() - // The bytes written so far + sizeof(kMpfSig) + // Excluding the MPF signature + sizeof(uint32_t) + // The 4 bytes for this offset + sizeof(uint32_t)); // The 4 bytes for the attribute IFD offset. + dataStruct->write32(Endian_SwapBE32(mpEntryOffset)); + + // Write the attribute IFD offset (zero because we don't write it). + dataStruct->write32(0); + + // Write the MP entries for primary image + dataStruct->write32( + Endian_SwapBE32(kMPEntryAttributeFormatJpeg | kMPEntryAttributeTypePrimary)); + dataStruct->write32(Endian_SwapBE32(primary_image_size)); + dataStruct->write32(Endian_SwapBE32(primary_image_offset)); + dataStruct->write16(0); + dataStruct->write16(0); + + // Write the MP entries for secondary image + dataStruct->write32(Endian_SwapBE32(kMPEntryAttributeFormatJpeg)); + dataStruct->write32(Endian_SwapBE32(secondary_image_size)); + dataStruct->write32(Endian_SwapBE32(secondary_image_offset)); + dataStruct->write16(0); + dataStruct->write16(0); + + return dataStruct; +} + +} // namespace android::jpegrecoverymap diff --git a/libs/jpegrecoverymap/tests/Android.bp b/libs/jpegrecoverymap/tests/Android.bp index 5a4edb2a25..61b3db9c62 100644 --- a/libs/jpegrecoverymap/tests/Android.bp +++ b/libs/jpegrecoverymap/tests/Android.bp @@ -40,6 +40,7 @@ cc_test { "libjpegencoder", "libjpegrecoverymap", "libskia", + "libutils", ], } diff --git a/libs/jpegrecoverymap/tests/jpegr_test.cpp b/libs/jpegrecoverymap/tests/jpegr_test.cpp index 7a3133d10c..df212e1fb1 100644 --- a/libs/jpegrecoverymap/tests/jpegr_test.cpp +++ b/libs/jpegrecoverymap/tests/jpegr_test.cpp @@ -177,11 +177,10 @@ TEST_F(JpegRTest, writeXmpThenRead) { jpegr_metadata metadata_expected; metadata_expected.maxContentBoost = 1.25; metadata_expected.minContentBoost = 0.75; - int length_expected = 1000; const std::string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator - std::string xmp = generateXmp(1000, metadata_expected); + std::string xmp = generateXmpForSecondaryImage(metadata_expected); std::vector xmpData; xmpData.reserve(nameSpaceLength + xmp.size()); @@ -220,7 +219,7 @@ TEST_F(JpegRTest, encodeFromP010ThenDecode) { } if (SAVE_ENCODING_RESULT) { // Output image data to file - std::string filePath = "/sdcard/Documents/encoded_from_jpeg_input.jpgr"; + std::string filePath = "/sdcard/Documents/encoded_from_p010_input.jpgr"; std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); if (!imageFile.is_open()) { ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); @@ -237,7 +236,7 @@ TEST_F(JpegRTest, encodeFromP010ThenDecode) { } if (SAVE_DECODING_RESULT) { // Output image data to file - std::string filePath = "/sdcard/Documents/decoded_from_jpeg_input.rgb10"; + std::string filePath = "/sdcard/Documents/decoded_from_p010_input.rgb10"; std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); if (!imageFile.is_open()) { ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); @@ -281,7 +280,7 @@ TEST_F(JpegRTest, encodeFromRawHdrAndSdrThenDecode) { } if (SAVE_ENCODING_RESULT) { // Output image data to file - std::string filePath = "/sdcard/Documents/encoded_from_jpeg_input.jpgr"; + std::string filePath = "/sdcard/Documents/encoded_from_p010_yuv420p_input.jpgr"; std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); if (!imageFile.is_open()) { ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); @@ -298,7 +297,7 @@ TEST_F(JpegRTest, encodeFromRawHdrAndSdrThenDecode) { } if (SAVE_DECODING_RESULT) { // Output image data to file - std::string filePath = "/sdcard/Documents/decoded_from_jpeg_input.rgb10"; + std::string filePath = "/sdcard/Documents/decoded_from_p010_yuv420p_input.rgb10"; std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); if (!imageFile.is_open()) { ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); @@ -346,7 +345,7 @@ TEST_F(JpegRTest, encodeFromRawHdrAndSdrAndJpegThenDecode) { } if (SAVE_ENCODING_RESULT) { // Output image data to file - std::string filePath = "/sdcard/Documents/encoded_from_jpeg_input.jpgr"; + std::string filePath = "/sdcard/Documents/encoded_from_p010_yuv420p_jpeg_input.jpgr"; std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); if (!imageFile.is_open()) { ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); @@ -363,7 +362,7 @@ TEST_F(JpegRTest, encodeFromRawHdrAndSdrAndJpegThenDecode) { } if (SAVE_DECODING_RESULT) { // Output image data to file - std::string filePath = "/sdcard/Documents/decoded_from_jpeg_input.rgb10"; + std::string filePath = "/sdcard/Documents/decoded_from_p010_yuv420p_jpeg_input.rgb10"; std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); if (!imageFile.is_open()) { ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); @@ -427,7 +426,7 @@ TEST_F(JpegRTest, encodeFromJpegThenDecode) { } if (SAVE_ENCODING_RESULT) { // Output image data to file - std::string filePath = "/sdcard/Documents/encoded_from_jpeg_input.jpgr"; + std::string filePath = "/sdcard/Documents/encoded_from_p010_jpeg_input.jpgr"; std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); if (!imageFile.is_open()) { ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); @@ -444,7 +443,7 @@ TEST_F(JpegRTest, encodeFromJpegThenDecode) { } if (SAVE_DECODING_RESULT) { // Output image data to file - std::string filePath = "/sdcard/Documents/decoded_from_jpeg_input.rgb10"; + std::string filePath = "/sdcard/Documents/decoded_from_p010_jpeg_input.rgb10"; std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); if (!imageFile.is_open()) { ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); -- GitLab From ca27bff948729baaafb223c10aff42d0aa0af4a9 Mon Sep 17 00:00:00 2001 From: Arif Dikici Date: Tue, 28 Feb 2023 22:03:31 +0000 Subject: [PATCH 0028/1187] Fixing owners. Change-Id: I2d73976e110396db40381201f9c08af9ab604a4e -- GitLab From 31b7267efca029d11acfb95947fc7ab20cfc86c6 Mon Sep 17 00:00:00 2001 From: Dichen Zhang Date: Tue, 28 Feb 2023 22:17:05 +0000 Subject: [PATCH 0029/1187] Fixing owners Change-Id: I2c7c011f8b7d94df41b8dd9e1b422a24771b5233 --- libs/jpegrecoverymap/OWNERS | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/jpegrecoverymap/OWNERS b/libs/jpegrecoverymap/OWNERS index 133af5bcd4..6ace354d0b 100644 --- a/libs/jpegrecoverymap/OWNERS +++ b/libs/jpegrecoverymap/OWNERS @@ -1,4 +1,3 @@ arifdikici@google.com -deakin@google.com dichenzhang@google.com kyslov@google.com \ No newline at end of file -- GitLab From b8a5468519ed7cd34bddb9405b6385da6e2426b3 Mon Sep 17 00:00:00 2001 From: Sungtak Lee Date: Thu, 2 Feb 2023 00:57:30 +0000 Subject: [PATCH 0030/1187] OMX: Add 64bit consumer usage flag parameter Bug: 185896428 Change-Id: Ie3621e71681d81caa78409487795dec0f3173f0f --- headers/media_plugin/media/openmax/OMX_AsString.h | 1 + headers/media_plugin/media/openmax/OMX_IndexExt.h | 1 + 2 files changed, 2 insertions(+) diff --git a/headers/media_plugin/media/openmax/OMX_AsString.h b/headers/media_plugin/media/openmax/OMX_AsString.h index ce30b417e0..165a868d57 100644 --- a/headers/media_plugin/media/openmax/OMX_AsString.h +++ b/headers/media_plugin/media/openmax/OMX_AsString.h @@ -561,6 +561,7 @@ inline static const char *asString(OMX_INDEXEXTTYPE i, const char *def = "??") { case OMX_IndexConfigPriority: return "ConfigPriority"; case OMX_IndexConfigOperatingRate: return "ConfigOperatingRate"; case OMX_IndexParamConsumerUsageBits: return "ParamConsumerUsageBits"; + case OMX_IndexParamConsumerUsageBits64: return "ParamConsumerUsageBits64"; case OMX_IndexConfigLatency: return "ConfigLatency"; default: return asString((OMX_INDEXTYPE)i, def); } diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h index 0af40dd28e..5ddd719ba1 100644 --- a/headers/media_plugin/media/openmax/OMX_IndexExt.h +++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h @@ -105,6 +105,7 @@ typedef enum OMX_INDEXEXTTYPE { OMX_IndexConfigLowLatency, /**< reference: OMX_CONFIG_BOOLEANTYPE */ OMX_IndexConfigAndroidTunnelPeek, /**< reference: OMX_CONFIG_BOOLEANTYPE */ OMX_IndexConfigAndroidTunnelPeekLegacyMode, /**< reference: OMX_CONFIG_BOOLEANTYPE */ + OMX_IndexParamConsumerUsageBits64, /**< reference: OMX_PARAM_U64TYPE */ OMX_IndexExtOtherEndUnused, /* Time configurations */ -- GitLab From 9b4443faa4b9b8bf4013e85527cbd788ac109bc4 Mon Sep 17 00:00:00 2001 From: Yeabkal Wubshit Date: Thu, 23 Feb 2023 23:35:07 -0800 Subject: [PATCH 0031/1187] Remove VelocityTracker::Estimator Only the velocity info is used in the estimator. Thus, remove the struct from the cpp VelocityTracker, and all related functions. Bug: 246395861 Test: atest libinput_tests Change-Id: I1b6eecce88f0bb982da2354cbc3fb2a09a1e048d --- include/input/VelocityTracker.h | 37 +---- libs/input/VelocityTracker.cpp | 178 ++++++---------------- libs/input/tests/VelocityTracker_test.cpp | 53 +++---- 3 files changed, 76 insertions(+), 192 deletions(-) diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index da97c3e855..5a23e8dca5 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -31,6 +31,8 @@ class VelocityTrackerStrategy; */ class VelocityTracker { public: + static const size_t MAX_DEGREE = 4; + enum class Strategy : int32_t { DEFAULT = -1, MIN = 0, @@ -47,23 +49,6 @@ public: MAX = LEGACY, }; - struct Estimator { - static const size_t MAX_DEGREE = 4; - - // Estimator time base. - nsecs_t time = 0; - - // Polynomial coefficients describing motion. - std::array coeff{}; - - // Polynomial degree (number of coefficients), or zero if no information is - // available. - uint32_t degree = 0; - - // Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit). - float confidence = 0; - }; - /* * Contains all available velocity data from a VelocityTracker. */ @@ -124,11 +109,6 @@ public: // [-maxVelocity, maxVelocity], inclusive. ComputedVelocity getComputedVelocity(int32_t units, float maxVelocity); - // Gets an estimator for the recent movements of the specified pointer id for the given axis. - // Returns false and clears the estimator if there is no information available - // about the pointer. - std::optional getEstimator(int32_t axis, int32_t pointerId) const; - // Gets the active pointer id, or -1 if none. inline int32_t getActivePointerId() const { return mActivePointerId.value_or(-1); } @@ -169,7 +149,7 @@ public: virtual void clearPointer(int32_t pointerId) = 0; virtual void addMovement(nsecs_t eventTime, int32_t pointerId, float position) = 0; - virtual std::optional getEstimator(int32_t pointerId) const = 0; + virtual std::optional getVelocity(int32_t pointerId) const = 0; }; @@ -193,13 +173,13 @@ public: RECENT, }; - // Degree must be no greater than Estimator::MAX_DEGREE. + // Degree must be no greater than VelocityTracker::MAX_DEGREE. LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = Weighting::NONE); ~LeastSquaresVelocityTrackerStrategy() override; void clearPointer(int32_t pointerId) override; void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; - std::optional getEstimator(int32_t pointerId) const override; + std::optional getVelocity(int32_t pointerId) const override; private: // Sample horizon. @@ -235,7 +215,7 @@ public: void clearPointer(int32_t pointerId) override; void addMovement(nsecs_t eventTime, int32_t pointerId, float positions) override; - std::optional getEstimator(int32_t pointerId) const override; + std::optional getVelocity(int32_t pointerId) const override; private: // Current state estimate for a particular pointer. @@ -252,7 +232,6 @@ private: void initState(State& state, nsecs_t eventTime, float pos) const; void updateState(State& state, nsecs_t eventTime, float pos) const; - void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const; }; @@ -266,7 +245,7 @@ public: void clearPointer(int32_t pointerId) override; void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; - std::optional getEstimator(int32_t pointerId) const override; + std::optional getVelocity(int32_t pointerId) const override; private: // Oldest sample to consider when calculating the velocity. @@ -294,7 +273,7 @@ public: void clearPointer(int32_t pointerId) override; void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; - std::optional getEstimator(int32_t pointerId) const override; + std::optional getVelocity(int32_t pointerId) const override; private: // Sample horizon. diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index 3632914b93..a88aa485fc 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -268,12 +268,8 @@ void VelocityTracker::addMovement(nsecs_t eventTime, int32_t pointerId, int32_t ", activePointerId=%s", eventTime, pointerId, toString(mActivePointerId).c_str()); - std::optional estimator = getEstimator(axis, pointerId); - ALOGD(" %d: axis=%d, position=%0.3f, " - "estimator (degree=%d, coeff=%s, confidence=%f)", - pointerId, axis, position, int((*estimator).degree), - vectorToString((*estimator).coeff.data(), (*estimator).degree + 1).c_str(), - (*estimator).confidence); + ALOGD(" %d: axis=%d, position=%0.3f, velocity=%s", pointerId, axis, position, + toString(getVelocity(axis, pointerId)).c_str()); } } @@ -349,9 +345,9 @@ void VelocityTracker::addMovement(const MotionEvent* event) { } std::optional VelocityTracker::getVelocity(int32_t axis, int32_t pointerId) const { - std::optional estimator = getEstimator(axis, pointerId); - if (estimator && (*estimator).degree >= 1) { - return (*estimator).coeff[1]; + const auto& it = mConfiguredStrategies.find(axis); + if (it != mConfiguredStrategies.end()) { + return it->second->getVelocity(pointerId); } return {}; } @@ -374,15 +370,6 @@ VelocityTracker::ComputedVelocity VelocityTracker::getComputedVelocity(int32_t u return computedVelocity; } -std::optional VelocityTracker::getEstimator(int32_t axis, - int32_t pointerId) const { - const auto& it = mConfiguredStrategies.find(axis); - if (it == mConfiguredStrategies.end()) { - return std::nullopt; - } - return it->second->getEstimator(pointerId); -} - // --- LeastSquaresVelocityTrackerStrategy --- LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(uint32_t degree, @@ -474,10 +461,9 @@ void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares * http://en.wikipedia.org/wiki/Gram-Schmidt */ -static bool solveLeastSquares(const std::vector& x, const std::vector& y, - const std::vector& w, uint32_t n, - std::array& outB, - float* outDet) { +static std::optional solveLeastSquares(const std::vector& x, + const std::vector& y, + const std::vector& w, uint32_t n) { const size_t m = x.size(); ALOGD_IF(DEBUG_STRATEGY, "solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n), @@ -515,7 +501,7 @@ static bool solveLeastSquares(const std::vector& x, const std::vector& x, const std::vector outB; for (uint32_t i = n; i != 0; ) { i--; outB[i] = vectorDot(&q[i][0], wy, m); @@ -570,34 +557,33 @@ static bool solveLeastSquares(const std::vector& x, const std::vector 0.000001f ? 1.0f - (sserr / sstot) : 1; - - ALOGD_IF(DEBUG_STRATEGY, " - sserr=%f", sserr); - ALOGD_IF(DEBUG_STRATEGY, " - sstot=%f", sstot); - ALOGD_IF(DEBUG_STRATEGY, " - det=%f", *outDet); - return true; + return outB[1]; } /* * Optimized unweighted second-order least squares fit. About 2x speed improvement compared to * the default implementation */ -static std::optional> solveUnweightedLeastSquaresDeg2( - const std::vector& x, const std::vector& y) { +static std::optional solveUnweightedLeastSquaresDeg2(const std::vector& x, + const std::vector& y) { const size_t count = x.size(); LOG_ALWAYS_FATAL_IF(count != y.size(), "Mismatching array sizes"); // Solving y = a*x^2 + b*x + c @@ -632,22 +618,11 @@ static std::optional> solveUnweightedLeastSquaresDeg2( ALOGW("division by 0 when computing velocity, Sxx=%f, Sx2x2=%f, Sxx2=%f", Sxx, Sx2x2, Sxx2); return std::nullopt; } - // Compute a - float numerator = Sx2y*Sxx - Sxy*Sxx2; - float a = numerator / denominator; - - // Compute b - numerator = Sxy*Sx2x2 - Sx2y*Sxx2; - float b = numerator / denominator; - // Compute c - float c = syi/count - b * sxi/count - a * sxi2/count; - - return std::make_optional(std::array({c, b, a})); + return (Sxy * Sx2x2 - Sx2y * Sxx2) / denominator; } -std::optional LeastSquaresVelocityTrackerStrategy::getEstimator( - int32_t pointerId) const { +std::optional LeastSquaresVelocityTrackerStrategy::getVelocity(int32_t pointerId) const { const auto movementIt = mMovements.find(pointerId); if (movementIt == mMovements.end()) { return std::nullopt; // no data @@ -695,45 +670,15 @@ std::optional LeastSquaresVelocityTrackerStrategy::g degree = m - 1; } + if (degree <= 0) { + return std::nullopt; + } if (degree == 2 && mWeighting == Weighting::NONE) { // Optimize unweighted, quadratic polynomial fit - std::optional> coeff = - solveUnweightedLeastSquaresDeg2(time, positions); - if (coeff) { - VelocityTracker::Estimator estimator; - estimator.time = newestMovement.eventTime; - estimator.degree = 2; - estimator.confidence = 1; - for (size_t i = 0; i <= estimator.degree; i++) { - estimator.coeff[i] = (*coeff)[i]; - } - return estimator; - } - } else if (degree >= 1) { - // General case for an Nth degree polynomial fit - float det; - uint32_t n = degree + 1; - VelocityTracker::Estimator estimator; - if (solveLeastSquares(time, positions, w, n, estimator.coeff, &det)) { - estimator.time = newestMovement.eventTime; - estimator.degree = degree; - estimator.confidence = det; - - ALOGD_IF(DEBUG_STRATEGY, "estimate: degree=%d, coeff=%s, confidence=%f", - int(estimator.degree), vectorToString(estimator.coeff.data(), n).c_str(), - estimator.confidence); - - return estimator; - } + return solveUnweightedLeastSquaresDeg2(time, positions); } - - // No velocity data available for this pointer, but we do have its current position. - VelocityTracker::Estimator estimator; - estimator.coeff[0] = positions[0]; - estimator.time = newestMovement.eventTime; - estimator.degree = 0; - estimator.confidence = 1; - return estimator; + // General case for an Nth degree polynomial fit + return solveLeastSquares(time, positions, w, degree + 1); } float LeastSquaresVelocityTrackerStrategy::chooseWeight(int32_t pointerId, uint32_t index) const { @@ -830,13 +775,9 @@ void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t mPointerIdBits.markBit(pointerId); } -std::optional IntegratingVelocityTrackerStrategy::getEstimator( - int32_t pointerId) const { +std::optional IntegratingVelocityTrackerStrategy::getVelocity(int32_t pointerId) const { if (mPointerIdBits.hasBit(pointerId)) { - const State& state = mPointerState[pointerId]; - VelocityTracker::Estimator estimator; - populateEstimator(state, &estimator); - return estimator; + return mPointerState[pointerId].vel; } return std::nullopt; @@ -886,17 +827,6 @@ void IntegratingVelocityTrackerStrategy::updateState(State& state, nsecs_t event state.pos = pos; } -void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state, - VelocityTracker::Estimator* outEstimator) const { - outEstimator->time = state.updateTime; - outEstimator->confidence = 1.0f; - outEstimator->degree = state.degree; - outEstimator->coeff[0] = state.pos; - outEstimator->coeff[1] = state.vel; - outEstimator->coeff[2] = state.accel / 2; -} - - // --- LegacyVelocityTrackerStrategy --- LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {} @@ -937,8 +867,7 @@ void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t point movement.position = position; } -std::optional LegacyVelocityTrackerStrategy::getEstimator( - int32_t pointerId) const { +std::optional LegacyVelocityTrackerStrategy::getVelocity(int32_t pointerId) const { const auto movementIt = mMovements.find(pointerId); if (movementIt == mMovements.end()) { return std::nullopt; // no data @@ -996,19 +925,10 @@ std::optional LegacyVelocityTrackerStrategy::getEsti } } - // Report velocity. - float newestPosition = newestMovement.position; - VelocityTracker::Estimator estimator; - estimator.time = newestMovement.eventTime; - estimator.confidence = 1; - estimator.coeff[0] = newestPosition; if (samplesUsed) { - estimator.coeff[1] = accumV; - estimator.degree = 1; - } else { - estimator.degree = 0; + return accumV; } - return estimator; + return std::nullopt; } // --- ImpulseVelocityTrackerStrategy --- @@ -1177,8 +1097,7 @@ static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t c return kineticEnergyToVelocity(work); } -std::optional ImpulseVelocityTrackerStrategy::getEstimator( - int32_t pointerId) const { +std::optional ImpulseVelocityTrackerStrategy::getVelocity(int32_t pointerId) const { const auto movementIt = mMovements.find(pointerId); if (movementIt == mMovements.end()) { return std::nullopt; // no data @@ -1214,16 +1133,9 @@ std::optional ImpulseVelocityTrackerStrategy::getEst if (m == 0) { return std::nullopt; // no data } - VelocityTracker::Estimator estimator; - estimator.coeff[0] = 0; - estimator.coeff[1] = calculateImpulseVelocity(time, positions, m, mDeltaValues); - estimator.coeff[2] = 0; - - estimator.time = newestMovement.eventTime; - estimator.degree = 2; // similar results to 2nd degree fit - estimator.confidence = 1; - ALOGD_IF(DEBUG_STRATEGY, "velocity: %.1f", estimator.coeff[1]); + const float velocity = calculateImpulseVelocity(time, positions, m, mDeltaValues); + ALOGD_IF(DEBUG_STRATEGY, "velocity: %.1f", velocity); if (DEBUG_IMPULSE) { // TODO(b/134179997): delete this block once the switch to 'impulse' is complete. @@ -1240,7 +1152,7 @@ std::optional ImpulseVelocityTrackerStrategy::getEst ALOGD("lsq2 velocity: could not compute velocity"); } } - return estimator; + return velocity; } } // namespace android diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index c6ad3a2218..40c6bbbf3c 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -42,8 +42,8 @@ constexpr int32_t DEFAULT_POINTER_ID = 0; // pointer ID used for manually define // here EV = expected value, tol = VELOCITY_TOLERANCE constexpr float VELOCITY_TOLERANCE = 0.2; -// estimate coefficients must be within 0.001% of the target value -constexpr float COEFFICIENT_TOLERANCE = 0.00001; +// quadratic velocity must be within 0.001% of the target value +constexpr float QUADRATIC_VELOCITY_TOLERANCE = 0.00001; // --- VelocityTrackerTest --- class VelocityTrackerTest : public testing::Test { }; @@ -76,10 +76,6 @@ static void checkVelocity(std::optional Vactual, std::optional Vta } } -static void checkCoefficient(float actual, float target) { - EXPECT_NEAR_BY_FRACTION(actual, target, COEFFICIENT_TOLERANCE); -} - struct Position { float x; float y; @@ -284,21 +280,20 @@ static void computeAndCheckAxisScrollVelocity( checkVelocity(computeVelocity(strategy, motions, AMOTION_EVENT_AXIS_SCROLL), targetVelocity); } -static void computeAndCheckQuadraticEstimate(const std::vector& motions, - const std::array& coefficients) { +static void computeAndCheckQuadraticVelocity(const std::vector& motions, + float velocity) { VelocityTracker vt(VelocityTracker::Strategy::LSQ2); std::vector events = createTouchMotionEventStream(motions); for (MotionEvent event : events) { vt.addMovement(&event); } - std::optional estimatorX = vt.getEstimator(AMOTION_EVENT_AXIS_X, 0); - std::optional estimatorY = vt.getEstimator(AMOTION_EVENT_AXIS_Y, 0); - EXPECT_TRUE(estimatorX); - EXPECT_TRUE(estimatorY); - for (size_t i = 0; i< coefficients.size(); i++) { - checkCoefficient((*estimatorX).coeff[i], coefficients[i]); - checkCoefficient((*estimatorY).coeff[i], coefficients[i]); - } + std::optional velocityX = vt.getVelocity(AMOTION_EVENT_AXIS_X, 0); + std::optional velocityY = vt.getVelocity(AMOTION_EVENT_AXIS_Y, 0); + ASSERT_TRUE(velocityX); + ASSERT_TRUE(velocityY); + + EXPECT_NEAR_BY_FRACTION(*velocityX, velocity, QUADRATIC_VELOCITY_TOLERANCE); + EXPECT_NEAR_BY_FRACTION(*velocityY, velocity, QUADRATIC_VELOCITY_TOLERANCE); } /* @@ -461,8 +456,6 @@ TEST_F(VelocityTrackerTest, TestApiInteractionsWithNoMotionEvents) { EXPECT_FALSE(vt.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)); - EXPECT_FALSE(vt.getEstimator(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)); - VelocityTracker::ComputedVelocity computedVelocity = vt.getComputedVelocity(1000, 1000); for (uint32_t id = 0; id <= MAX_POINTER_ID; id++) { EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, id)); @@ -1074,7 +1067,7 @@ TEST_F(VelocityTrackerTest, SailfishFlingDownFast3) { * If the events with POINTER_UP or POINTER_DOWN are not handled correctly (these should not be * part of the fitted data), this can cause large velocity values to be reported instead. */ -TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_ThreeFingerTap) { +TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategy_ThreeFingerTap) { std::vector motions = { { 0us, {{1063, 1128}, {NAN, NAN}, {NAN, NAN}} }, { 10800us, {{1063, 1128}, {682, 1318}, {NAN, NAN}} }, // POINTER_DOWN @@ -1162,7 +1155,7 @@ TEST_F(VelocityTrackerTest, LongDelayBeforeActionPointerUp) { * ================== Tests for least squares fitting ============================================== * * Special care must be taken when constructing tests for LeastSquaresVelocityTrackerStrategy - * getEstimator function. In particular: + * getVelocity function. In particular: * - inside the function, time gets converted from nanoseconds to seconds * before being used in the fit. * - any values that are older than 100 ms are being discarded. @@ -1183,7 +1176,7 @@ TEST_F(VelocityTrackerTest, LongDelayBeforeActionPointerUp) { * The coefficients are (0, 0, 1). * In the test, we would convert these coefficients to (0*(1E3)^0, 0*(1E3)^1, 1*(1E3)^2). */ -TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Constant) { +TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategy_Constant) { std::vector motions = { { 0ms, {{1, 1}} }, // 0 s { 1ms, {{1, 1}} }, // 0.001 s @@ -1195,13 +1188,13 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Constan // -0.002, 1 // -0.001, 1 // -0.ms, 1 - computeAndCheckQuadraticEstimate(motions, std::array({1, 0, 0})); + computeAndCheckQuadraticVelocity(motions, 0); } /* * Straight line y = x :: the constant and quadratic coefficients are zero. */ -TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Linear) { +TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategy_Linear) { std::vector motions = { { 0ms, {{-2, -2}} }, { 1ms, {{-1, -1}} }, @@ -1213,13 +1206,13 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Linear) // -0.002, -2 // -0.001, -1 // -0.000, 0 - computeAndCheckQuadraticEstimate(motions, std::array({0, 1E3, 0})); + computeAndCheckQuadraticVelocity(motions, 1E3); } /* * Parabola */ -TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic) { +TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategy_Parabolic) { std::vector motions = { { 0ms, {{1, 1}} }, { 1ms, {{4, 4}} }, @@ -1231,13 +1224,13 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabol // -0.002, 1 // -0.001, 4 // -0.000, 8 - computeAndCheckQuadraticEstimate(motions, std::array({8, 4.5E3, 0.5E6})); + computeAndCheckQuadraticVelocity(motions, 4.5E3); } /* * Parabola */ -TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic2) { +TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategy_Parabolic2) { std::vector motions = { { 0ms, {{1, 1}} }, { 1ms, {{4, 4}} }, @@ -1249,13 +1242,13 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabol // -0.002, 1 // -0.001, 4 // -0.000, 9 - computeAndCheckQuadraticEstimate(motions, std::array({9, 6E3, 1E6})); + computeAndCheckQuadraticVelocity(motions, 6E3); } /* * Parabola :: y = x^2 :: the constant and linear coefficients are zero. */ -TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabolic3) { +TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategy_Parabolic3) { std::vector motions = { { 0ms, {{4, 4}} }, { 1ms, {{1, 1}} }, @@ -1267,7 +1260,7 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_Parabol // -0.002, 4 // -0.001, 1 // -0.000, 0 - computeAndCheckQuadraticEstimate(motions, std::array({0, 0E3, 1E6})); + computeAndCheckQuadraticVelocity(motions, 0E3); } // Recorded by hand on sailfish, but only the diffs are taken to test cumulative axis velocity. -- GitLab From c821470c737150467563fe8c8f5753f0a4272242 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 3 Mar 2023 23:31:17 +0000 Subject: [PATCH 0032/1187] Revert^2 "Use "SessionHint" enum in ndk API" 63a0fd1944c0fe541e6cc3af16cc1119ac7d1065 Change-Id: Icd1164728c38b9d813dbe5f47118a08c4bef48dc --- include/private/performance_hint_private.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h index eaf3b5e791..d50c5f846e 100644 --- a/include/private/performance_hint_private.h +++ b/include/private/performance_hint_private.h @@ -17,6 +17,8 @@ #ifndef ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H #define ANDROID_PRIVATE_NATIVE_PERFORMANCE_HINT_PRIVATE_H +#include + __BEGIN_DECLS /** @@ -27,7 +29,7 @@ void APerformanceHint_setIHintManagerForTesting(void* iManager); /** * Hints for the session used to signal upcoming changes in the mode or workload. */ -enum SessionHint { +enum SessionHint: int32_t { /** * This hint indicates a sudden increase in CPU workload intensity. It means * that this hint session needs extra CPU resources immediately to meet the @@ -61,7 +63,7 @@ enum SessionHint { * @return 0 on success * EPIPE if communication with the system service has failed. */ -int APerformanceHint_sendHint(void* session, int hint); +int APerformanceHint_sendHint(void* session, SessionHint hint); /** * Return the list of thread ids, this API should only be used for testing only. -- GitLab From b999a7b415ca336270201b1ad346114769e91368 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Sun, 5 Mar 2023 20:01:14 +0000 Subject: [PATCH 0033/1187] [sf] make legacy frontend debug flag persistent Legacy frontend is still the default but we enable the new front end, we want to disable the legacy by default as well. Change-Id: I04ec50e05e9022be6efe1f83f29783ef49b11023 Test: presubmit Bug: 238781169 --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 786706a676..2c1e3339d8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -476,7 +476,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mLayerLifecycleManagerEnabled = base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false); mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled || - base::GetBoolProperty("debug.sf.enable_legacy_frontend"s, true); + base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); } LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { -- GitLab From a0e573c3ad544689381a4e555c02515a45d86a57 Mon Sep 17 00:00:00 2001 From: Yeabkal Wubshit Date: Thu, 2 Mar 2023 21:08:14 -0800 Subject: [PATCH 0034/1187] Create AccumulatingVelocityTrackerStrategy This is a partial implementation of VelocityTrackerStrategy, that stores data points during "add" operations. Extracting this logic into a common class helps avoid duplicated logic across several strategies that do the exact same thing when adding new movements. It also helps ease future updates/optimizations. Bug: 267211645 Test: atest libinput_tests Change-Id: I116e978b070aa451813fefa384ccc65e10ea45a0 --- include/input/VelocityTracker.h | 68 ++++++++++---------------- libs/input/VelocityTracker.cpp | 87 ++++----------------------------- 2 files changed, 36 insertions(+), 119 deletions(-) diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index 5a23e8dca5..6d51515cb3 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -152,11 +152,34 @@ public: virtual std::optional getVelocity(int32_t pointerId) const = 0; }; +/** + * A `VelocityTrackerStrategy` that accumulates added data points and processes the accumulated data + * points when getting velocity. + */ +class AccumulatingVelocityTrackerStrategy : public VelocityTrackerStrategy { +public: + void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; + void clearPointer(int32_t pointerId) override; + +protected: + struct Movement { + nsecs_t eventTime; + float position; + }; + + // Number of samples to keep. + // If different strategies would like to maintain different history size, we can make this a + // protected const field. + static constexpr uint32_t HISTORY_SIZE = 20; + + std::map mIndex; + std::map> mMovements; +}; /* * Velocity tracker algorithm based on least-squares linear regression. */ -class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy { +class LeastSquaresVelocityTrackerStrategy : public AccumulatingVelocityTrackerStrategy { public: enum class Weighting { // No weights applied. All data points are equally reliable. @@ -177,8 +200,6 @@ public: LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = Weighting::NONE); ~LeastSquaresVelocityTrackerStrategy() override; - void clearPointer(int32_t pointerId) override; - void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; std::optional getVelocity(int32_t pointerId) const override; private: @@ -187,23 +208,12 @@ private: // changes in direction. static const nsecs_t HORIZON = 100 * 1000000; // 100 ms - // Number of samples to keep. - static const uint32_t HISTORY_SIZE = 20; - - struct Movement { - nsecs_t eventTime; - float position; - }; - float chooseWeight(int32_t pointerId, uint32_t index) const; const uint32_t mDegree; const Weighting mWeighting; - std::map mIndex; - std::map> mMovements; }; - /* * Velocity tracker algorithm that uses an IIR filter. */ @@ -238,41 +248,26 @@ private: /* * Velocity tracker strategy used prior to ICS. */ -class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy { +class LegacyVelocityTrackerStrategy : public AccumulatingVelocityTrackerStrategy { public: LegacyVelocityTrackerStrategy(); ~LegacyVelocityTrackerStrategy() override; - void clearPointer(int32_t pointerId) override; - void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; std::optional getVelocity(int32_t pointerId) const override; private: // Oldest sample to consider when calculating the velocity. static const nsecs_t HORIZON = 200 * 1000000; // 100 ms - // Number of samples to keep. - static const uint32_t HISTORY_SIZE = 20; - // The minimum duration between samples when estimating velocity. static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms - - struct Movement { - nsecs_t eventTime; - float position; - }; - - std::map mIndex; - std::map> mMovements; }; -class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy { +class ImpulseVelocityTrackerStrategy : public AccumulatingVelocityTrackerStrategy { public: ImpulseVelocityTrackerStrategy(bool deltaValues); ~ImpulseVelocityTrackerStrategy() override; - void clearPointer(int32_t pointerId) override; - void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; std::optional getVelocity(int32_t pointerId) const override; private: @@ -281,21 +276,10 @@ private: // changes in direction. static constexpr nsecs_t HORIZON = 100 * 1000000; // 100 ms - // Number of samples to keep. - static constexpr size_t HISTORY_SIZE = 20; - - struct Movement { - nsecs_t eventTime; - float position; - }; - // Whether or not the input movement values for the strategy come in the form of delta values. // If the input values are not deltas, the strategy needs to calculate deltas as part of its // velocity calculation. const bool mDeltaValues; - - std::map mIndex; - std::map> mMovements; }; } // namespace android diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index a88aa485fc..ac042c5790 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -370,21 +370,12 @@ VelocityTracker::ComputedVelocity VelocityTracker::getComputedVelocity(int32_t u return computedVelocity; } -// --- LeastSquaresVelocityTrackerStrategy --- - -LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(uint32_t degree, - Weighting weighting) - : mDegree(degree), mWeighting(weighting) {} - -LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() { -} - -void LeastSquaresVelocityTrackerStrategy::clearPointer(int32_t pointerId) { +void AccumulatingVelocityTrackerStrategy::clearPointer(int32_t pointerId) { mIndex.erase(pointerId); mMovements.erase(pointerId); } -void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId, +void AccumulatingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId, float position) { // If data for this pointer already exists, we have a valid entry at the position of // mIndex[pointerId] and mMovements[pointerId]. In that case, we need to advance the index @@ -412,6 +403,14 @@ void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t movement.position = position; } +// --- LeastSquaresVelocityTrackerStrategy --- + +LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(uint32_t degree, + Weighting weighting) + : mDegree(degree), mWeighting(weighting) {} + +LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() {} + /** * Solves a linear least squares problem to obtain a N degree polynomial that fits * the specified input data as nearly as possible. @@ -834,39 +833,6 @@ LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {} LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() { } -void LegacyVelocityTrackerStrategy::clearPointer(int32_t pointerId) { - mIndex.erase(pointerId); - mMovements.erase(pointerId); -} - -void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId, - float position) { - // If data for this pointer already exists, we have a valid entry at the position of - // mIndex[pointerId] and mMovements[pointerId]. In that case, we need to advance the index - // to the next position in the circular buffer and write the new Movement there. Otherwise, - // if this is a first movement for this pointer, we initialize the maps mIndex and mMovements - // for this pointer and write to the first position. - auto [movementIt, inserted] = mMovements.insert({pointerId, {}}); - auto [indexIt, _] = mIndex.insert({pointerId, 0}); - size_t& index = indexIt->second; - if (!inserted && movementIt->second[index].eventTime != eventTime) { - // When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates - // of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include - // the new pointer. If the eventtimes for both events are identical, just update the data - // for this time. - // We only compare against the last value, as it is likely that addMovement is called - // in chronological order as events occur. - index++; - } - if (index == HISTORY_SIZE) { - index = 0; - } - - Movement& movement = movementIt->second[index]; - movement.eventTime = eventTime; - movement.position = position; -} - std::optional LegacyVelocityTrackerStrategy::getVelocity(int32_t pointerId) const { const auto movementIt = mMovements.find(pointerId); if (movementIt == mMovements.end()) { @@ -939,39 +905,6 @@ ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy(bool deltaValues) ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() { } -void ImpulseVelocityTrackerStrategy::clearPointer(int32_t pointerId) { - mIndex.erase(pointerId); - mMovements.erase(pointerId); -} - -void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId, - float position) { - // If data for this pointer already exists, we have a valid entry at the position of - // mIndex[pointerId] and mMovements[pointerId]. In that case, we need to advance the index - // to the next position in the circular buffer and write the new Movement there. Otherwise, - // if this is a first movement for this pointer, we initialize the maps mIndex and mMovements - // for this pointer and write to the first position. - auto [movementIt, inserted] = mMovements.insert({pointerId, {}}); - auto [indexIt, _] = mIndex.insert({pointerId, 0}); - size_t& index = indexIt->second; - if (!inserted && movementIt->second[index].eventTime != eventTime) { - // When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates - // of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include - // the new pointer. If the eventtimes for both events are identical, just update the data - // for this time. - // We only compare against the last value, as it is likely that addMovement is called - // in chronological order as events occur. - index++; - } - if (index == HISTORY_SIZE) { - index = 0; - } - - Movement& movement = movementIt->second[index]; - movement.eventTime = eventTime; - movement.position = position; -} - /** * Calculate the total impulse provided to the screen and the resulting velocity. * -- GitLab From fcf20b80e15ad23e31bb33e422495eaed2fc7448 Mon Sep 17 00:00:00 2001 From: Max Zhang Date: Thu, 15 Dec 2022 18:15:39 +0000 Subject: [PATCH 0035/1187] [1/4] Add user customizable MACRO_x keys in frameworks Define keycode in frameworks/native as input labels Project details can be found at go/dipper-custom-button Bug: 269742724 Test: local build Change-Id: I9af8e14892f65e14319f34421063ef330a02078e --- include/android/keycodes.h | 8 ++++++++ libs/input/InputEventLabels.cpp | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/android/keycodes.h b/include/android/keycodes.h index d4ba321057..f8fb256fae 100644 --- a/include/android/keycodes.h +++ b/include/android/keycodes.h @@ -831,6 +831,14 @@ enum { AKEYCODE_STYLUS_BUTTON_TAIL = 311, /** Key to open recent apps (a.k.a. Overview) */ AKEYCODE_RECENT_APPS = 312, + /** User customizable key #1. */ + AKEYCODE_MACRO_1 = 313, + /** User customizable key #2. */ + AKEYCODE_MACRO_2 = 314, + /** User customizable key #3. */ + AKEYCODE_MACRO_3 = 315, + /** User customizable key #4. */ + AKEYCODE_MACRO_4 = 316, // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index dd7cbb5ba9..5a9dae65ed 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -340,7 +340,11 @@ namespace android { DEFINE_KEYCODE(STYLUS_BUTTON_SECONDARY), \ DEFINE_KEYCODE(STYLUS_BUTTON_TERTIARY), \ DEFINE_KEYCODE(STYLUS_BUTTON_TAIL), \ - DEFINE_KEYCODE(RECENT_APPS) + DEFINE_KEYCODE(RECENT_APPS), \ + DEFINE_KEYCODE(MACRO_1), \ + DEFINE_KEYCODE(MACRO_2), \ + DEFINE_KEYCODE(MACRO_3), \ + DEFINE_KEYCODE(MACRO_4) // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. -- GitLab From 64f090f8d51958bf162ff50e0c21e833c8eb9bc3 Mon Sep 17 00:00:00 2001 From: Yeabkal Wubshit Date: Fri, 3 Mar 2023 17:35:11 -0800 Subject: [PATCH 0036/1187] Use RingBuffer in VelocityTracker Several strategies used to store data points in an array design to work as a circular buffer. Now that we've the RingBuffer data structure, migrate to using that. Bug: 267211645 Test: atest libinput_tests Change-Id: Id1253c646c81d3c30baea496b2e3a75f5726c616 --- include/input/RingBuffer.h | 12 +-- include/input/VelocityTracker.h | 4 +- libs/input/MotionPredictor.cpp | 2 +- libs/input/VelocityTracker.cpp | 128 +++++++++++++------------------- 4 files changed, 62 insertions(+), 84 deletions(-) diff --git a/include/input/RingBuffer.h b/include/input/RingBuffer.h index 67984b7c80..5e9972eef8 100644 --- a/include/input/RingBuffer.h +++ b/include/input/RingBuffer.h @@ -24,7 +24,6 @@ #include #include -#include #include namespace android { @@ -272,15 +271,16 @@ private: // Converts the index of an element in [0, size()] to its corresponding index in mBuffer. size_type bufferIndex(size_type elementIndex) const { - CHECK_LE(elementIndex, size()); + if (elementIndex > size()) { + abort(); + } size_type index = mBegin + elementIndex; if (index >= capacity()) { index -= capacity(); } - CHECK_LT(index, capacity()) - << android::base::StringPrintf("Invalid index calculated for element (%zu) " - "in buffer of size %zu", - elementIndex, size()); + if (index >= capacity()) { + abort(); + } return index; } diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index 6d51515cb3..6d1de649f9 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include #include @@ -172,8 +173,7 @@ protected: // protected const field. static constexpr uint32_t HISTORY_SIZE = 20; - std::map mIndex; - std::map> mMovements; + std::map> mMovements; }; /* diff --git a/libs/input/MotionPredictor.cpp b/libs/input/MotionPredictor.cpp index b4151c6ea1..0d4213c745 100644 --- a/libs/input/MotionPredictor.cpp +++ b/libs/input/MotionPredictor.cpp @@ -25,9 +25,9 @@ #include #include +#include #include #include -#include #include #include diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index ac042c5790..ba266b3969 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -22,7 +22,6 @@ #include #include -#include #include #include #include @@ -371,36 +370,26 @@ VelocityTracker::ComputedVelocity VelocityTracker::getComputedVelocity(int32_t u } void AccumulatingVelocityTrackerStrategy::clearPointer(int32_t pointerId) { - mIndex.erase(pointerId); mMovements.erase(pointerId); } void AccumulatingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId, float position) { - // If data for this pointer already exists, we have a valid entry at the position of - // mIndex[pointerId] and mMovements[pointerId]. In that case, we need to advance the index - // to the next position in the circular buffer and write the new Movement there. Otherwise, - // if this is a first movement for this pointer, we initialize the maps mIndex and mMovements - // for this pointer and write to the first position. - auto [movementIt, inserted] = mMovements.insert({pointerId, {}}); - auto [indexIt, _] = mIndex.insert({pointerId, 0}); - size_t& index = indexIt->second; - if (!inserted && movementIt->second[index].eventTime != eventTime) { + auto [movementIt, _] = mMovements.insert({pointerId, RingBuffer(HISTORY_SIZE)}); + RingBuffer& movements = movementIt->second; + const size_t size = movements.size(); + + if (size != 0 && movements[size - 1].eventTime == eventTime) { // When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates // of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include // the new pointer. If the eventtimes for both events are identical, just update the data - // for this time. + // for this time (i.e. pop out the last element, and insert the updated movement). // We only compare against the last value, as it is likely that addMovement is called // in chronological order as events occur. - index++; - } - if (index == HISTORY_SIZE) { - index = 0; + movements.popBack(); } - Movement& movement = movementIt->second[index]; - movement.eventTime = eventTime; - movement.position = position; + movements.pushBack({eventTime, position}); } // --- LeastSquaresVelocityTrackerStrategy --- @@ -626,37 +615,30 @@ std::optional LeastSquaresVelocityTrackerStrategy::getVelocity(int32_t po if (movementIt == mMovements.end()) { return std::nullopt; // no data } + + const RingBuffer& movements = movementIt->second; + const size_t size = movements.size(); + if (size == 0) { + return std::nullopt; // no data + } + // Iterate over movement samples in reverse time order and collect samples. std::vector positions; std::vector w; std::vector time; - uint32_t index = mIndex.at(pointerId); - const Movement& newestMovement = movementIt->second[index]; - do { - const Movement& movement = movementIt->second[index]; + const Movement& newestMovement = movements[size - 1]; + for (ssize_t i = size - 1; i >= 0; i--) { + const Movement& movement = movements[i]; nsecs_t age = newestMovement.eventTime - movement.eventTime; if (age > HORIZON) { break; } - if (movement.eventTime == 0 && index != 0) { - // All eventTime's are initialized to 0. In this fixed-width circular buffer, it's - // possible that not all entries are valid. We use a time=0 as a signal for those - // uninitialized values. If we encounter a time of 0 in a position - // that's > 0, it means that we hit the block where the data wasn't initialized. - // We still don't know whether the value at index=0, with eventTime=0 is valid. - // However, that's only possible when the value is by itself. So there's no hard in - // processing it anyways, since the velocity for a single point is zero, and this - // situation will only be encountered in artificial circumstances (in tests). - // In practice, time will never be 0. - break; - } positions.push_back(movement.position); - w.push_back(chooseWeight(pointerId, index)); + w.push_back(chooseWeight(pointerId, i)); time.push_back(-age * 0.000000001f); - index = (index == 0 ? HISTORY_SIZE : index) - 1; - } while (positions.size() < HISTORY_SIZE); + } const size_t m = positions.size(); if (m == 0) { @@ -681,19 +663,19 @@ std::optional LeastSquaresVelocityTrackerStrategy::getVelocity(int32_t po } float LeastSquaresVelocityTrackerStrategy::chooseWeight(int32_t pointerId, uint32_t index) const { - const std::array& movements = mMovements.at(pointerId); + const RingBuffer& movements = mMovements.at(pointerId); + const size_t size = movements.size(); switch (mWeighting) { case Weighting::DELTA: { // Weight points based on how much time elapsed between them and the next // point so that points that "cover" a shorter time span are weighed less. // delta 0ms: 0.5 // delta 10ms: 1.0 - if (index == mIndex.at(pointerId)) { + if (index == size - 1) { return 1.0f; } - uint32_t nextIndex = (index + 1) % HISTORY_SIZE; float deltaMillis = - (movements[nextIndex].eventTime - movements[index].eventTime) * 0.000001f; + (movements[index + 1].eventTime - movements[index].eventTime) * 0.000001f; if (deltaMillis < 0) { return 0.5f; } @@ -710,8 +692,7 @@ float LeastSquaresVelocityTrackerStrategy::chooseWeight(int32_t pointerId, uint3 // age 50ms: 1.0 // age 60ms: 0.5 float ageMillis = - (movements[mIndex.at(pointerId)].eventTime - movements[index].eventTime) * - 0.000001f; + (movements[size - 1].eventTime - movements[index].eventTime) * 0.000001f; if (ageMillis < 0) { return 0.5f; } @@ -733,8 +714,7 @@ float LeastSquaresVelocityTrackerStrategy::chooseWeight(int32_t pointerId, uint3 // age 50ms: 1.0 // age 100ms: 0.5 float ageMillis = - (movements[mIndex.at(pointerId)].eventTime - movements[index].eventTime) * - 0.000001f; + (movements[size - 1].eventTime - movements[index].eventTime) * 0.000001f; if (ageMillis < 50) { return 1.0f; } @@ -838,20 +818,25 @@ std::optional LegacyVelocityTrackerStrategy::getVelocity(int32_t pointerI if (movementIt == mMovements.end()) { return std::nullopt; // no data } - const Movement& newestMovement = movementIt->second[mIndex.at(pointerId)]; + + const RingBuffer& movements = movementIt->second; + const size_t size = movements.size(); + if (size == 0) { + return std::nullopt; // no data + } + + const Movement& newestMovement = movements[size - 1]; // Find the oldest sample that contains the pointer and that is not older than HORIZON. nsecs_t minTime = newestMovement.eventTime - HORIZON; - uint32_t oldestIndex = mIndex.at(pointerId); - uint32_t numTouches = 1; - do { - uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1; - const Movement& nextOldestMovement = mMovements.at(pointerId)[nextOldestIndex]; + uint32_t oldestIndex = size - 1; + for (ssize_t i = size - 1; i >= 0; i--) { + const Movement& nextOldestMovement = movements[i]; if (nextOldestMovement.eventTime < minTime) { break; } - oldestIndex = nextOldestIndex; - } while (++numTouches < HISTORY_SIZE); + oldestIndex = i; + } // Calculate an exponentially weighted moving average of the velocity estimate // at different points in time measured relative to the oldest sample. @@ -865,17 +850,13 @@ std::optional LegacyVelocityTrackerStrategy::getVelocity(int32_t pointerI // 16ms apart but some consecutive samples could be only 0.5sm apart because // the hardware or driver reports them irregularly or in bursts. float accumV = 0; - uint32_t index = oldestIndex; uint32_t samplesUsed = 0; - const Movement& oldestMovement = mMovements.at(pointerId)[oldestIndex]; + const Movement& oldestMovement = movements[oldestIndex]; float oldestPosition = oldestMovement.position; nsecs_t lastDuration = 0; - while (numTouches-- > 1) { - if (++index == HISTORY_SIZE) { - index = 0; - } - const Movement& movement = mMovements.at(pointerId)[index]; + for (size_t i = oldestIndex; i < size; i++) { + const Movement& movement = movements[i]; nsecs_t duration = movement.eventTime - oldestMovement.eventTime; // If the duration between samples is small, we may significantly overestimate @@ -1036,32 +1017,29 @@ std::optional ImpulseVelocityTrackerStrategy::getVelocity(int32_t pointer return std::nullopt; // no data } + const RingBuffer& movements = movementIt->second; + const size_t size = movements.size(); + if (size == 0) { + return std::nullopt; // no data + } + // Iterate over movement samples in reverse time order and collect samples. float positions[HISTORY_SIZE]; nsecs_t time[HISTORY_SIZE]; size_t m = 0; // number of points that will be used for fitting - size_t index = mIndex.at(pointerId); - const Movement& newestMovement = movementIt->second[index]; - do { - const Movement& movement = movementIt->second[index]; + const Movement& newestMovement = movements[size - 1]; + for (ssize_t i = size - 1; i >= 0; i--) { + const Movement& movement = movements[i]; nsecs_t age = newestMovement.eventTime - movement.eventTime; if (age > HORIZON) { break; } - if (movement.eventTime == 0 && index != 0) { - // All eventTime's are initialized to 0. If we encounter a time of 0 in a position - // that's >0, it means that we hit the block where the data wasn't initialized. - // It's also possible that the sample at 0 would be invalid, but there's no harm in - // processing it, since it would be just a single point, and will only be encountered - // in artificial circumstances (in tests). - break; - } positions[m] = movement.position; time[m] = movement.eventTime; - index = (index == 0 ? HISTORY_SIZE : index) - 1; - } while (++m < HISTORY_SIZE); + m++; + } if (m == 0) { return std::nullopt; // no data -- GitLab From 4a678b228dc6691f6c273a0b0b43e83fc10085af Mon Sep 17 00:00:00 2001 From: Yeabkal Wubshit Date: Thu, 23 Feb 2023 17:03:40 -0800 Subject: [PATCH 0037/1187] Avoid Temporary Memory Allocation in Impulse Velocity Calculation During calculating impulse velocity, we used to create arrays to store the data ponits that are within the HORIZON, and then pass those arrays (1 for position and one for time) to a separate static function to calculate velocity. This means that we have to do extra space allocation (~O(n)), plus process most/all data points twice - once during collecting the valid data points, and once during using their data to get velocity. This implementation avoids new array allocation by using a single linear processing to both get the valid data points (i.e. the ones within HORIZON from the latest data point), and to get the velocity. This approach also has the side-effect benefit of avoiding consideration of any old data-point on future calls on "computeCurrentVelocity", as we will effectively mark a data point permanently "invalid" if it fails to fall within the HORIZON at any point. Trace-based analysis indicates that this approach improves the `getVelocity` method by ~20% in time. Bug: 267211645 Test: unit tests unaffected Change-Id: Ie7671194476cd17131d79c06b5bc1440a958d384 --- include/input/VelocityTracker.h | 12 ++++ libs/input/VelocityTracker.cpp | 116 +++++++++++--------------------- 2 files changed, 53 insertions(+), 75 deletions(-) diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index 6d1de649f9..f218c512e8 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -159,6 +159,8 @@ public: */ class AccumulatingVelocityTrackerStrategy : public VelocityTrackerStrategy { public: + AccumulatingVelocityTrackerStrategy(nsecs_t horizonNanos, bool maintainHorizonDuringAdd); + void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override; void clearPointer(int32_t pointerId) override; @@ -173,6 +175,16 @@ protected: // protected const field. static constexpr uint32_t HISTORY_SIZE = 20; + /** + * Duration, in nanoseconds, since the latest movement where a movement may be considered for + * velocity calculation. + */ + const nsecs_t mHorizonNanos; + /** + * If true, data points outside of horizon (see `mHorizonNanos`) will be cleared after each + * addition of a new movement. + */ + const bool mMaintainHorizonDuringAdd; std::map> mMovements; }; diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index ba266b3969..150b68b9d2 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -55,6 +55,9 @@ const bool DEBUG_IMPULSE = // Nanoseconds per milliseconds. static const nsecs_t NANOS_PER_MS = 1000000; +// Seconds per nanosecond. +static const float SECONDS_PER_NANO = 1E-9; + // All axes supported for velocity tracking, mapped to their default strategies. // Although other strategies are available for testing and comparison purposes, // the default strategy is the one that applications will actually use. Be very careful @@ -369,6 +372,10 @@ VelocityTracker::ComputedVelocity VelocityTracker::getComputedVelocity(int32_t u return computedVelocity; } +AccumulatingVelocityTrackerStrategy::AccumulatingVelocityTrackerStrategy( + nsecs_t horizonNanos, bool maintainHorizonDuringAdd) + : mHorizonNanos(horizonNanos), mMaintainHorizonDuringAdd(maintainHorizonDuringAdd) {} + void AccumulatingVelocityTrackerStrategy::clearPointer(int32_t pointerId) { mMovements.erase(pointerId); } @@ -390,13 +397,25 @@ void AccumulatingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t } movements.pushBack({eventTime, position}); + + // Clear movements that do not fall within `mHorizonNanos` of the latest movement. + // Note that, if in the future we decide to use more movements (i.e. increase HISTORY_SIZE), + // we can consider making this step binary-search based, which will give us some improvement. + if (mMaintainHorizonDuringAdd) { + while (eventTime - movements[0].eventTime > mHorizonNanos) { + movements.popFront(); + } + } } // --- LeastSquaresVelocityTrackerStrategy --- LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting) - : mDegree(degree), mWeighting(weighting) {} + : AccumulatingVelocityTrackerStrategy(HORIZON /*horizonNanos*/, + false /*maintainHorizonDuringAdd*/), + mDegree(degree), + mWeighting(weighting) {} LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() {} @@ -808,7 +827,9 @@ void IntegratingVelocityTrackerStrategy::updateState(State& state, nsecs_t event // --- LegacyVelocityTrackerStrategy --- -LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {} +LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() + : AccumulatingVelocityTrackerStrategy(HORIZON /*horizonNanos*/, + false /*maintainHorizonDuringAdd*/) {} LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() { } @@ -881,7 +902,9 @@ std::optional LegacyVelocityTrackerStrategy::getVelocity(int32_t pointerI // --- ImpulseVelocityTrackerStrategy --- ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy(bool deltaValues) - : mDeltaValues(deltaValues) {} + : AccumulatingVelocityTrackerStrategy(HORIZON /*horizonNanos*/, + true /*maintainHorizonDuringAdd*/), + mDeltaValues(deltaValues) {} ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() { } @@ -960,57 +983,6 @@ static float kineticEnergyToVelocity(float work) { return (work < 0 ? -1.0 : 1.0) * sqrtf(fabsf(work)) * sqrt2; } -static float calculateImpulseVelocity(const nsecs_t* t, const float* x, size_t count, - bool deltaValues) { - // The input should be in reversed time order (most recent sample at index i=0) - // t[i] is in nanoseconds, but due to FP arithmetic, convert to seconds inside this function - static constexpr float SECONDS_PER_NANO = 1E-9; - - if (count < 2) { - return 0; // if 0 or 1 points, velocity is zero - } - if (t[1] > t[0]) { // Algorithm will still work, but not perfectly - ALOGE("Samples provided to calculateImpulseVelocity in the wrong order"); - } - - // If the data values are delta values, we do not have to calculate deltas here. - // We can use the delta values directly, along with the calculated time deltas. - // Since the data value input is in reversed time order: - // [a] for non-delta inputs, instantenous velocity = (x[i] - x[i-1])/(t[i] - t[i-1]) - // [b] for delta inputs, instantenous velocity = -x[i-1]/(t[i] - t[i - 1]) - // e.g., let the non-delta values are: V = [2, 3, 7], the equivalent deltas are D = [2, 1, 4]. - // Since the input is in reversed time order, the input values for this function would be - // V'=[7, 3, 2] and D'=[4, 1, 2] for the non-delta and delta values, respectively. - // - // The equivalent of {(V'[2] - V'[1]) = 2 - 3 = -1} would be {-D'[1] = -1} - // Similarly, the equivalent of {(V'[1] - V'[0]) = 3 - 7 = -4} would be {-D'[0] = -4} - - if (count == 2) { // if 2 points, basic linear calculation - if (t[1] == t[0]) { - ALOGE("Events have identical time stamps t=%" PRId64 ", setting velocity = 0", t[0]); - return 0; - } - const float deltaX = deltaValues ? -x[0] : x[1] - x[0]; - return deltaX / (SECONDS_PER_NANO * (t[1] - t[0])); - } - // Guaranteed to have at least 3 points here - float work = 0; - for (size_t i = count - 1; i > 0 ; i--) { // start with the oldest sample and go forward in time - if (t[i] == t[i-1]) { - ALOGE("Events have identical time stamps t=%" PRId64 ", skipping sample", t[i]); - continue; - } - float vprev = kineticEnergyToVelocity(work); // v[i-1] - const float deltaX = deltaValues ? -x[i-1] : x[i] - x[i-1]; - float vcurr = deltaX / (SECONDS_PER_NANO * (t[i] - t[i-1])); // v[i] - work += (vcurr - vprev) * fabsf(vcurr); - if (i == count - 1) { - work *= 0.5; // initial condition, case 2) above - } - } - return kineticEnergyToVelocity(work); -} - std::optional ImpulseVelocityTrackerStrategy::getVelocity(int32_t pointerId) const { const auto movementIt = mMovements.find(pointerId); if (movementIt == mMovements.end()) { @@ -1023,29 +995,22 @@ std::optional ImpulseVelocityTrackerStrategy::getVelocity(int32_t pointer return std::nullopt; // no data } - // Iterate over movement samples in reverse time order and collect samples. - float positions[HISTORY_SIZE]; - nsecs_t time[HISTORY_SIZE]; - size_t m = 0; // number of points that will be used for fitting - const Movement& newestMovement = movements[size - 1]; - for (ssize_t i = size - 1; i >= 0; i--) { - const Movement& movement = movements[i]; - - nsecs_t age = newestMovement.eventTime - movement.eventTime; - if (age > HORIZON) { - break; - } + float work = 0; + for (size_t i = 0; i < size - 1; i++) { + const Movement& mvt = movements[i]; + const Movement& nextMvt = movements[i + 1]; - positions[m] = movement.position; - time[m] = movement.eventTime; - m++; - } + float vprev = kineticEnergyToVelocity(work); + float delta = mDeltaValues ? nextMvt.position : nextMvt.position - mvt.position; + float vcurr = delta / (SECONDS_PER_NANO * (nextMvt.eventTime - mvt.eventTime)); + work += (vcurr - vprev) * fabsf(vcurr); - if (m == 0) { - return std::nullopt; // no data + if (i == 0) { + work *= 0.5; // initial condition, case 2) above + } } - const float velocity = calculateImpulseVelocity(time, positions, m, mDeltaValues); + const float velocity = kineticEnergyToVelocity(work); ALOGD_IF(DEBUG_STRATEGY, "velocity: %.1f", velocity); if (DEBUG_IMPULSE) { @@ -1053,8 +1018,9 @@ std::optional ImpulseVelocityTrackerStrategy::getVelocity(int32_t pointer // Calculate the lsq2 velocity for the same inputs to allow runtime comparisons. // X axis chosen arbitrarily for velocity comparisons. VelocityTracker lsq2(VelocityTracker::Strategy::LSQ2); - for (ssize_t i = m - 1; i >= 0; i--) { - lsq2.addMovement(time[i], pointerId, AMOTION_EVENT_AXIS_X, positions[i]); + for (size_t i = 0; i < size; i++) { + const Movement& mvt = movements[i]; + lsq2.addMovement(mvt.eventTime, pointerId, AMOTION_EVENT_AXIS_X, mvt.position); } std::optional v = lsq2.getVelocity(AMOTION_EVENT_AXIS_X, pointerId); if (v) { -- GitLab From fa806e4452c1e9094ff19167baaa459a63434f14 Mon Sep 17 00:00:00 2001 From: Yeabkal Wubshit Date: Mon, 6 Mar 2023 18:34:07 -0800 Subject: [PATCH 0038/1187] Avoid Temporary Memory Allocation in LSQ2 Velocity Calculation When calculating LSQ2 velocity with no-weights, we used to create two vectors: one for "age" of the movements since the latest movement, and one for the movements' position. We then passed this to a static helper function to calculate velocity. This CL avoids the creation of these intermediate vectors by calculating velocity in one pass. Furthermore, we're now clearing out old data points (i.e. the ones that are past the horizon) in the "add" operation for LSQ2. This means that the "getVelocity" method always gets called with the accumulated movements guaranteed to fall within the horizon. A minor clean up that is a side-effect of this change is that we won't be calculating "weights" for LSQ2 with no weights (we used to calculate these weights and store them in vectors for no use before). Trace measurements for only the "getVelocity" code block show ~2x improvements in time taken to executre "getVelocity". Bug: 271935895 Test: atest libinput_tests Change-Id: Id27bcbb183556479b9499b003823d3b0adec0423 --- include/input/VelocityTracker.h | 7 ++++ libs/input/VelocityTracker.cpp | 57 ++++++++++++++++----------------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index f218c512e8..b58feac444 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -221,6 +221,13 @@ private: static const nsecs_t HORIZON = 100 * 1000000; // 100 ms float chooseWeight(int32_t pointerId, uint32_t index) const; + /** + * An optimized least-squares solver for degree 2 and no weight (i.e. `Weighting.NONE`). + * The provided container of movements shall NOT be empty, and shall have the movements in + * chronological order. + */ + std::optional solveUnweightedLeastSquaresDeg2( + const RingBuffer& movements) const; const uint32_t mDegree; const Weighting mWeighting; diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index 150b68b9d2..38730dc966 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -413,7 +413,7 @@ void AccumulatingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting) : AccumulatingVelocityTrackerStrategy(HORIZON /*horizonNanos*/, - false /*maintainHorizonDuringAdd*/), + true /*maintainHorizonDuringAdd*/), mDegree(degree), mWeighting(weighting) {} @@ -589,16 +589,21 @@ static std::optional solveLeastSquares(const std::vector& x, * Optimized unweighted second-order least squares fit. About 2x speed improvement compared to * the default implementation */ -static std::optional solveUnweightedLeastSquaresDeg2(const std::vector& x, - const std::vector& y) { - const size_t count = x.size(); - LOG_ALWAYS_FATAL_IF(count != y.size(), "Mismatching array sizes"); - // Solving y = a*x^2 + b*x + c +std::optional LeastSquaresVelocityTrackerStrategy::solveUnweightedLeastSquaresDeg2( + const RingBuffer& movements) const { + // Solving y = a*x^2 + b*x + c, where + // - "x" is age (i.e. duration since latest movement) of the movemnets + // - "y" is positions of the movements. float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0; + const size_t count = movements.size(); + const Movement& newestMovement = movements[count - 1]; for (size_t i = 0; i < count; i++) { - float xi = x[i]; - float yi = y[i]; + const Movement& movement = movements[i]; + nsecs_t age = newestMovement.eventTime - movement.eventTime; + float xi = -age * SECONDS_PER_NANO; + float yi = movement.position; + float xi2 = xi*xi; float xi3 = xi2*xi; float xi4 = xi3*xi; @@ -641,6 +646,20 @@ std::optional LeastSquaresVelocityTrackerStrategy::getVelocity(int32_t po return std::nullopt; // no data } + uint32_t degree = mDegree; + if (degree > size - 1) { + degree = size - 1; + } + + if (degree <= 0) { + return std::nullopt; + } + + if (degree == 2 && mWeighting == Weighting::NONE) { + // Optimize unweighted, quadratic polynomial fit + return solveUnweightedLeastSquaresDeg2(movements); + } + // Iterate over movement samples in reverse time order and collect samples. std::vector positions; std::vector w; @@ -649,34 +668,12 @@ std::optional LeastSquaresVelocityTrackerStrategy::getVelocity(int32_t po const Movement& newestMovement = movements[size - 1]; for (ssize_t i = size - 1; i >= 0; i--) { const Movement& movement = movements[i]; - nsecs_t age = newestMovement.eventTime - movement.eventTime; - if (age > HORIZON) { - break; - } positions.push_back(movement.position); w.push_back(chooseWeight(pointerId, i)); time.push_back(-age * 0.000000001f); } - const size_t m = positions.size(); - if (m == 0) { - return std::nullopt; // no data - } - - // Calculate a least squares polynomial fit. - uint32_t degree = mDegree; - if (degree > m - 1) { - degree = m - 1; - } - - if (degree <= 0) { - return std::nullopt; - } - if (degree == 2 && mWeighting == Weighting::NONE) { - // Optimize unweighted, quadratic polynomial fit - return solveUnweightedLeastSquaresDeg2(time, positions); - } // General case for an Nth degree polynomial fit return solveLeastSquares(time, positions, w, degree + 1); } -- GitLab From 540dc07e42ce5188d3e7897256ba6e0d8671b903 Mon Sep 17 00:00:00 2001 From: Yeabkal Wubshit Date: Thu, 9 Mar 2023 17:11:39 +0000 Subject: [PATCH 0039/1187] Avoid RingBuffer creation on each VelocityTracker#add call The code used to create a new RingBuffer each time a movement was added to VelocityTracker. This is expensive, and it showed up as a regression in our benchmark tests. With this change, we create a new RingBuffer for a pointerId only if there is not one already. Bug: 267211645 Bug: 271935895 Test: atest libinput_tests, benchmark test regression fixed Change-Id: I47c6dda5741459a1bd84f3f5f46f932c26fda523 --- libs/input/VelocityTracker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index 38730dc966..431a7476f9 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -382,8 +382,8 @@ void AccumulatingVelocityTrackerStrategy::clearPointer(int32_t pointerId) { void AccumulatingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId, float position) { - auto [movementIt, _] = mMovements.insert({pointerId, RingBuffer(HISTORY_SIZE)}); - RingBuffer& movements = movementIt->second; + auto [ringBufferIt, _] = mMovements.try_emplace(pointerId, HISTORY_SIZE); + RingBuffer& movements = ringBufferIt->second; const size_t size = movements.size(); if (size != 0 && movements[size - 1].eventTime == eventTime) { -- GitLab From 631e425dbf8e5fa0bfca9fa5e76e3dad8f01cb6a Mon Sep 17 00:00:00 2001 From: Edgar Arriaga Date: Thu, 2 Mar 2023 02:11:24 +0000 Subject: [PATCH 0040/1187] Make frames dropped be a jank type in Frametimeline This allows the dropped frames to be accounted within frame timeline missed frames metrics, without this, the metric tells there are no missed frames when there are dropped frames. Bug: 271031574 Test: Verified in traces Change-Id: I838e0c10d4a92a4d5f753f020b57ea4e59fd0f8d --- libs/gui/include/gui/JankInfo.h | 2 ++ .../FrameTimeline/FrameTimeline.cpp | 25 +++++++++++++------ .../tests/unittests/FrameTimelineTest.cpp | 8 +++--- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/libs/gui/include/gui/JankInfo.h b/libs/gui/include/gui/JankInfo.h index 1dddeba616..bf354e7bb4 100644 --- a/libs/gui/include/gui/JankInfo.h +++ b/libs/gui/include/gui/JankInfo.h @@ -46,6 +46,8 @@ enum JankType { // where the previous frame was presented in the current frame's expected vsync. This pushes the // current frame to the next vsync. The behavior is similar to BufferStuffing. SurfaceFlingerStuffing = 0x100, + // Frame was dropped, as a newer frame was ready and replaced this frame. + Dropped = 0x200, }; } // namespace android diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 925f111dc6..40390de306 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -140,6 +140,10 @@ std::string jankTypeBitmaskToString(int32_t jankType) { janks.emplace_back("SurfaceFlinger Stuffing"); jankType &= ~JankType::SurfaceFlingerStuffing; } + if (jankType & JankType::Dropped) { + janks.emplace_back("Dropped Frame"); + jankType &= ~JankType::Dropped; + } // jankType should be 0 if all types of jank were checked for. LOG_ALWAYS_FATAL_IF(jankType != 0, "Unrecognized jank type value 0x%x", jankType); @@ -264,6 +268,11 @@ int32_t jankTypeBitmaskToProto(int32_t jankType) { protoJank |= FrameTimelineEvent::JANK_SF_STUFFING; jankType &= ~JankType::SurfaceFlingerStuffing; } + if (jankType & JankType::Dropped) { + // Jank dropped does not append to other janks, it fully overrides. + protoJank |= FrameTimelineEvent::JANK_DROPPED; + jankType &= ~JankType::Dropped; + } // jankType should be 0 if all types of jank were checked for. LOG_ALWAYS_FATAL_IF(jankType != 0, "Unrecognized jank type value 0x%x", jankType); @@ -365,8 +374,7 @@ void SurfaceFrame::setGpuComposition() { std::optional SurfaceFrame::getJankType() const { std::scoped_lock lock(mMutex); if (mPresentState == PresentState::Dropped) { - // Return no jank if it's a dropped frame since we cannot attribute a jank to a it. - return JankType::None; + return JankType::Dropped; } if (mActuals.presentTime == 0) { // Frame hasn't been presented yet. @@ -503,7 +511,8 @@ void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& r // We classify prediction expired as AppDeadlineMissed as the // TokenManager::kMaxTokens we store is large enough to account for a // reasonable app, so prediction expire would mean a huge scheduling delay. - mJankType = JankType::AppDeadlineMissed; + mJankType = mPresentState != PresentState::Presented ? JankType::Dropped + : JankType::AppDeadlineMissed; deadlineDelta = -1; return; } @@ -594,17 +603,17 @@ void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& r mJankType |= displayFrameJankType; } } + if (mPresentState != PresentState::Presented) { + mJankType = JankType::Dropped; + // Since frame was not presented, lets drop any present value + mActuals.presentTime = 0; + } } void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate, nsecs_t displayDeadlineDelta, nsecs_t displayPresentDelta) { std::scoped_lock lock(mMutex); - if (mPresentState != PresentState::Presented) { - // No need to update dropped buffers - return; - } - mActuals.presentTime = presentTime; nsecs_t deadlineDelta = 0; diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index abd77894af..b7a1c81422 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -1198,7 +1198,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_predictionExpiredDoesNotTraceExpecte TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { auto tracingSession = getTracingSessionForTest(); // Layer specific increment - EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)); + EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(2); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); @@ -1234,8 +1234,8 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { auto protoDroppedSurfaceFrameActualStart = createProtoActualSurfaceFrameStart(traceCookie + 2, surfaceFrameToken, displayFrameToken1, sPidOne, sLayerNameOne, - FrameTimelineEvent::PRESENT_DROPPED, false, false, - FrameTimelineEvent::JANK_NONE, + FrameTimelineEvent::PRESENT_DROPPED, true, false, + FrameTimelineEvent::JANK_DROPPED, FrameTimelineEvent::PREDICTION_VALID, true); auto protoDroppedSurfaceFrameActualEnd = createProtoFrameEnd(traceCookie + 2); @@ -1470,7 +1470,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDroppedFramesTraced createProtoActualSurfaceFrameStart(traceCookie + 1, surfaceFrameToken, displayFrameToken, sPidOne, sLayerNameOne, FrameTimelineEvent::PRESENT_DROPPED, false, false, - FrameTimelineEvent::JANK_NONE, + FrameTimelineEvent::JANK_DROPPED, FrameTimelineEvent::PREDICTION_EXPIRED, true); auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1); -- GitLab From eae1e257b6dc5a039d5c8422b089849730e04c83 Mon Sep 17 00:00:00 2001 From: Matt Buckley Date: Tue, 28 Feb 2023 06:51:28 +0000 Subject: [PATCH 0041/1187] Make SF Hint Session safety margin adjustable with a debug prop Bug: 271016792 Test: manual Change-Id: I59615b90dc109285cd681b89ff80a569037c2992 --- .../DisplayHardware/PowerAdvisor.cpp | 9 ++++++--- .../surfaceflinger/DisplayHardware/PowerAdvisor.h | 3 ++- .../tests/unittests/PowerAdvisorTest.cpp | 14 ++++++++++---- .../mock/DisplayHardware/MockAidlPowerHalWrapper.h | 2 ++ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index f05223cce0..36f71bb481 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -219,7 +219,7 @@ void PowerAdvisor::sendActualWorkDuration() { std::lock_guard lock(mPowerHalMutex); HalWrapper* const halWrapper = getPowerHal(); if (halWrapper != nullptr) { - halWrapper->sendActualWorkDuration(*actualDuration + kTargetSafetyMargin, + halWrapper->sendActualWorkDuration(*actualDuration + sTargetSafetyMargin, TimePoint::now()); } } @@ -232,12 +232,11 @@ void PowerAdvisor::sendPredictedWorkDuration() { } const std::optional predictedDuration = estimateWorkDuration(true); - if (predictedDuration.has_value()) { std::lock_guard lock(mPowerHalMutex); HalWrapper* const halWrapper = getPowerHal(); if (halWrapper != nullptr) { - halWrapper->sendActualWorkDuration(*predictedDuration + kTargetSafetyMargin, + halWrapper->sendActualWorkDuration(*predictedDuration + sTargetSafetyMargin, TimePoint::now()); } } @@ -812,6 +811,10 @@ std::optional AidlPowerHalWrapper::getTargetWorkDuration() { const bool AidlPowerHalWrapper::sTraceHintSessionData = base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false); +const Duration PowerAdvisor::sTargetSafetyMargin = std::chrono::microseconds( + base::GetIntProperty("debug.sf.hint_margin_us", + ticks(PowerAdvisor::kDefaultTargetSafetyMargin))); + PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { if (!mHasHal) { return nullptr; diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h index d45e7cb572..c4cfdc3482 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h @@ -274,7 +274,8 @@ private: // An adjustable safety margin which pads the "actual" value sent to PowerHAL, // encouraging more aggressive boosting to give SurfaceFlinger a larger margin for error - static constexpr const Duration kTargetSafetyMargin{1ms}; + static const Duration sTargetSafetyMargin; + static constexpr const Duration kDefaultTargetSafetyMargin{1ms}; // How long we expect hwc to run after the present call until it waits for the fence static constexpr const Duration kFenceWaitStartDelayValidated{150us}; diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp index 2d66d3cf92..d22ce17258 100644 --- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp +++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp @@ -42,12 +42,12 @@ public: void fakeBasicFrameTiming(TimePoint startTime, Duration vsyncPeriod); void setExpectedTiming(Duration totalFrameTargetDuration, TimePoint expectedPresentTime); Duration getFenceWaitDelayDuration(bool skipValidate); + Duration getErrorMargin(); protected: TestableSurfaceFlinger mFlinger; std::unique_ptr mPowerAdvisor; NiceMock* mMockAidlWrapper; - Duration kErrorMargin = 1ms; }; void PowerAdvisorTest::SetUp() FTL_FAKE_GUARD(mPowerAdvisor->mPowerHalMutex) { @@ -77,6 +77,8 @@ void PowerAdvisorTest::fakeBasicFrameTiming(TimePoint startTime, Duration vsyncP mPowerAdvisor->setCommitStart(startTime); mPowerAdvisor->setFrameDelay(0ns); mPowerAdvisor->setTargetWorkDuration(vsyncPeriod); + ON_CALL(*mMockAidlWrapper, getTargetWorkDuration()) + .WillByDefault(Return(std::make_optional(vsyncPeriod))); } Duration PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) { @@ -84,6 +86,10 @@ Duration PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) { : PowerAdvisor::kFenceWaitStartDelayValidated); } +Duration PowerAdvisorTest::getErrorMargin() { + return mPowerAdvisor->sTargetSafetyMargin; +} + namespace { TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) { @@ -109,7 +115,7 @@ TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) { // increment the frame startTime += vsyncPeriod; - const Duration expectedDuration = kErrorMargin + presentDuration + postCompDuration; + const Duration expectedDuration = getErrorMargin() + presentDuration + postCompDuration; EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1); fakeBasicFrameTiming(startTime, vsyncPeriod); @@ -145,7 +151,7 @@ TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) { // increment the frame startTime += vsyncPeriod; - const Duration expectedDuration = kErrorMargin + presentDuration + + const Duration expectedDuration = getErrorMargin() + presentDuration + getFenceWaitDelayDuration(false) - hwcBlockedDuration + postCompDuration; EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1); @@ -185,7 +191,7 @@ TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) { // increment the frame startTime += vsyncPeriod; - const Duration expectedDuration = kErrorMargin + presentDuration + postCompDuration; + const Duration expectedDuration = getErrorMargin() + presentDuration + postCompDuration; EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1); fakeBasicFrameTiming(startTime, vsyncPeriod); diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h index 5654691884..3ed85e0b1f 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h @@ -47,6 +47,8 @@ public: MOCK_METHOD(void, sendActualWorkDuration, (Duration actualDuration, TimePoint timestamp), (override)); MOCK_METHOD(bool, shouldReconnectHAL, (), (override)); + MOCK_METHOD(std::vector, getPowerHintSessionThreadIds, (), (override)); + MOCK_METHOD(std::optional, getTargetWorkDuration, (), (override)); }; } // namespace android::Hwc2::mock \ No newline at end of file -- GitLab From 4e49f18a515173523992f359a6a74feeb7b822a7 Mon Sep 17 00:00:00 2001 From: Dichen Zhang Date: Tue, 21 Mar 2023 23:33:41 +0000 Subject: [PATCH 0042/1187] JPEG/R: add restriction to max_display_boost input from user Change-Id: I82c24c285fb01cab57ec004f1440ac9b5adacc39 --- libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h | 9 +++++++-- libs/jpegrecoverymap/jpegr.cpp | 8 +++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h index 1ab1dd7245..6262e18479 100644 --- a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h +++ b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegr.h @@ -19,6 +19,10 @@ #include "jpegrerrorcode.h" +#ifndef FLT_MAX +#define FLT_MAX 0x1.fffffep127f +#endif + namespace android::jpegrecoverymap { // Color gamuts for image data @@ -206,7 +210,8 @@ public: * * @param compressed_jpegr_image compressed JPEGR image. * @param dest destination of the uncompressed JPEGR image. - * @param max_display_boost (optional) the maximum available boost supported by a display + * @param max_display_boost (optional) the maximum available boost supported by a display, + * the value must be greater than or equal to 1.0. * @param exif destination of the decoded EXIF metadata. The default value is NULL where the decoder will do nothing about it. If configured not NULL the decoder will write EXIF data into this structure. The format is defined in {@code jpegr_exif_struct} @@ -235,7 +240,7 @@ public: */ status_t decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, jr_uncompressed_ptr dest, - float max_display_boost = -1.0f, + float max_display_boost = FLT_MAX, jr_exif_ptr exif = nullptr, jpegr_output_format output_format = JPEGR_OUTPUT_HDR_LINEAR, jr_uncompressed_ptr recovery_map = nullptr, diff --git a/libs/jpegrecoverymap/jpegr.cpp b/libs/jpegrecoverymap/jpegr.cpp index e395d51a26..6863f5339a 100644 --- a/libs/jpegrecoverymap/jpegr.cpp +++ b/libs/jpegrecoverymap/jpegr.cpp @@ -339,6 +339,10 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, return ERROR_JPEGR_INVALID_NULL_PTR; } + if (max_display_boost < 1.0f) { + return ERROR_JPEGR_INVALID_INPUT_TYPE; + } + if (output_format == JPEGR_OUTPUT_SDR) { JpegDecoderHelper jpeg_decoder; if (!jpeg_decoder.decompressImage(compressed_jpegr_image->data, compressed_jpegr_image->length, @@ -680,9 +684,7 @@ status_t JpegR::applyRecoveryMap(jr_uncompressed_ptr uncompressed_yuv_420_image, dest->width = uncompressed_yuv_420_image->width; dest->height = uncompressed_yuv_420_image->height; ShepardsIDW idwTable(kMapDimensionScaleFactor); - float display_boost = max_display_boost > 0 ? - std::min(max_display_boost, metadata->maxContentBoost) - : metadata->maxContentBoost; + float display_boost = std::min(max_display_boost, metadata->maxContentBoost); RecoveryLUT recoveryLUT(metadata, display_boost); JobQueue jobQueue; -- GitLab From d0dfa170edecd026d52c48d9eb3fa2a4b1ae6819 Mon Sep 17 00:00:00 2001 From: Ayushi Khopkar Date: Mon, 20 Mar 2023 15:36:27 +0530 Subject: [PATCH 0043/1187] Updated fuzz_config in Android.bp file Added new fields in fuzz_config like - hotlists, description, vector, service_privilege, users, fuzzed_code_usage, etc. Bug: 271384401 Test: Build the updated fuzz targets Change-Id: Ibacc876f7afb0e6e2549711df41e6440be4d69a8 (cherry picked from commit 76a0cd25e41b636c25b59ccda27183f3106fb911) --- libs/gui/fuzzer/Android.bp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp index 82e1b5ae4d..872b069b36 100644 --- a/libs/gui/fuzzer/Android.bp +++ b/libs/gui/fuzzer/Android.bp @@ -72,6 +72,14 @@ cc_defaults { "android-media-fuzzing-reports@google.com", ], componentid: 155276, + hotlists: [ + "4593311", + ], + description: "The fuzzer targets the APIs of libgui library", + vector: "local_no_privileges_required", + service_privilege: "privileged", + users: "multi_user", + fuzzed_code_usage: "shipped", }, } -- GitLab From 4cb1d536771379d244560b37ce772a1e432305c3 Mon Sep 17 00:00:00 2001 From: Ayushi Khopkar Date: Mon, 20 Mar 2023 18:52:31 +0530 Subject: [PATCH 0044/1187] Updated fuzz_config in Android.bp file Added new fields in fuzz_config like - hotlists, description, vector, service_privilege, users, fuzzed_code_usage, etc. Bug: 271384401 Test: Build the updated fuzz targets Change-Id: I51e71c9689662cefd9ecf9cd9f3d34f6c1aa002b (cherry picked from commit b3daa1061b6d8377fe0bf71ea222499ad4b985d9) --- services/inputflinger/tests/fuzzers/Android.bp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp index 55c2db6c91..ae70e67cbb 100644 --- a/services/inputflinger/tests/fuzzers/Android.bp +++ b/services/inputflinger/tests/fuzzers/Android.bp @@ -73,6 +73,15 @@ cc_defaults { ], fuzz_config: { cc: ["android-framework-input@google.com"], + componentid: 155276, + hotlists: [ + "4593311", + ], + description: "The fuzzer targets the APIs of libinputflinger library", + vector: "local_no_privileges_required", + service_privilege: "privileged", + users: "multi_user", + fuzzed_code_usage: "shipped", }, } -- GitLab From b8b08a31c14e0d03d6efe0ab95ab3a2941b963bb Mon Sep 17 00:00:00 2001 From: Emil Bengtsson Date: Thu, 9 Feb 2023 13:46:40 +0100 Subject: [PATCH 0045/1187] Cancel dumpstate if client disconnects Bug: 268200878 Test: manual Change-Id: I834c0af0852c0e80ebdad8f2f90b698434e4d2ed (cherry picked from commit 3d509846cfa9430575f9eb4dfb46957b04788638) --- cmds/bugreportz/main.cpp | 17 +++++++++++++++++ cmds/dumpstate/dumpstate.cpp | 6 +++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cmds/bugreportz/main.cpp b/cmds/bugreportz/main.cpp index cd2652c717..790556ce5a 100644 --- a/cmds/bugreportz/main.cpp +++ b/cmds/bugreportz/main.cpp @@ -75,6 +75,23 @@ int main(int argc, char* argv[]) { return EXIT_FAILURE; } + // Wait a little while for dumpstatez to stop if it is running + bool dumpstate_running = false; + for (int i = 0; i < 20; i++) { + char buf[PROPERTY_VALUE_MAX]; + property_get("init.svc.dumpstatez", buf, ""); + dumpstate_running = strcmp(buf, "running") == 0; + + if (!dumpstate_running) break; + + sleep(1); + } + + if (dumpstate_running) { + fprintf(stderr, "FAIL:dumpstatez service is already running\n"); + return EXIT_FAILURE; + } + // TODO: code below was copy-and-pasted from bugreport.cpp (except by the // timeout value); // should be reused instead. diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index baf8e424c3..2a7089ed8b 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -2593,7 +2593,11 @@ static void ShowUsage() { } static void register_sig_handler() { - signal(SIGPIPE, SIG_IGN); + signal(SIGPIPE, [](int) { + MYLOGE("Connection with client lost, canceling."); + ds.Cancel(); + abort(); + }); } bool Dumpstate::FinishZipFile() { -- GitLab From 09a8fe42ba1d218c2f445e4fd5bc387e260ae067 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 21 Jul 2022 17:27:03 -0700 Subject: [PATCH 0046/1187] Convert tool type to enum class For better type safety, use enum class when sending tool type. Bug: 198472780 Test: atest libinput_tests inputflinger_tests Change-Id: I371f08087b9513b6f75966c124de77bc12f8324e --- include/input/Input.h | 24 +- include/input/InputTransport.h | 1 - libs/input/Input.cpp | 33 +- libs/input/InputTransport.cpp | 9 +- libs/input/MotionPredictor.cpp | 7 +- libs/input/tests/InputEvent_test.cpp | 10 +- .../tests/InputPublisherAndConsumer_test.cpp | 2 +- libs/input/tests/MotionPredictor_test.cpp | 2 +- libs/input/tests/TouchResampling_test.cpp | 2 +- libs/input/tests/VelocityTracker_test.cpp | 2 +- .../inputflinger/InputCommonConverter.cpp | 17 +- services/inputflinger/NotifyArgs.cpp | 6 +- .../PreferStylusOverTouchBlocker.cpp | 4 +- .../UnwantedInteractionBlocker.cpp | 18 +- .../benchmarks/InputDispatcher_benchmarks.cpp | 4 +- .../dispatcher/InputDispatcher.cpp | 7 +- .../inputflinger/reader/include/StylusState.h | 4 +- .../reader/mapper/CursorInputMapper.cpp | 2 +- .../mapper/ExternalStylusInputMapper.cpp | 4 +- .../reader/mapper/JoystickInputMapper.cpp | 2 +- .../reader/mapper/MultiTouchInputMapper.cpp | 17 +- .../mapper/RotaryEncoderInputMapper.cpp | 2 +- .../reader/mapper/SingleTouchInputMapper.cpp | 6 +- .../reader/mapper/TouchInputMapper.cpp | 40 ++- .../reader/mapper/TouchInputMapper.h | 4 +- .../MultiTouchMotionAccumulator.cpp | 10 +- .../accumulator/MultiTouchMotionAccumulator.h | 2 +- .../accumulator/TouchButtonAccumulator.cpp | 12 +- .../accumulator/TouchButtonAccumulator.h | 2 +- .../reader/mapper/gestures/GestureConverter.h | 8 +- .../gestures/HardwareStateConverter.cpp | 2 +- .../tests/GestureConverter_test.cpp | 116 +++--- .../tests/InputDispatcher_test.cpp | 328 ++++++++--------- .../tests/InputProcessorConverter_test.cpp | 2 +- .../tests/InputProcessor_test.cpp | 2 +- .../inputflinger/tests/InputReader_test.cpp | 330 +++++++++--------- .../inputflinger/tests/NotifyArgs_test.cpp | 2 +- .../tests/PreferStylusOverTouch_test.cpp | 14 +- .../tests/TestInputListenerMatchers.h | 4 +- .../tests/UnwantedInteractionBlocker_test.cpp | 26 +- .../tests/fuzzers/InputClassifierFuzzer.cpp | 2 +- .../tests/fuzzers/MapperHelpers.h | 8 + .../tests/fuzzers/MultiTouchInputFuzzer.cpp | 2 +- 43 files changed, 534 insertions(+), 567 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index e8af5f7d46..a033535f4b 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -216,7 +216,21 @@ std::string inputEventSourceToString(int32_t source); bool isFromSource(uint32_t source, uint32_t test); -bool isStylusToolType(uint32_t toolType); +/** + * The pointer tool type. + */ +enum class ToolType { + UNKNOWN = AMOTION_EVENT_TOOL_TYPE_UNKNOWN, + FINGER = AMOTION_EVENT_TOOL_TYPE_FINGER, + STYLUS = AMOTION_EVENT_TOOL_TYPE_STYLUS, + MOUSE = AMOTION_EVENT_TOOL_TYPE_MOUSE, + ERASER = AMOTION_EVENT_TOOL_TYPE_ERASER, + PALM = AMOTION_EVENT_TOOL_TYPE_PALM, + ftl_first = UNKNOWN, + ftl_last = PALM, +}; + +bool isStylusToolType(ToolType toolType); /* * Flags that flow alongside events in the input dispatch system to help with certain @@ -320,8 +334,6 @@ enum class MotionClassification : uint8_t { */ const char* motionClassificationToString(MotionClassification classification); -const char* motionToolTypeToString(int32_t toolType); - /** * Portion of FrameMetrics timeline of interest to input code. */ @@ -448,11 +460,11 @@ struct PointerProperties { int32_t id; // The pointer tool type. - int32_t toolType; + ToolType toolType; inline void clear() { id = -1; - toolType = 0; + toolType = ToolType::UNKNOWN; } bool operator==(const PointerProperties& other) const; @@ -638,7 +650,7 @@ public: return mPointerProperties[pointerIndex].id; } - inline int32_t getToolType(size_t pointerIndex) const { + inline ToolType getToolType(size_t pointerIndex) const { return mPointerProperties[pointerIndex].toolType; } diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index a1be542d7b..4f53c36d6f 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -669,7 +669,6 @@ private: static void addSample(MotionEvent* event, const InputMessage* msg); static bool canAddSample(const Batch& batch, const InputMessage* msg); static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time); - static bool shouldResampleTool(int32_t toolType); static bool isTouchResamplingEnabled(); }; diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 53b22cb883..4dbf575490 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -79,25 +79,6 @@ const char* motionClassificationToString(MotionClassification classification) { } } -const char* motionToolTypeToString(int32_t toolType) { - switch (toolType) { - case AMOTION_EVENT_TOOL_TYPE_UNKNOWN: - return "UNKNOWN"; - case AMOTION_EVENT_TOOL_TYPE_FINGER: - return "FINGER"; - case AMOTION_EVENT_TOOL_TYPE_STYLUS: - return "STYLUS"; - case AMOTION_EVENT_TOOL_TYPE_MOUSE: - return "MOUSE"; - case AMOTION_EVENT_TOOL_TYPE_ERASER: - return "ERASER"; - case AMOTION_EVENT_TOOL_TYPE_PALM: - return "PALM"; - default: - return "INVALID"; - } -} - // --- IdGenerator --- #if defined(__ANDROID__) [[maybe_unused]] @@ -256,8 +237,8 @@ bool isFromSource(uint32_t source, uint32_t test) { return (source & test) == test; } -bool isStylusToolType(uint32_t toolType) { - return toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS || toolType == AMOTION_EVENT_TOOL_TYPE_ERASER; +bool isStylusToolType(ToolType toolType) { + return toolType == ToolType::STYLUS || toolType == ToolType::ERASER; } VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) { @@ -810,7 +791,7 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) { mPointerProperties.push_back({}); PointerProperties& properties = mPointerProperties.back(); properties.id = parcel->readInt32(); - properties.toolType = parcel->readInt32(); + properties.toolType = static_cast(parcel->readInt32()); } while (sampleCount > 0) { @@ -866,7 +847,7 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const { for (size_t i = 0; i < pointerCount; i++) { const PointerProperties& properties = mPointerProperties[i]; parcel->writeInt32(properties.id); - parcel->writeInt32(properties.toolType); + parcel->writeInt32(static_cast(properties.toolType)); } const PointerCoords* pc = mSamplePointerCoords.data(); @@ -1030,9 +1011,9 @@ std::ostream& operator<<(std::ostream& out, const MotionEvent& event) { out << ", x[" << i << "]=" << x; out << ", y[" << i << "]=" << y; } - int toolType = event.getToolType(i); - if (toolType != AMOTION_EVENT_TOOL_TYPE_FINGER) { - out << ", toolType[" << i << "]=" << toolType; + ToolType toolType = event.getToolType(i); + if (toolType != ToolType::FINGER) { + out << ", toolType[" << i << "]=" << ftl::enum_string(toolType); } } if (event.getButtonState() != 0) { diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 311b2441a4..f6b4648d67 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -145,6 +145,10 @@ inline static const char* toString(bool value) { return value ? "true" : "false"; } +static bool shouldResampleTool(ToolType toolType) { + return toolType == ToolType::FINGER || toolType == ToolType::UNKNOWN; +} + // --- InputMessage --- bool InputMessage::isValid(size_t actualSize) const { @@ -1274,11 +1278,6 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, event->addSample(sampleTime, touchState.lastResample.pointers); } -bool InputConsumer::shouldResampleTool(int32_t toolType) { - return toolType == AMOTION_EVENT_TOOL_TYPE_FINGER - || toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) { ALOGD_IF(DEBUG_TRANSPORT_CONSUMER, "channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s", diff --git a/libs/input/MotionPredictor.cpp b/libs/input/MotionPredictor.cpp index 0d4213c745..a425b936ca 100644 --- a/libs/input/MotionPredictor.cpp +++ b/libs/input/MotionPredictor.cpp @@ -30,6 +30,7 @@ #include #include +#include #include namespace android { @@ -108,10 +109,10 @@ android::base::Result MotionPredictor::record(const MotionEvent& event) { return {}; } - const int32_t toolType = event.getPointerProperties(0)->toolType; - if (toolType != AMOTION_EVENT_TOOL_TYPE_STYLUS) { + const ToolType toolType = event.getPointerProperties(0)->toolType; + if (toolType != ToolType::STYLUS) { ALOGD_IF(isDebug(), "Prediction not supported for non-stylus tool: %s", - motionToolTypeToString(toolType)); + ftl::enum_string(toolType).c_str()); return {}; } diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp index 2132dc1bdf..59125dd428 100644 --- a/libs/input/tests/InputEvent_test.cpp +++ b/libs/input/tests/InputEvent_test.cpp @@ -259,10 +259,10 @@ void MotionEventTest::SetUp() { mPointerProperties[0].clear(); mPointerProperties[0].id = 1; - mPointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerProperties[0].toolType = ToolType::FINGER; mPointerProperties[1].clear(); mPointerProperties[1].id = 2; - mPointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + mPointerProperties[1].toolType = ToolType::STYLUS; mSamples[0].pointerCoords[0].clear(); mSamples[0].pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 10); @@ -366,9 +366,9 @@ void MotionEventTest::assertEqualsEventWithHistory(const MotionEvent* event) { ASSERT_EQ(2U, event->getPointerCount()); ASSERT_EQ(1, event->getPointerId(0)); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, event->getToolType(0)); + ASSERT_EQ(ToolType::FINGER, event->getToolType(0)); ASSERT_EQ(2, event->getPointerId(1)); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, event->getToolType(1)); + ASSERT_EQ(ToolType::STYLUS, event->getToolType(1)); ASSERT_EQ(2U, event->getHistorySize()); @@ -692,7 +692,7 @@ TEST_F(MotionEventTest, Transform) { MotionEvent createMotionEvent(int32_t source, uint32_t action, float x, float y, float dx, float dy, const ui::Transform& transform, const ui::Transform& rawTransform) { std::vector pointerProperties; - pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER}); + pointerProperties.push_back(PointerProperties{/*id=*/0, ToolType::FINGER}); std::vector pointerCoords; pointerCoords.emplace_back().clear(); pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_X, x); diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 5d8b9700b3..965fda73b4 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -172,7 +172,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { for (size_t i = 0; i < pointerCount; i++) { pointerProperties[i].clear(); pointerProperties[i].id = (i + 2) % pointerCount; - pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + pointerProperties[i].toolType = ToolType::FINGER; pointerCoords[i].clear(); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i); diff --git a/libs/input/tests/MotionPredictor_test.cpp b/libs/input/tests/MotionPredictor_test.cpp index c61efbf9ed..7a62f5ec58 100644 --- a/libs/input/tests/MotionPredictor_test.cpp +++ b/libs/input/tests/MotionPredictor_test.cpp @@ -45,7 +45,7 @@ static MotionEvent getMotionEvent(int32_t action, float x, float y, PointerProperties properties; properties.clear(); properties.id = i; - properties.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + properties.toolType = ToolType::STYLUS; pointerProperties.push_back(properties); PointerCoords coords; coords.clear(); diff --git a/libs/input/tests/TouchResampling_test.cpp b/libs/input/tests/TouchResampling_test.cpp index 7cb9526af0..655de803ae 100644 --- a/libs/input/tests/TouchResampling_test.cpp +++ b/libs/input/tests/TouchResampling_test.cpp @@ -99,7 +99,7 @@ void TouchResamplingTest::publishSimpleMotionEvent(int32_t action, nsecs_t event properties.push_back({}); properties.back().clear(); properties.back().id = pointer.id; - properties.back().toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + properties.back().toolType = ToolType::FINGER; coords.push_back({}); coords.back().clear(); diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index 2a424afeee..ffebff1e65 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -208,7 +208,7 @@ static std::vector createTouchMotionEventStream( coords[pointerIndex].isResampled = position.isResampled; properties[pointerIndex].id = pointerId; - properties[pointerIndex].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + properties[pointerIndex].toolType = ToolType::FINGER; pointerIndex++; } EXPECT_EQ(pointerIndex, pointerCount); diff --git a/services/inputflinger/InputCommonConverter.cpp b/services/inputflinger/InputCommonConverter.cpp index 0c93f5ce40..2437d0fcfc 100644 --- a/services/inputflinger/InputCommonConverter.cpp +++ b/services/inputflinger/InputCommonConverter.cpp @@ -200,17 +200,12 @@ static common::Button getButtonState(int32_t buttonState) { return static_cast(buttonState); } -static common::ToolType getToolType(int32_t toolType) { - static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_UNKNOWN) == - common::ToolType::UNKNOWN); - static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_FINGER) == - common::ToolType::FINGER); - static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_STYLUS) == - common::ToolType::STYLUS); - static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_MOUSE) == - common::ToolType::MOUSE); - static_assert(static_cast(AMOTION_EVENT_TOOL_TYPE_ERASER) == - common::ToolType::ERASER); +static common::ToolType getToolType(ToolType toolType) { + static_assert(static_cast(ToolType::UNKNOWN) == common::ToolType::UNKNOWN); + static_assert(static_cast(ToolType::FINGER) == common::ToolType::FINGER); + static_assert(static_cast(ToolType::STYLUS) == common::ToolType::STYLUS); + static_assert(static_cast(ToolType::MOUSE) == common::ToolType::MOUSE); + static_assert(static_cast(ToolType::ERASER) == common::ToolType::ERASER); return static_cast(toolType); } diff --git a/services/inputflinger/NotifyArgs.cpp b/services/inputflinger/NotifyArgs.cpp index b192ad73c3..5f2a22f467 100644 --- a/services/inputflinger/NotifyArgs.cpp +++ b/services/inputflinger/NotifyArgs.cpp @@ -161,9 +161,9 @@ std::string NotifyMotionArgs::dump() const { StringPrintf("id=%" PRIu32 " x=%.1f y=%.1f pressure=%.1f", pointerProperties[i].id, pointerCoords[i].getX(), pointerCoords[i].getY(), pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - const int32_t toolType = pointerProperties[i].toolType; - if (toolType != AMOTION_EVENT_TOOL_TYPE_FINGER) { - coords += StringPrintf(" toolType=%s", motionToolTypeToString(toolType)); + const ToolType toolType = pointerProperties[i].toolType; + if (toolType != ToolType::FINGER) { + coords += StringPrintf(" toolType=%s", ftl::enum_string(toolType).c_str()); } const float major = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR); const float minor = pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR); diff --git a/services/inputflinger/PreferStylusOverTouchBlocker.cpp b/services/inputflinger/PreferStylusOverTouchBlocker.cpp index ddd514676b..fbd296c131 100644 --- a/services/inputflinger/PreferStylusOverTouchBlocker.cpp +++ b/services/inputflinger/PreferStylusOverTouchBlocker.cpp @@ -24,11 +24,11 @@ static std::pair checkToolType(const NotifyMotionArgs& args) { bool hasTouch = false; for (size_t i = 0; i < args.pointerCount; i++) { // Make sure we are canceling stylus pointers - const int32_t toolType = args.pointerProperties[i].toolType; + const ToolType toolType = args.pointerProperties[i].toolType; if (isStylusToolType(toolType)) { hasStylus = true; } - if (toolType == AMOTION_EVENT_TOOL_TYPE_FINGER) { + if (toolType == ToolType::FINGER) { hasTouch = true; } } diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp index c170b81475..ae20f862dc 100644 --- a/services/inputflinger/UnwantedInteractionBlocker.cpp +++ b/services/inputflinger/UnwantedInteractionBlocker.cpp @@ -18,6 +18,7 @@ #include "UnwantedInteractionBlocker.h" #include +#include #include #include #include @@ -98,18 +99,21 @@ static bool isPalmRejectionEnabled() { return false; } -static int getLinuxToolCode(int toolType) { +static int getLinuxToolCode(ToolType toolType) { switch (toolType) { - case AMOTION_EVENT_TOOL_TYPE_STYLUS: + case ToolType::STYLUS: return BTN_TOOL_PEN; - case AMOTION_EVENT_TOOL_TYPE_ERASER: + case ToolType::ERASER: return BTN_TOOL_RUBBER; - case AMOTION_EVENT_TOOL_TYPE_FINGER: - return BTN_TOOL_FINGER; - default: - ALOGW("Got tool type %" PRId32 ", converting to BTN_TOOL_FINGER", toolType); + case ToolType::FINGER: return BTN_TOOL_FINGER; + case ToolType::UNKNOWN: + case ToolType::MOUSE: + case ToolType::PALM: + break; } + ALOGW("Got tool type %s, converting to BTN_TOOL_FINGER", ftl::enum_string(toolType).c_str()); + return BTN_TOOL_FINGER; } static int32_t getActionUpForPointerId(const NotifyMotionArgs& args, int32_t pointerId) { diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index f03c837f56..58324c4762 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -207,7 +207,7 @@ static MotionEvent generateMotionEvent() { pointerProperties[0].clear(); pointerProperties[0].id = 0; - pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + pointerProperties[0].toolType = ToolType::FINGER; pointerCoords[0].clear(); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100); @@ -235,7 +235,7 @@ static NotifyMotionArgs generateMotionArgs() { pointerProperties[0].clear(); pointerProperties[0].id = 0; - pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + pointerProperties[0].toolType = ToolType::FINGER; pointerCoords[0].clear(); pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 3d3a50a373..3cc2ed9f42 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -1862,11 +1862,12 @@ void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionE entry.yPrecision, entry.downTime); for (uint32_t i = 0; i < entry.pointerCount; i++) { - ALOGD(" Pointer %d: id=%d, toolType=%d, " + ALOGD(" Pointer %d: id=%d, toolType=%s, " "x=%f, y=%f, pressure=%f, size=%f, " "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " "orientation=%f", - i, entry.pointerProperties[i].id, entry.pointerProperties[i].toolType, + i, entry.pointerProperties[i].id, + ftl::enum_string(entry.pointerProperties[i].toolType).c_str(), entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), entry.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), @@ -4178,7 +4179,7 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { ALOGD(" Pointer %d: id=%d, toolType=%s, x=%f, y=%f, pressure=%f, size=%f, " "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, orientation=%f", i, args->pointerProperties[i].id, - motionToolTypeToString(args->pointerProperties[i].toolType), + ftl::enum_string(args->pointerProperties[i].toolType).c_str(), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), diff --git a/services/inputflinger/reader/include/StylusState.h b/services/inputflinger/reader/include/StylusState.h index ff15e0c660..d042784c9e 100644 --- a/services/inputflinger/reader/include/StylusState.h +++ b/services/inputflinger/reader/include/StylusState.h @@ -33,8 +33,8 @@ struct StylusState { std::optional pressure{}; /* The state of the stylus buttons as a bitfield (e.g. AMOTION_EVENT_BUTTON_SECONDARY). */ uint32_t buttons{}; - /* Which tool type the stylus is currently using (e.g. AMOTION_EVENT_TOOL_TYPE_ERASER). */ - int32_t toolType{AMOTION_EVENT_TOOL_TYPE_UNKNOWN}; + /* Which tool type the stylus is currently using (e.g. ToolType::ERASER). */ + ToolType toolType{ToolType::UNKNOWN}; void clear() { *this = StylusState{}; } }; diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 83cf28798c..a3fdcdf19d 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -350,7 +350,7 @@ std::list CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { PointerProperties pointerProperties; pointerProperties.clear(); pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE; + pointerProperties.toolType = ToolType::MOUSE; PointerCoords pointerCoords; pointerCoords.clear(); diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp index a44d15bcdf..99e6cf9a74 100644 --- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp +++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp @@ -77,8 +77,8 @@ std::list ExternalStylusInputMapper::sync(nsecs_t when) { mStylusState.when = when; mStylusState.toolType = mTouchButtonAccumulator.getToolType(); - if (mStylusState.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + if (mStylusState.toolType == ToolType::UNKNOWN) { + mStylusState.toolType = ToolType::STYLUS; } if (mRawPressureAxis.valid) { diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp index 7724cf7ed5..f65cdcb677 100644 --- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp +++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp @@ -321,7 +321,7 @@ std::list JoystickInputMapper::sync(nsecs_t when, nsecs_t readTime, PointerProperties pointerProperties; pointerProperties.clear(); pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + pointerProperties.toolType = ToolType::UNKNOWN; PointerCoords pointerCoords; pointerCoords.clear(); diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp index 33e72c7c6f..e87128825d 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp @@ -77,7 +77,7 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { continue; } - if (inSlot.getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) { + if (inSlot.getToolType() == ToolType::PALM) { std::optional id = getActiveBitId(inSlot); if (id) { outState->rawPointerData.canceledIdBits.markBit(id.value()); @@ -112,12 +112,12 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { outPointer.tiltY = 0; outPointer.toolType = inSlot.getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + if (outPointer.toolType == ToolType::UNKNOWN) { outPointer.toolType = mTouchButtonAccumulator.getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + if (outPointer.toolType == ToolType::UNKNOWN) { + outPointer.toolType = ToolType::FINGER; } - } else if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS && !mStylusMtToolSeen) { + } else if (outPointer.toolType == ToolType::STYLUS && !mStylusMtToolSeen) { mStylusMtToolSeen = true; // The multi-touch device produced a stylus event with MT_TOOL_PEN. Dynamically // re-configure this input device so that we add SOURCE_STYLUS if we haven't already. @@ -130,12 +130,11 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { bumpGeneration(); } } - if (shouldSimulateStylusWithTouch() && - outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER) { - outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + if (shouldSimulateStylusWithTouch() && outPointer.toolType == ToolType::FINGER) { + outPointer.toolType = ToolType::STYLUS; } - bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && + bool isHovering = mTouchButtonAccumulator.getToolType() != ToolType::MOUSE && (mTouchButtonAccumulator.isHovering() || (mRawPointerAxes.pressure.valid && inSlot.getPressure() <= 0)); outPointer.isHovering = isHovering; diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp index 94cc1457a9..c0a35b196e 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp @@ -121,7 +121,7 @@ std::list RotaryEncoderInputMapper::sync(nsecs_t when, nsecs_t readT PointerProperties pointerProperties; pointerProperties.clear(); pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + pointerProperties.toolType = ToolType::UNKNOWN; uint32_t policyFlags = 0; if (getDeviceContext().isExternal()) { diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp b/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp index 13ad224111..f13417a93b 100644 --- a/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/SingleTouchInputMapper.cpp @@ -41,7 +41,7 @@ void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { outState->rawPointerData.pointerCount = 1; outState->rawPointerData.idToIndex[0] = 0; - bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && + bool isHovering = mTouchButtonAccumulator.getToolType() != ToolType::MOUSE && (mTouchButtonAccumulator.isHovering() || (mRawPointerAxes.pressure.valid && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); @@ -61,8 +61,8 @@ void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX(); outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY(); outPointer.toolType = mTouchButtonAccumulator.getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + if (outPointer.toolType == ToolType::UNKNOWN) { + outPointer.toolType = ToolType::FINGER; } outPointer.isHovering = isHovering; } diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index df7ba49b4d..073c18babb 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -229,11 +229,12 @@ void TouchInputMapper::dump(std::string& dump) { 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=%d, isHovering=%s\n", + "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, pointer.toolType, toString(pointer.isHovering)); + pointer.distance, ftl::enum_string(pointer.toolType).c_str(), + toString(pointer.isHovering)); } dump += StringPrintf(INDENT3 "Last Cooked Button State: 0x%08x\n", @@ -248,7 +249,7 @@ void TouchInputMapper::dump(std::string& dump) { "pressure=%0.3f, touchMajor=%0.3f, touchMinor=%0.3f, " "toolMajor=%0.3f, toolMinor=%0.3f, " "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " - "toolType=%d, isHovering=%s\n", + "toolType=%s, isHovering=%s\n", i, pointerProperties.id, pointerCoords.getX(), pointerCoords.getY(), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y), @@ -260,7 +261,7 @@ void TouchInputMapper::dump(std::string& dump) { pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), - pointerProperties.toolType, + ftl::enum_string(pointerProperties.toolType).c_str(), toString(mLastCookedState.cookedPointerData.isHovering(i))); } @@ -1582,10 +1583,10 @@ std::list TouchInputMapper::cookAndDispatch(nsecs_t when, nsecs_t re mCurrentRawState.rawPointerData.pointerForId(id); if (isStylusToolType(pointer.toolType)) { mCurrentCookedState.stylusIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER || - pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + } else if (pointer.toolType == ToolType::FINGER || + pointer.toolType == ToolType::UNKNOWN) { mCurrentCookedState.fingerIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { + } else if (pointer.toolType == ToolType::MOUSE) { mCurrentCookedState.mouseIdBits.markBit(id); } } @@ -1704,7 +1705,7 @@ void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) { PointerCoords& coords = currentPointerData.editPointerCoordsWithId(*mFusedStylusPointerId); coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); - if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + if (mExternalStylusState.toolType != ToolType::UNKNOWN) { PointerProperties& properties = currentPointerData.editPointerPropertiesWithId(*mFusedStylusPointerId); properties.toolType = mExternalStylusState.toolType; @@ -2678,7 +2679,7 @@ std::list TouchInputMapper::dispatchPointerGestures(nsecs_t when, ns PointerProperties pointerProperties; pointerProperties.clear(); pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + pointerProperties.toolType = ToolType::FINGER; PointerCoords pointerCoords; pointerCoords.clear(); @@ -2887,7 +2888,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; mPointerGesture.currentGestureProperties[0].clear(); mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureProperties[0].toolType = ToolType::FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); @@ -2922,8 +2923,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.currentGestureProperties[0].clear(); mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureProperties[0].toolType = ToolType::FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, mPointerGesture.tapX); @@ -3010,7 +3010,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; mPointerGesture.currentGestureProperties[0].clear(); mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureProperties[0].toolType = ToolType::FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); @@ -3040,9 +3040,10 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; const PointerProperties& properties = mPointerGesture.currentGestureProperties[index]; const PointerCoords& coords = mPointerGesture.currentGestureCoords[index]; - ALOGD(" currentGesture[%d]: index=%d, toolType=%d, " + ALOGD(" currentGesture[%d]: index=%d, toolType=%s, " "x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X), + id, index, ftl::enum_string(properties.toolType).c_str(), + coords.getAxisValue(AMOTION_EVENT_AXIS_X), coords.getAxisValue(AMOTION_EVENT_AXIS_Y), coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); } @@ -3051,9 +3052,10 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPrevi uint32_t index = mPointerGesture.lastGestureIdToIndex[id]; const PointerProperties& properties = mPointerGesture.lastGestureProperties[index]; const PointerCoords& coords = mPointerGesture.lastGestureCoords[index]; - ALOGD(" lastGesture[%d]: index=%d, toolType=%d, " + ALOGD(" lastGesture[%d]: index=%d, toolType=%s, " "x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X), + id, index, ftl::enum_string(properties.toolType).c_str(), + coords.getAxisValue(AMOTION_EVENT_AXIS_X), coords.getAxisValue(AMOTION_EVENT_AXIS_Y), coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); } @@ -3342,7 +3344,7 @@ void TouchInputMapper::prepareMultiFingerPointerGestures(nsecs_t when, bool* can mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; mPointerGesture.currentGestureProperties[0].clear(); mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureProperties[0].toolType = ToolType::FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX); @@ -3435,7 +3437,7 @@ void TouchInputMapper::prepareMultiFingerPointerGestures(nsecs_t when, bool* can mPointerGesture.currentGestureProperties[i].clear(); mPointerGesture.currentGestureProperties[i].id = gestureId; - mPointerGesture.currentGestureProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + mPointerGesture.currentGestureProperties[i].toolType = ToolType::FINGER; mPointerGesture.currentGestureCoords[i].clear(); mPointerGesture.currentGestureCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX + diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index ae7faa9909..bc358b97e6 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -78,8 +78,8 @@ struct RawPointerData { int32_t distance{}; int32_t tiltX{}; int32_t tiltY{}; - // A fully decoded AMOTION_EVENT_TOOL_TYPE constant. - int32_t toolType{AMOTION_EVENT_TOOL_TYPE_UNKNOWN}; + // A fully decoded ToolType constant. + ToolType toolType{ToolType::UNKNOWN}; bool isHovering{false}; }; diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp index f6a42bdea0..f70be72741 100644 --- a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp +++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp @@ -154,18 +154,18 @@ void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Sl // --- MultiTouchMotionAccumulator::Slot --- -int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { +ToolType MultiTouchMotionAccumulator::Slot::getToolType() const { if (mHaveAbsMtToolType) { switch (mAbsMtToolType) { case MT_TOOL_FINGER: - return AMOTION_EVENT_TOOL_TYPE_FINGER; + return ToolType::FINGER; case MT_TOOL_PEN: - return AMOTION_EVENT_TOOL_TYPE_STYLUS; + return ToolType::STYLUS; case MT_TOOL_PALM: - return AMOTION_EVENT_TOOL_TYPE_PALM; + return ToolType::PALM; } } - return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + return ToolType::UNKNOWN; } } // namespace android diff --git a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h index 3c1a2a9e64..943dde5ca2 100644 --- a/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h +++ b/services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h @@ -45,7 +45,7 @@ public: inline int32_t getTrackingId() const { return mAbsMtTrackingId; } inline int32_t getPressure() const { return mAbsMtPressure; } inline int32_t getDistance() const { return mAbsMtDistance; } - int32_t getToolType() const; + ToolType getToolType() const; private: friend class MultiTouchMotionAccumulator; diff --git a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp index 6b84f32db2..8c4bed3267 100644 --- a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp +++ b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.cpp @@ -141,21 +141,21 @@ uint32_t TouchButtonAccumulator::getButtonState() const { return result; } -int32_t TouchButtonAccumulator::getToolType() const { +ToolType TouchButtonAccumulator::getToolType() const { if (mBtnToolMouse || mBtnToolLens) { - return AMOTION_EVENT_TOOL_TYPE_MOUSE; + return ToolType::MOUSE; } if (mBtnToolRubber) { - return AMOTION_EVENT_TOOL_TYPE_ERASER; + return ToolType::ERASER; } if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) { - return AMOTION_EVENT_TOOL_TYPE_STYLUS; + return ToolType::STYLUS; } if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap || mBtnToolQuintTap) { - return AMOTION_EVENT_TOOL_TYPE_FINGER; + return ToolType::FINGER; } - return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + return ToolType::UNKNOWN; } bool TouchButtonAccumulator::isToolActive() const { diff --git a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h index c2aa2adc0f..c5fd5f5168 100644 --- a/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h +++ b/services/inputflinger/reader/mapper/accumulator/TouchButtonAccumulator.h @@ -36,7 +36,7 @@ public: void process(const RawEvent* rawEvent); uint32_t getButtonState() const; - int32_t getToolType() const; + ToolType getToolType() const; bool isToolActive() const; bool isHovering() const; bool hasStylus() const; diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h index 2714d03ea3..70e8fb7758 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h @@ -99,10 +99,10 @@ private: // We never need any PointerProperties other than the finger tool type, so we can just keep a // const array of them. const std::array mFingerProps = {{ - {.id = 0, .toolType = AMOTION_EVENT_TOOL_TYPE_FINGER}, - {.id = 1, .toolType = AMOTION_EVENT_TOOL_TYPE_FINGER}, - {.id = 2, .toolType = AMOTION_EVENT_TOOL_TYPE_FINGER}, - {.id = 3, .toolType = AMOTION_EVENT_TOOL_TYPE_FINGER}, + {.id = 0, .toolType = ToolType::FINGER}, + {.id = 1, .toolType = ToolType::FINGER}, + {.id = 2, .toolType = ToolType::FINGER}, + {.id = 3, .toolType = ToolType::FINGER}, }}; std::array mFakeFingerCoords = {}; diff --git a/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp index d344babe72..e89262a71a 100644 --- a/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp +++ b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp @@ -85,7 +85,7 @@ SelfContainedHardwareState HardwareStateConverter::produceHardwareState(nsecs_t MultiTouchMotionAccumulator::Slot slot = mMotionAccumulator.getSlot(i); // Some touchpads continue to report contacts even after they've identified them as palms. // We want to exclude these contacts from the HardwareStates. - if (!slot.isInUse() || slot.getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) { + if (!slot.isInUse() || slot.getToolType() == ToolType::PALM) { continue; } diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp index 33f404d56b..c6d541e962 100644 --- a/services/inputflinger/tests/GestureConverter_test.cpp +++ b/services/inputflinger/tests/GestureConverter_test.cpp @@ -93,7 +93,7 @@ TEST_F(GestureConverterTest, Move) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(POINTER_X - 5, POINTER_Y + 10), WithRelativeMotion(-5, 10), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), WithButtonState(0), + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 5, POINTER_Y + 10)); @@ -111,7 +111,7 @@ TEST_F(GestureConverterTest, Move_Rotated) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(POINTER_X + 10, POINTER_Y + 5), WithRelativeMotion(10, 5), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), WithButtonState(0), + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X + 10, POINTER_Y + 5)); @@ -133,14 +133,14 @@ TEST_F(GestureConverterTest, ButtonsChange) { WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY), WithCoords(POINTER_X, POINTER_Y), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithCoords(POINTER_X, POINTER_Y), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), @@ -148,7 +148,7 @@ TEST_F(GestureConverterTest, ButtonsChange) { WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY), WithCoords(POINTER_X, POINTER_Y), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); // Then release the left button Gesture leftUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, @@ -162,7 +162,7 @@ TEST_F(GestureConverterTest, ButtonsChange) { WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), WithCoords(POINTER_X, POINTER_Y), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); // Finally release the right button Gesture rightUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, @@ -175,12 +175,12 @@ TEST_F(GestureConverterTest, ButtonsChange) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(0), WithCoords(POINTER_X, POINTER_Y), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0), WithCoords(POINTER_X, POINTER_Y), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); } TEST_F(GestureConverterTest, DragWithButton) { @@ -198,14 +198,14 @@ TEST_F(GestureConverterTest, DragWithButton) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithCoords(POINTER_X, POINTER_Y), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithCoords(POINTER_X, POINTER_Y), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); // Move Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); @@ -215,7 +215,7 @@ TEST_F(GestureConverterTest, DragWithButton) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(POINTER_X - 5, POINTER_Y + 10), WithRelativeMotion(-5, 10), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), + WithToolType(ToolType::FINGER), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f))); ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 5, POINTER_Y + 10)); @@ -231,12 +231,12 @@ TEST_F(GestureConverterTest, DragWithButton) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(0), WithCoords(POINTER_X - 5, POINTER_Y + 10), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0), WithCoords(POINTER_X - 5, POINTER_Y + 10), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); } TEST_F(GestureConverterTest, Scroll) { @@ -252,7 +252,7 @@ TEST_F(GestureConverterTest, Scroll) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y), WithGestureScrollDistance(0, 0, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), WithDownTime(downTime), + WithToolType(ToolType::FINGER), WithDownTime(downTime), WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))); args.pop_front(); ASSERT_THAT(std::get(args.front()), @@ -260,7 +260,7 @@ TEST_F(GestureConverterTest, Scroll) { WithCoords(POINTER_X, POINTER_Y - 10), WithGestureScrollDistance(0, 10, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), + WithToolType(ToolType::FINGER), WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))); Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5); @@ -271,7 +271,7 @@ TEST_F(GestureConverterTest, Scroll) { WithCoords(POINTER_X, POINTER_Y - 15), WithGestureScrollDistance(0, 5, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), + WithToolType(ToolType::FINGER), WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, @@ -283,7 +283,7 @@ TEST_F(GestureConverterTest, Scroll) { WithCoords(POINTER_X, POINTER_Y - 15), WithGestureScrollDistance(0, 0, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), + WithToolType(ToolType::FINGER), WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))); } @@ -301,14 +301,14 @@ TEST_F(GestureConverterTest, Scroll_Rotated) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y), WithGestureScrollDistance(0, 0, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), WithDownTime(downTime))); + WithToolType(ToolType::FINGER), WithDownTime(downTime))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(POINTER_X - 10, POINTER_Y), WithGestureScrollDistance(0, 10, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5); args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); @@ -318,7 +318,7 @@ TEST_F(GestureConverterTest, Scroll_Rotated) { WithCoords(POINTER_X - 15, POINTER_Y), WithGestureScrollDistance(0, 5, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, GESTURES_FLING_START); @@ -329,7 +329,7 @@ TEST_F(GestureConverterTest, Scroll_Rotated) { WithCoords(POINTER_X - 15, POINTER_Y), WithGestureScrollDistance(0, 0, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); } TEST_F(GestureConverterTest, Scroll_ClearsClassificationAndOffsetsAfterGesture) { @@ -393,7 +393,7 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { ASSERT_THAT(arg, AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(1u), WithToolType(ToolType::FINGER))); PointerCoords finger0Start = arg.pointerCoords[0]; args.pop_front(); arg = std::get(args.front()); @@ -402,7 +402,7 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(2u), WithToolType(ToolType::FINGER))); PointerCoords finger1Start = arg.pointerCoords[1]; args.pop_front(); arg = std::get(args.front()); @@ -411,7 +411,7 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER))); PointerCoords finger2Start = arg.pointerCoords[2]; args.pop_front(); @@ -420,7 +420,7 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithGestureOffset(0, -0.01, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER))); EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX()); EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX()); EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX()); @@ -437,7 +437,7 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithGestureOffset(0, -0.005, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER))); EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX()); EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX()); EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX()); @@ -453,19 +453,19 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(2u), WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(1u), WithToolType(ToolType::FINGER))); } TEST_F(GestureConverterTest, ThreeFingerSwipe_Rotated) { @@ -560,7 +560,7 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { ASSERT_THAT(arg, AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(1u), WithToolType(ToolType::FINGER))); PointerCoords finger0Start = arg.pointerCoords[0]; args.pop_front(); arg = std::get(args.front()); @@ -569,7 +569,7 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(2u), WithToolType(ToolType::FINGER))); PointerCoords finger1Start = arg.pointerCoords[1]; args.pop_front(); arg = std::get(args.front()); @@ -578,7 +578,7 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER))); PointerCoords finger2Start = arg.pointerCoords[2]; args.pop_front(); arg = std::get(args.front()); @@ -587,7 +587,7 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { 3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(4u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(4u), WithToolType(ToolType::FINGER))); PointerCoords finger3Start = arg.pointerCoords[3]; args.pop_front(); @@ -596,7 +596,7 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithGestureOffset(0.01, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(4u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(4u), WithToolType(ToolType::FINGER))); EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX() + 10); EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX() + 10); EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX() + 10); @@ -615,7 +615,7 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithGestureOffset(0.005, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(4u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(4u), WithToolType(ToolType::FINGER))); EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX() + 15); EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX() + 15); EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX() + 15); @@ -633,26 +633,26 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { 3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(4u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(4u), WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(2u), WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(1u), WithToolType(ToolType::FINGER))); } TEST_F(GestureConverterTest, Pinch_Inwards) { @@ -668,7 +668,7 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithCoords(POINTER_X - 100, POINTER_Y), WithPointerCount(1u), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | @@ -676,7 +676,7 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCoords(1, POINTER_X + 100, POINTER_Y), WithPointerCount(2u), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 0.8, GESTURES_ZOOM_UPDATE); @@ -688,7 +688,7 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { WithGesturePinchScaleFactor(0.8f, EPSILON), WithPointerCoords(0, POINTER_X - 80, POINTER_Y), WithPointerCoords(1, POINTER_X + 80, POINTER_Y), WithPointerCount(2u), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_END); @@ -699,13 +699,13 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); } TEST_F(GestureConverterTest, Pinch_Outwards) { @@ -721,7 +721,7 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithCoords(POINTER_X - 100, POINTER_Y), WithPointerCount(1u), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | @@ -729,7 +729,7 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCoords(1, POINTER_X + 100, POINTER_Y), WithPointerCount(2u), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1.2, GESTURES_ZOOM_UPDATE); @@ -741,7 +741,7 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { WithGesturePinchScaleFactor(1.2f, EPSILON), WithPointerCoords(0, POINTER_X - 120, POINTER_Y), WithPointerCoords(1, POINTER_X + 120, POINTER_Y), WithPointerCount(2u), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_END); @@ -752,13 +752,13 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); } TEST_F(GestureConverterTest, Pinch_ClearsClassificationAndScaleFactorAfterGesture) { @@ -802,18 +802,18 @@ TEST_F(GestureConverterTest, ResetWithButtonPressed) { WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), WithCoords(POINTER_X, POINTER_Y), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); args.pop_front(); EXPECT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(0), WithCoords(POINTER_X, POINTER_Y), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0), WithCoords(POINTER_X, POINTER_Y), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); } TEST_F(GestureConverterTest, ResetDuringScroll) { @@ -830,7 +830,7 @@ TEST_F(GestureConverterTest, ResetDuringScroll) { WithCoords(POINTER_X, POINTER_Y - 10), WithGestureScrollDistance(0, 0, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), + WithToolType(ToolType::FINGER), WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))); } @@ -849,19 +849,19 @@ TEST_F(GestureConverterTest, ResetDuringThreeFingerSwipe) { 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER))); args.pop_front(); EXPECT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(2u), WithToolType(ToolType::FINGER))); args.pop_front(); EXPECT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithPointerCount(1u), WithToolType(ToolType::FINGER))); } TEST_F(GestureConverterTest, ResetDuringPinch) { @@ -879,13 +879,13 @@ TEST_F(GestureConverterTest, ResetDuringPinch) { 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); args.pop_front(); EXPECT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER))); + WithToolType(ToolType::FINGER))); } } // namespace android diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index e2996437bf..a58ad84e90 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1464,7 +1464,7 @@ static InputEventInjectionResult injectKeyUp(const std::unique_ptrnotifyMotion(&( args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); // Second touch pointer down mDispatcher->notifyMotion(&( args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) - .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(110).y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100)) .build())); // First touch pointer lifts. The second one remains down mDispatcher->notifyMotion(&( args = MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) - .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(110).y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100)) .build())); window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); @@ -2069,8 +2069,8 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(150)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -2085,8 +2085,8 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { MotionEventBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(150)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, @@ -2102,7 +2102,7 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) .pointer(PointerBuilder(/* id */ 1, - AMOTION_EVENT_TOOL_TYPE_FINGER) + ToolType::FINGER) .x(100) .y(100)) .build(), @@ -2154,8 +2154,8 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(300).y(100)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -2179,8 +2179,8 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { const MotionEvent secondFingerMoveEvent = MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(310).y(110)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(310).y(110)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, @@ -2274,15 +2274,15 @@ TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) { args = MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .policyFlags(DEFAULT_POLICY_FLAGS) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); mDispatcher->notifyMotion(&( args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .policyFlags(DEFAULT_POLICY_FLAGS) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) - .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(120).y(120)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); spyWindow->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); @@ -2294,8 +2294,8 @@ TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) { args = MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .policyFlags(0) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) - .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(120).y(120)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)); @@ -2313,7 +2313,7 @@ TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) { args = MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .policyFlags(DEFAULT_POLICY_FLAGS) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); @@ -2358,7 +2358,7 @@ TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) { .deviceId(mouseDeviceId) .downTime(baseTime + 10) .eventTime(baseTime + 20) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE) .x(300) .y(100)) .build())); @@ -2372,7 +2372,7 @@ TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) { .deviceId(mouseDeviceId) .downTime(baseTime + 10) .eventTime(baseTime + 30) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE) .x(110) .y(100)) .build())); @@ -2386,7 +2386,7 @@ TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) { .deviceId(touchDeviceId) .downTime(baseTime + 40) .eventTime(baseTime + 40) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(100) .y(100)) .build())); @@ -2401,7 +2401,7 @@ TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) { .deviceId(touchDeviceId) .downTime(baseTime + 40) .eventTime(baseTime + 50) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(100) .y(100)) .build())); @@ -2415,7 +2415,7 @@ TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) { .deviceId(touchDeviceId) .downTime(baseTime + 60) .eventTime(baseTime + 60) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(300) .y(100)) .build())); @@ -2429,7 +2429,7 @@ TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) { .deviceId(touchDeviceId) .downTime(baseTime + 60) .eventTime(baseTime + 70) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(300) .y(100)) .build())); @@ -2467,7 +2467,7 @@ TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { mDispatcher->notifyMotion(&( args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) .build())); leftWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); @@ -2477,7 +2477,7 @@ TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) .build())); leftWindow->consumeMotionEvent( @@ -2490,7 +2490,7 @@ TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { .deviceId(mouseDeviceId) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); @@ -2498,7 +2498,7 @@ TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { mDispatcher->notifyMotion(&( args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); @@ -2508,8 +2508,8 @@ TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { mDispatcher->notifyMotion(&( args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) - .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100)) .build())); leftWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); @@ -2547,21 +2547,21 @@ TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { mDispatcher->notifyMotion(&( args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .build())); // Second touch pointer down mDispatcher->notifyMotion(&( args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) - .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(350).y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) .build())); // First touch pointer lifts. The second one remains down mDispatcher->notifyMotion(&( args = MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) - .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(350).y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) .build())); window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); @@ -2572,7 +2572,7 @@ TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(320).y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100)) .build())); window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId), @@ -2584,7 +2584,7 @@ TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { .deviceId(mouseDeviceId) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(320).y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); @@ -2592,8 +2592,8 @@ TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { mDispatcher->notifyMotion(&( args = MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) - .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(350).y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) .build())); // The pointer_down event should be ignored window->assertNoEvents(); @@ -2619,7 +2619,7 @@ TEST_F(InputDispatcherTest, UnfinishedInjectedEvent) { injectMotionEvent(mDispatcher, MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE) .x(50) .y(50)) .build())); @@ -2631,7 +2631,7 @@ TEST_F(InputDispatcherTest, UnfinishedInjectedEvent) { mDispatcher->notifyMotion(&( args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(300).y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .build())); window->consumeMotionEvent( @@ -2673,7 +2673,7 @@ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE) .x(50) .y(50)) .build())); @@ -2685,7 +2685,7 @@ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(100) .y(100)) .build())); @@ -2695,7 +2695,7 @@ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(100) .y(100)) .build())); @@ -2709,7 +2709,7 @@ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(300) .y(100)) .build())); @@ -2720,10 +2720,10 @@ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { injectMotionEvent(mDispatcher, MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(300) .y(100)) - .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(1, ToolType::FINGER) .x(100) .y(100)) .build())); @@ -2756,7 +2756,7 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS) .x(50) .y(50)) .build())); @@ -2768,7 +2768,7 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(100) .y(100)) .build())); @@ -2781,7 +2781,7 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS) .x(50) .y(50)) .build())); @@ -2794,7 +2794,7 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(100) .y(100)) .build())); @@ -2806,7 +2806,7 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS) .x(50) .y(50)) .build())); @@ -2839,40 +2839,40 @@ TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) { // Start hovering with stylus mDispatcher->notifyMotion( &(args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); // Stop hovering mDispatcher->notifyMotion( &(args = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); // Stylus touches down mDispatcher->notifyMotion( &(args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Stylus goes up mDispatcher->notifyMotion( &(args = MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP)); // Again hover mDispatcher->notifyMotion( &(args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); // Stop hovering mDispatcher->notifyMotion( &(args = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS).x(50).y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); @@ -2908,7 +2908,7 @@ TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { mDispatcher->notifyMotion(&( args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) .build())); spyWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); @@ -2919,7 +2919,7 @@ TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { mDispatcher->notifyMotion( &(args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); @@ -2929,7 +2929,7 @@ TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { mDispatcher->notifyMotion( &(args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(55).y(55)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); window->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); @@ -2941,7 +2941,7 @@ TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { mDispatcher->notifyMotion( &(args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(60).y(60)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); @@ -2950,7 +2950,7 @@ TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) .build())); spyWindow->consumeMotionEvent( @@ -2964,7 +2964,7 @@ TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { .deviceId(mouseDeviceId) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(100).y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); @@ -2974,7 +2974,7 @@ TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(110).y(110)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110)) .build())); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); window->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); @@ -2983,7 +2983,7 @@ TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { mDispatcher->notifyMotion( &(args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(65).y(65)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65)) .build())); // No more events @@ -3129,9 +3129,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) - .x(900) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400)) .build())); windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); @@ -3140,9 +3138,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) - .x(300) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); @@ -3152,9 +3148,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) - .x(300) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); windowLeft->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); @@ -3165,9 +3159,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) - .x(300) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); @@ -3177,9 +3169,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { AINPUT_SOURCE_MOUSE) .buttonState(0) .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) - .x(300) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE)); @@ -3187,9 +3177,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) .buttonState(0) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) - .x(300) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); windowLeft->consumeMotionUp(ADISPLAY_ID_DEFAULT); @@ -3198,9 +3186,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) - .x(900) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400)) .build())); windowRight->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); @@ -3230,14 +3216,14 @@ TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) { mDispatcher->notifyMotion(&( args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); mDispatcher->notifyMotion(&( args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(100)) - .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(120).y(120)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) .build())); window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); @@ -3247,7 +3233,7 @@ TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) { args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(300).y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId), WithPointerCount(2u))); @@ -3258,7 +3244,7 @@ TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) { .deviceId(mouseDeviceId) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(300).y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); @@ -3267,8 +3253,8 @@ TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) { mDispatcher->notifyMotion(&( args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(101).y(101)) - .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(121).y(121)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121)) .build())); window->assertNoEvents(); } @@ -3293,7 +3279,7 @@ TEST_F(InputDispatcherTest, HoverWithSpyWindows) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE) .x(100) .y(100)) .build())); @@ -3327,7 +3313,7 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE) .x(100) .y(100)) .build())); @@ -3337,7 +3323,7 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE) .x(110) .y(110)) .build())); @@ -3356,7 +3342,7 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(SECOND_DEVICE_ID) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(200) .y(200)) .build())); @@ -3380,7 +3366,7 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(SECOND_DEVICE_ID) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(200) .y(200)) .build())); @@ -3397,7 +3383,7 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(SECOND_DEVICE_ID) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(250) .y(250)) .build())); @@ -3412,7 +3398,7 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(SECOND_DEVICE_ID) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(0, ToolType::FINGER) .x(250) .y(250)) .build())); @@ -3441,9 +3427,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) - .x(300) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // Inject a series of mouse events for a mouse click @@ -3451,9 +3435,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) - .x(300) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); @@ -3464,9 +3446,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) - .x(300) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); @@ -3476,9 +3456,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { AINPUT_SOURCE_MOUSE) .buttonState(0) .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) - .x(300) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE)); @@ -3486,9 +3464,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) .buttonState(0) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) - .x(300) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); window->consumeMotionUp(ADISPLAY_ID_DEFAULT); @@ -3496,9 +3472,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) - .x(300) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); window->assertNoEvents(); } @@ -3521,7 +3495,7 @@ TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE) .x(300) .y(400)) .build())); @@ -3551,7 +3525,7 @@ TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) { mDispatcher->notifyMotion( &(args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE).x(10).y(10)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10)) .build())); window->consumeMotionEvent( AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); @@ -3560,7 +3534,7 @@ TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) { mDispatcher->notifyMotion( &(args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) .build())); window->consumeMotionEvent( @@ -3633,7 +3607,7 @@ TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) { MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .displayId(ADISPLAY_ID_DEFAULT) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE) .x(300) .y(600)) .build())); @@ -3654,7 +3628,7 @@ TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) { MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .displayId(ADISPLAY_ID_DEFAULT) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE) .x(400) .y(700)) .build())); @@ -3911,8 +3885,8 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(-30).y(-50)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -4033,7 +4007,7 @@ TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisp MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER) .x(untransformedPoint.x) .y(untransformedPoint.y)) .build(); @@ -6076,7 +6050,7 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) { const MotionEvent event = MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(20).y(20)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20)) .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, event)) @@ -7937,7 +7911,7 @@ protected: MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS) .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS) .x(50) .y(50)) .build())); @@ -7949,7 +7923,7 @@ protected: MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(MOUSE_POINTER_ID, - AMOTION_EVENT_TOOL_TYPE_MOUSE) + ToolType::MOUSE) .x(50) .y(50)) .build())); @@ -8038,8 +8012,8 @@ TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) { const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(60).y(60)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -8093,9 +8067,7 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS) .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS) - .x(50) - .y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) .build())) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8107,9 +8079,7 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS) .buttonState(0) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS) - .x(150) - .y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50)) .build())) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8122,9 +8092,7 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) { injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS) .buttonState(0) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_STYLUS) - .x(150) - .y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50)) .build())) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); @@ -8182,8 +8150,8 @@ TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) { MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(75).y(50)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -8209,8 +8177,8 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) { MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -8225,8 +8193,8 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) { const MotionEvent secondFingerMoveEvent = MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, @@ -8239,8 +8207,8 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) { const MotionEvent secondFingerUpEvent = MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, @@ -8265,9 +8233,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(SECOND_DISPLAY_ID) - .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN, SECOND_DISPLAY_ID, /*expectedFlag=*/0); @@ -8311,7 +8277,7 @@ TEST_F(InputDispatcherDragTests, MouseDragAndDrop) { MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(MOUSE_POINTER_ID, - AMOTION_EVENT_TOOL_TYPE_MOUSE) + ToolType::MOUSE) .x(50) .y(50)) .build())) @@ -8326,7 +8292,7 @@ TEST_F(InputDispatcherDragTests, MouseDragAndDrop) { MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(MOUSE_POINTER_ID, - AMOTION_EVENT_TOOL_TYPE_MOUSE) + ToolType::MOUSE) .x(150) .y(50)) .build())) @@ -8341,7 +8307,7 @@ TEST_F(InputDispatcherDragTests, MouseDragAndDrop) { MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) .buttonState(0) .pointer(PointerBuilder(MOUSE_POINTER_ID, - AMOTION_EVENT_TOOL_TYPE_MOUSE) + ToolType::MOUSE) .x(150) .y(50)) .build())) @@ -8813,8 +8779,8 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -8845,8 +8811,8 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -8884,8 +8850,8 @@ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(200)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -9007,8 +8973,8 @@ TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(200)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -9022,9 +8988,9 @@ TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(100).y(200)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer(PointerBuilder(/*id=*/2, AMOTION_EVENT_TOOL_TYPE_FINGER).x(-5).y(-5)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(100).y(200)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5)) .build(); ASSERT_EQ(InputEventInjectionResult::FAILED, injectMotionEvent(mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -9058,8 +9024,8 @@ TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) { MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(150)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -9073,9 +9039,9 @@ TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) { MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(150)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) - .pointer(PointerBuilder(/*id=*/2, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(150)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10)) + .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -9119,8 +9085,8 @@ TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) { MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -9166,8 +9132,8 @@ TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) { MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/*id=*/0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) - .pointer(PointerBuilder(/*id=*/1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(150)) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(10).y(10)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, @@ -9221,7 +9187,7 @@ public: NotifyMotionArgs motionArgs = generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT, {PointF{30, 40}}); - motionArgs.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + motionArgs.pointerProperties[0].toolType = ToolType::STYLUS; mDispatcher->notifyMotion(&motionArgs); } }; diff --git a/services/inputflinger/tests/InputProcessorConverter_test.cpp b/services/inputflinger/tests/InputProcessorConverter_test.cpp index 161a24ff70..4b42f4b141 100644 --- a/services/inputflinger/tests/InputProcessorConverter_test.cpp +++ b/services/inputflinger/tests/InputProcessorConverter_test.cpp @@ -30,7 +30,7 @@ static NotifyMotionArgs generateBasicMotionArgs() { // Create a basic motion event for testing PointerProperties properties; properties.id = 0; - properties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + properties.toolType = ToolType::FINGER; PointerCoords coords; coords.clear(); diff --git a/services/inputflinger/tests/InputProcessor_test.cpp b/services/inputflinger/tests/InputProcessor_test.cpp index b6deed8aae..0ffdef9daa 100644 --- a/services/inputflinger/tests/InputProcessor_test.cpp +++ b/services/inputflinger/tests/InputProcessor_test.cpp @@ -37,7 +37,7 @@ static NotifyMotionArgs generateBasicMotionArgs() { // Create a basic motion event for testing PointerProperties properties; properties.id = 0; - properties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + properties.toolType = ToolType::FINGER; PointerCoords coords; coords.clear(); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 853c5b0115..92d5357d8e 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1732,7 +1732,7 @@ TEST_F(TouchIntegrationTest, NotifiesPolicyWhenStylusGestureStarted) { mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + WithToolType(ToolType::STYLUS)))); ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertStylusGestureNotified(mDeviceInfo.getId())); @@ -1751,7 +1751,7 @@ TEST_F(TouchIntegrationTest, NotifiesPolicyWhenStylusGestureStarted) { mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER)))); + WithToolType(ToolType::FINGER)))); ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertStylusGestureNotNotified()); @@ -1768,7 +1768,7 @@ TEST_F(TouchIntegrationTest, NotifiesPolicyWhenStylusGestureStarted) { mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + WithToolType(ToolType::STYLUS)))); ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertStylusGestureNotified(mDeviceInfo.getId())); } @@ -1864,12 +1864,12 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingTouchGe TestFixture::mTouchscreen->sendSync(); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), + WithToolType(ToolType::STYLUS), WithButtonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY), WithDeviceId(touchscreenId)))); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), + WithToolType(ToolType::STYLUS), WithButtonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY), WithDeviceId(touchscreenId)))); @@ -1877,11 +1877,11 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingTouchGe TestFixture::mTouchscreen->sendSync(); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); // Release the stylus button. @@ -1896,7 +1896,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingHoverin const auto touchscreenId = TestFixture::mTouchscreenInfo.getId(); const auto stylusId = TestFixture::mStylusInfo.getId(); auto toolTypeDevice = - AllOf(WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithDeviceId(touchscreenId)); + AllOf(WithToolType(ToolType::STYLUS), WithDeviceId(touchscreenId)); // Press the stylus button. TestFixture::mStylus->pressKey(BTN_STYLUS); @@ -1980,7 +1980,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsWithinTouchGesture TestFixture::mTouchscreen->sendSync(); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); // Press and release a stylus button. Each change in button state also generates a MOVE event. @@ -1990,12 +1990,12 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsWithinTouchGesture WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), + WithToolType(ToolType::STYLUS), WithButtonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY), WithDeviceId(touchscreenId)))); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), + WithToolType(ToolType::STYLUS), WithButtonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY), WithDeviceId(touchscreenId)))); @@ -2005,11 +2005,11 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsWithinTouchGesture WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); // Finish the stylus gesture. @@ -2017,7 +2017,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsWithinTouchGesture TestFixture::mTouchscreen->sendSync(); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); } @@ -2039,7 +2039,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonMotionEventsDisable TestFixture::mTouchscreen->sendSync(); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); // Press and release a stylus button. Each change only generates a MOVE motion event. @@ -2050,7 +2050,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonMotionEventsDisable WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); TestFixture::mStylus->releaseKey(BTN_STYLUS); @@ -2059,7 +2059,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonMotionEventsDisable WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); // Finish the stylus gesture. @@ -2067,7 +2067,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonMotionEventsDisable TestFixture::mTouchscreen->sendSync(); ASSERT_NO_FATAL_FAILURE(TestFixture::mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId)))); } @@ -2108,7 +2108,7 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureReport mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId), WithPressure(100.f / RAW_PRESSURE_MAX)))); // Change the pressure on the external stylus, and ensure the touchscreen generates a MOVE @@ -2116,7 +2116,7 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureReport stylus->setPressure(200); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId), WithPressure(200.f / RAW_PRESSURE_MAX)))); // The external stylus did not generate any events. @@ -2162,7 +2162,7 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureNotRep // it shows up as a finger pointer. ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER), WithDeviceId(touchscreenId), + WithToolType(ToolType::FINGER), WithDeviceId(touchscreenId), WithPressure(1.f)))); // Change the pressure on the external stylus. Since the pressure was not present at the start @@ -2175,7 +2175,7 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureNotRep mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER)))); + WithToolType(ToolType::FINGER)))); // Start a new gesture. Since we have a valid pressure value, it shows up as a stylus. mDevice->sendTrackingId(FIRST_TRACKING_ID); @@ -2184,7 +2184,7 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureNotRep mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), WithButtonState(0), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId), WithPressure(200.f / RAW_PRESSURE_MAX)))); // The external stylus did not generate any events. @@ -2220,7 +2220,7 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_UnfusedExternalStylus) { mTestListener ->assertNotifyMotionWasCalled(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithToolType( - AMOTION_EVENT_TOOL_TYPE_FINGER), + ToolType::FINGER), WithButtonState(0), WithDeviceId(touchscreenId), WithPressure(1.f)), @@ -3875,7 +3875,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat ASSERT_EQ(0, args.edgeFlags); ASSERT_EQ(uint32_t(1), args.pointerCount); ASSERT_EQ(0, args.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::MOUSE, args.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 1.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); @@ -3893,7 +3893,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat ASSERT_EQ(0, args.edgeFlags); ASSERT_EQ(uint32_t(1), args.pointerCount); ASSERT_EQ(0, args.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::MOUSE, args.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 1.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); @@ -3914,7 +3914,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat ASSERT_EQ(0, args.edgeFlags); ASSERT_EQ(uint32_t(1), args.pointerCount); ASSERT_EQ(0, args.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::MOUSE, args.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); @@ -3932,7 +3932,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat ASSERT_EQ(0, args.edgeFlags); ASSERT_EQ(uint32_t(1), args.pointerCount); ASSERT_EQ(0, args.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::MOUSE, args.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertCursorPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); @@ -5195,7 +5195,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfB ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -5219,7 +5219,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfB ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -5242,7 +5242,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfB ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -5292,7 +5292,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMoves ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -5315,7 +5315,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMoves ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -5360,7 +5360,7 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture_VirtualDispl ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x, VIRTUAL_DISPLAY_WIDTH), toDisplayY(y, VIRTUAL_DISPLAY_HEIGHT), 1, 0, 0, 0, 0, 0, 0, 0)); @@ -5387,7 +5387,7 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture_VirtualDispl ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x, VIRTUAL_DISPLAY_WIDTH), toDisplayY(y, VIRTUAL_DISPLAY_HEIGHT), 1, 0, 0, 0, 0, 0, 0, 0)); @@ -5412,7 +5412,7 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture_VirtualDispl ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x, VIRTUAL_DISPLAY_WIDTH), toDisplayY(y, VIRTUAL_DISPLAY_HEIGHT), 1, 0, 0, 0, 0, 0, 0, 0)); @@ -5455,7 +5455,7 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -5480,7 +5480,7 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -5503,7 +5503,7 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -6151,14 +6151,14 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // eraser processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::ERASER, motionArgs.pointerProperties[0].toolType); // stylus processKey(mapper, BTN_TOOL_RUBBER, 0); @@ -6166,7 +6166,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::STYLUS, motionArgs.pointerProperties[0].toolType); // brush processKey(mapper, BTN_TOOL_PEN, 0); @@ -6174,7 +6174,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::STYLUS, motionArgs.pointerProperties[0].toolType); // pencil processKey(mapper, BTN_TOOL_BRUSH, 0); @@ -6182,7 +6182,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::STYLUS, motionArgs.pointerProperties[0].toolType); // air-brush processKey(mapper, BTN_TOOL_PENCIL, 0); @@ -6190,7 +6190,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::STYLUS, motionArgs.pointerProperties[0].toolType); // mouse processKey(mapper, BTN_TOOL_AIRBRUSH, 0); @@ -6198,7 +6198,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::MOUSE, motionArgs.pointerProperties[0].toolType); // lens processKey(mapper, BTN_TOOL_MOUSE, 0); @@ -6206,7 +6206,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::MOUSE, motionArgs.pointerProperties[0].toolType); // double-tap processKey(mapper, BTN_TOOL_LENS, 0); @@ -6214,7 +6214,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // triple-tap processKey(mapper, BTN_TOOL_DOUBLETAP, 0); @@ -6222,7 +6222,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // quad-tap processKey(mapper, BTN_TOOL_TRIPLETAP, 0); @@ -6230,7 +6230,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // finger processKey(mapper, BTN_TOOL_QUADTAP, 0); @@ -6238,28 +6238,28 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // stylus trumps finger processKey(mapper, BTN_TOOL_PEN, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::STYLUS, motionArgs.pointerProperties[0].toolType); // eraser trumps stylus processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::ERASER, motionArgs.pointerProperties[0].toolType); // mouse trumps eraser processKey(mapper, BTN_TOOL_MOUSE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::MOUSE, motionArgs.pointerProperties[0].toolType); // back to default tool type processKey(mapper, BTN_TOOL_MOUSE, 0); @@ -6269,7 +6269,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); } TEST_F(SingleTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) { @@ -6659,7 +6659,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenConfigEnabled_ShouldShowDirectSty processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), + WithToolType(ToolType::STYLUS), WithPointerCoords(0, toDisplayX(100), toDisplayY(200))))); ASSERT_TRUE(fakePointerController->isPointerShown()); ASSERT_NO_FATAL_FAILURE( @@ -6683,7 +6683,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenConfigDisabled_ShouldNotShowDirec processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), + WithToolType(ToolType::STYLUS), WithPointerCoords(0, toDisplayX(100), toDisplayY(200))))); ASSERT_FALSE(fakePointerController->isPointerShown()); } @@ -7125,7 +7125,7 @@ public: mStylusState.when = ARBITRARY_TIME; mStylusState.pressure = 0.f; - mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + mStylusState.toolType = ToolType::STYLUS; mReader->getContext()->setExternalStylusDevices({mExternalStylusDeviceInfo}); configureDevice(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE); processExternalStylusState(mapper); @@ -7149,7 +7149,7 @@ protected: void testStartFusedStylusGesture(SingleTouchInputMapper& mapper) { auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)); + AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS)); // The first pointer is withheld. processDown(mapper, 100, 200); @@ -7184,7 +7184,7 @@ protected: processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(EXPECTED_SOURCE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + WithToolType(ToolType::STYLUS)))); mStylusState.pressure = 0.f; processExternalStylusState(mapper); @@ -7194,7 +7194,7 @@ protected: void testUnsuccessfulFusionGesture(SingleTouchInputMapper& mapper) { auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER)); + AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::FINGER)); // The first pointer is withheld when an external stylus is connected, // and a timeout is requested. @@ -7252,7 +7252,7 @@ TEST_F(ExternalStylusFusionTest, SuccessfulFusion_TouchFirst) { TEST_F(ExternalStylusFusionTest, SuccessfulFusion_PressureFirst) { SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus(); auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)); + AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS)); // The external stylus reports pressure first. It is ignored for now. mStylusState.pressure = 1.f; @@ -7295,7 +7295,7 @@ TEST_F(ExternalStylusFusionTest, FusionIsRepeatedForEachNewGesture) { TEST_F(ExternalStylusFusionTest, FusedPointerReportsPressureChanges) { SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus(); auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)); + AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS)); mStylusState.pressure = 0.8f; processExternalStylusState(mapper); @@ -7357,7 +7357,7 @@ TEST_F(ExternalStylusFusionTest, FusedPointerReportsPressureChanges) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(EXPECTED_SOURCE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + WithToolType(ToolType::STYLUS)))); ASSERT_NO_FATAL_FAILURE(mReader->getContext()->assertTimeoutWasNotRequested()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); @@ -7368,17 +7368,17 @@ TEST_F(ExternalStylusFusionTest, FusedPointerReportsToolTypeChanges) { auto source = WithSource(EXPECTED_SOURCE); mStylusState.pressure = 1.f; - mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_ERASER; + mStylusState.toolType = ToolType::ERASER; processExternalStylusState(mapper); processDown(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(source, WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(AMOTION_EVENT_TOOL_TYPE_ERASER)))); + WithToolType(ToolType::ERASER)))); ASSERT_NO_FATAL_FAILURE(mReader->getContext()->assertTimeoutWasNotRequested()); // The external stylus reports a tool change. We wait for some time for a touch event. - mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + mStylusState.toolType = ToolType::STYLUS; processExternalStylusState(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); ASSERT_NO_FATAL_FAILURE( @@ -7389,11 +7389,11 @@ TEST_F(ExternalStylusFusionTest, FusedPointerReportsToolTypeChanges) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(source, WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + WithToolType(ToolType::STYLUS)))); ASSERT_NO_FATAL_FAILURE(mReader->getContext()->assertTimeoutWasNotRequested()); // There is another tool type change. - mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + mStylusState.toolType = ToolType::FINGER; processExternalStylusState(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); ASSERT_NO_FATAL_FAILURE( @@ -7404,13 +7404,13 @@ TEST_F(ExternalStylusFusionTest, FusedPointerReportsToolTypeChanges) { handleTimeout(mapper, ARBITRARY_TIME + TOUCH_DATA_TIMEOUT); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(source, WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER)))); + WithToolType(ToolType::FINGER)))); processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(source, WithMotionAction(AMOTION_EVENT_ACTION_UP), - WithToolType(AMOTION_EVENT_TOOL_TYPE_FINGER)))); + WithToolType(ToolType::FINGER)))); ASSERT_NO_FATAL_FAILURE(mReader->getContext()->assertTimeoutWasNotRequested()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); @@ -7419,7 +7419,7 @@ TEST_F(ExternalStylusFusionTest, FusedPointerReportsToolTypeChanges) { TEST_F(ExternalStylusFusionTest, FusedPointerReportsButtons) { SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus(); auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)); + AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS)); ASSERT_NO_FATAL_FAILURE(testStartFusedStylusGesture(mapper)); @@ -7636,7 +7636,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -7655,9 +7655,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -7686,9 +7686,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -7715,9 +7715,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -7738,7 +7738,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -7763,7 +7763,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -7790,9 +7790,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -7819,9 +7819,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -7842,7 +7842,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -7865,7 +7865,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); @@ -7953,7 +7953,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); @@ -7961,9 +7961,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -7983,9 +7983,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -8002,9 +8002,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(ACTION_POINTER_0_UP, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -8014,7 +8014,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); @@ -8029,7 +8029,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); @@ -8047,9 +8047,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(ACTION_POINTER_0_DOWN, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -8066,9 +8066,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(ACTION_POINTER_1_UP, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -8078,7 +8078,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); @@ -8090,7 +8090,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); @@ -8123,7 +8123,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); @@ -8131,9 +8131,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -8151,9 +8151,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -8171,9 +8171,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { ASSERT_EQ(ACTION_POINTER_0_UP, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -8183,7 +8183,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); @@ -8196,7 +8196,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); @@ -8212,9 +8212,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { ASSERT_EQ(ACTION_POINTER_0_DOWN, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -8232,9 +8232,9 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { ASSERT_EQ(ACTION_POINTER_1_UP, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], @@ -8244,7 +8244,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); @@ -8256,7 +8256,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); @@ -8783,14 +8783,14 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // eraser processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::ERASER, motionArgs.pointerProperties[0].toolType); // stylus processKey(mapper, BTN_TOOL_RUBBER, 0); @@ -8798,7 +8798,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::STYLUS, motionArgs.pointerProperties[0].toolType); // brush processKey(mapper, BTN_TOOL_PEN, 0); @@ -8806,7 +8806,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::STYLUS, motionArgs.pointerProperties[0].toolType); // pencil processKey(mapper, BTN_TOOL_BRUSH, 0); @@ -8814,7 +8814,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::STYLUS, motionArgs.pointerProperties[0].toolType); // air-brush processKey(mapper, BTN_TOOL_PENCIL, 0); @@ -8822,7 +8822,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::STYLUS, motionArgs.pointerProperties[0].toolType); // mouse processKey(mapper, BTN_TOOL_AIRBRUSH, 0); @@ -8830,7 +8830,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::MOUSE, motionArgs.pointerProperties[0].toolType); // lens processKey(mapper, BTN_TOOL_MOUSE, 0); @@ -8838,7 +8838,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::MOUSE, motionArgs.pointerProperties[0].toolType); // double-tap processKey(mapper, BTN_TOOL_LENS, 0); @@ -8846,7 +8846,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // triple-tap processKey(mapper, BTN_TOOL_DOUBLETAP, 0); @@ -8854,7 +8854,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // quad-tap processKey(mapper, BTN_TOOL_TRIPLETAP, 0); @@ -8862,7 +8862,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // finger processKey(mapper, BTN_TOOL_QUADTAP, 0); @@ -8870,42 +8870,42 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // stylus trumps finger processKey(mapper, BTN_TOOL_PEN, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::STYLUS, motionArgs.pointerProperties[0].toolType); // eraser trumps stylus processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::ERASER, motionArgs.pointerProperties[0].toolType); // mouse trumps eraser processKey(mapper, BTN_TOOL_MOUSE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::MOUSE, motionArgs.pointerProperties[0].toolType); // MT tool type trumps BTN tool types: MT_TOOL_FINGER processToolType(mapper, MT_TOOL_FINGER); // this is the first time we send MT_TOOL_TYPE processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // MT tool type trumps BTN tool types: MT_TOOL_PEN processToolType(mapper, MT_TOOL_PEN); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::STYLUS, motionArgs.pointerProperties[0].toolType); // back to default tool type processToolType(mapper, -1); // use a deliberately undefined tool type, for testing @@ -8916,7 +8916,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); } TEST_F(MultiTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) { @@ -9531,7 +9531,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // finger move processId(mapper, 1); @@ -9539,14 +9539,14 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // finger up. processId(mapper, -1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // new finger down processId(mapper, 1); @@ -9554,7 +9554,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) { processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); } /** @@ -9576,7 +9576,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_SinglePointer processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // Tool changed to MT_TOOL_PALM expect sending the cancel event. processToolType(mapper, MT_TOOL_PALM); @@ -9602,7 +9602,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_SinglePointer processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); } /** @@ -9624,7 +9624,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_TwoPointers) processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // Second finger down. processSlot(mapper, SECOND_SLOT); @@ -9633,7 +9633,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_TwoPointers) processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[1].toolType); // If the tool type of the first finger changes to MT_TOOL_PALM, // we expect to receive ACTION_POINTER_UP with cancel flag. @@ -9699,7 +9699,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_ShouldCancelW processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // Second finger down. processSlot(mapper, SECOND_SLOT); @@ -9708,7 +9708,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_ShouldCancelW processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // If the tool type of the first finger changes to MT_TOOL_PALM, // we expect to receive ACTION_POINTER_UP with cancel flag. @@ -9743,7 +9743,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_ShouldCancelW processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(uint32_t(1), motionArgs.pointerCount); // third finger move @@ -9797,7 +9797,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_KeepFirstPoin processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // Second finger down. processSlot(mapper, SECOND_SLOT); @@ -9806,7 +9806,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_KeepFirstPoin processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ACTION_POINTER_1_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); // If the tool type of the second finger changes to MT_TOOL_PALM, // we expect to receive ACTION_POINTER_UP with cancel flag. @@ -10003,7 +10003,7 @@ TEST_F(MultiTouchInputMapperTest, StylusSourceIsAddedDynamicallyFromToolType) { ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + WithToolType(ToolType::STYLUS)))); // Now that we know the device supports styluses, ensure that the device is re-configured with // the stylus source. @@ -10025,7 +10025,7 @@ TEST_F(MultiTouchInputMapperTest, StylusSourceIsAddedDynamicallyFromToolType) { ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + WithToolType(ToolType::STYLUS)))); } TEST_F(MultiTouchInputMapperTest, Process_WhenConfigEnabled_ShouldShowDirectStylusPointer) { @@ -10048,7 +10048,7 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenConfigEnabled_ShouldShowDirectStyl processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), + WithToolType(ToolType::STYLUS), WithPointerCoords(0, toDisplayX(100), toDisplayY(200))))); ASSERT_TRUE(fakePointerController->isPointerShown()); ASSERT_NO_FATAL_FAILURE( @@ -10075,7 +10075,7 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenConfigDisabled_ShouldNotShowDirect processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS), + WithToolType(ToolType::STYLUS), WithPointerCoords(0, toDisplayX(100), toDisplayY(200))))); ASSERT_FALSE(fakePointerController->isPointerShown()); } @@ -10468,7 +10468,7 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthSwipe) { ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(1U, motionArgs.pointerCount); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(MotionClassification::NONE, motionArgs.classification); ASSERT_NO_FATAL_FAILURE( assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)); @@ -10490,7 +10490,7 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthSwipe) { ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(1U, motionArgs.pointerCount); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(MotionClassification::TWO_FINGER_SWIPE, motionArgs.classification); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 0, movingDistance * mPointerMovementScale, 1, 0, 0, 0, @@ -10528,7 +10528,7 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthLowResolutionSwipe) ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(1U, motionArgs.pointerCount); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(MotionClassification::NONE, motionArgs.classification); ASSERT_NO_FATAL_FAILURE( assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)); @@ -10550,7 +10550,7 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthLowResolutionSwipe) ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(1U, motionArgs.pointerCount); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(MotionClassification::TWO_FINGER_SWIPE, motionArgs.classification); // New coordinate is the scaled relative coordinate from the initial coordinate. ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 0, @@ -10584,7 +10584,7 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthFreeform) { ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(1U, motionArgs.pointerCount); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(MotionClassification::NONE, motionArgs.classification); // One pointer for PRESS, and its coordinate is used as the origin for pointer coordinates. ASSERT_NO_FATAL_FAILURE( @@ -10610,15 +10610,15 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthFreeform) { ASSERT_EQ(1U, motionArgs.pointerCount); ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1U, motionArgs.pointerCount); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(MotionClassification::NONE, motionArgs.classification); ASSERT_EQ(2U, motionArgs.pointerCount); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN, motionArgs.action & AMOTION_EVENT_ACTION_MASK); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(MotionClassification::NONE, motionArgs.classification); // Two pointers' scaled relative coordinates from their initial centroid. // Initial y coordinates are 0 as y1 and y2 have the same value. @@ -10648,7 +10648,7 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthFreeform) { ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(2U, motionArgs.pointerCount); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); - ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(ToolType::FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(MotionClassification::NONE, motionArgs.classification); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], cookedX1, movingDistance * 2 * mPointerMovementScale, 1, 0, 0, @@ -10718,12 +10718,12 @@ TEST_F(MultiTouchPointerModeTest, WhenViewportActiveStatusChanged_PointerGesture ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithSource(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + WithToolType(ToolType::STYLUS)))); // TODO(b/257078296): Pointer mode generates extra event. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithSource(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + WithToolType(ToolType::STYLUS)))); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); // Make the viewport inactive. This will put the device in disabled mode, and the ongoing stylus @@ -10735,12 +10735,12 @@ TEST_F(MultiTouchPointerModeTest, WhenViewportActiveStatusChanged_PointerGesture ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL), WithSource(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + WithToolType(ToolType::STYLUS)))); // TODO(b/257078296): Pointer mode generates extra event. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL), WithSource(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS), - WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + WithToolType(ToolType::STYLUS)))); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } diff --git a/services/inputflinger/tests/NotifyArgs_test.cpp b/services/inputflinger/tests/NotifyArgs_test.cpp index 671558509d..15367568ab 100644 --- a/services/inputflinger/tests/NotifyArgs_test.cpp +++ b/services/inputflinger/tests/NotifyArgs_test.cpp @@ -54,7 +54,7 @@ TEST(NotifyMotionArgsTest, TestCopyAssignmentOperator) { for (size_t i = 0; i < pointerCount; i++) { pointerProperties[i].clear(); pointerProperties[i].id = i; - pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + pointerProperties[i].toolType = ToolType::FINGER; pointerCoords[i].clear(); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, x++); diff --git a/services/inputflinger/tests/PreferStylusOverTouch_test.cpp b/services/inputflinger/tests/PreferStylusOverTouch_test.cpp index 9014dfb48b..9818176cb0 100644 --- a/services/inputflinger/tests/PreferStylusOverTouch_test.cpp +++ b/services/inputflinger/tests/PreferStylusOverTouch_test.cpp @@ -45,8 +45,8 @@ static NotifyMotionArgs generateMotionArgs(nsecs_t downTime, nsecs_t eventTime, PointerCoords pointerCoords[pointerCount]; const int32_t deviceId = isFromSource(source, TOUCHSCREEN) ? TOUCH_DEVICE_ID : STYLUS_DEVICE_ID; - const int32_t toolType = isFromSource(source, TOUCHSCREEN) ? AMOTION_EVENT_TOOL_TYPE_FINGER - : AMOTION_EVENT_TOOL_TYPE_STYLUS; + const ToolType toolType = + isFromSource(source, TOUCHSCREEN) ? ToolType::FINGER : ToolType::STYLUS; for (size_t i = 0; i < pointerCount; i++) { pointerProperties[i].clear(); pointerProperties[i].id = i; @@ -278,20 +278,20 @@ TEST_F(PreferStylusOverTouchTest, MixedStylusAndTouchPointersAreIgnored) { // Event from a stylus device, but with finger tool type args = generateMotionArgs(/*downTime=*/1, /*eventTime=*/1, DOWN, {{1, 2}}, STYLUS); // Keep source stylus, but make the tool type touch - args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + args.pointerProperties[0].toolType = ToolType::FINGER; assertNotBlocked(args); // Second pointer (stylus pointer) goes down, from the same device args = generateMotionArgs(/*downTime=*/1, /*eventTime=*/2, POINTER_1_DOWN, {{1, 2}, {10, 20}}, STYLUS); // Keep source stylus, but make the tool type touch - args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args.pointerProperties[0].toolType = ToolType::STYLUS; assertNotBlocked(args); // Second pointer (stylus pointer) goes down, from the same device args = generateMotionArgs(/*downTime=*/1, /*eventTime=*/3, MOVE, {{2, 3}, {11, 21}}, STYLUS); // Keep source stylus, but make the tool type touch - args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + args.pointerProperties[0].toolType = ToolType::FINGER; assertNotBlocked(args); } @@ -418,14 +418,14 @@ TEST_F(PreferStylusOverTouchTest, MixedStylusAndTouchDeviceIsCanceledAtFirst) { // Introduce a stylus pointer into the device 1 stream. It should be ignored. args = generateMotionArgs(/*downTime=*/1, /*eventTime=*/3, POINTER_1_DOWN, {{1, 2}, {3, 4}}, TOUCHSCREEN); - args.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args.pointerProperties[1].toolType = ToolType::STYLUS; args.source = STYLUS; assertDropped(args); // Lift up touch from the mixed touch/stylus device args = generateMotionArgs(/*downTime=*/1, /*eventTime=*/4, CANCEL, {{1, 2}, {3, 4}}, TOUCHSCREEN); - args.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args.pointerProperties[1].toolType = ToolType::STYLUS; args.source = STYLUS; assertDropped(args); diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h index 09f7ae8b1c..338b74766e 100644 --- a/services/inputflinger/tests/TestInputListenerMatchers.h +++ b/services/inputflinger/tests/TestInputListenerMatchers.h @@ -138,8 +138,8 @@ MATCHER_P(WithPressure, pressure, "InputEvent with specified pressure") { MATCHER_P(WithToolType, toolType, "InputEvent with specified tool type") { const auto argToolType = arg.pointerProperties[0].toolType; - *result_listener << "expected tool type " << motionToolTypeToString(toolType) << ", but got " - << motionToolTypeToString(argToolType); + *result_listener << "expected tool type " << ftl::enum_string(toolType) << ", but got " + << ftl::enum_string(argToolType); return argToolType == toolType; } diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp index 3f749b1fed..2a9ace00c5 100644 --- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp +++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp @@ -79,7 +79,7 @@ static NotifyMotionArgs generateMotionArgs(nsecs_t downTime, nsecs_t eventTime, for (size_t i = 0; i < pointerCount; i++) { pointerProperties[i].clear(); pointerProperties[i].id = i; - pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + pointerProperties[i].toolType = ToolType::FINGER; pointerCoords[i].clear(); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, points[i].x); @@ -507,7 +507,7 @@ TEST_F(UnwantedInteractionBlockerTest, NoCrashWhenResetHappens) { TEST_F(UnwantedInteractionBlockerTest, NoCrashWhenStylusSourceWithFingerToolIsReceived) { mBlocker->notifyInputDevicesChanged({generateTestDeviceInfo()}); NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, DOWN, {{1, 2, 3}}); - args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + args.pointerProperties[0].toolType = ToolType::FINGER; args.source = AINPUT_SOURCE_STYLUS; mBlocker->notifyMotion(&args); } @@ -548,15 +548,15 @@ TEST_F(UnwantedInteractionBlockerTest, StylusAfterTouchWorks) { // Now touch down stylus args = generateMotionArgs(/*downTime=*/3, /*eventTime=*/3, DOWN, {{10, 20, 30}}); - args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args.pointerProperties[0].toolType = ToolType::STYLUS; args.source |= AINPUT_SOURCE_STYLUS; mBlocker->notifyMotion(&args); args = generateMotionArgs(/*downTime=*/3, /*eventTime=*/4, MOVE, {{40, 50, 60}}); - args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args.pointerProperties[0].toolType = ToolType::STYLUS; args.source |= AINPUT_SOURCE_STYLUS; mBlocker->notifyMotion(&args); args = generateMotionArgs(/*downTime=*/3, /*eventTime=*/5, UP, {{40, 50, 60}}); - args.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args.pointerProperties[0].toolType = ToolType::STYLUS; args.source |= AINPUT_SOURCE_STYLUS; mBlocker->notifyMotion(&args); } @@ -617,14 +617,14 @@ TEST_F(UnwantedInteractionBlockerTest, StylusIsNotBlocked) { info.addSource(AINPUT_SOURCE_STYLUS); mBlocker->notifyInputDevicesChanged({info}); NotifyMotionArgs args1 = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2, 3}}); - args1.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args1.pointerProperties[0].toolType = ToolType::STYLUS; mBlocker->notifyMotion(&args1); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(DOWN)); // Move the stylus, setting large TOUCH_MAJOR/TOUCH_MINOR dimensions NotifyMotionArgs args2 = generateMotionArgs(/*downTime=*/0, RESAMPLE_PERIOD, MOVE, {{4, 5, 200}}); - args2.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args2.pointerProperties[0].toolType = ToolType::STYLUS; mBlocker->notifyMotion(&args2); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE)); @@ -632,7 +632,7 @@ TEST_F(UnwantedInteractionBlockerTest, StylusIsNotBlocked) { // it's a palm. NotifyMotionArgs args3 = generateMotionArgs(/*downTime=*/0, 2 * RESAMPLE_PERIOD, UP, {{4, 5, 200}}); - args3.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args3.pointerProperties[0].toolType = ToolType::STYLUS; mBlocker->notifyMotion(&args3); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(UP)); } @@ -655,21 +655,21 @@ TEST_F(UnwantedInteractionBlockerTest, TouchIsBlockedWhenMixedWithStylus) { // Stylus pointer down NotifyMotionArgs args2 = generateMotionArgs(/*downTime=*/0, RESAMPLE_PERIOD, POINTER_1_DOWN, {{1, 2, 3}, {10, 20, 30}}); - args2.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args2.pointerProperties[1].toolType = ToolType::STYLUS; mBlocker->notifyMotion(&args2); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(POINTER_1_DOWN)); // Large touch oval on the next finger move NotifyMotionArgs args3 = generateMotionArgs(/*downTime=*/0, 2 * RESAMPLE_PERIOD, MOVE, {{1, 2, 300}, {11, 21, 30}}); - args3.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args3.pointerProperties[1].toolType = ToolType::STYLUS; mBlocker->notifyMotion(&args3); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE)); // Lift up the finger pointer. It should be canceled due to the heuristic filter. NotifyMotionArgs args4 = generateMotionArgs(/*downTime=*/0, 3 * RESAMPLE_PERIOD, POINTER_0_UP, {{1, 2, 300}, {11, 21, 30}}); - args4.pointerProperties[1].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args4.pointerProperties[1].toolType = ToolType::STYLUS; mBlocker->notifyMotion(&args4); mTestListener.assertNotifyMotionWasCalled( AllOf(WithMotionAction(POINTER_0_UP), WithFlags(FLAG_CANCELED))); @@ -677,7 +677,7 @@ TEST_F(UnwantedInteractionBlockerTest, TouchIsBlockedWhenMixedWithStylus) { NotifyMotionArgs args5 = generateMotionArgs(/*downTime=*/0, 4 * RESAMPLE_PERIOD, MOVE, {{12, 22, 30}}); args5.pointerProperties[0].id = args4.pointerProperties[1].id; - args5.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args5.pointerProperties[0].toolType = ToolType::STYLUS; mBlocker->notifyMotion(&args5); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE)); @@ -685,7 +685,7 @@ TEST_F(UnwantedInteractionBlockerTest, TouchIsBlockedWhenMixedWithStylus) { NotifyMotionArgs args6 = generateMotionArgs(/*downTime=*/0, 5 * RESAMPLE_PERIOD, UP, {{4, 5, 200}}); args6.pointerProperties[0].id = args4.pointerProperties[1].id; - args6.pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + args6.pointerProperties[0].toolType = ToolType::STYLUS; mBlocker->notifyMotion(&args6); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(UP)); } diff --git a/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp index 2909129126..6617f65adf 100644 --- a/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp @@ -28,7 +28,7 @@ NotifyMotionArgs generateFuzzedMotionArgs(FuzzedDataProvider &fdp) { // Create a basic motion event for testing PointerProperties properties; properties.id = 0; - properties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + properties.toolType = getFuzzedToolType(fdp); PointerCoords coords; coords.clear(); for (int32_t i = 0; i < fdp.ConsumeIntegralInRange(0, MAX_AXES); i++) { diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index 2cb5cdf9fc..d9a07b96d5 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -66,6 +66,14 @@ constexpr size_t kMaxSize = 256; namespace android { +template +ToolType getFuzzedToolType(Fdp& fdp) { + const int32_t toolType = fdp.template ConsumeIntegralInRange( + static_cast(ToolType::ftl_first), + static_cast(ToolType::ftl_last)); + return static_cast(toolType); +} + class FuzzEventHub : public EventHubInterface { InputDeviceIdentifier mIdentifier; std::vector mVideoFrames; diff --git a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp index 59cb94a2e2..20db39d885 100644 --- a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp @@ -128,7 +128,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { StylusState state{fdp->ConsumeIntegral(), fdp->ConsumeFloatingPoint(), fdp->ConsumeIntegral(), - fdp->ConsumeIntegral()}; + getFuzzedToolType(*fdp)}; std::list unused = mapper.updateExternalStylusState(state); }, [&]() -> void { mapper.getAssociatedDisplayId(); }, -- GitLab From cbfe23c938226f5fa83d9b37f9f4212ee0c65a6f Mon Sep 17 00:00:00 2001 From: Matt Buckley Date: Tue, 8 Nov 2022 23:12:04 +0000 Subject: [PATCH 0047/1187] Rewrite the PowerAdvisor using standard power wrappers and clean up * Replace custom AIDL/HIDL wrappers with libpowermanager * Remove early hint code as it is deprecated for load change hints Bug: b/245975645 Bug: b/244358432 Test: atest libsurfaceflinger_unittest Change-Id: I2a11779ce1f78bcf29ea0e7978cb8933e74e9f7b --- services/powermanager/Android.bp | 8 + services/surfaceflinger/Android.bp | 5 +- .../tests/MockPowerAdvisor.h | 9 +- .../DisplayHardware/PowerAdvisor.cpp | 569 ++++-------------- .../DisplayHardware/PowerAdvisor.h | 130 ++-- services/surfaceflinger/SurfaceFlinger.cpp | 29 +- services/surfaceflinger/SurfaceFlinger.h | 4 - .../unittests/AidlPowerHalWrapperTest.cpp | 241 -------- .../surfaceflinger/tests/unittests/Android.bp | 4 +- .../tests/unittests/PowerAdvisorTest.cpp | 55 +- .../SurfaceFlinger_PowerHintTest.cpp | 9 +- .../tests/unittests/TestableSurfaceFlinger.h | 4 - .../DisplayHardware/MockAidlPowerHalWrapper.h | 54 -- .../mock/DisplayHardware/MockPowerAdvisor.h | 9 +- ...Wrapper.cpp => MockPowerHalController.cpp} | 10 +- .../DisplayHardware/MockPowerHalController.h | 49 ++ 16 files changed, 285 insertions(+), 904 deletions(-) delete mode 100644 services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp delete mode 100644 services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h rename services/surfaceflinger/tests/unittests/mock/DisplayHardware/{MockAidlPowerHalWrapper.cpp => MockPowerHalController.cpp} (67%) create mode 100644 services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp index 7fb33e5dcf..b34e54fd6b 100644 --- a/services/powermanager/Android.bp +++ b/services/powermanager/Android.bp @@ -43,6 +43,14 @@ cc_library_shared { "android.hardware.power-V4-cpp", ], + export_shared_lib_headers: [ + "android.hardware.power@1.0", + "android.hardware.power@1.1", + "android.hardware.power@1.2", + "android.hardware.power@1.3", + "android.hardware.power-V4-cpp", + ], + cflags: [ "-Wall", "-Werror", diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index fe7cff7577..5683a9280f 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -47,8 +47,6 @@ cc_defaults { "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.4", - "android.hardware.power@1.0", - "android.hardware.power@1.3", "android.hardware.power-V4-cpp", "libbase", "libbinder", @@ -63,6 +61,7 @@ cc_defaults { "liblayers_proto", "liblog", "libnativewindow", + "libpowermanager", "libprocessgroup", "libprotobuf-cpp-lite", "libsync", @@ -105,7 +104,7 @@ cc_defaults { "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.4", - "android.hardware.power@1.3", + "libpowermanager", "libhidlbase", "libtimestats", ], diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h index c555b39db1..961ec808e8 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h @@ -37,11 +37,10 @@ public: MOCK_METHOD(void, notifyDisplayUpdateImminentAndCpuReset, (), (override)); MOCK_METHOD(bool, usePowerHintSession, (), (override)); MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); - MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override)); - MOCK_METHOD(void, setTargetWorkDuration, (Duration targetDuration), (override)); - MOCK_METHOD(void, sendActualWorkDuration, (), (override)); - MOCK_METHOD(void, sendPredictedWorkDuration, (), (override)); - MOCK_METHOD(void, enablePowerHint, (bool enabled), (override)); + MOCK_METHOD(bool, ensurePowerHintSessionRunning, (), (override)); + MOCK_METHOD(void, updateTargetWorkDuration, (Duration targetDuration), (override)); + MOCK_METHOD(void, reportActualWorkDuration, (), (override)); + MOCK_METHOD(void, enablePowerHintSession, (bool enabled), (override)); MOCK_METHOD(bool, startPowerHintSession, (const std::vector& threadIds), (override)); MOCK_METHOD(void, setGpuFenceTime, (DisplayId displayId, std::unique_ptr&& fenceTime), (override)); diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index 36f71bb481..37b68c865e 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include @@ -49,12 +49,7 @@ PowerAdvisor::~PowerAdvisor() = default; namespace impl { -namespace V1_0 = android::hardware::power::V1_0; -namespace V1_3 = android::hardware::power::V1_3; -using V1_3::PowerHint; - using android::hardware::power::Boost; -using android::hardware::power::IPower; using android::hardware::power::IPowerHintSession; using android::hardware::power::Mode; using android::hardware::power::SessionHint; @@ -80,7 +75,8 @@ void traceExpensiveRendering(bool enabled) { } // namespace -PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger) : mFlinger(flinger) { +PowerAdvisor::PowerAdvisor(SurfaceFlinger& flinger) + : mPowerHal(std::make_unique()), mFlinger(flinger) { if (getUpdateTimeout() > 0ms) { mScreenUpdateTimer.emplace("UpdateImminentTimer", getUpdateTimeout(), /* resetCallback */ nullptr, @@ -117,6 +113,10 @@ void PowerAdvisor::onBootFinished() { } void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expected) { + if (!mHasExpensiveRendering) { + ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it"); + return; + } if (expected) { mExpensiveDisplays.insert(displayId); } else { @@ -125,19 +125,16 @@ void PowerAdvisor::setExpensiveRenderingExpected(DisplayId displayId, bool expec const bool expectsExpensiveRendering = !mExpensiveDisplays.empty(); if (mNotifiedExpensiveRendering != expectsExpensiveRendering) { - std::lock_guard lock(mPowerHalMutex); - HalWrapper* const halWrapper = getPowerHal(); - if (halWrapper == nullptr) { - return; - } - - if (!halWrapper->setExpensiveRendering(expectsExpensiveRendering)) { - // The HAL has become unavailable; attempt to reconnect later - mReconnectPowerHal = true; + auto ret = getPowerHal().setMode(Mode::EXPENSIVE_RENDERING, expectsExpensiveRendering); + if (!ret.isOk()) { + if (ret.isUnsupported()) { + mHasExpensiveRendering = false; + } return; } mNotifiedExpensiveRendering = expectsExpensiveRendering; + traceExpensiveRendering(mNotifiedExpensiveRendering); } } @@ -149,16 +146,22 @@ void PowerAdvisor::notifyDisplayUpdateImminentAndCpuReset() { } if (mSendUpdateImminent.exchange(false)) { - std::lock_guard lock(mPowerHalMutex); - HalWrapper* const halWrapper = getPowerHal(); - if (halWrapper == nullptr) { - return; + ALOGV("AIDL notifyDisplayUpdateImminentAndCpuReset"); + if (usePowerHintSession() && ensurePowerHintSessionRunning()) { + std::lock_guard lock(mHintSessionMutex); + auto ret = mHintSession->sendHint(SessionHint::CPU_LOAD_RESET); + if (!ret.isOk()) { + mHintSessionRunning = false; + } } - if (!halWrapper->notifyDisplayUpdateImminentAndCpuReset()) { - // The HAL has become unavailable; attempt to reconnect later - mReconnectPowerHal = true; - return; + if (!mHasDisplayUpdateImminent) { + ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it"); + } else { + auto ret = getPowerHal().setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0); + if (ret.isUnsupported()) { + mHasDisplayUpdateImminent = false; + } } if (mScreenUpdateTimer) { @@ -178,87 +181,123 @@ void PowerAdvisor::notifyDisplayUpdateImminentAndCpuReset() { // checks both if it supports and if it's enabled bool PowerAdvisor::usePowerHintSession() { // uses cached value since the underlying support and flag are unlikely to change at runtime - return mPowerHintEnabled.value_or(false) && supportsPowerHintSession(); + return mHintSessionEnabled.value_or(false) && supportsPowerHintSession(); } bool PowerAdvisor::supportsPowerHintSession() { // cache to avoid needing lock every time - if (!mSupportsPowerHint.has_value()) { - std::lock_guard lock(mPowerHalMutex); - HalWrapper* const halWrapper = getPowerHal(); - mSupportsPowerHint = halWrapper && halWrapper->supportsPowerHintSession(); + if (!mSupportsHintSession.has_value()) { + mSupportsHintSession = getPowerHal().getHintSessionPreferredRate().isOk(); } - return *mSupportsPowerHint; + return *mSupportsHintSession; } -bool PowerAdvisor::isPowerHintSessionRunning() { - return mPowerHintSessionRunning; +bool PowerAdvisor::ensurePowerHintSessionRunning() { + if (!mHintSessionRunning && !mHintSessionThreadIds.empty() && usePowerHintSession()) { + startPowerHintSession(mHintSessionThreadIds); + } + return mHintSessionRunning; } -void PowerAdvisor::setTargetWorkDuration(Duration targetDuration) { +void PowerAdvisor::updateTargetWorkDuration(Duration targetDuration) { if (!usePowerHintSession()) { ALOGV("Power hint session target duration cannot be set, skipping"); return; } + ATRACE_CALL(); { - std::lock_guard lock(mPowerHalMutex); - HalWrapper* const halWrapper = getPowerHal(); - if (halWrapper != nullptr) { - halWrapper->setTargetWorkDuration(targetDuration); + mTargetDuration = targetDuration; + if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration.ns()); + if (ensurePowerHintSessionRunning() && (targetDuration != mLastTargetDurationSent)) { + ALOGV("Sending target time: %" PRId64 "ns", targetDuration.ns()); + mLastTargetDurationSent = targetDuration; + std::lock_guard lock(mHintSessionMutex); + auto ret = mHintSession->updateTargetWorkDuration(targetDuration.ns()); + if (!ret.isOk()) { + ALOGW("Failed to set power hint target work duration with error: %s", + ret.exceptionMessage().c_str()); + mHintSessionRunning = false; + } } } } -void PowerAdvisor::sendActualWorkDuration() { +void PowerAdvisor::reportActualWorkDuration() { if (!mBootFinished || !usePowerHintSession()) { ALOGV("Actual work duration power hint cannot be sent, skipping"); return; } - const std::optional actualDuration = estimateWorkDuration(false); - if (actualDuration.has_value()) { - std::lock_guard lock(mPowerHalMutex); - HalWrapper* const halWrapper = getPowerHal(); - if (halWrapper != nullptr) { - halWrapper->sendActualWorkDuration(*actualDuration + sTargetSafetyMargin, - TimePoint::now()); - } + ATRACE_CALL(); + std::optional actualDuration = estimateWorkDuration(); + if (!actualDuration.has_value() || actualDuration < 0ns || !ensurePowerHintSessionRunning()) { + ALOGV("Failed to send actual work duration, skipping"); + return; } -} + actualDuration = std::make_optional(*actualDuration + sTargetSafetyMargin); + mActualDuration = actualDuration; + WorkDuration duration; + duration.durationNanos = actualDuration->ns(); + duration.timeStampNanos = TimePoint::now().ns(); + mHintSessionQueue.push_back(duration); -void PowerAdvisor::sendPredictedWorkDuration() { - if (!mBootFinished || !usePowerHintSession()) { - ALOGV("Actual work duration power hint cannot be sent, skipping"); - return; + if (sTraceHintSessionData) { + ATRACE_INT64("Measured duration", actualDuration->ns()); + ATRACE_INT64("Target error term", Duration{*actualDuration - mTargetDuration}.ns()); + ATRACE_INT64("Reported duration", actualDuration->ns()); + ATRACE_INT64("Reported target", mLastTargetDurationSent.ns()); + ATRACE_INT64("Reported target error term", + Duration{*actualDuration - mLastTargetDurationSent}.ns()); } - const std::optional predictedDuration = estimateWorkDuration(true); - if (predictedDuration.has_value()) { - std::lock_guard lock(mPowerHalMutex); - HalWrapper* const halWrapper = getPowerHal(); - if (halWrapper != nullptr) { - halWrapper->sendActualWorkDuration(*predictedDuration + sTargetSafetyMargin, - TimePoint::now()); + ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64 + " with error: %" PRId64, + actualDuration->ns(), mLastTargetDurationSent.ns(), + Duration{*actualDuration - mLastTargetDurationSent}.ns()); + + { + std::lock_guard lock(mHintSessionMutex); + auto ret = mHintSession->reportActualWorkDuration(mHintSessionQueue); + if (!ret.isOk()) { + ALOGW("Failed to report actual work durations with error: %s", + ret.exceptionMessage().c_str()); + mHintSessionRunning = false; + return; } } + mHintSessionQueue.clear(); } -void PowerAdvisor::enablePowerHint(bool enabled) { - mPowerHintEnabled = enabled; +void PowerAdvisor::enablePowerHintSession(bool enabled) { + mHintSessionEnabled = enabled; } bool PowerAdvisor::startPowerHintSession(const std::vector& threadIds) { + if (!mBootFinished.load()) { + return false; + } if (!usePowerHintSession()) { - ALOGI("Power hint session cannot be started, skipping"); + ALOGI("Cannot start power hint session: disabled or unsupported"); + return false; } + if (mHintSessionRunning) { + ALOGE("Cannot start power hint session: already running"); + return false; + } + LOG_ALWAYS_FATAL_IF(threadIds.empty(), "No thread IDs provided to power hint session!"); { - std::lock_guard lock(mPowerHalMutex); - HalWrapper* halWrapper = getPowerHal(); - if (halWrapper != nullptr && usePowerHintSession()) { - halWrapper->setPowerHintSessionThreadIds(threadIds); - mPowerHintSessionRunning = halWrapper->startPowerHintSession(); + std::lock_guard lock(mHintSessionMutex); + mHintSession = nullptr; + mHintSessionThreadIds = threadIds; + + auto ret = getPowerHal().createHintSession(getpid(), static_cast(getuid()), + threadIds, mTargetDuration.ns()); + + if (ret.isOk()) { + mHintSessionRunning = true; + mHintSession = ret.value(); } } - return mPowerHintSessionRunning; + return mHintSessionRunning; } void PowerAdvisor::setGpuFenceTime(DisplayId displayId, std::unique_ptr&& fenceTime) { @@ -356,13 +395,13 @@ std::vector PowerAdvisor::getOrderedDisplayIds( return sortedDisplays; } -std::optional PowerAdvisor::estimateWorkDuration(bool earlyHint) { - if (earlyHint && (!mExpectedPresentTimes.isFull() || !mCommitStartTimes.isFull())) { +std::optional PowerAdvisor::estimateWorkDuration() { + if (!mExpectedPresentTimes.isFull() || !mCommitStartTimes.isFull()) { return std::nullopt; } // Tracks when we finish presenting to hwc - TimePoint estimatedEndTime = mCommitStartTimes[0]; + TimePoint estimatedHwcEndTime = mCommitStartTimes[0]; // How long we spent this frame not doing anything, waiting for fences or vsync Duration idleDuration = 0ns; @@ -375,21 +414,11 @@ std::optional PowerAdvisor::estimateWorkDuration(bool earlyHint) { // used to accumulate gpu time as we iterate over the active displays std::optional estimatedGpuEndTime; - // If we're predicting at the start of the frame, we use last frame as our reference point - // If we're predicting at the end of the frame, we use the current frame as a reference point - TimePoint referenceFrameStartTime = (earlyHint ? mCommitStartTimes[-1] : mCommitStartTimes[0]); - - // When the prior frame should be presenting to the display - // If we're predicting at the start of the frame, we use last frame's expected present time - // If we're predicting at the end of the frame, the present fence time is already known - TimePoint lastFramePresentTime = - (earlyHint ? mExpectedPresentTimes[-1] : mLastPresentFenceTime); - // The timing info for the previously calculated display, if there was one - std::optional previousDisplayReferenceTiming; + std::optional previousDisplayTiming; std::vector&& displayIds = getOrderedDisplayIds(&DisplayTimingData::hwcPresentStartTime); - DisplayTimeline referenceTiming, estimatedTiming; + DisplayTimeline displayTiming; // Iterate over the displays that use hwc in the same order they are presented for (DisplayId displayId : displayIds) { @@ -399,35 +428,26 @@ std::optional PowerAdvisor::estimateWorkDuration(bool earlyHint) { auto& displayData = mDisplayTimingData.at(displayId); - // mLastPresentFenceTime should always be the time of the reference frame, since it will be - // the previous frame's present fence if called at the start, and current frame's if called - // at the end - referenceTiming = displayData.calculateDisplayTimeline(mLastPresentFenceTime); + displayTiming = displayData.calculateDisplayTimeline(mLastPresentFenceTime); // If this is the first display, include the duration before hwc present starts - if (!previousDisplayReferenceTiming.has_value()) { - estimatedEndTime += referenceTiming.hwcPresentStartTime - referenceFrameStartTime; + if (!previousDisplayTiming.has_value()) { + estimatedHwcEndTime += displayTiming.hwcPresentStartTime - mCommitStartTimes[0]; } else { // Otherwise add the time since last display's hwc present finished - estimatedEndTime += referenceTiming.hwcPresentStartTime - - previousDisplayReferenceTiming->hwcPresentEndTime; + estimatedHwcEndTime += + displayTiming.hwcPresentStartTime - previousDisplayTiming->hwcPresentEndTime; } - // Late hint can re-use reference timing here since it's estimating its own reference frame - estimatedTiming = earlyHint - ? referenceTiming.estimateTimelineFromReference(lastFramePresentTime, - estimatedEndTime) - : referenceTiming; - // Update predicted present finish time with this display's present time - estimatedEndTime = estimatedTiming.hwcPresentEndTime; + estimatedHwcEndTime = displayTiming.hwcPresentEndTime; // Track how long we spent waiting for the fence, can be excluded from the timing estimate - idleDuration += estimatedTiming.probablyWaitsForPresentFence - ? lastFramePresentTime - estimatedTiming.presentFenceWaitStartTime + idleDuration += displayTiming.probablyWaitsForPresentFence + ? mLastPresentFenceTime - displayTiming.presentFenceWaitStartTime : 0ns; // Track how long we spent waiting to present, can be excluded from the timing estimate - idleDuration += earlyHint ? 0ns : referenceTiming.hwcPresentDelayDuration; + idleDuration += displayTiming.hwcPresentDelayDuration; // Estimate the reference frame's gpu timing auto gpuTiming = displayData.estimateGpuTiming(previousValidGpuEndTime); @@ -435,24 +455,24 @@ std::optional PowerAdvisor::estimateWorkDuration(bool earlyHint) { previousValidGpuEndTime = gpuTiming->startTime + gpuTiming->duration; // Estimate the prediction frame's gpu end time from the reference frame - estimatedGpuEndTime = std::max(estimatedTiming.hwcPresentStartTime, + estimatedGpuEndTime = std::max(displayTiming.hwcPresentStartTime, estimatedGpuEndTime.value_or(TimePoint{0ns})) + gpuTiming->duration; } - previousDisplayReferenceTiming = referenceTiming; + previousDisplayTiming = displayTiming; } ATRACE_INT64("Idle duration", idleDuration.ns()); - TimePoint estimatedFlingerEndTime = earlyHint ? estimatedEndTime : mLastSfPresentEndTime; + TimePoint estimatedFlingerEndTime = mLastSfPresentEndTime; // Don't count time spent idly waiting in the estimate as we could do more work in that time - estimatedEndTime -= idleDuration; + estimatedHwcEndTime -= idleDuration; estimatedFlingerEndTime -= idleDuration; // We finish the frame when both present and the gpu are done, so wait for the later of the two // Also add the frame delay duration since the target did not move while we were delayed Duration totalDuration = mFrameDelayDuration + - std::max(estimatedEndTime, estimatedGpuEndTime.value_or(TimePoint{0ns})) - + std::max(estimatedHwcEndTime, estimatedGpuEndTime.value_or(TimePoint{0ns})) - mCommitStartTimes[0]; // We finish SurfaceFlinger when post-composition finishes, so add that in here @@ -467,10 +487,7 @@ std::optional PowerAdvisor::estimateWorkDuration(bool earlyHint) { Duration PowerAdvisor::combineTimingEstimates(Duration totalDuration, Duration flingerDuration) { Duration targetDuration{0ns}; - { - std::lock_guard lock(mPowerHalMutex); - targetDuration = *getPowerHal()->getTargetWorkDuration(); - } + targetDuration = mTargetDuration; if (!mTotalFrameTargetDuration.has_value()) return flingerDuration; // Normalize total to the flinger target (vsync period) since that's how often we actually send @@ -480,26 +497,6 @@ Duration PowerAdvisor::combineTimingEstimates(Duration totalDuration, Duration f return std::max(flingerDuration, normalizedTotalDuration); } -PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimeline::estimateTimelineFromReference( - TimePoint fenceTime, TimePoint displayStartTime) { - DisplayTimeline estimated; - estimated.hwcPresentStartTime = displayStartTime; - - // We don't predict waiting for vsync alignment yet - estimated.hwcPresentDelayDuration = 0ns; - - // How long we expect to run before we start waiting for the fence - // For now just re-use last frame's post-present duration and assume it will not change much - // Excludes time spent waiting for vsync since that's not going to be consistent - estimated.presentFenceWaitStartTime = estimated.hwcPresentStartTime + - (presentFenceWaitStartTime - (hwcPresentStartTime + hwcPresentDelayDuration)); - estimated.probablyWaitsForPresentFence = fenceTime > estimated.presentFenceWaitStartTime; - estimated.hwcPresentEndTime = postPresentFenceHwcPresentDuration + - (estimated.probablyWaitsForPresentFence ? fenceTime - : estimated.presentFenceWaitStartTime); - return estimated; -} - PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayTimeline( TimePoint fenceTime) { DisplayTimeline timeline; @@ -560,321 +557,17 @@ std::optional PowerAdvisor::DisplayTimingData::estima return GpuTimeline{.duration = gpuDuration, .startTime = latestGpuStartTime}; } -class HidlPowerHalWrapper : public PowerAdvisor::HalWrapper { -public: - HidlPowerHalWrapper(sp powerHal) : mPowerHal(std::move(powerHal)) {} - - ~HidlPowerHalWrapper() override = default; - - static std::unique_ptr connect() { - // Power HAL 1.3 is not guaranteed to be available, thus we need to query - // Power HAL 1.0 first and try to cast it to Power HAL 1.3. - sp powerHal = nullptr; - sp powerHal_1_0 = V1_0::IPower::getService(); - if (powerHal_1_0 != nullptr) { - // Try to cast to Power HAL 1.3 - powerHal = V1_3::IPower::castFrom(powerHal_1_0); - if (powerHal == nullptr) { - ALOGW("No Power HAL 1.3 service in system, disabling PowerAdvisor"); - } else { - ALOGI("Loaded Power HAL 1.3 service"); - } - } else { - ALOGW("No Power HAL found, disabling PowerAdvisor"); - } - - if (powerHal == nullptr) { - return nullptr; - } - - return std::make_unique(std::move(powerHal)); - } - - bool setExpensiveRendering(bool enabled) override { - ALOGV("HIDL setExpensiveRendering %s", enabled ? "T" : "F"); - auto ret = mPowerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING, enabled); - if (ret.isOk()) { - traceExpensiveRendering(enabled); - } - return ret.isOk(); - } - - bool notifyDisplayUpdateImminentAndCpuReset() override { - // Power HAL 1.x doesn't have a notification for this - ALOGV("HIDL notifyUpdateImminent received but can't send"); - return true; - } - - bool supportsPowerHintSession() override { return false; } - - bool isPowerHintSessionRunning() override { return false; } - - void restartPowerHintSession() override {} - - void setPowerHintSessionThreadIds(const std::vector&) override {} - - bool startPowerHintSession() override { return false; } - - void setTargetWorkDuration(Duration) override {} - - void sendActualWorkDuration(Duration, TimePoint) override {} - - bool shouldReconnectHAL() override { return false; } - - std::vector getPowerHintSessionThreadIds() override { return std::vector{}; } - - std::optional getTargetWorkDuration() override { return std::nullopt; } - -private: - const sp mPowerHal = nullptr; -}; - -AidlPowerHalWrapper::AidlPowerHalWrapper(sp powerHal) : mPowerHal(std::move(powerHal)) { - auto ret = mPowerHal->isModeSupported(Mode::EXPENSIVE_RENDERING, &mHasExpensiveRendering); - if (!ret.isOk()) { - mHasExpensiveRendering = false; - } - - ret = mPowerHal->isBoostSupported(Boost::DISPLAY_UPDATE_IMMINENT, &mHasDisplayUpdateImminent); - if (!ret.isOk()) { - mHasDisplayUpdateImminent = false; - } - - mSupportsPowerHint = checkPowerHintSessionSupported(); -} - -AidlPowerHalWrapper::~AidlPowerHalWrapper() { - if (mPowerHintSession != nullptr) { - mPowerHintSession->close(); - mPowerHintSession = nullptr; - } -} - -std::unique_ptr AidlPowerHalWrapper::connect() { - // This only waits if the service is actually declared - sp powerHal = waitForVintfService(); - if (powerHal == nullptr) { - return nullptr; - } - ALOGI("Loaded AIDL Power HAL service"); - - return std::make_unique(std::move(powerHal)); -} - -bool AidlPowerHalWrapper::setExpensiveRendering(bool enabled) { - ALOGV("AIDL setExpensiveRendering %s", enabled ? "T" : "F"); - if (!mHasExpensiveRendering) { - ALOGV("Skipped sending EXPENSIVE_RENDERING because HAL doesn't support it"); - return true; - } - - auto ret = mPowerHal->setMode(Mode::EXPENSIVE_RENDERING, enabled); - if (ret.isOk()) { - traceExpensiveRendering(enabled); - } - return ret.isOk(); -} - -bool AidlPowerHalWrapper::notifyDisplayUpdateImminentAndCpuReset() { - ALOGV("AIDL notifyDisplayUpdateImminentAndCpuReset"); - if (isPowerHintSessionRunning()) { - mPowerHintSession->sendHint(SessionHint::CPU_LOAD_RESET); - } - - if (!mHasDisplayUpdateImminent) { - ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it"); - return true; - } - - auto ret = mPowerHal->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 0); - return ret.isOk(); -} - -// Only version 2+ of the aidl supports power hint sessions, hidl has no support -bool AidlPowerHalWrapper::supportsPowerHintSession() { - return mSupportsPowerHint; -} - -bool AidlPowerHalWrapper::checkPowerHintSessionSupported() { - int64_t unused; - // Try to get preferred rate to determine if hint sessions are supported - // We check for isOk not EX_UNSUPPORTED_OPERATION to lump together errors - return mPowerHal->getHintSessionPreferredRate(&unused).isOk(); -} - -bool AidlPowerHalWrapper::isPowerHintSessionRunning() { - return mPowerHintSession != nullptr; -} - -void AidlPowerHalWrapper::closePowerHintSession() { - if (mPowerHintSession != nullptr) { - mPowerHintSession->close(); - mPowerHintSession = nullptr; - } -} - -void AidlPowerHalWrapper::restartPowerHintSession() { - closePowerHintSession(); - startPowerHintSession(); -} - -void AidlPowerHalWrapper::setPowerHintSessionThreadIds(const std::vector& threadIds) { - if (threadIds != mPowerHintThreadIds) { - mPowerHintThreadIds = threadIds; - if (isPowerHintSessionRunning()) { - restartPowerHintSession(); - } - } -} - -bool AidlPowerHalWrapper::startPowerHintSession() { - if (mPowerHintSession != nullptr || mPowerHintThreadIds.empty()) { - ALOGV("Cannot start power hint session, skipping"); - return false; - } - auto ret = mPowerHal->createHintSession(getpid(), static_cast(getuid()), - mPowerHintThreadIds, mTargetDuration.ns(), - &mPowerHintSession); - if (!ret.isOk()) { - ALOGW("Failed to start power hint session with error: %s", - ret.exceptionToString(ret.exceptionCode()).c_str()); - } else { - mLastTargetDurationSent = mTargetDuration; - } - return isPowerHintSessionRunning(); -} - -void AidlPowerHalWrapper::setTargetWorkDuration(Duration targetDuration) { - ATRACE_CALL(); - mTargetDuration = targetDuration; - if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration.ns()); - if (isPowerHintSessionRunning() && (targetDuration != mLastTargetDurationSent)) { - ALOGV("Sending target time: %" PRId64 "ns", targetDuration.ns()); - mLastTargetDurationSent = targetDuration; - auto ret = mPowerHintSession->updateTargetWorkDuration(targetDuration.ns()); - if (!ret.isOk()) { - ALOGW("Failed to set power hint target work duration with error: %s", - ret.exceptionMessage().c_str()); - mShouldReconnectHal = true; - } - } -} - -void AidlPowerHalWrapper::sendActualWorkDuration(Duration actualDuration, TimePoint timestamp) { - ATRACE_CALL(); - if (actualDuration < 0ns || !isPowerHintSessionRunning()) { - ALOGV("Failed to send actual work duration, skipping"); - return; - } - mActualDuration = actualDuration; - WorkDuration duration; - duration.durationNanos = actualDuration.ns(); - duration.timeStampNanos = timestamp.ns(); - mPowerHintQueue.push_back(duration); - - if (sTraceHintSessionData) { - ATRACE_INT64("Measured duration", actualDuration.ns()); - ATRACE_INT64("Target error term", Duration{actualDuration - mTargetDuration}.ns()); - - ATRACE_INT64("Reported duration", actualDuration.ns()); - ATRACE_INT64("Reported target", mLastTargetDurationSent.ns()); - ATRACE_INT64("Reported target error term", - Duration{actualDuration - mLastTargetDurationSent}.ns()); - } - - ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64 - " with error: %" PRId64, - actualDuration.ns(), mLastTargetDurationSent.ns(), - Duration{actualDuration - mLastTargetDurationSent}.ns()); - - auto ret = mPowerHintSession->reportActualWorkDuration(mPowerHintQueue); - if (!ret.isOk()) { - ALOGW("Failed to report actual work durations with error: %s", - ret.exceptionMessage().c_str()); - mShouldReconnectHal = true; - } - mPowerHintQueue.clear(); -} - -bool AidlPowerHalWrapper::shouldReconnectHAL() { - return mShouldReconnectHal; -} - -std::vector AidlPowerHalWrapper::getPowerHintSessionThreadIds() { - return mPowerHintThreadIds; -} - -std::optional AidlPowerHalWrapper::getTargetWorkDuration() { - return mTargetDuration; -} - -const bool AidlPowerHalWrapper::sTraceHintSessionData = +const bool PowerAdvisor::sTraceHintSessionData = base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false); const Duration PowerAdvisor::sTargetSafetyMargin = std::chrono::microseconds( base::GetIntProperty("debug.sf.hint_margin_us", ticks(PowerAdvisor::kDefaultTargetSafetyMargin))); -PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { - if (!mHasHal) { - return nullptr; - } - - // Grab old hint session values before we destroy any existing wrapper - std::vector oldPowerHintSessionThreadIds; - std::optional oldTargetWorkDuration; - - if (mHalWrapper != nullptr) { - oldPowerHintSessionThreadIds = mHalWrapper->getPowerHintSessionThreadIds(); - oldTargetWorkDuration = mHalWrapper->getTargetWorkDuration(); - } - - // If we used to have a HAL, but it stopped responding, attempt to reconnect - if (mReconnectPowerHal) { - mHalWrapper = nullptr; - mReconnectPowerHal = false; - } - - if (mHalWrapper != nullptr) { - auto wrapper = mHalWrapper.get(); - // If the wrapper is fine, return it, but if it indicates a reconnect, remake it - if (!wrapper->shouldReconnectHAL()) { - return wrapper; - } - ALOGD("Reconnecting Power HAL"); - mHalWrapper = nullptr; - } - - // At this point, we know for sure there is no running session - mPowerHintSessionRunning = false; - - // First attempt to connect to the AIDL Power HAL - mHalWrapper = AidlPowerHalWrapper::connect(); - - // If that didn't succeed, attempt to connect to the HIDL Power HAL - if (mHalWrapper == nullptr) { - mHalWrapper = HidlPowerHalWrapper::connect(); - } else { - ALOGD("Successfully connecting AIDL Power HAL"); - // If AIDL, pass on any existing hint session values - mHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds); - // Only set duration and start if duration is defined - if (oldTargetWorkDuration.has_value()) { - mHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration); - // Only start if possible to run and both threadids and duration are defined - if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) { - mPowerHintSessionRunning = mHalWrapper->startPowerHintSession(); - } - } - } - - // If we make it to this point and still don't have a HAL, it's unlikely we - // will, so stop trying - if (mHalWrapper == nullptr) { - mHasHal = false; - } - - return mHalWrapper.get(); +power::PowerHalController& PowerAdvisor::getPowerHal() { + static std::once_flag halFlag; + std::call_once(halFlag, [this] { mPowerHal->init(); }); + return *mPowerHal; } } // namespace impl diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h index c4cfdc3482..7a0d4267fe 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h @@ -27,6 +27,7 @@ #include #include +#include #include #include #include "../Scheduler/OneShotTimer.h" @@ -52,15 +53,14 @@ public: // Checks both if it supports and if it's enabled virtual bool usePowerHintSession() = 0; virtual bool supportsPowerHintSession() = 0; - virtual bool isPowerHintSessionRunning() = 0; + + virtual bool ensurePowerHintSessionRunning() = 0; // Sends a power hint that updates to the target work duration for the frame - virtual void setTargetWorkDuration(Duration targetDuration) = 0; + virtual void updateTargetWorkDuration(Duration targetDuration) = 0; // Sends a power hint for the actual known work duration at the end of the frame - virtual void sendActualWorkDuration() = 0; - // Sends a power hint for the upcoming frame predicted from previous frame timing - virtual void sendPredictedWorkDuration() = 0; + virtual void reportActualWorkDuration() = 0; // Sets whether the power hint session is enabled - virtual void enablePowerHint(bool enabled) = 0; + virtual void enablePowerHintSession(bool enabled) = 0; // Initializes the power hint session virtual bool startPowerHintSession(const std::vector& threadIds) = 0; // Provides PowerAdvisor with a copy of the gpu fence so it can determine the gpu end time @@ -101,24 +101,6 @@ namespace impl { // full state of the system when sending out power hints to things like the GPU. class PowerAdvisor final : public Hwc2::PowerAdvisor { public: - class HalWrapper { - public: - virtual ~HalWrapper() = default; - - virtual bool setExpensiveRendering(bool enabled) = 0; - virtual bool notifyDisplayUpdateImminentAndCpuReset() = 0; - virtual bool supportsPowerHintSession() = 0; - virtual bool isPowerHintSessionRunning() = 0; - virtual void restartPowerHintSession() = 0; - virtual void setPowerHintSessionThreadIds(const std::vector& threadIds) = 0; - virtual bool startPowerHintSession() = 0; - virtual void setTargetWorkDuration(Duration targetDuration) = 0; - virtual void sendActualWorkDuration(Duration actualDuration, TimePoint timestamp) = 0; - virtual bool shouldReconnectHAL() = 0; - virtual std::vector getPowerHintSessionThreadIds() = 0; - virtual std::optional getTargetWorkDuration() = 0; - }; - PowerAdvisor(SurfaceFlinger& flinger); ~PowerAdvisor() override; @@ -129,11 +111,10 @@ public: void notifyDisplayUpdateImminentAndCpuReset() override; bool usePowerHintSession() override; bool supportsPowerHintSession() override; - bool isPowerHintSessionRunning() override; - void setTargetWorkDuration(Duration targetDuration) override; - void sendActualWorkDuration() override; - void sendPredictedWorkDuration() override; - void enablePowerHint(bool enabled) override; + bool ensurePowerHintSessionRunning() override; + void updateTargetWorkDuration(Duration targetDuration) override; + void reportActualWorkDuration() override; + void enablePowerHintSession(bool enabled) override; bool startPowerHintSession(const std::vector& threadIds) override; void setGpuFenceTime(DisplayId displayId, std::unique_ptr&& fenceTime); void setHwcValidateTiming(DisplayId displayId, TimePoint validateStartTime, @@ -155,15 +136,7 @@ public: private: friend class PowerAdvisorTest; - // Tracks if powerhal exists - bool mHasHal = true; - // Holds the hal wrapper for getPowerHal - std::unique_ptr mHalWrapper GUARDED_BY(mPowerHalMutex) = nullptr; - - HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex); - bool mReconnectPowerHal GUARDED_BY(mPowerHalMutex) = false; - std::mutex mPowerHalMutex; - + std::unique_ptr mPowerHal; std::atomic_bool mBootFinished = false; std::unordered_set mExpensiveDisplays; @@ -189,9 +162,6 @@ private: Duration postPresentFenceHwcPresentDuration{0ns}; // Are we likely to have waited for the present fence during composition bool probablyWaitsForPresentFence = false; - // Estimate one frame's timeline from that of a previous frame - DisplayTimeline estimateTimelineFromReference(TimePoint fenceTime, - TimePoint displayStartTime); }; struct GpuTimeline { @@ -243,8 +213,7 @@ private: std::vector getOrderedDisplayIds( std::optional DisplayTimingData::*sortBy); // Estimates a frame's total work duration including gpu time. - // Runs either at the beginning or end of a frame, using the most recent data available - std::optional estimateWorkDuration(bool earlyHint); + std::optional estimateWorkDuration(); // There are two different targets and actual work durations we care about, // this normalizes them together and takes the max of the two Duration combineTimingEstimates(Duration totalDuration, Duration flingerDuration); @@ -268,68 +237,41 @@ private: // Updated list of display IDs std::vector mDisplayIds; - std::optional mPowerHintEnabled; - std::optional mSupportsPowerHint; - bool mPowerHintSessionRunning = false; - - // An adjustable safety margin which pads the "actual" value sent to PowerHAL, - // encouraging more aggressive boosting to give SurfaceFlinger a larger margin for error - static const Duration sTargetSafetyMargin; - static constexpr const Duration kDefaultTargetSafetyMargin{1ms}; - - // How long we expect hwc to run after the present call until it waits for the fence - static constexpr const Duration kFenceWaitStartDelayValidated{150us}; - static constexpr const Duration kFenceWaitStartDelaySkippedValidate{250us}; -}; - -class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper { -public: - explicit AidlPowerHalWrapper(sp powerHal); - ~AidlPowerHalWrapper() override; - - static std::unique_ptr connect(); + // Ensure powerhal connection is initialized + power::PowerHalController& getPowerHal(); - bool setExpensiveRendering(bool enabled) override; - bool notifyDisplayUpdateImminentAndCpuReset() override; - bool supportsPowerHintSession() override; - bool isPowerHintSessionRunning() override; - void restartPowerHintSession() override; - void setPowerHintSessionThreadIds(const std::vector& threadIds) override; - bool startPowerHintSession() override; - void setTargetWorkDuration(Duration targetDuration) override; - void sendActualWorkDuration(Duration actualDuration, TimePoint timestamp) override; - bool shouldReconnectHAL() override; - std::vector getPowerHintSessionThreadIds() override; - std::optional getTargetWorkDuration() override; - -private: - friend class AidlPowerHalWrapperTest; + std::optional mHintSessionEnabled; + std::optional mSupportsHintSession; + bool mHintSessionRunning = false; - bool checkPowerHintSessionSupported(); - void closePowerHintSession(); + std::mutex mHintSessionMutex; + sp mHintSession GUARDED_BY(mHintSessionMutex) = nullptr; - const sp mPowerHal = nullptr; - bool mHasExpensiveRendering = false; - bool mHasDisplayUpdateImminent = false; - // Used to indicate an error state and need for reconstruction - bool mShouldReconnectHal = false; - - // Power hint session data - - // Concurrent access for this is protected by mPowerHalMutex - sp mPowerHintSession = nullptr; + // Initialize to true so we try to call, to check if it's supported + bool mHasExpensiveRendering = true; + bool mHasDisplayUpdateImminent = true; // Queue of actual durations saved to report - std::vector mPowerHintQueue; + std::vector mHintSessionQueue; // The latest values we have received for target and actual Duration mTargetDuration = kDefaultTargetDuration; std::optional mActualDuration; // The list of thread ids, stored so we can restart the session from this class if needed - std::vector mPowerHintThreadIds; - bool mSupportsPowerHint = false; + std::vector mHintSessionThreadIds; Duration mLastTargetDurationSent = kDefaultTargetDuration; // Whether we should emit ATRACE_INT data for hint sessions static const bool sTraceHintSessionData; - static constexpr Duration kDefaultTargetDuration{16ms}; + + // Default target duration for the hint session + static constexpr const Duration kDefaultTargetDuration{16ms}; + + // An adjustable safety margin which pads the "actual" value sent to PowerHAL, + // encouraging more aggressive boosting to give SurfaceFlinger a larger margin for error + static const Duration sTargetSafetyMargin; + static constexpr const Duration kDefaultTargetSafetyMargin{1ms}; + + // How long we expect hwc to run after the present call until it waits for the fence + static constexpr const Duration kFenceWaitStartDelayValidated{150us}; + static constexpr const Duration kFenceWaitStartDelaySkippedValidate{250us}; }; } // namespace impl diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5664d84976..523474b770 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -478,10 +478,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false); - // Power hint session mode, representing which hint(s) to send: early, late, or both) - mPowerHintSessionMode = - {.late = base::GetBoolProperty("debug.sf.send_late_power_session_hint"s, true), - .early = base::GetBoolProperty("debug.sf.send_early_power_session_hint"s, false)}; mLayerLifecycleManagerEnabled = base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false); mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled || @@ -715,12 +711,12 @@ void SurfaceFlinger::bootFinished() { readPersistentProperties(); mPowerAdvisor->onBootFinished(); - const bool powerHintEnabled = mFlagManager.use_adpf_cpu_hint(); - mPowerAdvisor->enablePowerHint(powerHintEnabled); - const bool powerHintUsed = mPowerAdvisor->usePowerHintSession(); + const bool hintSessionEnabled = mFlagManager.use_adpf_cpu_hint(); + mPowerAdvisor->enablePowerHintSession(hintSessionEnabled); + const bool hintSessionUsed = mPowerAdvisor->usePowerHintSession(); ALOGD("Power hint is %s", - powerHintUsed ? "supported" : (powerHintEnabled ? "unsupported" : "disabled")); - if (powerHintUsed) { + hintSessionUsed ? "supported" : (hintSessionEnabled ? "unsupported" : "disabled")); + if (hintSessionUsed) { std::optional renderEngineTid = getRenderEngine().getRenderEngineTid(); std::vector tidList; tidList.emplace_back(gettid()); @@ -2461,16 +2457,7 @@ bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expe mPowerAdvisor->setFrameDelay(frameDelay); mPowerAdvisor->setTotalFrameTargetWorkDuration(idealSfWorkDuration); - - const auto& display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get(); - const Period vsyncPeriod = display->getActiveMode().fps.getPeriod(); - mPowerAdvisor->setTargetWorkDuration(vsyncPeriod); - - // Send early hint here to make sure there's not another frame pending - if (mPowerHintSessionMode.early) { - // Send a rough prediction for this frame based on last frame's timing info - mPowerAdvisor->sendPredictedWorkDuration(); - } + mPowerAdvisor->updateTargetWorkDuration(vsyncPeriod); } if (mRefreshRateOverlaySpinner) { @@ -2658,9 +2645,7 @@ void SurfaceFlinger::composite(TimePoint frameTime, VsyncId vsyncId) mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(mPreviousPresentFences[0] .fenceTime->getSignalTime()), TimePoint::now()); - if (mPowerHintSessionMode.late) { - mPowerAdvisor->sendActualWorkDuration(); - } + mPowerAdvisor->reportActualWorkDuration(); } if (mScheduler->onPostComposition(presentTime)) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 74d00dd60c..03e188beeb 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1408,10 +1408,6 @@ private: // These classes do not store any client state but help with managing transaction callbacks // and stats. std::unordered_map> mLegacyLayers; - struct { - bool late = false; - bool early = false; - } mPowerHintSessionMode; TransactionHandler mTransactionHandler; display::DisplayMap mFrontEndDisplayInfos; diff --git a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp b/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp deleted file mode 100644 index 513f77989b..0000000000 --- a/services/surfaceflinger/tests/unittests/AidlPowerHalWrapperTest.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright 2022 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. - */ - -#undef LOG_TAG -#define LOG_TAG "AidlPowerHalWrapperTest" - -#include -#include -#include -#include -#include -#include -#include -#include -#include "DisplayHardware/PowerAdvisor.h" -#include "android/hardware/power/WorkDuration.h" -#include "binder/Status.h" -#include "log/log_main.h" -#include "mock/DisplayHardware/MockIPower.h" -#include "mock/DisplayHardware/MockIPowerHintSession.h" -#include "utils/Timers.h" - -using namespace android; -using namespace android::Hwc2::mock; -using namespace android::hardware::power; -using namespace std::chrono_literals; -using namespace testing; - -namespace android::Hwc2::impl { - -class AidlPowerHalWrapperTest : public testing::Test { -public: - void SetUp() override; - -protected: - std::unique_ptr mWrapper = nullptr; - sp> mMockHal = nullptr; - sp> mMockSession = nullptr; - void verifyAndClearExpectations(); - void sendActualWorkDurationGroup(std::vector durations); - static constexpr std::chrono::duration kStaleTimeout = 100ms; -}; - -void AidlPowerHalWrapperTest::SetUp() { - mMockHal = sp>::make(); - mMockSession = sp>::make(); - ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)).WillByDefault(Return(Status::ok())); - mWrapper = std::make_unique(mMockHal); -} - -void AidlPowerHalWrapperTest::verifyAndClearExpectations() { - Mock::VerifyAndClearExpectations(mMockHal.get()); - Mock::VerifyAndClearExpectations(mMockSession.get()); -} - -void AidlPowerHalWrapperTest::sendActualWorkDurationGroup(std::vector durations) { - for (size_t i = 0; i < durations.size(); i++) { - auto duration = durations[i]; - mWrapper->sendActualWorkDuration(Duration::fromNs(duration.durationNanos), - TimePoint::fromNs(duration.timeStampNanos)); - } -} - -WorkDuration toWorkDuration(std::chrono::nanoseconds durationNanos, int64_t timeStampNanos) { - WorkDuration duration; - duration.durationNanos = durationNanos.count(); - duration.timeStampNanos = timeStampNanos; - return duration; -} - -WorkDuration toWorkDuration(std::pair timePair) { - return toWorkDuration(timePair.first, timePair.second); -} - -std::string printWorkDurations(const ::std::vector& durations) { - std::ostringstream os; - for (auto duration : durations) { - os << duration.toString(); - os << "\n"; - } - return os.str(); -} - -namespace { -TEST_F(AidlPowerHalWrapperTest, supportsPowerHintSession) { - ASSERT_TRUE(mWrapper->supportsPowerHintSession()); - Mock::VerifyAndClearExpectations(mMockHal.get()); - ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)) - .WillByDefault(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE))); - auto newWrapper = AidlPowerHalWrapper(mMockHal); - EXPECT_FALSE(newWrapper.supportsPowerHintSession()); -} - -TEST_F(AidlPowerHalWrapperTest, startPowerHintSession) { - ASSERT_TRUE(mWrapper->supportsPowerHintSession()); - std::vector threadIds = {1, 2}; - mWrapper->setPowerHintSessionThreadIds(threadIds); - EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) - .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); - EXPECT_TRUE(mWrapper->startPowerHintSession()); - EXPECT_FALSE(mWrapper->startPowerHintSession()); -} - -TEST_F(AidlPowerHalWrapperTest, restartNewPowerHintSessionWithNewThreadIds) { - ASSERT_TRUE(mWrapper->supportsPowerHintSession()); - - std::vector threadIds = {1, 2}; - EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) - .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); - mWrapper->setPowerHintSessionThreadIds(threadIds); - EXPECT_EQ(mWrapper->getPowerHintSessionThreadIds(), threadIds); - ASSERT_TRUE(mWrapper->startPowerHintSession()); - verifyAndClearExpectations(); - - threadIds = {2, 3}; - EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) - .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); - EXPECT_CALL(*mMockSession.get(), close()).Times(1); - mWrapper->setPowerHintSessionThreadIds(threadIds); - EXPECT_EQ(mWrapper->getPowerHintSessionThreadIds(), threadIds); - verifyAndClearExpectations(); - - EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)).Times(0); - EXPECT_CALL(*mMockSession.get(), close()).Times(0); - mWrapper->setPowerHintSessionThreadIds(threadIds); - verifyAndClearExpectations(); -} - -TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration) { - ASSERT_TRUE(mWrapper->supportsPowerHintSession()); - - std::vector threadIds = {1, 2}; - mWrapper->setPowerHintSessionThreadIds(threadIds); - EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) - .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); - ASSERT_TRUE(mWrapper->startPowerHintSession()); - verifyAndClearExpectations(); - - std::chrono::nanoseconds base = 100ms; - // test cases with target work duration and whether it should update hint against baseline 100ms - const std::vector> testCases = - {{0ms, true}, {-1ms, true}, {200ms, true}, {2ms, true}, {100ms, false}, {109ms, true}}; - - for (const auto& test : testCases) { - // reset to 100ms baseline - mWrapper->setTargetWorkDuration(1ns); - mWrapper->setTargetWorkDuration(base); - - std::chrono::nanoseconds target = test.first; - EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(target.count())) - .Times(test.second ? 1 : 0); - mWrapper->setTargetWorkDuration(target); - verifyAndClearExpectations(); - } -} - -TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration_shouldReconnectOnError) { - ASSERT_TRUE(mWrapper->supportsPowerHintSession()); - - std::vector threadIds = {1, 2}; - mWrapper->setPowerHintSessionThreadIds(threadIds); - EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) - .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); - ASSERT_TRUE(mWrapper->startPowerHintSession()); - verifyAndClearExpectations(); - - EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(1)) - .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE))); - mWrapper->setTargetWorkDuration(1ns); - EXPECT_TRUE(mWrapper->shouldReconnectHAL()); -} - -TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration) { - ASSERT_TRUE(mWrapper->supportsPowerHintSession()); - - std::vector threadIds = {1, 2}; - mWrapper->setPowerHintSessionThreadIds(threadIds); - EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) - .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); - ASSERT_TRUE(mWrapper->startPowerHintSession()); - verifyAndClearExpectations(); - - auto base = toWorkDuration(100ms, 0); - // test cases with actual work durations and whether it should update hint against baseline - // 100ms - const std::vector>, bool>> - testCases = {{{{-1ms, 100}}, false}, - {{{50ms, 100}}, true}, - {{{100ms, 100}, {200ms, 200}}, true}, - {{{100ms, 500}, {100ms, 600}, {3ms, 600}}, true}}; - - for (const auto& test : testCases) { - // reset actual duration - sendActualWorkDurationGroup({base}); - - auto raw = test.first; - std::vector durations(raw.size()); - std::transform(raw.begin(), raw.end(), durations.begin(), - [](auto d) { return toWorkDuration(d); }); - for (auto& duration : durations) { - EXPECT_CALL(*mMockSession.get(), - reportActualWorkDuration(std::vector{duration})) - .Times(test.second ? 1 : 0); - } - sendActualWorkDurationGroup(durations); - verifyAndClearExpectations(); - } -} - -TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_shouldReconnectOnError) { - ASSERT_TRUE(mWrapper->supportsPowerHintSession()); - - std::vector threadIds = {1, 2}; - mWrapper->setPowerHintSessionThreadIds(threadIds); - EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) - .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); - ASSERT_TRUE(mWrapper->startPowerHintSession()); - verifyAndClearExpectations(); - WorkDuration duration; - duration.durationNanos = 1; - EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_)) - .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE))); - sendActualWorkDurationGroup({duration}); - EXPECT_TRUE(mWrapper->shouldReconnectHAL()); -} - -} // namespace -} // namespace android::Hwc2::impl diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index df3ffd288c..201d37ff7e 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -24,7 +24,7 @@ package { filegroup { name: "libsurfaceflinger_mock_sources", srcs: [ - "mock/DisplayHardware/MockAidlPowerHalWrapper.cpp", + "mock/DisplayHardware/MockPowerHalController.cpp", "mock/DisplayHardware/MockComposer.cpp", "mock/DisplayHardware/MockHWC2.cpp", "mock/DisplayHardware/MockIPower.cpp", @@ -70,7 +70,6 @@ cc_test { ":libsurfaceflinger_mock_sources", ":libsurfaceflinger_sources", "libsurfaceflinger_unittest_main.cpp", - "AidlPowerHalWrapperTest.cpp", "CompositionTest.cpp", "DisplayIdGeneratorTest.cpp", "DisplayTransactionTest.cpp", @@ -196,6 +195,7 @@ cc_defaults { "libinput", "liblog", "libnativewindow", + "libpowermanager", "libprocessgroup", "libprotobuf-cpp-lite", "libSurfaceFlingerProp", diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp index d22ce17258..0d66d59f26 100644 --- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp +++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp @@ -25,13 +25,15 @@ #include #include #include "TestableSurfaceFlinger.h" -#include "mock/DisplayHardware/MockAidlPowerHalWrapper.h" +#include "mock/DisplayHardware/MockIPowerHintSession.h" +#include "mock/DisplayHardware/MockPowerHalController.h" using namespace android; using namespace android::Hwc2::mock; using namespace android::hardware::power; using namespace std::chrono_literals; using namespace testing; +using namespace android::power; namespace android::Hwc2::impl { @@ -47,23 +49,27 @@ public: protected: TestableSurfaceFlinger mFlinger; std::unique_ptr mPowerAdvisor; - NiceMock* mMockAidlWrapper; + MockPowerHalController* mMockPowerHalController; + sp mMockPowerHintSession; }; -void PowerAdvisorTest::SetUp() FTL_FAKE_GUARD(mPowerAdvisor->mPowerHalMutex) { - std::unique_ptr mockAidlWrapper = - std::make_unique>(); - mPowerAdvisor = std::make_unique(*mFlinger.flinger()); - ON_CALL(*mockAidlWrapper.get(), supportsPowerHintSession()).WillByDefault(Return(true)); - ON_CALL(*mockAidlWrapper.get(), startPowerHintSession()).WillByDefault(Return(true)); - mPowerAdvisor->mHalWrapper = std::move(mockAidlWrapper); - mMockAidlWrapper = - reinterpret_cast*>(mPowerAdvisor->mHalWrapper.get()); +void PowerAdvisorTest::SetUp() { + mPowerAdvisor = std::make_unique(*mFlinger.flinger()); + mPowerAdvisor->mPowerHal = std::make_unique>(); + mMockPowerHalController = + reinterpret_cast(mPowerAdvisor->mPowerHal.get()); + ON_CALL(*mMockPowerHalController, getHintSessionPreferredRate) + .WillByDefault(Return(HalResult::fromStatus(binder::Status::ok(), 16000))); } void PowerAdvisorTest::startPowerHintSession() { const std::vector threadIds = {1, 2, 3}; - mPowerAdvisor->enablePowerHint(true); + mMockPowerHintSession = android::sp>::make(); + ON_CALL(*mMockPowerHalController, createHintSession) + .WillByDefault( + Return(HalResult>::fromStatus(binder::Status::ok(), + mMockPowerHintSession))); + mPowerAdvisor->enablePowerHintSession(true); mPowerAdvisor->startPowerHintSession(threadIds); } @@ -76,9 +82,7 @@ void PowerAdvisorTest::setExpectedTiming(Duration totalFrameTargetDuration, void PowerAdvisorTest::fakeBasicFrameTiming(TimePoint startTime, Duration vsyncPeriod) { mPowerAdvisor->setCommitStart(startTime); mPowerAdvisor->setFrameDelay(0ns); - mPowerAdvisor->setTargetWorkDuration(vsyncPeriod); - ON_CALL(*mMockAidlWrapper, getTargetWorkDuration()) - .WillByDefault(Return(std::make_optional(vsyncPeriod))); + mPowerAdvisor->updateTargetWorkDuration(vsyncPeriod); } Duration PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) { @@ -116,7 +120,10 @@ TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) { startTime += vsyncPeriod; const Duration expectedDuration = getErrorMargin() + presentDuration + postCompDuration; - EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1); + EXPECT_CALL(*mMockPowerHintSession, + reportActualWorkDuration(ElementsAre( + Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns()))))) + .Times(1); fakeBasicFrameTiming(startTime, vsyncPeriod); setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); @@ -124,7 +131,7 @@ TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) { mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us); mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us); mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration); - mPowerAdvisor->sendActualWorkDuration(); + mPowerAdvisor->reportActualWorkDuration(); } TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) { @@ -153,7 +160,10 @@ TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) { const Duration expectedDuration = getErrorMargin() + presentDuration + getFenceWaitDelayDuration(false) - hwcBlockedDuration + postCompDuration; - EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1); + EXPECT_CALL(*mMockPowerHintSession, + reportActualWorkDuration(ElementsAre( + Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns()))))) + .Times(1); fakeBasicFrameTiming(startTime, vsyncPeriod); setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); @@ -163,7 +173,7 @@ TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) { // now report the fence as having fired during the display HWC time mPowerAdvisor->setSfPresentTiming(startTime + 2ms + hwcBlockedDuration, startTime + presentDuration); - mPowerAdvisor->sendActualWorkDuration(); + mPowerAdvisor->reportActualWorkDuration(); } TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) { @@ -192,7 +202,10 @@ TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) { startTime += vsyncPeriod; const Duration expectedDuration = getErrorMargin() + presentDuration + postCompDuration; - EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1); + EXPECT_CALL(*mMockPowerHintSession, + reportActualWorkDuration(ElementsAre( + Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns()))))) + .Times(1); fakeBasicFrameTiming(startTime, vsyncPeriod); setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); @@ -202,7 +215,7 @@ TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) { mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us); mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us); mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration); - mPowerAdvisor->sendActualWorkDuration(); + mPowerAdvisor->reportActualWorkDuration(); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp index 7839ef0dbb..d0290ea03e 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp @@ -70,7 +70,6 @@ void SurfaceFlingerPowerHintTest::SetUp() { mFlinger.setupRenderEngine(std::unique_ptr(mRenderEngine)); mFlinger.setupTimeStats(std::shared_ptr(mTimeStats)); mFlinger.setupComposer(std::unique_ptr(mComposer)); - mFlinger.setPowerHintSessionMode(true, true); mFlinger.setupPowerAdvisor(std::unique_ptr(mPowerAdvisor)); static constexpr bool kIsPrimary = true; FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, hal::DisplayType::PHYSICAL, kIsPrimary) @@ -100,7 +99,7 @@ void SurfaceFlingerPowerHintTest::SetUp() { TEST_F(SurfaceFlingerPowerHintTest, sendDurationsIncludingHwcWaitTime) { ON_CALL(*mPowerAdvisor, usePowerHintSession()).WillByDefault(Return(true)); - EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(_)).Times(1); + EXPECT_CALL(*mPowerAdvisor, updateTargetWorkDuration(_)).Times(1); EXPECT_CALL(*mDisplaySurface, prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc)) .Times(1); @@ -109,7 +108,7 @@ TEST_F(SurfaceFlingerPowerHintTest, sendDurationsIncludingHwcWaitTime) { std::this_thread::sleep_for(kMockHwcRunTime); return hardware::graphics::composer::V2_1::Error::NONE; }); - EXPECT_CALL(*mPowerAdvisor, sendActualWorkDuration()).Times(1); + EXPECT_CALL(*mPowerAdvisor, reportActualWorkDuration()).Times(1); const TimePoint frameTime = scheduler::SchedulerClock::now(); constexpr Period kMockVsyncPeriod = 15ms; @@ -121,7 +120,7 @@ TEST_F(SurfaceFlingerPowerHintTest, inactiveOnDisplayDoze) { mDisplay->setPowerMode(hal::PowerMode::DOZE); - EXPECT_CALL(*mPowerAdvisor, setTargetWorkDuration(_)).Times(0); + EXPECT_CALL(*mPowerAdvisor, updateTargetWorkDuration(_)).Times(0); EXPECT_CALL(*mDisplaySurface, prepareFrame(compositionengine::DisplaySurface::CompositionType::Hwc)) .Times(1); @@ -130,7 +129,7 @@ TEST_F(SurfaceFlingerPowerHintTest, inactiveOnDisplayDoze) { std::this_thread::sleep_for(kMockHwcRunTime); return hardware::graphics::composer::V2_1::Error::NONE; }); - EXPECT_CALL(*mPowerAdvisor, sendActualWorkDuration()).Times(0); + EXPECT_CALL(*mPowerAdvisor, reportActualWorkDuration()).Times(0); const TimePoint frameTime = scheduler::SchedulerClock::now(); constexpr Period kMockVsyncPeriod = 15ms; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index fc9e653ba4..bbb355469c 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -344,10 +344,6 @@ public: layer->mDrawingParent = drawingParent; } - void setPowerHintSessionMode(bool early, bool late) { - mFlinger->mPowerHintSessionMode = {.late = late, .early = early}; - } - /* ------------------------------------------------------------------------ * Forwarding for functions being tested */ diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h deleted file mode 100644 index 3ed85e0b1f..0000000000 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2022 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 -#include - -#include "DisplayHardware/PowerAdvisor.h" - -namespace android { -namespace hardware { -namespace power { -class IPower; -} -} // namespace hardware -} // namespace android - -namespace android::Hwc2::mock { - -class MockAidlPowerHalWrapper : public Hwc2::impl::AidlPowerHalWrapper { -public: - MockAidlPowerHalWrapper(); - ~MockAidlPowerHalWrapper() override; - MOCK_METHOD(bool, setExpensiveRendering, (bool enabled), (override)); - MOCK_METHOD(bool, notifyDisplayUpdateImminentAndCpuReset, (), (override)); - MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); - MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override)); - MOCK_METHOD(void, restartPowerHintSession, (), (override)); - MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector& threadIds), - (override)); - MOCK_METHOD(bool, startPowerHintSession, (), (override)); - MOCK_METHOD(void, setTargetWorkDuration, (Duration targetDuration), (override)); - MOCK_METHOD(void, sendActualWorkDuration, (Duration actualDuration, TimePoint timestamp), - (override)); - MOCK_METHOD(bool, shouldReconnectHAL, (), (override)); - MOCK_METHOD(std::vector, getPowerHintSessionThreadIds, (), (override)); - MOCK_METHOD(std::optional, getTargetWorkDuration, (), (override)); -}; - -} // namespace android::Hwc2::mock \ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h index 7fc625c4b6..3caa2b9847 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h @@ -35,11 +35,10 @@ public: MOCK_METHOD(void, notifyDisplayUpdateImminentAndCpuReset, (), (override)); MOCK_METHOD(bool, usePowerHintSession, (), (override)); MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); - MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override)); - MOCK_METHOD(void, setTargetWorkDuration, (Duration targetDuration), (override)); - MOCK_METHOD(void, sendActualWorkDuration, (), (override)); - MOCK_METHOD(void, sendPredictedWorkDuration, (), (override)); - MOCK_METHOD(void, enablePowerHint, (bool enabled), (override)); + MOCK_METHOD(bool, ensurePowerHintSessionRunning, (), (override)); + MOCK_METHOD(void, updateTargetWorkDuration, (Duration targetDuration), (override)); + MOCK_METHOD(void, reportActualWorkDuration, (), (override)); + MOCK_METHOD(void, enablePowerHintSession, (bool enabled), (override)); MOCK_METHOD(bool, startPowerHintSession, (const std::vector& threadIds), (override)); MOCK_METHOD(void, setGpuFenceTime, (DisplayId displayId, std::unique_ptr&& fenceTime), (override)); diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.cpp similarity index 67% rename from services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.cpp rename to services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.cpp index 5049b1d367..3ec5c2d09b 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.cpp +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2023 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. @@ -14,13 +14,11 @@ * limitations under the License. */ -#include "MockAidlPowerHalWrapper.h" -#include "MockIPower.h" +#include "MockPowerHalController.h" namespace android::Hwc2::mock { -MockAidlPowerHalWrapper::MockAidlPowerHalWrapper() - : AidlPowerHalWrapper(sp>::make()){}; -MockAidlPowerHalWrapper::~MockAidlPowerHalWrapper() = default; +MockPowerHalController::MockPowerHalController() = default; +MockPowerHalController::~MockPowerHalController() = default; } // namespace android::Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h new file mode 100644 index 0000000000..358395d323 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2023 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 +#include + +#include + +namespace android { +namespace hardware { +namespace power { +class IPower; +} +} // namespace hardware +} // namespace android + +namespace android::Hwc2::mock { + +using android::hardware::power::Boost; +using android::hardware::power::Mode; +using android::power::HalResult; + +class MockPowerHalController : public power::PowerHalController { +public: + MockPowerHalController(); + ~MockPowerHalController() override; + MOCK_METHOD(HalResult, setBoost, (Boost, int32_t), (override)); + MOCK_METHOD(HalResult, setMode, (Mode, bool), (override)); + MOCK_METHOD(HalResult>, createHintSession, + (int32_t, int32_t, const std::vector&, int64_t), (override)); + MOCK_METHOD(HalResult, getHintSessionPreferredRate, (), (override)); +}; + +} // namespace android::Hwc2::mock \ No newline at end of file -- GitLab From fb4585b3dc8e5015dc91469ae004337601172aa9 Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Fri, 17 Feb 2023 17:12:46 +0000 Subject: [PATCH 0048/1187] Check for malformed Sensor Flattenable Test: libsensorserviceaidl_fuzzer with testcase from bug Bug: 269014004 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:aeec1802f7befc8fbb18313ad3ac0969c3811870) Merged-In: I0e255c64243c38876fb657cbf942fc1613363216 Change-Id: I0e255c64243c38876fb657cbf942fc1613363216 --- libs/sensor/Sensor.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp index ec0ced8663..b865c4d5d6 100644 --- a/libs/sensor/Sensor.cpp +++ b/libs/sensor/Sensor.cpp @@ -632,7 +632,13 @@ bool Sensor::unflattenString8(void const*& buffer, size_t& size, String8& output return false; } outputString8.setTo(static_cast(buffer), len); + + if (size < FlattenableUtils::align<4>(len)) { + ALOGE("Malformed Sensor String8 field. Should be in a 4-byte aligned buffer but is not."); + return false; + } FlattenableUtils::advance(buffer, size, FlattenableUtils::align<4>(len)); + return true; } -- GitLab From edb3f8e57fc25d3b0abd8cfc601cea814e90fcce Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Fri, 17 Feb 2023 19:35:25 +0000 Subject: [PATCH 0049/1187] Remove some new memory leaks from SensorManager After catching an error in Sensor::unflatten, there are memory leaks caught by the fuzzer in the same test case. Test: libsensorserviceaidl_fuzzer with testcase from bug Bug: 269014004 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:c95fa0f0e7c7b73746ff850b85a79fc5f92b784e) Merged-In: I509cceb41f56ca117d9475f6f6674244560fe582 Change-Id: I509cceb41f56ca117d9475f6f6674244560fe582 --- libs/sensor/ISensorServer.cpp | 12 ++++++++++-- libs/sensor/SensorManager.cpp | 5 +++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp index a6cacad374..93c95b98c5 100644 --- a/libs/sensor/ISensorServer.cpp +++ b/libs/sensor/ISensorServer.cpp @@ -66,7 +66,11 @@ public: v.setCapacity(n); while (n) { n--; - reply.read(s); + if(reply.read(s) != OK) { + ALOGE("Failed to read reply from getSensorList"); + v.clear(); + break; + } v.add(s); } return v; @@ -84,7 +88,11 @@ public: v.setCapacity(n); while (n) { n--; - reply.read(s); + if(reply.read(s) != OK) { + ALOGE("Failed to read reply from getDynamicSensorList"); + v.clear(); + break; + } v.add(s); } return v; diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp index 0ba9704263..c0525d4f5d 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -166,6 +166,11 @@ status_t SensorManager::assertStateLocked() { mSensors = mSensorServer->getSensorList(mOpPackageName); size_t count = mSensors.size(); + if (count == 0) { + ALOGE("Failed to get Sensor list"); + mSensorServer.clear(); + return UNKNOWN_ERROR; + } mSensorList = static_cast(malloc(count * sizeof(Sensor*))); LOG_ALWAYS_FATAL_IF(mSensorList == nullptr, "mSensorList NULL"); -- GitLab From 455ada53fcc0d3d06671f41993c6fd6c33d5db02 Mon Sep 17 00:00:00 2001 From: Anthony Stange Date: Tue, 21 Feb 2023 17:57:38 +0000 Subject: [PATCH 0050/1187] Add removeInstanceForPackageMethod to SensorManager In order to ensure that clients don't leak their sensor manager instance that we currently store in a static map, they need to be able to remove their instance. Otherwise, this instance is never removed from the list and will hang around until our SensorManage instance is destroyed. Bug: 269014004 Test: Run ./libsensorserviceaidl_fuzzer (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:9532f7c682fdd4b1e6e553cd6f61fc0cf2555902) Merged-In: I52185f74ae8d28b379440235ca6f03c5089081f5 Change-Id: I52185f74ae8d28b379440235ca6f03c5089081f5 --- libs/sensor/SensorManager.cpp | 10 ++++++++++ libs/sensor/include/sensor/SensorManager.h | 1 + services/sensorservice/hidl/SensorManager.cpp | 3 +++ 3 files changed, 14 insertions(+) diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp index c0525d4f5d..40061cde61 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -92,6 +92,16 @@ SensorManager& SensorManager::getInstanceForPackage(const String16& packageName) return *sensorManager; } +void SensorManager::removeInstanceForPackage(const String16& packageName) { + Mutex::Autolock _l(sLock); + auto iterator = sPackageInstances.find(packageName); + if (iterator != sPackageInstances.end()) { + SensorManager* sensorManager = iterator->second; + delete sensorManager; + sPackageInstances.erase(iterator); + } +} + SensorManager::SensorManager(const String16& opPackageName) : mSensorList(nullptr), mOpPackageName(opPackageName), mDirectConnectionHandle(1) { Mutex::Autolock _l(mLock); diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h index 8d0a8a45d9..7c9d604ff7 100644 --- a/libs/sensor/include/sensor/SensorManager.h +++ b/libs/sensor/include/sensor/SensorManager.h @@ -54,6 +54,7 @@ class SensorManager : public ASensorManager { public: static SensorManager& getInstanceForPackage(const String16& packageName); + static void removeInstanceForPackage(const String16& packageName); ~SensorManager(); ssize_t getSensorList(Sensor const* const** list); diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp index 938060063f..0a4e68412d 100644 --- a/services/sensorservice/hidl/SensorManager.cpp +++ b/services/sensorservice/hidl/SensorManager.cpp @@ -60,6 +60,9 @@ SensorManager::~SensorManager() { if (mPollThread.joinable()) { mPollThread.join(); } + + ::android::SensorManager::removeInstanceForPackage( + String16(ISensorManager::descriptor)); } // Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow. -- GitLab From e7fb46f5efa14e9002cffc3b8e442416550bbd59 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Tue, 28 Mar 2023 15:46:28 +0000 Subject: [PATCH 0051/1187] Use SkImages::BorrowTextureFrom Follow-up to https://googleplex-android-review.git.corp.google.com/c/platform/frameworks/base/+/22135940 Change-Id: Ibc95582a0de139d5d17b225aeadb8bbe6c1f5b9e Bug: skbug.com/13983 --- libs/renderengine/skia/AutoBackendTexture.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp index 5c122d4154..73b3b9cfcc 100644 --- a/libs/renderengine/skia/AutoBackendTexture.cpp +++ b/libs/renderengine/skia/AutoBackendTexture.cpp @@ -20,6 +20,9 @@ #define LOG_TAG "RenderEngine" #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include +#include + #include "ColorSpaces.h" #include "log/log_main.h" #include "utils/Trace.h" @@ -98,8 +101,9 @@ sk_sp AutoBackendTexture::makeImage(ui::Dataspace dataspace, SkAlphaTyp } sk_sp image = - SkImage::MakeFromTexture(context, mBackendTexture, kTopLeft_GrSurfaceOrigin, colorType, - alphaType, toSkColorSpace(dataspace), releaseImageProc, this); + SkImages::BorrowTextureFrom(context, mBackendTexture, kTopLeft_GrSurfaceOrigin, + colorType, alphaType, toSkColorSpace(dataspace), + releaseImageProc, this); if (image.get()) { // The following ref will be counteracted by releaseProc, when SkImage is discarded. ref(); -- GitLab From 9cba62a07f393d852dabf20b6e4d10e67b29c8d9 Mon Sep 17 00:00:00 2001 From: Ying Wei Date: Wed, 22 Mar 2023 22:25:28 +0000 Subject: [PATCH 0052/1187] Grab lock before reparenting in SurfaceFlinger commitMirrorDisplays() Bug: 271644537 Test: n/a Change-Id: I45384210791bd9280f63d95e3bdaef3d299fc818 --- services/surfaceflinger/SurfaceFlinger.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4367cf6cc0..b71df65148 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -7888,9 +7888,14 @@ bool SurfaceFlinger::commitMirrorDisplays(VsyncId vsyncId) { ISurfaceComposerClient::eNoColorFill, gui::LayerMetadata()); sp childMirror; - createEffectLayer(mirrorArgs, &unused, &childMirror); - childMirror->setClonedChild(layer->createClone()); - childMirror->reparent(mirrorDisplay.rootHandle); + { + Mutex::Autolock lock(mStateLock); + createEffectLayer(mirrorArgs, &unused, &childMirror); + childMirror->setClonedChild(layer->createClone()); + childMirror->reparent(mirrorDisplay.rootHandle); + } + // lock on mStateLock needs to be released before binder handle gets destroyed + unused.clear(); } } return true; -- GitLab From 66fad0ecb6406feab9bda7b8511dd228b4222c53 Mon Sep 17 00:00:00 2001 From: Ahmad Khalil Date: Thu, 30 Mar 2023 14:22:44 +0000 Subject: [PATCH 0053/1187] Removing test TestScheduleInParallelRunsInDelayOrder. It should be fine to remove this test since there's no need for ordering of different threads using relative time, and we do not offer ordering guarantees for relative timings across different threads. Ordering on a single thread is guaranteed and is still tested. Fix: 237099553 Test: We are just removing a test. Change-Id: Ie798ef62acce0e904293c7a856602ab7c9b8e5b0 --- .../test/VibratorCallbackSchedulerTest.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp index aaeb8f990a..4c0910a75e 100644 --- a/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp +++ b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp @@ -102,18 +102,6 @@ TEST_F(VibratorCallbackSchedulerTest, TestScheduleMultipleCallbacksRunsInDelayOr ASSERT_THAT(getExpiredCallbacks(), ElementsAre(3, 2, 1)); } -TEST_F(VibratorCallbackSchedulerTest, TestScheduleInParallelRunsInDelayOrder) { - std::vector threads; - for (int i = 0; i < 5; i++) { - threads.push_back(std::thread( - [=]() { mScheduler->schedule(createCallback(i), milliseconds(10 + 2 * i)); })); - } - std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); }); - - ASSERT_TRUE(waitForCallbacks(5, 25ms)); - ASSERT_THAT(getExpiredCallbacks(), ElementsAre(0, 1, 2, 3, 4)); -} - TEST_F(VibratorCallbackSchedulerTest, TestDestructorDropsPendingCallbacksAndKillsThread) { mScheduler->schedule(createCallback(1), 5ms); mScheduler.reset(nullptr); -- GitLab From 42d08f450b07080b3d2a64875a26046cce150822 Mon Sep 17 00:00:00 2001 From: Nick Deakin Date: Fri, 31 Mar 2023 16:00:13 -0400 Subject: [PATCH 0054/1187] jpegrecoverymap: XMP fixes. * Update semantic type from RecoveryMap to GainMap * Add parseType="Resource" to Directory rdf:li's, for XMP toolkit * Fix writing of HDRCapacity Min and Max values Bug: 264715926 Test: Tests pass Change-Id: Ia4073cd75646dd79aee391e8d44169b3527f6e93 --- .../include/jpegrecoverymap/jpegrutils.h | 18 ++--- libs/jpegrecoverymap/jpegrutils.cpp | 71 +++++++++++-------- libs/jpegrecoverymap/tests/jpegr_test.cpp | 4 +- 3 files changed, 53 insertions(+), 40 deletions(-) diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h index dd06fa24b1..09f416555c 100644 --- a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h +++ b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegrutils.h @@ -105,14 +105,16 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, jpegr_metadata_struc * xmlns:Item="http://ns.google.com/photos/1.0/container/item/"> * * - * + * * * - * + * * * @@ -142,14 +144,14 @@ std::string generateXmpForPrimaryImage(int secondary_image_length); * + * hdrgm:HDRCapacityMin="0" + * hdrgm:HDRCapacityMax="3" + * hdrgm:BaseRenditionIsHDR="False"/> * * * diff --git a/libs/jpegrecoverymap/jpegrutils.cpp b/libs/jpegrecoverymap/jpegrutils.cpp index ff96447320..cde0ceb520 100644 --- a/libs/jpegrecoverymap/jpegrutils.cpp +++ b/libs/jpegrecoverymap/jpegrutils.cpp @@ -15,14 +15,17 @@ */ #include -#include + +#include +#include + #include #include #include #include #include #include -#include +#include using namespace photos_editing_formats::image_io; using namespace std; @@ -230,26 +233,26 @@ const string kItemMime = Name(kItemPrefix, "Mime"); const string kItemSemantic = Name(kItemPrefix, "Semantic"); // Item XMP constants - element and attribute values -const string kSemanticPrimary = "Primary"; -const string kSemanticRecoveryMap = "RecoveryMap"; -const string kMimeImageJpeg = "image/jpeg"; - -// RecoveryMap XMP constants - URI and namespace prefix -const string kRecoveryMapUri = "http://ns.adobe.com/hdr-gain-map/1.0/"; -const string kRecoveryMapPrefix = "hdrgm"; - -// RecoveryMap XMP constants - element and attribute names -const string kMapVersion = Name(kRecoveryMapPrefix, "Version"); -const string kMapGainMapMin = Name(kRecoveryMapPrefix, "GainMapMin"); -const string kMapGainMapMax = Name(kRecoveryMapPrefix, "GainMapMax"); -const string kMapGamma = Name(kRecoveryMapPrefix, "Gamma"); -const string kMapOffsetSdr = Name(kRecoveryMapPrefix, "OffsetSDR"); -const string kMapOffsetHdr = Name(kRecoveryMapPrefix, "OffsetHDR"); -const string kMapHDRCapacityMin = Name(kRecoveryMapPrefix, "HDRCapacityMin"); -const string kMapHDRCapacityMax = Name(kRecoveryMapPrefix, "HDRCapacityMax"); -const string kMapBaseRendition = Name(kRecoveryMapPrefix, "BaseRendition"); - -// RecoveryMap XMP constants - names for XMP handlers +const string kSemanticPrimary = "Primary"; +const string kSemanticGainMap = "GainMap"; +const string kMimeImageJpeg = "image/jpeg"; + +// GainMap XMP constants - URI and namespace prefix +const string kGainMapUri = "http://ns.adobe.com/hdr-gain-map/1.0/"; +const string kGainMapPrefix = "hdrgm"; + +// GainMap XMP constants - element and attribute names +const string kMapVersion = Name(kGainMapPrefix, "Version"); +const string kMapGainMapMin = Name(kGainMapPrefix, "GainMapMin"); +const string kMapGainMapMax = Name(kGainMapPrefix, "GainMapMax"); +const string kMapGamma = Name(kGainMapPrefix, "Gamma"); +const string kMapOffsetSdr = Name(kGainMapPrefix, "OffsetSDR"); +const string kMapOffsetHdr = Name(kGainMapPrefix, "OffsetHDR"); +const string kMapHDRCapacityMin = Name(kGainMapPrefix, "HDRCapacityMin"); +const string kMapHDRCapacityMax = Name(kGainMapPrefix, "HDRCapacityMax"); +const string kMapBaseRenditionIsHDR = Name(kGainMapPrefix, "BaseRenditionIsHDR"); + +// GainMap XMP constants - names for XMP handlers const string XMPXmlHandler::minContentBoostAttrName = kMapGainMapMin; const string XMPXmlHandler::maxContentBoostAttrName = kMapGainMapMax; @@ -313,15 +316,23 @@ string generateXmpForPrimaryImage(int secondary_image_length) { writer.StartWritingElement("rdf:Description"); writer.WriteXmlns(kContainerPrefix, kContainerUri); writer.WriteXmlns(kItemPrefix, kItemUri); + writer.StartWritingElements(kConDirSeq); - size_t item_depth = writer.StartWritingElements(kLiItem); + + size_t item_depth = writer.StartWritingElement("rdf:li"); + writer.WriteAttributeNameAndValue("rdf:parseType", "Resource"); + writer.StartWritingElement(kConItem); writer.WriteAttributeNameAndValue(kItemSemantic, kSemanticPrimary); writer.WriteAttributeNameAndValue(kItemMime, kMimeImageJpeg); writer.FinishWritingElementsToDepth(item_depth); - writer.StartWritingElements(kLiItem); - writer.WriteAttributeNameAndValue(kItemSemantic, kSemanticRecoveryMap); + + writer.StartWritingElement("rdf:li"); + writer.WriteAttributeNameAndValue("rdf:parseType", "Resource"); + writer.StartWritingElement(kConItem); + writer.WriteAttributeNameAndValue(kItemSemantic, kSemanticGainMap); writer.WriteAttributeNameAndValue(kItemMime, kMimeImageJpeg); writer.WriteAttributeNameAndValue(kItemLength, secondary_image_length); + writer.FinishWriting(); return ss.str(); @@ -329,7 +340,6 @@ string generateXmpForPrimaryImage(int secondary_image_length) { string generateXmpForSecondaryImage(jpegr_metadata_struct& metadata) { const vector kConDirSeq({kConDirectory, string("rdf:Seq")}); - const vector kLiItem({string("rdf:li"), kConItem}); std::stringstream ss; photos_editing_formats::image_io::XmlWriter writer(ss); @@ -339,16 +349,17 @@ string generateXmpForSecondaryImage(jpegr_metadata_struct& metadata) { writer.StartWritingElement("rdf:RDF"); writer.WriteXmlns("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); writer.StartWritingElement("rdf:Description"); - writer.WriteXmlns(kRecoveryMapPrefix, kRecoveryMapUri); + writer.WriteXmlns(kGainMapPrefix, kGainMapUri); writer.WriteAttributeNameAndValue(kMapVersion, metadata.version); writer.WriteAttributeNameAndValue(kMapGainMapMin, log2(metadata.minContentBoost)); writer.WriteAttributeNameAndValue(kMapGainMapMax, log2(metadata.maxContentBoost)); writer.WriteAttributeNameAndValue(kMapGamma, "1"); writer.WriteAttributeNameAndValue(kMapOffsetSdr, "0"); writer.WriteAttributeNameAndValue(kMapOffsetHdr, "0"); - writer.WriteAttributeNameAndValue(kMapHDRCapacityMin, "0"); - writer.WriteAttributeNameAndValue(kMapHDRCapacityMax, "2.3"); - writer.WriteAttributeNameAndValue(kMapBaseRendition, "SDR"); + writer.WriteAttributeNameAndValue( + kMapHDRCapacityMin, std::max(log2(metadata.minContentBoost), 0.0f)); + writer.WriteAttributeNameAndValue(kMapHDRCapacityMax, log2(metadata.maxContentBoost)); + writer.WriteAttributeNameAndValue(kMapBaseRenditionIsHDR, "False"); writer.FinishWriting(); return ss.str(); diff --git a/libs/jpegrecoverymap/tests/jpegr_test.cpp b/libs/jpegrecoverymap/tests/jpegr_test.cpp index df90f53c41..7c669aba0a 100644 --- a/libs/jpegrecoverymap/tests/jpegr_test.cpp +++ b/libs/jpegrecoverymap/tests/jpegr_test.cpp @@ -192,8 +192,8 @@ TEST_F(JpegRTest, writeXmpThenRead) { jpegr_metadata_struct metadata_read; EXPECT_TRUE(getMetadataFromXMP(xmpData.data(), xmpData.size(), &metadata_read)); - ASSERT_EQ(metadata_expected.maxContentBoost, metadata_read.maxContentBoost); - ASSERT_EQ(metadata_expected.minContentBoost, metadata_read.minContentBoost); + EXPECT_FLOAT_EQ(metadata_expected.maxContentBoost, metadata_read.maxContentBoost); + EXPECT_FLOAT_EQ(metadata_expected.minContentBoost, metadata_read.minContentBoost); } /* Test Encode API-0 and decode */ -- GitLab From 71ddb4376475db6bb77d32aa6aa3ce56a6ce20e0 Mon Sep 17 00:00:00 2001 From: Justin Chung Date: Mon, 27 Mar 2023 04:29:07 +0000 Subject: [PATCH 0055/1187] Keep touch mode for the key event triggered by gesture Bug: 267391997 Test: atest --host libinput_tests inputflinger_tests Change-Id: I686cb8f9dff01f5964f40518ea60509d806b8d8f --- include/input/Input.h | 1 + .../reader/mapper/KeyboardInputMapper.cpp | 12 ++++++++---- .../reader/mapper/KeyboardInputMapper.h | 1 + services/inputflinger/tests/InputReader_test.cpp | 13 +++++++++++++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index e8af5f7d46..b5959fbb19 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -243,6 +243,7 @@ enum { // Indicates that the key represents a special gesture that has been detected by // the touch firmware or driver. Causes touch events from the same device to be canceled. + // This policy flag prevents key events from changing touch mode state. POLICY_FLAG_GESTURE = 0x00000008, POLICY_FLAG_RAW_MASK = 0x0000ffff, diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp index 269c1060d6..ef46fb144f 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp @@ -199,6 +199,7 @@ std::list KeyboardInputMapper::processKey(nsecs_t when, nsecs_t read int32_t keyCode; int32_t keyMetaState; uint32_t policyFlags; + int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM; if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState, &policyFlags)) { @@ -220,6 +221,7 @@ std::list KeyboardInputMapper::processKey(nsecs_t when, nsecs_t read // key repeat, be sure to use same keycode as before in case of rotation keyCode = mKeyDowns[*keyDownIndex].keyCode; downTime = mKeyDowns[*keyDownIndex].downTime; + flags = mKeyDowns[*keyDownIndex].flags; } else { // key down if ((policyFlags & POLICY_FLAG_VIRTUAL) && @@ -228,12 +230,14 @@ std::list KeyboardInputMapper::processKey(nsecs_t when, nsecs_t read } if (policyFlags & POLICY_FLAG_GESTURE) { out += getDeviceContext().cancelTouch(when, readTime); + flags |= AKEY_EVENT_FLAG_KEEP_TOUCH_MODE; } KeyDown keyDown; keyDown.keyCode = keyCode; keyDown.scanCode = scanCode; keyDown.downTime = when; + keyDown.flags = flags; mKeyDowns.push_back(keyDown); } } else { @@ -242,6 +246,7 @@ std::list KeyboardInputMapper::processKey(nsecs_t when, nsecs_t read // key up, be sure to use same keycode as before in case of rotation keyCode = mKeyDowns[*keyDownIndex].keyCode; downTime = mKeyDowns[*keyDownIndex].downTime; + flags = mKeyDowns[*keyDownIndex].flags; mKeyDowns.erase(mKeyDowns.begin() + *keyDownIndex); } else { // key was not actually down @@ -275,9 +280,8 @@ std::list KeyboardInputMapper::processKey(nsecs_t when, nsecs_t read out.emplace_back(NotifyKeyArgs(getContext()->getNextId(), when, readTime, getDeviceId(), mSource, getDisplayId(), policyFlags, - down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, - downTime)); + down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, flags, + keyCode, scanCode, keyMetaState, downTime)); return out; } @@ -404,7 +408,7 @@ std::list KeyboardInputMapper::cancelAllDownKeys(nsecs_t when) { out.emplace_back(NotifyKeyArgs(getContext()->getNextId(), when, systemTime(SYSTEM_TIME_MONOTONIC), getDeviceId(), mSource, getDisplayId(), /*policyFlags=*/0, AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_CANCELED, + mKeyDowns[i].flags | AKEY_EVENT_FLAG_CANCELED, mKeyDowns[i].keyCode, mKeyDowns[i].scanCode, AMETA_NONE, mKeyDowns[i].downTime)); } diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h index 2fc82c3d13..fe6812c705 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h @@ -54,6 +54,7 @@ private: nsecs_t downTime{}; int32_t keyCode{}; int32_t scanCode{}; + int32_t flags{}; }; uint32_t mSource{}; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 853c5b0115..5d369768bd 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -3651,6 +3651,19 @@ TEST_F(KeyboardInputMapperTest, LayoutInfoCorrectlyMapped) { ASSERT_EQ("extended", mDevice->getDeviceInfo().getKeyboardLayoutInfo()->layoutType); } +TEST_F(KeyboardInputMapperTest, Process_GesureEventToSetFlagKeepTouchMode) { + mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, POLICY_FLAG_GESTURE); + KeyboardInputMapper& mapper = + addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); + NotifyKeyArgs args; + + // Key down + process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_LEFT, 1); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); + ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_KEEP_TOUCH_MODE, args.flags); +} + // --- KeyboardInputMapperTest_ExternalDevice --- class KeyboardInputMapperTest_ExternalDevice : public InputMapperTest { -- GitLab From 343626c30d16bd0979860e094d0bf3a57570b303 Mon Sep 17 00:00:00 2001 From: Parth Sane Date: Thu, 6 Apr 2023 16:17:04 +0000 Subject: [PATCH 0056/1187] Add Traces to SurfaceFlinger constructor and init This will help debug boot time regressions Test: Manually checked that boot trace has the init and constructor slices in perfetto Bug: 271576143 Change-Id: I91287e3810052ae08933b3631453698ab2d30a59 --- services/surfaceflinger/SurfaceFlinger.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2f024cedac..14c757d2b1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -373,6 +373,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) } SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) { + ATRACE_CALL(); ALOGI("SurfaceFlinger is starting"); hasSyncFramework = running_without_sync_framework(true); @@ -799,6 +800,7 @@ chooseRenderEngineTypeViaSysProp() { // Do not call property_set on main thread which will be blocked by init // Use StartPropertySetThread instead. void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { + ATRACE_CALL(); ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); addTransactionReadyFilters(); -- GitLab From 9c8646077a6ae0e11a0ae90f64a5a084756cbd73 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 13 Apr 2023 20:29:33 +0000 Subject: [PATCH 0057/1187] lazy AIDL services: test multiple callbacks In order to test multiple lazy callbacks, an additional API is exposed from LazyServiceRegistrar. Bug: 278038751 Test: aidl_lazy_test Change-Id: I3cb102a9727b5f126703d389fb416969fccae26d --- libs/binder/LazyServiceRegistrar.cpp | 4 ++++ libs/binder/include/binder/LazyServiceRegistrar.h | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp index f66993f926..7644806e2b 100644 --- a/libs/binder/LazyServiceRegistrar.cpp +++ b/libs/binder/LazyServiceRegistrar.cpp @@ -324,6 +324,10 @@ LazyServiceRegistrar& LazyServiceRegistrar::getInstance() { return *registrarInstance; } +LazyServiceRegistrar LazyServiceRegistrar::createExtraTestInstance() { + return LazyServiceRegistrar(); +} + status_t LazyServiceRegistrar::registerService(const sp& service, const std::string& name, bool allowIsolated, int dumpFlags) { if (!mClientCC->registerService(service, name, allowIsolated, dumpFlags)) { diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h index 2e22b84ff0..bda3d19ee1 100644 --- a/libs/binder/include/binder/LazyServiceRegistrar.h +++ b/libs/binder/include/binder/LazyServiceRegistrar.h @@ -93,7 +93,17 @@ class LazyServiceRegistrar { */ void reRegister(); - private: + /** + * Create a second instance of lazy service registrar. + * + * WARNING: dangerous! DO NOT USE THIS - LazyServiceRegistrar + * should be single-instanced, so that the service will only + * shut down when all services are unused. A separate instance + * is only used to test race conditions. + */ + static LazyServiceRegistrar createExtraTestInstance(); + + private: std::shared_ptr mClientCC; LazyServiceRegistrar(); }; -- GitLab From 9be91876fc7458e2095077257538d48d050e56fc Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 13 Apr 2023 22:08:37 +0000 Subject: [PATCH 0058/1187] Explicit init .rc user. Set the user explicitly. Bug: 276813155 Test: boot Change-Id: I9cbd77afb04303a3e09643cc1029aef7fee2ae3b --- cmds/servicemanager/servicemanager.recovery.rc | 1 + 1 file changed, 1 insertion(+) diff --git a/cmds/servicemanager/servicemanager.recovery.rc b/cmds/servicemanager/servicemanager.recovery.rc index b927c018df..6354fd7d53 100644 --- a/cmds/servicemanager/servicemanager.recovery.rc +++ b/cmds/servicemanager/servicemanager.recovery.rc @@ -1,5 +1,6 @@ service servicemanager /system/bin/servicemanager disabled group system readproc + user root onrestart setprop servicemanager.ready false seclabel u:r:servicemanager:s0 -- GitLab From c392d8f88e1e6060353ecc7f4a6563e55cb77f23 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 13 Apr 2023 19:32:51 +0000 Subject: [PATCH 0059/1187] InputListener: Pass NotifyArgs by reference Bug: 245989146 Test: Presubmit Change-Id: I15af8a6737625a062f31acc1ab6974d52eb91d66 --- services/inputflinger/InputListener.cpp | 67 +- services/inputflinger/InputProcessor.cpp | 28 +- services/inputflinger/InputProcessor.h | 16 +- .../UnwantedInteractionBlocker.cpp | 40 +- .../inputflinger/UnwantedInteractionBlocker.h | 18 +- .../benchmarks/InputDispatcher_benchmarks.cpp | 4 +- .../dispatcher/InputDispatcher.cpp | 190 ++-- .../inputflinger/dispatcher/InputDispatcher.h | 20 +- services/inputflinger/include/InputListener.h | 32 +- services/inputflinger/include/NotifyArgs.h | 9 +- services/inputflinger/reader/InputReader.cpp | 8 +- .../tests/InputDispatcher_test.cpp | 873 ++++++++---------- .../tests/InputProcessor_test.cpp | 18 +- .../inputflinger/tests/TestInputListener.cpp | 22 +- .../inputflinger/tests/TestInputListener.h | 18 +- .../tests/UnwantedInteractionBlocker_test.cpp | 120 +-- .../tests/fuzzers/InputClassifierFuzzer.cpp | 51 +- .../tests/fuzzers/MapperHelpers.h | 16 +- 18 files changed, 695 insertions(+), 855 deletions(-) diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp index 1bc1adf154..aa55873aa5 100644 --- a/services/inputflinger/InputListener.cpp +++ b/services/inputflinger/InputListener.cpp @@ -47,16 +47,14 @@ Visitor(V...) -> Visitor; void InputListenerInterface::notify(const NotifyArgs& generalArgs) { Visitor v{ [&](const NotifyInputDevicesChangedArgs& args) { notifyInputDevicesChanged(args); }, - [&](const NotifyConfigurationChangedArgs& args) { notifyConfigurationChanged(&args); }, - [&](const NotifyKeyArgs& args) { notifyKey(&args); }, - [&](const NotifyMotionArgs& args) { notifyMotion(&args); }, - [&](const NotifySwitchArgs& args) { notifySwitch(&args); }, - [&](const NotifySensorArgs& args) { notifySensor(&args); }, - [&](const NotifyVibratorStateArgs& args) { notifyVibratorState(&args); }, - [&](const NotifyDeviceResetArgs& args) { notifyDeviceReset(&args); }, - [&](const NotifyPointerCaptureChangedArgs& args) { - notifyPointerCaptureChanged(&args); - }, + [&](const NotifyConfigurationChangedArgs& args) { notifyConfigurationChanged(args); }, + [&](const NotifyKeyArgs& args) { notifyKey(args); }, + [&](const NotifyMotionArgs& args) { notifyMotion(args); }, + [&](const NotifySwitchArgs& args) { notifySwitch(args); }, + [&](const NotifySensorArgs& args) { notifySensor(args); }, + [&](const NotifyVibratorStateArgs& args) { notifyVibratorState(args); }, + [&](const NotifyDeviceResetArgs& args) { notifyDeviceReset(args); }, + [&](const NotifyPointerCaptureChangedArgs& args) { notifyPointerCaptureChanged(args); }, }; std::visit(v, generalArgs); } @@ -78,45 +76,44 @@ void QueuedInputListener::notifyInputDevicesChanged(const NotifyInputDevicesChan mArgsQueue.emplace_back(args); } -void QueuedInputListener::notifyConfigurationChanged( - const NotifyConfigurationChangedArgs* args) { - traceEvent(__func__, args->id); - mArgsQueue.emplace_back(*args); +void QueuedInputListener::notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) { + traceEvent(__func__, args.id); + mArgsQueue.emplace_back(args); } -void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) { - traceEvent(__func__, args->id); - mArgsQueue.emplace_back(*args); +void QueuedInputListener::notifyKey(const NotifyKeyArgs& args) { + traceEvent(__func__, args.id); + mArgsQueue.emplace_back(args); } -void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { - traceEvent(__func__, args->id); - mArgsQueue.emplace_back(*args); +void QueuedInputListener::notifyMotion(const NotifyMotionArgs& args) { + traceEvent(__func__, args.id); + mArgsQueue.emplace_back(args); } -void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) { - traceEvent(__func__, args->id); - mArgsQueue.emplace_back(*args); +void QueuedInputListener::notifySwitch(const NotifySwitchArgs& args) { + traceEvent(__func__, args.id); + mArgsQueue.emplace_back(args); } -void QueuedInputListener::notifySensor(const NotifySensorArgs* args) { - traceEvent(__func__, args->id); - mArgsQueue.emplace_back(*args); +void QueuedInputListener::notifySensor(const NotifySensorArgs& args) { + traceEvent(__func__, args.id); + mArgsQueue.emplace_back(args); } -void QueuedInputListener::notifyVibratorState(const NotifyVibratorStateArgs* args) { - traceEvent(__func__, args->id); - mArgsQueue.emplace_back(*args); +void QueuedInputListener::notifyVibratorState(const NotifyVibratorStateArgs& args) { + traceEvent(__func__, args.id); + mArgsQueue.emplace_back(args); } -void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) { - traceEvent(__func__, args->id); - mArgsQueue.emplace_back(*args); +void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs& args) { + traceEvent(__func__, args.id); + mArgsQueue.emplace_back(args); } -void QueuedInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) { - traceEvent(__func__, args->id); - mArgsQueue.emplace_back(*args); +void QueuedInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) { + traceEvent(__func__, args.id); + mArgsQueue.emplace_back(args); } void QueuedInputListener::flush() { diff --git a/services/inputflinger/InputProcessor.cpp b/services/inputflinger/InputProcessor.cpp index 6c0bcffd6b..7a84be93b1 100644 --- a/services/inputflinger/InputProcessor.cpp +++ b/services/inputflinger/InputProcessor.cpp @@ -419,63 +419,63 @@ void InputProcessor::notifyInputDevicesChanged(const NotifyInputDevicesChangedAr mQueuedListener.flush(); } -void InputProcessor::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { +void InputProcessor::notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) { // pass through mQueuedListener.notifyConfigurationChanged(args); mQueuedListener.flush(); } -void InputProcessor::notifyKey(const NotifyKeyArgs* args) { +void InputProcessor::notifyKey(const NotifyKeyArgs& args) { // pass through mQueuedListener.notifyKey(args); mQueuedListener.flush(); } -void InputProcessor::notifyMotion(const NotifyMotionArgs* args) { +void InputProcessor::notifyMotion(const NotifyMotionArgs& args) { { // acquire lock std::scoped_lock lock(mLock); // MotionClassifier is only used for touch events, for now - const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(*args); + const bool sendToMotionClassifier = mMotionClassifier && isTouchEvent(args); if (!sendToMotionClassifier) { mQueuedListener.notifyMotion(args); } else { - NotifyMotionArgs newArgs(*args); + NotifyMotionArgs newArgs(args); const MotionClassification newClassification = mMotionClassifier->classify(newArgs); - LOG_ALWAYS_FATAL_IF(args->classification != MotionClassification::NONE && + LOG_ALWAYS_FATAL_IF(args.classification != MotionClassification::NONE && newClassification != MotionClassification::NONE, "Conflicting classifications %s (new) and %s (old)!", motionClassificationToString(newClassification), - motionClassificationToString(args->classification)); + motionClassificationToString(args.classification)); newArgs.classification = newClassification; - mQueuedListener.notifyMotion(&newArgs); + mQueuedListener.notifyMotion(newArgs); } } // release lock mQueuedListener.flush(); } -void InputProcessor::notifySensor(const NotifySensorArgs* args) { +void InputProcessor::notifySensor(const NotifySensorArgs& args) { // pass through mQueuedListener.notifySensor(args); mQueuedListener.flush(); } -void InputProcessor::notifyVibratorState(const NotifyVibratorStateArgs* args) { +void InputProcessor::notifyVibratorState(const NotifyVibratorStateArgs& args) { // pass through mQueuedListener.notifyVibratorState(args); mQueuedListener.flush(); } -void InputProcessor::notifySwitch(const NotifySwitchArgs* args) { +void InputProcessor::notifySwitch(const NotifySwitchArgs& args) { // pass through mQueuedListener.notifySwitch(args); mQueuedListener.flush(); } -void InputProcessor::notifyDeviceReset(const NotifyDeviceResetArgs* args) { +void InputProcessor::notifyDeviceReset(const NotifyDeviceResetArgs& args) { { // acquire lock std::scoped_lock lock(mLock); if (mMotionClassifier) { - mMotionClassifier->reset(*args); + mMotionClassifier->reset(args); } } // release lock @@ -484,7 +484,7 @@ void InputProcessor::notifyDeviceReset(const NotifyDeviceResetArgs* args) { mQueuedListener.flush(); } -void InputProcessor::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) { +void InputProcessor::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) { // pass through mQueuedListener.notifyPointerCaptureChanged(args); mQueuedListener.flush(); diff --git a/services/inputflinger/InputProcessor.h b/services/inputflinger/InputProcessor.h index 01795a8983..dcbfebc62f 100644 --- a/services/inputflinger/InputProcessor.h +++ b/services/inputflinger/InputProcessor.h @@ -246,14 +246,14 @@ public: explicit InputProcessor(InputListenerInterface& listener); void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override; - void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; - void notifyKey(const NotifyKeyArgs* args) override; - void notifyMotion(const NotifyMotionArgs* args) override; - void notifySwitch(const NotifySwitchArgs* args) override; - void notifySensor(const NotifySensorArgs* args) override; - void notifyVibratorState(const NotifyVibratorStateArgs* args) override; - void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; - void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override; + void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override; + void notifyKey(const NotifyKeyArgs& args) override; + void notifyMotion(const NotifyMotionArgs& args) override; + void notifySwitch(const NotifySwitchArgs& args) override; + void notifySensor(const NotifySensorArgs& args) override; + void notifyVibratorState(const NotifyVibratorStateArgs& args) override; + void notifyDeviceReset(const NotifyDeviceResetArgs& args) override; + void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override; void dump(std::string& dump) override; void monitor() override; diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp index 6d43e8d009..02bc47d6bb 100644 --- a/services/inputflinger/UnwantedInteractionBlocker.cpp +++ b/services/inputflinger/UnwantedInteractionBlocker.cpp @@ -329,24 +329,24 @@ UnwantedInteractionBlocker::UnwantedInteractionBlocker(InputListenerInterface& l : mQueuedListener(listener), mEnablePalmRejection(enablePalmRejection) {} void UnwantedInteractionBlocker::notifyConfigurationChanged( - const NotifyConfigurationChangedArgs* args) { + const NotifyConfigurationChangedArgs& args) { mQueuedListener.notifyConfigurationChanged(args); mQueuedListener.flush(); } -void UnwantedInteractionBlocker::notifyKey(const NotifyKeyArgs* args) { +void UnwantedInteractionBlocker::notifyKey(const NotifyKeyArgs& args) { mQueuedListener.notifyKey(args); mQueuedListener.flush(); } -void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) { - ALOGD_IF(DEBUG_INBOUND_MOTION, "%s: %s", __func__, args->dump().c_str()); +void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs& args) { + ALOGD_IF(DEBUG_INBOUND_MOTION, "%s: %s", __func__, args.dump().c_str()); { // acquire lock std::scoped_lock lock(mLock); const std::vector processedArgs = - mPreferStylusOverTouchBlocker.processMotion(*args); + mPreferStylusOverTouchBlocker.processMotion(args); for (const NotifyMotionArgs& loopArgs : processedArgs) { - notifyMotionLocked(&loopArgs); + notifyMotionLocked(loopArgs); } } // release lock @@ -356,56 +356,56 @@ void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs* args) { void UnwantedInteractionBlocker::enqueueOutboundMotionLocked(const NotifyMotionArgs& args) { ALOGD_IF(DEBUG_OUTBOUND_MOTION, "%s: %s", __func__, args.dump().c_str()); - mQueuedListener.notifyMotion(&args); + mQueuedListener.notifyMotion(args); } -void UnwantedInteractionBlocker::notifyMotionLocked(const NotifyMotionArgs* args) { - auto it = mPalmRejectors.find(args->deviceId); - const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args->source); +void UnwantedInteractionBlocker::notifyMotionLocked(const NotifyMotionArgs& args) { + auto it = mPalmRejectors.find(args.deviceId); + const bool sendToPalmRejector = it != mPalmRejectors.end() && isFromTouchscreen(args.source); if (!sendToPalmRejector) { - enqueueOutboundMotionLocked(*args); + enqueueOutboundMotionLocked(args); return; } - std::vector processedArgs = it->second.processMotion(*args); + std::vector processedArgs = it->second.processMotion(args); for (const NotifyMotionArgs& loopArgs : processedArgs) { enqueueOutboundMotionLocked(loopArgs); } } -void UnwantedInteractionBlocker::notifySwitch(const NotifySwitchArgs* args) { +void UnwantedInteractionBlocker::notifySwitch(const NotifySwitchArgs& args) { mQueuedListener.notifySwitch(args); mQueuedListener.flush(); } -void UnwantedInteractionBlocker::notifySensor(const NotifySensorArgs* args) { +void UnwantedInteractionBlocker::notifySensor(const NotifySensorArgs& args) { mQueuedListener.notifySensor(args); mQueuedListener.flush(); } -void UnwantedInteractionBlocker::notifyVibratorState(const NotifyVibratorStateArgs* args) { +void UnwantedInteractionBlocker::notifyVibratorState(const NotifyVibratorStateArgs& args) { mQueuedListener.notifyVibratorState(args); mQueuedListener.flush(); } -void UnwantedInteractionBlocker::notifyDeviceReset(const NotifyDeviceResetArgs* args) { +void UnwantedInteractionBlocker::notifyDeviceReset(const NotifyDeviceResetArgs& args) { { // acquire lock std::scoped_lock lock(mLock); - auto it = mPalmRejectors.find(args->deviceId); + auto it = mPalmRejectors.find(args.deviceId); if (it != mPalmRejectors.end()) { AndroidPalmFilterDeviceInfo info = it->second.getPalmFilterDeviceInfo(); // Re-create the object instead of resetting it mPalmRejectors.erase(it); - mPalmRejectors.emplace(args->deviceId, info); + mPalmRejectors.emplace(args.deviceId, info); } mQueuedListener.notifyDeviceReset(args); - mPreferStylusOverTouchBlocker.notifyDeviceReset(*args); + mPreferStylusOverTouchBlocker.notifyDeviceReset(args); } // release lock // Send events to the next stage without holding the lock mQueuedListener.flush(); } void UnwantedInteractionBlocker::notifyPointerCaptureChanged( - const NotifyPointerCaptureChangedArgs* args) { + const NotifyPointerCaptureChangedArgs& args) { mQueuedListener.notifyPointerCaptureChanged(args); mQueuedListener.flush(); } diff --git a/services/inputflinger/UnwantedInteractionBlocker.h b/services/inputflinger/UnwantedInteractionBlocker.h index 3bc5240eb6..419da8366e 100644 --- a/services/inputflinger/UnwantedInteractionBlocker.h +++ b/services/inputflinger/UnwantedInteractionBlocker.h @@ -91,14 +91,14 @@ public: explicit UnwantedInteractionBlocker(InputListenerInterface& listener, bool enablePalmRejection); void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override; - void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; - void notifyKey(const NotifyKeyArgs* args) override; - void notifyMotion(const NotifyMotionArgs* args) override; - void notifySwitch(const NotifySwitchArgs* args) override; - void notifySensor(const NotifySensorArgs* args) override; - void notifyVibratorState(const NotifyVibratorStateArgs* args) override; - void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; - void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override; + void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override; + void notifyKey(const NotifyKeyArgs& args) override; + void notifyMotion(const NotifyMotionArgs& args) override; + void notifySwitch(const NotifySwitchArgs& args) override; + void notifySensor(const NotifySensorArgs& args) override; + void notifyVibratorState(const NotifyVibratorStateArgs& args) override; + void notifyDeviceReset(const NotifyDeviceResetArgs& args) override; + void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override; void dump(std::string& dump) override; void monitor() override; @@ -119,7 +119,7 @@ private: // Use a separate palm rejector for every touch device. std::map mPalmRejectors GUARDED_BY(mLock); // TODO(b/210159205): delete this when simultaneous stylus and touch is supported - void notifyMotionLocked(const NotifyMotionArgs* args) REQUIRES(mLock); + void notifyMotionLocked(const NotifyMotionArgs& args) REQUIRES(mLock); // Call this function for outbound events so that they can be logged when logging is enabled. void enqueueOutboundMotionLocked(const NotifyMotionArgs& args) REQUIRES(mLock); diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index 58324c4762..f852001679 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -277,12 +277,12 @@ static void benchmarkNotifyMotion(benchmark::State& state) { motionArgs.action = AMOTION_EVENT_ACTION_DOWN; motionArgs.downTime = now(); motionArgs.eventTime = motionArgs.downTime; - dispatcher.notifyMotion(&motionArgs); + dispatcher.notifyMotion(motionArgs); // Send ACTION_UP motionArgs.action = AMOTION_EVENT_ACTION_UP; motionArgs.eventTime = now(); - dispatcher.notifyMotion(&motionArgs); + dispatcher.notifyMotion(motionArgs); window->consumeEvent(); window->consumeEvent(); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 7e244c9be1..a5677d1ecb 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4025,9 +4025,9 @@ std::unique_ptr InputDispatcher::splitMotionEvent( return splitMotionEntry; } -void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { +void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) { if (debugInboundEventDetails()) { - ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args->eventTime); + ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args.eventTime); } bool needWake = false; @@ -4035,7 +4035,7 @@ void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChange std::scoped_lock _l(mLock); std::unique_ptr newEntry = - std::make_unique(args->id, args->eventTime); + std::make_unique(args.id, args.eventTime); needWake = enqueueInboundEventLocked(std::move(newEntry)); } // release lock @@ -4083,23 +4083,22 @@ void InputDispatcher::accelerateMetaShortcuts(const int32_t deviceId, const int3 } } -void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { +void InputDispatcher::notifyKey(const NotifyKeyArgs& args) { ALOGD_IF(debugInboundEventDetails(), "notifyKey - id=%" PRIx32 ", eventTime=%" PRId64 ", deviceId=%d, source=%s, displayId=%" PRId32 "policyFlags=0x%x, action=%s, flags=0x%x, keyCode=%s, scanCode=0x%x, metaState=0x%x, " "downTime=%" PRId64, - args->id, args->eventTime, args->deviceId, - inputEventSourceToString(args->source).c_str(), args->displayId, args->policyFlags, - KeyEvent::actionToString(args->action), args->flags, KeyEvent::getLabel(args->keyCode), - args->scanCode, args->metaState, args->downTime); - if (!validateKeyEvent(args->action)) { + args.id, args.eventTime, args.deviceId, inputEventSourceToString(args.source).c_str(), + args.displayId, args.policyFlags, KeyEvent::actionToString(args.action), args.flags, + KeyEvent::getLabel(args.keyCode), args.scanCode, args.metaState, args.downTime); + if (!validateKeyEvent(args.action)) { return; } - uint32_t policyFlags = args->policyFlags; - int32_t flags = args->flags; - int32_t metaState = args->metaState; + uint32_t policyFlags = args.policyFlags; + int32_t flags = args.flags; + int32_t metaState = args.metaState; // InputDispatcher tracks and generates key repeats on behalf of // whatever notifies it, so repeatCount should always be set to 0 constexpr int32_t repeatCount = 0; @@ -4113,13 +4112,13 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { policyFlags |= POLICY_FLAG_TRUSTED; - int32_t keyCode = args->keyCode; - accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState); + int32_t keyCode = args.keyCode; + accelerateMetaShortcuts(args.deviceId, args.action, keyCode, metaState); KeyEvent event; - event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC, - args->action, flags, keyCode, args->scanCode, metaState, repeatCount, - args->downTime, args->eventTime); + event.initialize(args.id, args.deviceId, args.source, args.displayId, INVALID_HMAC, args.action, + flags, keyCode, args.scanCode, metaState, repeatCount, args.downTime, + args.eventTime); android::base::Timer t; mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); @@ -4144,10 +4143,9 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { } std::unique_ptr newEntry = - std::make_unique(args->id, args->eventTime, args->deviceId, args->source, - args->displayId, policyFlags, args->action, flags, - keyCode, args->scanCode, metaState, repeatCount, - args->downTime); + std::make_unique(args.id, args.eventTime, args.deviceId, args.source, + args.displayId, policyFlags, args.action, flags, keyCode, + args.scanCode, metaState, repeatCount, args.downTime); needWake = enqueueInboundEventLocked(std::move(newEntry)); mLock.unlock(); @@ -4158,47 +4156,47 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { } } -bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) { +bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs& args) { return mInputFilterEnabled; } -void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { +void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) { if (debugInboundEventDetails()) { ALOGD("notifyMotion - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=%s, " "displayId=%" PRId32 ", policyFlags=0x%x, " "action=%s, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, " "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, " "yCursorPosition=%f, downTime=%" PRId64, - args->id, args->eventTime, args->deviceId, - inputEventSourceToString(args->source).c_str(), args->displayId, args->policyFlags, - MotionEvent::actionToString(args->action).c_str(), args->actionButton, args->flags, - args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, - args->yPrecision, args->xCursorPosition, args->yCursorPosition, args->downTime); - for (uint32_t i = 0; i < args->pointerCount; i++) { + args.id, args.eventTime, args.deviceId, inputEventSourceToString(args.source).c_str(), + args.displayId, args.policyFlags, MotionEvent::actionToString(args.action).c_str(), + args.actionButton, args.flags, args.metaState, args.buttonState, args.edgeFlags, + args.xPrecision, args.yPrecision, args.xCursorPosition, args.yCursorPosition, + args.downTime); + for (uint32_t i = 0; i < args.pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%s, x=%f, y=%f, pressure=%f, size=%f, " "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, orientation=%f", - i, args->pointerProperties[i].id, - ftl::enum_string(args->pointerProperties[i].toolType).c_str(), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); - } - } - LOG_ALWAYS_FATAL_IF(!validateMotionEvent(args->action, args->actionButton, args->pointerCount, - args->pointerProperties), - "Invalid event: %s", args->dump().c_str()); - - uint32_t policyFlags = args->policyFlags; + i, args.pointerProperties[i].id, + ftl::enum_string(args.pointerProperties[i].toolType).c_str(), + args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), + args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), + args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), + args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), + args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), + args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), + args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), + args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), + args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); + } + } + LOG_ALWAYS_FATAL_IF(!validateMotionEvent(args.action, args.actionButton, args.pointerCount, + args.pointerProperties), + "Invalid event: %s", args.dump().c_str()); + + uint32_t policyFlags = args.policyFlags; policyFlags |= POLICY_FLAG_TRUSTED; android::base::Timer t; - mPolicy->interceptMotionBeforeQueueing(args->displayId, args->eventTime, /*byref*/ policyFlags); + mPolicy->interceptMotionBeforeQueueing(args.displayId, args.eventTime, policyFlags); if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) { ALOGW("Excessive delay in interceptMotionBeforeQueueing; took %s ms", std::to_string(t.duration().count()).c_str()); @@ -4210,10 +4208,10 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { if (!(policyFlags & POLICY_FLAG_PASS_TO_USER)) { // Set the flag anyway if we already have an ongoing gesture. That would allow us to // complete the processing of the current stroke. - const auto touchStateIt = mTouchStatesByDisplay.find(args->displayId); + const auto touchStateIt = mTouchStatesByDisplay.find(args.displayId); if (touchStateIt != mTouchStatesByDisplay.end()) { const TouchState& touchState = touchStateIt->second; - if (touchState.deviceId == args->deviceId && touchState.isDown()) { + if (touchState.deviceId == args.deviceId && touchState.isDown()) { policyFlags |= POLICY_FLAG_PASS_TO_USER; } } @@ -4221,20 +4219,20 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { if (shouldSendMotionToInputFilterLocked(args)) { ui::Transform displayTransform; - if (const auto it = mDisplayInfos.find(args->displayId); it != mDisplayInfos.end()) { + if (const auto it = mDisplayInfos.find(args.displayId); it != mDisplayInfos.end()) { displayTransform = it->second.transform; } mLock.unlock(); MotionEvent event; - event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC, - args->action, args->actionButton, args->flags, args->edgeFlags, - args->metaState, args->buttonState, args->classification, - displayTransform, args->xPrecision, args->yPrecision, - args->xCursorPosition, args->yCursorPosition, displayTransform, - args->downTime, args->eventTime, args->pointerCount, - args->pointerProperties, args->pointerCoords); + event.initialize(args.id, args.deviceId, args.source, args.displayId, INVALID_HMAC, + args.action, args.actionButton, args.flags, args.edgeFlags, + args.metaState, args.buttonState, args.classification, + displayTransform, args.xPrecision, args.yPrecision, + args.xCursorPosition, args.yCursorPosition, displayTransform, + args.downTime, args.eventTime, args.pointerCount, + args.pointerProperties, args.pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { @@ -4246,21 +4244,20 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { // Just enqueue a new motion event. std::unique_ptr newEntry = - std::make_unique(args->id, args->eventTime, args->deviceId, - args->source, args->displayId, policyFlags, - args->action, args->actionButton, args->flags, - args->metaState, args->buttonState, - args->classification, args->edgeFlags, - args->xPrecision, args->yPrecision, - args->xCursorPosition, args->yCursorPosition, - args->downTime, args->pointerCount, - args->pointerProperties, args->pointerCoords); - - if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID && - IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER && + std::make_unique(args.id, args.eventTime, args.deviceId, args.source, + args.displayId, policyFlags, args.action, + args.actionButton, args.flags, args.metaState, + args.buttonState, args.classification, args.edgeFlags, + args.xPrecision, args.yPrecision, + args.xCursorPosition, args.yCursorPosition, + args.downTime, args.pointerCount, + args.pointerProperties, args.pointerCoords); + + if (args.id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID && + IdGenerator::getSource(args.id) == IdGenerator::Source::INPUT_READER && !mInputFilterEnabled) { - const bool isDown = args->action == AMOTION_EVENT_ACTION_DOWN; - mLatencyTracker.trackListener(args->id, isDown, args->eventTime, args->readTime); + const bool isDown = args.action == AMOTION_EVENT_ACTION_DOWN; + mLatencyTracker.trackListener(args.id, isDown, args.eventTime, args.readTime); } needWake = enqueueInboundEventLocked(std::move(newEntry)); @@ -4272,12 +4269,12 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { } } -void InputDispatcher::notifySensor(const NotifySensorArgs* args) { +void InputDispatcher::notifySensor(const NotifySensorArgs& args) { if (debugInboundEventDetails()) { ALOGD("notifySensor - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, " " sensorType=%s", - args->id, args->eventTime, args->deviceId, args->source, - ftl::enum_string(args->sensorType).c_str()); + args.id, args.eventTime, args.deviceId, args.source, + ftl::enum_string(args.sensorType).c_str()); } bool needWake = false; @@ -4286,10 +4283,9 @@ void InputDispatcher::notifySensor(const NotifySensorArgs* args) { // Just enqueue a new sensor event. std::unique_ptr newEntry = - std::make_unique(args->id, args->eventTime, args->deviceId, - args->source, /* policyFlags=*/0, args->hwTimestamp, - args->sensorType, args->accuracy, - args->accuracyChanged, args->values); + std::make_unique(args.id, args.eventTime, args.deviceId, args.source, + /* policyFlags=*/0, args.hwTimestamp, args.sensorType, + args.accuracy, args.accuracyChanged, args.values); needWake = enqueueInboundEventLocked(std::move(newEntry)); mLock.unlock(); @@ -4300,34 +4296,34 @@ void InputDispatcher::notifySensor(const NotifySensorArgs* args) { } } -void InputDispatcher::notifyVibratorState(const NotifyVibratorStateArgs* args) { +void InputDispatcher::notifyVibratorState(const NotifyVibratorStateArgs& args) { if (debugInboundEventDetails()) { - ALOGD("notifyVibratorState - eventTime=%" PRId64 ", device=%d, isOn=%d", args->eventTime, - args->deviceId, args->isOn); + ALOGD("notifyVibratorState - eventTime=%" PRId64 ", device=%d, isOn=%d", args.eventTime, + args.deviceId, args.isOn); } - mPolicy->notifyVibratorState(args->deviceId, args->isOn); + mPolicy->notifyVibratorState(args.deviceId, args.isOn); } -bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) { +bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs& args) { return mInputFilterEnabled; } -void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) { +void InputDispatcher::notifySwitch(const NotifySwitchArgs& args) { if (debugInboundEventDetails()) { ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, " "switchMask=0x%08x", - args->eventTime, args->policyFlags, args->switchValues, args->switchMask); + args.eventTime, args.policyFlags, args.switchValues, args.switchMask); } - uint32_t policyFlags = args->policyFlags; + uint32_t policyFlags = args.policyFlags; policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->notifySwitch(args->eventTime, args->switchValues, args->switchMask, policyFlags); + mPolicy->notifySwitch(args.eventTime, args.switchValues, args.switchMask, policyFlags); } -void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { +void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs& args) { if (debugInboundEventDetails()) { - ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args->eventTime, - args->deviceId); + ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args.eventTime, + args.deviceId); } bool needWake = false; @@ -4335,7 +4331,7 @@ void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { std::scoped_lock _l(mLock); std::unique_ptr newEntry = - std::make_unique(args->id, args->eventTime, args->deviceId); + std::make_unique(args.id, args.eventTime, args.deviceId); needWake = enqueueInboundEventLocked(std::move(newEntry)); } // release lock @@ -4344,17 +4340,17 @@ void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { } } -void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) { +void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) { if (debugInboundEventDetails()) { - ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args->eventTime, - args->request.enable ? "true" : "false"); + ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args.eventTime, + args.request.enable ? "true" : "false"); } bool needWake = false; { // acquire lock std::scoped_lock _l(mLock); - auto entry = std::make_unique(args->id, args->eventTime, - args->request); + auto entry = + std::make_unique(args.id, args.eventTime, args.request); needWake = enqueueInboundEventLocked(std::move(entry)); } // release lock diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index aaf12146af..4aba24cc72 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -94,14 +94,14 @@ public: status_t stop() override; void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override{}; - void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; - void notifyKey(const NotifyKeyArgs* args) override; - void notifyMotion(const NotifyMotionArgs* args) override; - void notifySwitch(const NotifySwitchArgs* args) override; - void notifySensor(const NotifySensorArgs* args) override; - void notifyVibratorState(const NotifyVibratorStateArgs* args) override; - void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; - void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override; + void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override; + void notifyKey(const NotifyKeyArgs& args) override; + void notifyMotion(const NotifyMotionArgs& args) override; + void notifySwitch(const NotifySwitchArgs& args) override; + void notifySensor(const NotifySensorArgs& args) override; + void notifyVibratorState(const NotifyVibratorStateArgs& args) override; + void notifyDeviceReset(const NotifyDeviceResetArgs& args) override; + void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override; android::os::InputEventInjectionResult injectInputEvent( const InputEvent* event, std::optional targetUid, @@ -332,8 +332,8 @@ private: REQUIRES(mLock); // Input filter processing. - bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) REQUIRES(mLock); - bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) REQUIRES(mLock); + bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs& args) REQUIRES(mLock); + bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs& args) REQUIRES(mLock); // Inbound event processing. void drainInboundQueueLocked() REQUIRES(mLock); diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h index d1b86c8cc4..4f78f032c7 100644 --- a/services/inputflinger/include/InputListener.h +++ b/services/inputflinger/include/InputListener.h @@ -38,14 +38,14 @@ public: virtual ~InputListenerInterface() { } virtual void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) = 0; - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0; - virtual void notifyKey(const NotifyKeyArgs* args) = 0; - virtual void notifyMotion(const NotifyMotionArgs* args) = 0; - virtual void notifySwitch(const NotifySwitchArgs* args) = 0; - virtual void notifySensor(const NotifySensorArgs* args) = 0; - virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) = 0; - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0; - virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) = 0; + virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) = 0; + virtual void notifyKey(const NotifyKeyArgs& args) = 0; + virtual void notifyMotion(const NotifyMotionArgs& args) = 0; + virtual void notifySwitch(const NotifySwitchArgs& args) = 0; + virtual void notifySensor(const NotifySensorArgs& args) = 0; + virtual void notifyVibratorState(const NotifyVibratorStateArgs& args) = 0; + virtual void notifyDeviceReset(const NotifyDeviceResetArgs& args) = 0; + virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) = 0; void notify(const NotifyArgs& args); }; @@ -60,14 +60,14 @@ public: explicit QueuedInputListener(InputListenerInterface& innerListener); virtual void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override; - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; - virtual void notifyKey(const NotifyKeyArgs* args) override; - virtual void notifyMotion(const NotifyMotionArgs* args) override; - virtual void notifySwitch(const NotifySwitchArgs* args) override; - virtual void notifySensor(const NotifySensorArgs* args) override; - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; - void notifyVibratorState(const NotifyVibratorStateArgs* args) override; - void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override; + virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override; + virtual void notifyKey(const NotifyKeyArgs& args) override; + virtual void notifyMotion(const NotifyMotionArgs& args) override; + virtual void notifySwitch(const NotifySwitchArgs& args) override; + virtual void notifySensor(const NotifySensorArgs& args) override; + virtual void notifyDeviceReset(const NotifyDeviceResetArgs& args) override; + void notifyVibratorState(const NotifyVibratorStateArgs& args) override; + void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override; void flush(); diff --git a/services/inputflinger/include/NotifyArgs.h b/services/inputflinger/include/NotifyArgs.h index f12482b1b2..7d29dd9cb2 100644 --- a/services/inputflinger/include/NotifyArgs.h +++ b/services/inputflinger/include/NotifyArgs.h @@ -36,6 +36,7 @@ struct NotifyInputDevicesChangedArgs { bool operator==(const NotifyInputDevicesChangedArgs& rhs) const = default; NotifyInputDevicesChangedArgs(const NotifyInputDevicesChangedArgs& other) = default; + NotifyInputDevicesChangedArgs& operator=(const NotifyInputDevicesChangedArgs&) = default; }; /* Describes a configuration change event. */ @@ -50,6 +51,7 @@ struct NotifyConfigurationChangedArgs { bool operator==(const NotifyConfigurationChangedArgs& rhs) const = default; NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other) = default; + NotifyConfigurationChangedArgs& operator=(const NotifyConfigurationChangedArgs&) = default; }; /* Describes a key event. */ @@ -79,6 +81,7 @@ struct NotifyKeyArgs { bool operator==(const NotifyKeyArgs& rhs) const = default; NotifyKeyArgs(const NotifyKeyArgs& other) = default; + NotifyKeyArgs& operator=(const NotifyKeyArgs&) = default; }; /* Describes a motion event. */ @@ -129,7 +132,6 @@ struct NotifyMotionArgs { const std::vector& videoFrames); NotifyMotionArgs(const NotifyMotionArgs& other); - NotifyMotionArgs& operator=(const android::NotifyMotionArgs&) = default; bool operator==(const NotifyMotionArgs& rhs) const; @@ -157,6 +159,7 @@ struct NotifySensorArgs { bool accuracyChanged, nsecs_t hwTimestamp, std::vector values); NotifySensorArgs(const NotifySensorArgs& other) = default; + NotifySensorArgs& operator=(const NotifySensorArgs&) = default; }; /* Describes a switch event. */ @@ -174,6 +177,7 @@ struct NotifySwitchArgs { uint32_t switchMask); NotifySwitchArgs(const NotifySwitchArgs& other) = default; + NotifySwitchArgs& operator=(const NotifySwitchArgs&) = default; bool operator==(const NotifySwitchArgs& rhs) const = default; }; @@ -191,6 +195,7 @@ struct NotifyDeviceResetArgs { NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId); NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) = default; + NotifyDeviceResetArgs& operator=(const NotifyDeviceResetArgs&) = default; bool operator==(const NotifyDeviceResetArgs& rhs) const = default; }; @@ -207,6 +212,7 @@ struct NotifyPointerCaptureChangedArgs { NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime, const PointerCaptureRequest&); NotifyPointerCaptureChangedArgs(const NotifyPointerCaptureChangedArgs& other) = default; + NotifyPointerCaptureChangedArgs& operator=(const NotifyPointerCaptureChangedArgs&) = default; }; /* Describes a vibrator state event. */ @@ -222,6 +228,7 @@ struct NotifyVibratorStateArgs { NotifyVibratorStateArgs(int32_t id, nsecs_t eventTIme, int32_t deviceId, bool isOn); NotifyVibratorStateArgs(const NotifyVibratorStateArgs& other) = default; + NotifyVibratorStateArgs& operator=(const NotifyVibratorStateArgs&) = default; }; using NotifyArgs = diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 6f54faacee..0afe79dcc4 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -387,8 +387,7 @@ void InputReader::handleConfigurationChangedLocked(nsecs_t when) { updateGlobalMetaStateLocked(); // Enqueue configuration changed. - NotifyConfigurationChangedArgs args(mContext.getNextId(), when); - mQueuedListener.notifyConfigurationChanged(&args); + mQueuedListener.notifyConfigurationChanged({mContext.getNextId(), when}); } void InputReader::refreshConfigurationLocked(uint32_t changes) { @@ -420,9 +419,8 @@ void InputReader::refreshConfigurationLocked(uint32_t changes) { "There was no change in the pointer capture state."); } else { mCurrentPointerCaptureRequest = mConfig.pointerCaptureRequest; - const NotifyPointerCaptureChangedArgs args(mContext.getNextId(), now, - mCurrentPointerCaptureRequest); - mQueuedListener.notifyPointerCaptureChanged(&args); + mQueuedListener.notifyPointerCaptureChanged( + {mContext.getNextId(), now, mCurrentPointerCaptureRequest}); } } } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 5e51bfc1ea..27d7b9c93f 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -818,8 +818,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { TEST_F(InputDispatcherTest, NotifyConfigurationChanged_CallsPolicy) { constexpr nsecs_t eventTime = 20; - NotifyConfigurationChangedArgs args(/*id=*/10, eventTime); - mDispatcher->notifyConfigurationChanged(&args); + mDispatcher->notifyConfigurationChanged({/*id=*/10, eventTime}); ASSERT_TRUE(mDispatcher->waitForIdle()); mFakePolicy->assertNotifyConfigurationChangedWasCalled(eventTime); @@ -828,7 +827,7 @@ TEST_F(InputDispatcherTest, NotifyConfigurationChanged_CallsPolicy) { TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) { NotifySwitchArgs args(/*id=*/10, /*eventTime=*/20, /*policyFlags=*/0, /*switchValues=*/1, /*switchMask=*/2); - mDispatcher->notifySwitch(&args); + mDispatcher->notifySwitch(args); // InputDispatcher adds POLICY_FLAG_TRUSTED because the event went through InputListener args.policyFlags |= POLICY_FLAG_TRUSTED; @@ -1743,8 +1742,9 @@ static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLA return args; } -static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, int32_t displayId, - const std::vector& points) { +[[nodiscard]] static NotifyMotionArgs generateMotionArgs(int32_t action, int32_t source, + int32_t displayId, + const std::vector& points) { size_t pointerCount = points.size(); if (action == AMOTION_EVENT_ACTION_DOWN || action == AMOTION_EVENT_ACTION_UP) { EXPECT_EQ(1U, pointerCount) << "Actions DOWN and UP can only contain a single pointer"; @@ -1946,26 +1946,20 @@ TEST_F(InputDispatcherTest, CancelAfterPointer0Up) { sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); - NotifyMotionArgs args; // First touch pointer down on right window - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .build()); // Second touch pointer down - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - - .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) - .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100)) + .build()); // First touch pointer lifts. The second one remains down - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) - - .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) - .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(100)) + .build()); window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); window->consumeMotionEvent(WithMotionAction(POINTER_0_UP)); @@ -2256,54 +2250,48 @@ TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) { mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, window}}}); const int32_t touchDeviceId = 4; - NotifyMotionArgs args; // Two pointers down - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .policyFlags(DEFAULT_POLICY_FLAGS) - .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) - .build())); - - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .policyFlags(DEFAULT_POLICY_FLAGS) - .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) - .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) - .build())); + mDispatcher->notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .policyFlags(DEFAULT_POLICY_FLAGS) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .build()); + + mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .policyFlags(DEFAULT_POLICY_FLAGS) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); spyWindow->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); // Cancel the current gesture. Send the cancel without the default policy flags. - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .policyFlags(0) - .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) - .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) - .build())); + mDispatcher->notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_CANCEL, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .policyFlags(0) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL)); // We don't need to reset the device to reproduce the issue, but the reset event typically // follows, so we keep it here to model the actual listener behaviour more closely. - NotifyDeviceResetArgs resetArgs; - resetArgs.id = 1; // arbitrary id - resetArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC); - resetArgs.deviceId = touchDeviceId; - mDispatcher->notifyDeviceReset(&resetArgs); + mDispatcher->notifyDeviceReset({/*id=*/1, systemTime(SYSTEM_TIME_MONOTONIC), touchDeviceId}); // Start new gesture - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .policyFlags(DEFAULT_POLICY_FLAGS) - .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) - .build())); + mDispatcher->notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .policyFlags(DEFAULT_POLICY_FLAGS) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); @@ -2453,53 +2441,49 @@ TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { NotifyMotionArgs args; // Start hovering over the left window - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) - .deviceId(mouseDeviceId) - .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) + .build()); leftWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); // Mouse down on left window - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) - .deviceId(mouseDeviceId) - .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) + .build()); leftWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId))); leftWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) - .deviceId(mouseDeviceId) - .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) - .build())); + mDispatcher->notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) + .build()); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); // First touch pointer down on right window - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .build()); leftWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Second touch pointer down on left window - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) - .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100)) + .build()); leftWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); // This MOVE event is not necessary (doesn't carry any new information), but it's there in the @@ -2533,57 +2517,52 @@ TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { NotifyMotionArgs args; // First touch pointer down - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .build()); // Second touch pointer down - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) - .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) + .build()); // First touch pointer lifts. The second one remains down - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) - .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_UP, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) + .build()); window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); window->consumeMotionEvent(WithMotionAction(POINTER_0_UP)); // Mouse down. The touch should be canceled - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) - .deviceId(mouseDeviceId) - .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100)) + .build()); window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId), WithPointerCount(1u))); window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) - .deviceId(mouseDeviceId) - .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100)) - .build())); + mDispatcher->notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(320).y(100)) + .build()); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); // Second touch pointer down. - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) - .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_0_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) + .build()); // The pointer_down event should be ignored window->assertNoEvents(); } @@ -2617,11 +2596,10 @@ TEST_F(InputDispatcherTest, UnfinishedInjectedEvent) { // Now a real touch comes. Rather than crashing or dropping the real event, the injected pointer // should be canceled and the new gesture should take over. - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .build()); window->consumeMotionEvent( AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(VIRTUAL_KEYBOARD_ID))); @@ -2823,46 +2801,38 @@ TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) { mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, window}}}); - NotifyMotionArgs args; - // Start hovering with stylus - mDispatcher->notifyMotion( - &(args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); // Stop hovering - mDispatcher->notifyMotion( - &(args = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) - .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); // Stylus touches down - mDispatcher->notifyMotion( - &(args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) - .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Stylus goes up - mDispatcher->notifyMotion( - &(args = MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS) - .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_UP)); // Again hover - mDispatcher->notifyMotion( - &(args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) - .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); // Stop hovering - mDispatcher->notifyMotion( - &(args = MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) - .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); // No more events @@ -2891,35 +2861,31 @@ TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { const int32_t mouseDeviceId = 7; const int32_t touchDeviceId = 4; - NotifyMotionArgs args; // Hover a bit with mouse first - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) - .deviceId(mouseDeviceId) - .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) + .build()); spyWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); window->consumeMotionEvent( AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); // Start touching - mDispatcher->notifyMotion( - &(args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); - mDispatcher->notifyMotion( - &(args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(55).y(55)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); window->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); @@ -2927,20 +2893,18 @@ TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindow->getToken())); window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); - mDispatcher->notifyMotion( - &(args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(60).y(60)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); // Mouse down - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) - .deviceId(mouseDeviceId) - .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) + .build()); spyWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId))); @@ -2948,32 +2912,30 @@ TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) - .deviceId(mouseDeviceId) - .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) - .build())); + mDispatcher->notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); // Mouse move! - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) - .deviceId(mouseDeviceId) - .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110)) + .build()); spyWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); window->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); // Touch move! - mDispatcher->notifyMotion( - &(args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(65).y(65)) + .build()); // No more events spyWindow->assertNoEvents(); @@ -2991,16 +2953,15 @@ TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) { sp::make(application, mDispatcher, "Window", DISPLAY_ID); mDispatcher->setInputWindows({{DISPLAY_ID, {window}}}); - NotifyMotionArgs args; // Touch down on the empty space - mDispatcher->notifyMotion(&(args = generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{-1, -1}}))); + mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{-1, -1}})); mDispatcher->waitForIdle(); window->assertNoEvents(); // Now touch down on the window with another pointer - mDispatcher->notifyMotion(&(args = generateTouchArgs(POINTER_1_DOWN, {{-1, -1}, {10, 10}}))); + mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{-1, -1}, {10, 10}})); mDispatcher->waitForIdle(); window->consumeMotionDown(); } @@ -3021,16 +2982,15 @@ TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) { mDispatcher->setInputWindows({{DISPLAY_ID, {window1, window2}}}); - NotifyMotionArgs args; // Touch down on the non-touchable window - mDispatcher->notifyMotion(&(args = generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}))); + mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}})); mDispatcher->waitForIdle(); window1->assertNoEvents(); window2->assertNoEvents(); // Now touch down on the window with another pointer - mDispatcher->notifyMotion(&(args = generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}))); + mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}})); mDispatcher->waitForIdle(); window2->consumeMotionDown(); } @@ -3050,9 +3010,8 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) { mDispatcher->setInputWindows({{DISPLAY_ID, {window1, window2}}}); - NotifyMotionArgs args; // Touch down on the first window - mDispatcher->notifyMotion(&(args = generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}))); + mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}})); mDispatcher->waitForIdle(); InputEvent* inputEvent1 = window1->consume(); @@ -3063,7 +3022,7 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) { ASSERT_EQ(motionEvent1.getDownTime(), motionEvent1.getEventTime()); // Now touch down on the window with another pointer - mDispatcher->notifyMotion(&(args = generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}))); + mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}})); mDispatcher->waitForIdle(); InputEvent* inputEvent2 = window2->consume(); ASSERT_NE(inputEvent2, nullptr); @@ -3073,14 +3032,12 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) { ASSERT_EQ(motionEvent2.getDownTime(), motionEvent2.getEventTime()); // Now move the pointer on the second window - mDispatcher->notifyMotion( - &(args = generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}))); + mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}})); mDispatcher->waitForIdle(); window2->consumeMotionEvent(WithDownTime(downTimeForWindow2)); // Now add new touch down on the second window - mDispatcher->notifyMotion( - &(args = generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}}))); + mDispatcher->notifyMotion(generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}})); mDispatcher->waitForIdle(); window2->consumeMotionEvent(WithDownTime(downTimeForWindow2)); @@ -3089,13 +3046,13 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) { window1->assertNoEvents(); // Now move the pointer on the first window - mDispatcher->notifyMotion(&( - args = generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}}))); + mDispatcher->notifyMotion( + generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}, {150, 50}})); mDispatcher->waitForIdle(); window1->consumeMotionEvent(WithDownTime(downTimeForWindow1)); - mDispatcher->notifyMotion(&( - args = generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}}))); + mDispatcher->notifyMotion( + generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}})); mDispatcher->waitForIdle(); window1->consumeMotionEvent(WithDownTime(downTimeForWindow1)); } @@ -3199,52 +3156,47 @@ TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) { const int32_t touchDeviceId = 4; const int32_t mouseDeviceId = 6; - NotifyMotionArgs args; // Two pointers down - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) - .build())); - - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) - .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .build()); + + mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) + .build()); window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); // Inject a series of mouse events for a mouse click - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) - .deviceId(mouseDeviceId) - .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) + .build()); window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId), WithPointerCount(2u))); window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(mouseDeviceId))); - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) - .deviceId(mouseDeviceId) - .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) - .build())); + mDispatcher->notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) + .build()); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); // Try to send more touch events while the mouse is down. Since it's a continuation of an // already canceled gesture, it should be ignored. - mDispatcher->notifyMotion(&( - args = MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101)) - .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(101).y(101)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(121).y(121)) + .build()); window->assertNoEvents(); } @@ -3508,23 +3460,20 @@ TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) { const int32_t mouseDeviceId = 7; const int32_t touchDeviceId = 4; - NotifyMotionArgs args; // Start hovering with the mouse - mDispatcher->notifyMotion( - &(args = MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) - .deviceId(mouseDeviceId) - .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(10)) + .build()); window->consumeMotionEvent( AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); // Touch goes down - mDispatcher->notifyMotion( - &(args = MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) - .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) - .build())); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .build()); window->consumeMotionEvent( AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId))); @@ -3550,15 +3499,15 @@ TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) { ADISPLAY_ID_DEFAULT, {{50, 50}}); motionArgs.xCursorPosition = 50; motionArgs.yCursorPosition = 50; - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(motionArgs); ASSERT_NO_FATAL_FAILURE( window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)))); // Tap on the window - motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {{10, 10}}); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {{10, 10}})); ASSERT_NO_FATAL_FAILURE( window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT), WithSource(AINPUT_SOURCE_MOUSE)))); @@ -3567,9 +3516,8 @@ TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) { window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)))); - motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {{10, 10}}); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {{10, 10}})); ASSERT_NO_FATAL_FAILURE( window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)))); @@ -3661,16 +3609,14 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) { window->consumeFocusEvent(true); - NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); // Window should receive key down event. window->consumeKeyDown(ADISPLAY_ID_DEFAULT); // When device reset happens, that key stream should be terminated with FLAG_CANCELED // on the app side. - NotifyDeviceResetArgs args(/*id=*/10, /*eventTime=*/20, DEVICE_ID); - mDispatcher->notifyDeviceReset(&args); + mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID}); window->consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT, AKEY_EVENT_FLAG_CANCELED); } @@ -3682,18 +3628,15 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) { mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); // Window should receive motion down event. window->consumeMotionDown(ADISPLAY_ID_DEFAULT); // When device reset happens, that motion stream should be terminated with ACTION_CANCEL // on the app side. - NotifyDeviceResetArgs args(/*id=*/10, /*eventTime=*/20, DEVICE_ID); - mDispatcher->notifyDeviceReset(&args); + mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID}); window->consumeMotionEvent( AllOf(WithMotionAction(ACTION_CANCEL), WithDisplayId(ADISPLAY_ID_DEFAULT))); } @@ -3709,11 +3652,11 @@ TEST_F(InputDispatcherTest, InterceptKeyByPolicy) { window->consumeFocusEvent(true); - NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); + const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); const std::chrono::milliseconds interceptKeyTimeout = 50ms; const nsecs_t injectTime = keyArgs.eventTime; mFakePolicy->setInterceptKeyTimeout(interceptKeyTimeout); - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(keyArgs); // The dispatching time should be always greater than or equal to intercept key timeout. window->consumeKeyDown(ADISPLAY_ID_DEFAULT); ASSERT_TRUE((systemTime(SYSTEM_TIME_MONOTONIC) - injectTime) >= @@ -3731,11 +3674,9 @@ TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) { window->consumeFocusEvent(true); - NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); - NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); mFakePolicy->setInterceptKeyTimeout(150ms); - mDispatcher->notifyKey(&keyDown); - mDispatcher->notifyKey(&keyUp); + mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); + mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT)); // Window should receive key event immediately when same key up. window->consumeKeyDown(ADISPLAY_ID_DEFAULT); @@ -3764,10 +3705,9 @@ TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinates) { mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {outsideWindow, window}}}); // Tap on first window. - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {PointF{50, 50}}); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {PointF{50, 50}})); window->consumeMotionDown(); // The coordinates of the tap in 'outsideWindow' are relative to its top left corner. // Therefore, we should offset them by (100, 100) relative to the screen's top left corner. @@ -3798,18 +3738,17 @@ TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) { mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, secondWindow, thirdWindow}}}); // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE. - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {PointF{-10, -10}}); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {PointF{-10, -10}})); window->assertNoEvents(); secondWindow->assertNoEvents(); // The second pointer lands inside `secondWindow`, which should receive a DOWN event. // Now, `window` should get ACTION_OUTSIDE. - motionArgs = generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {PointF{-10, -10}, PointF{105, 105}}); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, + {PointF{-10, -10}, PointF{105, 105}})); const std::map expectedPointers{{0, PointF{-10, -10}}, {1, PointF{105, 105}}}; window->consumeMotionEvent( AllOf(WithMotionAction(ACTION_OUTSIDE), WithPointers(expectedPointers))); @@ -3818,9 +3757,9 @@ TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) { // The third pointer lands inside `thirdWindow`, which should receive a DOWN event. There is // no ACTION_OUTSIDE sent to `window` because one has already been sent for this gesture. - motionArgs = generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}}); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion( + generateMotionArgs(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {PointF{-10, -10}, PointF{105, 105}, PointF{205, 205}})); window->assertNoEvents(); secondWindow->consumeMotionMove(); thirdWindow->consumeMotionDown(); @@ -3837,10 +3776,10 @@ TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) { window->consumeFocusEvent(true); - NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); - NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyKey(&keyDown); - mDispatcher->notifyKey(&keyUp); + const NotifyKeyArgs keyDown = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); + const NotifyKeyArgs keyUp = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); + mDispatcher->notifyKey(keyDown); + mDispatcher->notifyKey(keyUp); window->consumeKeyDown(ADISPLAY_ID_DEFAULT); window->consumeKeyUp(ADISPLAY_ID_DEFAULT); @@ -3850,8 +3789,8 @@ TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) { window->consumeFocusEvent(false); - mDispatcher->notifyKey(&keyDown); - mDispatcher->notifyKey(&keyUp); + mDispatcher->notifyKey(keyDown); + mDispatcher->notifyKey(keyUp); window->assertNoEvents(); } @@ -3959,10 +3898,9 @@ TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) // Send down to the first window. The point is represented in the display space. The point is // selected so that if the hit test was performed with the point and the bounds being in // different coordinate spaces, the event would end up in the incorrect window. - NotifyMotionArgs downMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {PointF{75, 55}}); - mDispatcher->notifyMotion(&downMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {PointF{75, 55}})); firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); @@ -4013,10 +3951,9 @@ TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinate auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); // Send down to the second window. - NotifyMotionArgs downMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {PointF{150, 220}}); - mDispatcher->notifyMotion(&downMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {PointF{150, 220}})); firstWindow->assertNoEvents(); const MotionEvent* event = secondWindow->consumeMotion(); @@ -4071,14 +4008,14 @@ TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) for (const auto pointInsideWindow : insidePoints) { const vec2 p = displayTransform.inverse().transform(pointInsideWindow); const PointF pointInDisplaySpace{p.x, p.y}; - const auto down = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {pointInDisplaySpace}); - mDispatcher->notifyMotion(&down); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {pointInDisplaySpace})); window->consumeMotionDown(); - const auto up = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {pointInDisplaySpace}); - mDispatcher->notifyMotion(&up); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {pointInDisplaySpace})); window->consumeMotionUp(); } @@ -4088,13 +4025,13 @@ TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) for (const auto pointOutsideWindow : outsidePoints) { const vec2 p = displayTransform.inverse().transform(pointOutsideWindow); const PointF pointInDisplaySpace{p.x, p.y}; - const auto down = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {pointInDisplaySpace}); - mDispatcher->notifyMotion(&down); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {pointInDisplaySpace})); - const auto up = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {pointInDisplaySpace}); - mDispatcher->notifyMotion(&up); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {pointInDisplaySpace})); } window->assertNoEvents(); } @@ -4132,10 +4069,8 @@ TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow, wallpaper}}}); // Send down to the first window - NotifyMotionArgs downMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&downMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); // Only the first window should get the down event firstWindow->consumeMotionDown(); @@ -4152,10 +4087,8 @@ TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); // Send up event to the second window - NotifyMotionArgs upMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&upMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT)); // The first window gets no events and the second gets up firstWindow->assertNoEvents(); secondWindow->consumeMotionUp(); @@ -4191,10 +4124,8 @@ TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) { mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, firstWindow, secondWindow}}}); // Send down to the first window - NotifyMotionArgs downMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&downMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); // Only the first window and spy should get the down event spyWindow->consumeMotionDown(); firstWindow->consumeMotionDown(); @@ -4209,10 +4140,8 @@ TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) { secondWindow->consumeMotionDown(); // Send up event to the second window - NotifyMotionArgs upMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&upMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT)); // The first window gets no events and the second+spy get up firstWindow->assertNoEvents(); spyWindow->consumeMotionUp(); @@ -4238,19 +4167,16 @@ TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); // Send down to the first window - NotifyMotionArgs downMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {touchPoint}); - mDispatcher->notifyMotion(&downMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {touchPoint})); // Only the first window should get the down event firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); // Send pointer down to the first window - NotifyMotionArgs pointerDownMotionArgs = - generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {touchPoint, touchPoint}); - mDispatcher->notifyMotion(&pointerDownMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint})); // Only the first window should get the pointer down event firstWindow->consumeMotionPointerDown(1); secondWindow->assertNoEvents(); @@ -4265,19 +4191,15 @@ TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { secondWindow->consumeMotionPointerDown(1); // Send pointer up to the second window - NotifyMotionArgs pointerUpMotionArgs = - generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {touchPoint, touchPoint}); - mDispatcher->notifyMotion(&pointerUpMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint})); // The first window gets nothing and the second gets pointer up firstWindow->assertNoEvents(); secondWindow->consumeMotionPointerUp(1); // Send up event to the second window - NotifyMotionArgs upMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&upMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT)); // The first window gets nothing and the second gets up firstWindow->assertNoEvents(); secondWindow->consumeMotionUp(); @@ -4308,10 +4230,8 @@ TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) { {{ADISPLAY_ID_DEFAULT, {firstWindow, wallpaper1, secondWindow, wallpaper2}}}); // Send down to the first window - NotifyMotionArgs downMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&downMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); // Only the first window should get the down event firstWindow->consumeMotionDown(); @@ -4331,10 +4251,8 @@ TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) { wallpaper2->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); // Send up event to the second window - NotifyMotionArgs upMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&upMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT)); // The first window gets no events and the second gets up firstWindow->assertNoEvents(); secondWindow->consumeMotionUp(); @@ -4378,19 +4296,17 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { PointF pointInSecond = {300, 600}; // Send down to the first window - NotifyMotionArgs firstDownMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {pointInFirst}); - mDispatcher->notifyMotion(&firstDownMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {pointInFirst})); // Only the first window should get the down event firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); // Send down to the second window - NotifyMotionArgs secondDownMotionArgs = - generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {pointInFirst, pointInSecond}); - mDispatcher->notifyMotion(&secondDownMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, + {pointInFirst, pointInSecond})); // The first window gets a move and the second a down firstWindow->consumeMotionMove(); secondWindow->consumeMotionDown(); @@ -4402,19 +4318,16 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { secondWindow->consumeMotionPointerDown(1); // Send pointer up to the second window - NotifyMotionArgs pointerUpMotionArgs = - generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {pointInFirst, pointInSecond}); - mDispatcher->notifyMotion(&pointerUpMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, + {pointInFirst, pointInSecond})); // The first window gets nothing and the second gets pointer up firstWindow->assertNoEvents(); secondWindow->consumeMotionPointerUp(1); // Send up event to the second window - NotifyMotionArgs upMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&upMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT)); // The first window gets nothing and the second gets up firstWindow->assertNoEvents(); secondWindow->consumeMotionUp(); @@ -4444,19 +4357,17 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { PointF pointInSecond = {300, 600}; // Send down to the first window - NotifyMotionArgs firstDownMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {pointInFirst}); - mDispatcher->notifyMotion(&firstDownMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {pointInFirst})); // Only the first window should get the down event firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); // Send down to the second window - NotifyMotionArgs secondDownMotionArgs = - generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {pointInFirst, pointInSecond}); - mDispatcher->notifyMotion(&secondDownMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, + {pointInFirst, pointInSecond})); // The first window gets a move and the second a down firstWindow->consumeMotionMove(); secondWindow->consumeMotionDown(); @@ -4471,19 +4382,16 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { // The rest of the dispatch should proceed as normal // Send pointer up to the second window - NotifyMotionArgs pointerUpMotionArgs = - generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {pointInFirst, pointInSecond}); - mDispatcher->notifyMotion(&pointerUpMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, + {pointInFirst, pointInSecond})); // The first window gets MOVE and the second gets pointer up firstWindow->consumeMotionMove(); secondWindow->consumeMotionUp(); // Send up event to the first window - NotifyMotionArgs upMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&upMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT)); // The first window gets nothing and the second gets up firstWindow->consumeMotionUp(); secondWindow->assertNoEvents(); @@ -4618,8 +4526,7 @@ TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) { window->consumeFocusEvent(true); - NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); // Window should receive key down event. window->consumeKeyDown(ADISPLAY_ID_DEFAULT); @@ -4632,8 +4539,7 @@ TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); - NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); mDispatcher->waitForIdle(); window->assertNoEvents(); @@ -4648,13 +4554,10 @@ TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) { mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); // Send key - NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); // Send motion - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); // Window should receive only the motion event window->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -4681,19 +4584,17 @@ TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) { PointF pointInSecond = {300, 600}; // Send down to the first window - NotifyMotionArgs firstDownMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {pointInFirst}); - mDispatcher->notifyMotion(&firstDownMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {pointInFirst})); // Only the first window should get the down event firstWindow->consumeMotionDown(); secondWindow->assertNoEvents(); // Send down to the second window - NotifyMotionArgs secondDownMotionArgs = - generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {pointInFirst, pointInSecond}); - mDispatcher->notifyMotion(&secondDownMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, + {pointInFirst, pointInSecond})); // The first window gets a move and the second a down firstWindow->consumeMotionMove(); secondWindow->consumeMotionDown(); @@ -4703,16 +4604,14 @@ TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) { generateMotionArgs(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond}); pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED; - mDispatcher->notifyMotion(&pointerUpMotionArgs); + mDispatcher->notifyMotion(pointerUpMotionArgs); // The first window gets move and the second gets cancel. firstWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); secondWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); // Send up event. - NotifyMotionArgs upMotionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&upMotionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT)); // The first window gets up and the second gets nothing. firstWindow->consumeMotionUp(); secondWindow->assertNoEvents(); @@ -4934,7 +4833,7 @@ TEST_F(InputDispatcherTest, TestMoveEvent) { generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(motionArgs); // Window should receive motion down event. window->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -4944,7 +4843,7 @@ TEST_F(InputDispatcherTest, TestMoveEvent) { motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, motionArgs.pointerCoords[0].getX() - 10); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(motionArgs); window->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE, ADISPLAY_ID_DEFAULT, /*expectedFlags=*/0); } @@ -5013,8 +4912,8 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); - NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN); - mDispatcher->notifyKey(&keyArgs); + const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN); + mDispatcher->notifyKey(keyArgs); InputEvent* event = window->consume(); ASSERT_NE(event, nullptr); @@ -5055,10 +4954,10 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { mDispatcher->onWindowInfosChanged({*window->getInfo()}, {displayInfo}); - NotifyMotionArgs motionArgs = + const NotifyMotionArgs motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(motionArgs); InputEvent* event = window->consume(); ASSERT_NE(event, nullptr); @@ -5355,17 +5254,17 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { {{ADISPLAY_ID_DEFAULT, {slipperyExitWindow, slipperyEnterWindow}}}); // Use notifyMotion instead of injecting to avoid dealing with injection permissions - NotifyMotionArgs args = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {{50, 50}}); - mDispatcher->notifyMotion(&args); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {{50, 50}})); slipperyExitWindow->consumeMotionDown(); slipperyExitWindow->setFrame(Rect(70, 70, 100, 100)); mDispatcher->setInputWindows( {{ADISPLAY_ID_DEFAULT, {slipperyExitWindow, slipperyEnterWindow}}}); - args = generateMotionArgs(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {{51, 51}}); - mDispatcher->notifyMotion(&args); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_MOVE, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {{51, 51}})); slipperyExitWindow->consumeMotionCancel(); @@ -5405,7 +5304,7 @@ protected: NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); keyArgs.deviceId = deviceId; keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(keyArgs); // Window should receive key down event. mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); @@ -5428,7 +5327,7 @@ protected: NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); keyArgs.deviceId = deviceId; keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(keyArgs); // Window should receive key down event. mWindow->consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT, @@ -5491,8 +5390,7 @@ TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingK TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterDisableInputDevice) { sendAndConsumeKeyDown(DEVICE_ID); expectKeyRepeatOnce(/*repeatCount=*/1); - NotifyDeviceResetArgs args(/*id=*/10, /*eventTime=*/20, DEVICE_ID); - mDispatcher->notifyDeviceReset(&args); + mDispatcher->notifyDeviceReset({/*id=*/10, /*eventTime=*/20, DEVICE_ID}); mWindow->consumeKeyUp(ADISPLAY_ID_DEFAULT, AKEY_EVENT_FLAG_CANCELED | AKEY_EVENT_FLAG_LONG_PRESS); mWindow->assertNoEvents(); @@ -5744,10 +5642,10 @@ protected: motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(motionArgs); motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(motionArgs); ASSERT_TRUE(mDispatcher->waitForIdle()); if (expectToBeFiltered) { const auto xy = transform.transform(motionArgs.pointerCoords->getXYValue()); @@ -5761,9 +5659,9 @@ protected: NotifyKeyArgs keyArgs; keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN); - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(keyArgs); keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP); - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(keyArgs); ASSERT_TRUE(mDispatcher->waitForIdle()); if (expectToBeFiltered) { @@ -6113,9 +6011,8 @@ protected: void touchAndAssertPositions(int32_t action, const std::vector& touchedPoints, std::vector expectedPoints) { - NotifyMotionArgs motionArgs = generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, touchedPoints); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, touchedPoints)); // Always consume from window1 since it's the window that has the InputReceiver consumeMotionEvent(mWindow1, action, expectedPoints); @@ -6988,17 +6885,16 @@ TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) { // The other window should not be affected by that. TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) { // Touch Window 1 - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {FOCUSED_WINDOW_LOCATION}); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {FOCUSED_WINDOW_LOCATION})); mUnfocusedWindow->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_OUTSIDE, ADISPLAY_ID_DEFAULT, /*flags=*/0); // Touch Window 2 - motionArgs = generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION}); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion( + generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {FOCUSED_WINDOW_LOCATION, UNFOCUSED_WINDOW_LOCATION})); const std::chrono::duration timeout = mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); @@ -7070,10 +6966,9 @@ TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_ std::this_thread::sleep_for(10ms); // Touch unfocused window. This should force the pending key to get dropped. - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {UNFOCUSED_WINDOW_LOCATION}); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {UNFOCUSED_WINDOW_LOCATION})); // We do not consume the motion right away, because that would require dispatcher to first // process (== drop) the key event, and by that time, ANR will be raised. @@ -7128,10 +7023,9 @@ protected: TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouches) { PointF touchedPoint = {10, 10}; - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {touchedPoint}); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {touchedPoint})); mNoInputWindow->assertNoEvents(); // Even though the window 'mNoInputWindow' positioned above 'mBottomWindow' does not have @@ -7156,10 +7050,9 @@ TEST_F(InputDispatcherMultiWindowOcclusionTests, PointF touchedPoint = {10, 10}; - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {touchedPoint}); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {touchedPoint})); mNoInputWindow->assertNoEvents(); mBottomWindow->assertNoEvents(); @@ -7332,8 +7225,7 @@ protected: } void notifyPointerCaptureChanged(const PointerCaptureRequest& request) { - const NotifyPointerCaptureChangedArgs args = generatePointerCaptureChangedArgs(request); - mDispatcher->notifyPointerCaptureChanged(&args); + mDispatcher->notifyPointerCaptureChanged(generatePointerCaptureChangedArgs(request)); } PointerCaptureRequest requestAndVerifyPointerCapture(const sp& window, @@ -7509,10 +7401,9 @@ protected: } void touch(const std::vector& points = {PointF{100, 200}}) { - NotifyMotionArgs args = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, points); - mDispatcher->notifyMotion(&args); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + points)); } }; @@ -8322,27 +8213,22 @@ TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); // With the flag set, window should not get any input - NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); window->assertNoEvents(); - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); window->assertNoEvents(); // With the flag cleared, the window should get input window->setDropInput(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); - keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT)); window->consumeKeyUp(ADISPLAY_ID_DEFAULT); - motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); window->consumeMotionDown(ADISPLAY_ID_DEFAULT); window->assertNoEvents(); } @@ -8368,27 +8254,22 @@ TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); // With the flag set, window should not get any input - NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); window->assertNoEvents(); - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); window->assertNoEvents(); // With the flag cleared, the window should get input window->setDropInputIfObscured(false); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); - keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT)); window->consumeKeyUp(ADISPLAY_ID_DEFAULT); - motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); window->consumeMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED); window->assertNoEvents(); } @@ -8414,26 +8295,21 @@ TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) { window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); // With the flag set, window should not get any input - NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); window->assertNoEvents(); - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); window->assertNoEvents(); // When the window is no longer obscured because it went on top, it should get input mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, obscuringWindow}}}); - keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT); - mDispatcher->notifyKey(&keyArgs); + mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT)); window->consumeKeyUp(ADISPLAY_ID_DEFAULT); - motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT); - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); window->consumeMotionDown(ADISPLAY_ID_DEFAULT); window->assertNoEvents(); } @@ -9167,10 +9043,9 @@ public: } void sendFingerEvent(int32_t action) { - NotifyMotionArgs motionArgs = + mDispatcher->notifyMotion( generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, - ADISPLAY_ID_DEFAULT, {PointF{20, 20}}); - mDispatcher->notifyMotion(&motionArgs); + ADISPLAY_ID_DEFAULT, {PointF{20, 20}})); } void sendStylusEvent(int32_t action) { @@ -9178,7 +9053,7 @@ public: generateMotionArgs(action, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT, {PointF{30, 40}}); motionArgs.pointerProperties[0].toolType = ToolType::STYLUS; - mDispatcher->notifyMotion(&motionArgs); + mDispatcher->notifyMotion(motionArgs); } }; diff --git a/services/inputflinger/tests/InputProcessor_test.cpp b/services/inputflinger/tests/InputProcessor_test.cpp index 0ffdef9daa..3b7cbfac5c 100644 --- a/services/inputflinger/tests/InputProcessor_test.cpp +++ b/services/inputflinger/tests/InputProcessor_test.cpp @@ -72,7 +72,7 @@ TEST_F(InputProcessorTest, SendToNextStage_NotifyConfigurationChangedArgs) { // Create a basic configuration change and send to processor NotifyConfigurationChangedArgs args(/*sequenceNum=*/1, /*eventTime=*/2); - mProcessor->notifyConfigurationChanged(&args); + mProcessor->notifyConfigurationChanged(args); NotifyConfigurationChangedArgs outArgs; ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyConfigurationChangedWasCalled(&outArgs)); ASSERT_EQ(args, outArgs); @@ -85,10 +85,8 @@ TEST_F(InputProcessorTest, SendToNextStage_NotifyKeyArgs) { AKEY_EVENT_ACTION_DOWN, /*flags=*/4, AKEYCODE_HOME, /*scanCode=*/5, AMETA_NONE, /*downTime=*/6); - mProcessor->notifyKey(&args); - NotifyKeyArgs outArgs; - ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyKeyWasCalled(&outArgs)); - ASSERT_EQ(args, outArgs); + mProcessor->notifyKey(args); + ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyKeyWasCalled(testing::Eq(args))); } /** @@ -97,10 +95,8 @@ TEST_F(InputProcessorTest, SendToNextStage_NotifyKeyArgs) { */ TEST_F(InputProcessorTest, SendToNextStage_NotifyMotionArgs) { NotifyMotionArgs motionArgs = generateBasicMotionArgs(); - mProcessor->notifyMotion(&motionArgs); - NotifyMotionArgs args; - ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(motionArgs, args); + mProcessor->notifyMotion(motionArgs); + ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyMotionWasCalled(testing::Eq(motionArgs))); } /** @@ -111,7 +107,7 @@ TEST_F(InputProcessorTest, SendToNextStage_NotifySwitchArgs) { NotifySwitchArgs args(/*sequenceNum=*/1, /*eventTime=*/2, /*policyFlags=*/3, /*switchValues=*/4, /*switchMask=*/5); - mProcessor->notifySwitch(&args); + mProcessor->notifySwitch(args); NotifySwitchArgs outArgs; ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifySwitchWasCalled(&outArgs)); ASSERT_EQ(args, outArgs); @@ -124,7 +120,7 @@ TEST_F(InputProcessorTest, SendToNextStage_NotifySwitchArgs) { TEST_F(InputProcessorTest, SendToNextStage_NotifyDeviceResetArgs) { NotifyDeviceResetArgs args(/*sequenceNum=*/1, /*eventTime=*/2, /*deviceId=*/3); - mProcessor->notifyDeviceReset(&args); + mProcessor->notifyDeviceReset(args); NotifyDeviceResetArgs outArgs; ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyDeviceResetWasCalled(&outArgs)); ASSERT_EQ(args, outArgs); diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp index ac1dc05f6d..fc917dd582 100644 --- a/services/inputflinger/tests/TestInputListener.cpp +++ b/services/inputflinger/tests/TestInputListener.cpp @@ -168,47 +168,47 @@ void TestInputListener::assertNotCalled(std::string message, std::optional -void TestInputListener::addToQueue(const NotifyArgsType* args) { +void TestInputListener::addToQueue(const NotifyArgsType& args) { std::scoped_lock lock(mLock); std::vector& queue = std::get>(mQueues); - queue.push_back(*args); + queue.push_back(args); mCondition.notify_all(); } void TestInputListener::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) { - addToQueue(&args); + addToQueue(args); } -void TestInputListener::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { +void TestInputListener::notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) { addToQueue(args); } -void TestInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) { +void TestInputListener::notifyDeviceReset(const NotifyDeviceResetArgs& args) { addToQueue(args); } -void TestInputListener::notifyKey(const NotifyKeyArgs* args) { +void TestInputListener::notifyKey(const NotifyKeyArgs& args) { addToQueue(args); } -void TestInputListener::notifyMotion(const NotifyMotionArgs* args) { +void TestInputListener::notifyMotion(const NotifyMotionArgs& args) { addToQueue(args); } -void TestInputListener::notifySwitch(const NotifySwitchArgs* args) { +void TestInputListener::notifySwitch(const NotifySwitchArgs& args) { addToQueue(args); } -void TestInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) { +void TestInputListener::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) { addToQueue(args); } -void TestInputListener::notifySensor(const NotifySensorArgs* args) { +void TestInputListener::notifySensor(const NotifySensorArgs& args) { addToQueue(args); } -void TestInputListener::notifyVibratorState(const NotifyVibratorStateArgs* args) { +void TestInputListener::notifyVibratorState(const NotifyVibratorStateArgs& args) { addToQueue(args); } diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h index da2cab3351..deb60483fb 100644 --- a/services/inputflinger/tests/TestInputListener.h +++ b/services/inputflinger/tests/TestInputListener.h @@ -77,25 +77,25 @@ private: void assertNotCalled(std::string message, std::optional timeout = {}); template - void addToQueue(const NotifyArgsType* args); + void addToQueue(const NotifyArgsType& args); virtual void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override; - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override; + virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override; - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override; + virtual void notifyDeviceReset(const NotifyDeviceResetArgs& args) override; - virtual void notifyKey(const NotifyKeyArgs* args) override; + virtual void notifyKey(const NotifyKeyArgs& args) override; - virtual void notifyMotion(const NotifyMotionArgs* args) override; + virtual void notifyMotion(const NotifyMotionArgs& args) override; - virtual void notifySwitch(const NotifySwitchArgs* args) override; + virtual void notifySwitch(const NotifySwitchArgs& args) override; - virtual void notifySensor(const NotifySensorArgs* args) override; + virtual void notifySensor(const NotifySensorArgs& args) override; - virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override; + virtual void notifyVibratorState(const NotifyVibratorStateArgs& args) override; - virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override; + virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override; std::mutex mLock; std::condition_variable mCondition; diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp index be731b1a2f..1fff2c7590 100644 --- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp +++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp @@ -421,7 +421,7 @@ TEST_F(UnwantedInteractionBlockerTest, ConfigurationChangedIsPassedToNextListene // Create a basic configuration change and send to blocker NotifyConfigurationChangedArgs args(/*sequenceNum=*/1, /*eventTime=*/2); - mBlocker->notifyConfigurationChanged(&args); + mBlocker->notifyConfigurationChanged(args); NotifyConfigurationChangedArgs outArgs; ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyConfigurationChangedWasCalled(&outArgs)); ASSERT_EQ(args, outArgs); @@ -438,10 +438,8 @@ TEST_F(UnwantedInteractionBlockerTest, KeyIsPassedToNextListener) { AKEY_EVENT_ACTION_DOWN, /*flags=*/4, AKEYCODE_HOME, /*scanCode=*/5, AMETA_NONE, /*downTime=*/6); - mBlocker->notifyKey(&args); - NotifyKeyArgs outArgs; - ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyKeyWasCalled(&outArgs)); - ASSERT_EQ(args, outArgs); + mBlocker->notifyKey(args); + ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyKeyWasCalled(testing::Eq(args))); } /** @@ -452,10 +450,8 @@ TEST_F(UnwantedInteractionBlockerTest, KeyIsPassedToNextListener) { TEST_F(UnwantedInteractionBlockerTest, DownEventIsPassedToNextListener) { NotifyMotionArgs motionArgs = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2, 3}}); - mBlocker->notifyMotion(&motionArgs); - NotifyMotionArgs args; - ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(motionArgs, args); + mBlocker->notifyMotion(motionArgs); + ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyMotionWasCalled(testing::Eq(motionArgs))); } /** @@ -466,7 +462,7 @@ TEST_F(UnwantedInteractionBlockerTest, SwitchIsPassedToNextListener) { NotifySwitchArgs args(/*sequenceNum=*/1, /*eventTime=*/2, /*policyFlags=*/3, /*switchValues=*/4, /*switchMask=*/5); - mBlocker->notifySwitch(&args); + mBlocker->notifySwitch(args); NotifySwitchArgs outArgs; ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifySwitchWasCalled(&outArgs)); ASSERT_EQ(args, outArgs); @@ -479,7 +475,7 @@ TEST_F(UnwantedInteractionBlockerTest, SwitchIsPassedToNextListener) { TEST_F(UnwantedInteractionBlockerTest, DeviceResetIsPassedToNextListener) { NotifyDeviceResetArgs args(/*sequenceNum=*/1, /*eventTime=*/2, DEVICE_ID); - mBlocker->notifyDeviceReset(&args); + mBlocker->notifyDeviceReset(args); NotifyDeviceResetArgs outArgs; ASSERT_NO_FATAL_FAILURE(mTestListener.assertNotifyDeviceResetWasCalled(&outArgs)); ASSERT_EQ(args, outArgs); @@ -491,17 +487,12 @@ TEST_F(UnwantedInteractionBlockerTest, DeviceResetIsPassedToNextListener) { * a crash due to inconsistent event stream could have occurred. */ TEST_F(UnwantedInteractionBlockerTest, NoCrashWhenResetHappens) { - NotifyMotionArgs args; mBlocker->notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}}); - mBlocker->notifyMotion( - &(args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, DOWN, {{1, 2, 3}}))); - mBlocker->notifyMotion( - &(args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/2, MOVE, {{4, 5, 6}}))); - NotifyDeviceResetArgs resetArgs(/*sequenceNum=*/1, /*eventTime=*/3, DEVICE_ID); - mBlocker->notifyDeviceReset(&resetArgs); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, DOWN, {{1, 2, 3}})); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/2, MOVE, {{4, 5, 6}})); + mBlocker->notifyDeviceReset({/*sequenceNum=*/1, /*eventTime=*/3, DEVICE_ID}); // Start a new gesture with a DOWN event, even though the previous event stream was incomplete. - mBlocker->notifyMotion( - &(args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/4, DOWN, {{7, 8, 9}}))); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/4, DOWN, {{7, 8, 9}})); } TEST_F(UnwantedInteractionBlockerTest, NoCrashWhenStylusSourceWithFingerToolIsReceived) { @@ -509,7 +500,7 @@ TEST_F(UnwantedInteractionBlockerTest, NoCrashWhenStylusSourceWithFingerToolIsRe NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, DOWN, {{1, 2, 3}}); args.pointerProperties[0].toolType = ToolType::FINGER; args.source = AINPUT_SOURCE_STYLUS; - mBlocker->notifyMotion(&args); + mBlocker->notifyMotion(args); } /** @@ -517,48 +508,41 @@ TEST_F(UnwantedInteractionBlockerTest, NoCrashWhenStylusSourceWithFingerToolIsRe * UnwantedInteractionBlocker has not changed, there should not be a reset. */ TEST_F(UnwantedInteractionBlockerTest, NoResetIfDeviceInfoChanges) { - NotifyMotionArgs args; mBlocker->notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}}); - mBlocker->notifyMotion( - &(args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, DOWN, {{1, 2, 3}}))); - mBlocker->notifyMotion( - &(args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/2, MOVE, {{4, 5, 6}}))); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, DOWN, {{1, 2, 3}})); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/2, MOVE, {{4, 5, 6}})); // Now pretend the device changed, even though nothing is different for DEVICE_ID in practice. mBlocker->notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}}); // The MOVE event continues the gesture that started before 'devices changed', so it should not // cause a crash. - mBlocker->notifyMotion( - &(args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/4, MOVE, {{7, 8, 9}}))); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/4, MOVE, {{7, 8, 9}})); } /** * Send a touch event, and then a stylus event. Make sure that both work. */ TEST_F(UnwantedInteractionBlockerTest, StylusAfterTouchWorks) { - NotifyMotionArgs args; mBlocker->notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}}); - args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2, 3}}); - mBlocker->notifyMotion(&args); - args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, MOVE, {{4, 5, 6}}); - mBlocker->notifyMotion(&args); - args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/2, UP, {{4, 5, 6}}); - mBlocker->notifyMotion(&args); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2, 3}})); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, MOVE, {{4, 5, 6}})); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/2, UP, {{4, 5, 6}})); // Now touch down stylus + NotifyMotionArgs args; args = generateMotionArgs(/*downTime=*/3, /*eventTime=*/3, DOWN, {{10, 20, 30}}); args.pointerProperties[0].toolType = ToolType::STYLUS; args.source |= AINPUT_SOURCE_STYLUS; - mBlocker->notifyMotion(&args); + mBlocker->notifyMotion(args); args = generateMotionArgs(/*downTime=*/3, /*eventTime=*/4, MOVE, {{40, 50, 60}}); args.pointerProperties[0].toolType = ToolType::STYLUS; args.source |= AINPUT_SOURCE_STYLUS; - mBlocker->notifyMotion(&args); + mBlocker->notifyMotion(args); args = generateMotionArgs(/*downTime=*/3, /*eventTime=*/5, UP, {{40, 50, 60}}); args.pointerProperties[0].toolType = ToolType::STYLUS; args.source |= AINPUT_SOURCE_STYLUS; - mBlocker->notifyMotion(&args); + mBlocker->notifyMotion(args); } /** @@ -569,16 +553,13 @@ TEST_F(UnwantedInteractionBlockerTest, StylusAfterTouchWorks) { */ TEST_F(UnwantedInteractionBlockerTest, DumpCanBeAccessedOnAnotherThread) { mBlocker->notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}}); - NotifyMotionArgs args1 = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2, 3}}); - mBlocker->notifyMotion(&args1); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2, 3}})); std::thread dumpThread([this]() { std::string dump; mBlocker->dump(dump); }); - NotifyMotionArgs args2 = generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, MOVE, {{4, 5, 6}}); - mBlocker->notifyMotion(&args2); - NotifyMotionArgs args3 = generateMotionArgs(/*downTime=*/0, /*eventTime=*/2, UP, {{4, 5, 6}}); - mBlocker->notifyMotion(&args3); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, MOVE, {{4, 5, 6}})); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/2, UP, {{4, 5, 6}})); dumpThread.join(); } @@ -589,20 +570,17 @@ TEST_F(UnwantedInteractionBlockerTest, DumpCanBeAccessedOnAnotherThread) { TEST_F(UnwantedInteractionBlockerTest, HeuristicFilterWorks) { mBlocker->notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}}); // Small touch down - NotifyMotionArgs args1 = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2, 3}}); - mBlocker->notifyMotion(&args1); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2, 3}})); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(DOWN)); // Large touch oval on the next move - NotifyMotionArgs args2 = - generateMotionArgs(/*downTime=*/0, RESAMPLE_PERIOD, MOVE, {{4, 5, 200}}); - mBlocker->notifyMotion(&args2); + mBlocker->notifyMotion( + generateMotionArgs(/*downTime=*/0, RESAMPLE_PERIOD, MOVE, {{4, 5, 200}})); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE)); // Lift up the touch to force the model to decide on whether it's a palm - NotifyMotionArgs args3 = - generateMotionArgs(/*downTime=*/0, 2 * RESAMPLE_PERIOD, UP, {{4, 5, 200}}); - mBlocker->notifyMotion(&args3); + mBlocker->notifyMotion( + generateMotionArgs(/*downTime=*/0, 2 * RESAMPLE_PERIOD, UP, {{4, 5, 200}})); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(CANCEL)); } @@ -618,14 +596,14 @@ TEST_F(UnwantedInteractionBlockerTest, StylusIsNotBlocked) { mBlocker->notifyInputDevicesChanged(deviceChangedArgs); NotifyMotionArgs args1 = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2, 3}}); args1.pointerProperties[0].toolType = ToolType::STYLUS; - mBlocker->notifyMotion(&args1); + mBlocker->notifyMotion(args1); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(DOWN)); // Move the stylus, setting large TOUCH_MAJOR/TOUCH_MINOR dimensions NotifyMotionArgs args2 = generateMotionArgs(/*downTime=*/0, RESAMPLE_PERIOD, MOVE, {{4, 5, 200}}); args2.pointerProperties[0].toolType = ToolType::STYLUS; - mBlocker->notifyMotion(&args2); + mBlocker->notifyMotion(args2); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE)); // Lift up the stylus. If it were a touch event, this would force the model to decide on whether @@ -633,7 +611,7 @@ TEST_F(UnwantedInteractionBlockerTest, StylusIsNotBlocked) { NotifyMotionArgs args3 = generateMotionArgs(/*downTime=*/0, 2 * RESAMPLE_PERIOD, UP, {{4, 5, 200}}); args3.pointerProperties[0].toolType = ToolType::STYLUS; - mBlocker->notifyMotion(&args3); + mBlocker->notifyMotion(args3); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(UP)); } @@ -649,28 +627,28 @@ TEST_F(UnwantedInteractionBlockerTest, TouchIsBlockedWhenMixedWithStylus) { // Touch down NotifyMotionArgs args1 = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2, 3}}); - mBlocker->notifyMotion(&args1); + mBlocker->notifyMotion(args1); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(DOWN)); // Stylus pointer down NotifyMotionArgs args2 = generateMotionArgs(/*downTime=*/0, RESAMPLE_PERIOD, POINTER_1_DOWN, {{1, 2, 3}, {10, 20, 30}}); args2.pointerProperties[1].toolType = ToolType::STYLUS; - mBlocker->notifyMotion(&args2); + mBlocker->notifyMotion(args2); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(POINTER_1_DOWN)); // Large touch oval on the next finger move NotifyMotionArgs args3 = generateMotionArgs(/*downTime=*/0, 2 * RESAMPLE_PERIOD, MOVE, {{1, 2, 300}, {11, 21, 30}}); args3.pointerProperties[1].toolType = ToolType::STYLUS; - mBlocker->notifyMotion(&args3); + mBlocker->notifyMotion(args3); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE)); // Lift up the finger pointer. It should be canceled due to the heuristic filter. NotifyMotionArgs args4 = generateMotionArgs(/*downTime=*/0, 3 * RESAMPLE_PERIOD, POINTER_0_UP, {{1, 2, 300}, {11, 21, 30}}); args4.pointerProperties[1].toolType = ToolType::STYLUS; - mBlocker->notifyMotion(&args4); + mBlocker->notifyMotion(args4); mTestListener.assertNotifyMotionWasCalled( AllOf(WithMotionAction(POINTER_0_UP), WithFlags(FLAG_CANCELED))); @@ -678,7 +656,7 @@ TEST_F(UnwantedInteractionBlockerTest, TouchIsBlockedWhenMixedWithStylus) { generateMotionArgs(/*downTime=*/0, 4 * RESAMPLE_PERIOD, MOVE, {{12, 22, 30}}); args5.pointerProperties[0].id = args4.pointerProperties[1].id; args5.pointerProperties[0].toolType = ToolType::STYLUS; - mBlocker->notifyMotion(&args5); + mBlocker->notifyMotion(args5); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(MOVE)); // Lift up the stylus pointer @@ -686,7 +664,7 @@ TEST_F(UnwantedInteractionBlockerTest, TouchIsBlockedWhenMixedWithStylus) { generateMotionArgs(/*downTime=*/0, 5 * RESAMPLE_PERIOD, UP, {{4, 5, 200}}); args6.pointerProperties[0].id = args4.pointerProperties[1].id; args6.pointerProperties[0].toolType = ToolType::STYLUS; - mBlocker->notifyMotion(&args6); + mBlocker->notifyMotion(args6); mTestListener.assertNotifyMotionWasCalled(WithMotionAction(UP)); } @@ -700,17 +678,15 @@ TEST_F(UnwantedInteractionBlockerTestDeathTest, InconsistentEventAfterResetCause ScopedSilentDeath _silentDeath; NotifyMotionArgs args; mBlocker->notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}}); - mBlocker->notifyMotion( - &(args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, DOWN, {{1, 2, 3}}))); - mBlocker->notifyMotion( - &(args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/2, MOVE, {{4, 5, 6}}))); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, DOWN, {{1, 2, 3}})); + mBlocker->notifyMotion(generateMotionArgs(/*downTime=*/0, /*eventTime=*/2, MOVE, {{4, 5, 6}})); NotifyDeviceResetArgs resetArgs(/*sequenceNum=*/1, /*eventTime=*/3, DEVICE_ID); - mBlocker->notifyDeviceReset(&resetArgs); + mBlocker->notifyDeviceReset(resetArgs); // Sending MOVE without a DOWN -> should crash! ASSERT_DEATH( { - mBlocker->notifyMotion(&(args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/4, - MOVE, {{7, 8, 9}}))); + mBlocker->notifyMotion( + generateMotionArgs(/*downTime=*/0, /*eventTime=*/4, MOVE, {{7, 8, 9}})); }, "Could not find slot"); } @@ -720,9 +696,13 @@ TEST_F(UnwantedInteractionBlockerTestDeathTest, InconsistentEventAfterResetCause */ TEST_F(UnwantedInteractionBlockerTestDeathTest, WhenMoveWithoutDownCausesACrash) { ScopedSilentDeath _silentDeath; - NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, MOVE, {{1, 2, 3}}); mBlocker->notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}}); - ASSERT_DEATH({ mBlocker->notifyMotion(&args); }, "Could not find slot"); + ASSERT_DEATH( + { + mBlocker->notifyMotion( + generateMotionArgs(/*downTime=*/0, /*eventTime=*/1, MOVE, {{1, 2, 3}})); + }, + "Could not find slot"); } class PalmRejectorTest : public testing::Test { diff --git a/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp index 6617f65adf..f8ebc97ccd 100644 --- a/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp @@ -67,51 +67,42 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { fdp.PickValueInArray>({ [&]() -> void { // SendToNextStage_NotifyConfigurationChangedArgs - NotifyConfigurationChangedArgs - args(/*sequenceNum=*/fdp.ConsumeIntegral(), - /*eventTime=*/fdp.ConsumeIntegral()); - mClassifier->notifyConfigurationChanged(&args); + mClassifier->notifyConfigurationChanged( + {/*sequenceNum=*/fdp.ConsumeIntegral(), + /*eventTime=*/fdp.ConsumeIntegral()}); }, [&]() -> void { // SendToNextStage_NotifyKeyArgs const nsecs_t eventTime = fdp.ConsumeIntegral(); const nsecs_t readTime = eventTime + fdp.ConsumeIntegralInRange(0, 1E8); - NotifyKeyArgs keyArgs(/*sequenceNum=*/fdp.ConsumeIntegral(), - eventTime, readTime, - /*deviceId=*/fdp.ConsumeIntegral(), - AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_DEFAULT, - /*policyFlags=*/fdp.ConsumeIntegral(), - AKEY_EVENT_ACTION_DOWN, - /*flags=*/fdp.ConsumeIntegral(), AKEYCODE_HOME, - /*scanCode=*/fdp.ConsumeIntegral(), AMETA_NONE, - /*downTime=*/fdp.ConsumeIntegral()); - - mClassifier->notifyKey(&keyArgs); + mClassifier->notifyKey({/*sequenceNum=*/fdp.ConsumeIntegral(), + eventTime, readTime, + /*deviceId=*/fdp.ConsumeIntegral(), + AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_DEFAULT, + /*policyFlags=*/fdp.ConsumeIntegral(), + AKEY_EVENT_ACTION_DOWN, + /*flags=*/fdp.ConsumeIntegral(), AKEYCODE_HOME, + /*scanCode=*/fdp.ConsumeIntegral(), AMETA_NONE, + /*downTime=*/fdp.ConsumeIntegral()}); }, [&]() -> void { // SendToNextStage_NotifyMotionArgs - NotifyMotionArgs motionArgs = generateFuzzedMotionArgs(fdp); - mClassifier->notifyMotion(&motionArgs); + mClassifier->notifyMotion(generateFuzzedMotionArgs(fdp)); }, [&]() -> void { // SendToNextStage_NotifySwitchArgs - NotifySwitchArgs switchArgs(/*sequenceNum=*/fdp.ConsumeIntegral(), - /*eventTime=*/fdp.ConsumeIntegral(), - /*policyFlags=*/fdp.ConsumeIntegral(), - /*switchValues=*/fdp.ConsumeIntegral(), - /*switchMask=*/fdp.ConsumeIntegral()); - - mClassifier->notifySwitch(&switchArgs); + mClassifier->notifySwitch({/*sequenceNum=*/fdp.ConsumeIntegral(), + /*eventTime=*/fdp.ConsumeIntegral(), + /*policyFlags=*/fdp.ConsumeIntegral(), + /*switchValues=*/fdp.ConsumeIntegral(), + /*switchMask=*/fdp.ConsumeIntegral()}); }, [&]() -> void { // SendToNextStage_NotifyDeviceResetArgs - NotifyDeviceResetArgs resetArgs( - /*sequenceNum=*/fdp.ConsumeIntegral(), - /*eventTime=*/fdp.ConsumeIntegral(), - /*deviceId=*/fdp.ConsumeIntegral()); - - mClassifier->notifyDeviceReset(&resetArgs); + mClassifier->notifyDeviceReset({/*sequenceNum=*/fdp.ConsumeIntegral(), + /*eventTime=*/fdp.ConsumeIntegral(), + /*deviceId=*/fdp.ConsumeIntegral()}); }, [&]() -> void { // InputClassifierConverterTest diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index 0dc627a8f7..1e44e0fba0 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -294,14 +294,14 @@ public: class FuzzInputListener : public virtual InputListenerInterface { public: void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override {} - void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override {} - void notifyKey(const NotifyKeyArgs* args) override {} - void notifyMotion(const NotifyMotionArgs* args) override {} - void notifySwitch(const NotifySwitchArgs* args) override {} - void notifySensor(const NotifySensorArgs* args) override{}; - void notifyVibratorState(const NotifyVibratorStateArgs* args) override{}; - void notifyDeviceReset(const NotifyDeviceResetArgs* args) override {} - void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override{}; + void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override {} + void notifyKey(const NotifyKeyArgs& args) override {} + void notifyMotion(const NotifyMotionArgs& args) override {} + void notifySwitch(const NotifySwitchArgs& args) override {} + void notifySensor(const NotifySensorArgs& args) override{}; + void notifyVibratorState(const NotifyVibratorStateArgs& args) override{}; + void notifyDeviceReset(const NotifyDeviceResetArgs& args) override {} + void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override{}; }; class FuzzInputReaderContext : public InputReaderContext { -- GitLab From 4ac2a268cbd211389d7f1d27853b8eeb6f956b72 Mon Sep 17 00:00:00 2001 From: Nick Deakin Date: Wed, 19 Apr 2023 15:27:13 -0400 Subject: [PATCH 0060/1187] UltraHDR: update Version handling. Version is now a string as spec'd, and identifier is added to Primary image XMP to indicate presence of a gain map. Bug: 278784125 Test: tests pass Change-Id: Ia76879ca3d187edb78927ad5bab79fc8eef07da8 --- libs/ultrahdr/include/ultrahdr/jpegrutils.h | 7 +++++-- libs/ultrahdr/include/ultrahdr/ultrahdr.h | 4 ++-- libs/ultrahdr/jpegr.cpp | 4 ++-- libs/ultrahdr/jpegrutils.cpp | 4 +++- libs/ultrahdr/tests/jpegr_test.cpp | 3 ++- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/libs/ultrahdr/include/ultrahdr/jpegrutils.h b/libs/ultrahdr/include/ultrahdr/jpegrutils.h index ed38e07c2d..4ab664e798 100644 --- a/libs/ultrahdr/include/ultrahdr/jpegrutils.h +++ b/libs/ultrahdr/include/ultrahdr/jpegrutils.h @@ -102,7 +102,9 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, ultrahdr_metadata_st * xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> * + * xmlns:Item="http://ns.google.com/photos/1.0/container/item/" + * xmlns:hdrgm="http://ns.adobe.com/hdr-gain-map/1.0/" + * hdrgm:Version="1"> * * * length; // primary image - const string xmp_primary = generateXmpForPrimaryImage(secondary_image_size); + const string xmp_primary = generateXmpForPrimaryImage(secondary_image_size, *metadata); // same as primary const int xmp_primary_length = 2 + nameSpaceLength + xmp_primary.size(); diff --git a/libs/ultrahdr/jpegrutils.cpp b/libs/ultrahdr/jpegrutils.cpp index 9d07a6f889..6430af12c7 100644 --- a/libs/ultrahdr/jpegrutils.cpp +++ b/libs/ultrahdr/jpegrutils.cpp @@ -302,7 +302,7 @@ bool getMetadataFromXMP(uint8_t* xmp_data, size_t xmp_size, ultrahdr_metadata_st return true; } -string generateXmpForPrimaryImage(int secondary_image_length) { +string generateXmpForPrimaryImage(int secondary_image_length, ultrahdr_metadata_struct& metadata) { const vector kConDirSeq({kConDirectory, string("rdf:Seq")}); const vector kLiItem({string("rdf:li"), kConItem}); @@ -316,6 +316,8 @@ string generateXmpForPrimaryImage(int secondary_image_length) { writer.StartWritingElement("rdf:Description"); writer.WriteXmlns(kContainerPrefix, kContainerUri); writer.WriteXmlns(kItemPrefix, kItemUri); + writer.WriteXmlns(kGainMapPrefix, kGainMapUri); + writer.WriteAttributeNameAndValue(kMapVersion, metadata.version); writer.StartWritingElements(kConDirSeq); diff --git a/libs/ultrahdr/tests/jpegr_test.cpp b/libs/ultrahdr/tests/jpegr_test.cpp index ba3b4d0418..58cd8f4711 100644 --- a/libs/ultrahdr/tests/jpegr_test.cpp +++ b/libs/ultrahdr/tests/jpegr_test.cpp @@ -180,6 +180,7 @@ TEST_F(JpegRTest, build) { TEST_F(JpegRTest, writeXmpThenRead) { ultrahdr_metadata_struct metadata_expected; + metadata_expected.version = "1.0"; metadata_expected.maxContentBoost = 1.25; metadata_expected.minContentBoost = 0.75; const std::string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; @@ -538,7 +539,7 @@ TEST_F(JpegRTest, ProfileGainMapFuncs) { JpegRBenchmark benchmark; - ultrahdr_metadata_struct metadata = { .version = 1, + ultrahdr_metadata_struct metadata = { .version = "1.0", .maxContentBoost = 8.0f, .minContentBoost = 1.0f / 8.0f }; -- GitLab From 82396e8990bdffde91b9249a4edbeb03b3e73819 Mon Sep 17 00:00:00 2001 From: Chris Glover Date: Thu, 20 Apr 2023 10:23:22 +0100 Subject: [PATCH 0061/1187] Add support for EGL_EXT_gl_colorspace_bt2020_hlg to libEGL This implements EGL_EXT_gl_colorspace_bt2020_hlg in terms of HAL data formats such that applications can create HLG encoded surfaces. As per the spec, applications need to ensure correct HLG encoding, which made it possible to implement this extension without involving the driver. The change includes a manual update of eglext.h because the spec is not yet ready. https://github.com/KhronosGroup/EGL-Registry/pull/177 Test: Manually ran tests implemented in dEQP in a separate change https://gerrit.khronos.org/c/vk-gl-cts/+/11608 Bug: 277210442 Change-Id: I3e011a786930d978fbc0d86aad29d25e4cdcc148 --- opengl/include/EGL/eglext.h | 5 +++++ opengl/libs/EGL/egl_display.cpp | 5 +++-- opengl/libs/EGL/egl_platform_entries.cpp | 9 ++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h index 501bf58531..32c21f61b9 100644 --- a/opengl/include/EGL/eglext.h +++ b/opengl/include/EGL/eglext.h @@ -697,6 +697,11 @@ EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribEXT (EGLDisplay dpy, EGLint a #define EGL_EXT_device_query 1 #endif /* EGL_EXT_device_query */ +#ifndef EGL_EXT_gl_colorspace_bt2020_hlg +#define EGL_EXT_gl_colorspace_bt2020_hlg 1 +#define EGL_GL_COLORSPACE_BT2020_HLG_EXT 0x333E +#endif /* EGL_EXT_gl_colorspace_bt2020_hlg */ + #ifndef EGL_EXT_gl_colorspace_bt2020_linear #define EGL_EXT_gl_colorspace_bt2020_linear 1 #define EGL_GL_COLORSPACE_BT2020_LINEAR_EXT 0x333F diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index c2c856e22a..9823fc839e 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -353,8 +353,9 @@ EGLBoolean egl_display_t::initialize(EGLint* major, EGLint* minor) { // Typically that means there is an HDR capable display attached, but could be // support for attaching an HDR display. In either case, advertise support for // HDR color spaces. - mExtensionString.append( - "EGL_EXT_gl_colorspace_bt2020_linear EGL_EXT_gl_colorspace_bt2020_pq "); + mExtensionString.append("EGL_EXT_gl_colorspace_bt2020_hlg " + "EGL_EXT_gl_colorspace_bt2020_linear " + "EGL_EXT_gl_colorspace_bt2020_pq "); } char const* start = gExtensionString; diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index 2bca14d2f9..48718bb78a 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -18,6 +18,7 @@ #include "egl_platform_entries.h" +#include #include #include #include @@ -29,7 +30,6 @@ #include #include #include -#include #include #include @@ -421,11 +421,14 @@ static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) { return HAL_DATASPACE_V0_SCRGB; } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) { return HAL_DATASPACE_V0_SCRGB_LINEAR; + } else if (colorspace == EGL_GL_COLORSPACE_BT2020_HLG_EXT) { + return static_cast(HAL_DATASPACE_BT2020_HLG); } else if (colorspace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT) { return HAL_DATASPACE_BT2020_LINEAR; } else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) { return HAL_DATASPACE_BT2020_PQ; } + return HAL_DATASPACE_UNKNOWN; } @@ -452,6 +455,9 @@ static std::vector getDriverColorSpaces(egl_display_t* dp) { if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_scrgb_linear")) { colorSpaces.push_back(EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT); } + if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_hlg")) { + colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_HLG_EXT); + } if (findExtension(dp->disp.queryString.extensions, "EGL_EXT_gl_colorspace_bt2020_linear")) { colorSpaces.push_back(EGL_GL_COLORSPACE_BT2020_LINEAR_EXT); } @@ -485,6 +491,7 @@ static EGLBoolean processAttributes(egl_display_t* dp, ANativeWindow* window, case EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT: case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT: case EGL_GL_COLORSPACE_SCRGB_EXT: + case EGL_GL_COLORSPACE_BT2020_HLG_EXT: case EGL_GL_COLORSPACE_BT2020_LINEAR_EXT: case EGL_GL_COLORSPACE_BT2020_PQ_EXT: case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT: -- GitLab From c2b04f79531b050deef84e28489d7cf313b47d0f Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 20 Apr 2023 23:43:02 +0000 Subject: [PATCH 0062/1187] libbinder: hide record/replay APIs from Binder.h These are not used except by the implementation of Binder, and 'Parcel data' is not a very clear API - it is not intended to be used. Bug: N/A Test: N/A Change-Id: Iae5134633b313bfa1caa21db0d6db0dabe92e0a0 --- libs/binder/include/binder/Binder.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h index d960a0b894..744da0f825 100644 --- a/libs/binder/include/binder/Binder.h +++ b/libs/binder/include/binder/Binder.h @@ -105,12 +105,6 @@ public: [[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd clientFd, const sp& keepAliveBinder); - // Start recording transactions to the unique_fd in data. - // See RecordedTransaction.h for more details. - [[nodiscard]] status_t startRecordingTransactions(const Parcel& data); - // Stop the current recording. - [[nodiscard]] status_t stopRecordingTransactions(); - protected: virtual ~BBinder(); @@ -131,6 +125,8 @@ private: [[nodiscard]] status_t setRpcClientDebug(const Parcel& data); void removeRpcServerLink(const sp& link); + [[nodiscard]] status_t startRecordingTransactions(const Parcel& data); + [[nodiscard]] status_t stopRecordingTransactions(); std::atomic mExtras; -- GitLab From bcfa7faa8076f5191c1cd48c66e9f0ceb3b60891 Mon Sep 17 00:00:00 2001 From: Cody Heiner Date: Mon, 17 Apr 2023 18:34:30 -0700 Subject: [PATCH 0063/1187] Change getService (deprecated) to waitForService The `getService` method is now deprecated. This changes the getService calls to waitForService. The only potential difference in functionality is that getService times out after 10 seconds, while waitForService waits indefinitely. Test: flash to device and reboot, `adb logcat | egrep -i "twoshay|flinger"` shows nothing suspiciously different before/after the change. Bug: 265069414 Change-Id: I84c5f860c869a4e11be6e5490268920dae1e29cc --- services/surfaceflinger/SurfaceFlinger.cpp | 4 ++-- services/surfaceflinger/tests/IPC_test.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5746fae099..a89b48e3e4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -687,7 +687,7 @@ void SurfaceFlinger::bootFinished() { // wait patiently for the window manager death const String16 name("window"); - mWindowManager = defaultServiceManager()->getService(name); + mWindowManager = defaultServiceManager()->waitForService(name); if (mWindowManager != 0) { mWindowManager->linkToDeath(sp::fromExisting(this)); } @@ -701,7 +701,7 @@ void SurfaceFlinger::bootFinished() { LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); - sp input(defaultServiceManager()->getService(String16("inputflinger"))); + sp input(defaultServiceManager()->waitForService(String16("inputflinger"))); static_cast(mScheduler->schedule([=]() FTL_FAKE_GUARD(kMainThreadContext) { if (input == nullptr) { diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp index 40a5d5757d..18bd3b92d2 100644 --- a/services/surfaceflinger/tests/IPC_test.cpp +++ b/services/surfaceflinger/tests/IPC_test.cpp @@ -289,7 +289,7 @@ sp IPCTest::initRemoteService() { IPCThreadState::self()->joinThreadPool(); [&]() { exit(0); }(); } - sp binder = defaultServiceManager()->getService(serviceName); + sp binder = defaultServiceManager()->waitForService(serviceName); remote = interface_cast(binder); remote->setDeathToken(mDeathRecipient); } -- GitLab From dc141d1863d5122481791ffd48f657d0fbbb5c47 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 20 Apr 2023 23:33:25 +0000 Subject: [PATCH 0064/1187] libbinder: RecordedTransaction: simplify chunk read - remove function used once - include errno in error - avoid double-log Bug: N/A Test: binderUnitTests Change-Id: Ia4ddb102839fe40511475452307683740b8e693e --- libs/binder/RecordedTransaction.cpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/libs/binder/RecordedTransaction.cpp b/libs/binder/RecordedTransaction.cpp index ef58ed365f..cb9c327dc7 100644 --- a/libs/binder/RecordedTransaction.cpp +++ b/libs/binder/RecordedTransaction.cpp @@ -161,17 +161,6 @@ static_assert(sizeof(ChunkDescriptor) % 8 == 0); constexpr uint32_t kMaxChunkDataSize = 0xfffffff0; typedef uint64_t transaction_checksum_t; -static android::status_t readChunkDescriptor(borrowed_fd fd, ChunkDescriptor* chunkOut, - transaction_checksum_t* sum) { - if (!android::base::ReadFully(fd, chunkOut, sizeof(ChunkDescriptor))) { - LOG(ERROR) << "Failed to read Chunk Descriptor from fd " << fd.get(); - return android::UNKNOWN_ERROR; - } - - *sum ^= *reinterpret_cast(chunkOut); - return android::NO_ERROR; -} - std::optional RecordedTransaction::fromFile(const unique_fd& fd) { RecordedTransaction t; ChunkDescriptor chunk; @@ -192,11 +181,13 @@ std::optional RecordedTransaction::fromFile(const unique_fd LOG(ERROR) << "Not enough file remains to contain expected chunk descriptor"; return std::nullopt; } - transaction_checksum_t checksum = 0; - if (NO_ERROR != readChunkDescriptor(fd, &chunk, &checksum)) { - LOG(ERROR) << "Failed to read chunk descriptor."; + + if (!android::base::ReadFully(fd, &chunk, sizeof(ChunkDescriptor))) { + LOG(ERROR) << "Failed to read ChunkDescriptor from fd " << fd.get() << ". " + << strerror(errno); return std::nullopt; } + transaction_checksum_t checksum = *reinterpret_cast(&chunk); fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR); if (fdCurrentPosition == -1) { -- GitLab From a8244b9a23667710155990035405d3132b844177 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 20 Apr 2023 23:34:11 +0000 Subject: [PATCH 0065/1187] libbinder: binderRecordReplayTest Initial scaffolding for a functional record replay test. Future directions: - adding additional types (int, float, etc..) - adding support for binder objects - adding support RPC binder record/replay - adding support for host Bug: N/A Test: binderRecordReplayTest Change-Id: I1a7083e850ac0e49bf006bd0c6c68076e0b993b2 --- libs/binder/tests/Android.bp | 22 ++++ .../binder/tests/IBinderRecordReplayTest.aidl | 20 +++ libs/binder/tests/binderRecordReplayTest.cpp | 115 ++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 libs/binder/tests/IBinderRecordReplayTest.aidl create mode 100644 libs/binder/tests/binderRecordReplayTest.cpp diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 873e9550f9..7a462db797 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -110,6 +110,28 @@ cc_test { test_suites: ["general-tests"], } +cc_test { + name: "binderRecordReplayTest", + srcs: ["binderRecordReplayTest.cpp"], + shared_libs: [ + "libbinder", + "libcutils", + "libutils", + ], + static_libs: [ + "binderRecordReplayTestIface-cpp", + ], + test_suites: ["general-tests"], +} + +aidl_interface { + name: "binderRecordReplayTestIface", + unstable: true, + srcs: [ + "IBinderRecordReplayTest.aidl", + ], +} + cc_test { name: "binderLibTest", defaults: ["binder_test_defaults"], diff --git a/libs/binder/tests/IBinderRecordReplayTest.aidl b/libs/binder/tests/IBinderRecordReplayTest.aidl new file mode 100644 index 0000000000..3c8c722da4 --- /dev/null +++ b/libs/binder/tests/IBinderRecordReplayTest.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2023 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. + */ + +interface IBinderRecordReplayTest { + void setInt(int input); + int getInt(); +} diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp new file mode 100644 index 0000000000..55148acf14 --- /dev/null +++ b/libs/binder/tests/binderRecordReplayTest.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2023 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace android; +using android::binder::Status; +using android::binder::debug::RecordedTransaction; + +const String16 kServerName = String16("binderRecordReplay"); + +class MyRecordReplay : public BnBinderRecordReplayTest { +public: + Status setInt(int input) { + mInt = input; + return Status::ok(); + } + Status getInt(int* output) { + *output = mInt; + return Status::ok(); + } + +private: + int mInt = 0; +}; + +TEST(BinderClearBuf, RecordReplayRepeatInt) { + // get the remote service + sp binder = defaultServiceManager()->getService(kServerName); + ASSERT_NE(nullptr, binder); + sp iface = interface_cast(binder); + sp bpBinder = binder->remoteBinder(); + ASSERT_NE(nullptr, bpBinder); + + base::unique_fd fd( + open("/data/local/tmp/binderRecordReplayTest.rec", O_RDWR | O_CREAT | O_CLOEXEC, 0666)); + ASSERT_TRUE(fd.ok()); + + // record a transaction + bpBinder->startRecordingBinder(fd); + EXPECT_TRUE(iface->setInt(3).isOk()); + bpBinder->stopRecordingBinder(); + + // test transaction does the thing we expect it to do + int output; + EXPECT_TRUE(iface->getInt(&output).isOk()); + EXPECT_EQ(output, 3); + + // write over the existing state + EXPECT_TRUE(iface->setInt(5).isOk()); + EXPECT_TRUE(iface->getInt(&output).isOk()); + EXPECT_EQ(output, 5); + + // replay transaction + ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET)); + std::optional transaction = RecordedTransaction::fromFile(fd); + ASSERT_NE(transaction, std::nullopt); + + // TODO: move logic to replay RecordedTransaction into RecordedTransaction + Parcel data; + data.setData(transaction->getDataParcel().data(), transaction->getDataParcel().dataSize()); + status_t status = binder->remoteBinder()->transact(transaction->getCode(), data, nullptr, + transaction->getFlags()); + + // make sure recording does the thing we expect it to do + EXPECT_EQ(OK, status); + EXPECT_TRUE(iface->getInt(&output).isOk()); + EXPECT_EQ(output, 3); + + // TODO: we should also make sure we can convert the recording to a fuzzer + // corpus entry, and we will be able to replay it in the same way +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + + if (fork() == 0) { + prctl(PR_SET_PDEATHSIG, SIGHUP); + + auto server = sp::make(); + android::defaultServiceManager()->addService(kServerName, server.get()); + + IPCThreadState::self()->joinThreadPool(true); + exit(1); // should not reach + } + + // not racey, but getService sleeps for 1s + usleep(100000); + + return RUN_ALL_TESTS(); +} -- GitLab From 28c8728295ade83a659d9432d2adbf253eb9196e Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 14 Apr 2023 21:03:01 +0000 Subject: [PATCH 0066/1187] freeze rpc binder wire protocol for Android U Bug: 266741352 Test: binderRpcWireProtocolTest Change-Id: Iafa1f49a9f0f536162c59ff44143f05b61e9c9e8 Merged-In: Iafa1f49a9f0f536162c59ff44143f05b61e9c9e8 --- libs/binder/RpcState.cpp | 2 +- libs/binder/include/binder/RpcSession.h | 4 ++-- libs/binder/tests/binderRpcWireProtocolTest.cpp | 13 ++++++++++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index ed3ce24e46..03fa69973d 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -928,7 +928,7 @@ processTransactInternalTailCall: transactionData.size() - offsetof(RpcWireTransaction, data)}; Span objectTableSpan; - if (session->getProtocolVersion().value() > + if (session->getProtocolVersion().value() >= RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) { std::optional> objectTableBytes = parcelSpan.splitOff(transaction->parcelDataSize); diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h index a323febbc7..cb6460398d 100644 --- a/libs/binder/include/binder/RpcSession.h +++ b/libs/binder/include/binder/RpcSession.h @@ -37,9 +37,9 @@ class RpcState; class RpcTransport; class FdTrigger; -constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 1; +constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 2; constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL = 0xF0000000; -constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL; +constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = 1; // Starting with this version: // diff --git a/libs/binder/tests/binderRpcWireProtocolTest.cpp b/libs/binder/tests/binderRpcWireProtocolTest.cpp index 3dab2c748b..642cea440d 100644 --- a/libs/binder/tests/binderRpcWireProtocolTest.cpp +++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp @@ -237,14 +237,25 @@ TEST(RpcWire, V0) { checkRepr(kCurrentRepr, 0); } +TEST(RpcWire, V1) { + checkRepr(kCurrentRepr, 1); +} + TEST(RpcWire, CurrentVersion) { checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION); } -static_assert(RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL, +static_assert(RPC_WIRE_PROTOCOL_VERSION == 1, "If the binder wire protocol is updated, this test should test additional versions. " "The binder wire protocol should only be updated on upstream AOSP."); +TEST(RpcWire, NextIsPlusOneReminder) { + if (RPC_WIRE_PROTOCOL_VERSION != RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) { + EXPECT_EQ(RPC_WIRE_PROTOCOL_VERSION + 1, RPC_WIRE_PROTOCOL_VERSION_NEXT) + << "Make sure to note what the next version should be."; + } +} + TEST(RpcWire, ReleaseBranchHasFrozenRpcWireProtocol) { if (RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) { EXPECT_FALSE(base::GetProperty("ro.build.version.codename", "") == "REL") -- GitLab From 2ed5cf9a07889c97d9fc28471934f1115c72736f Mon Sep 17 00:00:00 2001 From: Sungtak Lee Date: Mon, 24 Apr 2023 17:51:45 +0000 Subject: [PATCH 0067/1187] Add toString() to HardwareBuffer Bug: N/A Test: m Change-Id: I7452fd53876eacb0a062d5a5c601594de2190ee1 --- .../include/android/hardware_buffer_aidl.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libs/nativewindow/include/android/hardware_buffer_aidl.h b/libs/nativewindow/include/android/hardware_buffer_aidl.h index 1659d54539..e269f0dddf 100644 --- a/libs/nativewindow/include/android/hardware_buffer_aidl.h +++ b/libs/nativewindow/include/android/hardware_buffer_aidl.h @@ -34,6 +34,10 @@ #include #include +#ifdef __cplusplus +#include +#endif + __BEGIN_DECLS /** @@ -142,6 +146,15 @@ public: return ret; } + inline std::string toString() const { + if (!mBuffer) { + return ""; + } + uint64_t id = 0; + AHardwareBuffer_getId(mBuffer, &id); + return ""; + } + private: HardwareBuffer(const HardwareBuffer& other) = delete; HardwareBuffer& operator=(const HardwareBuffer& other) = delete; -- GitLab From 68275d7ca0951a6e46563f2578a8098113a32dc7 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 21 Apr 2023 22:12:45 +0000 Subject: [PATCH 0068/1187] libbinder: remove 32-bit ABI support This was an old userspace ABI, but we've encouraged all platforms to move to a consistent ABI, regardless of bitness of the device. This corresponds to a kernel config option that we started requiring not be set in Android P. After this, the build system still needs to have this support removed. Bug: 232423610 Test: boot cf Change-Id: Iff5997f910d86c73bbd6502ec393434d248cdcd5 --- libs/binder/Android.bp | 4 -- libs/binder/ProcessState.cpp | 9 +--- libs/binder/include/binder/Parcel.h | 5 -- libs/binder/tests/Android.bp | 49 ----------------- libs/binder/tests/binderAbiHelper.h | 52 ------------------- .../tests/binderDriverInterfaceTest.cpp | 5 +- libs/binder/tests/binderLibTest.cpp | 5 +- 7 files changed, 3 insertions(+), 126 deletions(-) delete mode 100644 libs/binder/tests/binderAbiHelper.h diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 1f1fafccee..a4f2b070c4 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -144,10 +144,6 @@ cc_defaults { "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", ], product_variables: { - binder32bit: { - cflags: ["-DBINDER_IPC_32BIT=1"], - }, - debuggable: { cflags: [ "-DBINDER_RPC_DEV_SERVERS", diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 5f1f50672a..3fa686782a 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -104,14 +104,7 @@ bool ProcessState::isVndservicemanagerEnabled() { return access("/vendor/bin/vndservicemanager", R_OK) == 0; } -sp ProcessState::init(const char *driver, bool requireDefault) -{ -#ifdef BINDER_IPC_32BIT - LOG_ALWAYS_FATAL("32-bit binder IPC is not supported for new devices starting in Android P. If " - "you do need to use this mode, please see b/232423610 or file an issue with " - "AOSP upstream as otherwise this will be removed soon."); -#endif - +sp ProcessState::init(const char* driver, bool requireDefault) { if (driver == nullptr) { std::lock_guard l(gProcessMutex); if (gProcess) { diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 162cd406dc..e28d374b26 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -34,13 +34,8 @@ #include #include -#ifdef BINDER_IPC_32BIT -//NOLINTNEXTLINE(google-runtime-int) b/173188702 -typedef unsigned int binder_size_t; -#else //NOLINTNEXTLINE(google-runtime-int) b/173188702 typedef unsigned long long binder_size_t; -#endif struct flat_binder_object; diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 873e9550f9..56f4ac7fe5 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -31,29 +31,9 @@ cc_defaults { ], } -cc_test { - name: "binderDriverInterfaceTest_IPC_32", - defaults: ["binder_test_defaults"], - srcs: ["binderDriverInterfaceTest.cpp"], - header_libs: ["libbinder_headers"], - compile_multilib: "32", - multilib: { - lib32: { - suffix: "", - }, - }, - cflags: ["-DBINDER_IPC_32BIT=1"], - test_suites: ["vts"], -} - cc_test { name: "binderDriverInterfaceTest", defaults: ["binder_test_defaults"], - product_variables: { - binder32bit: { - cflags: ["-DBINDER_IPC_32BIT=1"], - }, - }, header_libs: ["libbinder_headers"], srcs: ["binderDriverInterfaceTest.cpp"], test_suites: [ @@ -62,30 +42,6 @@ cc_test { ], } -cc_test { - name: "binderLibTest_IPC_32", - defaults: ["binder_test_defaults"], - srcs: ["binderLibTest.cpp"], - shared_libs: [ - "libbase", - "libbinder", - "liblog", - "libutils", - ], - static_libs: [ - "libgmock", - ], - compile_multilib: "32", - multilib: { - lib32: { - suffix: "", - }, - }, - cflags: ["-DBINDER_IPC_32BIT=1"], - test_suites: ["vts"], - require_root: true, -} - // unit test only, which can run on host and doesn't use /dev/binder cc_test { name: "binderUnitTest", @@ -113,11 +69,6 @@ cc_test { cc_test { name: "binderLibTest", defaults: ["binder_test_defaults"], - product_variables: { - binder32bit: { - cflags: ["-DBINDER_IPC_32BIT=1"], - }, - }, srcs: ["binderLibTest.cpp"], shared_libs: [ diff --git a/libs/binder/tests/binderAbiHelper.h b/libs/binder/tests/binderAbiHelper.h deleted file mode 100644 index 369b55dc22..0000000000 --- a/libs/binder/tests/binderAbiHelper.h +++ /dev/null @@ -1,52 +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. - */ - -#pragma once - -#include -#include - -#ifdef BINDER_IPC_32BIT -static constexpr bool kBuild32Abi = true; -#else -static constexpr bool kBuild32Abi = false; -#endif - -// TODO: remove when CONFIG_ANDROID_BINDER_IPC_32BIT is no longer supported -static inline bool ReadKernelConfigIs32BitAbi() { - // failure case implies we run with standard ABI - return 0 == system("zcat /proc/config.gz | grep -E \"^CONFIG_ANDROID_BINDER_IPC_32BIT=y$\""); -} - -static inline void ExitIfWrongAbi() { - bool runtime32Abi = ReadKernelConfigIs32BitAbi(); - - if (kBuild32Abi != runtime32Abi) { - std::cout << "[==========] Running 1 test from 1 test suite." << std::endl; - std::cout << "[----------] Global test environment set-up." << std::endl; - std::cout << "[----------] 1 tests from BinderLibTest" << std::endl; - std::cout << "[ RUN ] BinderTest.AbortForWrongAbi" << std::endl; - std::cout << "[ INFO ] test build abi 32: " << kBuild32Abi << " runtime abi 32: " << runtime32Abi << " so, skipping tests " << std::endl; - std::cout << "[ OK ] BinderTest.AbortForWrongAbi (0 ms) " << std::endl; - std::cout << "[----------] 1 tests from BinderTest (0 ms total)" << std::endl; - std::cout << "" << std::endl; - std::cout << "[----------] Global test environment tear-down" << std::endl; - std::cout << "[==========] 1 test from 1 test suite ran. (0 ms total)" << std::endl; - std::cout << "[ PASSED ] 1 tests." << std::endl; - exit(0); - } -} - diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp index 8cc3054f80..cf23a4658c 100644 --- a/libs/binder/tests/binderDriverInterfaceTest.cpp +++ b/libs/binder/tests/binderDriverInterfaceTest.cpp @@ -25,8 +25,6 @@ #include #include -#include "binderAbiHelper.h" - #define BINDER_DEV_NAME "/dev/binder" testing::Environment* binder_env; @@ -362,8 +360,7 @@ TEST_F(BinderDriverInterfaceTest, RequestDeathNotification) { binderTestReadEmpty(); } -int main(int argc, char **argv) { - ExitIfWrongAbi(); +int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); binder_env = AddGlobalTestEnvironment(new BinderDriverInterfaceTestEnv()); diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 8974ad745d..abc423b669 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -48,7 +48,6 @@ #include #include "../binder_module.h" -#include "binderAbiHelper.h" #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) @@ -2022,9 +2021,7 @@ int run_server(int index, int readypipefd, bool usePoll) return 1; /* joinThreadPool should not return */ } -int main(int argc, char **argv) { - ExitIfWrongAbi(); - +int main(int argc, char** argv) { if (argc == 4 && !strcmp(argv[1], "--servername")) { binderservername = argv[2]; } else { -- GitLab From 536deac847bbf1e8fbc7d9a60df00c60133df374 Mon Sep 17 00:00:00 2001 From: Andrei Homescu Date: Tue, 25 Apr 2023 07:09:03 +0000 Subject: [PATCH 0069/1187] binderRpcTest: More heap memory on Trusty binderRpcTest uses a lot of memory and crashes on Trusty if it runs out, so raise its heap limit from 160K to 256K. Bug: None Test: Boot emulator Change-Id: Ib8f4188f50415a5e017a3c00f2073055bc3269e3 --- libs/binder/trusty/binderRpcTest/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/binder/trusty/binderRpcTest/manifest.json b/libs/binder/trusty/binderRpcTest/manifest.json index d8b080f0d4..1cefac5a2b 100644 --- a/libs/binder/trusty/binderRpcTest/manifest.json +++ b/libs/binder/trusty/binderRpcTest/manifest.json @@ -1,6 +1,6 @@ { "uuid": "9dbe9fb8-60fd-4bdd-af86-03e95d7ad78b", "app_name": "binderRpcTest", - "min_heap": 163840, + "min_heap": 262144, "min_stack": 16384 } -- GitLab From 3d37ef29628ef7e24d0fa1e1b494f87d9cfc8458 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 25 Apr 2023 18:25:14 +0000 Subject: [PATCH 0070/1187] Revert "libbinder: double cost for incorrect wait config" This reverts commit 2839c45cf9c29c11c588e5fdc868c00922f2ae6e. Reason for revert: no clear path forward for some wakelock users Fixes: 279514466 Change-Id: I93884340ea224fe71aa05b1e30bd2f1b538f8804 --- libs/binder/IServiceManager.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index d4ef0b73a1..2408307459 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -412,11 +412,13 @@ sp ServiceManagerShim::waitForService(const String16& name16) // command, so we hang indefinitely. std::unique_lock lock(waiter->mMutex); using std::literals::chrono_literals::operator""s; - waiter->mCv.wait_for(lock, 2s, [&] { return waiter->mBinder != nullptr; }); + waiter->mCv.wait_for(lock, 1s, [&] { + return waiter->mBinder != nullptr; + }); if (waiter->mBinder != nullptr) return waiter->mBinder; } - ALOGW("Waited two seconds for %s (is service started? Number of threads started in the " + ALOGW("Waited one second for %s (is service started? Number of threads started in the " "threadpool: %zu. Are binder threads started and available?)", name.c_str(), ProcessState::self()->getThreadPoolMaxTotalThreadCount()); -- GitLab From 0543cf5860a95e7693a0228baba4dbb75bbbcb7b Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 26 Apr 2023 00:40:34 +0000 Subject: [PATCH 0071/1187] libbinder: replace flaky tests with real coverage A lazy service shouldn't quit when it has clients, but sometimes it needs to, such as when the device is shutting down, so we test that it works. In Android U, I broke this behavior, and it was caught by other tests. However, now we have test support for this directly in aidl_lazy_test. Fixes: 279301793 Fixes: 278337172 Fixes: 277886514 Fixes: 276536663 Fixes: 278117892 Test: aidl_lazy_test Change-Id: I594305d5fd9ad2b4193ec828ccd012817a481b1a --- libs/binder/TEST_MAPPING | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index 41707d48b2..0e8e18747b 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -91,12 +91,6 @@ { "name": "binderRpcTest" }, - { - "name": "CtsRootRollbackManagerHostTestCases" - }, - { - "name": "StagedRollbackTest" - }, { "name": "binderRpcTestNoKernel" }, -- GitLab From 75105629cba78fbc9f6a7f4f69e210767f256db6 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 26 Apr 2023 22:32:18 +0000 Subject: [PATCH 0072/1187] binderRpcTest: reduce thread pool saturated flake Limit one of the checks here since we tightened timings around it. Fixes: 278414056 Test: N/A Change-Id: I9a86ef09784dd093e4ffd45c91892bb5788ab2a5 --- libs/binder/tests/binderRpcTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 8d1300779a..287e077d40 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -462,7 +462,7 @@ static void testThreadPoolOverSaturated(sp iface, size_t numCall EXPECT_GE(epochMsAfter, epochMsBefore + 2 * sleepMs); // Potential flake, but make sure calls are handled in parallel. - EXPECT_LE(epochMsAfter, epochMsBefore + 3 * sleepMs); + EXPECT_LE(epochMsAfter, epochMsBefore + 4 * sleepMs); } TEST_P(BinderRpc, ThreadPoolOverSaturated) { -- GitLab From 23740b95e8589f57aba82f61ef875013d8b92c6f Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 21 Apr 2023 11:30:20 -0700 Subject: [PATCH 0073/1187] Validate events before printing them Before this patch, enabling the injection logs would cause a crash when running inputflinger_tests. This happened because the events were getting printed prior to getting checked for validity. To fix this, move the check to the beginning of the function. Test: m inputflinger_tests && $ANDROID_HOST_OUT/nativetest64/inputflinger_tests/inputflinger_tests Bug: 274073185 Change-Id: I8c92e47133e0eea55186be049434bdfd5c0348ff --- .../dispatcher/InputDispatcher.cpp | 160 +++++++++++------- 1 file changed, 103 insertions(+), 57 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index af3819d607..ac936f3ef9 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -54,6 +54,7 @@ #define INDENT4 " " using namespace android::ftl::flag_operators; +using android::base::Error; using android::base::HwTimeoutMultiplier; using android::base::Result; using android::base::StringPrintf; @@ -129,48 +130,68 @@ inline int32_t getMotionEventActionPointerIndex(int32_t action) { AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } -bool isValidKeyAction(int32_t action) { +Result checkKeyAction(int32_t action) { switch (action) { case AKEY_EVENT_ACTION_DOWN: case AKEY_EVENT_ACTION_UP: - return true; + return {}; default: - return false; + return Error() << "Key event has invalid action code " << action; } } -bool validateKeyEvent(int32_t action) { - if (!isValidKeyAction(action)) { - ALOGE("Key event has invalid action code 0x%x", action); - return false; - } - return true; +Result validateKeyEvent(int32_t action) { + return checkKeyAction(action); } -bool isValidMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) { +Result checkMotionAction(int32_t action, int32_t actionButton, int32_t pointerCount) { switch (MotionEvent::getActionMasked(action)) { case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_UP: - return pointerCount == 1; + case AMOTION_EVENT_ACTION_UP: { + if (pointerCount != 1) { + return Error() << "invalid pointer count " << pointerCount; + } + return {}; + } case AMOTION_EVENT_ACTION_MOVE: case AMOTION_EVENT_ACTION_HOVER_ENTER: case AMOTION_EVENT_ACTION_HOVER_MOVE: - case AMOTION_EVENT_ACTION_HOVER_EXIT: - return pointerCount >= 1; + case AMOTION_EVENT_ACTION_HOVER_EXIT: { + if (pointerCount < 1) { + return Error() << "invalid pointer count " << pointerCount; + } + return {}; + } case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_OUTSIDE: case AMOTION_EVENT_ACTION_SCROLL: - return true; + return {}; case AMOTION_EVENT_ACTION_POINTER_DOWN: case AMOTION_EVENT_ACTION_POINTER_UP: { const int32_t index = MotionEvent::getActionIndex(action); - return index >= 0 && index < pointerCount && pointerCount > 1; + if (index < 0) { + return Error() << "invalid index " << index << " for " + << MotionEvent::actionToString(action); + } + if (index >= pointerCount) { + return Error() << "invalid index " << index << " for pointerCount " << pointerCount; + } + if (pointerCount <= 1) { + return Error() << "invalid pointer count " << pointerCount << " for " + << MotionEvent::actionToString(action); + } + return {}; } case AMOTION_EVENT_ACTION_BUTTON_PRESS: - case AMOTION_EVENT_ACTION_BUTTON_RELEASE: - return actionButton != 0; + case AMOTION_EVENT_ACTION_BUTTON_RELEASE: { + if (actionButton == 0) { + return Error() << "action button should be nonzero for " + << MotionEvent::actionToString(action); + } + return {}; + } default: - return false; + return Error() << "invalid action " << action; } } @@ -178,32 +199,50 @@ int64_t millis(std::chrono::nanoseconds t) { return std::chrono::duration_cast(t).count(); } -bool validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount, - const PointerProperties* pointerProperties) { - if (!isValidMotionAction(action, actionButton, pointerCount)) { - ALOGE("Motion event has invalid action code 0x%x", action); - return false; +Result validateMotionEvent(int32_t action, int32_t actionButton, size_t pointerCount, + const PointerProperties* pointerProperties) { + Result actionCheck = checkMotionAction(action, actionButton, pointerCount); + if (!actionCheck.ok()) { + return actionCheck; } if (pointerCount < 1 || pointerCount > MAX_POINTERS) { - ALOGE("Motion event has invalid pointer count %zu; value must be between 1 and %zu.", - pointerCount, MAX_POINTERS); - return false; + return Error() << "Motion event has invalid pointer count " << pointerCount + << "; value must be between 1 and " << MAX_POINTERS << "."; } std::bitset pointerIdBits; for (size_t i = 0; i < pointerCount; i++) { int32_t id = pointerProperties[i].id; if (id < 0 || id > MAX_POINTER_ID) { - ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", id, - MAX_POINTER_ID); - return false; + return Error() << "Motion event has invalid pointer id " << id + << "; value must be between 0 and " << MAX_POINTER_ID; } if (pointerIdBits.test(id)) { - ALOGE("Motion event has duplicate pointer id %d", id); - return false; + return Error() << "Motion event has duplicate pointer id " << id; } pointerIdBits.set(id); } - return true; + return {}; +} + +Result validateInputEvent(const InputEvent& event) { + switch (event.getType()) { + case InputEventType::KEY: { + const KeyEvent& key = static_cast(event); + const int32_t action = key.getAction(); + return validateKeyEvent(action); + } + case InputEventType::MOTION: { + const MotionEvent& motion = static_cast(event); + const int32_t action = motion.getAction(); + const size_t pointerCount = motion.getPointerCount(); + const PointerProperties* pointerProperties = motion.getPointerProperties(); + const int32_t actionButton = motion.getActionButton(); + return validateMotionEvent(action, actionButton, pointerCount, pointerProperties); + } + default: { + return {}; + } + } } std::string dumpRegion(const Region& region) { @@ -4092,7 +4131,9 @@ void InputDispatcher::notifyKey(const NotifyKeyArgs& args) { args.id, args.eventTime, args.deviceId, inputEventSourceToString(args.source).c_str(), args.displayId, args.policyFlags, KeyEvent::actionToString(args.action), args.flags, KeyEvent::getLabel(args.keyCode), args.scanCode, args.metaState, args.downTime); - if (!validateKeyEvent(args.action)) { + Result keyCheck = validateKeyEvent(args.action); + if (!keyCheck.ok()) { + LOG(ERROR) << "invalid key event: " << keyCheck.error(); return; } @@ -4188,9 +4229,13 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) { args.pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); } } - LOG_ALWAYS_FATAL_IF(!validateMotionEvent(args.action, args.actionButton, args.pointerCount, - args.pointerProperties), - "Invalid event: %s", args.dump().c_str()); + + Result motionCheck = validateMotionEvent(args.action, args.actionButton, + args.pointerCount, args.pointerProperties); + if (!motionCheck.ok()) { + LOG(FATAL) << "Invalid event: " << args.dump() << "; reason: " << motionCheck.error(); + return; + } uint32_t policyFlags = args.policyFlags; policyFlags |= POLICY_FLAG_TRUSTED; @@ -4364,6 +4409,12 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev InputEventInjectionSync syncMode, std::chrono::milliseconds timeout, uint32_t policyFlags) { + Result eventValidation = validateInputEvent(*event); + if (!eventValidation.ok()) { + LOG(INFO) << "Injection failed: invalid event: " << eventValidation.error(); + return InputEventInjectionResult::FAILED; + } + if (debugInboundEventDetails()) { LOG(DEBUG) << __func__ << ": targetUid=" << toString(targetUid) << ", syncMode=" << ftl::enum_string(syncMode) << ", timeout=" << timeout.count() @@ -4389,11 +4440,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev switch (event->getType()) { case InputEventType::KEY: { const KeyEvent& incomingKey = static_cast(*event); - int32_t action = incomingKey.getAction(); - if (!validateKeyEvent(action)) { - return InputEventInjectionResult::FAILED; - } - + const int32_t action = incomingKey.getAction(); int32_t flags = incomingKey.getFlags(); if (policyFlags & POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY) { flags |= AKEY_EVENT_FLAG_IS_ACCESSIBILITY_EVENT; @@ -4435,20 +4482,13 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev case InputEventType::MOTION: { const MotionEvent& motionEvent = static_cast(*event); - const int32_t action = motionEvent.getAction(); const bool isPointerEvent = isFromSource(event->getSource(), AINPUT_SOURCE_CLASS_POINTER); // If a pointer event has no displayId specified, inject it to the default display. const uint32_t displayId = isPointerEvent && (event->getDisplayId() == ADISPLAY_ID_NONE) ? ADISPLAY_ID_DEFAULT : event->getDisplayId(); - const size_t pointerCount = motionEvent.getPointerCount(); - const PointerProperties* pointerProperties = motionEvent.getPointerProperties(); - const int32_t actionButton = motionEvent.getActionButton(); int32_t flags = motionEvent.getFlags(); - if (!validateMotionEvent(action, actionButton, pointerCount, pointerProperties)) { - return InputEventInjectionResult::FAILED; - } if (!(policyFlags & POLICY_FLAG_FILTERED)) { nsecs_t eventTime = motionEvent.getEventTime(); @@ -4470,8 +4510,9 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev std::unique_ptr injectedEntry = std::make_unique(motionEvent.getId(), *sampleEventTimes, resolvedDeviceId, motionEvent.getSource(), - displayId, policyFlags, action, actionButton, - flags, motionEvent.getMetaState(), + displayId, policyFlags, motionEvent.getAction(), + motionEvent.getActionButton(), flags, + motionEvent.getMetaState(), motionEvent.getButtonState(), motionEvent.getClassification(), motionEvent.getEdgeFlags(), @@ -4479,18 +4520,22 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev motionEvent.getYPrecision(), motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), - motionEvent.getDownTime(), uint32_t(pointerCount), - pointerProperties, samplePointerCoords); + motionEvent.getDownTime(), + motionEvent.getPointerCount(), + motionEvent.getPointerProperties(), + samplePointerCoords); transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { sampleEventTimes += 1; - samplePointerCoords += pointerCount; + samplePointerCoords += motionEvent.getPointerCount(); std::unique_ptr nextInjectedEntry = std::make_unique(motionEvent.getId(), *sampleEventTimes, resolvedDeviceId, motionEvent.getSource(), - displayId, policyFlags, action, actionButton, - flags, motionEvent.getMetaState(), + displayId, policyFlags, + motionEvent.getAction(), + motionEvent.getActionButton(), flags, + motionEvent.getMetaState(), motionEvent.getButtonState(), motionEvent.getClassification(), motionEvent.getEdgeFlags(), @@ -4499,7 +4544,8 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), - uint32_t(pointerCount), pointerProperties, + motionEvent.getPointerCount(), + motionEvent.getPointerProperties(), samplePointerCoords); transformMotionEntryForInjectionLocked(*nextInjectedEntry, motionEvent.getTransform()); -- GitLab From 3d0d3e99c0335b94fa41fafce6d0fb3fedb07f75 Mon Sep 17 00:00:00 2001 From: zhangjincheng Date: Tue, 25 Apr 2023 15:41:04 +0800 Subject: [PATCH 0074/1187] opengl: fix resource leak when dlsym failed Bug: 280001152 Test: coverity test Change-Id: Id189b304e791ec60c2661f941b0f0d480cf15227 Signed-off-by: zhangjincheng --- opengl/libs/EGL/egl_angle_platform.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp index d38f2eff01..c0ead5096f 100644 --- a/opengl/libs/EGL/egl_angle_platform.cpp +++ b/opengl/libs/EGL/egl_angle_platform.cpp @@ -145,6 +145,7 @@ bool initializeAnglePlatform(EGLDisplay dpy) { if (!angleGetDisplayPlatform) { ALOGE("dlsym lookup of ANGLEGetDisplayPlatform in libEGL_angle failed!"); + dlclose(so); return false; } @@ -155,6 +156,7 @@ bool initializeAnglePlatform(EGLDisplay dpy) { if (!((angleGetDisplayPlatform)(dpy, g_PlatformMethodNames, g_NumPlatformMethods, nullptr, &platformMethods))) { ALOGE("ANGLEGetDisplayPlatform call failed!"); + dlclose(so); return false; } if (platformMethods) { -- GitLab From 7957867cc13bd17c55eaf5624c2905037d881b59 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 27 Apr 2023 19:38:00 +0000 Subject: [PATCH 0075/1187] sm: lazy service - fix race There is a possible race: - service registers binder A - service registers client callback (cc1) for A - sm send cc1 "A hasClients" - service registers binder A (again - bad behavior!) - side effect: "hasClients" implicitly set to false - service registers client callback (cc2) for A - sm sends cc1 and cc2 "A hasClients" Due to an intentionally overly careful check in client callbacks, they crash when this double-send of 'hasClients' is hit. This CL retains the state of cc1 in order to fix the issue. Comments are added with various details about the implementation, and b/279948722 is filed to resolve these comments. Bug: 279898063 Test: aidl_lazy_test Change-Id: Ida443d5b02f19736baabdc57ff283995cdcc2a87 --- cmds/servicemanager/ServiceManager.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 56c9d4688b..4472db10c0 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -372,8 +372,10 @@ Status ServiceManager::addService(const std::string& name, const sp& bi } auto it = mNameToService.find(name); + bool prevClients = false; if (it != mNameToService.end()) { const Service& existing = it->second; + prevClients = existing.hasClients; // We could do better than this because if the other service dies, it // may not have an entry here. However, this case is unlikely. We are @@ -401,10 +403,13 @@ Status ServiceManager::addService(const std::string& name, const sp& bi .binder = binder, .allowIsolated = allowIsolated, .dumpPriority = dumpPriority, + .hasClients = prevClients, // see b/279898063, matters if existing callbacks + .guaranteeClient = false, // handled below .ctx = ctx, }; if (auto it = mNameToRegistrationCallback.find(name); it != mNameToRegistrationCallback.end()) { + // TODO: this is only needed once // See also getService - handles case where client never gets the service, // we want the service to quit. mNameToService[name].guaranteeClient = true; @@ -623,6 +628,14 @@ void ServiceManager::removeRegistrationCallback(const wp& who, void ServiceManager::binderDied(const wp& who) { for (auto it = mNameToService.begin(); it != mNameToService.end();) { if (who == it->second.binder) { + // TODO: currently, this entry contains the state also + // associated with mNameToClientCallback. If we allowed + // other processes to register client callbacks, we + // would have to preserve hasClients (perhaps moving + // that state into mNameToClientCallback, which is complicated + // because those callbacks are associated w/ particular binder + // objects, though they are indexed by name now, they may + // need to be indexed by binder at that point). it = mNameToService.erase(it); } else { ++it; @@ -690,7 +703,10 @@ Status ServiceManager::registerClientCallback(const std::string& name, const sp< return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Couldn't linkToDeath."); } - // make sure all callbacks have been told about a consistent state - b/278038751 + // WARNING: binderDied makes an assumption about this. If we open up client + // callbacks to other services, certain race conditions may lead to services + // getting extra client callback notifications. + // Make sure all callbacks have been told about a consistent state - b/278038751 if (serviceIt->second.hasClients) { cb->onClients(service, true); } -- GitLab From 847d8c54095c7f0df70f0b99fe2dfbbf31070204 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 2 May 2023 23:56:58 +0000 Subject: [PATCH 0076/1187] libbinder: keep uninit descriptor empty Java users creating custom binder interfaces may rely on empty descriptors. Bug: 278655444 Test: binderAllocationLimits Change-Id: I8bba68a3906517dff060853fc6224b5b5d7d37ab --- libs/binder/BpBinder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 53852d88ed..8d9955dd6b 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -47,7 +47,7 @@ std::atomic_bool BpBinder::sCountByUidEnabled(false); binder_proxy_limit_callback BpBinder::sLimitCallback; bool BpBinder::sBinderProxyThrottleCreate = false; -static StaticString16 kDescriptorUninit(u""); +static StaticString16 kDescriptorUninit(u""); // Arbitrarily high value that probably distinguishes a bad behaving app uint32_t BpBinder::sBinderProxyCountHighWatermark = 2500; -- GitLab From 4ed688dcb5507fcfa12a2190229ef2de548e8a96 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 3 May 2023 23:03:56 +0000 Subject: [PATCH 0077/1187] binderRecordReplayTest: require_root I did not discover this was needed locally due to b/271842039. Change-Id: Ida7e29bff0f2af347c5d31c992497894a594861e Test: N/A --- libs/binder/TEST_MAPPING | 3 +++ libs/binder/tests/Android.bp | 1 + 2 files changed, 4 insertions(+) diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index 0e8e18747b..151d617050 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -15,6 +15,9 @@ { "name": "binderDriverInterfaceTest" }, + { + "name": "binderRecordReplayTest" + }, { "name": "binderHostDeviceTest" }, diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index cad364d8e8..0280c96689 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -78,6 +78,7 @@ cc_test { "binderRecordReplayTestIface-cpp", ], test_suites: ["general-tests"], + require_root: true, } aidl_interface { -- GitLab From b5d2b645555b647c111dff3ad980a6df191a783f Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 4 May 2023 00:31:45 +0000 Subject: [PATCH 0078/1187] binderRpcTest: session leak test,time for shutdown This is hard to reproduce locally, but it is happening on our infrastructure as well as being reported by partners. Bug: 275482320 Bug: 279834069 Test: binderRpcTest Change-Id: I260e117092f7a181a3ad4358b2e5c416937d5295 --- libs/binder/tests/binderRpcTest.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 287e077d40..d01e9d7090 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -687,6 +687,8 @@ TEST_P(BinderRpc, SessionWithIncomingThreadpoolDoesntLeak) { } EXPECT_EQ(nullptr, session.promote()); + + sleep(1); // give time for remote session to shutdown } TEST_P(BinderRpc, SingleDeathRecipient) { -- GitLab From 02359977682c21cd000052c945bce61ec8aa3da7 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Wed, 3 May 2023 23:15:17 +0000 Subject: [PATCH 0079/1187] Refactored binderRecordReplayTest Added generic test class which can be used to expand tests to different AIDL supported types Test: m binderRecordReplayTest && adb sync data && adb shell /data/nativetest64/binderRecordReplayTest/binderRecordReplayTest Bug: 279646634 Change-Id: Ib736cc16acdffb12785fcf4d77b602eb4c2b7e0a --- libs/binder/tests/binderRecordReplayTest.cpp | 111 +++++++++++-------- 1 file changed, 66 insertions(+), 45 deletions(-) diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp index 55148acf14..fac74aa3fb 100644 --- a/libs/binder/tests/binderRecordReplayTest.cpp +++ b/libs/binder/tests/binderRecordReplayTest.cpp @@ -48,51 +48,72 @@ private: int mInt = 0; }; -TEST(BinderClearBuf, RecordReplayRepeatInt) { - // get the remote service - sp binder = defaultServiceManager()->getService(kServerName); - ASSERT_NE(nullptr, binder); - sp iface = interface_cast(binder); - sp bpBinder = binder->remoteBinder(); - ASSERT_NE(nullptr, bpBinder); - - base::unique_fd fd( - open("/data/local/tmp/binderRecordReplayTest.rec", O_RDWR | O_CREAT | O_CLOEXEC, 0666)); - ASSERT_TRUE(fd.ok()); - - // record a transaction - bpBinder->startRecordingBinder(fd); - EXPECT_TRUE(iface->setInt(3).isOk()); - bpBinder->stopRecordingBinder(); - - // test transaction does the thing we expect it to do - int output; - EXPECT_TRUE(iface->getInt(&output).isOk()); - EXPECT_EQ(output, 3); - - // write over the existing state - EXPECT_TRUE(iface->setInt(5).isOk()); - EXPECT_TRUE(iface->getInt(&output).isOk()); - EXPECT_EQ(output, 5); - - // replay transaction - ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET)); - std::optional transaction = RecordedTransaction::fromFile(fd); - ASSERT_NE(transaction, std::nullopt); - - // TODO: move logic to replay RecordedTransaction into RecordedTransaction - Parcel data; - data.setData(transaction->getDataParcel().data(), transaction->getDataParcel().dataSize()); - status_t status = binder->remoteBinder()->transact(transaction->getCode(), data, nullptr, - transaction->getFlags()); - - // make sure recording does the thing we expect it to do - EXPECT_EQ(OK, status); - EXPECT_TRUE(iface->getInt(&output).isOk()); - EXPECT_EQ(output, 3); - - // TODO: we should also make sure we can convert the recording to a fuzzer - // corpus entry, and we will be able to replay it in the same way +class BinderClearBuf : public ::testing::Test { +public: + void SetUp() override { + // get the remote service + mBinder = defaultServiceManager()->getService(kServerName); + ASSERT_NE(nullptr, mBinder); + mInterface = interface_cast(mBinder); + mBpBinder = mBinder->remoteBinder(); + ASSERT_NE(nullptr, mBpBinder); + } + + template + void DoTest(Status (IBinderRecordReplayTest::*set)(T), T recordedValue, + Status (IBinderRecordReplayTest::*get)(T*), T changedValue) { + base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec", + O_RDWR | O_CREAT | O_CLOEXEC, 0666)); + ASSERT_TRUE(fd.ok()); + + // record a transaction + mBpBinder->startRecordingBinder(fd); + auto status = (*mInterface.*set)(recordedValue); + EXPECT_TRUE(status.isOk()); + mBpBinder->stopRecordingBinder(); + + // test transaction does the thing we expect it to do + T output; + status = (*mInterface.*get)(&output); + EXPECT_TRUE(status.isOk()); + EXPECT_EQ(output, recordedValue); + + // write over the existing state + status = (*mInterface.*set)(changedValue); + EXPECT_TRUE(status.isOk()); + + status = (*mInterface.*get)(&output); + EXPECT_TRUE(status.isOk()); + + EXPECT_EQ(output, changedValue); + + // replay transaction + ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET)); + std::optional transaction = RecordedTransaction::fromFile(fd); + ASSERT_NE(transaction, std::nullopt); + + // TODO: move logic to replay RecordedTransaction into RecordedTransaction + Parcel data; + data.setData(transaction->getDataParcel().data(), transaction->getDataParcel().dataSize()); + auto result = mBinder->remoteBinder()->transact(transaction->getCode(), data, nullptr, + transaction->getFlags()); + + // make sure recording does the thing we expect it to do + EXPECT_EQ(OK, result); + + status = (*mInterface.*get)(&output); + EXPECT_TRUE(status.isOk()); + EXPECT_EQ(output, recordedValue); + } + +private: + sp mBinder; + sp mBpBinder; + sp mInterface; +}; + +TEST_F(BinderClearBuf, RecordReplayRepeatInt) { + DoTest(&IBinderRecordReplayTest::setInt, 3, &IBinderRecordReplayTest::getInt, 5); } int main(int argc, char** argv) { -- GitLab From ac656b2d2d1e97394584411951590cabe4f48ccb Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 4 May 2023 00:57:42 +0000 Subject: [PATCH 0080/1187] Adding primitive types to binderRecordReplayTest Adding AIDL supported primitive types to record replay test Test: m binderRecordReplayTest && adb sync data && adb shell /data/nativetest64/binderRecordReplayTest/binderRecordReplayTest Bug: 279646634 Change-Id: If163fe2a8a4e66794cf09e57db98000507811b94 --- .../binder/tests/IBinderRecordReplayTest.aidl | 18 +++++ libs/binder/tests/binderRecordReplayTest.cpp | 66 +++++++++++++++---- 2 files changed, 70 insertions(+), 14 deletions(-) diff --git a/libs/binder/tests/IBinderRecordReplayTest.aidl b/libs/binder/tests/IBinderRecordReplayTest.aidl index 3c8c722da4..2497277177 100644 --- a/libs/binder/tests/IBinderRecordReplayTest.aidl +++ b/libs/binder/tests/IBinderRecordReplayTest.aidl @@ -15,6 +15,24 @@ */ interface IBinderRecordReplayTest { + void setByte(byte input); + byte getByte(); + + void setChar(char input); + char getChar(); + + void setBoolean(boolean input); + boolean getBoolean(); + void setInt(int input); int getInt(); + + void setFloat(float input); + float getFloat(); + + void setLong(long input); + long getLong(); + + void setDouble(double input); + double getDouble(); } diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp index fac74aa3fb..599889caf2 100644 --- a/libs/binder/tests/binderRecordReplayTest.cpp +++ b/libs/binder/tests/binderRecordReplayTest.cpp @@ -33,19 +33,27 @@ using android::binder::debug::RecordedTransaction; const String16 kServerName = String16("binderRecordReplay"); +#define GENERATE_GETTER_SETTER(name, T) \ + Status set##name(T input) { \ + m##name = input; \ + return Status::ok(); \ + } \ + \ + Status get##name(T* output) { \ + *output = m##name; \ + return Status::ok(); \ + } \ + T m##name + class MyRecordReplay : public BnBinderRecordReplayTest { public: - Status setInt(int input) { - mInt = input; - return Status::ok(); - } - Status getInt(int* output) { - *output = mInt; - return Status::ok(); - } - -private: - int mInt = 0; + GENERATE_GETTER_SETTER(Boolean, bool); + GENERATE_GETTER_SETTER(Byte, int8_t); + GENERATE_GETTER_SETTER(Int, int); + GENERATE_GETTER_SETTER(Char, char16_t); + GENERATE_GETTER_SETTER(Long, int64_t); + GENERATE_GETTER_SETTER(Float, float); + GENERATE_GETTER_SETTER(Double, double); }; class BinderClearBuf : public ::testing::Test { @@ -60,8 +68,8 @@ public: } template - void DoTest(Status (IBinderRecordReplayTest::*set)(T), T recordedValue, - Status (IBinderRecordReplayTest::*get)(T*), T changedValue) { + void recordReplay(Status (IBinderRecordReplayTest::*set)(T), T recordedValue, + Status (IBinderRecordReplayTest::*get)(T*), T changedValue) { base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec", O_RDWR | O_CREAT | O_CLOEXEC, 0666)); ASSERT_TRUE(fd.ok()); @@ -112,8 +120,38 @@ private: sp mInterface; }; +TEST_F(BinderClearBuf, RecordReplayRepeatByte) { + recordReplay(&IBinderRecordReplayTest::setByte, int8_t{122}, &IBinderRecordReplayTest::getByte, + int8_t{90}); +} + +TEST_F(BinderClearBuf, RecordReplayRepeatBoolean) { + recordReplay(&IBinderRecordReplayTest::setBoolean, true, &IBinderRecordReplayTest::getBoolean, + false); +} + +TEST_F(BinderClearBuf, RecordReplayRepeatChar) { + recordReplay(&IBinderRecordReplayTest::setChar, char16_t{'G'}, + &IBinderRecordReplayTest::getChar, char16_t{'K'}); +} + TEST_F(BinderClearBuf, RecordReplayRepeatInt) { - DoTest(&IBinderRecordReplayTest::setInt, 3, &IBinderRecordReplayTest::getInt, 5); + recordReplay(&IBinderRecordReplayTest::setInt, 3, &IBinderRecordReplayTest::getInt, 5); +} + +TEST_F(BinderClearBuf, RecordReplayRepeatFloat) { + recordReplay(&IBinderRecordReplayTest::setFloat, 1.1f, &IBinderRecordReplayTest::getFloat, + 22.0f); +} + +TEST_F(BinderClearBuf, RecordReplayRepeatLong) { + recordReplay(&IBinderRecordReplayTest::setLong, int64_t{1LL << 55}, + &IBinderRecordReplayTest::getLong, int64_t{1LL << 12}); +} + +TEST_F(BinderClearBuf, RecordReplayRepeatDouble) { + recordReplay(&IBinderRecordReplayTest::setDouble, 0.00, &IBinderRecordReplayTest::getDouble, + 1.11); } int main(int argc, char** argv) { -- GitLab From 7994df26ce02e1f996718bc5a958acb8f6794d11 Mon Sep 17 00:00:00 2001 From: Liz Kammer Date: Thu, 4 May 2023 12:25:58 +0000 Subject: [PATCH 0081/1187] Remove excess dependency on libGLESv2 libgui_bufferqueue_static is linked statically as part of com.android.media.swcodec, libGLESv2 is neither part of the apex nor providing apex stubs, so the dependency should be avoided. It also appears to be unnecessary. Test: m libgui_bufferqueue_static libgui libgui_mocks Change-Id: Ia9d94d8b294ad1c3d30d4794bf71d4f6da7dc623 --- libs/gui/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 0a63c1564e..a00dff433e 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -242,6 +242,7 @@ cc_library_shared { shared_libs: [ "libbinder", + "libGLESv2", ], export_shared_lib_headers: [ @@ -367,7 +368,6 @@ cc_defaults { "libbase", "libcutils", "libEGL", - "libGLESv2", "libhidlbase", "liblog", "libnativewindow", -- GitLab From a8c236b2220cc7f9b0479a82d76d0962a84e902f Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Tue, 25 Apr 2023 13:56:05 +0000 Subject: [PATCH 0082/1187] InputMapper refactor: TouchInputMapper Add a factory method for TouchInputMapper(s) to be configured on initilisation Test: m checkinput && atest libinput_tests inputflinger_tests Bug: 256009910 Change-Id: I738e2947ff98016e00c290365292ab01b04e7d26 --- services/inputflinger/reader/InputDevice.cpp | 6 +- .../inputflinger/reader/include/InputDevice.h | 10 + .../inputflinger/reader/mapper/InputMapper.h | 28 ++- .../reader/mapper/MultiTouchInputMapper.h | 9 +- .../reader/mapper/SingleTouchInputMapper.h | 9 +- .../reader/mapper/TouchInputMapper.cpp | 3 +- .../reader/mapper/TouchInputMapper.h | 17 +- services/inputflinger/tests/InputMapperTest.h | 11 + .../inputflinger/tests/InputReader_test.cpp | 190 +++++++++--------- .../tests/fuzzers/FuzzContainer.h | 7 +- 10 files changed, 174 insertions(+), 116 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index b86906b2cd..ec8a443eba 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -203,7 +203,7 @@ std::list InputDevice::configure(nsecs_t when, using Change = InputReaderConfiguration::Change; - if (!isIgnored()) { + if (!changes.any() || !isIgnored()) { // Full configuration should happen the first time configure is called // and when the device type is changed. Changing a device type can // affect various other parameters so should result in a @@ -503,9 +503,9 @@ std::vector> InputDevice::createMappers( classes.test(InputDeviceClass::TOUCH_MT) && !isSonyDualShock4Touchpad) { mappers.push_back(std::make_unique(contextPtr, readerConfig)); } else if (classes.test(InputDeviceClass::TOUCH_MT)) { - mappers.push_back(std::make_unique(contextPtr, readerConfig)); + mappers.push_back(createInputMapper(contextPtr, readerConfig)); } else if (classes.test(InputDeviceClass::TOUCH)) { - mappers.push_back(std::make_unique(contextPtr, readerConfig)); + mappers.push_back(createInputMapper(contextPtr, readerConfig)); } // Joystick-like devices. diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 63035466cc..0b8a608891 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -149,6 +149,16 @@ public: return *mapper; } + template + T& constructAndAddMapper(int32_t eventHubId, Args... args) { + // create mapper + auto& devicePair = mDevices[eventHubId]; + auto& deviceContext = devicePair.first; + auto& mappers = devicePair.second; + mappers.push_back(createInputMapper(*deviceContext, args...)); + return static_cast(*mappers.back()); + } + // construct and add a controller to the input device template T& addController(int32_t eventHubId) { diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h index f017317485..06de4c25e3 100644 --- a/services/inputflinger/reader/mapper/InputMapper.h +++ b/services/inputflinger/reader/mapper/InputMapper.h @@ -25,6 +25,20 @@ #include "VibrationElement.h" namespace android { +/** + * This is the factory method that must be used to create any InputMapper + */ +template +std::unique_ptr createInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, Args... args) { + // Using `new` to access non-public constructors. + std::unique_ptr mapper(new T(deviceContext, readerConfig, args...)); + // We need to reset and configure the mapper to ensure it is ready to process event + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + std::list unused = mapper->reset(now); + unused += mapper->reconfigure(now, readerConfig, /*changes=*/{}); + return mapper; +} /* An input mapper transforms raw input events into cooked event data. * A single input device can have multiple associated input mappers in order to interpret @@ -39,8 +53,15 @@ namespace android { */ class InputMapper { public: - explicit InputMapper(InputDeviceContext& deviceContext, - const InputReaderConfiguration& readerConfig); + /** + * Subclasses must either provide a public constructor + * or must be-friend the factory method. + */ + template + friend std::unique_ptr createInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, + Args... args); + virtual ~InputMapper(); inline int32_t getDeviceId() { return mDeviceContext.getId(); } @@ -102,6 +123,9 @@ public: protected: InputDeviceContext& mDeviceContext; + explicit InputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig); + status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo); void bumpGeneration(); diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h index a617420dc9..1d788dffd4 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h @@ -23,8 +23,11 @@ namespace android { class MultiTouchInputMapper : public TouchInputMapper { public: - explicit MultiTouchInputMapper(InputDeviceContext& deviceContext, - const InputReaderConfiguration& readerConfig); + template + friend std::unique_ptr createInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, + Args... args); + ~MultiTouchInputMapper() override; [[nodiscard]] std::list reset(nsecs_t when) override; @@ -36,6 +39,8 @@ protected: bool hasStylus() const override; private: + explicit MultiTouchInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig); // simulate_stylus_with_touch is a debug mode that converts all finger pointers reported by this // mapper's touchscreen into stylus pointers, and adds SOURCE_STYLUS to the input device. // It is used to simulate stylus events for debugging and testing on a device that does not diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h index 93410078d1..7726bfb159 100644 --- a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h +++ b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h @@ -23,8 +23,11 @@ namespace android { class SingleTouchInputMapper : public TouchInputMapper { public: - explicit SingleTouchInputMapper(InputDeviceContext& deviceContext, - const InputReaderConfiguration& readerConfig); + template + friend std::unique_ptr createInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, + Args... args); + ~SingleTouchInputMapper() override; [[nodiscard]] std::list reset(nsecs_t when) override; @@ -37,6 +40,8 @@ protected: private: SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; + explicit SingleTouchInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig); }; } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index c72a263dcd..f4d50b8fa1 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -125,8 +125,7 @@ TouchInputMapper::TouchInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig) : InputMapper(deviceContext, readerConfig), mTouchButtonAccumulator(deviceContext), - mConfig(readerConfig), - mParameters(computeParameters(deviceContext)) {} + mConfig(readerConfig) {} TouchInputMapper::~TouchInputMapper() {} diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 7141924e83..d8b59ca39b 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -146,8 +146,6 @@ struct CookedPointerData { class TouchInputMapper : public InputMapper { public: - explicit TouchInputMapper(InputDeviceContext& deviceContext, - const InputReaderConfiguration& readerConfig); ~TouchInputMapper() override; uint32_t getSources() const override; @@ -358,25 +356,28 @@ protected: nsecs_t mExternalStylusFusionTimeout; bool mExternalStylusDataPending; // A subset of the buttons in mCurrentRawState that came from an external stylus. - int32_t mExternalStylusButtonsApplied; + int32_t mExternalStylusButtonsApplied{0}; // True if we sent a HOVER_ENTER event. - bool mSentHoverEnter; + bool mSentHoverEnter{false}; // Have we assigned pointer IDs for this stream - bool mHavePointerIds; + bool mHavePointerIds{false}; // Is the current stream of direct touch events aborted - bool mCurrentMotionAborted; + bool mCurrentMotionAborted{false}; // The time the primary pointer last went down. - nsecs_t mDownTime; + nsecs_t mDownTime{0}; // The pointer controller, or null if the device is not a pointer. std::shared_ptr mPointerController; std::vector mVirtualKeys; + explicit TouchInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig); + virtual void dumpParameters(std::string& dump); virtual void configureRawPointerAxes(); virtual void dumpRawPointerAxes(std::string& dump); @@ -513,7 +514,7 @@ private: STYLUS, MOUSE, }; - PointerUsage mPointerUsage; + PointerUsage mPointerUsage{PointerUsage::NONE}; struct PointerGesture { enum class Mode { diff --git a/services/inputflinger/tests/InputMapperTest.h b/services/inputflinger/tests/InputMapperTest.h index d9690349fb..2b6655c45e 100644 --- a/services/inputflinger/tests/InputMapperTest.h +++ b/services/inputflinger/tests/InputMapperTest.h @@ -73,6 +73,17 @@ protected: return mapper; } + template + T& constructAndAddMapper(Args... args) { + // ensure a device entry exists for this eventHubId + mDevice->addEmptyEventHubDevice(EVENTHUB_ID); + // configure the empty device + configureDevice(/*changes=*/{}); + + return mDevice->constructAndAddMapper(EVENTHUB_ID, mFakePolicy->getReaderConfiguration(), + args...); + } + void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height, ui::Rotation orientation, const std::string& uniqueId, std::optional physicalPort, diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 568d4e859b..5645f4cc01 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -5082,7 +5082,7 @@ void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper& mapper) { TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) { prepareButtons(); prepareAxes(POSITION); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources()); } @@ -5091,7 +5091,7 @@ TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_Return prepareButtons(); prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources()); } @@ -5102,7 +5102,7 @@ TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) { prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); // Unknown key. ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper.getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); @@ -5130,7 +5130,7 @@ TEST_F(SingleTouchInputMapperTest, GetScanCodeState) { prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); // Unknown key. ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper.getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); @@ -5158,7 +5158,7 @@ TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); uint8_t flags[2] = { 0, 0 }; ASSERT_TRUE( @@ -5173,7 +5173,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNor prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); mReader->getContext()->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -5223,7 +5223,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfB prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); mReader->getContext()->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -5344,7 +5344,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMoves prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); mReader->getContext()->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -5419,7 +5419,7 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture_VirtualDispl prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); mReader->getContext()->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -5515,7 +5515,7 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); mReader->getContext()->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -5605,7 +5605,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_DoesNotRotateMot prepareAxes(POSITION); // InputReader works in the un-rotated coordinate space, so orientation-aware devices do not // need to be rotated. Touchscreens are orientation-aware by default. - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs args; @@ -5630,7 +5630,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_RotatesMotion // Since InputReader works in the un-rotated coordinate space, only devices that are not // orientation-aware are affected by display rotation. addConfigurationProperty("touch.orientationAware", "0"); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs args; @@ -5699,7 +5699,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation0_RotatesMotions) { addConfigurationProperty("touch.orientation", "ORIENTATION_0"); clearViewports(); prepareDisplay(ui::ROTATION_0); - auto& mapper = addMapperAndConfigure(); + auto& mapper = constructAndAddMapper(); NotifyMotionArgs args; // Orientation 0. @@ -5723,7 +5723,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation90_RotatesMotions) { addConfigurationProperty("touch.orientation", "ORIENTATION_90"); clearViewports(); prepareDisplay(ui::ROTATION_0); - auto& mapper = addMapperAndConfigure(); + auto& mapper = constructAndAddMapper(); NotifyMotionArgs args; // Orientation 90. @@ -5747,7 +5747,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation180_RotatesMotions) { addConfigurationProperty("touch.orientation", "ORIENTATION_180"); clearViewports(); prepareDisplay(ui::ROTATION_0); - auto& mapper = addMapperAndConfigure(); + auto& mapper = constructAndAddMapper(); NotifyMotionArgs args; // Orientation 180. @@ -5771,7 +5771,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation270_RotatesMotions) { addConfigurationProperty("touch.orientation", "ORIENTATION_270"); clearViewports(); prepareDisplay(ui::ROTATION_0); - auto& mapper = addMapperAndConfigure(); + auto& mapper = constructAndAddMapper(); NotifyMotionArgs args; // Orientation 270. @@ -5795,7 +5795,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationSpecified_RotatesMotio // orientation-aware are affected by display rotation. addConfigurationProperty("touch.orientationAware", "0"); addConfigurationProperty("touch.orientation", "ORIENTATION_90"); - auto& mapper = addMapperAndConfigure(); + auto& mapper = constructAndAddMapper(); NotifyMotionArgs args; @@ -5862,7 +5862,7 @@ TEST_F(SingleTouchInputMapperTest, Process_IgnoresTouchesOutsidePhysicalFrame) { prepareAxes(POSITION); addConfigurationProperty("touch.orientationAware", "1"); prepareDisplay(ui::ROTATION_0); - auto& mapper = addMapperAndConfigure(); + auto& mapper = constructAndAddMapper(); // Set a physical frame in the display viewport. auto viewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL); @@ -5916,7 +5916,7 @@ TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE | TOOL | DISTANCE | TILT); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; @@ -5961,7 +5961,7 @@ TEST_F(SingleTouchInputMapperTest, Process_XYAxes_AffineCalibration) { prepareLocationCalibration(); prepareButtons(); prepareAxes(POSITION); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); int32_t rawX = 100; int32_t rawY = 200; @@ -5983,7 +5983,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllButtons) { prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; NotifyKeyArgs keyArgs; @@ -6226,7 +6226,7 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -6362,7 +6362,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueI prepareButtons(); prepareAxes(POSITION); mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_FINGER, 0, AKEYCODE_UNKNOWN, 0); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -6433,7 +6433,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenAbsPressureIsPresent_HoversIfItsV prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -6504,7 +6504,7 @@ TEST_F(SingleTouchInputMapperTest, Reset_CancelsOngoingGesture) { prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); // Touch down. processDown(mapper, 100, 200); @@ -6526,7 +6526,7 @@ TEST_F(SingleTouchInputMapperTest, Reset_RecreatesTouchState) { prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); // Set the initial state for the touch pointer. mFakeEventHub->setAbsoluteAxisValue(EVENTHUB_ID, ABS_X, 100); @@ -6554,7 +6554,7 @@ TEST_F(SingleTouchInputMapperTest, prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; // Down. @@ -6582,7 +6582,7 @@ TEST_F(SingleTouchInputMapperTest, prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled()); NotifyMotionArgs motionArgs; @@ -6642,7 +6642,7 @@ TEST_F(SingleTouchInputMapperTest, ButtonIsReleasedOnTouchUp) { prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled()); // Press a stylus button. @@ -6683,7 +6683,7 @@ TEST_F(SingleTouchInputMapperTest, StylusButtonMotionEventsDisabled) { mFakePolicy->setStylusButtonMotionEventsEnabled(false); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled()); // Press a stylus button. @@ -6720,7 +6720,7 @@ TEST_F(SingleTouchInputMapperTest, WhenDeviceTypeIsSetToTouchNavigation_setsCorr prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled()); ASSERT_EQ(AINPUT_SOURCE_TOUCH_NAVIGATION, mapper.getSources()); @@ -6736,7 +6736,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenConfigEnabled_ShouldShowDirectSty mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_PEN, 0, AKEYCODE_UNKNOWN, 0); mFakePolicy->setPointerController(fakePointerController); mFakePolicy->setStylusPointerIconEnabled(true); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); processKey(mapper, BTN_TOOL_PEN, 1); processMove(mapper, 100, 200); @@ -6760,7 +6760,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenConfigDisabled_ShouldNotShowDirec mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_PEN, 0, AKEYCODE_UNKNOWN, 0); mFakePolicy->setPointerController(fakePointerController); mFakePolicy->setStylusPointerIconEnabled(false); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); processKey(mapper, BTN_TOOL_PEN, 1); processMove(mapper, 100, 200); @@ -6778,7 +6778,7 @@ TEST_F(SingleTouchInputMapperTest, WhenDeviceTypeIsChangedToTouchNavigation_upda prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); // Ensure that the device is created as a touchscreen, not touch navigation. ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources()); @@ -6812,7 +6812,7 @@ TEST_F(SingleTouchInputMapperTest, HoverEventsOutsidePhysicalFrameAreIgnored) { mFakePolicy->updateViewport(*viewport); configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); // Hovering inside the physical frame produces events. processKey(mapper, BTN_TOOL_PEN, 1); @@ -6918,7 +6918,7 @@ TEST_F(TouchDisplayProjectionTest, IgnoresTouchesOutsidePhysicalDisplay) { prepareButtons(); prepareAxes(POSITION); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -6953,7 +6953,7 @@ TEST_F(TouchDisplayProjectionTest, EmitsTouchDownAfterEnteringPhysicalDisplay) { prepareButtons(); prepareAxes(POSITION); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -7082,7 +7082,7 @@ TEST_P(TouchscreenPrecisionTestsFixture, OrientationPrecision) { addConfigurationProperty("touch.orientation", ftl::enum_string(touchscreenOrientation).c_str()); prepareDisplay(ui::ROTATION_0); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); // If the touchscreen is installed in a rotated orientation relative to the display (i.e. in // orientations of either 90 or 270) this means the display's natural resolution will be @@ -7134,7 +7134,7 @@ TEST_P(TouchscreenPrecisionTestsFixture, RotationPrecisionWhenOrientationAware) addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(displayRotation); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); const auto& expectedPoints = kMappedCorners.at(displayRotation); @@ -7172,7 +7172,7 @@ TEST_P(TouchscreenPrecisionTestsFixture, RotationPrecisionOrientationAwareInOri2 addConfigurationProperty("touch.deviceType", "touchScreen"); addConfigurationProperty("touch.orientation", "ORIENTATION_270"); - SingleTouchInputMapper& mapper = addMapperAndConfigure(); + SingleTouchInputMapper& mapper = constructAndAddMapper(); // Ori 270, so width and height swapped const Rect physicalFrame{0, 0, DISPLAY_HEIGHT, DISPLAY_WIDTH}; @@ -7208,7 +7208,7 @@ TEST_P(TouchscreenPrecisionTestsFixture, MotionRangesAreOrientedInRotatedDisplay prepareDisplay(displayRotation); __attribute__((unused)) SingleTouchInputMapper& mapper = - addMapperAndConfigure(); + constructAndAddMapper(); const InputDeviceInfo deviceInfo = mDevice->getDeviceInfo(); // MotionRanges use display pixels as their units @@ -7253,7 +7253,7 @@ public: prepareDisplay(ui::ROTATION_0); prepareButtons(); prepareAxes(POSITION); - auto& mapper = addMapperAndConfigure(); + auto& mapper = constructAndAddMapper(); mStylusState.when = ARBITRARY_TIME; mStylusState.pressure = 0.f; @@ -7742,7 +7742,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); mReader->getContext()->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -8026,7 +8026,7 @@ TEST_F(MultiTouchInputMapperTest, AxisResolution_IsPopulated) { mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MIN, RAW_TOOL_MAX, /*flat*/ 0, /*flat*/ 0, /*resolution*/ 15); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // X and Y axes assertAxisResolution(mapper, AMOTION_EVENT_AXIS_X, 10 / X_PRECISION); @@ -8050,7 +8050,7 @@ TEST_F(MultiTouchInputMapperTest, TouchMajorAndMinorAxes_DoNotAppearIfNotSupport // We do not add ABS_MT_TOUCH_MAJOR / MINOR or ABS_MT_WIDTH_MAJOR / MINOR axes - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // Touch major and minor assertAxisNotPresent(mapper, AMOTION_EVENT_AXIS_TOUCH_MAJOR); @@ -8065,7 +8065,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID); prepareVirtualKeys(); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); mReader->getContext()->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -8236,7 +8236,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT); prepareVirtualKeys(); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); mReader->getContext()->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -8401,7 +8401,7 @@ TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR | DISTANCE); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; @@ -8451,7 +8451,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | TOUCH | TOOL | MINOR); addConfigurationProperty("touch.size.calibration", "geometric"); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; @@ -8491,7 +8491,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_SummedLinearCalibrati addConfigurationProperty("touch.size.scale", "10"); addConfigurationProperty("touch.size.bias", "160"); addConfigurationProperty("touch.size.isSummed", "1"); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // These calculations are based on the input device calibration documentation. // Note: We only provide a single common touch/tool value because the device is assumed @@ -8541,7 +8541,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_AreaCalibration) { addConfigurationProperty("touch.size.calibration", "area"); addConfigurationProperty("touch.size.scale", "43"); addConfigurationProperty("touch.size.bias", "3"); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; @@ -8573,7 +8573,7 @@ TEST_F(MultiTouchInputMapperTest, Process_PressureAxis_AmplitudeCalibration) { prepareAxes(POSITION | PRESSURE); addConfigurationProperty("touch.pressure.calibration", "amplitude"); addConfigurationProperty("touch.pressure.scale", "0.01"); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); InputDeviceInfo info; mapper.populateDeviceInfo(info); @@ -8605,7 +8605,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllButtons) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; NotifyKeyArgs keyArgs; @@ -8848,7 +8848,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleMappedStylusButtons) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); mFakeEventHub->addKey(EVENTHUB_ID, BTN_A, 0, AKEYCODE_STYLUS_BUTTON_PRIMARY, 0); mFakeEventHub->addKey(EVENTHUB_ID, 0, 0xabcd, AKEYCODE_STYLUS_BUTTON_SECONDARY, 0); @@ -8905,7 +8905,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -9056,7 +9056,7 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIs prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT); mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -9126,7 +9126,7 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTPressureIsPresent_HoversIfIts addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -9207,7 +9207,7 @@ TEST_F(MultiTouchInputMapperTest, Configure_AssignsDisplayPort) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareAxes(POSITION); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi1); mFakePolicy->addInputPortAssociation(usb2, hdmi2); @@ -9237,7 +9237,7 @@ TEST_F(MultiTouchInputMapperTest, Configure_AssignsDisplayPort) { TEST_F(MultiTouchInputMapperTest, Configure_AssignsDisplayUniqueId) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareAxes(POSITION); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, VIRTUAL_DISPLAY_UNIQUE_ID); @@ -9266,7 +9266,7 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) { prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // Check source is mouse that would obtain the PointerController. ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources()); @@ -9286,7 +9286,7 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) { TEST_F(MultiTouchInputMapperTest, Process_SendsReadTime) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareAxes(POSITION); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); prepareDisplay(ui::ROTATION_0); process(mapper, 10, /*readTime=*/11, EV_ABS, ABS_MT_TRACKING_ID, 1); @@ -9317,7 +9317,7 @@ TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreDropped) { /*isActive=*/false, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO); prepareAxes(POSITION); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; processPosition(mapper, 100, 100); @@ -9337,7 +9337,7 @@ TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreProcessed) { /*isActive=*/false, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO); prepareAxes(POSITION); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; processPosition(mapper, 100, 100); @@ -9359,7 +9359,7 @@ TEST_F(MultiTouchInputMapperTest, Process_DeactivateViewport_AbortTouches) { configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO); prepareAxes(POSITION); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // Finger down int32_t x = 100, y = 100; @@ -9402,7 +9402,7 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) { // Setup the first touch screen device. prepareAxes(POSITION | ID | SLOT); addConfigurationProperty("touch.deviceType", "touchScreen"); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // Create the second touch screen device, and enable multi fingers. const std::string USB2 = "USB2"; @@ -9426,9 +9426,9 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) { String8("touchScreen")); // Setup the second touch screen device. - MultiTouchInputMapper& mapper2 = - device2->addMapper(SECOND_EVENTHUB_ID, - mFakePolicy->getReaderConfiguration()); + device2->addEmptyEventHubDevice(SECOND_EVENTHUB_ID); + MultiTouchInputMapper& mapper2 = device2->constructAndAddMapper< + MultiTouchInputMapper>(SECOND_EVENTHUB_ID, mFakePolicy->getReaderConfiguration()); std::list unused = device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), /*changes=*/{}); @@ -9493,7 +9493,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) { prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; // Unrotated video frame @@ -9517,7 +9517,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_ReceivedByListener) { TEST_F(MultiTouchInputMapperTest, VideoFrames_AreNotRotated) { prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // Unrotated video frame TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2}); NotifyMotionArgs motionArgs; @@ -9542,7 +9542,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_WhenNotOrientationAware_AreRotated // Since InputReader works in the un-rotated coordinate space, only devices that are not // orientation-aware are affected by display rotation. addConfigurationProperty("touch.orientationAware", "0"); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // Unrotated video frame TouchVideoFrame frame(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2}); NotifyMotionArgs motionArgs; @@ -9573,7 +9573,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_WhenNotOrientationAware_AreRotated TEST_F(MultiTouchInputMapperTest, VideoFrames_MultipleFramesAreNotRotated) { prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // Unrotated video frames. There's no rule that they must all have the same dimensions, // so mix these. TouchVideoFrame frame1(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2}); @@ -9596,7 +9596,7 @@ TEST_F(MultiTouchInputMapperTest, VideoFrames_WhenNotOrientationAware_MultipleFr // Since InputReader works in the un-rotated coordinate space, only devices that are not // orientation-aware are affected by display rotation. addConfigurationProperty("touch.orientationAware", "0"); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // Unrotated video frames. There's no rule that they must all have the same dimensions, // so mix these. TouchVideoFrame frame1(3, 2, {1, 2, 3, 4, 5, 6}, {1, 2}); @@ -9633,7 +9633,7 @@ TEST_F(MultiTouchInputMapperTest, Configure_EnabledForAssociatedDisplay) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareAxes(POSITION); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); ASSERT_EQ(mDevice->isEnabled(), false); @@ -9654,7 +9654,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleSingleTouch) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -9699,7 +9699,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_SinglePointer addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -9747,7 +9747,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_TwoPointers) addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -9822,7 +9822,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_ShouldCancelW addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -9920,7 +9920,7 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandlePalmToolType_KeepFirstPoin addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -9992,7 +9992,7 @@ TEST_F(MultiTouchInputMapperTest, Process_MultiTouch_WithInvalidTrackingId) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -10049,7 +10049,7 @@ TEST_F(MultiTouchInputMapperTest, Reset_PreservesLastTouchState) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // First finger down. processId(mapper, FIRST_TRACKING_ID); @@ -10090,7 +10090,7 @@ TEST_F(MultiTouchInputMapperTest, Reset_PreservesLastTouchState_NoPointersDown) addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // First finger touches down and releases. processId(mapper, FIRST_TRACKING_ID); @@ -10118,7 +10118,7 @@ TEST_F(MultiTouchInputMapperTest, StylusSourceIsAddedDynamicallyFromToolType) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE | TOOL_TYPE); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled()); // Even if the device supports reporting the ABS_MT_TOOL_TYPE axis, which could give it the @@ -10173,7 +10173,7 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenConfigEnabled_ShouldShowDirectStyl std::make_shared(); mFakePolicy->setPointerController(fakePointerController); mFakePolicy->setStylusPointerIconEnabled(true); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); processId(mapper, FIRST_TRACKING_ID); processPressure(mapper, RAW_PRESSURE_MIN); @@ -10200,7 +10200,7 @@ TEST_F(MultiTouchInputMapperTest, Process_WhenConfigDisabled_ShouldNotShowDirect std::make_shared(); mFakePolicy->setPointerController(fakePointerController); mFakePolicy->setStylusPointerIconEnabled(false); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); processId(mapper, FIRST_TRACKING_ID); processPressure(mapper, RAW_PRESSURE_MIN); @@ -10228,7 +10228,7 @@ TEST_F(MultiTouchInputMapperTest_ExternalDevice, Viewports_Fallback) { prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper.getSources()); @@ -10263,7 +10263,7 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchpadCapture) { mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); mFakePolicy->setPointerCapture(true); mFakePolicy->setPointerController(fakePointerController); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // captured touchpad should be a touchpad source NotifyDeviceResetArgs resetArgs; @@ -10411,7 +10411,7 @@ TEST_F(MultiTouchInputMapperTest, Process_UnCapturedTouchpadPointer) { mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0); mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); mFakePolicy->setPointerController(fakePointerController); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // run uncaptured pointer tests - pushes out generic events // FINGER 0 DOWN processId(mapper, 3); @@ -10472,7 +10472,7 @@ TEST_F(MultiTouchInputMapperTest, WhenCapturedAndNotCaptured_GetSources) { mFakeEventHub->addKey(EVENTHUB_ID, BTN_LEFT, 0, AKEYCODE_UNKNOWN, 0); mFakePolicy->setPointerController(fakePointerController); mFakePolicy->setPointerCapture(false); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); // uncaptured touchpad should be a pointer device ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources()); @@ -10496,7 +10496,7 @@ TEST_F(BluetoothMultiTouchInputMapperTest, TimestampSmoothening) { addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(ui::ROTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); nsecs_t kernelEventTime = ARBITRARY_TIME; nsecs_t expectedEventTime = ARBITRARY_TIME; @@ -10583,7 +10583,7 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthSwipe) { // which is greater than fraction of the diagnal length of the touchpad (349). // Thus, MaxSwipWidth is 750. preparePointerMode(/*xResolution=*/25, /*yResolution=*/25); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; // Two fingers down at once. @@ -10643,7 +10643,7 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthLowResolutionSwipe) // which is greater than fraction of the diagnal length of the touchpad (349). // Thus, MaxSwipWidth is the fraction of the diagnal length, 349. preparePointerMode(/*xResolution=*/5, /*yResolution=*/5); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; // Two fingers down at once. @@ -10699,7 +10699,7 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthLowResolutionSwipe) */ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthFreeform) { preparePointerMode(/*xResolution=*/25, /*yResolution=*/25); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; @@ -10794,7 +10794,7 @@ TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthFreeform) { TEST_F(MultiTouchPointerModeTest, TwoFingerSwipeOffsets) { preparePointerMode(/*xResolution=*/25, /*yResolution=*/25); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs motionArgs; // Place two fingers down. @@ -10841,7 +10841,7 @@ TEST_F(MultiTouchPointerModeTest, TwoFingerSwipeOffsets) { TEST_F(MultiTouchPointerModeTest, WhenViewportActiveStatusChanged_PointerGestureIsReset) { preparePointerMode(/*xResolution=*/25, /*yResolution=*/25); mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_PEN, 0, AKEYCODE_UNKNOWN, 0); - MultiTouchInputMapper& mapper = addMapperAndConfigure(); + MultiTouchInputMapper& mapper = constructAndAddMapper(); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled()); // Start a stylus gesture. diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h index 84ac0fd262..b9929289f1 100644 --- a/services/inputflinger/tests/fuzzers/FuzzContainer.h +++ b/services/inputflinger/tests/fuzzers/FuzzContainer.h @@ -75,9 +75,12 @@ public: template T& getMapper(Args... args) { - T& mapper = mFuzzDevice->addMapper(mFdp->ConsumeIntegral(), args...); + int32_t eventhubId = mFdp->ConsumeIntegral(); + // ensure a device entry exists for this eventHubId + mFuzzDevice->addEmptyEventHubDevice(eventhubId); configureDevice(); - return mapper; + + return mFuzzDevice->template constructAndAddMapper(eventhubId, args...); } }; -- GitLab From e036ad77ed50cbd0b908cb7304ce5e9539f06d8f Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Thu, 27 Apr 2023 12:48:15 +0000 Subject: [PATCH 0083/1187] InputMapper refactor: CursorInputMapper Add a factory method for CursorInputMapper(s) to be configured on initilisation Test: m checkinput && atest libinput_tests inputflinger_tests Bug: 256009910 Change-Id: Id789ff890b7e147de16c07a9dcd095a21eba43f9 --- services/inputflinger/reader/InputDevice.cpp | 2 +- .../reader/mapper/CursorInputMapper.cpp | 52 ++++++++----------- .../reader/mapper/CursorInputMapper.h | 12 +++-- .../inputflinger/tests/InputReader_test.cpp | 42 +++++++-------- 4 files changed, 52 insertions(+), 56 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index ec8a443eba..b0c44880c5 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -488,7 +488,7 @@ std::vector> InputDevice::createMappers( // Cursor-like devices. if (classes.test(InputDeviceClass::CURSOR)) { - mappers.push_back(std::make_unique(contextPtr, readerConfig)); + mappers.push_back(createInputMapper(contextPtr, readerConfig)); } // Touchscreens and touchpad devices. diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 8ef5ff6358..c684ed40b6 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -71,9 +71,7 @@ void CursorMotionAccumulator::finishSync() { CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig) : InputMapper(deviceContext, readerConfig), - mLastEventTime(std::numeric_limits::min()) { - configureWithZeroChanges(readerConfig); -} + mLastEventTime(std::numeric_limits::min()) {} CursorInputMapper::~CursorInputMapper() { if (mPointerController != nullptr) { @@ -142,46 +140,51 @@ std::list CursorInputMapper::reconfigure(nsecs_t when, ConfigurationChanges changes) { std::list out = InputMapper::reconfigure(when, readerConfig, changes); - if (!changes.any()) { - configureWithZeroChanges(readerConfig); - return out; + if (!changes.any()) { // first time only + configureBasicParams(); } - const bool configurePointerCapture = mParameters.mode != Parameters::Mode::NAVIGATION && - changes.test(InputReaderConfiguration::Change::POINTER_CAPTURE); + const bool configurePointerCapture = !changes.any() || + (mParameters.mode != Parameters::Mode::NAVIGATION && + changes.test(InputReaderConfiguration::Change::POINTER_CAPTURE)); if (configurePointerCapture) { configureOnPointerCapture(readerConfig); out.push_back(NotifyDeviceResetArgs(getContext()->getNextId(), when, getDeviceId())); } - if (changes.test(InputReaderConfiguration::Change::POINTER_SPEED) || configurePointerCapture) { + if (!changes.any() || changes.test(InputReaderConfiguration::Change::POINTER_SPEED) || + configurePointerCapture) { configureOnChangePointerSpeed(readerConfig); } - if (changes.test(InputReaderConfiguration::Change::DISPLAY_INFO) || configurePointerCapture) { + if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO) || + configurePointerCapture) { configureOnChangeDisplayInfo(readerConfig); } return out; } -void CursorInputMapper::configureParameters() { - mParameters.mode = Parameters::Mode::POINTER; - const PropertyMap& config = getDeviceContext().getConfiguration(); +CursorInputMapper::Parameters CursorInputMapper::computeParameters( + const InputDeviceContext& deviceContext) { + Parameters parameters; + parameters.mode = Parameters::Mode::POINTER; + const PropertyMap& config = deviceContext.getConfiguration(); std::optional cursorModeString = config.getString("cursor.mode"); if (cursorModeString.has_value()) { if (*cursorModeString == "navigation") { - mParameters.mode = Parameters::Mode::NAVIGATION; + parameters.mode = Parameters::Mode::NAVIGATION; } else if (*cursorModeString != "pointer" && *cursorModeString != "default") { ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString->c_str()); } } - mParameters.orientationAware = config.getBool("cursor.orientationAware").value_or(false); + parameters.orientationAware = config.getBool("cursor.orientationAware").value_or(false); - mParameters.hasAssociatedDisplay = false; - if (mParameters.mode == Parameters::Mode::POINTER || mParameters.orientationAware) { - mParameters.hasAssociatedDisplay = true; + parameters.hasAssociatedDisplay = false; + if (parameters.mode == Parameters::Mode::POINTER || parameters.orientationAware) { + parameters.hasAssociatedDisplay = true; } + return parameters; } void CursorInputMapper::dumpParameters(std::string& dump) { @@ -424,22 +427,11 @@ std::optional CursorInputMapper::getAssociatedDisplayId() { return mDisplayId; } -void CursorInputMapper::configureWithZeroChanges(const InputReaderConfiguration& readerConfig) { - // Configuration with zero changes - configureBasicParams(); - if (mParameters.mode != Parameters::Mode::NAVIGATION && - readerConfig.pointerCaptureRequest.enable) { - configureOnPointerCapture(readerConfig); - } - configureOnChangePointerSpeed(readerConfig); - configureOnChangeDisplayInfo(readerConfig); -} - void CursorInputMapper::configureBasicParams() { mCursorScrollAccumulator.configure(getDeviceContext()); // Configure basic parameters. - configureParameters(); + mParameters = computeParameters(getDeviceContext()); // Configure device mode. switch (mParameters.mode) { diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h index caf2e5a4c4..b879bfdd08 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.h +++ b/services/inputflinger/reader/mapper/CursorInputMapper.h @@ -53,8 +53,10 @@ private: class CursorInputMapper : public InputMapper { public: - explicit CursorInputMapper(InputDeviceContext& deviceContext, - const InputReaderConfiguration& readerConfig); + template + friend std::unique_ptr createInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, + Args... args); virtual ~CursorInputMapper(); virtual uint32_t getSources() const override; @@ -125,15 +127,17 @@ private: nsecs_t mDownTime; nsecs_t mLastEventTime; - void configureParameters(); + explicit CursorInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig); void dumpParameters(std::string& dump); - void configureWithZeroChanges(const InputReaderConfiguration& readerConfig); void configureBasicParams(); void configureOnPointerCapture(const InputReaderConfiguration& config); void configureOnChangePointerSpeed(const InputReaderConfiguration& config); void configureOnChangeDisplayInfo(const InputReaderConfiguration& config); [[nodiscard]] std::list sync(nsecs_t when, nsecs_t readTime); + + static Parameters computeParameters(const InputDeviceContext& deviceContext); }; } // namespace android diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 5645f4cc01..c34dcac3aa 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -3875,21 +3875,21 @@ void CursorInputMapperTest::testMotionRotation(CursorInputMapper& mapper, int32_ TEST_F(CursorInputMapperTest, WhenModeIsPointer_GetSources_ReturnsMouse) { addConfigurationProperty("cursor.mode", "pointer"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources()); } TEST_F(CursorInputMapperTest, WhenModeIsNavigation_GetSources_ReturnsTrackball) { addConfigurationProperty("cursor.mode", "navigation"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper.getSources()); } TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeFromPointerController) { addConfigurationProperty("cursor.mode", "pointer"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); InputDeviceInfo info; mapper.populateDeviceInfo(info); @@ -3919,7 +3919,7 @@ TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeF TEST_F(CursorInputMapperTest, WhenModeIsNavigation_PopulateDeviceInfo_ReturnsScaledRange) { addConfigurationProperty("cursor.mode", "navigation"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); InputDeviceInfo info; mapper.populateDeviceInfo(info); @@ -3937,7 +3937,7 @@ TEST_F(CursorInputMapperTest, WhenModeIsNavigation_PopulateDeviceInfo_ReturnsSca TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) { addConfigurationProperty("cursor.mode", "navigation"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); mReader->getContext()->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); @@ -4025,7 +4025,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaStat TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { addConfigurationProperty("cursor.mode", "navigation"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs args; @@ -4049,7 +4049,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { addConfigurationProperty("cursor.mode", "navigation"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs args; @@ -4078,7 +4078,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { addConfigurationProperty("cursor.mode", "navigation"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); NotifyMotionArgs args; @@ -4127,7 +4127,7 @@ TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldNotRotateMotion // InputReader works in the un-rotated coordinate space, so orientation-aware devices do not // need to be rotated. addConfigurationProperty("cursor.orientationAware", "1"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); prepareDisplay(ui::ROTATION_90); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); @@ -4145,7 +4145,7 @@ TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotion addConfigurationProperty("cursor.mode", "navigation"); // Since InputReader works in the un-rotated coordinate space, only devices that are not // orientation-aware are affected by display rotation. - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); clearViewports(); prepareDisplay(ui::ROTATION_0); @@ -4194,7 +4194,7 @@ TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldRotateMotion TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { addConfigurationProperty("cursor.mode", "pointer"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1); mFakePointerController->setPosition(100, 200); @@ -4448,7 +4448,7 @@ TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { TEST_F(CursorInputMapperTest, Process_WhenModeIsPointer_ShouldMoveThePointerAround) { addConfigurationProperty("cursor.mode", "pointer"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1); mFakePointerController->setPosition(100, 200); @@ -4469,7 +4469,7 @@ TEST_F(CursorInputMapperTest, Process_WhenModeIsPointer_ShouldMoveThePointerArou TEST_F(CursorInputMapperTest, Process_PointerCapture) { addConfigurationProperty("cursor.mode", "pointer"); mFakePolicy->setPointerCapture(true); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); NotifyDeviceResetArgs resetArgs; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); @@ -4561,7 +4561,7 @@ TEST_F(CursorInputMapperTest, PointerCaptureDisablesVelocityProcessing) { const VelocityControlParameters testParams(/*scale=*/5.f, /*low threshold=*/0.f, /*high threshold=*/100.f, /*acceleration=*/10.f); mFakePolicy->setVelocityControlParams(testParams); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); NotifyDeviceResetArgs resetArgs; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); @@ -4602,7 +4602,7 @@ TEST_F(CursorInputMapperTest, PointerCaptureDisablesVelocityProcessing) { TEST_F(CursorInputMapperTest, PointerCaptureDisablesOrientationChanges) { addConfigurationProperty("cursor.mode", "pointer"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); NotifyDeviceResetArgs resetArgs; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); @@ -4643,7 +4643,7 @@ TEST_F(CursorInputMapperTest, PointerCaptureDisablesOrientationChanges) { } TEST_F(CursorInputMapperTest, ConfigureDisplayId_NoAssociatedViewport) { - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); // Set up the default display. prepareDisplay(ui::ROTATION_90); @@ -4669,7 +4669,7 @@ TEST_F(CursorInputMapperTest, ConfigureDisplayId_NoAssociatedViewport) { } TEST_F(CursorInputMapperTest, ConfigureDisplayId_WithAssociatedViewport) { - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); // Set up the default display. prepareDisplay(ui::ROTATION_90); @@ -4695,7 +4695,7 @@ TEST_F(CursorInputMapperTest, ConfigureDisplayId_WithAssociatedViewport) { } TEST_F(CursorInputMapperTest, ConfigureDisplayId_IgnoresEventsForMismatchedPointerDisplay) { - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); // Set up the default display as the display on which the pointer should be shown. prepareDisplay(ui::ROTATION_90); @@ -4728,7 +4728,7 @@ protected: TEST_F(BluetoothCursorInputMapperTest, TimestampSmoothening) { addConfigurationProperty("cursor.mode", "pointer"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); nsecs_t kernelEventTime = ARBITRARY_TIME; nsecs_t expectedEventTime = ARBITRARY_TIME; @@ -4755,7 +4755,7 @@ TEST_F(BluetoothCursorInputMapperTest, TimestampSmoothening) { TEST_F(BluetoothCursorInputMapperTest, TimestampSmootheningIsCapped) { addConfigurationProperty("cursor.mode", "pointer"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); nsecs_t expectedEventTime = ARBITRARY_TIME; process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 1); @@ -4792,7 +4792,7 @@ TEST_F(BluetoothCursorInputMapperTest, TimestampSmootheningIsCapped) { TEST_F(BluetoothCursorInputMapperTest, TimestampSmootheningNotUsed) { addConfigurationProperty("cursor.mode", "pointer"); - CursorInputMapper& mapper = addMapperAndConfigure(); + CursorInputMapper& mapper = constructAndAddMapper(); nsecs_t kernelEventTime = ARBITRARY_TIME; nsecs_t expectedEventTime = ARBITRARY_TIME; -- GitLab From c035337222b73ef77077c06b3a769e6b6e6aa8c1 Mon Sep 17 00:00:00 2001 From: Liz Kammer Date: Wed, 3 May 2023 17:59:47 -0400 Subject: [PATCH 0084/1187] Remove excess dependency on libGLESv2 libgui_bufferqueue_static is linked statically as part of com.android.media.swcodec, libGLESv2 is neither part of the apex nor providing apex stubs, so the dependency should be avoided. It also appears to be unnecessary. Test: m libgui_bufferqueue_static libgui libgui_mocks Merged-In: Ia9d94d8b294ad1c3d30d4794bf71d4f6da7dc623 Change-Id: Ia9d94d8b294ad1c3d30d4794bf71d4f6da7dc623 --- libs/gui/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 2ac11746c3..0fe6f24842 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -214,6 +214,7 @@ cc_library_shared { shared_libs: [ "libbinder", + "libGLESv2", ], export_shared_lib_headers: [ @@ -326,7 +327,6 @@ cc_defaults { "libbase", "libcutils", "libEGL", - "libGLESv2", "libhidlbase", "liblog", "libnativewindow", -- GitLab From 9b255825883fb4a7de3f40d624fd2b2546ee6cdf Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Fri, 5 May 2023 17:01:05 +0000 Subject: [PATCH 0085/1187] Updating triage assignee for rust fuzzers Test: m example_fuzzer_rs parcel_fuzzer_rs Bug: N/A Change-Id: I1b4dd69db1ff5c71a08d2ef045da183edd95baed --- libs/binder/rust/tests/parcel_fuzzer/Android.bp | 1 + .../parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp | 1 + 2 files changed, 2 insertions(+) diff --git a/libs/binder/rust/tests/parcel_fuzzer/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/Android.bp index df8a2afb03..ac968237a0 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/Android.bp +++ b/libs/binder/rust/tests/parcel_fuzzer/Android.bp @@ -21,6 +21,7 @@ rust_fuzz { "waghpawan@google.com", "smoreland@google.com", ], + triage_assignee: "waghpawan@google.com", // hotlist "AIDL fuzzers bugs" on buganizer hotlists: ["4637097"], }, diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp index 5cb406afc2..2537ce0bcb 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp +++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp @@ -29,6 +29,7 @@ rust_fuzz { "waghpawan@google.com", "smoreland@google.com", ], + triage_assignee: "waghpawan@google.com", // hotlist "AIDL fuzzers bugs" on buganizer hotlists: ["4637097"], }, -- GitLab From 34aac2be4a653e86f29743b6caa9bf6347a191e8 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 5 May 2023 23:05:07 +0000 Subject: [PATCH 0086/1187] example_service_fuzzer: explicit deps Not detected automatically. Bug: 280164233 Test: check data/fuzz/x86_64/lib Change-Id: I8892a0367712da4c0ddedb83902dcc10a3a113d1 --- .../parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp index 5cb406afc2..f37cfca8a1 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp +++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp @@ -19,6 +19,11 @@ rust_fuzz { srcs: [ "service_fuzzer.rs", ], + shared_libs: [ + "libbinder", + "libbinder_ndk", + "libutils", + ], rustlibs: [ "libbinder_rs", "libbinder_random_parcel_rs", -- GitLab From 475f66c1ab0cba95e2b5fab557f9da6bbb27078b Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Fri, 5 May 2023 21:46:07 +0000 Subject: [PATCH 0087/1187] Adding cc_defaults to disable leaks Bug: N/A Test: N/A Change-Id: Ibb02b1573c9ddfca4bc23a861fcd5d1818e8088a --- libs/binder/tests/Android.bp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 0280c96689..4929b34714 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -792,3 +792,15 @@ cc_defaults { hotlists: ["4637097"], }, } + +cc_defaults { + name: "fuzzer_disable_leaks", + fuzz_config: { + asan_options: [ + "detect_leaks=0", + ], + hwasan_options: [ + "detect_leaks=0", + ], + }, +} -- GitLab From 530c25b45c997cd91402aa3e9b55c2682b851d8c Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Fri, 5 May 2023 22:29:25 +0000 Subject: [PATCH 0088/1187] Disable leaks in libsenorserviceaidl_fuzzer Test: m libsensorserviceaidl_fuzzer Bug: 280478515 Change-Id: If973fcf0b4c03e399a8f79f6ca80bafed61c6b2b --- services/sensorservice/aidl/fuzzer/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/services/sensorservice/aidl/fuzzer/Android.bp b/services/sensorservice/aidl/fuzzer/Android.bp index 0d6e476e70..cb586c6b69 100644 --- a/services/sensorservice/aidl/fuzzer/Android.bp +++ b/services/sensorservice/aidl/fuzzer/Android.bp @@ -11,6 +11,7 @@ cc_fuzz { name: "libsensorserviceaidl_fuzzer", defaults: [ "service_fuzzer_defaults", + "fuzzer_disable_leaks", ], host_supported: true, static_libs: [ -- GitLab From d3cf3c7610a427713434998a36fd7466c21f1491 Mon Sep 17 00:00:00 2001 From: Spandan Das Date: Sat, 6 May 2023 00:01:25 +0000 Subject: [PATCH 0089/1187] Make apex_available to com.android.neuralnetworks explicit in Android.bp These libraries are available to com.android.neuralnetworks via the baseline apexAvailable map in build/soong/apex/apex.go. This CL makes this explicit in Android.bp Test: m nothing #passes Bug: 281077552 Change-Id: I7554921abdbfe106915129ff35718abafee002ae --- cmds/lshal/libprocpartition/Android.bp | 4 ++++ libs/arect/Android.bp | 1 + 2 files changed, 5 insertions(+) diff --git a/cmds/lshal/libprocpartition/Android.bp b/cmds/lshal/libprocpartition/Android.bp index af85666276..d0e4b74543 100644 --- a/cmds/lshal/libprocpartition/Android.bp +++ b/cmds/lshal/libprocpartition/Android.bp @@ -37,4 +37,8 @@ cc_library_static { "include", ], min_sdk_version: "30", + apex_available: [ + "//apex_available:platform", + "com.android.neuralnetworks", + ], } diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp index 5e539f24e1..1a9766d72e 100644 --- a/libs/arect/Android.bp +++ b/libs/arect/Android.bp @@ -72,6 +72,7 @@ cc_library_static { "//apex_available:platform", "com.android.media", "com.android.media.swcodec", + "com.android.neuralnetworks", ], } -- GitLab From c8338635e7dbc7a90c6ba434ef68c96967ffb12f Mon Sep 17 00:00:00 2001 From: Andrei Homescu Date: Fri, 5 May 2023 03:14:41 +0000 Subject: [PATCH 0090/1187] libbinder_rs: Use NonNull inside Status Replacing the raw pointer inside Status with a NonNull will allow us to wrap Status in an Option transparently and transmute between the two types. Bug: 278648274 Test: presubmit Change-Id: I61aea43fdd238d62dfffa6300bc8e0eac8e17a21 --- libs/binder/rust/src/error.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs index f6b09ed8fe..ba260624bc 100644 --- a/libs/binder/rust/src/error.rs +++ b/libs/binder/rust/src/error.rs @@ -20,6 +20,7 @@ use crate::sys; use std::error; use std::ffi::{CStr, CString}; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; +use std::ptr; use std::result; pub use sys::binder_status_t as status_t; @@ -92,7 +93,7 @@ fn parse_exception_code(code: i32) -> ExceptionCode { /// track of and chain binder errors along with service specific errors. /// /// Used in AIDL transactions to represent failed transactions. -pub struct Status(*mut sys::AStatus); +pub struct Status(ptr::NonNull); // Safety: The `AStatus` that the `Status` points to must have an entirely thread-safe API for the // duration of the `Status` object's lifetime. We ensure this by not allowing mutation of a `Status` @@ -119,7 +120,7 @@ impl Status { // Rust takes ownership of the returned pointer. sys::AStatus_newOk() }; - Self(ptr) + Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } /// Create a status object from a service specific error @@ -147,7 +148,7 @@ impl Status { sys::AStatus_fromServiceSpecificError(err) } }; - Self(ptr) + Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } /// Creates a status object from a service specific error. @@ -161,7 +162,7 @@ impl Status { let ptr = unsafe { sys::AStatus_fromExceptionCodeWithMessage(exception as i32, message.as_ptr()) }; - Self(ptr) + Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } else { exception.into() } @@ -181,7 +182,7 @@ impl Status { /// /// This constructor is safe iff `ptr` is a valid pointer to an `AStatus`. pub(crate) unsafe fn from_ptr(ptr: *mut sys::AStatus) -> Self { - Self(ptr) + Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } /// Returns `true` if this status represents a successful transaction. @@ -326,7 +327,7 @@ impl From for Status { // UNKNOWN_ERROR. sys::AStatus_fromStatus(status) }; - Self(ptr) + Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } } @@ -338,7 +339,7 @@ impl From for Status { // Unknown values will be coerced into EX_TRANSACTION_FAILED. sys::AStatus_fromExceptionCode(code as i32) }; - Self(ptr) + Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } } @@ -367,7 +368,7 @@ impl Drop for Status { // pointee, so we need to delete it here. We know that the pointer // will be valid here since `Status` always contains a valid pointer // while it is alive. - sys::AStatus_delete(self.0); + sys::AStatus_delete(self.0.as_mut()); } } } @@ -381,11 +382,15 @@ impl Drop for Status { /// `Status` object is still alive. unsafe impl AsNative for Status { fn as_native(&self) -> *const sys::AStatus { - self.0 + self.0.as_ptr() } fn as_native_mut(&mut self) -> *mut sys::AStatus { - self.0 + unsafe { + // Safety: The pointer will be valid here since `Status` always + // contains a valid and initialized pointer while it is alive. + self.0.as_mut() + } } } -- GitLab From 2b802f732009b09a27a57f8834124a93f0f8d81b Mon Sep 17 00:00:00 2001 From: Andrei Homescu Date: Fri, 5 May 2023 03:21:43 +0000 Subject: [PATCH 0091/1187] libbinder_rs: Remove Vec> from parcelable.rs Vec> leaks elements if it was partially initialized and we got an error. Replace it with a safer Vec> which uses either Default or Option::None to initialize elements. Bug: 278648274 Test: atest atest_integration_test Change-Id: I2ec97a17b215cb875a48e894eb04832e8a967fca --- libs/binder/rust/src/binder.rs | 4 + .../binder/rust/src/parcel/file_descriptor.rs | 8 + libs/binder/rust/src/parcel/parcelable.rs | 183 +++++++++++++++--- .../rust/src/parcel/parcelable_holder.rs | 8 + libs/binder/rust/src/proxy.rs | 8 + 5 files changed, 186 insertions(+), 25 deletions(-) diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index d0e35de3f7..b90b40bac8 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -1122,6 +1122,10 @@ macro_rules! declare_binder_enum { } impl $crate::binder_impl::Deserialize for $enum { + type UninitType = Self; + fn uninit() -> Self::UninitType { Self::UninitType::default() } + fn from_init(value: Self) -> Self::UninitType { value } + fn deserialize(parcel: &$crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result { parcel.read().map(Self) } diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs index de6d64934a..7fe37f3b68 100644 --- a/libs/binder/rust/src/parcel/file_descriptor.rs +++ b/libs/binder/rust/src/parcel/file_descriptor.rs @@ -132,6 +132,14 @@ impl DeserializeOption for ParcelFileDescriptor { } impl Deserialize for ParcelFileDescriptor { + type UninitType = Option; + fn uninit() -> Self::UninitType { + Self::UninitType::default() + } + fn from_init(value: Self) -> Self::UninitType { + Some(value) + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { Deserialize::deserialize(parcel).transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL)) } diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs index 4b658fc74d..5d8c11cf94 100644 --- a/libs/binder/rust/src/parcel/parcelable.rs +++ b/libs/binder/rust/src/parcel/parcelable.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -use crate::binder::{AsNative, FromIBinder, Stability, Strong}; +use crate::binder::{AsNative, FromIBinder, Interface, Stability, Strong}; use crate::error::{status_result, status_t, Result, Status, StatusCode}; use crate::parcel::BorrowedParcel; use crate::proxy::SpIBinder; @@ -22,7 +22,7 @@ use crate::sys; use std::convert::{TryFrom, TryInto}; use std::ffi::c_void; -use std::mem::{self, ManuallyDrop, MaybeUninit}; +use std::mem::{self, ManuallyDrop}; use std::os::raw::c_char; use std::ptr; use std::slice; @@ -60,6 +60,26 @@ pub trait Serialize { /// A struct whose instances can be restored from a [`Parcel`]. // Might be able to hook this up as a serde backend in the future? pub trait Deserialize: Sized { + /// Type for the uninitialized value of this type. Will be either `Self` + /// if the type implements `Default`, `Option` otherwise. + type UninitType; + + /// Assert at compile-time that `Self` and `Self::UninitType` have the same + /// size and alignment. This will either fail to compile or evaluate to `true`. + /// The only two macros that work here are `panic!` and `assert!`, so we cannot + /// use `assert_eq!`. + const ASSERT_UNINIT_SIZE_AND_ALIGNMENT: bool = { + assert!(std::mem::size_of::() == std::mem::size_of::()); + assert!(std::mem::align_of::() == std::mem::align_of::()); + true + }; + + /// Return an uninitialized or default-initialized value for this type. + fn uninit() -> Self::UninitType; + + /// Convert an initialized value of type `Self` into `Self::UninitType`. + fn from_init(value: Self) -> Self::UninitType; + /// Deserialize an instance from the given [`Parcel`]. fn deserialize(parcel: &BorrowedParcel<'_>) -> Result; @@ -121,7 +141,7 @@ unsafe extern "C" fn serialize_element( pub trait DeserializeArray: Deserialize { /// Deserialize an array of type from the given parcel. fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result>> { - let mut vec: Option>> = None; + let mut vec: Option> = None; let res = unsafe { // Safety: Safe FFI, vec is the correct opaque type expected by // allocate_vec and deserialize_element. @@ -136,8 +156,8 @@ pub trait DeserializeArray: Deserialize { let vec: Option> = unsafe { // Safety: We are assuming that the NDK correctly initialized every // element of the vector by now, so we know that all the - // MaybeUninits are now properly initialized. We can transmute from - // Vec> to Vec because MaybeUninit has the same + // UninitTypes are now properly initialized. We can transmute from + // Vec to Vec because T::UninitType has the same // alignment and size as T, so the pointer to the vector allocation // will be compatible. mem::transmute(vec) @@ -149,14 +169,14 @@ pub trait DeserializeArray: Deserialize { /// Callback to deserialize a parcelable element. /// /// The opaque array data pointer must be a mutable pointer to an -/// `Option>>` with at least enough elements for `index` to be valid +/// `Option>` with at least enough elements for `index` to be valid /// (zero-based). unsafe extern "C" fn deserialize_element( parcel: *const sys::AParcel, array: *mut c_void, index: usize, ) -> status_t { - let vec = &mut *(array as *mut Option>>); + let vec = &mut *(array as *mut Option>); let vec = match vec { Some(v) => v, None => return StatusCode::BAD_INDEX as status_t, @@ -170,7 +190,7 @@ unsafe extern "C" fn deserialize_element( Ok(e) => e, Err(code) => return code as status_t, }; - ptr::write(vec[index].as_mut_ptr(), element); + vec[index] = T::from_init(element); StatusCode::OK as status_t } @@ -233,15 +253,15 @@ pub trait DeserializeOption: Deserialize { /// # Safety /// /// The opaque data pointer passed to the array read function must be a mutable -/// pointer to an `Option>>`. `buffer` will be assigned a mutable pointer +/// pointer to an `Option>`. `buffer` will be assigned a mutable pointer /// to the allocated vector data if this function returns true. -unsafe extern "C" fn allocate_vec_with_buffer( +unsafe extern "C" fn allocate_vec_with_buffer( data: *mut c_void, len: i32, buffer: *mut *mut T, ) -> bool { let res = allocate_vec::(data, len); - let vec = &mut *(data as *mut Option>>); + let vec = &mut *(data as *mut Option>); if let Some(new_vec) = vec { *buffer = new_vec.as_mut_ptr() as *mut T; } @@ -253,20 +273,18 @@ unsafe extern "C" fn allocate_vec_with_buffer( /// # Safety /// /// The opaque data pointer passed to the array read function must be a mutable -/// pointer to an `Option>>`. -unsafe extern "C" fn allocate_vec(data: *mut c_void, len: i32) -> bool { - let vec = &mut *(data as *mut Option>>); +/// pointer to an `Option>`. +unsafe extern "C" fn allocate_vec(data: *mut c_void, len: i32) -> bool { + let vec = &mut *(data as *mut Option>); if len < 0 { *vec = None; return true; } - let mut new_vec: Vec> = Vec::with_capacity(len as usize); - // Safety: We are filling the vector with uninitialized data here, but this - // is safe because the vector contains MaybeUninit elements which can be - // uninitialized. We're putting off the actual unsafe bit, transmuting the - // vector to a Vec until the contents are initialized. - new_vec.set_len(len as usize); + // Assert at compile time that `T` and `T::UninitType` have the same size and alignment. + let _ = T::ASSERT_UNINIT_SIZE_AND_ALIGNMENT; + let mut new_vec: Vec = Vec::with_capacity(len as usize); + new_vec.resize_with(len as usize, T::uninit); ptr::write(vec, Some(new_vec)); true @@ -283,8 +301,11 @@ macro_rules! parcelable_primitives { } /// Safety: All elements in the vector must be properly initialized. -unsafe fn vec_assume_init(vec: Vec>) -> Vec { - // We can convert from Vec> to Vec because MaybeUninit +unsafe fn vec_assume_init(vec: Vec) -> Vec { + // Assert at compile time that `T` and `T::UninitType` have the same size and alignment. + let _ = T::ASSERT_UNINIT_SIZE_AND_ALIGNMENT; + + // We can convert from Vec to Vec because T::UninitType // has the same alignment and size as T, so the pointer to the vector // allocation will be compatible. let mut vec = ManuallyDrop::new(vec); @@ -307,6 +328,9 @@ macro_rules! impl_parcelable { {Deserialize, $ty:ty, $read_fn:path} => { impl Deserialize for $ty { + type UninitType = Self; + fn uninit() -> Self::UninitType { Self::UninitType::default() } + fn from_init(value: Self) -> Self::UninitType { value } fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { let mut val = Self::default(); unsafe { @@ -348,11 +372,11 @@ macro_rules! impl_parcelable { {DeserializeArray, $ty:ty, $read_array_fn:path} => { impl DeserializeArray for $ty { fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result>> { - let mut vec: Option>> = None; + let mut vec: Option> = None; let status = unsafe { // Safety: `Parcel` always contains a valid pointer to an // `AParcel`. `allocate_vec` expects the opaque pointer to - // be of type `*mut Option>>`, so `&mut vec` is + // be of type `*mut Option>`, so `&mut vec` is // correct for it. $read_array_fn( parcel.as_native(), @@ -364,7 +388,7 @@ macro_rules! impl_parcelable { let vec: Option> = unsafe { // Safety: We are assuming that the NDK correctly // initialized every element of the vector by now, so we - // know that all the MaybeUninits are now properly + // know that all the UninitTypes are now properly // initialized. vec.map(|vec| vec_assume_init(vec)) }; @@ -440,6 +464,14 @@ impl Serialize for u8 { } impl Deserialize for u8 { + type UninitType = Self; + fn uninit() -> Self::UninitType { + Self::UninitType::default() + } + fn from_init(value: Self) -> Self::UninitType { + value + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { i8::deserialize(parcel).map(|v| v as u8) } @@ -471,6 +503,14 @@ impl Serialize for i16 { } impl Deserialize for i16 { + type UninitType = Self; + fn uninit() -> Self::UninitType { + Self::UninitType::default() + } + fn from_init(value: Self) -> Self::UninitType { + value + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { u16::deserialize(parcel).map(|v| v as i16) } @@ -547,6 +587,14 @@ impl SerializeOption for String { } impl Deserialize for Option { + type UninitType = Self; + fn uninit() -> Self::UninitType { + Self::UninitType::default() + } + fn from_init(value: Self) -> Self::UninitType { + value + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { let mut vec: Option> = None; let status = unsafe { @@ -575,6 +623,14 @@ impl Deserialize for Option { impl DeserializeArray for Option {} impl Deserialize for String { + type UninitType = Self; + fn uninit() -> Self::UninitType { + Self::UninitType::default() + } + fn from_init(value: Self) -> Self::UninitType { + value + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { Deserialize::deserialize(parcel).transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL)) } @@ -611,6 +667,14 @@ impl SerializeOption for Vec { } impl Deserialize for Vec { + type UninitType = Self; + fn uninit() -> Self::UninitType { + Self::UninitType::default() + } + fn from_init(value: Self) -> Self::UninitType { + value + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { DeserializeArray::deserialize_array(parcel) .transpose() @@ -640,6 +704,14 @@ impl SerializeOption for [T; N] { impl SerializeArray for [T; N] {} impl Deserialize for [T; N] { + type UninitType = [T::UninitType; N]; + fn uninit() -> Self::UninitType { + [(); N].map(|_| T::uninit()) + } + fn from_init(value: Self) -> Self::UninitType { + value.map(T::from_init) + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { let vec = DeserializeArray::deserialize_array(parcel) .transpose() @@ -664,6 +736,14 @@ impl Serialize for Stability { } impl Deserialize for Stability { + type UninitType = Self; + fn uninit() -> Self::UninitType { + Self::UninitType::default() + } + fn from_init(value: Self) -> Self::UninitType { + value + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { i32::deserialize(parcel).and_then(Stability::try_from) } @@ -682,6 +762,14 @@ impl Serialize for Status { } impl Deserialize for Status { + type UninitType = Option; + fn uninit() -> Self::UninitType { + Self::UninitType::default() + } + fn from_init(value: Self) -> Self::UninitType { + Some(value) + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { let mut status_ptr = ptr::null_mut(); let ret_status = unsafe { @@ -717,12 +805,29 @@ impl SerializeOption for Strong { impl SerializeArray for Strong {} impl Deserialize for Strong { + type UninitType = Option>; + fn uninit() -> Self::UninitType { + Self::UninitType::default() + } + fn from_init(value: Self) -> Self::UninitType { + Some(value) + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { let ibinder: SpIBinder = parcel.read()?; FromIBinder::try_from(ibinder) } } +struct AssertIBinder; +impl Interface for AssertIBinder {} +impl FromIBinder for AssertIBinder { + // This is only needed so we can assert on the size of Strong + fn try_from(_: SpIBinder) -> Result> { + unimplemented!() + } +} + impl DeserializeOption for Strong { fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result> { let ibinder: Option = parcel.read()?; @@ -752,6 +857,14 @@ impl Serialize for Option { } impl Deserialize for Option { + type UninitType = Self; + fn uninit() -> Self::UninitType { + Self::UninitType::default() + } + fn from_init(value: Self) -> Self::UninitType { + value + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { DeserializeOption::deserialize_option(parcel) } @@ -821,6 +934,9 @@ macro_rules! impl_deserialize_for_parcelable { }; ($parcelable:ident < $( $param:ident ),* > ) => { impl < $($param: Default),* > $crate::binder_impl::Deserialize for $parcelable < $($param),* > { + type UninitType = Self; + fn uninit() -> Self::UninitType { Self::UninitType::default() } + fn from_init(value: Self) -> Self::UninitType { value } fn deserialize( parcel: &$crate::binder_impl::BorrowedParcel<'_>, ) -> std::result::Result { @@ -876,6 +992,14 @@ impl Serialize for Box { } impl Deserialize for Box { + type UninitType = Option; + fn uninit() -> Self::UninitType { + Self::UninitType::default() + } + fn from_init(value: Self) -> Self::UninitType { + Some(value) + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { Deserialize::deserialize(parcel).map(Box::new) } @@ -900,6 +1024,7 @@ mod tests { #[test] fn test_custom_parcelable() { + #[derive(Default)] struct Custom(u32, bool, String, Vec); impl Serialize for Custom { @@ -912,6 +1037,14 @@ mod tests { } impl Deserialize for Custom { + type UninitType = Self; + fn uninit() -> Self::UninitType { + Self::UninitType::default() + } + fn from_init(value: Self) -> Self::UninitType { + value + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { Ok(Custom( parcel.read()?, diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs index c829d37dca..383cc83509 100644 --- a/libs/binder/rust/src/parcel/parcelable_holder.rs +++ b/libs/binder/rust/src/parcel/parcelable_holder.rs @@ -169,6 +169,14 @@ impl Serialize for ParcelableHolder { } impl Deserialize for ParcelableHolder { + type UninitType = Self; + fn uninit() -> Self::UninitType { + Self::new(Default::default()) + } + fn from_init(value: Self) -> Self::UninitType { + value + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { let status: i32 = parcel.read()?; if status == NULL_PARCELABLE_FLAG { diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs index 254efaed9a..036f6b4f01 100644 --- a/libs/binder/rust/src/proxy.rs +++ b/libs/binder/rust/src/proxy.rs @@ -439,6 +439,14 @@ impl SerializeOption for SpIBinder { impl SerializeArray for SpIBinder {} impl Deserialize for SpIBinder { + type UninitType = Option; + fn uninit() -> Self::UninitType { + Self::UninitType::default() + } + fn from_init(value: Self) -> Self::UninitType { + Some(value) + } + fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { parcel.read_binder().transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL)) } -- GitLab From de196989284b118dde06f32fa55c3d6b7a1a85aa Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Mon, 8 May 2023 15:01:12 +0900 Subject: [PATCH 0092/1187] servicemanager: Fix UpdatableViaApex tests These tests are supposed to run with known vendor apexes. Make the skip conditions more explicit so that they are run on only cuttlefish phones. Todo: for better coverage, we could add more targets with known preinstalled vendor apexes. Bug: 280483521 Test: servicemanager_test Change-Id: Id553583fa56aba586d588c90e263cab99188237e --- cmds/servicemanager/test_sm.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp index 0fd8d8ee2a..d5ba078235 100644 --- a/cmds/servicemanager/test_sm.cpp +++ b/cmds/servicemanager/test_sm.cpp @@ -27,11 +27,14 @@ #include "Access.h" #include "ServiceManager.h" -using android::sp; using android::Access; using android::BBinder; using android::IBinder; using android::ServiceManager; +using android::sp; +using android::base::EndsWith; +using android::base::GetProperty; +using android::base::StartsWith; using android::binder::Status; using android::os::BnServiceCallback; using android::os::IServiceManager; @@ -77,9 +80,11 @@ static sp getPermissiveServiceManager() { return sm; } -static bool isCuttlefish() { - return android::base::StartsWith(android::base::GetProperty("ro.product.vendor.device", ""), - "vsoc_"); +// Determines if test device is a cuttlefish phone device +static bool isCuttlefishPhone() { + auto device = GetProperty("ro.product.vendor.device", ""); + auto product = GetProperty("ro.product.vendor.name", ""); + return StartsWith(device, "vsoc_") && EndsWith(product, "_phone"); } TEST(AddService, HappyHappy) { @@ -314,7 +319,7 @@ TEST(ListServices, CriticalServices) { } TEST(Vintf, UpdatableViaApex) { - if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices"; + if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices"; auto sm = getPermissiveServiceManager(); std::optional updatableViaApex; @@ -326,7 +331,7 @@ TEST(Vintf, UpdatableViaApex) { } TEST(Vintf, UpdatableViaApex_InvalidNameReturnsNullOpt) { - if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices"; + if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices"; auto sm = getPermissiveServiceManager(); std::optional updatableViaApex; @@ -337,7 +342,7 @@ TEST(Vintf, UpdatableViaApex_InvalidNameReturnsNullOpt) { } TEST(Vintf, GetUpdatableNames) { - if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices"; + if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices"; auto sm = getPermissiveServiceManager(); std::vector names; @@ -348,7 +353,7 @@ TEST(Vintf, GetUpdatableNames) { } TEST(Vintf, GetUpdatableNames_InvalidApexNameReturnsEmpty) { - if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices"; + if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices"; auto sm = getPermissiveServiceManager(); std::vector names; -- GitLab From c55f75fc90e99c55a7133f82c407520f22937d96 Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Thu, 27 Apr 2023 13:01:58 +0000 Subject: [PATCH 0093/1187] InputMapper refactor: ExternalStylusInputMapper Add a factory method for ExternalStylusInputMapper to be configured on initilisation Test: m checkinput && atest libinput_tests inputflinger_tests Bug: 256009910 Change-Id: If75377416f4f6d3954480bf4e32886f3daf7f1f3 --- services/inputflinger/reader/InputDevice.cpp | 2 +- .../reader/mapper/ExternalStylusInputMapper.h | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index b0c44880c5..819e97a478 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -520,7 +520,7 @@ std::vector> InputDevice::createMappers( // External stylus-like devices. if (classes.test(InputDeviceClass::EXTERNAL_STYLUS)) { - mappers.push_back(std::make_unique(contextPtr, readerConfig)); + mappers.push_back(createInputMapper(contextPtr, readerConfig)); } return mappers; } diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h index 841c437543..97df02b69f 100644 --- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h +++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h @@ -26,8 +26,10 @@ namespace android { class ExternalStylusInputMapper : public InputMapper { public: - explicit ExternalStylusInputMapper(InputDeviceContext& deviceContext, - const InputReaderConfiguration& readerConfig); + template + friend std::unique_ptr createInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, + Args... args); virtual ~ExternalStylusInputMapper() = default; uint32_t getSources() const override; @@ -46,6 +48,8 @@ private: StylusState mStylusState; + explicit ExternalStylusInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig); [[nodiscard]] std::list sync(nsecs_t when); }; -- GitLab From ae876351487643d78691486792dfe7fd00dd60e9 Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Wed, 26 Apr 2023 14:16:50 +0000 Subject: [PATCH 0094/1187] InputMapper refactor: JoystickInputMapper Add a factory method for JoystickInputMapper to be configured on initilisation Test: m checkinput && atest libinput_tests inputflinger_tests Bug: 256009910 Change-Id: I7fbcd9590a91af8b3b61bb6f3824f66eda800410 --- services/inputflinger/reader/InputDevice.cpp | 2 +- .../inputflinger/reader/mapper/JoystickInputMapper.h | 9 +++++++-- services/inputflinger/tests/InputReader_test.cpp | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index b0c44880c5..bff6b179d9 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -510,7 +510,7 @@ std::vector> InputDevice::createMappers( // Joystick-like devices. if (classes.test(InputDeviceClass::JOYSTICK)) { - mappers.push_back(std::make_unique(contextPtr, readerConfig)); + mappers.push_back(createInputMapper(contextPtr, readerConfig)); } // Motion sensor enabled devices. diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.h b/services/inputflinger/reader/mapper/JoystickInputMapper.h index 49673a2f4e..313f0922b7 100644 --- a/services/inputflinger/reader/mapper/JoystickInputMapper.h +++ b/services/inputflinger/reader/mapper/JoystickInputMapper.h @@ -22,8 +22,10 @@ namespace android { class JoystickInputMapper : public InputMapper { public: - explicit JoystickInputMapper(InputDeviceContext& deviceContext, - const InputReaderConfiguration& readerConfig); + template + friend std::unique_ptr createInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, + Args... args); virtual ~JoystickInputMapper(); virtual uint32_t getSources() const override; @@ -87,6 +89,9 @@ private: } }; + explicit JoystickInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig); + static Axis createAxis(const AxisInfo& AxisInfo, const RawAbsoluteAxisInfo& rawAxisInfo, bool explicitlyMapped); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index c34dcac3aa..ecfa5483b3 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -10917,7 +10917,7 @@ const int32_t JoystickInputMapperTest::RAW_Y_MAX = 32767; TEST_F(JoystickInputMapperTest, Configure_AssignsDisplayUniqueId) { prepareAxes(); - JoystickInputMapper& mapper = addMapperAndConfigure(); + JoystickInputMapper& mapper = constructAndAddMapper(); mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, VIRTUAL_DISPLAY_UNIQUE_ID); -- GitLab From f224f62b67d47aa1d675f4274b3e2389c3b7589a Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Wed, 26 Apr 2023 14:54:20 +0000 Subject: [PATCH 0095/1187] InputMapper refactor: RotaryEncoderInputMapper Add a factory method for RotaryEncoderInputMapper to be configured on initilisation Test: m checkinput && atest libinput_tests inputflinger_tests Bug: 256009910 Change-Id: I9b2c9409e98f5a8fa389538bb99c4c9c10d780a5 --- services/inputflinger/reader/InputDevice.cpp | 2 +- .../inputflinger/reader/mapper/RotaryEncoderInputMapper.h | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index b0c44880c5..59c568a788 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -451,7 +451,7 @@ std::vector> InputDevice::createMappers( // Scroll wheel-like devices. if (classes.test(InputDeviceClass::ROTARY_ENCODER)) { - mappers.push_back(std::make_unique(contextPtr, readerConfig)); + mappers.push_back(createInputMapper(contextPtr, readerConfig)); } // Vibrator-like devices. diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h index d3dcbe1bb4..9e2e8c4342 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h @@ -25,8 +25,10 @@ namespace android { class RotaryEncoderInputMapper : public InputMapper { public: - explicit RotaryEncoderInputMapper(InputDeviceContext& deviceContext, - const InputReaderConfiguration& readerConfig); + template + friend std::unique_ptr createInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, + Args... args); virtual ~RotaryEncoderInputMapper(); virtual uint32_t getSources() const override; @@ -45,6 +47,8 @@ private: float mScalingFactor; ui::Rotation mOrientation; + explicit RotaryEncoderInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig); [[nodiscard]] std::list sync(nsecs_t when, nsecs_t readTime); }; -- GitLab From fb706c3835608366381f4bbb5e921e798be4fe52 Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Wed, 26 Apr 2023 15:07:55 +0000 Subject: [PATCH 0096/1187] InputMapper refactor: SensorInputMapper Add a factory method for SensorInputMapper to be configured on initilisation Test: m checkinput && atest libinput_tests inputflinger_tests Bug: 256009910 Change-Id: Ib1b32424cebc57c789288ce86d7c5e8d145dc552 --- services/inputflinger/reader/InputDevice.cpp | 2 +- services/inputflinger/reader/mapper/SensorInputMapper.h | 9 +++++++-- services/inputflinger/tests/InputReader_test.cpp | 6 +++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index b0c44880c5..b44f3cba50 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -515,7 +515,7 @@ std::vector> InputDevice::createMappers( // Motion sensor enabled devices. if (classes.test(InputDeviceClass::SENSOR)) { - mappers.push_back(std::make_unique(contextPtr, readerConfig)); + mappers.push_back(createInputMapper(contextPtr, readerConfig)); } // External stylus-like devices. diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.h b/services/inputflinger/reader/mapper/SensorInputMapper.h index 1f82559db8..a55dcd1905 100644 --- a/services/inputflinger/reader/mapper/SensorInputMapper.h +++ b/services/inputflinger/reader/mapper/SensorInputMapper.h @@ -27,8 +27,10 @@ static constexpr ssize_t SENSOR_VEC_LEN = 3; class SensorInputMapper : public InputMapper { public: - explicit SensorInputMapper(InputDeviceContext& deviceContext, - const InputReaderConfiguration& readerConfig); + template + friend std::unique_ptr createInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, + Args... args); ~SensorInputMapper() override; uint32_t getSources() const override; @@ -106,6 +108,9 @@ private: } }; + explicit SensorInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig); + static Axis createAxis(const AxisInfo& AxisInfo, const RawAbsoluteAxisInfo& rawAxisInfo); // Axes indexed by raw ABS_* axis index. diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index c34dcac3aa..1de4f95812 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -2784,7 +2784,7 @@ void SensorInputMapperTest::setGyroProperties() { } TEST_F(SensorInputMapperTest, GetSources) { - SensorInputMapper& mapper = addMapperAndConfigure(); + SensorInputMapper& mapper = constructAndAddMapper(); ASSERT_EQ(static_cast(AINPUT_SOURCE_SENSOR), mapper.getSources()); } @@ -2792,7 +2792,7 @@ TEST_F(SensorInputMapperTest, GetSources) { TEST_F(SensorInputMapperTest, ProcessAccelerometerSensor) { setAccelProperties(); prepareAccelAxes(); - SensorInputMapper& mapper = addMapperAndConfigure(); + SensorInputMapper& mapper = constructAndAddMapper(); ASSERT_TRUE(mapper.enableSensor(InputDeviceSensorType::ACCELEROMETER, std::chrono::microseconds(10000), @@ -2822,7 +2822,7 @@ TEST_F(SensorInputMapperTest, ProcessAccelerometerSensor) { TEST_F(SensorInputMapperTest, ProcessGyroscopeSensor) { setGyroProperties(); prepareGyroAxes(); - SensorInputMapper& mapper = addMapperAndConfigure(); + SensorInputMapper& mapper = constructAndAddMapper(); ASSERT_TRUE(mapper.enableSensor(InputDeviceSensorType::GYROSCOPE, std::chrono::microseconds(10000), -- GitLab From df992eb9dac0100bfcb8a67a992abb5ff97ea35b Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Wed, 26 Apr 2023 16:12:10 +0000 Subject: [PATCH 0097/1187] InputMapper refactor: SwitchInputMapper Add a factory method for SwitchInputMapper to be configured on initilisation Test: m checkinput && atest libinput_tests inputflinger_tests Bug: 256009910 Change-Id: Ib2d8e680f72a3e07202fc6e4db7a48e54528555f --- services/inputflinger/reader/InputDevice.cpp | 2 +- services/inputflinger/reader/mapper/SwitchInputMapper.h | 8 ++++++-- services/inputflinger/tests/InputReader_test.cpp | 6 +++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index b0c44880c5..6b02852cf9 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -446,7 +446,7 @@ std::vector> InputDevice::createMappers( // Switch-like devices. if (classes.test(InputDeviceClass::SWITCH)) { - mappers.push_back(std::make_unique(contextPtr, readerConfig)); + mappers.push_back(createInputMapper(contextPtr, readerConfig)); } // Scroll wheel-like devices. diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.h b/services/inputflinger/reader/mapper/SwitchInputMapper.h index 7ec282b721..2fb48bbf25 100644 --- a/services/inputflinger/reader/mapper/SwitchInputMapper.h +++ b/services/inputflinger/reader/mapper/SwitchInputMapper.h @@ -22,8 +22,10 @@ namespace android { class SwitchInputMapper : public InputMapper { public: - explicit SwitchInputMapper(InputDeviceContext& deviceContext, - const InputReaderConfiguration& readerConfig); + template + friend std::unique_ptr createInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, + Args... args); virtual ~SwitchInputMapper(); virtual uint32_t getSources() const override; @@ -36,6 +38,8 @@ private: uint32_t mSwitchValues; uint32_t mUpdatedSwitchMask; + explicit SwitchInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig); void processSwitch(int32_t switchCode, int32_t switchValue); [[nodiscard]] std::list sync(nsecs_t when); }; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index c34dcac3aa..7d0fe4d926 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -2603,13 +2603,13 @@ protected: }; TEST_F(SwitchInputMapperTest, GetSources) { - SwitchInputMapper& mapper = addMapperAndConfigure(); + SwitchInputMapper& mapper = constructAndAddMapper(); ASSERT_EQ(uint32_t(AINPUT_SOURCE_SWITCH), mapper.getSources()); } TEST_F(SwitchInputMapperTest, GetSwitchState) { - SwitchInputMapper& mapper = addMapperAndConfigure(); + SwitchInputMapper& mapper = constructAndAddMapper(); mFakeEventHub->setSwitchState(EVENTHUB_ID, SW_LID, 1); ASSERT_EQ(1, mapper.getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); @@ -2619,7 +2619,7 @@ TEST_F(SwitchInputMapperTest, GetSwitchState) { } TEST_F(SwitchInputMapperTest, Process) { - SwitchInputMapper& mapper = addMapperAndConfigure(); + SwitchInputMapper& mapper = constructAndAddMapper(); std::list out; out = process(mapper, ARBITRARY_TIME, READ_TIME, EV_SW, SW_LID, 1); ASSERT_TRUE(out.empty()); -- GitLab From 04e643ceacce438363afb521b7a1ff429562aab7 Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Wed, 26 Apr 2023 15:20:33 +0000 Subject: [PATCH 0098/1187] InputMapper refactor: TouchpadInputMapper Add a factory method for TouchpadInputMapper to be configured on initilisation Test: m checkinput && atest libinput_tests inputflinger_tests Bug: 256009910 Change-Id: I1189eede635330b24f3f1175d2aa4b46775362b7 --- services/inputflinger/reader/InputDevice.cpp | 2 +- services/inputflinger/reader/mapper/TouchpadInputMapper.h | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index b0c44880c5..3cae9d92d8 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -501,7 +501,7 @@ std::vector> InputDevice::createMappers( (identifier.product == 0x05c4 || identifier.product == 0x09cc); if (ENABLE_TOUCHPAD_GESTURES_LIBRARY && classes.test(InputDeviceClass::TOUCHPAD) && classes.test(InputDeviceClass::TOUCH_MT) && !isSonyDualShock4Touchpad) { - mappers.push_back(std::make_unique(contextPtr, readerConfig)); + mappers.push_back(createInputMapper(contextPtr, readerConfig)); } else if (classes.test(InputDeviceClass::TOUCH_MT)) { mappers.push_back(createInputMapper(contextPtr, readerConfig)); } else if (classes.test(InputDeviceClass::TOUCH)) { diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h index 3128d18a05..23d0fd3cf3 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h @@ -40,8 +40,10 @@ namespace android { class TouchpadInputMapper : public InputMapper { public: - explicit TouchpadInputMapper(InputDeviceContext& deviceContext, - const InputReaderConfiguration& readerConfig); + template + friend std::unique_ptr createInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, + Args... args); ~TouchpadInputMapper(); uint32_t getSources() const override; @@ -58,6 +60,8 @@ public: private: void resetGestureInterpreter(nsecs_t when); + explicit TouchpadInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig); [[nodiscard]] std::list sendHardwareState(nsecs_t when, nsecs_t readTime, SelfContainedHardwareState schs); [[nodiscard]] std::list processGestures(nsecs_t when, nsecs_t readTime); -- GitLab From 0f26b30cc1a730a828f1b7bd16a1ff77dbc7282d Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Wed, 26 Apr 2023 16:23:13 +0000 Subject: [PATCH 0099/1187] InputMapper refactor: VibratorInputMapper Add a factory method for VibratorInputMapper to be configured with on initilisation Test: m checkinput && atest libinput_tests inputflinger_tests Bug: 256009910 Change-Id: I3c1ad85a8fc293ec1a8c1a5c82da36e304538046 --- services/inputflinger/reader/InputDevice.cpp | 2 +- services/inputflinger/reader/mapper/VibratorInputMapper.h | 8 ++++++-- services/inputflinger/tests/InputReader_test.cpp | 6 +++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index b0c44880c5..f9807f81f0 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -456,7 +456,7 @@ std::vector> InputDevice::createMappers( // Vibrator-like devices. if (classes.test(InputDeviceClass::VIBRATOR)) { - mappers.push_back(std::make_unique(contextPtr, readerConfig)); + mappers.push_back(createInputMapper(contextPtr, readerConfig)); } // Battery-like devices or light-containing devices. diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.h b/services/inputflinger/reader/mapper/VibratorInputMapper.h index 384c07512a..9079c73f8e 100644 --- a/services/inputflinger/reader/mapper/VibratorInputMapper.h +++ b/services/inputflinger/reader/mapper/VibratorInputMapper.h @@ -22,8 +22,10 @@ namespace android { class VibratorInputMapper : public InputMapper { public: - explicit VibratorInputMapper(InputDeviceContext& deviceContext, - const InputReaderConfiguration& readerConfig); + template + friend std::unique_ptr createInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, + Args... args); virtual ~VibratorInputMapper(); virtual uint32_t getSources() const override; @@ -46,6 +48,8 @@ private: ssize_t mIndex; nsecs_t mNextStepTime; + explicit VibratorInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig); [[nodiscard]] std::list nextStep(); [[nodiscard]] NotifyVibratorStateArgs stopVibrating(); }; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index c34dcac3aa..4aff504ce5 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -2645,13 +2645,13 @@ protected: }; TEST_F(VibratorInputMapperTest, GetSources) { - VibratorInputMapper& mapper = addMapperAndConfigure(); + VibratorInputMapper& mapper = constructAndAddMapper(); ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mapper.getSources()); } TEST_F(VibratorInputMapperTest, GetVibratorIds) { - VibratorInputMapper& mapper = addMapperAndConfigure(); + VibratorInputMapper& mapper = constructAndAddMapper(); ASSERT_EQ(mapper.getVibratorIds().size(), 2U); } @@ -2659,7 +2659,7 @@ TEST_F(VibratorInputMapperTest, GetVibratorIds) { TEST_F(VibratorInputMapperTest, Vibrate) { constexpr uint8_t DEFAULT_AMPLITUDE = 192; constexpr int32_t VIBRATION_TOKEN = 100; - VibratorInputMapper& mapper = addMapperAndConfigure(); + VibratorInputMapper& mapper = constructAndAddMapper(); VibrationElement pattern(2); VibrationSequence sequence(2); -- GitLab From 67ca684ad1e5d6286bdbae568ee0fc97be40d3c1 Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Wed, 26 Apr 2023 14:43:16 +0000 Subject: [PATCH 0100/1187] InputMapper refactor: KeyboardInputMapper Add a factory method for KeyboardInputMapper to be configured on initilisation Test: m checkinput && atest libinput_tests inputflinger_tests Bug: 256009910 Change-Id: Iceb8676542de85309c208af93ee7cc385e46a067 --- services/inputflinger/reader/InputDevice.cpp | 4 +- .../reader/mapper/KeyboardInputMapper.h | 10 ++- .../inputflinger/tests/InputReader_test.cpp | 85 ++++++++++--------- 3 files changed, 54 insertions(+), 45 deletions(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 3f6d557aa8..ff30429cfe 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -482,8 +482,8 @@ std::vector> InputDevice::createMappers( } if (keyboardSource != 0) { - mappers.push_back(std::make_unique(contextPtr, readerConfig, - keyboardSource, keyboardType)); + mappers.push_back(createInputMapper(contextPtr, readerConfig, + keyboardSource, keyboardType)); } // Cursor-like devices. diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h index 8889a0f209..45fd68b8bb 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h @@ -23,9 +23,10 @@ namespace android { class KeyboardInputMapper : public InputMapper { public: - KeyboardInputMapper(InputDeviceContext& deviceContext, - const InputReaderConfiguration& readerConfig, uint32_t source, - int32_t keyboardType); + template + friend std::unique_ptr createInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, + Args... args); ~KeyboardInputMapper() override = default; uint32_t getSources() const override; @@ -83,6 +84,9 @@ private: bool doNotWakeByDefault{}; } mParameters{}; + KeyboardInputMapper(InputDeviceContext& deviceContext, + const InputReaderConfiguration& readerConfig, uint32_t source, + int32_t keyboardType); void configureParameters(); void dumpParameters(std::string& dump) const; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 750ac1d488..2df44ff2a4 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -2892,7 +2892,7 @@ void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper& mapper, TEST_F(KeyboardInputMapperTest, GetSources) { KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper.getSources()); @@ -2908,7 +2908,7 @@ TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, POLICY_FLAG_WAKE); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); // Initial metastate is AMETA_NONE. ASSERT_EQ(AMETA_NONE, mapper.getMetaState()); @@ -3009,7 +3009,7 @@ TEST_F(KeyboardInputMapperTest, Process_KeyRemapping) { mFakeEventHub->addKeyRemapping(EVENTHUB_ID, AKEYCODE_A, AKEYCODE_B); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); // Key down by scan code. @@ -3031,7 +3031,7 @@ TEST_F(KeyboardInputMapperTest, Process_SendsReadTime) { mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); NotifyKeyArgs args; @@ -3054,7 +3054,7 @@ TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) { mFakeEventHub->addKey(EVENTHUB_ID, 0, KEY_SCROLLLOCK, AKEYCODE_SCROLL_LOCK, 0); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); // Initial metastate is AMETA_NONE. @@ -3095,7 +3095,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateD mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); prepareDisplay(ui::ROTATION_90); @@ -3117,7 +3117,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { addConfigurationProperty("keyboard.orientationAware", "1"); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); prepareDisplay(ui::ROTATION_0); @@ -3189,7 +3189,7 @@ TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_NotOrientationAware mFakeEventHub->addKey(EVENTHUB_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); NotifyKeyArgs args; @@ -3215,7 +3215,7 @@ TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_OrientationAware) { addConfigurationProperty("keyboard.orientationAware", "1"); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); NotifyKeyArgs args; @@ -3243,7 +3243,7 @@ TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_OrientationAware) { TEST_F(KeyboardInputMapperTest, GetKeyCodeState) { KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); mFakeEventHub->setKeyCodeState(EVENTHUB_ID, AKEYCODE_A, 1); @@ -3255,7 +3255,7 @@ TEST_F(KeyboardInputMapperTest, GetKeyCodeState) { TEST_F(KeyboardInputMapperTest, GetKeyCodeForKeyLocation) { KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); mFakeEventHub->addKeyCodeMapping(EVENTHUB_ID, AKEYCODE_Y, AKEYCODE_Z); @@ -3268,7 +3268,7 @@ TEST_F(KeyboardInputMapperTest, GetKeyCodeForKeyLocation) { TEST_F(KeyboardInputMapperTest, GetScanCodeState) { KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); mFakeEventHub->setScanCodeState(EVENTHUB_ID, KEY_A, 1); @@ -3280,7 +3280,7 @@ TEST_F(KeyboardInputMapperTest, GetScanCodeState) { TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) { KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0); @@ -3300,7 +3300,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); // Initial metastate is AMETA_NONE. ASSERT_EQ(AMETA_NONE, mapper.getMetaState()); @@ -3366,7 +3366,7 @@ TEST_F(KeyboardInputMapperTest, NoMetaStateWhenMetaKeysNotPresent) { mFakeEventHub->addKey(EVENTHUB_ID, BTN_Y, 0, AKEYCODE_BUTTON_Y, 0); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC); // Meta state should be AMETA_NONE after reset @@ -3416,14 +3416,16 @@ TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) { mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); + device2->addEmptyEventHubDevice(SECOND_EVENTHUB_ID); KeyboardInputMapper& mapper2 = - device2->addMapper(SECOND_EVENTHUB_ID, - mFakePolicy->getReaderConfiguration(), - AINPUT_SOURCE_KEYBOARD, - AINPUT_KEYBOARD_TYPE_ALPHABETIC); + device2->constructAndAddMapper(SECOND_EVENTHUB_ID, + mFakePolicy + ->getReaderConfiguration(), + AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); std::list unused = device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), /*changes=*/{}); @@ -3485,7 +3487,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleAfterReattach) { mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); // Initial metastate is AMETA_NONE. ASSERT_EQ(AMETA_NONE, mapper.getMetaState()); @@ -3531,11 +3533,13 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleAfterReattach) { mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0); mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0); + device2->addEmptyEventHubDevice(SECOND_EVENTHUB_ID); KeyboardInputMapper& mapper2 = - device2->addMapper(SECOND_EVENTHUB_ID, - mFakePolicy->getReaderConfiguration(), - AINPUT_SOURCE_KEYBOARD, - AINPUT_KEYBOARD_TYPE_ALPHABETIC); + device2->constructAndAddMapper(SECOND_EVENTHUB_ID, + mFakePolicy + ->getReaderConfiguration(), + AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); std::list unused = device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), /*changes=*/{}); @@ -3554,10 +3558,10 @@ TEST_F(KeyboardInputMapperTest, Process_toggleCapsLockState) { mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0); // Suppose we have two mappers. (DPAD + KEYBOARD) - addMapperAndConfigure(AINPUT_SOURCE_DPAD, + constructAndAddMapper(AINPUT_SOURCE_DPAD, AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); // Initial metastate is AMETA_NONE. ASSERT_EQ(AMETA_NONE, mapper.getMetaState()); @@ -3576,7 +3580,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleInMultiDevices) { mFakeEventHub->addKey(EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0); KeyboardInputMapper& mapper1 = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); // keyboard 2. @@ -3594,11 +3598,13 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleInMultiDevices) { mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0); mFakeEventHub->addKey(SECOND_EVENTHUB_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0); + device2->addEmptyEventHubDevice(SECOND_EVENTHUB_ID); KeyboardInputMapper& mapper2 = - device2->addMapper(SECOND_EVENTHUB_ID, - mFakePolicy->getReaderConfiguration(), - AINPUT_SOURCE_KEYBOARD, - AINPUT_KEYBOARD_TYPE_ALPHABETIC); + device2->constructAndAddMapper(SECOND_EVENTHUB_ID, + mFakePolicy + ->getReaderConfiguration(), + AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); std::list unused = device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), /*changes=*/{}); @@ -3654,7 +3660,7 @@ TEST_F(KeyboardInputMapperTest, Process_DisabledDevice) { mFakeEventHub->addKey(EVENTHUB_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); // Key down by scan code. process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1); @@ -3680,9 +3686,8 @@ TEST_F(KeyboardInputMapperTest, Process_DisabledDevice) { } TEST_F(KeyboardInputMapperTest, Configure_AssignKeyboardLayoutInfo) { - mDevice->addMapper(EVENTHUB_ID, mFakePolicy->getReaderConfiguration(), - AINPUT_SOURCE_KEYBOARD, - AINPUT_KEYBOARD_TYPE_ALPHABETIC); + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, + AINPUT_KEYBOARD_TYPE_ALPHABETIC); std::list unused = mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), /*changes=*/{}); @@ -3713,7 +3718,7 @@ TEST_F(KeyboardInputMapperTest, LayoutInfoCorrectlyMapped) { RawLayoutInfo{.languageTag = "en", .layoutType = "extended"}); // Configuration - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); InputReaderConfiguration config; std::list unused = mDevice->configure(ARBITRARY_TIME, config, /*changes=*/{}); @@ -3725,7 +3730,7 @@ TEST_F(KeyboardInputMapperTest, LayoutInfoCorrectlyMapped) { TEST_F(KeyboardInputMapperTest, Process_GesureEventToSetFlagKeepTouchMode) { mFakeEventHub->addKey(EVENTHUB_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, POLICY_FLAG_GESTURE); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); NotifyKeyArgs args; @@ -3752,7 +3757,7 @@ TEST_F(KeyboardInputMapperTest_ExternalDevice, WakeBehavior) { POLICY_FLAG_WAKE); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1); @@ -3790,7 +3795,7 @@ TEST_F(KeyboardInputMapperTest_ExternalDevice, DoNotWakeByDefaultBehavior) { addConfigurationProperty("keyboard.doNotWakeByDefault", "1"); KeyboardInputMapper& mapper = - addMapperAndConfigure(AINPUT_SOURCE_KEYBOARD, + constructAndAddMapper(AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1); -- GitLab From cf0e4a985a44987524ef4a8ae150f943457c48bb Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Tue, 9 May 2023 23:52:48 +0900 Subject: [PATCH 0101/1187] Allow AVF C++ demo to use libbinder_rpc Bug: 279024580 Test: m Change-Id: I27dc30e335c83b8469da0f9ffcc0fcc52cd10f9f --- libs/binder/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index a4f2b070c4..7db961826e 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -550,6 +550,7 @@ cc_library { ":__subpackages__", "//packages/modules/Virtualization/javalib/jni", "//packages/modules/Virtualization/vm_payload", + "//packages/modules/Virtualization/demo_native", "//device/google/cuttlefish/shared/minidroid:__subpackages__", "//system/software_defined_vehicle:__subpackages__", ], -- GitLab From acd5547083d576964b67dc69f92815afe2d5bfa0 Mon Sep 17 00:00:00 2001 From: Ying Wei Date: Wed, 10 May 2023 05:51:27 +0000 Subject: [PATCH 0102/1187] Fix a typo in TimeStatsHelper Test: N/A BUG: 281781733 Change-Id: I38d0db62b76f5ac1faeacd1199a997fee0666470 --- .../surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp index cf1ca65972..cbbcb91469 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp +++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp @@ -115,7 +115,7 @@ std::string TimeStatsHelper::TimeStatsLayer::toString() const { StringAppendF(&result, "badDesiredPresentFrames = %d\n", badDesiredPresentFrames); result.append("Jank payload for this layer:\n"); result.append(jankPayload.toString()); - result.append("SetFrateRate vote for this layer:\n"); + result.append("SetFrameRate vote for this layer:\n"); result.append(setFrameRateVote.toString()); const auto iter = deltas.find("present2present"); if (iter != deltas.end()) { -- GitLab From aa33e856788ce62259b33df6a8b341e5450eb581 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 10 May 2023 16:42:15 +0000 Subject: [PATCH 0103/1187] servicemanager: log missing service requestor pid To aid reducing logspam when clients repeatedly request services. Bug: N/A Test: boot & check logs Change-Id: I7acce0c94f00ee954d3285b3a4b94ca56b7636ef --- cmds/servicemanager/ServiceManager.cpp | 11 ++++++----- cmds/servicemanager/ServiceManager.h | 2 +- cmds/servicemanager/test_sm.cpp | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 4472db10c0..98a70ed973 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -301,7 +301,7 @@ sp ServiceManager::tryGetService(const std::string& name, bool startIfN } if (!out && startIfNotFound) { - tryStartService(name); + tryStartService(ctx, name); } if (out) { @@ -651,10 +651,11 @@ void ServiceManager::binderDied(const wp& who) { } } -void ServiceManager::tryStartService(const std::string& name) { - ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service. (if it's not " - "configured to be a lazy service, it may be stuck starting or still starting).", - name.c_str()); +void ServiceManager::tryStartService(const Access::CallingContext& ctx, const std::string& name) { + ALOGI("Since '%s' could not be found (requested by debug pid %d), trying to start it as a lazy " + "AIDL service. (if it's not configured to be a lazy service, it may be stuck starting or " + "still starting).", + name.c_str(), ctx.debugPid); std::thread([=] { if (!base::SetProperty("ctl.interface_start", "aidl/" + name)) { diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h index 3aa6731eb3..3b925a48cb 100644 --- a/cmds/servicemanager/ServiceManager.h +++ b/cmds/servicemanager/ServiceManager.h @@ -67,7 +67,7 @@ public: void clear(); protected: - virtual void tryStartService(const std::string& name); + virtual void tryStartService(const Access::CallingContext& ctx, const std::string& name); private: struct Service { diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp index 0fd8d8ee2a..11e20073a0 100644 --- a/cmds/servicemanager/test_sm.cpp +++ b/cmds/servicemanager/test_sm.cpp @@ -62,7 +62,7 @@ public: class MockServiceManager : public ServiceManager { public: MockServiceManager(std::unique_ptr&& access) : ServiceManager(std::move(access)) {} - MOCK_METHOD1(tryStartService, void(const std::string& name)); + MOCK_METHOD2(tryStartService, void(const Access::CallingContext&, const std::string& name)); }; static sp getPermissiveServiceManager() { -- GitLab From 90b8289e4dab6818441eca1b1bb0cbf89d335fb3 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 11 May 2023 00:10:26 +0000 Subject: [PATCH 0104/1187] binderRpcBenchmark: set label label is clearer to interpret output than looking up numbers, and this doesn't break JSON parsing of the output. Bug: 271994750 Test: binderRpcBenchmark Change-Id: Idf38145fbd6c321be34379d4b5589b9cab4ed81c --- libs/binder/tests/binderRpcBenchmark.cpp | 32 ++++++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp index 593927306e..9c96c4182d 100644 --- a/libs/binder/tests/binderRpcBenchmark.cpp +++ b/libs/binder/tests/binderRpcBenchmark.cpp @@ -129,12 +129,33 @@ static sp getBinderForOptions(benchmark::State& state) { } } +static void SetLabel(benchmark::State& state) { + Transport transport = static_cast(state.range(0)); + switch (transport) { +#ifdef __BIONIC__ + case KERNEL: + state.SetLabel("kernel"); + break; +#endif + case RPC: + state.SetLabel("rpc"); + break; + case RPC_TLS: + state.SetLabel("rpc_tls"); + break; + default: + LOG(FATAL) << "Unknown transport value: " << transport; + } +} + void BM_pingTransaction(benchmark::State& state) { sp binder = getBinderForOptions(state); while (state.KeepRunning()) { CHECK_EQ(OK, binder->pingBinder()); } + + SetLabel(state); } BENCHMARK(BM_pingTransaction)->ArgsProduct({kTransportList}); @@ -164,6 +185,8 @@ void BM_repeatTwoPageString(benchmark::State& state) { Status ret = iface->repeatString(str, &out); CHECK(ret.isOk()) << ret; } + + SetLabel(state); } BENCHMARK(BM_repeatTwoPageString)->ArgsProduct({kTransportList}); @@ -182,6 +205,8 @@ void BM_throughputForTransportAndBytes(benchmark::State& state) { Status ret = iface->repeatBytes(bytes, &out); CHECK(ret.isOk()) << ret; } + + SetLabel(state); } BENCHMARK(BM_throughputForTransportAndBytes) ->ArgsProduct({kTransportList, @@ -201,6 +226,8 @@ void BM_repeatBinder(benchmark::State& state) { Status ret = iface->repeatBinder(binder, &out); CHECK(ret.isOk()) << ret; } + + SetLabel(state); } BENCHMARK(BM_repeatBinder)->ArgsProduct({kTransportList}); @@ -228,11 +255,6 @@ int main(int argc, char** argv) { ::benchmark::Initialize(&argc, argv); if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; - std::cerr << "Tests suffixes:" << std::endl; - std::cerr << "\t.../" << Transport::KERNEL << " is KERNEL" << std::endl; - std::cerr << "\t.../" << Transport::RPC << " is RPC" << std::endl; - std::cerr << "\t.../" << Transport::RPC_TLS << " is RPC with TLS" << std::endl; - #ifdef __BIONIC__ if (0 == fork()) { prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay -- GitLab From 9b254ddf6dfdf9c84f6592addf856555cfb04bbb Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 11 May 2023 00:37:55 +0000 Subject: [PATCH 0105/1187] binderParcelBenchmark: in TEST_MAPPING Bug: 271994750 Test: atest binderParcelBenchmark Change-Id: If5ac7fcac841344093b0b3424ba8e280f5135253 --- libs/binder/TEST_MAPPING | 3 +++ libs/binder/tests/Android.bp | 1 + 2 files changed, 4 insertions(+) diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index 0e8e18747b..85d7d90558 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -18,6 +18,9 @@ { "name": "binderHostDeviceTest" }, + { + "name": "binderParcelBenchmark" + }, { "name": "binderTextOutputTest" }, diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index cad364d8e8..8593be4eac 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -689,6 +689,7 @@ cc_benchmark { "liblog", "libutils", ], + test_suites: ["general-tests"], } cc_test_host { -- GitLab From 95afb8a0846ea7e1935835aeffb6010673c8426d Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Thu, 11 May 2023 14:57:41 +0000 Subject: [PATCH 0106/1187] Use relocated SkImages context typedefs In http://review.skia.org/661059, we moved many SkImage related methods, including these typedefs. This updates android/native to use the moved types. Change-Id: Id429256ffd9ef4316f23095797a63777fc6ddb48 --- libs/renderengine/skia/AutoBackendTexture.cpp | 2 +- libs/renderengine/skia/AutoBackendTexture.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp index 46a60f61eb..f3ef968d40 100644 --- a/libs/renderengine/skia/AutoBackendTexture.cpp +++ b/libs/renderengine/skia/AutoBackendTexture.cpp @@ -82,7 +82,7 @@ void AutoBackendTexture::releaseSurfaceProc(SkSurface::ReleaseContext releaseCon // releaseImageProc is invoked by SkImage, when the texture is no longer in use. // "releaseContext" contains an "AutoBackendTexture*". -void AutoBackendTexture::releaseImageProc(SkImage::ReleaseContext releaseContext) { +void AutoBackendTexture::releaseImageProc(SkImages::ReleaseContext releaseContext) { AutoBackendTexture* textureRelease = reinterpret_cast(releaseContext); textureRelease->unref(false); } diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h index 00b901be11..509ac40f77 100644 --- a/libs/renderengine/skia/AutoBackendTexture.h +++ b/libs/renderengine/skia/AutoBackendTexture.h @@ -144,7 +144,7 @@ private: CleanupManager& mCleanupMgr; static void releaseSurfaceProc(SkSurface::ReleaseContext releaseContext); - static void releaseImageProc(SkImage::ReleaseContext releaseContext); + static void releaseImageProc(SkImages::ReleaseContext releaseContext); int mUsageCount = 0; -- GitLab From 9a580625a8bd7631cdffae81ab68e5fd4e7bc1be Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 28 Apr 2023 21:13:26 +0000 Subject: [PATCH 0107/1187] Add sanitizers to libinput The library was already getting sanitized for some undefined behaviour on device. This change will move the sanitization to all platforms like host, and also expands the list of sanitizers. We can't enable the address sanitizer today, unfortunately. It causes the libinput to not be able to load on some configurations. It's not clear what's causing that yet. Bug: 271455682 Change-Id: I9588b0f7b42eec2070cd5556f94671fd934b7bec Test: presubmit --- libs/input/Android.bp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 869458c407..4be7328346 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -85,6 +85,12 @@ cc_library { "-Wl,--exclude-libs=libtflite_static.a", ], + sanitize: { + undefined: true, + all_undefined: true, + misc_undefined: ["integer"], + }, + static_libs: [ "libui-types", "libtflite_static", @@ -117,10 +123,6 @@ cc_library { "libgui_window_info_static", ], - sanitize: { - misc_undefined: ["integer"], - }, - required: [ "motion_predictor_model_prebuilt", ], -- GitLab From 9b65fe51a1c7470b52d768e7774a08f4466727ae Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Thu, 11 May 2023 13:57:27 -0400 Subject: [PATCH 0108/1187] Remove underscores from tests names I5532e140a603be222cb3ea1ae563638317c1d745 introduced some tests with underscores in their names, which GoogleTest discourages. Theses aren't (currently) harmful, but update them to conform to recommendations. Bug: 269685949 Bug: 259407931 Test: ActiveDisplayRotationFlagsTest Change-Id: Ia5dd12f4b7fc32758ad4cb79f1e3118c98fd9340 --- .../tests/unittests/ActiveDisplayRotationFlagsTest.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/tests/unittests/ActiveDisplayRotationFlagsTest.cpp b/services/surfaceflinger/tests/unittests/ActiveDisplayRotationFlagsTest.cpp index 7077523fc3..f1bb231f26 100644 --- a/services/surfaceflinger/tests/unittests/ActiveDisplayRotationFlagsTest.cpp +++ b/services/surfaceflinger/tests/unittests/ActiveDisplayRotationFlagsTest.cpp @@ -85,7 +85,7 @@ TEST_F(ActiveDisplayRotationFlagsTest, rotate90) { ASSERT_EQ(ui::Transform::ROT_90, SurfaceFlinger::getActiveDisplayRotationFlags()); } -TEST_F(ActiveDisplayRotationFlagsTest, rotate90_inactive) { +TEST_F(ActiveDisplayRotationFlagsTest, rotate90inactive) { auto displayToken = mOuterDisplay->getDisplayToken().promote(); mFlinger.mutableDrawingState().displays.editValueFor(displayToken).orientation = ui::ROTATION_0; mFlinger.mutableCurrentState().displays.editValueFor(displayToken).orientation = @@ -95,7 +95,7 @@ TEST_F(ActiveDisplayRotationFlagsTest, rotate90_inactive) { ASSERT_EQ(ui::Transform::ROT_0, SurfaceFlinger::getActiveDisplayRotationFlags()); } -TEST_F(ActiveDisplayRotationFlagsTest, rotateBoth_innerActive) { +TEST_F(ActiveDisplayRotationFlagsTest, rotateBothInnerActive) { auto displayToken = mInnerDisplay->getDisplayToken().promote(); mFlinger.mutableDrawingState().displays.editValueFor(displayToken).orientation = ui::ROTATION_0; mFlinger.mutableCurrentState().displays.editValueFor(displayToken).orientation = @@ -110,7 +110,7 @@ TEST_F(ActiveDisplayRotationFlagsTest, rotateBoth_innerActive) { ASSERT_EQ(ui::Transform::ROT_180, SurfaceFlinger::getActiveDisplayRotationFlags()); } -TEST_F(ActiveDisplayRotationFlagsTest, rotateBoth_outerActive) { +TEST_F(ActiveDisplayRotationFlagsTest, rotateBothOuterActive) { mFlinger.mutableActiveDisplayId() = kOuterDisplayId; auto displayToken = mInnerDisplay->getDisplayToken().promote(); mFlinger.mutableDrawingState().displays.editValueFor(displayToken).orientation = ui::ROTATION_0; -- GitLab From 632f14093e915651ed716c22f0ba6efa3d115aa0 Mon Sep 17 00:00:00 2001 From: Aditya Kumar Date: Mon, 27 Feb 2023 18:14:59 +0000 Subject: [PATCH 0109/1187] Revert "Disable thinlto in libbinder for riscv64 targets" This reverts commit 383b8a548fdb3b9503d523559346529abf0b0284. Reason for revert: Not needed as emultated tls is now globally disabled https://android-review.git.corp.google.com/c/platform/build/soong/+/2431153 Change-Id: I9423d7783bfccc49876f2137c1c2fb705c165be2 --- libs/binder/Android.bp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 7db961826e..34331381db 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -281,14 +281,6 @@ cc_defaults { cflags: [ "-DBINDER_WITH_KERNEL_IPC", ], - arch: { - // TODO(b/254713216): undefined symbol in BufferedTextOutput::getBuffer - riscv64: { - lto: { - thin: false, - }, - }, - }, } cc_library { -- GitLab From 7c8dd48ffd8662146fe54dba5a3b7d8015fdc07d Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Thu, 23 Mar 2023 15:30:03 -0700 Subject: [PATCH 0110/1187] Fix publishing RPC Server on the same address/port after a short time Bug: 274786956 Test: atest libsdvrpc_test_cpp Change-Id: I58b0b99b5e3ab8c9659eed0eba9ff689000b84ac --- libs/binder/RpcServer.cpp | 16 ++++++++++++++++ libs/binder/include/binder/RpcServer.h | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 9282856f5c..1635e2a3c4 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -161,6 +161,12 @@ void RpcServer::setConnectionFilter(std::function&& f mConnectionFilter = std::move(filter); } +void RpcServer::setServerSocketModifier(std::function&& modifier) { + RpcMutexLockGuard _l(mLock); + LOG_ALWAYS_FATAL_IF(mServer.fd != -1, "Already started"); + mServerSocketModifier = std::move(modifier); +} + sp RpcServer::getRootObject() { RpcMutexLockGuard _l(mLock); bool hasWeak = mRootObjectWeak.unsafe_get(); @@ -335,6 +341,8 @@ bool RpcServer::shutdown() { mJoinThread.reset(); } + mServer = RpcTransportFd(); + LOG_RPC_DETAIL("Finished waiting on shutdown."); mShutdownTrigger = nullptr; @@ -556,6 +564,14 @@ status_t RpcServer::setupSocketServer(const RpcSocketAddress& addr) { ALOGE("Could not create socket at %s: %s", addr.toString().c_str(), strerror(savedErrno)); return -savedErrno; } + + { + RpcMutexLockGuard _l(mLock); + if (mServerSocketModifier != nullptr) { + mServerSocketModifier(socket_fd); + } + } + if (0 != TEMP_FAILURE_RETRY(bind(socket_fd.get(), addr.addr(), addr.addrSize()))) { int savedErrno = errno; ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno)); diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h index 1001b64ede..481639516f 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -183,6 +183,13 @@ public: */ void setConnectionFilter(std::function&& filter); + /** + * Set optional modifier of each newly created server socket. + * + * The only argument is a successfully created file descriptor, not bound to an address yet. + */ + void setServerSocketModifier(std::function&& modifier); + /** * See RpcTransportCtx::getCertificate */ @@ -267,6 +274,7 @@ private: wp mRootObjectWeak; std::function(const void*, size_t)> mRootObjectFactory; std::function mConnectionFilter; + std::function mServerSocketModifier; std::map, sp> mSessions; std::unique_ptr mShutdownTrigger; RpcConditionVariable mShutdownCv; -- GitLab From 8c656c6c9f9c855818ecf2df92ba38193114fa30 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 11 May 2023 21:00:36 +0000 Subject: [PATCH 0111/1187] libbinder_ndk_unit_test: show cookie can own data The existing example is dangerous because it gives the death recipient ownership of data on the stack. If the test fails, then the callback would be referencing invalid stack data. Now, this example owns the cookie, so it is more clear how to have the cookie contain arbitrary additional data, and there is no longer a memory corruption issue if the test happened to fail. Fixes: 275407810 Test: libbinder_ndk_unit_test Change-Id: I2b2ce675d3fae7e033bd701208b095ebe14da1e5 --- .../ndk/tests/libbinder_ndk_unit_test.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index cefc42f25e..664894ebac 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -497,14 +497,28 @@ TEST(NdkBinder, ActiveServicesCallbackTest) { struct DeathRecipientCookie { std::function*onDeath, *onUnlink; + + // may contain additional data + // - if it contains AIBinder, then you must call AIBinder_unlinkToDeath manually, + // because it would form a strong reference cycle + // - if it points to a data member of another structure, this should have a weak + // promotable reference or a strong reference, in case that object is deleted + // while the death recipient is firing }; void LambdaOnDeath(void* cookie) { auto funcs = static_cast(cookie); + + // may reference other cookie members + (*funcs->onDeath)(); }; void LambdaOnUnlink(void* cookie) { auto funcs = static_cast(cookie); (*funcs->onUnlink)(); + + // may reference other cookie members + + delete funcs; }; TEST(NdkBinder, DeathRecipient) { using namespace std::chrono_literals; @@ -536,12 +550,12 @@ TEST(NdkBinder, DeathRecipient) { unlinkCv.notify_one(); }; - DeathRecipientCookie cookie = {&onDeath, &onUnlink}; + DeathRecipientCookie* cookie = new DeathRecipientCookie{&onDeath, &onUnlink}; AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath); AIBinder_DeathRecipient_setOnUnlinked(recipient, LambdaOnUnlink); - EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast(&cookie))); + EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast(cookie))); // the binder driver should return this if the service dies during the transaction EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die()); -- GitLab From a201336bf90504ab48130ea0344690d6d803d1ea Mon Sep 17 00:00:00 2001 From: zijunzhao Date: Thu, 11 May 2023 21:27:19 +0000 Subject: [PATCH 0112/1187] Fix the Nullable pointer is dereferenced issue The member ai_addr is allowed to be null, which will cause dereferencing nullptr issue here. See https://android-build.corp.google.com/artifact/pending/P54712024/aosp_arm64-userdebug/latest/view/logs%2Fbuild.log for more details Bug: None Test: mm Change-Id: Ie1e8ec56bbd1edee0456c26d0d29775bc7abbbb5 --- libs/binder/RpcServer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 9282856f5c..84131a51bc 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -81,6 +81,7 @@ status_t RpcServer::setupInetServer(const char* address, unsigned int port, auto aiStart = InetSocketAddress::getAddrInfo(address, port); if (aiStart == nullptr) return UNKNOWN_ERROR; for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) { + if (ai->ai_addr == nullptr) continue; InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, address, port); if (status_t status = setupSocketServer(socketAddress); status != OK) { continue; -- GitLab From d98952d07f290edf7672d5fcfa9bdbac4e513a0d Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 11 May 2023 23:27:43 +0000 Subject: [PATCH 0113/1187] servicemanager: log if doesn't become ctx mgr Currently, this is a silent failure. This is made to be fatal in a separate patch, for revertability. Bug: 280514080 Test: boot Change-Id: If5a524f056d77905c818f466c5c677666caa1640 --- cmds/servicemanager/main.cpp | 5 ++++- libs/binder/include/binder/ProcessState.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp index c1a04dde89..520d6f9e7e 100644 --- a/cmds/servicemanager/main.cpp +++ b/cmds/servicemanager/main.cpp @@ -131,7 +131,10 @@ int main(int argc, char** argv) { } IPCThreadState::self()->setTheContextObject(manager); - ps->becomeContextManager(); + if (!ps->becomeContextManager()) { + LOG(ERROR) << "Could not become context manager"; + // TODO(b/280514080): fatal + } sp looper = Looper::prepare(false /*allowNonCallbacks*/); diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index ce578e3f5c..81391e96e7 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -55,7 +55,7 @@ public: // For main functions - dangerous for libraries to use void startThreadPool(); - bool becomeContextManager(); + [[nodiscard]] bool becomeContextManager(); sp getStrongProxyForHandle(int32_t handle); void expungeHandle(int32_t handle, IBinder* binder); -- GitLab From 601b795cf5660c8b47d0defcfdec1188ede2ead2 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 11 May 2023 23:29:00 +0000 Subject: [PATCH 0114/1187] servicemanager: fatal if not ctx mgr Bug: 280514080 Test: boot Change-Id: I368658b1121782fb5b80b1f44be10e048f013930 --- cmds/servicemanager/main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp index 520d6f9e7e..86a45e61ea 100644 --- a/cmds/servicemanager/main.cpp +++ b/cmds/servicemanager/main.cpp @@ -132,8 +132,7 @@ int main(int argc, char** argv) { IPCThreadState::self()->setTheContextObject(manager); if (!ps->becomeContextManager()) { - LOG(ERROR) << "Could not become context manager"; - // TODO(b/280514080): fatal + LOG(FATAL) << "Could not become context manager"; } sp looper = Looper::prepare(false /*allowNonCallbacks*/); -- GitLab From 8da4538c8daa4a3787f6f44af74c0b4bfbc9009a Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 11 May 2023 08:08:50 +0000 Subject: [PATCH 0115/1187] binderRecordReplayTest: test arrays Adding AIDL supported array types to record replay test Test: m binderRecordReplayTest && adb sync data && adb shell /data/nativetest64/binderRecordReplayTest/binderRecordReplayTest Bug: 279646634 Change-Id: I35471262c2cad5126173aa3139ee6938cdc802de --- libs/binder/tests/Android.bp | 8 + .../binder/tests/IBinderRecordReplayTest.aidl | 34 ++++ libs/binder/tests/binderRecordReplayTest.cpp | 170 +++++++++++++++--- 3 files changed, 185 insertions(+), 27 deletions(-) diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 4929b34714..5ab71581d3 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -76,6 +76,7 @@ cc_test { ], static_libs: [ "binderRecordReplayTestIface-cpp", + "binderReadParcelIface-cpp", ], test_suites: ["general-tests"], require_root: true, @@ -87,6 +88,13 @@ aidl_interface { srcs: [ "IBinderRecordReplayTest.aidl", ], + imports: ["binderReadParcelIface"], + backend: { + java: { + enabled: true, + platform_apis: true, + }, + }, } cc_test { diff --git a/libs/binder/tests/IBinderRecordReplayTest.aidl b/libs/binder/tests/IBinderRecordReplayTest.aidl index 2497277177..bd6b03c6e0 100644 --- a/libs/binder/tests/IBinderRecordReplayTest.aidl +++ b/libs/binder/tests/IBinderRecordReplayTest.aidl @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import parcelables.SingleDataParcelable; interface IBinderRecordReplayTest { void setByte(byte input); @@ -35,4 +36,37 @@ interface IBinderRecordReplayTest { void setDouble(double input); double getDouble(); + + void setString(String input); + String getString(); + + void setSingleDataParcelable(in SingleDataParcelable p); + SingleDataParcelable getSingleDataParcelable(); + + void setByteArray(in byte[] input); + byte[] getByteArray(); + + void setCharArray(in char[] input); + char[] getCharArray(); + + void setBooleanArray(in boolean[] input); + boolean[] getBooleanArray(); + + void setIntArray(in int[] input); + int[] getIntArray(); + + void setFloatArray(in float[] input); + float[] getFloatArray(); + + void setLongArray(in long[] input); + long[] getLongArray(); + + void setDoubleArray(in double[] input); + double[] getDoubleArray(); + + void setStringArray(in String[] input); + String[] getStringArray(); + + void setSingleDataParcelableArray(in SingleDataParcelable[] input); + SingleDataParcelable[] getSingleDataParcelableArray(); } diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp index 599889caf2..db7854679f 100644 --- a/libs/binder/tests/binderRecordReplayTest.cpp +++ b/libs/binder/tests/binderRecordReplayTest.cpp @@ -27,14 +27,29 @@ #include +#include "parcelables/SingleDataParcelable.h" + using namespace android; using android::binder::Status; using android::binder::debug::RecordedTransaction; +using parcelables::SingleDataParcelable; const String16 kServerName = String16("binderRecordReplay"); +#define GENERATE_GETTER_SETTER_PRIMITIVE(name, T) \ + Status set##name(T input) { \ + m##name = input; \ + return Status::ok(); \ + } \ + \ + Status get##name(T* output) { \ + *output = m##name; \ + return Status::ok(); \ + } \ + T m##name + #define GENERATE_GETTER_SETTER(name, T) \ - Status set##name(T input) { \ + Status set##name(const T& input) { \ m##name = input; \ return Status::ok(); \ } \ @@ -47,29 +62,42 @@ const String16 kServerName = String16("binderRecordReplay"); class MyRecordReplay : public BnBinderRecordReplayTest { public: - GENERATE_GETTER_SETTER(Boolean, bool); - GENERATE_GETTER_SETTER(Byte, int8_t); - GENERATE_GETTER_SETTER(Int, int); - GENERATE_GETTER_SETTER(Char, char16_t); - GENERATE_GETTER_SETTER(Long, int64_t); - GENERATE_GETTER_SETTER(Float, float); - GENERATE_GETTER_SETTER(Double, double); + GENERATE_GETTER_SETTER_PRIMITIVE(Boolean, bool); + GENERATE_GETTER_SETTER_PRIMITIVE(Byte, int8_t); + GENERATE_GETTER_SETTER_PRIMITIVE(Int, int); + GENERATE_GETTER_SETTER_PRIMITIVE(Char, char16_t); + GENERATE_GETTER_SETTER_PRIMITIVE(Long, int64_t); + GENERATE_GETTER_SETTER_PRIMITIVE(Float, float); + GENERATE_GETTER_SETTER_PRIMITIVE(Double, double); + + GENERATE_GETTER_SETTER(String, String16); + GENERATE_GETTER_SETTER(SingleDataParcelable, SingleDataParcelable); + + GENERATE_GETTER_SETTER(BooleanArray, std::vector); + GENERATE_GETTER_SETTER(ByteArray, std::vector); + GENERATE_GETTER_SETTER(IntArray, std::vector); + GENERATE_GETTER_SETTER(CharArray, std::vector); + GENERATE_GETTER_SETTER(LongArray, std::vector); + GENERATE_GETTER_SETTER(FloatArray, std::vector); + GENERATE_GETTER_SETTER(DoubleArray, std::vector); + GENERATE_GETTER_SETTER(StringArray, std::vector<::android::String16>); + GENERATE_GETTER_SETTER(SingleDataParcelableArray, std::vector); }; -class BinderClearBuf : public ::testing::Test { +class BinderRecordReplayTest : public ::testing::Test { public: void SetUp() override { // get the remote service - mBinder = defaultServiceManager()->getService(kServerName); - ASSERT_NE(nullptr, mBinder); - mInterface = interface_cast(mBinder); - mBpBinder = mBinder->remoteBinder(); + auto binder = defaultServiceManager()->getService(kServerName); + ASSERT_NE(nullptr, binder); + mInterface = interface_cast(binder); + mBpBinder = binder->remoteBinder(); ASSERT_NE(nullptr, mBpBinder); } - template - void recordReplay(Status (IBinderRecordReplayTest::*set)(T), T recordedValue, - Status (IBinderRecordReplayTest::*get)(T*), T changedValue) { + template + void recordReplay(Status (IBinderRecordReplayTest::*set)(T), U recordedValue, + Status (IBinderRecordReplayTest::*get)(U*), U changedValue) { base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec", O_RDWR | O_CREAT | O_CLOEXEC, 0666)); ASSERT_TRUE(fd.ok()); @@ -81,7 +109,7 @@ public: mBpBinder->stopRecordingBinder(); // test transaction does the thing we expect it to do - T output; + U output; status = (*mInterface.*get)(&output); EXPECT_TRUE(status.isOk()); EXPECT_EQ(output, recordedValue); @@ -103,8 +131,8 @@ public: // TODO: move logic to replay RecordedTransaction into RecordedTransaction Parcel data; data.setData(transaction->getDataParcel().data(), transaction->getDataParcel().dataSize()); - auto result = mBinder->remoteBinder()->transact(transaction->getCode(), data, nullptr, - transaction->getFlags()); + auto result = + mBpBinder->transact(transaction->getCode(), data, nullptr, transaction->getFlags()); // make sure recording does the thing we expect it to do EXPECT_EQ(OK, result); @@ -115,45 +143,133 @@ public: } private: - sp mBinder; sp mBpBinder; sp mInterface; }; -TEST_F(BinderClearBuf, RecordReplayRepeatByte) { +TEST_F(BinderRecordReplayTest, ReplayByte) { recordReplay(&IBinderRecordReplayTest::setByte, int8_t{122}, &IBinderRecordReplayTest::getByte, int8_t{90}); } -TEST_F(BinderClearBuf, RecordReplayRepeatBoolean) { +TEST_F(BinderRecordReplayTest, ReplayBoolean) { recordReplay(&IBinderRecordReplayTest::setBoolean, true, &IBinderRecordReplayTest::getBoolean, false); } -TEST_F(BinderClearBuf, RecordReplayRepeatChar) { +TEST_F(BinderRecordReplayTest, ReplayChar) { recordReplay(&IBinderRecordReplayTest::setChar, char16_t{'G'}, &IBinderRecordReplayTest::getChar, char16_t{'K'}); } -TEST_F(BinderClearBuf, RecordReplayRepeatInt) { +TEST_F(BinderRecordReplayTest, ReplayInt) { recordReplay(&IBinderRecordReplayTest::setInt, 3, &IBinderRecordReplayTest::getInt, 5); } -TEST_F(BinderClearBuf, RecordReplayRepeatFloat) { +TEST_F(BinderRecordReplayTest, ReplayFloat) { recordReplay(&IBinderRecordReplayTest::setFloat, 1.1f, &IBinderRecordReplayTest::getFloat, 22.0f); } -TEST_F(BinderClearBuf, RecordReplayRepeatLong) { +TEST_F(BinderRecordReplayTest, ReplayLong) { recordReplay(&IBinderRecordReplayTest::setLong, int64_t{1LL << 55}, &IBinderRecordReplayTest::getLong, int64_t{1LL << 12}); } -TEST_F(BinderClearBuf, RecordReplayRepeatDouble) { +TEST_F(BinderRecordReplayTest, ReplayDouble) { recordReplay(&IBinderRecordReplayTest::setDouble, 0.00, &IBinderRecordReplayTest::getDouble, 1.11); } +TEST_F(BinderRecordReplayTest, ReplayString) { + const ::android::String16& input1 = String16("This is saved string"); + const ::android::String16& input2 = String16("This is changed string"); + recordReplay(&IBinderRecordReplayTest::setString, input1, &IBinderRecordReplayTest::getString, + input2); +} + +TEST_F(BinderRecordReplayTest, ReplaySingleDataParcelable) { + SingleDataParcelable saved, changed; + saved.data = 3; + changed.data = 5; + recordReplay(&IBinderRecordReplayTest::setSingleDataParcelable, saved, + &IBinderRecordReplayTest::getSingleDataParcelable, changed); +} + +TEST_F(BinderRecordReplayTest, ReplayByteArray) { + std::vector savedArray = {uint8_t{255}, uint8_t{0}, uint8_t{127}}; + std::vector changedArray = {uint8_t{2}, uint8_t{7}, uint8_t{117}}; + recordReplay(&IBinderRecordReplayTest::setByteArray, savedArray, + &IBinderRecordReplayTest::getByteArray, changedArray); +} + +TEST_F(BinderRecordReplayTest, ReplayBooleanArray) { + std::vector savedArray = {true, false, true}; + std::vector changedArray = {false, true, false}; + recordReplay(&IBinderRecordReplayTest::setBooleanArray, savedArray, + &IBinderRecordReplayTest::getBooleanArray, changedArray); +} + +TEST_F(BinderRecordReplayTest, ReplayCharArray) { + std::vector savedArray = {char16_t{'G'}, char16_t{'L'}, char16_t{'K'}, char16_t{'T'}}; + std::vector changedArray = {char16_t{'X'}, char16_t{'Y'}, char16_t{'Z'}}; + recordReplay(&IBinderRecordReplayTest::setCharArray, savedArray, + &IBinderRecordReplayTest::getCharArray, changedArray); +} + +TEST_F(BinderRecordReplayTest, ReplayIntArray) { + std::vector savedArray = {12, 45, 178}; + std::vector changedArray = {32, 14, 78, 1899}; + recordReplay(&IBinderRecordReplayTest::setIntArray, savedArray, + &IBinderRecordReplayTest::getIntArray, changedArray); +} + +TEST_F(BinderRecordReplayTest, ReplayFloatArray) { + std::vector savedArray = {12.14f, 45.56f, 123.178f}; + std::vector changedArray = {0.00f, 14.0f, 718.1f, 1899.122f, 3268.123f}; + recordReplay(&IBinderRecordReplayTest::setFloatArray, savedArray, + &IBinderRecordReplayTest::getFloatArray, changedArray); +} + +TEST_F(BinderRecordReplayTest, ReplayLongArray) { + std::vector savedArray = {int64_t{1LL << 11}, int64_t{1LL << 55}, int64_t{1LL << 45}}; + std::vector changedArray = {int64_t{1LL << 1}, int64_t{1LL << 21}, int64_t{1LL << 33}, + int64_t{1LL << 63}}; + recordReplay(&IBinderRecordReplayTest::setLongArray, savedArray, + &IBinderRecordReplayTest::getLongArray, changedArray); +} + +TEST_F(BinderRecordReplayTest, ReplayDoubleArray) { + std::vector savedArray = {12.1412313, 45.561232, 123.1781111}; + std::vector changedArray = {0.00111, 14.32130, 712312318.19, 1899212.122, + 322168.122123}; + recordReplay(&IBinderRecordReplayTest::setDoubleArray, savedArray, + &IBinderRecordReplayTest::getDoubleArray, changedArray); +} + +TEST_F(BinderRecordReplayTest, ReplayStringArray) { + std::vector savedArray = {String16("This is saved value"), String16(), + String16("\0\0", 2), String16("\xF3\x01\xAC\xAD\x21\xAF")}; + + std::vector changedArray = {String16("This is changed value"), String16("\1\2", 30)}; + recordReplay(&IBinderRecordReplayTest::setStringArray, savedArray, + &IBinderRecordReplayTest::getStringArray, changedArray); +} + +TEST_F(BinderRecordReplayTest, ReplaySingleDataParcelableArray) { + SingleDataParcelable s1, s2, s3, s4, s5; + s1.data = 5213; + s2.data = 1512; + s3.data = 4233; + s4.data = 123124; + s5.data = 0; + std::vector saved = {s1, s2, s3}; + std::vector changed = {s4, s5}; + + recordReplay(&IBinderRecordReplayTest::setSingleDataParcelableArray, saved, + &IBinderRecordReplayTest::getSingleDataParcelableArray, changed); +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); -- GitLab From 00bec72f359e3c190bbb4896e5dc794de840f874 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Fri, 12 May 2023 19:26:03 +0000 Subject: [PATCH 0116/1187] [native] Migrate SkSurface creation to SkSurfaces factories Follow-up to http://review.skia.org/687639 Change-Id: I1cf13748fa8d15b1370cebe3b13d4c8bd5b61293 --- libs/renderengine/skia/AutoBackendTexture.cpp | 9 +++++---- libs/renderengine/skia/filters/GaussianBlurFilter.cpp | 5 +++-- services/surfaceflinger/RefreshRateOverlay.cpp | 3 ++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp index f3ef968d40..76fc92dd18 100644 --- a/libs/renderengine/skia/AutoBackendTexture.cpp +++ b/libs/renderengine/skia/AutoBackendTexture.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "ColorSpaces.h" #include "log/log_main.h" @@ -137,10 +138,10 @@ sk_sp AutoBackendTexture::getOrCreateSurface(ui::Dataspace dataspace, LOG_ALWAYS_FATAL_IF(!mIsOutputBuffer, "You can't generate a SkSurface for a read-only texture"); if (!mSurface.get() || mDataspace != dataspace) { sk_sp surface = - SkSurface::MakeFromBackendTexture(context, mBackendTexture, - kTopLeft_GrSurfaceOrigin, 0, mColorType, - toSkColorSpace(dataspace), nullptr, - releaseSurfaceProc, this); + SkSurfaces::WrapBackendTexture(context, mBackendTexture, + kTopLeft_GrSurfaceOrigin, 0, mColorType, + toSkColorSpace(dataspace), nullptr, + releaseSurfaceProc, this); if (surface.get()) { // The following ref will be counteracted by releaseProc, when SkSurface is discarded. ref(); diff --git a/libs/renderengine/skia/filters/GaussianBlurFilter.cpp b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp index 511d7c9350..a77d5bf97d 100644 --- a/libs/renderengine/skia/filters/GaussianBlurFilter.cpp +++ b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "include/gpu/GpuTypes.h" // from Skia #include #include @@ -45,8 +46,8 @@ sk_sp GaussianBlurFilter::generate(GrRecordingContext* context, const u // Create blur surface with the bit depth and colorspace of the original surface SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale), std::ceil(blurRect.height() * kInputScale)); - sk_sp surface = SkSurface::MakeRenderTarget(context, - skgpu::Budgeted::kNo, scaledInfo); + sk_sp surface = SkSurfaces::RenderTarget(context, + skgpu::Budgeted::kNo, scaledInfo); SkPaint paint; paint.setBlendMode(SkBlendMode::kSrc); diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index f1fd6db0a0..607bec2e3f 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -148,7 +148,8 @@ auto RefreshRateOverlay::SevenSegmentDrawer::draw(int displayFps, int renderFps, LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "RefreshRateOverlay: Buffer failed to allocate: %d", bufferStatus); - sk_sp surface = SkSurface::MakeRasterN32Premul(bufferWidth, bufferHeight); + sk_sp surface = SkSurfaces::Raster( + SkImageInfo::MakeN32Premul(bufferWidth, bufferHeight)); SkCanvas* canvas = surface->getCanvas(); canvas->setMatrix(canvasTransform); -- GitLab From d6e4ebb75557d7fabc0e788db39084f607a26a81 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 11 May 2023 23:12:08 +0000 Subject: [PATCH 0117/1187] Delete fds and binders in fuzzService Test: m servicemanager_fuzzer && adb sync data && adb shell /data/fuzz/x86_64/servicemanager_fuzzer/servicemanager_fuzzer Bug: 264303686 Change-Id: I025998fcdfb0a813e3521127a15e0681cf71bd4c --- .../tests/parcel_fuzzer/libbinder_driver.cpp | 94 ++++++++++++------- 1 file changed, 60 insertions(+), 34 deletions(-) diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index 8bef33f2ca..488a09ed83 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -37,47 +37,73 @@ void fuzzService(const sp& binder, FuzzedDataProvider&& provider) { } while (provider.remaining_bytes() > 0) { - // Most of the AIDL services will have small set of transaction codes. - uint32_t code = provider.ConsumeBool() ? provider.ConsumeIntegral() - : provider.ConsumeIntegralInRange(0, 100); - uint32_t flags = provider.ConsumeIntegral(); - Parcel data; - // for increased fuzz coverage - data.setEnforceNoDataAvail(provider.ConsumeBool()); + provider.PickValueInArray>({ + [&]() { + // Most of the AIDL services will have small set of transaction codes. + uint32_t code = provider.ConsumeBool() + ? provider.ConsumeIntegral() + : provider.ConsumeIntegralInRange(0, 100); + uint32_t flags = provider.ConsumeIntegral(); + Parcel data; + // for increased fuzz coverage + data.setEnforceNoDataAvail(provider.ConsumeBool()); - sp target = options.extraBinders.at( - provider.ConsumeIntegralInRange(0, options.extraBinders.size() - 1)); - options.writeHeader = [&target](Parcel* p, FuzzedDataProvider& provider) { - // most code will be behind checks that the head of the Parcel - // is exactly this, so make it easier for fuzzers to reach this - if (provider.ConsumeBool()) { - p->writeInterfaceToken(target->getInterfaceDescriptor()); - } - }; + sp target = options.extraBinders.at( + provider.ConsumeIntegralInRange(0, + options.extraBinders.size() - + 1)); + options.writeHeader = [&target](Parcel* p, FuzzedDataProvider& provider) { + // most code will be behind checks that the head of the Parcel + // is exactly this, so make it easier for fuzzers to reach this + if (provider.ConsumeBool()) { + p->writeInterfaceToken(target->getInterfaceDescriptor()); + } + }; - std::vector subData = provider.ConsumeBytes( - provider.ConsumeIntegralInRange(0, provider.remaining_bytes())); - fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), &options); + std::vector subData = provider.ConsumeBytes( + provider.ConsumeIntegralInRange(0, provider.remaining_bytes())); + fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), + &options); - Parcel reply; - // for increased fuzz coverage - reply.setEnforceNoDataAvail(provider.ConsumeBool()); - (void)target->transact(code, data, &reply, flags); + Parcel reply; + // for increased fuzz coverage + reply.setEnforceNoDataAvail(provider.ConsumeBool()); + (void)target->transact(code, data, &reply, flags); - // feed back in binders and fds that are returned from the service, so that - // we can fuzz those binders, and use the fds and binders to feed back into - // the binders - auto retBinders = reply.debugReadAllStrongBinders(); - options.extraBinders.insert(options.extraBinders.end(), retBinders.begin(), - retBinders.end()); - auto retFds = reply.debugReadAllFileDescriptors(); - for (size_t i = 0; i < retFds.size(); i++) { - options.extraFds.push_back(base::unique_fd(dup(retFds[i]))); - } + // feed back in binders and fds that are returned from the service, so that + // we can fuzz those binders, and use the fds and binders to feed back into + // the binders + auto retBinders = reply.debugReadAllStrongBinders(); + options.extraBinders.insert(options.extraBinders.end(), retBinders.begin(), + retBinders.end()); + auto retFds = reply.debugReadAllFileDescriptors(); + for (size_t i = 0; i < retFds.size(); i++) { + options.extraFds.push_back(base::unique_fd(dup(retFds[i]))); + } + }, + [&]() { + if (options.extraFds.size() == 0) { + return; + } + uint32_t toDelete = + provider.ConsumeIntegralInRange(0, + options.extraFds.size() - 1); + options.extraFds.erase(options.extraFds.begin() + toDelete); + }, + [&]() { + if (options.extraBinders.size() <= 1) { + return; + } + uint32_t toDelete = + provider.ConsumeIntegralInRange(0, + options.extraBinders.size() - + 1); + options.extraBinders.erase(options.extraBinders.begin() + toDelete); + }, + })(); } // invariants - auto ps = ProcessState::selfOrNull(); if (ps) { CHECK_EQ(0, ps->getThreadPoolMaxTotalThreadCount()) -- GitLab From e75c4fa460849a3ec8c1e90c53a3e4d4a61df1db Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Fri, 12 May 2023 21:14:14 +0000 Subject: [PATCH 0118/1187] Fuzz Gpu AIDL service Adding AIDL fuzzer for GPU service using fuzzService. Test: m gpu_service_fuzzer && adb sync data && adb shell /data/fuzz/x86_64/gpu_service_fuzzer/gpu_service_fuzzer Bug: 232439428 Change-Id: I123244a0c1fd4c2cf9d84b1b295f1e866d1d5ed8 --- services/gpuservice/tests/fuzzers/Android.bp | 26 +++++++++++++++++ .../tests/fuzzers/GpuServiceFuzzer.cpp | 29 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 services/gpuservice/tests/fuzzers/Android.bp create mode 100644 services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp diff --git a/services/gpuservice/tests/fuzzers/Android.bp b/services/gpuservice/tests/fuzzers/Android.bp new file mode 100644 index 0000000000..6bcc5e8601 --- /dev/null +++ b/services/gpuservice/tests/fuzzers/Android.bp @@ -0,0 +1,26 @@ +package { + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_fuzz { + name: "gpu_service_fuzzer", + defaults: [ + "service_fuzzer_defaults", + "fuzzer_disable_leaks", + ], + static_libs: [ + "liblog", + ], + fuzz_config: { + cc: [ + "paulthomson@google.com", + "pbaiget@google.com", + ], + triage_assignee: "waghpawan@google.com", + }, + include_dirs: ["frameworks/native/services/gpuservice/"], + srcs: ["GpuServiceFuzzer.cpp"], + shared_libs: [ + "libgpuservice", + ], +} diff --git a/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp new file mode 100644 index 0000000000..c2574a3fd3 --- /dev/null +++ b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 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 + +#include "GpuService.h" + +using ::android::fuzzService; +using ::android::GpuService; +using ::android::sp; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + sp gpuService = new GpuService(); + fuzzService(gpuService, FuzzedDataProvider(data, size)); + return 0; +} -- GitLab From ca3f638f9628fddd0f713c932cca8818c1898890 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 11 May 2023 23:23:26 +0000 Subject: [PATCH 0119/1187] libbinder: RpcServer protocol version error Return an error if you set an invalid protocol version on an RpcServer. Previously, this would cause errors later down the line. Bug: 278946301 Test: binderRpcTest Change-Id: Id496f1d39b2a32ce775e585f7690ae59503dc3aa --- libs/binder/RpcServer.cpp | 7 ++++++- libs/binder/RpcSession.cpp | 6 +----- libs/binder/RpcState.cpp | 12 ++++++++++++ libs/binder/RpcState.h | 2 ++ libs/binder/include/binder/RpcServer.h | 2 +- libs/binder/tests/binderRpcTest.cpp | 8 +++++--- libs/binder/tests/binderRpcTestService.cpp | 2 +- libs/binder/tests/binderRpcTestServiceTrusty.cpp | 4 +++- libs/binder/trusty/RpcServerTrusty.cpp | 2 +- libs/binder/trusty/include/binder/RpcServerTrusty.h | 4 +++- 10 files changed, 35 insertions(+), 14 deletions(-) diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 9282856f5c..1e91b7e5e2 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -123,8 +123,13 @@ size_t RpcServer::getMaxThreads() { return mMaxThreads; } -void RpcServer::setProtocolVersion(uint32_t version) { +bool RpcServer::setProtocolVersion(uint32_t version) { + if (!RpcState::validateProtocolVersion(version)) { + return false; + } + mProtocolVersion = version; + return true; } void RpcServer::setSupportedFileDescriptorTransportModes( diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index fbad0f7756..c3dee1650e 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -104,11 +104,7 @@ size_t RpcSession::getMaxOutgoingThreads() { } bool RpcSession::setProtocolVersionInternal(uint32_t version, bool checkStarted) { - if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT && - version != RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) { - ALOGE("Cannot start RPC session with version %u which is unknown (current protocol version " - "is %u).", - version, RPC_WIRE_PROTOCOL_VERSION); + if (!RpcState::validateProtocolVersion(version)) { return false; } diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 03fa69973d..ff35f5f35c 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -398,6 +398,18 @@ status_t RpcState::rpcRec( return OK; } +bool RpcState::validateProtocolVersion(uint32_t version) { + if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT && + version != RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) { + ALOGE("Cannot use RPC binder protocol version %u which is unknown (current protocol " + "version " + "is %u).", + version, RPC_WIRE_PROTOCOL_VERSION); + return false; + } + return true; +} + status_t RpcState::readNewSessionResponse(const sp& connection, const sp& session, uint32_t* version) { RpcNewSessionResponse response; diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h index 0e23ea7515..1fe71a5a78 100644 --- a/libs/binder/RpcState.h +++ b/libs/binder/RpcState.h @@ -63,6 +63,8 @@ public: RpcState(); ~RpcState(); + [[nodiscard]] static bool validateProtocolVersion(uint32_t version); + [[nodiscard]] status_t readNewSessionResponse(const sp& connection, const sp& session, uint32_t* version); [[nodiscard]] status_t sendConnectionInit(const sp& connection, diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h index 1001b64ede..1e3560d0fb 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -137,7 +137,7 @@ public: * used. However, this can be used in order to prevent newer protocol * versions from ever being used. This is expected to be useful for testing. */ - void setProtocolVersion(uint32_t version); + [[nodiscard]] bool setProtocolVersion(uint32_t version); /** * Set the supported transports for sending and receiving file descriptors. diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 287e077d40..4d028b4b9b 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -1353,7 +1353,7 @@ TEST_P(BinderRpcServerOnly, SetExternalServerTest) { base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR))); int sinkFd = sink.get(); auto server = RpcServer::make(newTlsFactory(std::get<0>(GetParam()))); - server->setProtocolVersion(std::get<1>(GetParam())); + ASSERT_TRUE(server->setProtocolVersion(std::get<1>(GetParam()))); ASSERT_FALSE(server->hasServer()); ASSERT_EQ(OK, server->setupExternalServer(std::move(sink))); ASSERT_TRUE(server->hasServer()); @@ -1369,7 +1369,7 @@ TEST_P(BinderRpcServerOnly, Shutdown) { auto addr = allocateSocketAddress(); auto server = RpcServer::make(newTlsFactory(std::get<0>(GetParam()))); - server->setProtocolVersion(std::get<1>(GetParam())); + ASSERT_TRUE(server->setProtocolVersion(std::get<1>(GetParam()))); ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str())); auto joinEnds = std::make_shared(); @@ -1418,7 +1418,9 @@ public: std::unique_ptr auth = std::make_unique()) { auto [socketType, rpcSecurity, certificateFormat, serverVersion] = param; auto rpcServer = RpcServer::make(newTlsFactory(rpcSecurity)); - rpcServer->setProtocolVersion(serverVersion); + if (!rpcServer->setProtocolVersion(serverVersion)) { + return AssertionFailure() << "Invalid protocol version: " << serverVersion; + } switch (socketType) { case SocketType::PRECONNECTED: { return AssertionFailure() << "Not supported by this test"; diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp index a9736d5ecd..5e83fbfab2 100644 --- a/libs/binder/tests/binderRpcTestService.cpp +++ b/libs/binder/tests/binderRpcTestService.cpp @@ -118,7 +118,7 @@ int main(int argc, char* argv[]) { auto certVerifier = std::make_shared(); sp server = RpcServer::make(newTlsFactory(rpcSecurity, certVerifier)); - server->setProtocolVersion(serverConfig.serverVersion); + CHECK(server->setProtocolVersion(serverConfig.serverVersion)); server->setMaxThreads(serverConfig.numThreads); server->setSupportedFileDescriptorTransportModes(serverSupportedFileDescriptorTransportModes); diff --git a/libs/binder/tests/binderRpcTestServiceTrusty.cpp b/libs/binder/tests/binderRpcTestServiceTrusty.cpp index 85573895e9..5c7a96af32 100644 --- a/libs/binder/tests/binderRpcTestServiceTrusty.cpp +++ b/libs/binder/tests/binderRpcTestServiceTrusty.cpp @@ -90,7 +90,9 @@ int main(void) { auto server = std::move(*serverOrErr); serverInfo.server = server; - serverInfo.server->setProtocolVersion(serverVersion); + if (!serverInfo.server->setProtocolVersion(serverVersion)) { + return EXIT_FAILURE; + } serverInfo.server->setPerSessionRootObject([=](const void* /*addrPtr*/, size_t /*len*/) { auto service = sp::make(); // Assign a unique connection identifier to service->port so diff --git a/libs/binder/trusty/RpcServerTrusty.cpp b/libs/binder/trusty/RpcServerTrusty.cpp index 68b000849c..8f643230d1 100644 --- a/libs/binder/trusty/RpcServerTrusty.cpp +++ b/libs/binder/trusty/RpcServerTrusty.cpp @@ -67,7 +67,7 @@ RpcServerTrusty::RpcServerTrusty(std::unique_ptr ctx, std::stri // 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. - mRpcServer->setProtocolVersion(0); + LOG_ALWAYS_FATAL_IF(!mRpcServer->setProtocolVersion(0)); if (mPortAcl) { // Initialize the array of pointers to uuids. diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h index 6678eb8fec..119f2a393f 100644 --- a/libs/binder/trusty/include/binder/RpcServerTrusty.h +++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h @@ -59,7 +59,9 @@ public: size_t msgMaxSize, std::unique_ptr rpcTransportCtxFactory = nullptr); - void setProtocolVersion(uint32_t version) { mRpcServer->setProtocolVersion(version); } + [[nodiscard]] bool setProtocolVersion(uint32_t version) { + return mRpcServer->setProtocolVersion(version); + } void setSupportedFileDescriptorTransportModes( const std::vector& modes) { mRpcServer->setSupportedFileDescriptorTransportModes(modes); -- GitLab From 77a13f5aaf9a10cafd92b97ebc1bfbbb3934b948 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 16 May 2023 17:59:25 +0000 Subject: [PATCH 0120/1187] libbinder_random_parcel: fuzz mult binders We fuzz multiple binders and those that they return internally. Now, we expose an API that allows you to fuzz a group of services at the same time. Test: servicemanager_fuzzer for a few minutes (CPP backend) Test: android.hardware.vibrator-service.example_fuzzer for a few minutes (NDK backend) Fixes: 282961568 Change-Id: I4f511243e0a743f67d52c7b3287c751cb96e0e50 --- .../fuzzbinder/libbinder_driver.h | 11 +++++++++++ .../fuzzbinder/libbinder_ndk_driver.h | 11 +++++++++++ libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp | 6 ++++-- .../tests/parcel_fuzzer/libbinder_ndk_driver.cpp | 9 +++++++++ 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h index a9a6197439..cb37cfaa27 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h @@ -19,7 +19,17 @@ #include #include +#include + namespace android { + +/** + * See fuzzService, but fuzzes multiple services at the same time. + * + * Consumes providers. + */ +void fuzzService(const std::vector>& binders, FuzzedDataProvider&& provider); + /** * Based on the random data in provider, construct an arbitrary number of * Parcel objects and send them to the service in serial. @@ -34,4 +44,5 @@ namespace android { * } */ void fuzzService(const sp& binder, FuzzedDataProvider&& provider); + } // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h index f2b782337c..d8bf87a58c 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h @@ -16,10 +16,21 @@ #pragma once +#include #include #include +#include + namespace android { + +/** + * See fuzzService, but fuzzes multiple services at the same time. + * + * Consumes providers. + */ +void fuzzService(const std::vector& binders, FuzzedDataProvider&& provider); + /** * Based on the random data in provider, construct an arbitrary number of * Parcel objects and send them to the service in serial. diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index 8bef33f2ca..216e6b5166 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -24,10 +24,12 @@ namespace android { void fuzzService(const sp& binder, FuzzedDataProvider&& provider) { - sp target; + fuzzService(std::vector>{binder}, std::move(provider)); +} +void fuzzService(const std::vector>& binders, FuzzedDataProvider&& provider) { RandomParcelOptions options{ - .extraBinders = {binder}, + .extraBinders = binders, .extraFds = {}, }; diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp index a1fb70131e..0b0ca34586 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp @@ -24,6 +24,15 @@ namespace android { +void fuzzService(const std::vector& binders, FuzzedDataProvider&& provider) { + std::vector> cppBinders; + for (const auto& binder : binders) { + cppBinders.push_back(binder.get()->getBinder()); + } + + fuzzService(cppBinders, std::move(provider)); +} + void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider) { fuzzService(binder->getBinder(), std::move(provider)); } -- GitLab From 3162ce055889c81e502b3a0b8ba4a3e96a7d0a2f Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Tue, 16 May 2023 22:41:00 +0000 Subject: [PATCH 0121/1187] Fixing test failure on hwasan builds Test: m binderRecordReplayTest && adb sync data && adb shell /data/nativetest64/binderRecordReplayTest/binderRecordReplayTest Bug: 282448807 Change-Id: I68625329ee42ba680689505f0fe82156bf27d9f8 --- libs/binder/tests/binderRecordReplayTest.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp index db7854679f..17d5c8a219 100644 --- a/libs/binder/tests/binderRecordReplayTest.cpp +++ b/libs/binder/tests/binderRecordReplayTest.cpp @@ -234,7 +234,7 @@ TEST_F(BinderRecordReplayTest, ReplayFloatArray) { TEST_F(BinderRecordReplayTest, ReplayLongArray) { std::vector savedArray = {int64_t{1LL << 11}, int64_t{1LL << 55}, int64_t{1LL << 45}}; std::vector changedArray = {int64_t{1LL << 1}, int64_t{1LL << 21}, int64_t{1LL << 33}, - int64_t{1LL << 63}}; + int64_t{1LL << 62}}; recordReplay(&IBinderRecordReplayTest::setLongArray, savedArray, &IBinderRecordReplayTest::getLongArray, changedArray); } @@ -251,7 +251,8 @@ TEST_F(BinderRecordReplayTest, ReplayStringArray) { std::vector savedArray = {String16("This is saved value"), String16(), String16("\0\0", 2), String16("\xF3\x01\xAC\xAD\x21\xAF")}; - std::vector changedArray = {String16("This is changed value"), String16("\1\2", 30)}; + std::vector changedArray = {String16("This is changed value"), + String16("\xF0\x90\x90\xB7\xE2\x82\xAC")}; recordReplay(&IBinderRecordReplayTest::setStringArray, savedArray, &IBinderRecordReplayTest::getStringArray, changedArray); } -- GitLab From 9f250b0ca6fd99bd5943955de3211e05eaa59dbc Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 16 May 2023 23:27:42 +0000 Subject: [PATCH 0122/1187] binderRpcTest: host requires vsock loopback Upgrade your kernels, folks! Bug: 187754872 Test: binderRpcTest with and without vsock_loopback enabled Change-Id: I72e1cc949533342ac819e1cbf3ff977380a33f33 --- libs/binder/tests/binderRpcTest.cpp | 10 +++++++++- libs/binder/tests/binderRpcTestService.cpp | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 287e077d40..d6aa6c636f 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -1120,7 +1120,7 @@ INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, ::testing::Values(true), ::testing::Values(true)), BinderRpc::PrintParamInfo); #else // BINDER_RPC_TO_TRUSTY_TEST -static bool testSupportVsockLoopback() { +bool testSupportVsockLoopback() { // We don't need to enable TLS to know if vsock is supported. unsigned int vsockPort = allocateVsockPort(); @@ -1220,7 +1220,15 @@ static std::vector testSocketTypes(bool hasPreconnected = true) { if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED); +#ifdef __BIONIC__ + // Devices may not have vsock support. AVF tests will verify whether they do, but + // we can't require it due to old kernels for the time being. static bool hasVsockLoopback = testSupportVsockLoopback(); +#else + // On host machines, we always assume we have vsock loopback. If we don't, the + // subsequent failures will be more clear than showing one now. + static bool hasVsockLoopback = true; +#endif if (hasVsockLoopback) { ret.push_back(SocketType::VSOCK); diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp index a9736d5ecd..66221c59bd 100644 --- a/libs/binder/tests/binderRpcTestService.cpp +++ b/libs/binder/tests/binderRpcTestService.cpp @@ -139,7 +139,8 @@ int main(int argc, char* argv[]) { CHECK_EQ(OK, server->setupRawSocketServer(std::move(socketFd))); break; case SocketType::VSOCK: - CHECK_EQ(OK, server->setupVsockServer(VMADDR_CID_LOCAL, serverConfig.vsockPort)); + CHECK_EQ(OK, server->setupVsockServer(VMADDR_CID_LOCAL, serverConfig.vsockPort)) + << "Need `sudo modprobe vsock_loopback`?"; break; case SocketType::INET: { CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort)); -- GitLab From 895ad6e36626b8bdf609eadc36d6ff49f1b38517 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 12 May 2023 20:15:25 +0000 Subject: [PATCH 0123/1187] Sanitize address for libinput tests We can't enable hwasan for libinput, or for host. On host, enable the regular address sanitizer. Bug: 271455682 Change-Id: I9e6938fdc3b834ab19642947ceb65f36356a6ca5 Test: presubmit --- libs/input/tests/Android.bp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index 42bdf57514..6aae25d6d7 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -44,12 +44,20 @@ cc_test { "-Wno-unused-parameter", ], sanitize: { + hwaddress: true, undefined: true, all_undefined: true, diag: { undefined: true, }, }, + target: { + host: { + sanitize: { + address: true, + }, + }, + }, shared_libs: [ "libbase", "libbinder", -- GitLab From bbd443fd6c2abb3e01dd0d4870a432421012ee54 Mon Sep 17 00:00:00 2001 From: Himanshu Jakhmola Date: Mon, 13 Mar 2023 16:00:47 +0530 Subject: [PATCH 0124/1187] Use cpu_number to index mapping Change applicable when compiling data from vals policywise. Instead of using cpu_number as index to access vals, use cpu_number to index mapping to get index for accessing vals for a cpu. CRs-Fixed: 3413580 Bug: 280947753 Test: CtsStatsdAtomHostTestCases.android.cts.statsdatom.cpu.CpuStatsTests#testCpuCyclesPerUidCluster Change-Id: Id17661c50bda4cd4aecee6c7658e97c718dd4ec4 --- libs/cputimeinstate/cputimeinstate.cpp | 32 ++++++++++++++++++-------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 706704ad34..4a7bd36202 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -55,6 +55,7 @@ static uint32_t gNPolicies = 0; static uint32_t gNCpus = 0; static std::vector> gPolicyFreqs; static std::vector> gPolicyCpus; +static std::vector gCpuIndexMap; static std::set gAllFreqs; static unique_fd gTisTotalMapFd; static unique_fd gTisMapFd; @@ -108,7 +109,7 @@ static bool initGlobals() { free(dirlist[i]); } free(dirlist); - + uint32_t max_cpu_number = 0; for (const auto &policy : policyFileNames) { std::vector freqs; for (const auto &name : {"available", "boost"}) { @@ -127,8 +128,19 @@ static bool initGlobals() { std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus"); auto cpus = readNumbersFromFile(path); if (!cpus) return false; + for (auto cpu : *cpus) { + if(cpu > max_cpu_number) + max_cpu_number = cpu; + } gPolicyCpus.emplace_back(*cpus); } + gCpuIndexMap = std::vector(max_cpu_number+1, -1); + uint32_t cpuorder = 0; + for (const auto &cpuList : gPolicyCpus) { + for (auto cpu : cpuList) { + gCpuIndexMap[cpu] = cpuorder++; + } + } gTisTotalMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_timeInState_total_time_in_state_map")}; @@ -277,7 +289,7 @@ std::optional>> getTotalCpuFreqTimes() { for (uint32_t policyIdx = 0; policyIdx < gNPolicies; ++policyIdx) { if (freqIdx >= gPolicyFreqs[policyIdx].size()) continue; for (const auto &cpu : gPolicyCpus[policyIdx]) { - out[policyIdx][freqIdx] += vals[cpu]; + out[policyIdx][freqIdx] += vals[gCpuIndexMap[cpu]]; } } } @@ -316,7 +328,8 @@ std::optional>> getUidCpuFreqTimes(uint32_t ui auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY : out[j].end(); for (const auto &cpu : gPolicyCpus[j]) { - std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus()); + std::transform(begin, end, std::begin(vals[gCpuIndexMap[cpu]].ar), begin, + std::plus()); } } } @@ -382,7 +395,8 @@ getUidsUpdatedCpuFreqTimes(uint64_t *lastUpdate) { auto end = nextOffset < gPolicyFreqs[i].size() ? begin + FREQS_PER_ENTRY : map[key.uid][i].end(); for (const auto &cpu : gPolicyCpus[i]) { - std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus()); + std::transform(begin, end, std::begin(vals[gCpuIndexMap[cpu]].ar), begin, + std::plus()); } } prevKey = key; @@ -437,8 +451,8 @@ std::optional getUidConcurrentTimes(uint32_t uid, bool retry) : ret.policy[policy].end(); for (const auto &cpu : gPolicyCpus[policy]) { - std::transform(policyBegin, policyEnd, std::begin(vals[cpu].policy), policyBegin, - std::plus()); + std::transform(policyBegin, policyEnd, std::begin(vals[gCpuIndexMap[cpu]].policy), + policyBegin, std::plus()); } } } @@ -506,8 +520,8 @@ std::optional> getUidsUpdatedCon : ret[key.uid].policy[policy].end(); for (const auto &cpu : gPolicyCpus[policy]) { - std::transform(policyBegin, policyEnd, std::begin(vals[cpu].policy), policyBegin, - std::plus()); + std::transform(policyBegin, policyEnd, std::begin(vals[gCpuIndexMap[cpu]].policy), + policyBegin, std::plus()); } } } while (prevKey = key, !getNextMapKey(gConcurrentMapFd, &prevKey, &key)); @@ -640,7 +654,7 @@ getAggregatedTaskCpuFreqTimes(pid_t tgid, const std::vector &aggregati auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY : map[key.aggregation_key][j].end(); for (const auto &cpu : gPolicyCpus[j]) { - std::transform(begin, end, std::begin(vals[cpu].ar), begin, + std::transform(begin, end, std::begin(vals[gCpuIndexMap[cpu]].ar), begin, std::plus()); } } -- GitLab From c034b3a9bc122e4df4f5ebadf45c585612ef80d3 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 5 Apr 2023 20:09:16 +0000 Subject: [PATCH 0125/1187] Do not allow wildcard matching in GL loader. Previously when ro.hardware.egl and ro.board.platform were not set, the loader would attempt to load the exact GLES drivers, and if it failed, it would attempt to use wildcard matching to find the GLES drivers. However, ro.hardware.egl must be set to point to the GLES drivers and hence wildcard matching should be disallowed. This patch makes sure the GL loader no longer uses that path if a device is launched in Android 14 and beyond. Bug: b/277100371 Test: boot Test: atest CtsAngleIntegrationHostTestCases Change-Id: Ie9221ba37947c7462de8321819543a4c67979f67 --- opengl/libs/EGL/Loader.cpp | 45 ++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index dd14bcfb55..6ea400721d 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -236,29 +237,22 @@ void* Loader::open(egl_connection_t* cnx) LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s", android::GraphicsEnv::getInstance().getDriverPath().c_str()); } - // Finally, try to load system driver. If ANGLE is the system driver - // (i.e. we are forcing the legacy system driver instead of ANGLE), use - // the driver suffix that was passed down from above. - if (shouldForceLegacyDriver) { - std::string suffix = android::GraphicsEnv::getInstance().getLegacySuffix(); - hnd = attempt_to_load_system_driver(cnx, suffix.c_str(), true); - } else { - // Start by searching for the library name appended by the system - // properties of the GLES userspace driver in both locations. - // i.e.: - // libGLES_${prop}.so, or: - // libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so - for (auto key : HAL_SUBNAME_KEY_PROPERTIES) { - auto prop = base::GetProperty(key, ""); - if (prop.empty()) { - continue; - } - hnd = attempt_to_load_system_driver(cnx, prop.c_str(), true); - if (hnd) { - break; - } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) { - failToLoadFromDriverSuffixProperty = true; - } + // Finally, try to load system driver. + // Start by searching for the library name appended by the system + // properties of the GLES userspace driver in both locations. + // i.e.: + // libGLES_${prop}.so, or: + // libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so + for (auto key : HAL_SUBNAME_KEY_PROPERTIES) { + auto prop = base::GetProperty(key, ""); + if (prop.empty()) { + continue; + } + hnd = attempt_to_load_system_driver(cnx, prop.c_str(), true); + if (hnd) { + break; + } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) { + failToLoadFromDriverSuffixProperty = true; } } } @@ -272,7 +266,10 @@ void* Loader::open(egl_connection_t* cnx) hnd = attempt_to_load_system_driver(cnx, nullptr, true); } - if (!hnd && !failToLoadFromDriverSuffixProperty) { + if (!hnd && !failToLoadFromDriverSuffixProperty && + property_get_int32("ro.vendor.api_level", 0) < __ANDROID_API_U__) { + // Still can't find the graphics drivers with the exact name. This time try to use wildcard + // matching if the device is launched before Android 14. hnd = attempt_to_load_system_driver(cnx, nullptr, false); } -- GitLab From e43d0d0159494220aa67bf47eff45788b52987d6 Mon Sep 17 00:00:00 2001 From: zijunzhao Date: Thu, 18 May 2023 19:29:02 +0000 Subject: [PATCH 0126/1187] Fix -Wnullable-to-nonnull-conversion error Fix the build errors like https://android-build.googleplex.com/builds/pending/P56005836/aosp_arm64-userdebug/latest/view/logs/build.log Bugs: b/245972273 Test: mm -j Change-Id: I8edeace5afddc2cf6783899c889a3f2a542156a3 --- libs/binder/MemoryHeapBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp index 8fe1d2bb3d..3da06ba4db 100644 --- a/libs/binder/MemoryHeapBase.cpp +++ b/libs/binder/MemoryHeapBase.cpp @@ -78,7 +78,7 @@ MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name) if (SEAL_FLAGS && (fcntl(fd, F_ADD_SEALS, SEAL_FLAGS) == -1)) { ALOGE("MemoryHeapBase: MemFD %s sealing with flags %x failed with error %s", name, SEAL_FLAGS, strerror(errno)); - munmap(mBase, mSize); + if (mNeedUnmap) munmap(mBase, mSize); mBase = nullptr; mSize = 0; close(fd); -- GitLab From 40ff9899891c89fd71f7a6d10f47de4bc2277ac3 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Fri, 19 May 2023 14:02:22 +0000 Subject: [PATCH 0127/1187] Add includes of android/hardware_buffer.h This will be removed from SkSurface.h in http://review.skia.org/700223 Change-Id: Ia174cb42fbf667c8e8d926d45eb32d76325f2c23 --- libs/renderengine/skia/AutoBackendTexture.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp index 76fc92dd18..fc9b4da8bf 100644 --- a/libs/renderengine/skia/AutoBackendTexture.cpp +++ b/libs/renderengine/skia/AutoBackendTexture.cpp @@ -24,6 +24,7 @@ #include #include +#include #include "ColorSpaces.h" #include "log/log_main.h" #include "utils/Trace.h" -- GitLab From 00777b2fcdc7d7a8e4afd7893731c31a7221ad1a Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Wed, 17 May 2023 20:20:33 +0000 Subject: [PATCH 0128/1187] Adding AIDL fuzzer for installd Fuzzing InstalldNativeService using fuzzService API. Test: m installd_service_fuzzer && adb sync data && adb shell /data/fuzz/x86_64/installd_service_fuzzer/installd_service_fuzzer Test: atest installd_service_test Bug: 232439428 Change-Id: I7dcb9d88e8971fcc355f863fea49bf26f23052d5 --- cmds/installd/tests/Android.bp | 32 ++++++++--- .../tests/fuzzers/InstalldServiceFuzzer.cpp | 53 +++++++++++++++++++ 2 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp index 07f73b9029..61fe316225 100644 --- a/cmds/installd/tests/Android.bp +++ b/cmds/installd/tests/Android.bp @@ -77,10 +77,8 @@ cc_test { }, } -cc_test { - name: "installd_service_test", - test_suites: ["device-tests"], - srcs: ["installd_service_test.cpp"], +cc_defaults { + name: "installd_service_test_defaults", cflags: [ "-Wall", "-Werror", @@ -106,8 +104,6 @@ cc_test { "liblogwrap", "libc++fs", ], - test_config: "installd_service_test.xml", - product_variables: { arc: { exclude_srcs: [ @@ -124,6 +120,14 @@ cc_test { }, } +cc_test { + name: "installd_service_test", + test_suites: ["device-tests"], + srcs: ["installd_service_test.cpp"], + defaults: ["installd_service_test_defaults"], + test_config: "installd_service_test.xml", +} + cc_test { name: "installd_dexopt_test", test_suites: ["device-tests"], @@ -209,3 +213,19 @@ cc_test { "liblog", ], } + +cc_fuzz { + name: "installd_service_fuzzer", + defaults: [ + "service_fuzzer_defaults", + "fuzzer_disable_leaks", + "installd_service_test_defaults", + ], + srcs: ["fuzzers/InstalldServiceFuzzer.cpp"], + fuzz_config: { + cc: [ + "android-package-manager-team@google.com", + ], + triage_assignee: "waghpawan@google.com", + }, +} diff --git a/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp b/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp new file mode 100644 index 0000000000..b1c6940207 --- /dev/null +++ b/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2023 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 + +#include "InstalldNativeService.h" +#include "dexopt.h" + +using ::android::fuzzService; +using ::android::sp; +using ::android::installd::InstalldNativeService; + +namespace android { +namespace installd { + +bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char* oat_dir, const char* apk_path, + const char* instruction_set) { + return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set); +} + +bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char* apk_path, + const char* instruction_set) { + return calculate_odex_file_path_default(path, apk_path, instruction_set); +} + +bool create_cache_path(char path[PKG_PATH_MAX], const char* src, const char* instruction_set) { + return create_cache_path_default(path, src, instruction_set); +} + +bool force_compile_without_image() { + return false; +} + +} // namespace installd +} // namespace android + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + auto service = sp::make(); + fuzzService(service, FuzzedDataProvider(data, size)); + return 0; +} \ No newline at end of file -- GitLab From f3f3991bc8475c36e51c74333acd13df55abbf2c Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Fri, 19 May 2023 11:20:05 -0700 Subject: [PATCH 0129/1187] Fix status log in getLatestVsyncEventData status.toString8 lists error code and message already formatted. Bug: 283421301 Test: ABTD Change-Id: Ica98e4d8a7c6aef39cc2223c458381a07341765d --- libs/gui/DisplayEventReceiver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index 6849a95d1e..67cbc7b111 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -99,7 +99,7 @@ status_t DisplayEventReceiver::getLatestVsyncEventData( if (mEventConnection != nullptr) { auto status = mEventConnection->getLatestVsyncEventData(outVsyncEventData); if (!status.isOk()) { - ALOGE("Failed to get latest vsync event data: %s", status.exceptionMessage().c_str()); + ALOGE("Failed to get latest vsync event data: %s", status.toString8().c_str()); return status.transactionError(); } return NO_ERROR; -- GitLab From 94134f25fef9f2fd7bff29148514a9eef9328c09 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Fri, 19 May 2023 18:24:14 +0000 Subject: [PATCH 0130/1187] Adding fuzzer to verify fuzzService functionality Adding a TestService which crashes and adding a fuzzer to fuzz this service. Whenever fuzzService is modified, this fuzzer should be run. It usually crashes in first few seconds. This fuzzer won't run on the infra Test: m test_service_fuzzer_should_crash && out/host/linux-x86/fuzz/x86_64/test_service_fuzzer_should_crash/test_service_fuzzer_should_crash Test: m test_service_fuzzer_should_crash && adb sync data && adb shell /data/fuzz/x86_64/test_service_fuzzer_should_crash/test_service_fuzzer_should_crash Bug: 282239388 Change-Id: I6b0da6a9dcf9708be5a6df2315c58b0bd38fbf9a --- .../parcel_fuzzer/test_fuzzer/Android.bp | 42 +++++++++++++++ .../test_fuzzer/ITestService.aidl | 24 +++++++++ .../test_fuzzer/TestServiceFuzzer.cpp | 51 +++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp create mode 100644 libs/binder/tests/parcel_fuzzer/test_fuzzer/ITestService.aidl create mode 100644 libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp new file mode 100644 index 0000000000..28da285128 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp @@ -0,0 +1,42 @@ +package { + default_applicable_licenses: ["frameworks_native_license"], +} + +aidl_interface { + name: "testServiceIface", + host_supported: true, + unstable: true, + srcs: [ + "ITestService.aidl", + ], + backend: { + java: { + enabled: true, + platform_apis: true, + }, + rust: { + enabled: true, + }, + }, +} + +// Adding this fuzzer to test the fuzzService functionality +cc_fuzz { + name: "test_service_fuzzer_should_crash", + defaults: [ + "service_fuzzer_defaults", + ], + static_libs: [ + "liblog", + "testServiceIface-cpp", + ], + host_supported: true, + srcs: ["TestServiceFuzzer.cpp"], + fuzz_config: { + triage_assignee: "waghpawan@google.com", + + // This fuzzer should be used only test fuzzService locally + fuzz_on_haiku_host: false, + fuzz_on_haiku_device: false, + }, +} diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/ITestService.aidl b/libs/binder/tests/parcel_fuzzer/test_fuzzer/ITestService.aidl new file mode 100644 index 0000000000..3eadc02387 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/ITestService.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2023 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. + */ + +interface ITestService { + + void setIntData(int input); + + void setCharData(char input); + + void setBooleanData(boolean input); +} \ No newline at end of file diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp new file mode 100644 index 0000000000..8907ea0c54 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023 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 +#include + +#include + +using android::fuzzService; +using android::sp; +using android::binder::Status; + +namespace android { +// This service is to verify that fuzzService is functioning properly +class TestService : public BnTestService { +public: + Status setIntData(int /*input*/) { + LOG_ALWAYS_FATAL("Expected crash in setIntData"); + return Status::ok(); + } + + Status setCharData(char16_t /*input*/) { + LOG_ALWAYS_FATAL("Expected crash in setCharData"); + return Status::ok(); + } + + Status setBooleanData(bool /*input*/) { + LOG_ALWAYS_FATAL("Expected crash in setBooleanData"); + return Status::ok(); + } +}; +} // namespace android + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + auto service = sp::make(); + fuzzService(service, FuzzedDataProvider(data, size)); + return 0; +} -- GitLab From 5255c97174dfacd6553aa0e1b4a70c925264eab5 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 19 May 2023 22:53:41 +0000 Subject: [PATCH 0131/1187] libbinder: save space for optional config options. Previously, we required user and userdebug vesions of this library to be the same, but now we can save some space. Bug: N/A Test: Android's SDK finalization script passes Change-Id: I6a5f2a04ea8bf4ff2253ad052ea757ce2031a27c --- libs/binder/Binder.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index 3e49656575..0f4a6cabde 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -58,15 +58,15 @@ static_assert(sizeof(BBinder) == 20); // global b/c b/230079120 - consistent symbol table #ifdef BINDER_RPC_DEV_SERVERS -bool kEnableRpcDevServers = true; +constexpr bool kEnableRpcDevServers = true; #else -bool kEnableRpcDevServers = false; +constexpr bool kEnableRpcDevServers = false; #endif #ifdef BINDER_ENABLE_RECORDING -bool kEnableRecording = true; +constexpr bool kEnableRecording = true; #else -bool kEnableRecording = false; +constexpr bool kEnableRecording = false; #endif // Log any reply transactions for which the data exceeds this size -- GitLab From ad841236efb964fa6150c793e8c273a120c3b8b7 Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Mon, 22 May 2023 13:14:14 -0700 Subject: [PATCH 0132/1187] Update gui fuzzer lib to use power ndk Bug: 280438886 Test: mm Change-Id: Iba0cb96d9c3b7001cc505f71d1c8cbf1f021576f --- libs/gui/fuzzer/Android.bp | 2 +- .../libgui_surfaceComposerClient_fuzzer.cpp | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp index 872b069b36..75bae7650f 100644 --- a/libs/gui/fuzzer/Android.bp +++ b/libs/gui/fuzzer/Android.bp @@ -46,7 +46,7 @@ cc_defaults { "android.hardware.configstore-utils", "android.hardware.graphics.bufferqueue@1.0", "android.hardware.graphics.bufferqueue@2.0", - "android.hardware.power-V4-cpp", + "android.hardware.power-V4-ndk", "android.hidl.token@1.0", "libSurfaceFlingerProp", "libgui", diff --git a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp index 57720dd513..20c007c308 100644 --- a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp +++ b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include +#include #include #include #include @@ -39,10 +39,13 @@ constexpr ui::ColorMode kColormodes[] = {ui::ColorMode::NATIVE, ui::ColorMode::BT2100_HLG, ui::ColorMode::DISPLAY_BT2020}; -constexpr hardware::power::Boost kBoost[] = { - hardware::power::Boost::INTERACTION, hardware::power::Boost::DISPLAY_UPDATE_IMMINENT, - hardware::power::Boost::ML_ACC, hardware::power::Boost::AUDIO_LAUNCH, - hardware::power::Boost::CAMERA_LAUNCH, hardware::power::Boost::CAMERA_SHOT, +constexpr aidl::android::hardware::power::Boost kBoost[] = { + aidl::android::hardware::power::Boost::INTERACTION, + aidl::android::hardware::power::Boost::DISPLAY_UPDATE_IMMINENT, + aidl::android::hardware::power::Boost::ML_ACC, + aidl::android::hardware::power::Boost::AUDIO_LAUNCH, + aidl::android::hardware::power::Boost::CAMERA_LAUNCH, + aidl::android::hardware::power::Boost::CAMERA_SHOT, }; constexpr gui::TouchOcclusionMode kMode[] = { @@ -284,7 +287,7 @@ void SurfaceComposerClientFuzzer::invokeSurfaceComposerClient() { SurfaceComposerClient::doUncacheBufferTransaction(mFdp.ConsumeIntegral()); SurfaceComposerClient::setDisplayBrightness(displayToken, getBrightness(&mFdp)); - hardware::power::Boost boostId = mFdp.PickValueInArray(kBoost); + aidl::android::hardware::power::Boost boostId = mFdp.PickValueInArray(kBoost); SurfaceComposerClient::notifyPowerBoost((int32_t)boostId); String8 surfaceName((mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes)).c_str()); -- GitLab From a1889805df06c4d9c501ea025dca86ed115c4954 Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Mon, 22 May 2023 21:29:09 +0000 Subject: [PATCH 0133/1187] surfaceflinger: move some libs from shared to static These libraries are only used by this process on a device and gain no benifit from being included as shared libraries. Moving them to static saves disk space, memory, and cpu cycles from the dynamic linker. With 3 reboots before and after I'm seeing average savings of 398885 bytes of storage space from installed files, 60KB private dirty memory, 403KB PSS from libraries/binary only, and 780KB PSS from everything in showmap. go/shared-to-static for more info on how this was determined. Test: m Bug: 280829178 Change-Id: Iafe01db89d55fe579b7c97832b0ed45298a424c4 --- services/displayservice/Android.bp | 12 +++++-- services/surfaceflinger/Android.bp | 11 +++--- .../CompositionEngine/Android.bp | 5 +-- services/surfaceflinger/TimeStats/Android.bp | 36 ++++++++++++------- 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/services/displayservice/Android.bp b/services/displayservice/Android.bp index 8681784405..c88f2fca83 100644 --- a/services/displayservice/Android.bp +++ b/services/displayservice/Android.bp @@ -23,7 +23,7 @@ package { default_applicable_licenses: ["frameworks_native_license"], } -cc_library_shared { +cc_library_static { name: "libdisplayservicehidl", srcs: [ @@ -37,18 +37,24 @@ cc_library_shared { "libgui", "libhidlbase", "libutils", + ], + + static_libs: [ "android.frameworks.displayservice@1.0", ], export_include_dirs: ["include"], export_shared_lib_headers: [ - "android.frameworks.displayservice@1.0", "libgui", "libutils", ], + export_static_lib_headers: [ + "android.frameworks.displayservice@1.0", + ], + cflags: [ "-Werror", "-Wall", - ] + ], } diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 5683a9280f..b355221f4b 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -27,6 +27,7 @@ cc_defaults { defaults: [ "android.hardware.graphics.composer3-ndk_shared", "librenderengine_deps", + "libtimestats_deps", "surfaceflinger_defaults", ], cflags: [ @@ -58,14 +59,12 @@ cc_defaults { "libGLESv2", "libgui", "libhidlbase", - "liblayers_proto", "liblog", "libnativewindow", "libpowermanager", "libprocessgroup", "libprotobuf-cpp-lite", "libsync", - "libtimestats", "libui", "libinput", "libutils", @@ -77,11 +76,13 @@ cc_defaults { "libcompositionengine", "libframetimeline", "libgui_aidl_static", + "liblayers_proto", "libperfetto_client_experimental", "librenderengine", "libscheduler", "libserviceutils", "libshaders", + "libtimestats", "libtonemap", ], header_libs: [ @@ -95,6 +96,7 @@ cc_defaults { "libcompositionengine", "librenderengine", "libserviceutils", + "libtimestats", ], export_shared_lib_headers: [ "android.hardware.graphics.allocator@2.0", @@ -106,7 +108,6 @@ cc_defaults { "android.hardware.graphics.composer@2.4", "libpowermanager", "libhidlbase", - "libtimestats", ], // TODO (marissaw): this library is not used by surfaceflinger. This is here so // the library compiled in a way that is accessible to system partition when running @@ -213,14 +214,12 @@ cc_defaults { "-DLOG_TAG=\"SurfaceFlinger\"", ], shared_libs: [ - "android.frameworks.displayservice@1.0", "android.hardware.configstore-utils", "android.hardware.configstore@1.0", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.allocator@3.0", "libbinder", "libcutils", - "libdisplayservicehidl", "libhidlbase", "liblog", "libprocessgroup", @@ -228,6 +227,8 @@ cc_defaults { "libutils", ], static_libs: [ + "android.frameworks.displayservice@1.0", + "libdisplayservicehidl", "libserviceutils", ], } diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index f3a0186e3e..702bd332b6 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -12,6 +12,7 @@ cc_defaults { defaults: [ "android.hardware.graphics.composer3-ndk_shared", "librenderengine_deps", + "libtimestats_deps", "surfaceflinger_defaults", ], cflags: [ @@ -30,18 +31,18 @@ cc_defaults { "libbase", "libcutils", "libgui", - "liblayers_proto", "liblog", "libnativewindow", "libprotobuf-cpp-lite", "libSurfaceFlingerProp", - "libtimestats", "libui", "libutils", ], static_libs: [ + "liblayers_proto", "libmath", "librenderengine", + "libtimestats", "libtonemap", "libaidlcommonsupport", "libprocessgroup", diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp index 4686eed54c..c3141be9db 100644 --- a/services/surfaceflinger/TimeStats/Android.bp +++ b/services/surfaceflinger/TimeStats/Android.bp @@ -7,14 +7,9 @@ package { default_applicable_licenses: ["frameworks_native_license"], } -cc_library { - name: "libtimestats", - srcs: [ - "TimeStats.cpp", - ], - header_libs: [ - "libscheduler_headers", - ], +cc_defaults { + name: "libtimestats_deps", + shared_libs: [ "android.hardware.graphics.composer@2.4", "libbase", @@ -22,17 +17,34 @@ cc_library { "liblog", "libprotobuf-cpp-lite", "libtimestats_atoms_proto", - "libtimestats_proto", "libui", "libutils", ], + + static_libs: [ + "libtimestats_proto", + ], + + export_static_lib_headers: [ + "libtimestats_proto", + ], +} + +cc_library { + name: "libtimestats", + defaults: [ + "libtimestats_deps", + ], + srcs: [ + "TimeStats.cpp", + ], + header_libs: [ + "libscheduler_headers", + ], export_include_dirs: ["."], export_header_lib_headers: [ "libscheduler_headers", ], - export_shared_lib_headers: [ - "libtimestats_proto", - ], cppflags: [ "-Wall", "-Werror", -- GitLab From 6681c02369f3af7558a239ed39961b8b972fa01c Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Mon, 15 May 2023 13:38:16 -0500 Subject: [PATCH 0134/1187] Skip window infos updates if no listeners This change fixes a bug where WindowInfosListenerInvoker's active message count is incremented for messages when there are no listeners. In this case, onWindowInfosReported is never called, leading to out-of-sync window infos once listeners are added back. This scenario may occur if system server dies. Bug: 279792237 Test: WindowInfosListenerInvokerTest, manual tested by killing system server Change-Id: If62f7cc56b48570f633e8e640006f020b053ea6f --- services/surfaceflinger/SurfaceFlinger.cpp | 44 ++-- services/surfaceflinger/SurfaceFlinger.h | 5 +- .../WindowInfosListenerInvoker.cpp | 148 ++++++----- .../WindowInfosListenerInvoker.h | 40 ++- .../fuzzer/surfaceflinger_fuzzers_utils.h | 2 +- .../surfaceflinger/tests/unittests/Android.bp | 1 + .../WindowInfosListenerInvokerTest.cpp | 244 ++++++++++++++++++ 7 files changed, 365 insertions(+), 119 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9c11e5f50f..a32da6c056 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2529,7 +2529,7 @@ bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expe } updateCursorAsync(); - updateInputFlinger(vsyncId); + updateInputFlinger(vsyncId, frameTime); if (mLayerTracingEnabled && !mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { // This will block and tracing should only be enabled for debugging. @@ -3723,7 +3723,7 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { doCommitTransactions(); } -void SurfaceFlinger::updateInputFlinger(VsyncId vsyncId) { +void SurfaceFlinger::updateInputFlinger(VsyncId vsyncId, TimePoint frameTime) { if (!mInputFlinger || (!mUpdateInputInfo && mInputWindowCommands.empty())) { return; } @@ -3735,8 +3735,6 @@ void SurfaceFlinger::updateInputFlinger(VsyncId vsyncId) { if (mUpdateInputInfo) { mUpdateInputInfo = false; updateWindowInfo = true; - mLastInputFlingerUpdateVsyncId = vsyncId; - mLastInputFlingerUpdateTimestamp = systemTime(); buildWindowInfos(windowInfos, displayInfos); } @@ -3758,17 +3756,18 @@ void SurfaceFlinger::updateInputFlinger(VsyncId vsyncId) { inputWindowCommands = std::move(mInputWindowCommands), inputFlinger = mInputFlinger, this, - visibleWindowsChanged]() { + visibleWindowsChanged, vsyncId, frameTime]() { ATRACE_NAME("BackgroundExecutor::updateInputFlinger"); if (updateWindowInfo) { mWindowInfosListenerInvoker - ->windowInfosChanged(std::move(windowInfos), std::move(displayInfos), + ->windowInfosChanged(gui::WindowInfosUpdate{std::move(windowInfos), + std::move(displayInfos), + ftl::to_underlying(vsyncId), + frameTime.ns()}, std::move( inputWindowCommands.windowInfosReportedListeners), /* forceImmediateCall= */ visibleWindowsChanged || - !inputWindowCommands.focusRequests.empty(), - mLastInputFlingerUpdateVsyncId, - mLastInputFlingerUpdateTimestamp); + !inputWindowCommands.focusRequests.empty()); } else { // If there are listeners but no changes to input windows, call the listeners // immediately. @@ -6143,27 +6142,14 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp result.append("\n"); result.append("Window Infos:\n"); - StringAppendF(&result, " input flinger update vsync id: %" PRId64 "\n", - ftl::to_underlying(mLastInputFlingerUpdateVsyncId)); - StringAppendF(&result, " input flinger update timestamp (ns): %" PRId64 "\n", - mLastInputFlingerUpdateTimestamp); + auto windowInfosDebug = mWindowInfosListenerInvoker->getDebugInfo(); + StringAppendF(&result, " max send vsync id: %" PRId64 "\n", + ftl::to_underlying(windowInfosDebug.maxSendDelayVsyncId)); + StringAppendF(&result, " max send delay (ns): %" PRId64 " ns\n", + windowInfosDebug.maxSendDelayDuration); + StringAppendF(&result, " unsent messages: %" PRIu32 "\n", + windowInfosDebug.pendingMessageCount); result.append("\n"); - - if (VsyncId unsentVsyncId = mWindowInfosListenerInvoker->getUnsentMessageVsyncId(); - unsentVsyncId != VsyncId()) { - StringAppendF(&result, " unsent input flinger update vsync id: %" PRId64 "\n", - ftl::to_underlying(unsentVsyncId)); - StringAppendF(&result, " unsent input flinger update timestamp (ns): %" PRId64 "\n", - mWindowInfosListenerInvoker->getUnsentMessageTimestamp()); - result.append("\n"); - } - - if (uint32_t pendingMessages = mWindowInfosListenerInvoker->getPendingMessageCount(); - pendingMessages != 0) { - StringAppendF(&result, " pending input flinger calls: %" PRIu32 "\n", - mWindowInfosListenerInvoker->getPendingMessageCount()); - result.append("\n"); - } } mat4 SurfaceFlinger::calculateColorMatrix(float saturation) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6b9ba8c32c..b7d2047671 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -718,7 +718,7 @@ private: void updateLayerHistory(const frontend::LayerSnapshot& snapshot); frontend::Update flushLifecycleUpdates() REQUIRES(kMainThreadContext); - void updateInputFlinger(VsyncId); + void updateInputFlinger(VsyncId vsyncId, TimePoint frameTime); void persistDisplayBrightness(bool needsComposite) REQUIRES(kMainThreadContext); void buildWindowInfos(std::vector& outWindowInfos, std::vector& outDisplayInfos); @@ -1250,9 +1250,6 @@ private: VsyncId mLastCommittedVsyncId; - VsyncId mLastInputFlingerUpdateVsyncId; - nsecs_t mLastInputFlingerUpdateTimestamp; - // If blurs should be enabled on this device. bool mSupportsBlur = false; std::atomic mFrameMissedCount = 0; diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index b2885fb9b4..20699ef123 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -16,8 +16,11 @@ #include #include +#include #include +#include +#include "BackgroundExecutor.h" #include "WindowInfosListenerInvoker.h" namespace android { @@ -26,7 +29,7 @@ using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; -using WindowInfosListenerVector = ftl::SmallVector, 3>; +using WindowInfosListenerVector = ftl::SmallVector, 3>; struct WindowInfosReportedListenerInvoker : gui::BnWindowInfosReportedListener, IBinder::DeathRecipient { @@ -86,45 +89,19 @@ void WindowInfosListenerInvoker::binderDied(const wp& who) { } void WindowInfosListenerInvoker::windowInfosChanged( - std::vector windowInfos, std::vector displayInfos, - WindowInfosReportedListenerSet reportedListeners, bool forceImmediateCall, VsyncId vsyncId, - nsecs_t timestamp) { - reportedListeners.insert(sp::fromExisting(this)); - auto callListeners = [this, windowInfos = std::move(windowInfos), - displayInfos = std::move(displayInfos), vsyncId, - timestamp](WindowInfosReportedListenerSet reportedListeners) mutable { - WindowInfosListenerVector windowInfosListeners; - { - std::scoped_lock lock(mListenersMutex); - for (const auto& [_, listener] : mWindowInfosListeners) { - windowInfosListeners.push_back(listener); - } - } - - auto reportedInvoker = - sp::make(windowInfosListeners, - std::move(reportedListeners)); - - gui::WindowInfosUpdate update(std::move(windowInfos), std::move(displayInfos), - ftl::to_underlying(vsyncId), timestamp); - - for (const auto& listener : windowInfosListeners) { - sp asBinder = IInterface::asBinder(listener); - - // linkToDeath is used here to ensure that the windowInfosReportedListeners - // are called even if one of the windowInfosListeners dies before - // calling onWindowInfosReported. - asBinder->linkToDeath(reportedInvoker); + gui::WindowInfosUpdate update, WindowInfosReportedListenerSet reportedListeners, + bool forceImmediateCall) { + WindowInfosListenerVector listeners; + { + std::scoped_lock lock{mMessagesMutex}; - auto status = listener->onWindowInfosChanged(update, reportedInvoker); - if (!status.isOk()) { - reportedInvoker->onWindowInfosReported(); - } + if (!mDelayInfo) { + mDelayInfo = DelayInfo{ + .vsyncId = update.vsyncId, + .frameTime = update.timestamp, + }; } - }; - { - std::scoped_lock lock(mMessagesMutex); // If there are unacked messages and this isn't a forced call, then return immediately. // If a forced window infos change doesn't happen first, the update will be sent after // the WindowInfosReportedListeners are called. If a forced window infos change happens or @@ -132,44 +109,87 @@ void WindowInfosListenerInvoker::windowInfosChanged( // will be dropped and the listeners will only be called with the latest info. This is done // to reduce the amount of binder memory used. if (mActiveMessageCount > 0 && !forceImmediateCall) { - mWindowInfosChangedDelayed = std::move(callListeners); - mUnsentVsyncId = vsyncId; - mUnsentTimestamp = timestamp; - mReportedListenersDelayed.merge(reportedListeners); + mDelayedUpdate = std::move(update); + mReportedListeners.merge(reportedListeners); + return; + } + + if (mDelayedUpdate) { + mDelayedUpdate.reset(); + } + + { + std::scoped_lock lock{mListenersMutex}; + for (const auto& [_, listener] : mWindowInfosListeners) { + listeners.push_back(listener); + } + } + if (CC_UNLIKELY(listeners.empty())) { + mReportedListeners.merge(reportedListeners); + mDelayInfo.reset(); return; } - mWindowInfosChangedDelayed = nullptr; - mUnsentVsyncId = VsyncId(); - mUnsentTimestamp = -1; - reportedListeners.merge(mReportedListenersDelayed); + reportedListeners.insert(sp::fromExisting(this)); + reportedListeners.merge(mReportedListeners); + mReportedListeners.clear(); + mActiveMessageCount++; + updateMaxSendDelay(); + mDelayInfo.reset(); } - callListeners(std::move(reportedListeners)); -} -binder::Status WindowInfosListenerInvoker::onWindowInfosReported() { - std::function callListeners; - WindowInfosReportedListenerSet reportedListeners; + auto reportedInvoker = + sp::make(listeners, std::move(reportedListeners)); - { - std::scoped_lock lock{mMessagesMutex}; - mActiveMessageCount--; - if (!mWindowInfosChangedDelayed || mActiveMessageCount > 0) { - return binder::Status::ok(); - } + for (const auto& listener : listeners) { + sp asBinder = IInterface::asBinder(listener); - mActiveMessageCount++; - callListeners = std::move(mWindowInfosChangedDelayed); - mWindowInfosChangedDelayed = nullptr; - mUnsentVsyncId = VsyncId(); - mUnsentTimestamp = -1; - reportedListeners = std::move(mReportedListenersDelayed); - mReportedListenersDelayed.clear(); + // linkToDeath is used here to ensure that the windowInfosReportedListeners + // are called even if one of the windowInfosListeners dies before + // calling onWindowInfosReported. + asBinder->linkToDeath(reportedInvoker); + + auto status = listener->onWindowInfosChanged(update, reportedInvoker); + if (!status.isOk()) { + reportedInvoker->onWindowInfosReported(); + } } +} - callListeners(std::move(reportedListeners)); +binder::Status WindowInfosListenerInvoker::onWindowInfosReported() { + BackgroundExecutor::getInstance().sendCallbacks({[this]() { + gui::WindowInfosUpdate update; + { + std::scoped_lock lock{mMessagesMutex}; + mActiveMessageCount--; + if (!mDelayedUpdate || mActiveMessageCount > 0) { + return; + } + update = std::move(*mDelayedUpdate); + mDelayedUpdate.reset(); + } + windowInfosChanged(std::move(update), {}, false); + }}); return binder::Status::ok(); } +WindowInfosListenerInvoker::DebugInfo WindowInfosListenerInvoker::getDebugInfo() { + std::scoped_lock lock{mMessagesMutex}; + updateMaxSendDelay(); + mDebugInfo.pendingMessageCount = mActiveMessageCount; + return mDebugInfo; +} + +void WindowInfosListenerInvoker::updateMaxSendDelay() { + if (!mDelayInfo) { + return; + } + nsecs_t delay = TimePoint::now().ns() - mDelayInfo->frameTime; + if (delay > mDebugInfo.maxSendDelayDuration) { + mDebugInfo.maxSendDelayDuration = delay; + mDebugInfo.maxSendDelayVsyncId = VsyncId{mDelayInfo->vsyncId}; + } +} + } // namespace android diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index ade607fc99..bc465a3a2b 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include @@ -40,26 +41,18 @@ public: void addWindowInfosListener(sp); void removeWindowInfosListener(const sp& windowInfosListener); - void windowInfosChanged(std::vector, std::vector, + void windowInfosChanged(gui::WindowInfosUpdate update, WindowInfosReportedListenerSet windowInfosReportedListeners, - bool forceImmediateCall, VsyncId vsyncId, nsecs_t timestamp); + bool forceImmediateCall); binder::Status onWindowInfosReported() override; - VsyncId getUnsentMessageVsyncId() { - std::scoped_lock lock(mMessagesMutex); - return mUnsentVsyncId; - } - - nsecs_t getUnsentMessageTimestamp() { - std::scoped_lock lock(mMessagesMutex); - return mUnsentTimestamp; - } - - uint32_t getPendingMessageCount() { - std::scoped_lock lock(mMessagesMutex); - return mActiveMessageCount; - } + struct DebugInfo { + VsyncId maxSendDelayVsyncId; + nsecs_t maxSendDelayDuration; + uint32_t pendingMessageCount; + }; + DebugInfo getDebugInfo(); protected: void binderDied(const wp& who) override; @@ -73,11 +66,16 @@ private: std::mutex mMessagesMutex; uint32_t mActiveMessageCount GUARDED_BY(mMessagesMutex) = 0; - std::function mWindowInfosChangedDelayed - GUARDED_BY(mMessagesMutex); - VsyncId mUnsentVsyncId GUARDED_BY(mMessagesMutex); - nsecs_t mUnsentTimestamp GUARDED_BY(mMessagesMutex) = -1; - WindowInfosReportedListenerSet mReportedListenersDelayed; + std::optional mDelayedUpdate GUARDED_BY(mMessagesMutex); + WindowInfosReportedListenerSet mReportedListeners; + + DebugInfo mDebugInfo GUARDED_BY(mMessagesMutex); + struct DelayInfo { + int64_t vsyncId; + nsecs_t frameTime; + }; + std::optional mDelayInfo GUARDED_BY(mMessagesMutex); + void updateMaxSendDelay() REQUIRES(mMessagesMutex); }; } // namespace android diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 534a8f3b87..8e208bc538 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -590,7 +590,7 @@ public: mFlinger->binderDied(display); mFlinger->onFirstRef(); - mFlinger->updateInputFlinger(VsyncId{0}); + mFlinger->updateInputFlinger(VsyncId{}, TimePoint{}); mFlinger->updateCursorAsync(); mutableScheduler().setVsyncConfig({.sfOffset = mFdp.ConsumeIntegral(), diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 84a8529cda..86af303744 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -139,6 +139,7 @@ cc_test { "VSyncReactorTest.cpp", "VsyncConfigurationTest.cpp", "VsyncScheduleTest.cpp", + "WindowInfosListenerInvokerTest.cpp", ], } diff --git a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp new file mode 100644 index 0000000000..af4971b063 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp @@ -0,0 +1,244 @@ +#include +#include +#include +#include +#include + +#include "BackgroundExecutor.h" +#include "WindowInfosListenerInvoker.h" +#include "android/gui/IWindowInfosReportedListener.h" + +namespace android { + +class WindowInfosListenerInvokerTest : public testing::Test { +protected: + WindowInfosListenerInvokerTest() : mInvoker(sp::make()) {} + + ~WindowInfosListenerInvokerTest() { + std::mutex mutex; + std::condition_variable cv; + bool flushComplete = false; + // Flush the BackgroundExecutor thread to ensure any scheduled tasks are complete. + // Otherwise, references those tasks hold may go out of scope before they are done + // executing. + BackgroundExecutor::getInstance().sendCallbacks({[&]() { + std::scoped_lock lock{mutex}; + flushComplete = true; + cv.notify_one(); + }}); + std::unique_lock lock{mutex}; + cv.wait(lock, [&]() { return flushComplete; }); + } + + sp mInvoker; +}; + +using WindowInfosUpdateConsumer = std::function&)>; + +class Listener : public gui::BnWindowInfosListener { +public: + Listener(WindowInfosUpdateConsumer consumer) : mConsumer(std::move(consumer)) {} + + binder::Status onWindowInfosChanged( + const gui::WindowInfosUpdate& update, + const sp& reportedListener) override { + mConsumer(update, reportedListener); + return binder::Status::ok(); + } + +private: + WindowInfosUpdateConsumer mConsumer; +}; + +// Test that WindowInfosListenerInvoker#windowInfosChanged calls a single window infos listener. +TEST_F(WindowInfosListenerInvokerTest, callsSingleListener) { + std::mutex mutex; + std::condition_variable cv; + + int callCount = 0; + + mInvoker->addWindowInfosListener( + sp::make([&](const gui::WindowInfosUpdate&, + const sp& reportedListener) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); + + reportedListener->onWindowInfosReported(); + })); + + BackgroundExecutor::getInstance().sendCallbacks( + {[this]() { mInvoker->windowInfosChanged({}, {}, false); }}); + + std::unique_lock lock{mutex}; + cv.wait(lock, [&]() { return callCount == 1; }); + EXPECT_EQ(callCount, 1); +} + +// Test that WindowInfosListenerInvoker#windowInfosChanged calls multiple window infos listeners. +TEST_F(WindowInfosListenerInvokerTest, callsMultipleListeners) { + std::mutex mutex; + std::condition_variable cv; + + int callCount = 0; + const int expectedCallCount = 3; + + for (int i = 0; i < expectedCallCount; i++) { + mInvoker->addWindowInfosListener(sp::make( + [&](const gui::WindowInfosUpdate&, + const sp& reportedListener) { + std::scoped_lock lock{mutex}; + callCount++; + if (callCount == expectedCallCount) { + cv.notify_one(); + } + + reportedListener->onWindowInfosReported(); + })); + } + + BackgroundExecutor::getInstance().sendCallbacks( + {[&]() { mInvoker->windowInfosChanged({}, {}, false); }}); + + std::unique_lock lock{mutex}; + cv.wait(lock, [&]() { return callCount == expectedCallCount; }); + EXPECT_EQ(callCount, expectedCallCount); +} + +// Test that WindowInfosListenerInvoker#windowInfosChanged delays sending a second message until +// after the WindowInfosReportedListener is called. +TEST_F(WindowInfosListenerInvokerTest, delaysUnackedCall) { + std::mutex mutex; + std::condition_variable cv; + + int callCount = 0; + + // Simulate a slow ack by not calling the WindowInfosReportedListener. + mInvoker->addWindowInfosListener(sp::make( + [&](const gui::WindowInfosUpdate&, const sp&) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); + })); + + BackgroundExecutor::getInstance().sendCallbacks({[&]() { + mInvoker->windowInfosChanged({}, {}, false); + mInvoker->windowInfosChanged({}, {}, false); + }}); + + { + std::unique_lock lock{mutex}; + cv.wait(lock, [&]() { return callCount == 1; }); + } + EXPECT_EQ(callCount, 1); + + // Ack the first message. + mInvoker->onWindowInfosReported(); + + { + std::unique_lock lock{mutex}; + cv.wait(lock, [&]() { return callCount == 2; }); + } + EXPECT_EQ(callCount, 2); +} + +// Test that WindowInfosListenerInvoker#windowInfosChanged immediately sends a second message when +// forceImmediateCall is true. +TEST_F(WindowInfosListenerInvokerTest, sendsForcedMessage) { + std::mutex mutex; + std::condition_variable cv; + + int callCount = 0; + const int expectedCallCount = 2; + + // Simulate a slow ack by not calling the WindowInfosReportedListener. + mInvoker->addWindowInfosListener(sp::make( + [&](const gui::WindowInfosUpdate&, const sp&) { + std::scoped_lock lock{mutex}; + callCount++; + if (callCount == expectedCallCount) { + cv.notify_one(); + } + })); + + BackgroundExecutor::getInstance().sendCallbacks({[&]() { + mInvoker->windowInfosChanged({}, {}, false); + mInvoker->windowInfosChanged({}, {}, true); + }}); + + { + std::unique_lock lock{mutex}; + cv.wait(lock, [&]() { return callCount == expectedCallCount; }); + } + EXPECT_EQ(callCount, expectedCallCount); +} + +// Test that WindowInfosListenerInvoker#windowInfosChanged skips old messages when more than one +// message is delayed. +TEST_F(WindowInfosListenerInvokerTest, skipsDelayedMessage) { + std::mutex mutex; + std::condition_variable cv; + + int64_t lastUpdateId = -1; + + // Simulate a slow ack by not calling the WindowInfosReportedListener. + mInvoker->addWindowInfosListener( + sp::make([&](const gui::WindowInfosUpdate& update, + const sp&) { + std::scoped_lock lock{mutex}; + lastUpdateId = update.vsyncId; + cv.notify_one(); + })); + + BackgroundExecutor::getInstance().sendCallbacks({[&]() { + mInvoker->windowInfosChanged({{}, {}, /* vsyncId= */ 1, 0}, {}, false); + mInvoker->windowInfosChanged({{}, {}, /* vsyncId= */ 2, 0}, {}, false); + mInvoker->windowInfosChanged({{}, {}, /* vsyncId= */ 3, 0}, {}, false); + }}); + + { + std::unique_lock lock{mutex}; + cv.wait(lock, [&]() { return lastUpdateId == 1; }); + } + EXPECT_EQ(lastUpdateId, 1); + + // Ack the first message. The third update should be sent. + mInvoker->onWindowInfosReported(); + + { + std::unique_lock lock{mutex}; + cv.wait(lock, [&]() { return lastUpdateId == 3; }); + } + EXPECT_EQ(lastUpdateId, 3); +} + +// Test that WindowInfosListenerInvoker#windowInfosChanged immediately calls listener after a call +// where no listeners were configured. +TEST_F(WindowInfosListenerInvokerTest, noListeners) { + std::mutex mutex; + std::condition_variable cv; + + int callCount = 0; + + // Test that calling windowInfosChanged without any listeners doesn't cause the next call to be + // delayed. + BackgroundExecutor::getInstance().sendCallbacks({[&]() { + mInvoker->windowInfosChanged({}, {}, false); + mInvoker->addWindowInfosListener(sp::make( + [&](const gui::WindowInfosUpdate&, const sp&) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); + })); + mInvoker->windowInfosChanged({}, {}, false); + }}); + + { + std::unique_lock lock{mutex}; + cv.wait(lock, [&]() { return callCount == 1; }); + } + EXPECT_EQ(callCount, 1); +} + +} // namespace android -- GitLab From dfb9218b34625b1639d28910848a5c206163cbab Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 24 May 2023 17:48:59 +0000 Subject: [PATCH 0135/1187] RPC binder: expose session to per-client roots Bug: 274156888 Test: N/A Change-Id: Iad721ebea7ddd461ed41f2ba1fc08849309f7611 --- libs/binder/RpcServer.cpp | 5 +++-- libs/binder/include/binder/RpcServer.h | 20 +++++++++++-------- libs/binder/tests/binderRpcTestService.cpp | 7 ++++++- .../tests/binderRpcTestServiceTrusty.cpp | 17 ++++++++-------- .../trusty/include/binder/RpcServerTrusty.h | 3 ++- 5 files changed, 32 insertions(+), 20 deletions(-) diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 00e040f3a4..55fc16de45 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -154,7 +154,7 @@ void RpcServer::setRootObjectWeak(const wp& binder) { mRootObjectWeak = binder; } void RpcServer::setPerSessionRootObject( - std::function(const void*, size_t)>&& makeObject) { + std::function(wp session, const void*, size_t)>&& makeObject) { RpcMutexLockGuard _l(mLock); mRootObject.clear(); mRootObjectWeak.clear(); @@ -515,7 +515,8 @@ void RpcServer::establishConnection( // if null, falls back to server root sp sessionSpecificRoot; if (server->mRootObjectFactory != nullptr) { - sessionSpecificRoot = server->mRootObjectFactory(addr.data(), addrLen); + sessionSpecificRoot = + server->mRootObjectFactory(wp(session), addr.data(), addrLen); if (sessionSpecificRoot == nullptr) { ALOGE("Warning: server returned null from root object factory"); } diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h index 56ac7b0c4f..b804f7b92a 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -163,14 +163,18 @@ public: * Allows a root object to be created for each session. * * Takes one argument: a callable that is invoked once per new session. - * The callable takes two arguments: a type-erased pointer to an OS- and - * transport-specific address structure, e.g., sockaddr_vm for vsock, and - * an integer representing the size in bytes of that structure. The - * callable should validate the size, then cast the type-erased pointer - * to a pointer to the actual type of the address, e.g., const void* to - * const sockaddr_vm*. + * The callable takes three arguments: + * - a weak pointer to the session. If you want to hold onto this in the root object, then + * you should keep a weak pointer, and promote it when needed. For instance, if you refer + * to this from the root object, then you could get ahold of transport-specific information. + * - a type-erased pointer to an OS- and transport-specific address structure, e.g., + * sockaddr_vm for vsock + * - an integer representing the size in bytes of that structure. The callable should + * validate the size, then cast the type-erased pointer to a pointer to the actual type of the + * address, e.g., const void* to const sockaddr_vm*. */ - void setPerSessionRootObject(std::function(const void*, size_t)>&& object); + void setPerSessionRootObject( + std::function(wp session, const void*, size_t)>&& object); sp getRootObject(); /** @@ -272,7 +276,7 @@ private: sp mRootObject; wp mRootObjectWeak; - std::function(const void*, size_t)> mRootObjectFactory; + std::function(wp, const void*, size_t)> mRootObjectFactory; std::function mConnectionFilter; std::function mServerSocketModifier; std::map, sp> mSessions; diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp index 5e83fbfab2..cb09a7fbab 100644 --- a/libs/binder/tests/binderRpcTestService.cpp +++ b/libs/binder/tests/binderRpcTestService.cpp @@ -164,7 +164,12 @@ int main(int argc, char* argv[]) { } } - server->setPerSessionRootObject([&](const void* addrPtr, size_t len) { + server->setPerSessionRootObject([&](wp session, const void* addrPtr, size_t len) { + { + sp spSession = session.promote(); + CHECK_NE(nullptr, spSession.get()); + } + // UNIX sockets with abstract addresses return // sizeof(sa_family_t)==2 in addrlen CHECK_GE(len, sizeof(sa_family_t)); diff --git a/libs/binder/tests/binderRpcTestServiceTrusty.cpp b/libs/binder/tests/binderRpcTestServiceTrusty.cpp index 5c7a96af32..cb632e95bf 100644 --- a/libs/binder/tests/binderRpcTestServiceTrusty.cpp +++ b/libs/binder/tests/binderRpcTestServiceTrusty.cpp @@ -93,14 +93,15 @@ int main(void) { if (!serverInfo.server->setProtocolVersion(serverVersion)) { return EXIT_FAILURE; } - serverInfo.server->setPerSessionRootObject([=](const void* /*addrPtr*/, size_t /*len*/) { - auto service = sp::make(); - // Assign a unique connection identifier to service->port so - // getClientPort returns a unique value per connection - service->port = ++gConnectionCounter; - service->server = server; - return service; - }); + serverInfo.server->setPerSessionRootObject( + [=](wp /*session*/, const void* /*addrPtr*/, size_t /*len*/) { + auto service = sp::make(); + // Assign a unique connection identifier to service->port so + // getClientPort returns a unique value per connection + service->port = ++gConnectionCounter; + service->server = server; + return service; + }); servers.push_back(std::move(serverInfo)); } diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h index 119f2a393f..8924b3679f 100644 --- a/libs/binder/trusty/include/binder/RpcServerTrusty.h +++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h @@ -68,7 +68,8 @@ public: } void setRootObject(const sp& binder) { mRpcServer->setRootObject(binder); } void setRootObjectWeak(const wp& binder) { mRpcServer->setRootObjectWeak(binder); } - void setPerSessionRootObject(std::function(const void*, size_t)>&& object) { + void setPerSessionRootObject( + std::function(wp session, const void*, size_t)>&& object) { mRpcServer->setPerSessionRootObject(std::move(object)); } sp getRootObject() { return mRpcServer->getRootObject(); } -- GitLab From 1ec890d9dd15888e4308798d2def23b54d875b57 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 24 May 2023 18:13:32 +0000 Subject: [PATCH 0136/1187] BpBinder fuzzer: wait longer This was timing out on ASAN builds. Fixes: 274084938 Test: binder_bpBinderFuzz for a few minutes Change-Id: I326f54c2cd06395304664737bee0407eff83b964 --- libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp index 910c9dc25c..a6fd487fe5 100644 --- a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp +++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp @@ -51,8 +51,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { sp session = RpcSession::make(); session->setMaxIncomingThreads(1); status_t status; - for (size_t tries = 0; tries < 5; tries++) { - usleep(10000); + + // b/274084938 - ASAN may be slow, wait a while + for (size_t tries = 0; tries < 50; tries++) { + usleep(100000); status = session->setupUnixDomainClient(addr.c_str()); if (status == OK) break; } -- GitLab From fd0f24d175cb2d67b75b49ea211c810e04a5f008 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Mon, 22 May 2023 21:39:41 +0000 Subject: [PATCH 0137/1187] Adding host script to run test fuzzer. Adding a test fuzzer which calls into TestService which aborts in implemented methods. This allows us to test fuzzService functionality. Adding sh_host_test which will run this test. Test: atest -c fuzz_service_test Bug: 282239388 Change-Id: I0bfff9b4b7ff124415206a7f40db0e88bee1962d --- .../parcel_fuzzer/test_fuzzer/Android.bp | 13 ++++++ .../test_fuzzer/fuzz_service_test_config.xml | 22 ++++++++++ .../test_fuzzer/run_fuzz_service_test.sh | 42 +++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml create mode 100644 libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp index 28da285128..e60ca22497 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp @@ -40,3 +40,16 @@ cc_fuzz { fuzz_on_haiku_device: false, }, } + +sh_test_host { + name: "fuzz_service_test", + src: "run_fuzz_service_test.sh", + filename: "run_fuzz_service_test.sh", + test_config: "fuzz_service_test_config.xml", + data_bins: [ + "test_service_fuzzer_should_crash", + ], + required: [ + "test_service_fuzzer_should_crash", + ], +} diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml b/libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml new file mode 100644 index 0000000000..19eb33a635 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml @@ -0,0 +1,22 @@ + + + + diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh new file mode 100644 index 0000000000..cec52fd6e7 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Copyright (C) 2023 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. + +color_success=$'\E'"[0;32m" +color_failed=$'\E'"[0;31m" +color_reset=$'\E'"[00m" + +FUZZER_NAME=test_service_fuzzer_should_crash +FUZZER_OUT=fuzzer-output + +if [ ! -f "$FUZZER_NAME" ] +then + echo -e "${color_failed}Binary $FUZZER_NAME does not exist" + echo "${color_reset}" + exit 1 +fi + +echo "INFO: Running fuzzer : test_service_fuzzer_should_crash" + +./test_service_fuzzer_should_crash -max_total_time=30 &>${FUZZER_OUT} + +echo "INFO: Searching fuzzer output for expected crashes" +if grep -q "Expected crash in set" ${FUZZER_OUT}; +then + echo -e "${color_success}Success: Found expected crash. fuzzService test successful!" +else + echo -e "${color_failed}Failed: Unable to find successful fuzzing output from test_service_fuzzer_should_crash" + echo "${color_reset}" + exit 1 +fi -- GitLab From a6091b6b3e4a8eda5b7016247585af0514ffc45f Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Tue, 23 May 2023 21:54:09 +0000 Subject: [PATCH 0138/1187] Adding fuzz_service_test to run at presubmit Test: TH Bug: 282239388 Change-Id: I252f3b20e3ba474a246f6f2c6a099229f417c9ba --- libs/binder/TEST_MAPPING | 3 +++ libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp | 1 + 2 files changed, 4 insertions(+) diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index 199574eb84..2b3ff4407a 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -63,6 +63,9 @@ { "name": "libbinderthreadstateutils_test" }, + { + "name": "fuzz_service_test" + }, { "name": "CtsOsTestCases", "options": [ diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp index e60ca22497..7b5928769c 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp @@ -52,4 +52,5 @@ sh_test_host { required: [ "test_service_fuzzer_should_crash", ], + test_suites: ["general-tests"], } -- GitLab From 5604403170aa7ba2aae1d9d2e394026fcd7e215e Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 24 May 2023 19:31:25 +0000 Subject: [PATCH 0139/1187] binderSafeInterfaceTest: over maxFds, not double This test is timing out, so test only 100 more calls than maxFds instead of double that number. This still will check against leaks, but limit the total time that this testcase takes to run. Fixes: 283165591 Test: binderSafeInterfaceTest Change-Id: Ib022d29905997f65bfe85b83a1ff01848d16bd3b --- libs/binder/tests/binderSafeInterfaceTest.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp index c857d62cb2..5e8a32a61b 100644 --- a/libs/binder/tests/binderSafeInterfaceTest.cpp +++ b/libs/binder/tests/binderSafeInterfaceTest.cpp @@ -35,6 +35,7 @@ #include +#include #include #include @@ -686,10 +687,12 @@ TEST_F(SafeInterfaceTest, TestIncrementNativeHandle) { // Determine the maximum number of fds this process can have open struct rlimit limit {}; ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &limit)); - uint32_t maxFds = static_cast(limit.rlim_cur); + uint64_t maxFds = limit.rlim_cur; + + ALOG(LOG_INFO, "SafeInterfaceTest", "%s max FDs: %" PRIu64, __PRETTY_FUNCTION__, maxFds); // Perform this test enough times to rule out fd leaks - for (uint32_t iter = 0; iter < (2 * maxFds); ++iter) { + for (uint32_t iter = 0; iter < (maxFds + 100); ++iter) { native_handle* handle = native_handle_create(1 /*numFds*/, 1 /*numInts*/); ASSERT_NE(nullptr, handle); handle->data[0] = dup(eventFd.get()); -- GitLab From dde4598f651fc427e58133a0e71285c6d8505243 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 24 May 2023 22:27:14 +0000 Subject: [PATCH 0140/1187] libbinder: limit RpcTransport visibility I always wanted to restrict the visibility of this class, but it proved difficult in the original RPC transport implementation. Now that we are considering adding more transports, I'm adding an explicit list of transports here. The reasoning is in the code. Bug: N/A Test: compile Change-Id: Ib841e6c1c7cb6b59a6ca3aa15bbd94e66be3f6e8 --- libs/binder/RpcTransportRaw.cpp | 4 --- libs/binder/RpcTransportTipcAndroid.cpp | 4 --- libs/binder/RpcTransportTls.cpp | 7 ++-- libs/binder/include/binder/RpcTransport.h | 36 +++++++++++++++++-- libs/binder/trusty/RpcTransportTipcTrusty.cpp | 4 --- 5 files changed, 37 insertions(+), 18 deletions(-) diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp index cd067bfee7..f3575cc7d8 100644 --- a/libs/binder/RpcTransportRaw.cpp +++ b/libs/binder/RpcTransportRaw.cpp @@ -29,8 +29,6 @@ namespace android { -namespace { - // RpcTransport with TLS disabled. class RpcTransportRaw : public RpcTransport { public: @@ -96,8 +94,6 @@ public: std::vector getCertificate(RpcCertificateFormat) const override { return {}; } }; -} // namespace - std::unique_ptr RpcTransportCtxFactoryRaw::newServerCtx() const { return std::make_unique(); } diff --git a/libs/binder/RpcTransportTipcAndroid.cpp b/libs/binder/RpcTransportTipcAndroid.cpp index d5a6da2e3d..0c81d83032 100644 --- a/libs/binder/RpcTransportTipcAndroid.cpp +++ b/libs/binder/RpcTransportTipcAndroid.cpp @@ -31,8 +31,6 @@ using android::base::Result; namespace android { -namespace { - // RpcTransport for writing Trusty IPC clients in Android. class RpcTransportTipcAndroid : public RpcTransport { public: @@ -217,8 +215,6 @@ public: std::vector getCertificate(RpcCertificateFormat) const override { return {}; } }; -} // namespace - std::unique_ptr RpcTransportCtxFactoryTipcAndroid::newServerCtx() const { return std::make_unique(); } diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp index 3e98ecca9b..785f6ce2ce 100644 --- a/libs/binder/RpcTransportTls.cpp +++ b/libs/binder/RpcTransportTls.cpp @@ -275,6 +275,8 @@ private: bssl::UniquePtr mSsl; }; +} // namespace + class RpcTransportTls : public RpcTransport { public: RpcTransportTls(RpcTransportFd socket, Ssl ssl) @@ -411,7 +413,8 @@ status_t RpcTransportTls::interruptableReadFully( } // For |ssl|, set internal FD to |fd|, and do handshake. Handshake is triggerable by |fdTrigger|. -bool setFdAndDoHandshake(Ssl* ssl, const android::RpcTransportFd& socket, FdTrigger* fdTrigger) { +static bool setFdAndDoHandshake(Ssl* ssl, const android::RpcTransportFd& socket, + FdTrigger* fdTrigger) { bssl::UniquePtr bio = newSocketBio(socket.fd); TEST_AND_RETURN(false, bio != nullptr); auto [_, errorQueue] = ssl->call(SSL_set_bio, bio.get(), bio.get()); @@ -540,8 +543,6 @@ protected: } }; -} // namespace - std::unique_ptr RpcTransportCtxFactoryTls::newServerCtx() const { return android::RpcTransportCtxTls::create(mCertVerifier, mAuth.get()); diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h index fd52a3a1a9..6db9ad983c 100644 --- a/libs/binder/include/binder/RpcTransport.h +++ b/libs/binder/include/binder/RpcTransport.h @@ -39,6 +39,16 @@ namespace android { class FdTrigger; struct RpcTransportFd; +// for 'friend' +class RpcTransportRaw; +class RpcTransportTls; +class RpcTransportTipcAndroid; +class RpcTransportTipcTrusty; +class RpcTransportCtxRaw; +class RpcTransportCtxTls; +class RpcTransportCtxTipcAndroid; +class RpcTransportCtxTipcTrusty; + // Represents a socket connection. // No thread-safety is guaranteed for these APIs. class RpcTransport { @@ -92,7 +102,21 @@ public: */ [[nodiscard]] virtual bool isWaiting() = 0; -protected: +private: + // limit the classes which can implement RpcTransport. Being able to change this + // interface is important to allow development of RPC binder. In the past, we + // changed this interface to use iovec for efficiency, and we added FDs to the + // interface. If another transport is needed, it should be added directly here. + // non-socket FDs likely also need changes in RpcSession in order to get + // connected, and similarly to how addrinfo was type-erased from RPC binder + // interfaces when RpcTransportTipc* was added, other changes may be needed + // to add more transports. + + friend class ::android::RpcTransportRaw; + friend class ::android::RpcTransportTls; + friend class ::android::RpcTransportTipcAndroid; + friend class ::android::RpcTransportTipcTrusty; + RpcTransport() = default; }; @@ -117,7 +141,13 @@ public: [[nodiscard]] virtual std::vector getCertificate( RpcCertificateFormat format) const = 0; -protected: +private: + // see comment on RpcTransport + friend class ::android::RpcTransportCtxRaw; + friend class ::android::RpcTransportCtxTls; + friend class ::android::RpcTransportCtxTipcAndroid; + friend class ::android::RpcTransportCtxTipcTrusty; + RpcTransportCtx() = default; }; @@ -140,7 +170,7 @@ protected: RpcTransportCtxFactory() = default; }; -struct RpcTransportFd { +struct RpcTransportFd final { private: mutable bool isPolling{false}; diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp index d249b2e1eb..692f82d6cd 100644 --- a/libs/binder/trusty/RpcTransportTipcTrusty.cpp +++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp @@ -29,8 +29,6 @@ namespace android { -namespace { - // RpcTransport for Trusty. class RpcTransportTipcTrusty : public RpcTransport { public: @@ -282,8 +280,6 @@ public: std::vector getCertificate(RpcCertificateFormat) const override { return {}; } }; -} // namespace - std::unique_ptr RpcTransportCtxFactoryTipcTrusty::newServerCtx() const { return std::make_unique(); } -- GitLab From 48abe6a88d407f662ca32bba9a4fd496a116586d Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 24 May 2023 22:35:38 +0000 Subject: [PATCH 0141/1187] libbinder_ndk_unit_test: shutdown wait time to 20s Servicemanager will shut down a service after 10s, but this appears to be hitting a race on certain devices. Switching to 20s to be safe. aidl_lazy_test is the main test testing these APIs. This is just supposed to test the NDK APIs. Bug: seeing in presubmit Test: libbinder_ndk_unit_test Change-Id: I71b18c917c739f41fffcca1f2250e450aa9d4703 --- libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 664894ebac..8c9844cde9 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -53,7 +53,7 @@ constexpr char kForcePersistNdkUnitTestService[] = "ForcePersistNdkUnitTestServi constexpr char kActiveServicesNdkUnitTestService[] = "ActiveServicesNdkUnitTestService"; constexpr char kBinderNdkUnitTestServiceFlagged[] = "BinderNdkUnitTestFlagged"; -constexpr unsigned int kShutdownWaitTime = 11; +constexpr unsigned int kShutdownWaitTime = 20; constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715; class MyTestFoo : public IFoo { -- GitLab From a525c455397d038604ed026e4889ef606843eced Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Mon, 22 May 2023 13:13:26 -0700 Subject: [PATCH 0142/1187] Update power manager benchmark to use power ndk Bug: 280438886 Test: mm Change-Id: I581a644af69eb54eb5b50199c77aa811e354ee67 --- services/powermanager/benchmarks/Android.bp | 3 +- .../benchmarks/PowerHalAidlBenchmarks.cpp | 62 ++++++++++--------- .../PowerHalControllerBenchmarks.cpp | 8 +-- .../benchmarks/PowerHalHidlBenchmarks.cpp | 8 +-- 4 files changed, 42 insertions(+), 39 deletions(-) diff --git a/services/powermanager/benchmarks/Android.bp b/services/powermanager/benchmarks/Android.bp index 4343aec227..03fc38d304 100644 --- a/services/powermanager/benchmarks/Android.bp +++ b/services/powermanager/benchmarks/Android.bp @@ -32,6 +32,7 @@ cc_benchmark { shared_libs: [ "libbase", "libbinder", + "libbinder_ndk", "libhidlbase", "liblog", "libpowermanager", @@ -40,7 +41,7 @@ cc_benchmark { "android.hardware.power@1.1", "android.hardware.power@1.2", "android.hardware.power@1.3", - "android.hardware.power-V4-cpp", + "android.hardware.power-V4-ndk", ], static_libs: [ "libtestUtil", diff --git a/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp index 6e5e14de28..759485ffce 100644 --- a/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp +++ b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp @@ -16,21 +16,24 @@ #define LOG_TAG "PowerHalAidlBenchmarks" -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include +#include +#include #include #include -using android::hardware::power::Boost; -using android::hardware::power::IPower; -using android::hardware::power::IPowerHintSession; -using android::hardware::power::Mode; -using android::hardware::power::WorkDuration; +using aidl::android::hardware::power::Boost; +using aidl::android::hardware::power::IPower; +using aidl::android::hardware::power::IPowerHintSession; +using aidl::android::hardware::power::Mode; +using aidl::android::hardware::power::WorkDuration; +using android::power::PowerHalLoader; using std::chrono::microseconds; using namespace android; @@ -63,15 +66,15 @@ static constexpr microseconds ONEWAY_API_DELAY = 100us; template static void runBenchmark(benchmark::State& state, microseconds delay, R (IPower::*fn)(Args0...), Args1&&... args1) { - sp hal = waitForVintfService(); + std::shared_ptr hal = PowerHalLoader::loadAidl(); if (hal == nullptr) { ALOGV("Power HAL not available, skipping test..."); return; } - binder::Status ret = (*hal.*fn)(std::forward(args1)...); - if (ret.exceptionCode() == binder::Status::Exception::EX_UNSUPPORTED_OPERATION) { + ndk::ScopedAStatus ret = (*hal.*fn)(std::forward(args1)...); + if (ret.getExceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { ALOGV("Power HAL does not support this operation, skipping test..."); return; } @@ -79,7 +82,7 @@ static void runBenchmark(benchmark::State& state, microseconds delay, R (IPower: while (state.KeepRunning()) { ret = (*hal.*fn)(std::forward(args1)...); state.PauseTiming(); - if (!ret.isOk()) state.SkipWithError(ret.toString8().c_str()); + if (!ret.isOk()) state.SkipWithError(ret.getDescription().c_str()); if (delay > 0us) { testDelaySpin(std::chrono::duration_cast>(delay).count()); } @@ -90,9 +93,9 @@ static void runBenchmark(benchmark::State& state, microseconds delay, R (IPower: template static void runSessionBenchmark(benchmark::State& state, R (IPowerHintSession::*fn)(Args0...), Args1&&... args1) { - sp pwHal = waitForVintfService(); + std::shared_ptr hal = PowerHalLoader::loadAidl(); - if (pwHal == nullptr) { + if (hal == nullptr) { ALOGV("Power HAL not available, skipping test..."); return; } @@ -100,32 +103,32 @@ static void runSessionBenchmark(benchmark::State& state, R (IPowerHintSession::* // do not use tid from the benchmark process, use 1 for init std::vector threadIds{1}; int64_t durationNanos = 16666666L; - sp hal; + std::shared_ptr session; - auto status = pwHal->createHintSession(1, 0, threadIds, durationNanos, &hal); + auto status = hal->createHintSession(1, 0, threadIds, durationNanos, &session); - if (hal == nullptr) { + if (session == nullptr) { ALOGV("Power HAL doesn't support session, skipping test..."); return; } - binder::Status ret = (*hal.*fn)(std::forward(args1)...); - if (ret.exceptionCode() == binder::Status::Exception::EX_UNSUPPORTED_OPERATION) { + ndk::ScopedAStatus ret = (*session.*fn)(std::forward(args1)...); + if (ret.getExceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { ALOGV("Power HAL does not support this operation, skipping test..."); return; } while (state.KeepRunning()) { - ret = (*hal.*fn)(std::forward(args1)...); + ret = (*session.*fn)(std::forward(args1)...); state.PauseTiming(); - if (!ret.isOk()) state.SkipWithError(ret.toString8().c_str()); + if (!ret.isOk()) state.SkipWithError(ret.getDescription().c_str()); if (ONEWAY_API_DELAY > 0us) { testDelaySpin(std::chrono::duration_cast>(ONEWAY_API_DELAY) .count()); } state.ResumeTiming(); } - hal->close(); + session->close(); } static void BM_PowerHalAidlBenchmarks_isBoostSupported(benchmark::State& state) { @@ -155,16 +158,17 @@ static void BM_PowerHalAidlBenchmarks_createHintSession(benchmark::State& state) int64_t durationNanos = 16666666L; int32_t tgid = 999; int32_t uid = 1001; - sp appSession; - sp hal = waitForVintfService(); + std::shared_ptr appSession; + std::shared_ptr hal = PowerHalLoader::loadAidl(); if (hal == nullptr) { ALOGV("Power HAL not available, skipping test..."); return; } - binder::Status ret = hal->createHintSession(tgid, uid, threadIds, durationNanos, &appSession); - if (ret.exceptionCode() == binder::Status::Exception::EX_UNSUPPORTED_OPERATION) { + ndk::ScopedAStatus ret = + hal->createHintSession(tgid, uid, threadIds, durationNanos, &appSession); + if (ret.getExceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { ALOGV("Power HAL does not support this operation, skipping test..."); return; } @@ -172,7 +176,7 @@ static void BM_PowerHalAidlBenchmarks_createHintSession(benchmark::State& state) while (state.KeepRunning()) { ret = hal->createHintSession(tgid, uid, threadIds, durationNanos, &appSession); state.PauseTiming(); - if (!ret.isOk()) state.SkipWithError(ret.toString8().c_str()); + if (!ret.isOk()) state.SkipWithError(ret.getDescription().c_str()); appSession->close(); state.ResumeTiming(); } diff --git a/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp index f8abc7aba6..effddda6a4 100644 --- a/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp +++ b/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp @@ -16,15 +16,15 @@ #define LOG_TAG "PowerHalControllerBenchmarks" -#include -#include +#include +#include #include #include #include #include -using android::hardware::power::Boost; -using android::hardware::power::Mode; +using aidl::android::hardware::power::Boost; +using aidl::android::hardware::power::Mode; using android::power::HalResult; using android::power::PowerHalController; diff --git a/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp index 167f3a64af..111b5d70bc 100644 --- a/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp +++ b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp @@ -16,10 +16,10 @@ #define LOG_TAG "PowerHalHidlBenchmarks" +#include +#include +#include #include -#include -#include -#include #include #include #include @@ -27,8 +27,6 @@ #include using android::hardware::Return; -using android::hardware::power::Boost; -using android::hardware::power::Mode; using android::hardware::power::V1_0::Feature; using android::hardware::power::V1_0::PowerHint; using std::chrono::microseconds; -- GitLab From 99f6f3cfd0ebc10af5fec9423323d5d73e01193a Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Mon, 22 May 2023 13:12:16 -0700 Subject: [PATCH 0143/1187] Update power manager to use power ndk Bug: 280438886 Test: atest libpowermanager_test libsurfaceflinger_unittest libcompositionengine_test Change-Id: I6bc17035665d5654b6becf71aa4e29ab9351cae8 --- include/powermanager/PowerHalController.h | 20 +-- include/powermanager/PowerHalLoader.h | 6 +- include/powermanager/PowerHalWrapper.h | 146 +++++++++++------- services/powermanager/Android.bp | 5 +- services/powermanager/PowerHalController.cpp | 23 +-- services/powermanager/PowerHalLoader.cpp | 30 +++- services/powermanager/PowerHalWrapper.cpp | 117 +++++--------- services/powermanager/tests/Android.bp | 4 +- .../tests/PowerHalControllerTest.cpp | 10 +- .../powermanager/tests/PowerHalLoaderTest.cpp | 38 ++--- .../tests/PowerHalWrapperAidlTest.cpp | 104 ++++++++----- .../tests/PowerHalWrapperHidlV1_0Test.cpp | 10 +- .../tests/PowerHalWrapperHidlV1_1Test.cpp | 10 +- .../tests/PowerHalWrapperHidlV1_2Test.cpp | 10 +- .../tests/PowerHalWrapperHidlV1_3Test.cpp | 10 +- services/surfaceflinger/Android.bp | 2 +- .../CompositionEngine/Android.bp | 2 +- .../DisplayHardware/PowerAdvisor.cpp | 20 +-- .../DisplayHardware/PowerAdvisor.h | 7 +- services/surfaceflinger/SurfaceFlinger.cpp | 4 +- .../surfaceflinger/tests/unittests/Android.bp | 2 +- .../tests/unittests/PowerAdvisorTest.cpp | 25 +-- .../SurfaceFlinger_NotifyPowerBoostTest.cpp | 4 +- .../mock/DisplayHardware/MockIPower.h | 31 ++-- .../DisplayHardware/MockIPowerHintSession.h | 30 ++-- .../DisplayHardware/MockPowerHalController.h | 9 +- 26 files changed, 373 insertions(+), 306 deletions(-) diff --git a/include/powermanager/PowerHalController.h b/include/powermanager/PowerHalController.h index 71a36d09e5..32ceb2805b 100644 --- a/include/powermanager/PowerHalController.h +++ b/include/powermanager/PowerHalController.h @@ -17,11 +17,11 @@ #ifndef ANDROID_POWERHALCONTROLLER_H #define ANDROID_POWERHALCONTROLLER_H +#include +#include +#include +#include #include -#include -#include -#include -#include #include namespace android { @@ -55,11 +55,13 @@ public: void init(); - virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override; - virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override; - virtual HalResult> createHintSession( - int32_t tgid, int32_t uid, const std::vector& threadIds, - int64_t durationNanos) override; + virtual HalResult setBoost(aidl::android::hardware::power::Boost boost, + int32_t durationMs) override; + virtual HalResult setMode(aidl::android::hardware::power::Mode mode, + bool enabled) override; + virtual HalResult> + createHintSession(int32_t tgid, int32_t uid, const std::vector& threadIds, + int64_t durationNanos) override; virtual HalResult getHintSessionPreferredRate() override; private: diff --git a/include/powermanager/PowerHalLoader.h b/include/powermanager/PowerHalLoader.h index e0384f31db..cbbfa597ba 100644 --- a/include/powermanager/PowerHalLoader.h +++ b/include/powermanager/PowerHalLoader.h @@ -17,11 +17,11 @@ #ifndef ANDROID_POWERHALLOADER_H #define ANDROID_POWERHALLOADER_H +#include #include #include #include #include -#include namespace android { @@ -31,7 +31,7 @@ namespace power { class PowerHalLoader { public: static void unloadAll(); - static sp loadAidl(); + static std::shared_ptr loadAidl(); static sp loadHidlV1_0(); static sp loadHidlV1_1(); static sp loadHidlV1_2(); @@ -39,7 +39,7 @@ public: private: static std::mutex gHalMutex; - static sp gHalAidl GUARDED_BY(gHalMutex); + static std::shared_ptr gHalAidl GUARDED_BY(gHalMutex); static sp gHalHidlV1_0 GUARDED_BY(gHalMutex); static sp gHalHidlV1_1 GUARDED_BY(gHalMutex); static sp gHalHidlV1_2 GUARDED_BY(gHalMutex); diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h index 8028aa86e1..4e4a1b000d 100644 --- a/include/powermanager/PowerHalWrapper.h +++ b/include/powermanager/PowerHalWrapper.h @@ -17,14 +17,15 @@ #ifndef ANDROID_POWERHALWRAPPER_H #define ANDROID_POWERHALWRAPPER_H +#include +#include +#include +#include #include #include #include #include -#include -#include -#include -#include +#include namespace android { @@ -47,7 +48,7 @@ public: } static HalResult unsupported() { return HalResult("", /* unsupported= */ true); } - static HalResult fromStatus(binder::Status status, T data) { + static HalResult fromStatus(const binder::Status& status, T data) { if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { return HalResult::unsupported(); } @@ -56,14 +57,28 @@ public: } return HalResult::failed(std::string(status.toString8().c_str())); } - static HalResult fromStatus(hardware::power::V1_0::Status status, T data); + + static HalResult fromStatus(const ndk::ScopedAStatus& status, T data) { + if (status.getExceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { + return HalResult::unsupported(); + } + if (status.isOk()) { + return HalResult::ok(data); + } + return HalResult::failed(std::string(status.getDescription())); + } template - static HalResult fromReturn(hardware::Return& ret, T data); + static HalResult fromReturn(hardware::Return& ret, T data) { + return ret.isOk() ? HalResult::ok(data) : HalResult::failed(ret.description()); + } template static HalResult fromReturn(hardware::Return& ret, hardware::power::V1_0::Status status, - T data); + T data) { + return ret.isOk() ? HalResult::fromStatus(status, data) + : HalResult::failed(ret.description()); + } // This will throw std::bad_optional_access if this result is not ok. const T& value() const { return mValue.value(); } @@ -91,12 +106,30 @@ public: static HalResult failed(std::string msg) { return HalResult(std::move(msg)); } static HalResult unsupported() { return HalResult(/* unsupported= */ true); } - static HalResult fromStatus(status_t status); - static HalResult fromStatus(binder::Status status); - static HalResult fromStatus(hardware::power::V1_0::Status status); + static HalResult fromStatus(const binder::Status& status) { + if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { + return HalResult::unsupported(); + } + if (status.isOk()) { + return HalResult::ok(); + } + return HalResult::failed(std::string(status.toString8().c_str())); + } + + static HalResult fromStatus(const ndk::ScopedAStatus& status) { + if (status.getExceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { + return HalResult::unsupported(); + } + if (status.isOk()) { + return HalResult::ok(); + } + return HalResult::failed(std::string(status.getDescription())); + } template - static HalResult fromReturn(hardware::Return& ret); + static HalResult fromReturn(hardware::Return& ret) { + return ret.isOk() ? HalResult::ok() : HalResult::failed(ret.description()); + } bool isOk() const { return !mUnsupported && !mFailed; } bool isFailed() const { return !mUnsupported && mFailed; } @@ -119,11 +152,12 @@ class HalWrapper { public: virtual ~HalWrapper() = default; - virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) = 0; - virtual HalResult setMode(hardware::power::Mode mode, bool enabled) = 0; - virtual HalResult> createHintSession( - int32_t tgid, int32_t uid, const std::vector& threadIds, - int64_t durationNanos) = 0; + virtual HalResult setBoost(aidl::android::hardware::power::Boost boost, + int32_t durationMs) = 0; + virtual HalResult setMode(aidl::android::hardware::power::Mode mode, bool enabled) = 0; + virtual HalResult> + createHintSession(int32_t tgid, int32_t uid, const std::vector& threadIds, + int64_t durationNanos) = 0; virtual HalResult getHintSessionPreferredRate() = 0; }; @@ -131,14 +165,15 @@ public: class EmptyHalWrapper : public HalWrapper { public: EmptyHalWrapper() = default; - ~EmptyHalWrapper() = default; + ~EmptyHalWrapper() override = default; - virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override; - virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override; - virtual HalResult> createHintSession( + HalResult setBoost(aidl::android::hardware::power::Boost boost, + int32_t durationMs) override; + HalResult setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + HalResult> createHintSession( int32_t tgid, int32_t uid, const std::vector& threadIds, int64_t durationNanos) override; - virtual HalResult getHintSessionPreferredRate() override; + HalResult getHintSessionPreferredRate() override; }; // Wrapper for the HIDL Power HAL v1.0. @@ -146,14 +181,15 @@ class HidlHalWrapperV1_0 : public HalWrapper { public: explicit HidlHalWrapperV1_0(sp handleV1_0) : mHandleV1_0(std::move(handleV1_0)) {} - virtual ~HidlHalWrapperV1_0() = default; + ~HidlHalWrapperV1_0() override = default; - virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override; - virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override; - virtual HalResult> createHintSession( + HalResult setBoost(aidl::android::hardware::power::Boost boost, + int32_t durationMs) override; + HalResult setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + HalResult> createHintSession( int32_t tgid, int32_t uid, const std::vector& threadIds, int64_t durationNanos) override; - virtual HalResult getHintSessionPreferredRate() override; + HalResult getHintSessionPreferredRate() override; protected: const sp mHandleV1_0; @@ -167,67 +203,71 @@ private: // Wrapper for the HIDL Power HAL v1.1. class HidlHalWrapperV1_1 : public HidlHalWrapperV1_0 { public: - HidlHalWrapperV1_1(sp handleV1_1) + explicit HidlHalWrapperV1_1(sp handleV1_1) : HidlHalWrapperV1_0(std::move(handleV1_1)) {} - virtual ~HidlHalWrapperV1_1() = default; + ~HidlHalWrapperV1_1() override = default; protected: - virtual HalResult sendPowerHint(hardware::power::V1_3::PowerHint hintId, - uint32_t data) override; + HalResult sendPowerHint(hardware::power::V1_3::PowerHint hintId, uint32_t data) override; }; // Wrapper for the HIDL Power HAL v1.2. class HidlHalWrapperV1_2 : public HidlHalWrapperV1_1 { public: - virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override; - virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override; - HidlHalWrapperV1_2(sp handleV1_2) + HalResult setBoost(aidl::android::hardware::power::Boost boost, + int32_t durationMs) override; + HalResult setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + explicit HidlHalWrapperV1_2(sp handleV1_2) : HidlHalWrapperV1_1(std::move(handleV1_2)) {} - virtual ~HidlHalWrapperV1_2() = default; + ~HidlHalWrapperV1_2() override = default; protected: - virtual HalResult sendPowerHint(hardware::power::V1_3::PowerHint hintId, - uint32_t data) override; + HalResult sendPowerHint(hardware::power::V1_3::PowerHint hintId, uint32_t data) override; }; // Wrapper for the HIDL Power HAL v1.3. class HidlHalWrapperV1_3 : public HidlHalWrapperV1_2 { public: - virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override; - HidlHalWrapperV1_3(sp handleV1_3) + HalResult setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + explicit HidlHalWrapperV1_3(sp handleV1_3) : HidlHalWrapperV1_2(std::move(handleV1_3)) {} - virtual ~HidlHalWrapperV1_3() = default; + ~HidlHalWrapperV1_3() override = default; protected: - virtual HalResult sendPowerHint(hardware::power::V1_3::PowerHint hintId, - uint32_t data) override; + HalResult sendPowerHint(hardware::power::V1_3::PowerHint hintId, uint32_t data) override; }; // Wrapper for the AIDL Power HAL. class AidlHalWrapper : public HalWrapper { public: - explicit AidlHalWrapper(sp handle) : mHandle(std::move(handle)) {} - virtual ~AidlHalWrapper() = default; - - virtual HalResult setBoost(hardware::power::Boost boost, int32_t durationMs) override; - virtual HalResult setMode(hardware::power::Mode mode, bool enabled) override; - virtual HalResult> createHintSession( + explicit AidlHalWrapper(std::shared_ptr handle) + : mHandle(std::move(handle)) {} + ~AidlHalWrapper() override = default; + + HalResult setBoost(aidl::android::hardware::power::Boost boost, + int32_t durationMs) override; + HalResult setMode(aidl::android::hardware::power::Mode mode, bool enabled) override; + HalResult> createHintSession( int32_t tgid, int32_t uid, const std::vector& threadIds, int64_t durationNanos) override; - virtual HalResult getHintSessionPreferredRate() override; + HalResult getHintSessionPreferredRate() override; private: // Control access to the boost and mode supported arrays. std::mutex mBoostMutex; std::mutex mModeMutex; - sp mHandle; + std::shared_ptr mHandle; // Android framework only sends boost upto DISPLAY_UPDATE_IMMINENT. // Need to increase the array size if more boost supported. - std::array, - static_cast(hardware::power::Boost::DISPLAY_UPDATE_IMMINENT) + 1> + std::array< + std::atomic, + static_cast(aidl::android::hardware::power::Boost::DISPLAY_UPDATE_IMMINENT) + + 1> mBoostSupportedArray GUARDED_BY(mBoostMutex) = {HalSupport::UNKNOWN}; std::array, - static_cast(*(android::enum_range().end() - 1)) + 1> + static_cast( + *(ndk::enum_range().end() - 1)) + + 1> mModeSupportedArray GUARDED_BY(mModeMutex) = {HalSupport::UNKNOWN}; }; diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp index b34e54fd6b..2523f3b6a6 100644 --- a/services/powermanager/Android.bp +++ b/services/powermanager/Android.bp @@ -33,6 +33,7 @@ cc_library_shared { shared_libs: [ "libbinder", + "libbinder_ndk", "libhidlbase", "liblog", "libutils", @@ -40,7 +41,7 @@ cc_library_shared { "android.hardware.power@1.1", "android.hardware.power@1.2", "android.hardware.power@1.3", - "android.hardware.power-V4-cpp", + "android.hardware.power-V4-ndk", ], export_shared_lib_headers: [ @@ -48,7 +49,7 @@ cc_library_shared { "android.hardware.power@1.1", "android.hardware.power@1.2", "android.hardware.power@1.3", - "android.hardware.power-V4-cpp", + "android.hardware.power-V4-ndk", ], cflags: [ diff --git a/services/powermanager/PowerHalController.cpp b/services/powermanager/PowerHalController.cpp index f89035fd1c..9a23c848c9 100644 --- a/services/powermanager/PowerHalController.cpp +++ b/services/powermanager/PowerHalController.cpp @@ -15,11 +15,11 @@ */ #define LOG_TAG "PowerHalController" +#include +#include +#include +#include #include -#include -#include -#include -#include #include #include #include @@ -33,7 +33,8 @@ namespace power { // ------------------------------------------------------------------------------------------------- std::unique_ptr HalConnector::connect() { - if (sp halAidl = PowerHalLoader::loadAidl()) { + if (std::shared_ptr halAidl = + PowerHalLoader::loadAidl()) { return std::make_unique(halAidl); } // If V1_0 isn't defined, none of them are @@ -90,20 +91,24 @@ HalResult PowerHalController::processHalResult(HalResult result, const cha return result; } -HalResult PowerHalController::setBoost(Boost boost, int32_t durationMs) { +HalResult PowerHalController::setBoost(aidl::android::hardware::power::Boost boost, + int32_t durationMs) { std::shared_ptr handle = initHal(); auto result = handle->setBoost(boost, durationMs); return processHalResult(result, "setBoost"); } -HalResult PowerHalController::setMode(Mode mode, bool enabled) { +HalResult PowerHalController::setMode(aidl::android::hardware::power::Mode mode, + bool enabled) { std::shared_ptr handle = initHal(); auto result = handle->setMode(mode, enabled); return processHalResult(result, "setMode"); } -HalResult> PowerHalController::createHintSession( - int32_t tgid, int32_t uid, const std::vector& threadIds, int64_t durationNanos) { +HalResult> +PowerHalController::createHintSession(int32_t tgid, int32_t uid, + const std::vector& threadIds, + int64_t durationNanos) { std::shared_ptr handle = initHal(); auto result = handle->createHintSession(tgid, uid, threadIds, durationNanos); return processHalResult(result, "createHintSession"); diff --git a/services/powermanager/PowerHalLoader.cpp b/services/powermanager/PowerHalLoader.cpp index 6bd40f8ff2..22144615da 100644 --- a/services/powermanager/PowerHalLoader.cpp +++ b/services/powermanager/PowerHalLoader.cpp @@ -16,10 +16,11 @@ #define LOG_TAG "PowerHalLoader" +#include +#include #include #include #include -#include #include #include #include @@ -54,7 +55,7 @@ sp loadHal(bool& exists, sp& hal, F& loadFn, const char* halName) { // ------------------------------------------------------------------------------------------------- std::mutex PowerHalLoader::gHalMutex; -sp PowerHalLoader::gHalAidl = nullptr; +std::shared_ptr PowerHalLoader::gHalAidl = nullptr; sp PowerHalLoader::gHalHidlV1_0 = nullptr; sp PowerHalLoader::gHalHidlV1_1 = nullptr; sp PowerHalLoader::gHalHidlV1_2 = nullptr; @@ -69,11 +70,30 @@ void PowerHalLoader::unloadAll() { gHalHidlV1_3 = nullptr; } -sp PowerHalLoader::loadAidl() { +std::shared_ptr PowerHalLoader::loadAidl() { std::lock_guard lock(gHalMutex); static bool gHalExists = true; - static auto loadFn = []() { return waitForVintfService(); }; - return loadHal(gHalExists, gHalAidl, loadFn, "AIDL"); + if (!gHalExists) { + return nullptr; + } + if (gHalAidl) { + return gHalAidl; + } + auto aidlServiceName = + std::string(aidl::android::hardware::power::IPower::descriptor) + "/default"; + if (!AServiceManager_isDeclared(aidlServiceName.c_str())) { + gHalExists = false; + return nullptr; + } + gHalAidl = aidl::android::hardware::power::IPower::fromBinder( + ndk::SpAIBinder(AServiceManager_waitForService(aidlServiceName.c_str()))); + if (gHalAidl) { + ALOGI("Successfully connected to Power HAL AIDL service."); + } else { + ALOGI("Power HAL AIDL service not available."); + gHalExists = false; + } + return gHalAidl; } sp PowerHalLoader::loadHidlV1_0() { diff --git a/services/powermanager/PowerHalWrapper.cpp b/services/powermanager/PowerHalWrapper.cpp index 9e7adf8e5c..76afbfc646 100644 --- a/services/powermanager/PowerHalWrapper.cpp +++ b/services/powermanager/PowerHalWrapper.cpp @@ -15,86 +15,49 @@ */ #define LOG_TAG "HalWrapper" -#include -#include -#include +#include +#include +#include #include #include #include using namespace android::hardware::power; -namespace Aidl = android::hardware::power; +namespace Aidl = aidl::android::hardware::power; namespace android { namespace power { // ------------------------------------------------------------------------------------------------- - -inline HalResult toHalResult(const binder::Status& result) { +inline HalResult toHalResult(const ndk::ScopedAStatus& result) { if (result.isOk()) { return HalResult::ok(); } - ALOGE("Power HAL request failed: %s", result.toString8().c_str()); - return HalResult::fromStatus(result); -} - -template -template -HalResult HalResult::fromReturn(hardware::Return& ret, T data) { - return ret.isOk() ? HalResult::ok(data) : HalResult::failed(ret.description()); -} - -template -template -HalResult HalResult::fromReturn(hardware::Return& ret, V1_0::Status status, T data) { - return ret.isOk() ? HalResult::fromStatus(status, data) - : HalResult::failed(ret.description()); -} - -// ------------------------------------------------------------------------------------------------- - -HalResult HalResult::fromStatus(status_t status) { - if (status == android::OK) { - return HalResult::ok(); - } - return HalResult::failed(statusToString(status)); + ALOGE("Power HAL request failed: %s", result.getDescription().c_str()); + return HalResult::failed(result.getDescription()); } -HalResult HalResult::fromStatus(binder::Status status) { - if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) { - return HalResult::unsupported(); - } - if (status.isOk()) { - return HalResult::ok(); - } - return HalResult::failed(std::string(status.toString8().c_str())); -} - -template -HalResult HalResult::fromReturn(hardware::Return& ret) { - return ret.isOk() ? HalResult::ok() : HalResult::failed(ret.description()); -} // ------------------------------------------------------------------------------------------------- -HalResult EmptyHalWrapper::setBoost(Boost boost, int32_t durationMs) { +HalResult EmptyHalWrapper::setBoost(Aidl::Boost boost, int32_t durationMs) { ALOGV("Skipped setBoost %s with duration %dms because Power HAL not available", toString(boost).c_str(), durationMs); return HalResult::unsupported(); } -HalResult EmptyHalWrapper::setMode(Mode mode, bool enabled) { +HalResult EmptyHalWrapper::setMode(Aidl::Mode mode, bool enabled) { ALOGV("Skipped setMode %s to %s because Power HAL not available", toString(mode).c_str(), enabled ? "true" : "false"); return HalResult::unsupported(); } -HalResult> EmptyHalWrapper::createHintSession( +HalResult> EmptyHalWrapper::createHintSession( int32_t, int32_t, const std::vector& threadIds, int64_t) { ALOGV("Skipped createHintSession(task num=%zu) because Power HAL not available", threadIds.size()); - return HalResult>::unsupported(); + return HalResult>::unsupported(); } HalResult EmptyHalWrapper::getHintSessionPreferredRate() { @@ -104,8 +67,8 @@ HalResult EmptyHalWrapper::getHintSessionPreferredRate() { // ------------------------------------------------------------------------------------------------- -HalResult HidlHalWrapperV1_0::setBoost(Boost boost, int32_t durationMs) { - if (boost == Boost::INTERACTION) { +HalResult HidlHalWrapperV1_0::setBoost(Aidl::Boost boost, int32_t durationMs) { + if (boost == Aidl::Boost::INTERACTION) { return sendPowerHint(V1_3::PowerHint::INTERACTION, durationMs); } else { ALOGV("Skipped setBoost %s because Power HAL AIDL not available", toString(boost).c_str()); @@ -113,20 +76,20 @@ HalResult HidlHalWrapperV1_0::setBoost(Boost boost, int32_t durationMs) { } } -HalResult HidlHalWrapperV1_0::setMode(Mode mode, bool enabled) { +HalResult HidlHalWrapperV1_0::setMode(Aidl::Mode mode, bool enabled) { uint32_t data = enabled ? 1 : 0; switch (mode) { - case Mode::LAUNCH: + case Aidl::Mode::LAUNCH: return sendPowerHint(V1_3::PowerHint::LAUNCH, data); - case Mode::LOW_POWER: + case Aidl::Mode::LOW_POWER: return sendPowerHint(V1_3::PowerHint::LOW_POWER, data); - case Mode::SUSTAINED_PERFORMANCE: + case Aidl::Mode::SUSTAINED_PERFORMANCE: return sendPowerHint(V1_3::PowerHint::SUSTAINED_PERFORMANCE, data); - case Mode::VR: + case Aidl::Mode::VR: return sendPowerHint(V1_3::PowerHint::VR_MODE, data); - case Mode::INTERACTIVE: + case Aidl::Mode::INTERACTIVE: return setInteractive(enabled); - case Mode::DOUBLE_TAP_TO_WAKE: + case Aidl::Mode::DOUBLE_TAP_TO_WAKE: return setFeature(V1_0::Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, enabled); default: ALOGV("Skipped setMode %s because Power HAL AIDL not available", @@ -150,11 +113,11 @@ HalResult HidlHalWrapperV1_0::setFeature(V1_0::Feature feature, bool enabl return HalResult::fromReturn(ret); } -HalResult> HidlHalWrapperV1_0::createHintSession( +HalResult> HidlHalWrapperV1_0::createHintSession( int32_t, int32_t, const std::vector& threadIds, int64_t) { ALOGV("Skipped createHintSession(task num=%zu) because Power HAL not available", threadIds.size()); - return HalResult>::unsupported(); + return HalResult>::unsupported(); } HalResult HidlHalWrapperV1_0::getHintSessionPreferredRate() { @@ -178,26 +141,26 @@ HalResult HidlHalWrapperV1_2::sendPowerHint(V1_3::PowerHint hintId, uint32 return HalResult::fromReturn(ret); } -HalResult HidlHalWrapperV1_2::setBoost(Boost boost, int32_t durationMs) { +HalResult HidlHalWrapperV1_2::setBoost(Aidl::Boost boost, int32_t durationMs) { switch (boost) { - case Boost::CAMERA_SHOT: + case Aidl::Boost::CAMERA_SHOT: return sendPowerHint(V1_3::PowerHint::CAMERA_SHOT, durationMs); - case Boost::CAMERA_LAUNCH: + case Aidl::Boost::CAMERA_LAUNCH: return sendPowerHint(V1_3::PowerHint::CAMERA_LAUNCH, durationMs); default: return HidlHalWrapperV1_1::setBoost(boost, durationMs); } } -HalResult HidlHalWrapperV1_2::setMode(Mode mode, bool enabled) { +HalResult HidlHalWrapperV1_2::setMode(Aidl::Mode mode, bool enabled) { uint32_t data = enabled ? 1 : 0; switch (mode) { - case Mode::CAMERA_STREAMING_SECURE: - case Mode::CAMERA_STREAMING_LOW: - case Mode::CAMERA_STREAMING_MID: - case Mode::CAMERA_STREAMING_HIGH: + case Aidl::Mode::CAMERA_STREAMING_SECURE: + case Aidl::Mode::CAMERA_STREAMING_LOW: + case Aidl::Mode::CAMERA_STREAMING_MID: + case Aidl::Mode::CAMERA_STREAMING_HIGH: return sendPowerHint(V1_3::PowerHint::CAMERA_STREAMING, data); - case Mode::AUDIO_STREAMING_LOW_LATENCY: + case Aidl::Mode::AUDIO_STREAMING_LOW_LATENCY: return sendPowerHint(V1_3::PowerHint::AUDIO_LOW_LATENCY, data); default: return HidlHalWrapperV1_1::setMode(mode, enabled); @@ -206,9 +169,9 @@ HalResult HidlHalWrapperV1_2::setMode(Mode mode, bool enabled) { // ------------------------------------------------------------------------------------------------- -HalResult HidlHalWrapperV1_3::setMode(Mode mode, bool enabled) { +HalResult HidlHalWrapperV1_3::setMode(Aidl::Mode mode, bool enabled) { uint32_t data = enabled ? 1 : 0; - if (mode == Mode::EXPENSIVE_RENDERING) { + if (mode == Aidl::Mode::EXPENSIVE_RENDERING) { return sendPowerHint(V1_3::PowerHint::EXPENSIVE_RENDERING, data); } return HidlHalWrapperV1_2::setMode(mode, enabled); @@ -222,7 +185,7 @@ HalResult HidlHalWrapperV1_3::sendPowerHint(V1_3::PowerHint hintId, uint32 // ------------------------------------------------------------------------------------------------- -HalResult AidlHalWrapper::setBoost(Boost boost, int32_t durationMs) { +HalResult AidlHalWrapper::setBoost(Aidl::Boost boost, int32_t durationMs) { std::unique_lock lock(mBoostMutex); size_t idx = static_cast(boost); @@ -237,7 +200,7 @@ HalResult AidlHalWrapper::setBoost(Boost boost, int32_t durationMs) { auto isSupportedRet = mHandle->isBoostSupported(boost, &isSupported); if (!isSupportedRet.isOk()) { ALOGE("Skipped setBoost %s because check support failed with: %s", - toString(boost).c_str(), isSupportedRet.toString8().c_str()); + toString(boost).c_str(), isSupportedRet.getDescription().c_str()); // return HalResult::FAILED; return HalResult::fromStatus(isSupportedRet); } @@ -254,7 +217,7 @@ HalResult AidlHalWrapper::setBoost(Boost boost, int32_t durationMs) { return toHalResult(mHandle->setBoost(boost, durationMs)); } -HalResult AidlHalWrapper::setMode(Mode mode, bool enabled) { +HalResult AidlHalWrapper::setMode(Aidl::Mode mode, bool enabled) { std::unique_lock lock(mModeMutex); size_t idx = static_cast(mode); @@ -268,7 +231,7 @@ HalResult AidlHalWrapper::setMode(Mode mode, bool enabled) { bool isSupported = false; auto isSupportedRet = mHandle->isModeSupported(mode, &isSupported); if (!isSupportedRet.isOk()) { - return HalResult::failed(isSupportedRet.toString8().c_str()); + return HalResult::failed(isSupportedRet.getDescription()); } mModeSupportedArray[idx] = isSupported ? HalSupport::ON : HalSupport::OFF; @@ -283,10 +246,10 @@ HalResult AidlHalWrapper::setMode(Mode mode, bool enabled) { return toHalResult(mHandle->setMode(mode, enabled)); } -HalResult> AidlHalWrapper::createHintSession( +HalResult> AidlHalWrapper::createHintSession( int32_t tgid, int32_t uid, const std::vector& threadIds, int64_t durationNanos) { - sp appSession; - return HalResult>:: + std::shared_ptr appSession; + return HalResult>:: fromStatus(mHandle->createHintSession(tgid, uid, threadIds, durationNanos, &appSession), appSession); } diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp index 54dffcf817..08fcdc8275 100644 --- a/services/powermanager/tests/Android.bp +++ b/services/powermanager/tests/Android.bp @@ -43,6 +43,7 @@ cc_test { shared_libs: [ "libbase", "libbinder", + "libbinder_ndk", "libhidlbase", "liblog", "libpowermanager", @@ -51,9 +52,10 @@ cc_test { "android.hardware.power@1.1", "android.hardware.power@1.2", "android.hardware.power@1.3", - "android.hardware.power-V4-cpp", + "android.hardware.power-V4-ndk", ], static_libs: [ "libgmock", ], + require_root: true, } diff --git a/services/powermanager/tests/PowerHalControllerTest.cpp b/services/powermanager/tests/PowerHalControllerTest.cpp index 6cc7a6f3da..01270ce599 100644 --- a/services/powermanager/tests/PowerHalControllerTest.cpp +++ b/services/powermanager/tests/PowerHalControllerTest.cpp @@ -16,9 +16,9 @@ #define LOG_TAG "PowerHalControllerTest" -#include -#include -#include +#include +#include +#include #include #include #include @@ -26,8 +26,8 @@ #include -using android::hardware::power::Boost; -using android::hardware::power::Mode; +using aidl::android::hardware::power::Boost; +using aidl::android::hardware::power::Mode; using android::hardware::power::V1_0::Feature; using android::hardware::power::V1_0::IPower; using android::hardware::power::V1_0::PowerHint; diff --git a/services/powermanager/tests/PowerHalLoaderTest.cpp b/services/powermanager/tests/PowerHalLoaderTest.cpp index e36deed042..7d9735421b 100644 --- a/services/powermanager/tests/PowerHalLoaderTest.cpp +++ b/services/powermanager/tests/PowerHalLoaderTest.cpp @@ -16,9 +16,8 @@ #define LOG_TAG "PowerHalLoaderTest" -#include +#include #include -#include #include #include @@ -28,7 +27,7 @@ using IPowerV1_0 = android::hardware::power::V1_0::IPower; using IPowerV1_1 = android::hardware::power::V1_1::IPower; using IPowerV1_2 = android::hardware::power::V1_2::IPower; using IPowerV1_3 = android::hardware::power::V1_3::IPower; -using IPowerAidl = android::hardware::power::IPower; +using IPowerAidl = aidl::android::hardware::power::IPower; using namespace android; using namespace android::power; @@ -37,30 +36,30 @@ using namespace testing; // ------------------------------------------------------------------------------------------------- template -sp loadHal(); +T loadHal(); template <> -sp loadHal() { +std::shared_ptr loadHal>() { return PowerHalLoader::loadAidl(); } template <> -sp loadHal() { +sp loadHal>() { return PowerHalLoader::loadHidlV1_0(); } template <> -sp loadHal() { +sp loadHal>() { return PowerHalLoader::loadHidlV1_1(); } template <> -sp loadHal() { +sp loadHal>() { return PowerHalLoader::loadHidlV1_2(); } template <> -sp loadHal() { +sp loadHal>() { return PowerHalLoader::loadHidlV1_3(); } @@ -69,46 +68,47 @@ sp loadHal() { template class PowerHalLoaderTest : public Test { public: - sp load() { return ::loadHal(); } + T load() { return ::loadHal(); } void unload() { PowerHalLoader::unloadAll(); } }; // ------------------------------------------------------------------------------------------------- - -typedef ::testing::Types PowerHalTypes; +typedef ::testing::Types, sp, sp, + sp, sp> + PowerHalTypes; TYPED_TEST_SUITE(PowerHalLoaderTest, PowerHalTypes); TYPED_TEST(PowerHalLoaderTest, TestLoadsOnlyOnce) { - sp firstHal = this->load(); + TypeParam firstHal = this->load(); if (firstHal == nullptr) { ALOGE("Power HAL not available. Skipping test."); return; } - sp secondHal = this->load(); + TypeParam secondHal = this->load(); ASSERT_EQ(firstHal, secondHal); } TYPED_TEST(PowerHalLoaderTest, TestUnload) { - sp firstHal = this->load(); + TypeParam firstHal = this->load(); if (firstHal == nullptr) { ALOGE("Power HAL not available. Skipping test."); return; } this->unload(); - sp secondHal = this->load(); + TypeParam secondHal = this->load(); ASSERT_NE(secondHal, nullptr); ASSERT_NE(firstHal, secondHal); } TYPED_TEST(PowerHalLoaderTest, TestLoadMultiThreadLoadsOnlyOnce) { - std::vector>> futures; + std::vector> futures; for (int i = 0; i < 10; i++) { futures.push_back( std::async(std::launch::async, &PowerHalLoaderTest::load, this)); } futures[0].wait(); - sp firstHal = futures[0].get(); + TypeParam firstHal = futures[0].get(); if (firstHal == nullptr) { ALOGE("Power HAL not available. Skipping test."); return; @@ -116,7 +116,7 @@ TYPED_TEST(PowerHalLoaderTest, TestLoadMultiThreadLoadsOnlyOnce) { for (int i = 1; i < 10; i++) { futures[i].wait(); - sp currentHal = futures[i].get(); + TypeParam currentHal = futures[i].get(); ASSERT_EQ(firstHal, currentHal); } } diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp index cb1a77a45f..641ba9f44b 100644 --- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp +++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp @@ -16,9 +16,9 @@ #define LOG_TAG "PowerHalWrapperAidlTest" -#include -#include -#include +#include +#include +#include #include #include #include @@ -28,11 +28,11 @@ #include #include +using aidl::android::hardware::power::Boost; +using aidl::android::hardware::power::IPower; +using aidl::android::hardware::power::IPowerHintSession; +using aidl::android::hardware::power::Mode; using android::binder::Status; -using android::hardware::power::Boost; -using android::hardware::power::IPower; -using android::hardware::power::IPowerHintSession; -using android::hardware::power::Mode; using namespace android; using namespace android::power; @@ -43,18 +43,21 @@ using namespace testing; class MockIPower : public IPower { public: - MOCK_METHOD(Status, isBoostSupported, (Boost boost, bool* ret), (override)); - MOCK_METHOD(Status, setBoost, (Boost boost, int32_t durationMs), (override)); - MOCK_METHOD(Status, isModeSupported, (Mode mode, bool* ret), (override)); - MOCK_METHOD(Status, setMode, (Mode mode, bool enabled), (override)); - MOCK_METHOD(Status, createHintSession, + MockIPower() = default; + + MOCK_METHOD(ndk::ScopedAStatus, isBoostSupported, (Boost boost, bool* ret), (override)); + MOCK_METHOD(ndk::ScopedAStatus, setBoost, (Boost boost, int32_t durationMs), (override)); + MOCK_METHOD(ndk::ScopedAStatus, isModeSupported, (Mode mode, bool* ret), (override)); + MOCK_METHOD(ndk::ScopedAStatus, setMode, (Mode mode, bool enabled), (override)); + MOCK_METHOD(ndk::ScopedAStatus, createHintSession, (int32_t tgid, int32_t uid, const std::vector& threadIds, - int64_t durationNanos, sp* session), + int64_t durationNanos, std::shared_ptr* session), (override)); - MOCK_METHOD(Status, getHintSessionPreferredRate, (int64_t * rate), (override)); - MOCK_METHOD(int32_t, getInterfaceVersion, (), (override)); - MOCK_METHOD(std::string, getInterfaceHash, (), (override)); - MOCK_METHOD(IBinder*, onAsBinder, (), (override)); + MOCK_METHOD(ndk::ScopedAStatus, getHintSessionPreferredRate, (int64_t * rate), (override)); + MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t * version), (override)); + MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string * hash), (override)); + MOCK_METHOD(ndk::SpAIBinder, asBinder, (), (override)); + MOCK_METHOD(bool, isRemote, (), (override)); }; // ------------------------------------------------------------------------------------------------- @@ -65,13 +68,13 @@ public: protected: std::unique_ptr mWrapper = nullptr; - sp> mMockHal = nullptr; + std::shared_ptr> mMockHal = nullptr; }; // ------------------------------------------------------------------------------------------------- void PowerHalWrapperAidlTest::SetUp() { - mMockHal = new StrictMock(); + mMockHal = ndk::SharedRefBase::make>(); mWrapper = std::make_unique(mMockHal); ASSERT_NE(nullptr, mWrapper); } @@ -83,9 +86,11 @@ TEST_F(PowerHalWrapperAidlTest, TestSetBoostSuccessful) { InSequence seq; EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::DISPLAY_UPDATE_IMMINENT), _)) .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status()))); + .WillOnce(DoAll(SetArgPointee<1>(true), + Return(testing::ByMove(ndk::ScopedAStatus::ok())))); EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::DISPLAY_UPDATE_IMMINENT), Eq(100))) - .Times(Exactly(1)); + .Times(Exactly(1)) + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); } auto result = mWrapper->setBoost(Boost::DISPLAY_UPDATE_IMMINENT, 100); @@ -97,13 +102,14 @@ TEST_F(PowerHalWrapperAidlTest, TestSetBoostFailed) { InSequence seq; EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _)) .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status()))); + .WillOnce(DoAll(SetArgPointee<1>(true), + Return(testing::ByMove(ndk::ScopedAStatus::ok())))); EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100))) .Times(Exactly(1)) - .WillRepeatedly(Return(Status::fromExceptionCode(-1))); + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::fromExceptionCode(-1)))); EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::DISPLAY_UPDATE_IMMINENT), _)) .Times(Exactly(1)) - .WillRepeatedly(Return(Status::fromExceptionCode(-1))); + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::fromExceptionCode(-1)))); } auto result = mWrapper->setBoost(Boost::INTERACTION, 100); @@ -115,7 +121,8 @@ TEST_F(PowerHalWrapperAidlTest, TestSetBoostFailed) { TEST_F(PowerHalWrapperAidlTest, TestSetBoostUnsupported) { EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _)) .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status()))); + .WillOnce(DoAll(SetArgPointee<1>(false), + Return(testing::ByMove(ndk::ScopedAStatus::ok())))); auto result = mWrapper->setBoost(Boost::INTERACTION, 1000); ASSERT_TRUE(result.isUnsupported()); @@ -128,8 +135,13 @@ TEST_F(PowerHalWrapperAidlTest, TestSetBoostMultiThreadCheckSupportedOnlyOnce) { InSequence seq; EXPECT_CALL(*mMockHal.get(), isBoostSupported(Eq(Boost::INTERACTION), _)) .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status()))); - EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100))).Times(Exactly(10)); + .WillOnce(DoAll(SetArgPointee<1>(true), + Return(testing::ByMove(ndk::ScopedAStatus::ok())))); + auto& exp = EXPECT_CALL(*mMockHal.get(), setBoost(Eq(Boost::INTERACTION), Eq(100))) + .Times(Exactly(10)); + for (int i = 0; i < 10; i++) { + exp.WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); + } } std::vector threads; @@ -147,9 +159,11 @@ TEST_F(PowerHalWrapperAidlTest, TestSetModeSuccessful) { InSequence seq; EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::DISPLAY_INACTIVE), _)) .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status()))); + .WillOnce(DoAll(SetArgPointee<1>(true), + Return(testing::ByMove(ndk::ScopedAStatus::ok())))); EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::DISPLAY_INACTIVE), Eq(false))) - .Times(Exactly(1)); + .Times(Exactly(1)) + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); } auto result = mWrapper->setMode(Mode::DISPLAY_INACTIVE, false); @@ -161,13 +175,14 @@ TEST_F(PowerHalWrapperAidlTest, TestSetModeFailed) { InSequence seq; EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _)) .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status()))); + .WillOnce(DoAll(SetArgPointee<1>(true), + Return(testing::ByMove(ndk::ScopedAStatus::ok())))); EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(true))) .Times(Exactly(1)) - .WillRepeatedly(Return(Status::fromExceptionCode(-1))); + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::fromExceptionCode(-1)))); EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::DISPLAY_INACTIVE), _)) .Times(Exactly(1)) - .WillRepeatedly(Return(Status::fromExceptionCode(-1))); + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::fromExceptionCode(-1)))); } auto result = mWrapper->setMode(Mode::LAUNCH, true); @@ -179,14 +194,16 @@ TEST_F(PowerHalWrapperAidlTest, TestSetModeFailed) { TEST_F(PowerHalWrapperAidlTest, TestSetModeUnsupported) { EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _)) .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status()))); + .WillOnce(DoAll(SetArgPointee<1>(false), + Return(testing::ByMove(ndk::ScopedAStatus::ok())))); auto result = mWrapper->setMode(Mode::LAUNCH, true); ASSERT_TRUE(result.isUnsupported()); EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::CAMERA_STREAMING_HIGH), _)) .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<1>(false), Return(Status()))); + .WillOnce(DoAll(SetArgPointee<1>(false), + Return(testing::ByMove(ndk::ScopedAStatus::ok())))); result = mWrapper->setMode(Mode::CAMERA_STREAMING_HIGH, true); ASSERT_TRUE(result.isUnsupported()); } @@ -196,8 +213,13 @@ TEST_F(PowerHalWrapperAidlTest, TestSetModeMultiThreadCheckSupportedOnlyOnce) { InSequence seq; EXPECT_CALL(*mMockHal.get(), isModeSupported(Eq(Mode::LAUNCH), _)) .Times(Exactly(1)) - .WillRepeatedly(DoAll(SetArgPointee<1>(true), Return(Status()))); - EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(false))).Times(Exactly(10)); + .WillOnce(DoAll(SetArgPointee<1>(true), + Return(testing::ByMove(ndk::ScopedAStatus::ok())))); + auto& exp = EXPECT_CALL(*mMockHal.get(), setMode(Eq(Mode::LAUNCH), Eq(false))) + .Times(Exactly(10)); + for (int i = 0; i < 10; i++) { + exp.WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); + } } std::vector threads; @@ -217,7 +239,8 @@ TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionSuccessful) { int64_t durationNanos = 16666666L; EXPECT_CALL(*mMockHal.get(), createHintSession(Eq(tgid), Eq(uid), Eq(threadIds), Eq(durationNanos), _)) - .Times(Exactly(1)); + .Times(Exactly(1)) + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); auto result = mWrapper->createHintSession(tgid, uid, threadIds, durationNanos); ASSERT_TRUE(result.isOk()); } @@ -230,13 +253,16 @@ TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionFailed) { EXPECT_CALL(*mMockHal.get(), createHintSession(Eq(tgid), Eq(uid), Eq(threadIds), Eq(durationNanos), _)) .Times(Exactly(1)) - .WillRepeatedly(Return(Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT))); + .WillOnce(Return(testing::ByMove( + ndk::ScopedAStatus::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT)))); auto result = mWrapper->createHintSession(tgid, uid, threadIds, durationNanos); ASSERT_TRUE(result.isFailed()); } TEST_F(PowerHalWrapperAidlTest, TestGetHintSessionPreferredRate) { - EXPECT_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)).Times(Exactly(1)); + EXPECT_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)) + .Times(Exactly(1)) + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); auto result = mWrapper->getHintSessionPreferredRate(); ASSERT_TRUE(result.isOk()); int64_t rate = result.value(); diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp index 0cd2e22e7e..461143bfc6 100644 --- a/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp +++ b/services/powermanager/tests/PowerHalWrapperHidlV1_0Test.cpp @@ -16,17 +16,17 @@ #define LOG_TAG "PowerHalWrapperHidlV1_0Test" -#include -#include -#include +#include +#include +#include #include #include #include #include #include -using android::hardware::power::Boost; -using android::hardware::power::Mode; +using aidl::android::hardware::power::Boost; +using aidl::android::hardware::power::Mode; using android::hardware::power::V1_0::Feature; using android::hardware::power::V1_0::IPower; using android::hardware::power::V1_0::PowerHint; diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp index 32f84e20b6..79dd996098 100644 --- a/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp +++ b/services/powermanager/tests/PowerHalWrapperHidlV1_1Test.cpp @@ -16,18 +16,18 @@ #define LOG_TAG "PowerHalWrapperHidlV1_1Test" +#include +#include +#include #include -#include -#include -#include #include #include #include #include #include -using android::hardware::power::Boost; -using android::hardware::power::Mode; +using aidl::android::hardware::power::Boost; +using aidl::android::hardware::power::Mode; using android::hardware::power::V1_0::Feature; using android::hardware::power::V1_0::PowerHint; using IPowerV1_1 = android::hardware::power::V1_1::IPower; diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_2Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_2Test.cpp index cf48409f5f..aa6d6c7a3d 100644 --- a/services/powermanager/tests/PowerHalWrapperHidlV1_2Test.cpp +++ b/services/powermanager/tests/PowerHalWrapperHidlV1_2Test.cpp @@ -16,18 +16,18 @@ #define LOG_TAG "PowerHalWrapperHidlV1_2Test" +#include +#include +#include #include -#include -#include -#include #include #include #include #include #include -using android::hardware::power::Boost; -using android::hardware::power::Mode; +using aidl::android::hardware::power::Boost; +using aidl::android::hardware::power::Mode; using android::hardware::power::V1_0::Feature; using PowerHintV1_0 = android::hardware::power::V1_0::PowerHint; using PowerHintV1_2 = android::hardware::power::V1_2::PowerHint; diff --git a/services/powermanager/tests/PowerHalWrapperHidlV1_3Test.cpp b/services/powermanager/tests/PowerHalWrapperHidlV1_3Test.cpp index 2c48537edc..a995afd750 100644 --- a/services/powermanager/tests/PowerHalWrapperHidlV1_3Test.cpp +++ b/services/powermanager/tests/PowerHalWrapperHidlV1_3Test.cpp @@ -16,18 +16,18 @@ #define LOG_TAG "PowerHalWrapperHidlV1_3Test" +#include +#include +#include #include -#include -#include -#include #include #include #include #include #include -using android::hardware::power::Boost; -using android::hardware::power::Mode; +using aidl::android::hardware::power::Boost; +using aidl::android::hardware::power::Mode; using android::hardware::power::V1_0::Feature; using PowerHintV1_0 = android::hardware::power::V1_0::PowerHint; using PowerHintV1_2 = android::hardware::power::V1_2::PowerHint; diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 5683a9280f..e0c80249b9 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -47,7 +47,7 @@ cc_defaults { "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.4", - "android.hardware.power-V4-cpp", + "android.hardware.power-V4-ndk", "libbase", "libbinder", "libbinder_ndk", diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index f3a0186e3e..a094111d40 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -26,7 +26,7 @@ cc_defaults { "android.hardware.graphics.composer@2.4", "android.hardware.power@1.0", "android.hardware.power@1.3", - "android.hardware.power-V4-cpp", + "android.hardware.power-V4-ndk", "libbase", "libcutils", "libgui", diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index 37b68c865e..730db40f7a 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -31,9 +31,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include @@ -49,11 +49,11 @@ PowerAdvisor::~PowerAdvisor() = default; namespace impl { -using android::hardware::power::Boost; -using android::hardware::power::IPowerHintSession; -using android::hardware::power::Mode; -using android::hardware::power::SessionHint; -using android::hardware::power::WorkDuration; +using aidl::android::hardware::power::Boost; +using aidl::android::hardware::power::IPowerHintSession; +using aidl::android::hardware::power::Mode; +using aidl::android::hardware::power::SessionHint; +using aidl::android::hardware::power::WorkDuration; PowerAdvisor::~PowerAdvisor() = default; @@ -215,7 +215,7 @@ void PowerAdvisor::updateTargetWorkDuration(Duration targetDuration) { auto ret = mHintSession->updateTargetWorkDuration(targetDuration.ns()); if (!ret.isOk()) { ALOGW("Failed to set power hint target work duration with error: %s", - ret.exceptionMessage().c_str()); + ret.getDescription().c_str()); mHintSessionRunning = false; } } @@ -259,7 +259,7 @@ void PowerAdvisor::reportActualWorkDuration() { auto ret = mHintSession->reportActualWorkDuration(mHintSessionQueue); if (!ret.isOk()) { ALOGW("Failed to report actual work durations with error: %s", - ret.exceptionMessage().c_str()); + ret.getDescription().c_str()); mHintSessionRunning = false; return; } diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h index 7a0d4267fe..8c724df24c 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include @@ -245,13 +245,14 @@ private: bool mHintSessionRunning = false; std::mutex mHintSessionMutex; - sp mHintSession GUARDED_BY(mHintSessionMutex) = nullptr; + std::shared_ptr mHintSession + GUARDED_BY(mHintSessionMutex) = nullptr; // Initialize to true so we try to call, to check if it's supported bool mHasExpensiveRendering = true; bool mHasDisplayUpdateImminent = true; // Queue of actual durations saved to report - std::vector mHintSessionQueue; + std::vector mHintSessionQueue; // The latest values we have received for target and actual Duration mTargetDuration = kDefaultTargetDuration; std::optional mActualDuration; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8f506f1086..626450efaa 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -24,6 +24,7 @@ #include "SurfaceFlinger.h" +#include #include #include #include @@ -34,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -1999,7 +1999,7 @@ status_t SurfaceFlinger::removeHdrLayerInfoListener( } status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) { - using hardware::power::Boost; + using aidl::android::hardware::power::Boost; Boost powerBoost = static_cast(boostId); if (powerBoost == Boost::INTERACTION) { diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index faa1fb124a..7932daa7a0 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -159,7 +159,7 @@ cc_defaults { "android.hardware.power@1.1", "android.hardware.power@1.2", "android.hardware.power@1.3", - "android.hardware.power-V4-cpp", + "android.hardware.power-V4-ndk", "libaidlcommonsupport", "libcompositionengine_mocks", "libcompositionengine", diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp index 0d66d59f26..85f66f4ed0 100644 --- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp +++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp @@ -18,10 +18,10 @@ #define LOG_TAG "PowerAdvisorTest" #include -#include -#include +#include #include #include +#include #include #include #include "TestableSurfaceFlinger.h" @@ -50,7 +50,7 @@ protected: TestableSurfaceFlinger mFlinger; std::unique_ptr mPowerAdvisor; MockPowerHalController* mMockPowerHalController; - sp mMockPowerHintSession; + std::shared_ptr mMockPowerHintSession; }; void PowerAdvisorTest::SetUp() { @@ -64,13 +64,14 @@ void PowerAdvisorTest::SetUp() { void PowerAdvisorTest::startPowerHintSession() { const std::vector threadIds = {1, 2, 3}; - mMockPowerHintSession = android::sp>::make(); + mMockPowerHintSession = ndk::SharedRefBase::make>(); ON_CALL(*mMockPowerHalController, createHintSession) - .WillByDefault( - Return(HalResult>::fromStatus(binder::Status::ok(), - mMockPowerHintSession))); + .WillByDefault(Return(HalResult>:: + fromStatus(binder::Status::ok(), mMockPowerHintSession))); mPowerAdvisor->enablePowerHintSession(true); mPowerAdvisor->startPowerHintSession(threadIds); + ON_CALL(*mMockPowerHintSession, updateTargetWorkDuration) + .WillByDefault(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); } void PowerAdvisorTest::setExpectedTiming(Duration totalFrameTargetDuration, @@ -123,8 +124,8 @@ TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) { EXPECT_CALL(*mMockPowerHintSession, reportActualWorkDuration(ElementsAre( Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns()))))) - .Times(1); - + .Times(1) + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); fakeBasicFrameTiming(startTime, vsyncPeriod); setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); mPowerAdvisor->setDisplays(displayIds); @@ -163,7 +164,8 @@ TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) { EXPECT_CALL(*mMockPowerHintSession, reportActualWorkDuration(ElementsAre( Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns()))))) - .Times(1); + .Times(1) + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); fakeBasicFrameTiming(startTime, vsyncPeriod); setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); @@ -205,7 +207,8 @@ TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) { EXPECT_CALL(*mMockPowerHintSession, reportActualWorkDuration(ElementsAre( Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns()))))) - .Times(1); + .Times(1) + .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok()))); fakeBasicFrameTiming(startTime, vsyncPeriod); setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp index 4e9f293dc3..22b72f98e5 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp @@ -23,12 +23,12 @@ #include "DisplayTransactionTestHelpers.h" #include "FakeDisplayInjector.h" -#include +#include namespace android { namespace { -using android::hardware::power::Boost; +using aidl::android::hardware::power::Boost; TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) { using namespace std::chrono_literals; diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h index 0ddc90d585..a088aabc11 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPower.h @@ -18,14 +18,14 @@ #include "binder/Status.h" -#include +#include #include +using aidl::android::hardware::power::Boost; +using aidl::android::hardware::power::IPower; +using aidl::android::hardware::power::IPowerHintSession; +using aidl::android::hardware::power::Mode; using android::binder::Status; -using android::hardware::power::Boost; -using android::hardware::power::IPower; -using android::hardware::power::IPowerHintSession; -using android::hardware::power::Mode; namespace android::Hwc2::mock { @@ -33,18 +33,19 @@ class MockIPower : public IPower { public: MockIPower(); - MOCK_METHOD(Status, isBoostSupported, (Boost boost, bool* ret), (override)); - MOCK_METHOD(Status, setBoost, (Boost boost, int32_t durationMs), (override)); - MOCK_METHOD(Status, isModeSupported, (Mode mode, bool* ret), (override)); - MOCK_METHOD(Status, setMode, (Mode mode, bool enabled), (override)); - MOCK_METHOD(Status, createHintSession, + MOCK_METHOD(ndk::ScopedAStatus, isBoostSupported, (Boost boost, bool* ret), (override)); + MOCK_METHOD(ndk::ScopedAStatus, setBoost, (Boost boost, int32_t durationMs), (override)); + MOCK_METHOD(ndk::ScopedAStatus, isModeSupported, (Mode mode, bool* ret), (override)); + MOCK_METHOD(ndk::ScopedAStatus, setMode, (Mode mode, bool enabled), (override)); + MOCK_METHOD(ndk::ScopedAStatus, createHintSession, (int32_t tgid, int32_t uid, const std::vector& threadIds, - int64_t durationNanos, sp* session), + int64_t durationNanos, std::shared_ptr* session), (override)); - MOCK_METHOD(Status, getHintSessionPreferredRate, (int64_t * rate), (override)); - MOCK_METHOD(int32_t, getInterfaceVersion, (), (override)); - MOCK_METHOD(std::string, getInterfaceHash, (), (override)); - MOCK_METHOD(IBinder*, onAsBinder, (), (override)); + MOCK_METHOD(ndk::ScopedAStatus, getHintSessionPreferredRate, (int64_t * rate), (override)); + MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t * version), (override)); + MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string * hash), (override)); + MOCK_METHOD(ndk::SpAIBinder, asBinder, (), (override)); + MOCK_METHOD(bool, isRemote, (), (override)); }; } // namespace android::Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h index f4ded216cb..2b9520fca7 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h @@ -18,14 +18,14 @@ #include "binder/Status.h" -#include +#include #include +using aidl::android::hardware::power::IPowerHintSession; +using aidl::android::hardware::power::SessionHint; using android::binder::Status; -using android::hardware::power::IPowerHintSession; -using android::hardware::power::SessionHint; -using namespace android::hardware::power; +using namespace aidl::android::hardware::power; namespace android::Hwc2::mock { @@ -33,16 +33,18 @@ class MockIPowerHintSession : public IPowerHintSession { public: MockIPowerHintSession(); - MOCK_METHOD(IBinder*, onAsBinder, (), (override)); - MOCK_METHOD(Status, pause, (), (override)); - MOCK_METHOD(Status, resume, (), (override)); - MOCK_METHOD(Status, close, (), (override)); - MOCK_METHOD(int32_t, getInterfaceVersion, (), (override)); - MOCK_METHOD(std::string, getInterfaceHash, (), (override)); - MOCK_METHOD(Status, updateTargetWorkDuration, (int64_t), (override)); - MOCK_METHOD(Status, reportActualWorkDuration, (const ::std::vector&), (override)); - MOCK_METHOD(Status, sendHint, (SessionHint), (override)); - MOCK_METHOD(Status, setThreads, (const ::std::vector&), (override)); + MOCK_METHOD(ndk::SpAIBinder, asBinder, (), (override)); + MOCK_METHOD(ndk::ScopedAStatus, pause, (), (override)); + MOCK_METHOD(ndk::ScopedAStatus, resume, (), (override)); + MOCK_METHOD(ndk::ScopedAStatus, close, (), (override)); + MOCK_METHOD(ndk::ScopedAStatus, getInterfaceVersion, (int32_t * version), (override)); + MOCK_METHOD(ndk::ScopedAStatus, getInterfaceHash, (std::string * hash), (override)); + MOCK_METHOD(bool, isRemote, (), (override)); + MOCK_METHOD(ndk::ScopedAStatus, updateTargetWorkDuration, (int64_t), (override)); + MOCK_METHOD(ndk::ScopedAStatus, reportActualWorkDuration, (const ::std::vector&), + (override)); + MOCK_METHOD(ndk::ScopedAStatus, sendHint, (SessionHint), (override)); + MOCK_METHOD(ndk::ScopedAStatus, setThreads, (const ::std::vector&), (override)); }; } // namespace android::Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h index 358395d323..c8269302b1 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h @@ -31,8 +31,8 @@ class IPower; namespace android::Hwc2::mock { -using android::hardware::power::Boost; -using android::hardware::power::Mode; +using aidl::android::hardware::power::Boost; +using aidl::android::hardware::power::Mode; using android::power::HalResult; class MockPowerHalController : public power::PowerHalController { @@ -41,8 +41,9 @@ public: ~MockPowerHalController() override; MOCK_METHOD(HalResult, setBoost, (Boost, int32_t), (override)); MOCK_METHOD(HalResult, setMode, (Mode, bool), (override)); - MOCK_METHOD(HalResult>, createHintSession, - (int32_t, int32_t, const std::vector&, int64_t), (override)); + MOCK_METHOD(HalResult>, + createHintSession, (int32_t, int32_t, const std::vector&, int64_t), + (override)); MOCK_METHOD(HalResult, getHintSessionPreferredRate, (), (override)); }; -- GitLab From fba4845a5558e9c34810e47a1494bc09f9d9681d Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 25 May 2023 04:07:41 +0000 Subject: [PATCH 0144/1187] Revert "Adding fuzz_service_test to run at presubmit" This reverts commit a6091b6b3e4a8eda5b7016247585af0514ffc45f. Reason for revert: b/284227523 Change-Id: Ife075945dde35540f3a85f9ad2d2298419e33486 --- libs/binder/TEST_MAPPING | 3 --- libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp | 1 - 2 files changed, 4 deletions(-) diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index 2b3ff4407a..199574eb84 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -63,9 +63,6 @@ { "name": "libbinderthreadstateutils_test" }, - { - "name": "fuzz_service_test" - }, { "name": "CtsOsTestCases", "options": [ diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp index 7b5928769c..e60ca22497 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp @@ -52,5 +52,4 @@ sh_test_host { required: [ "test_service_fuzzer_should_crash", ], - test_suites: ["general-tests"], } -- GitLab From ebe1ef614b644d14ca140349c841186cfdc0964d Mon Sep 17 00:00:00 2001 From: Michelle Yang Date: Thu, 25 May 2023 15:26:17 +0000 Subject: [PATCH 0145/1187] Revert "Adding host script to run test fuzzer." This reverts commit fd0f24d175cb2d67b75b49ea211c810e04a5f008. Reason for revert: b/284239067 Change-Id: I509f588aa0606ddb94d3d6825abcf56321773a0a --- .../parcel_fuzzer/test_fuzzer/Android.bp | 13 ------ .../test_fuzzer/fuzz_service_test_config.xml | 22 ---------- .../test_fuzzer/run_fuzz_service_test.sh | 42 ------------------- 3 files changed, 77 deletions(-) delete mode 100644 libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml delete mode 100644 libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp index e60ca22497..28da285128 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp @@ -40,16 +40,3 @@ cc_fuzz { fuzz_on_haiku_device: false, }, } - -sh_test_host { - name: "fuzz_service_test", - src: "run_fuzz_service_test.sh", - filename: "run_fuzz_service_test.sh", - test_config: "fuzz_service_test_config.xml", - data_bins: [ - "test_service_fuzzer_should_crash", - ], - required: [ - "test_service_fuzzer_should_crash", - ], -} diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml b/libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml deleted file mode 100644 index 19eb33a635..0000000000 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh deleted file mode 100644 index cec52fd6e7..0000000000 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash -# Copyright (C) 2023 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. - -color_success=$'\E'"[0;32m" -color_failed=$'\E'"[0;31m" -color_reset=$'\E'"[00m" - -FUZZER_NAME=test_service_fuzzer_should_crash -FUZZER_OUT=fuzzer-output - -if [ ! -f "$FUZZER_NAME" ] -then - echo -e "${color_failed}Binary $FUZZER_NAME does not exist" - echo "${color_reset}" - exit 1 -fi - -echo "INFO: Running fuzzer : test_service_fuzzer_should_crash" - -./test_service_fuzzer_should_crash -max_total_time=30 &>${FUZZER_OUT} - -echo "INFO: Searching fuzzer output for expected crashes" -if grep -q "Expected crash in set" ${FUZZER_OUT}; -then - echo -e "${color_success}Success: Found expected crash. fuzzService test successful!" -else - echo -e "${color_failed}Failed: Unable to find successful fuzzing output from test_service_fuzzer_should_crash" - echo "${color_reset}" - exit 1 -fi -- GitLab From 730cf3cdbb070a65b6a0792901d25a2a191648db Mon Sep 17 00:00:00 2001 From: Nergi Rahardi Date: Thu, 13 Apr 2023 12:41:17 +0900 Subject: [PATCH 0146/1187] Adds API to update InputDispatcher key repeat info. This will be used to update key repeat configuration from InputManager (through Settings config). - Removed requestRefreshConfiguration from InputDispatcher - Refactor pull config model to push model Bug: 251050590 Test: atest inputflinger_tests Change-Id: I63325f6a067c837bcb4de488c922f151daf226da --- .../benchmarks/InputDispatcher_benchmarks.cpp | 2 -- .../inputflinger/dispatcher/InputDispatcher.cpp | 14 +++++++------- services/inputflinger/dispatcher/InputDispatcher.h | 4 ++-- .../dispatcher/include/InputDispatcherInterface.h | 7 +++---- .../include/InputDispatcherPolicyInterface.h | 3 --- .../inputflinger/tests/InputDispatcher_test.cpp | 12 +----------- 6 files changed, 13 insertions(+), 29 deletions(-) diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index f65533ea79..4e12a17b00 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -80,8 +80,6 @@ private: void notifyVibratorState(int32_t deviceId, bool isOn) override {} - InputDispatcherConfiguration getDispatcherConfiguration() override { return mConfig; } - bool filterInputEvent(const InputEvent& inputEvent, uint32_t policyFlags) override { return true; // dispatch event normally } diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index aa71e93f4a..b15081caf6 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -6740,13 +6740,6 @@ void InputDispatcher::cancelCurrentTouch() { mLooper->wake(); } -void InputDispatcher::requestRefreshConfiguration() { - InputDispatcherConfiguration config = mPolicy.getDispatcherConfiguration(); - - std::scoped_lock _l(mLock); - mConfig = config; -} - void InputDispatcher::setMonitorDispatchingTimeoutForTest(std::chrono::nanoseconds timeout) { std::scoped_lock _l(mLock); mMonitorDispatchingTimeout = timeout; @@ -6858,4 +6851,11 @@ sp InputDispatcher::findWallpaperWindowBelow( return nullptr; } +void InputDispatcher::setKeyRepeatConfiguration(nsecs_t timeout, nsecs_t delay) { + std::scoped_lock _l(mLock); + + mConfig.keyRepeatTimeout = timeout; + mConfig.keyRepeatDelay = delay; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 8ca01b7a09..969abf2425 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -148,11 +148,11 @@ public: void cancelCurrentTouch() override; - void requestRefreshConfiguration() override; - // Public to allow tests to verify that a Monitor can get ANR. void setMonitorDispatchingTimeoutForTest(std::chrono::nanoseconds timeout); + void setKeyRepeatConfiguration(nsecs_t timeout, nsecs_t delay) override; + private: enum class DropReason { NOT_DROPPED, diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index c752ddd699..3e863c082b 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -226,11 +226,10 @@ public: */ virtual void cancelCurrentTouch() = 0; - /** - * Request that the InputDispatcher's configuration, which can be obtained through the policy, - * be updated. + /* + * Updates key repeat configuration timeout and delay. */ - virtual void requestRefreshConfiguration() = 0; + virtual void setKeyRepeatConfiguration(nsecs_t timeout, nsecs_t delay) = 0; }; } // namespace android diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h index 5539915694..5e4d79ddff 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h @@ -73,9 +73,6 @@ public: InputDeviceSensorAccuracy accuracy) = 0; virtual void notifyVibratorState(int32_t deviceId, bool isOn) = 0; - /* Gets the input dispatcher configuration. */ - virtual InputDispatcherConfiguration getDispatcherConfiguration() = 0; - /* Filters an input event. * Return true to dispatch the event unmodified, false to consume the event. * A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 3660f81b92..8e9d990b28 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -204,8 +204,6 @@ MATCHER_P(WithPointers, pointers, "MotionEvent with specified pointers") { // --- FakeInputDispatcherPolicy --- class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { - InputDispatcherConfiguration mConfig; - using AnrResult = std::pair, int32_t /*pid*/>; public: @@ -346,11 +344,6 @@ public: "signal"; } - void setKeyRepeatConfiguration(nsecs_t timeout, nsecs_t delay) { - mConfig.keyRepeatTimeout = timeout; - mConfig.keyRepeatDelay = delay; - } - PointerCaptureRequest assertSetPointerCaptureCalled(bool enabled) { std::unique_lock lock(mLock); base::ScopedLockAssertion assumeLocked(mLock); @@ -535,8 +528,6 @@ private: void notifyVibratorState(int32_t deviceId, bool isOn) override {} - InputDispatcherConfiguration getDispatcherConfiguration() override { return mConfig; } - bool filterInputEvent(const InputEvent& inputEvent, uint32_t policyFlags) override { std::scoped_lock lock(mLock); switch (inputEvent.getType()) { @@ -5732,10 +5723,9 @@ protected: virtual void SetUp() override { mFakePolicy = std::make_unique(); - mFakePolicy->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY); mDispatcher = std::make_unique(*mFakePolicy); - mDispatcher->requestRefreshConfiguration(); mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); + mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY); ASSERT_EQ(OK, mDispatcher->start()); setUpWindow(); -- GitLab From 029f9a773ab3dd0a64646991a01548c1d820e283 Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 25 May 2023 12:11:38 -0400 Subject: [PATCH 0147/1187] Add warning that GB<->AHB is not VNDK-safe Bug: 282126131 Test: make Change-Id: I5c0a0b735942a02bd7c69de0b4f3c41fb34babda --- libs/ui/include/ui/GraphicBuffer.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h index dbe475b805..f859848b0c 100644 --- a/libs/ui/include/ui/GraphicBuffer.h +++ b/libs/ui/include/ui/GraphicBuffer.h @@ -36,6 +36,15 @@ #include +#if defined(__ANDROID_APEX__) || defined(__ANDROID_VNDK__) +// TODO: Provide alternatives that aren't broken +#define AHB_CONVERSION \ + [[deprecated("WARNING: VNDK casts beteween GraphicBuffer & AHardwareBuffer are UNSAFE and " \ + "will be removed in the future")]] +#else +#define AHB_CONVERSION +#endif + namespace android { class GraphicBufferMapper; @@ -80,10 +89,10 @@ public: static sp from(ANativeWindowBuffer *); - static GraphicBuffer* fromAHardwareBuffer(AHardwareBuffer*); - static GraphicBuffer const* fromAHardwareBuffer(AHardwareBuffer const*); - AHardwareBuffer* toAHardwareBuffer(); - AHardwareBuffer const* toAHardwareBuffer() const; + AHB_CONVERSION static GraphicBuffer* fromAHardwareBuffer(AHardwareBuffer*); + AHB_CONVERSION static GraphicBuffer const* fromAHardwareBuffer(AHardwareBuffer const*); + AHB_CONVERSION AHardwareBuffer* toAHardwareBuffer(); + AHB_CONVERSION AHardwareBuffer const* toAHardwareBuffer() const; // Create a GraphicBuffer to be unflatten'ed into or be reallocated. GraphicBuffer(); -- GitLab From 06987165f75318039aad372032c36662d78fcc45 Mon Sep 17 00:00:00 2001 From: Kangping Dong Date: Thu, 25 May 2023 17:15:55 +0000 Subject: [PATCH 0148/1187] [Thread] define the ThreadNetwork hardware feature FR: 235016403 Bug: 284296494 (cherry picked from https://android-review.googlesource.com/q/commit:521aba80e6b853fd56ad045f54e9c6ce25bf9cc0) Merged-In: Ie86f2711e673d99a8e1832ce5bbaecb1454d4199 Change-Id: Ie86f2711e673d99a8e1832ce5bbaecb1454d4199 --- data/etc/Android.bp | 6 ++++++ data/etc/android.hardware.threadnetwork.xml | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 data/etc/android.hardware.threadnetwork.xml diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 754e7b2ac0..061829d930 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -262,6 +262,12 @@ prebuilt_etc { defaults: ["frameworks_native_data_etc_defaults"], } +prebuilt_etc { + name: "android.hardware.threadnetwork.prebuilt.xml", + src: "android.hardware.threadnetwork.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + prebuilt_etc { name: "android.hardware.usb.accessory.prebuilt.xml", src: "android.hardware.usb.accessory.xml", diff --git a/data/etc/android.hardware.threadnetwork.xml b/data/etc/android.hardware.threadnetwork.xml new file mode 100644 index 0000000000..9cbdc905fb --- /dev/null +++ b/data/etc/android.hardware.threadnetwork.xml @@ -0,0 +1,19 @@ + + + + + + -- GitLab From 7d2f9f1231542662a25f1f80ea3c5c603f210501 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 19 Apr 2022 09:18:29 -0700 Subject: [PATCH 0149/1187] Add ToolbarActionBarTest to input presubmit This test injects keys, and changes window focus, which are both important aspects of input dispatch. Let's move this test to input presubmit, because future breakages are likely to be caused by input changes. Bug: 229623669 Test: cd frameworks/native/service/inputflinger && atest Change-Id: Ibb09616e94f63775da439681bd3df1a0823db4dc --- services/inputflinger/TEST_MAPPING | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING index f0b107222a..68af9b8351 100644 --- a/services/inputflinger/TEST_MAPPING +++ b/services/inputflinger/TEST_MAPPING @@ -81,6 +81,14 @@ } ] }, + { + "name": "CtsAppTestCases", + "options": [ + { + "include-filter": "android.app.cts.ToolbarActionBarTest" + } + ] + }, { "name": "FrameworksServicesTests", "options": [ @@ -184,6 +192,14 @@ } ] }, + { + "name": "CtsAppTestCases", + "options": [ + { + "include-filter": "android.app.cts.ToolbarActionBarTest" + } + ] + }, { "name": "FrameworksServicesTests", "options": [ -- GitLab From 550a3b5d5ed68beb359fb68dbdd827113990b1d4 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Sat, 27 May 2023 00:20:51 +0000 Subject: [PATCH 0150/1187] libbinder fuzzer driver: uid corpus continuity I was looking at the coverage for some of our fuzzers, and I noticed that some paths were only taken with specific UIDs. This change allows an easily discoverable single bit flip to try a UID which is guaranteed to exist. Bug: N/A Test: run servicemanager_fuzzer for a few minutes Change-Id: Ib0d8c608ec1fc609fa69f1f5b76e8dc25d548f38 --- libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index 69f7147a56..0b3902dbac 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -33,9 +33,13 @@ void fuzzService(const std::vector>& binders, FuzzedDataProvider&& p .extraFds = {}, }; + // Always take so that a perturbation of just the one ConsumeBool byte will always + // take the same path, but with a different UID. Without this, the fuzzer needs to + // guess both the change in value and the shift at the same time. + int64_t maybeSetUid = provider.ConsumeIntegral(); if (provider.ConsumeBool()) { // set calling uid - IPCThreadState::self()->restoreCallingIdentity(provider.ConsumeIntegral()); + IPCThreadState::self()->restoreCallingIdentity(maybeSetUid); } while (provider.remaining_bytes() > 0) { -- GitLab From 5c703e7c520161b3ca645d9cea90cd50b26ca392 Mon Sep 17 00:00:00 2001 From: Yuxin Hu Date: Thu, 25 May 2023 22:46:13 +0000 Subject: [PATCH 0151/1187] Fix the missing extension EGL_ANDROID_image_native_buffer In http://ag/22040002, EGL_ANDROID_get_frame_timestamps is conditionally added to the mExtensionString. A space at the end of the extension name is mandatory, because we use ' ' or '\0' as an indicator when parsing the mExtensionString to find each individual extension name. Bug: b/269060366 Bug: b/280016556 Test: m; atest android.hardware.nativehardware.cts.AHardwareBufferNativeTests Change-Id: I2552b47dda49a09218a7741c45641c02bdd807ee Merged-In: I2552b47dda49a09218a7741c45641c02bdd807ee --- opengl/libs/EGL/egl_display.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index c2c856e22a..6593c1bb16 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -326,10 +326,10 @@ EGLBoolean egl_display_t::initialize(EGLint* major, EGLint* minor) { // device's present timestamps are reliable (which may not be the case on emulators). if (cnx->useAngle) { if (android::base::GetBoolProperty("service.sf.present_timestamp", false)) { - mExtensionString.append("EGL_ANDROID_get_frame_timestamps"); + mExtensionString.append("EGL_ANDROID_get_frame_timestamps "); } } else { - mExtensionString.append("EGL_ANDROID_get_frame_timestamps"); + mExtensionString.append("EGL_ANDROID_get_frame_timestamps "); } hasColorSpaceSupport = findExtension(disp.queryString.extensions, "EGL_KHR_gl_colorspace"); -- GitLab From fa9c6bc59756bb2b91a643ddc0f7855cbc447ff9 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 25 May 2023 21:01:44 +0000 Subject: [PATCH 0152/1187] Revert "Revert "Adding host script to run test fuzzer."" This reverts commit ebe1ef614b644d14ca140349c841186cfdc0964d. Reason for revert: Fixing breakages in followup Test: atest -c fuzz_service_test Bug: 282239388 Change-Id: I3a2cf7f929cdeeb363af02ddce8d9fbfffaca233 --- .../parcel_fuzzer/test_fuzzer/Android.bp | 21 ++++++++++ .../test_fuzzer/fuzz_service_test_config.xml | 22 ++++++++++ .../test_fuzzer/run_fuzz_service_test.sh | 42 +++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml create mode 100644 libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp index 28da285128..e5cd1f9c5d 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp @@ -40,3 +40,24 @@ cc_fuzz { fuzz_on_haiku_device: false, }, } + +sh_test_host { + name: "fuzz_service_test", + src: "run_fuzz_service_test.sh", + filename: "run_fuzz_service_test.sh", + test_config: "fuzz_service_test_config.xml", + data_bins: [ + "test_service_fuzzer_should_crash", + ], + required: [ + "test_service_fuzzer_should_crash", + ], + target: { + linux_bionic: { + enabled: false, + }, + darwin: { + enabled: false, + }, + }, +} diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml b/libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml new file mode 100644 index 0000000000..19eb33a635 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml @@ -0,0 +1,22 @@ + + + + diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh new file mode 100644 index 0000000000..cec52fd6e7 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Copyright (C) 2023 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. + +color_success=$'\E'"[0;32m" +color_failed=$'\E'"[0;31m" +color_reset=$'\E'"[00m" + +FUZZER_NAME=test_service_fuzzer_should_crash +FUZZER_OUT=fuzzer-output + +if [ ! -f "$FUZZER_NAME" ] +then + echo -e "${color_failed}Binary $FUZZER_NAME does not exist" + echo "${color_reset}" + exit 1 +fi + +echo "INFO: Running fuzzer : test_service_fuzzer_should_crash" + +./test_service_fuzzer_should_crash -max_total_time=30 &>${FUZZER_OUT} + +echo "INFO: Searching fuzzer output for expected crashes" +if grep -q "Expected crash in set" ${FUZZER_OUT}; +then + echo -e "${color_success}Success: Found expected crash. fuzzService test successful!" +else + echo -e "${color_failed}Failed: Unable to find successful fuzzing output from test_service_fuzzer_should_crash" + echo "${color_reset}" + exit 1 +fi -- GitLab From 00bf23867263aa5425c2cf56e9925e726e9ebab5 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Fri, 19 May 2023 14:23:16 -0700 Subject: [PATCH 0153/1187] Add surfaceflinger owners to libgui OWNERS Bug: 255664414 Test: n/a Change-Id: I047c8d57f4c40cafd1e17bd458f37176f2f8fc8a --- libs/gui/OWNERS | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS index 05b55337ab..826a418aab 100644 --- a/libs/gui/OWNERS +++ b/libs/gui/OWNERS @@ -1,12 +1,7 @@ -adyabr@google.com -alecmouri@google.com -chaviw@google.com chrisforbes@google.com jreck@google.com -lpy@google.com -pdwilliams@google.com -racarr@google.com -vishnun@google.com + +file:/services/surfaceflinger/OWNERS per-file EndToEndNativeInputTest.cpp = svv@google.com -- GitLab From aef359aeca1ece29c6870bd5e3c3f52943b85d7f Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 25 May 2023 21:03:16 +0000 Subject: [PATCH 0154/1187] Revert "Revert "Adding fuzz_service_test to run at presubmit"" This reverts commit fba4845a5558e9c34810e47a1494bc09f9d9681d. Reason for revert: Fixed build breakage on linux_bionic Test: TH, Runs with abtd Change-Id: Ib7880073b86f54fcbf617879ea87fc4b5f58a539 --- libs/binder/TEST_MAPPING | 3 +++ libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp | 1 + 2 files changed, 4 insertions(+) diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index 199574eb84..2b3ff4407a 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -63,6 +63,9 @@ { "name": "libbinderthreadstateutils_test" }, + { + "name": "fuzz_service_test" + }, { "name": "CtsOsTestCases", "options": [ diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp index e5cd1f9c5d..690c39afc9 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp @@ -60,4 +60,5 @@ sh_test_host { enabled: false, }, }, + test_suites: ["general-tests"], } -- GitLab From 208e11adf3595140f592830fe5fd7fb777bb02f3 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Wed, 31 May 2023 19:34:46 +0000 Subject: [PATCH 0155/1187] [native] Migrate SkSurface::flush methods to skgpu::ganesh version Follow-up part 2 to https://skia-review.googlesource.com/c/skia/+/698237 Change-Id: I83f8cdfea84117792712b28561d615e832d04d89 --- libs/renderengine/skia/SkiaRenderEngine.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index 5854135afe..24c6ae84d0 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -20,6 +20,7 @@ #include "SkiaRenderEngine.h" +#include #include #include #include @@ -1105,7 +1106,7 @@ void SkiaRenderEngine::drawLayersInternal( } if (kFlushAfterEveryLayer) { ATRACE_NAME("flush surface"); - activeSurface->flush(); + skgpu::ganesh::Flush(activeSurface); } } for (const auto& borderRenderInfo : display.borderInfoList) { @@ -1133,7 +1134,7 @@ void SkiaRenderEngine::drawLayersInternal( { ATRACE_NAME("flush surface"); LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface); - activeSurface->flush(); + skgpu::ganesh::Flush(activeSurface); } auto drawFence = sp::make(flushAndSubmit(grContext)); -- GitLab From 9c2032247e3ba71394247432b776c4991d10cc7b Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 31 May 2023 21:26:41 +0000 Subject: [PATCH 0156/1187] RPC binder: one more pool test flake fix Fixes: 285094756 Test: binderRpcTest Change-Id: Ie36371803c03ab4e25f7bee0a26842c5f2dc92e4 --- libs/binder/tests/binderRpcTest.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 505f30fc41..f88cfd6965 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -461,8 +461,11 @@ static void testThreadPoolOverSaturated(sp iface, size_t numCall EXPECT_GE(epochMsAfter, epochMsBefore + 2 * sleepMs); - // Potential flake, but make sure calls are handled in parallel. - EXPECT_LE(epochMsAfter, epochMsBefore + 4 * sleepMs); + // Potential flake, but make sure calls are handled in parallel. Due + // to past flakes, this only checks that the amount of time taken has + // some parallelism. Other tests such as ThreadPoolGreaterThanEqualRequested + // check this more exactly. + EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs); } TEST_P(BinderRpc, ThreadPoolOverSaturated) { -- GitLab From fa522a96c95a552eeb3248486d948d4c768df92f Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 31 May 2023 23:08:54 +0000 Subject: [PATCH 0157/1187] Revert "libbinder_ndk_unit_test: shutdown wait time to 20s" This reverts commit 48abe6a88d407f662ca32bba9a4fd496a116586d. Reason for revert: not the issue, see b/285202885 Change-Id: I876e73d3ff06dc657d91f7944bc0b81079e67700 --- libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 8c9844cde9..664894ebac 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -53,7 +53,7 @@ constexpr char kForcePersistNdkUnitTestService[] = "ForcePersistNdkUnitTestServi constexpr char kActiveServicesNdkUnitTestService[] = "ActiveServicesNdkUnitTestService"; constexpr char kBinderNdkUnitTestServiceFlagged[] = "BinderNdkUnitTestFlagged"; -constexpr unsigned int kShutdownWaitTime = 20; +constexpr unsigned int kShutdownWaitTime = 11; constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715; class MyTestFoo : public IFoo { -- GitLab From 09034a905676afd72d351994142fceece2ac48a2 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 31 May 2023 20:49:11 +0000 Subject: [PATCH 0158/1187] RPC binder: limit experimental wire protocol usage Add runtime checks, because we only currently check the defaults. Fixes: 278946301 Test: binderRpcTest Change-Id: I119c8c49d5938a9d6f36c29c1bb70732155c6037 --- libs/binder/RpcState.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index ff35f5f35c..5c1b2305a6 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -34,6 +34,10 @@ #include +#ifdef __ANDROID__ +#include +#endif + namespace android { using base::StringPrintf; @@ -399,14 +403,27 @@ status_t RpcState::rpcRec( } bool RpcState::validateProtocolVersion(uint32_t version) { - if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT && - version != RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) { + if (version == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) { +#if defined(__ANDROID__) + char codename[PROPERTY_VALUE_MAX]; + property_get("ro.build.version.codename", codename, ""); + if (!strcmp(codename, "REL")) { + ALOGE("Cannot use experimental RPC binder protocol on a release branch."); + return false; + } +#else + // don't restrict on other platforms, though experimental should + // only really be used for testing, we don't have a good way to see + // what is shipping outside of Android +#endif + } else if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT) { ALOGE("Cannot use RPC binder protocol version %u which is unknown (current protocol " "version " "is %u).", version, RPC_WIRE_PROTOCOL_VERSION); return false; } + return true; } -- GitLab From 4af9ce3b3105a7e0556c2b38ff95605ffcd4e5ed Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Fri, 19 May 2023 14:23:16 -0700 Subject: [PATCH 0159/1187] Add surfaceflinger owners to libgui OWNERS Bug: 255664414 Test: n/a (cherry picked from https://android-review.googlesource.com/q/commit:00bf23867263aa5425c2cf56e9925e726e9ebab5) Merged-In: I047c8d57f4c40cafd1e17bd458f37176f2f8fc8a Change-Id: I047c8d57f4c40cafd1e17bd458f37176f2f8fc8a --- libs/gui/OWNERS | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS index 05b55337ab..826a418aab 100644 --- a/libs/gui/OWNERS +++ b/libs/gui/OWNERS @@ -1,12 +1,7 @@ -adyabr@google.com -alecmouri@google.com -chaviw@google.com chrisforbes@google.com jreck@google.com -lpy@google.com -pdwilliams@google.com -racarr@google.com -vishnun@google.com + +file:/services/surfaceflinger/OWNERS per-file EndToEndNativeInputTest.cpp = svv@google.com -- GitLab From 8df810fd71f0cc9bf9fdf28a28eaa83ccc34ccef Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 1 Jun 2023 19:52:47 +0000 Subject: [PATCH 0160/1187] libbinder_ndk_unit_test: log service test cbs To make this test more debuggable from the logs. Bug: 285202885 Test: libbinder_ndk_unit_test Change-Id: I5d1d38daaef6468f01924de53479f520f3d5dab8 --- libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 8c9844cde9..3198da7046 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -107,11 +107,13 @@ class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest { } static bool activeServicesCallback(bool hasClients, void* context) { if (hasClients) { + LOG(INFO) << "hasClients, so not unregistering."; return false; } // Unregister all services if (!AServiceManager_tryUnregister()) { + LOG(INFO) << "Could not unregister service the first time."; // Prevent shutdown (test will fail) return false; } @@ -121,6 +123,7 @@ class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest { // Unregister again before shutdown if (!AServiceManager_tryUnregister()) { + LOG(INFO) << "Could not unregister service the second time."; // Prevent shutdown (test will fail) return false; } @@ -128,6 +131,7 @@ class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest { // Check if the context was passed correctly MyBinderNdkUnitTest* service = static_cast(context); if (service->contextTestValue != kContextTestValue) { + LOG(INFO) << "Incorrect context value."; // Prevent shutdown (test will fail) return false; } @@ -479,6 +483,8 @@ TEST(NdkBinder, ForcedPersistenceTest) { } TEST(NdkBinder, ActiveServicesCallbackTest) { + LOG(INFO) << "ActiveServicesCallbackTest starting"; + ndk::SpAIBinder binder(AServiceManager_waitForService(kActiveServicesNdkUnitTestService)); std::shared_ptr service = aidl::IBinderNdkUnitTest::fromBinder(binder); @@ -489,6 +495,7 @@ TEST(NdkBinder, ActiveServicesCallbackTest) { service = nullptr; IPCThreadState::self()->flushCommands(); + LOG(INFO) << "ActiveServicesCallbackTest about to sleep"; sleep(kShutdownWaitTime); ASSERT_FALSE(isServiceRunning(kActiveServicesNdkUnitTestService)) -- GitLab From 01658be6316720d9d04bb990f5936ab2a213181e Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Fri, 2 Jun 2023 19:03:10 +0000 Subject: [PATCH 0161/1187] [native] Fix includes of SkTileMode and SkBlendMode Needed to change #includes in https://skia-review.googlesource.com/c/skia/+/706539 Change-Id: I30c247cd562212b35d37a09f4e585efac9cf83af --- libs/renderengine/skia/filters/BlurFilter.cpp | 2 ++ libs/renderengine/skia/filters/GaussianBlurFilter.cpp | 2 ++ libs/renderengine/skia/filters/KawaseBlurFilter.cpp | 1 + 3 files changed, 5 insertions(+) diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp index 2557ac9770..1e0c4cf9d0 100644 --- a/libs/renderengine/skia/filters/BlurFilter.cpp +++ b/libs/renderengine/skia/filters/BlurFilter.cpp @@ -16,6 +16,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "BlurFilter.h" +#include #include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/libs/renderengine/skia/filters/GaussianBlurFilter.cpp b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp index a77d5bf97d..e72c501336 100644 --- a/libs/renderengine/skia/filters/GaussianBlurFilter.cpp +++ b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp @@ -17,6 +17,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "GaussianBlurFilter.h" +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include "include/gpu/GpuTypes.h" // from Skia #include diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp index e370c39a94..d1d92e5c6e 100644 --- a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp +++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include -- GitLab From 57b1591dca003b488d42e85dfdc5e096d35fdf8e Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 2 Jun 2023 21:35:00 +0000 Subject: [PATCH 0162/1187] libbinder_driver: never enforce data avail It would be good to cover this too, but we do have it covered via binder_parcel_fuzzer now, and this causes a lot of wasted cycles for our AIDL fuzzers. Bug: N/A Test: diffing strace of runs before/after Change-Id: I743b62272c402c400c5e357adf5538dc5440f2a6 --- libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index 0b3902dbac..cb2878c697 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -52,7 +52,7 @@ void fuzzService(const std::vector>& binders, FuzzedDataProvider&& p uint32_t flags = provider.ConsumeIntegral(); Parcel data; // for increased fuzz coverage - data.setEnforceNoDataAvail(provider.ConsumeBool()); + data.setEnforceNoDataAvail(false); sp target = options.extraBinders.at( provider.ConsumeIntegralInRange(0, @@ -73,7 +73,7 @@ void fuzzService(const std::vector>& binders, FuzzedDataProvider&& p Parcel reply; // for increased fuzz coverage - reply.setEnforceNoDataAvail(provider.ConsumeBool()); + reply.setEnforceNoDataAvail(false); (void)target->transact(code, data, &reply, flags); // feed back in binders and fds that are returned from the service, so that -- GitLab From 3a667498ecd2a9a35f5e86c58140a22202c22c2f Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 2 Jun 2023 21:41:39 +0000 Subject: [PATCH 0163/1187] Parcel: service fuzzing mode In service fuzzing mode, we disable logs in the core Parcel code and also limit some API checks. This increases fuzzer efficiency (~2x or more, ignoring service-specific inefficiencies) just due to bypassing the 'mixing copies of libbinder' check, which isn't critical for fuzzing. Bug: N/A Test: manual, diffing strace outputs Change-Id: I4952b3ab5f55f27f33d5124e39541fdd40143971 --- libs/binder/Parcel.cpp | 53 ++++++++++++++----- libs/binder/include/binder/Parcel.h | 5 ++ .../tests/parcel_fuzzer/libbinder_driver.cpp | 2 + 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 0aca163eab..f95bfa33ce 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -947,7 +947,10 @@ bool Parcel::enforceInterface(const char16_t* interface, threadState->setCallingWorkSourceUidWithoutPropagation(workSource); // vendor header int32_t header = readInt32(); - if (header != kHeader) { + + // fuzzers skip this check, because it is for protecting the underlying ABI, but + // we don't want it to reduce our coverage + if (header != kHeader && !mServiceFuzzing) { ALOGE("Expecting header 0x%x but found 0x%x. Mixing copies of libbinder?", kHeader, header); return false; @@ -966,9 +969,11 @@ bool Parcel::enforceInterface(const char16_t* interface, (!len || !memcmp(parcel_interface, interface, len * sizeof (char16_t)))) { return true; } else { - ALOGW("**** enforceInterface() expected '%s' but read '%s'", - String8(interface, len).string(), - String8(parcel_interface, parcel_interface_len).string()); + if (!mServiceFuzzing) { + ALOGW("**** enforceInterface() expected '%s' but read '%s'", + String8(interface, len).string(), + String8(parcel_interface, parcel_interface_len).string()); + } return false; } } @@ -977,6 +982,10 @@ void Parcel::setEnforceNoDataAvail(bool enforceNoDataAvail) { mEnforceNoDataAvail = enforceNoDataAvail; } +void Parcel::setServiceFuzzing() { + mServiceFuzzing = true; +} + binder::Status Parcel::enforceNoDataAvail() const { if (!mEnforceNoDataAvail) { return binder::Status::ok(); @@ -1722,7 +1731,9 @@ status_t Parcel::validateReadData(size_t upperBound) const do { if (mDataPos < kernelFields->mObjects[nextObject] + sizeof(flat_binder_object)) { // Requested info overlaps with an object - ALOGE("Attempt to read from protected data in Parcel %p", this); + if (!mServiceFuzzing) { + ALOGE("Attempt to read from protected data in Parcel %p", this); + } return PERMISSION_DENIED; } nextObject++; @@ -2092,7 +2103,11 @@ String8 Parcel::readString8() const size_t len; const char* str = readString8Inplace(&len); if (str) return String8(str, len); - ALOGE("Reading a NULL string not supported here."); + + if (!mServiceFuzzing) { + ALOGE("Reading a NULL string not supported here."); + } + return String8(); } @@ -2132,7 +2147,11 @@ String16 Parcel::readString16() const size_t len; const char16_t* str = readString16Inplace(&len); if (str) return String16(str, len); - ALOGE("Reading a NULL string not supported here."); + + if (!mServiceFuzzing) { + ALOGE("Reading a NULL string not supported here."); + } + return String16(); } @@ -2172,7 +2191,9 @@ status_t Parcel::readStrongBinder(sp* val) const { status_t status = readNullableStrongBinder(val); if (status == OK && !val->get()) { - ALOGW("Expecting binder but got null!"); + if (!mServiceFuzzing) { + ALOGW("Expecting binder but got null!"); + } status = UNEXPECTED_NULL; } return status; @@ -2237,9 +2258,11 @@ int Parcel::readFileDescriptor() const { if (const auto* rpcFields = maybeRpcFields()) { if (!std::binary_search(rpcFields->mObjectPositions.begin(), rpcFields->mObjectPositions.end(), mDataPos)) { - ALOGW("Attempt to read file descriptor from Parcel %p at offset %zu that is not in the " - "object list", - this, mDataPos); + if (!mServiceFuzzing) { + ALOGW("Attempt to read file descriptor from Parcel %p at offset %zu that is not in " + "the object list", + this, mDataPos); + } return BAD_TYPE; } @@ -2497,8 +2520,11 @@ const flat_binder_object* Parcel::readObject(bool nullMetaData) const return obj; } } - ALOGW("Attempt to read object from Parcel %p at offset %zu that is not in the object list", - this, DPOS); + if (!mServiceFuzzing) { + ALOGW("Attempt to read object from Parcel %p at offset %zu that is not in the object " + "list", + this, DPOS); + } } return nullptr; } @@ -3093,6 +3119,7 @@ void Parcel::initState() mDeallocZero = false; mOwner = nullptr; mEnforceNoDataAvail = true; + mServiceFuzzing = false; } void Parcel::scanForFds() const { diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index e28d374b26..15bb325459 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -149,6 +149,10 @@ public: // This Api is used by fuzzers to skip dataAvail checks. void setEnforceNoDataAvail(bool enforceNoDataAvail); + // When fuzzing, we want to remove certain ABI checks that cause significant + // lost coverage, and we also want to avoid logs that cost too much to write. + void setServiceFuzzing(); + void freeData(); size_t objectsCount() const; @@ -1330,6 +1334,7 @@ private: // Set this to false to skip dataAvail checks. bool mEnforceNoDataAvail; + bool mServiceFuzzing; release_func mOwner; diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index cb2878c697..24a9345193 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -53,6 +53,7 @@ void fuzzService(const std::vector>& binders, FuzzedDataProvider&& p Parcel data; // for increased fuzz coverage data.setEnforceNoDataAvail(false); + data.setServiceFuzzing(); sp target = options.extraBinders.at( provider.ConsumeIntegralInRange(0, @@ -74,6 +75,7 @@ void fuzzService(const std::vector>& binders, FuzzedDataProvider&& p Parcel reply; // for increased fuzz coverage reply.setEnforceNoDataAvail(false); + reply.setServiceFuzzing(); (void)target->transact(code, data, &reply, flags); // feed back in binders and fds that are returned from the service, so that -- GitLab From e99d88216aec57742f66c1fa0e8198fe45971be8 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 2 Jun 2023 21:56:39 +0000 Subject: [PATCH 0164/1187] service fuzzer: ignore interface checks We bypass this half the time in the driver now, but it's better to bypass it here in Parcel so that we fuzz how different fields are set at the beginning of Parcel. Bug: N/A Test: servicemanager_fuzzer for several minutes Change-Id: I17399680c0f5d9239071e9d4fa6bcedb545f7871 --- libs/binder/Parcel.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index f95bfa33ce..2c2a1b636e 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -969,12 +969,18 @@ bool Parcel::enforceInterface(const char16_t* interface, (!len || !memcmp(parcel_interface, interface, len * sizeof (char16_t)))) { return true; } else { - if (!mServiceFuzzing) { + if (mServiceFuzzing) { + // ignore. Theoretically, this could cause a few false positives, because + // people could assume things about getInterfaceDescriptor if they pass + // this point, but it would be extremely fragile. It's more important that + // we fuzz with the above things read from the Parcel. + return true; + } else { ALOGW("**** enforceInterface() expected '%s' but read '%s'", String8(interface, len).string(), String8(parcel_interface, parcel_interface_len).string()); + return false; } - return false; } } -- GitLab From 7086bcb3838b81f9290df8d766ec30316de53e59 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Fri, 2 Jun 2023 15:18:11 -0700 Subject: [PATCH 0165/1187] activity_manager: use waitForService instead of getService Test: build & boot Bug: 284487308 Change-Id: I9f81398c1350749d55e6f97e84dffbc38fcdcd62 --- libs/binder/ActivityManager.cpp | 42 ++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp index aca5009148..526427663b 100644 --- a/libs/binder/ActivityManager.cpp +++ b/libs/binder/ActivityManager.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -33,27 +34,36 @@ ActivityManager::ActivityManager() sp ActivityManager::getService() { std::lock_guard scoped_lock(mLock); - int64_t startTime = 0; sp service = mService; - while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) { - sp binder = defaultServiceManager()->checkService(String16("activity")); - if (binder == nullptr) { - // Wait for the activity service to come back... - if (startTime == 0) { - startTime = uptimeMillis(); - ALOGI("Waiting for activity service"); - } else if ((uptimeMillis() - startTime) > 1000000) { - ALOGW("Waiting too long for activity service, giving up"); - service = nullptr; - break; - } - usleep(25000); - } else { + if (ProcessState::self()->isThreadPoolStarted()) { + if (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) { + sp binder = defaultServiceManager()->waitForService(String16("activity")); service = interface_cast(binder); mService = service; } + } else { + ALOGI("Thread pool not started. Polling for activity service."); + int64_t startTime = 0; + while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) { + sp binder = defaultServiceManager()->checkService(String16("activity")); + if (binder == nullptr) { + // Wait for the activity service to come back... + if (startTime == 0) { + startTime = uptimeMillis(); + ALOGI("Waiting for activity service"); + } else if ((uptimeMillis() - startTime) > 1000000) { + ALOGW("Waiting too long for activity service, giving up"); + service = nullptr; + break; + } + usleep(25000); + } else { + service = interface_cast(binder); + mService = service; + } + } } - return service; + return mService; } int ActivityManager::openContentUri(const String16& stringUri) -- GitLab From 072c398215c489775b2250d17eeb841bed8bc476 Mon Sep 17 00:00:00 2001 From: Alice Wang Date: Thu, 25 May 2023 09:45:13 +0000 Subject: [PATCH 0166/1187] [rpc_binder] Add ARpcServer_newBoundSocket API This cl is part of the change to replace the init-dependent binder API ARpcServer_newInitUnixDomain with a more generic version ARpcServer_newBoundSocket. Test: atest microdroid_manager_test Bug: 275729094 Change-Id: I5b8688fb5964e775845a3b878466f8a3cfee2e25 --- libs/binder/Android.bp | 1 - .../binder_rpc_unstable.hpp | 7 ++++--- libs/binder/libbinder_rpc_unstable.cpp | 15 ++++--------- libs/binder/libbinder_rpc_unstable.map.txt | 2 +- libs/binder/rust/rpcbinder/src/server.rs | 21 ++++++------------- 5 files changed, 15 insertions(+), 31 deletions(-) diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 34331381db..deff76b3a5 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -525,7 +525,6 @@ cc_library { "libbase", "libbinder", "libbinder_ndk", - "libcutils_sockets", "liblog", "libutils", ], diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp index a157792156..7d0acd1843 100644 --- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp +++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp @@ -40,12 +40,13 @@ enum class ARpcSession_FileDescriptorTransportMode { [[nodiscard]] ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid, unsigned int port); -// Starts a Unix domain RPC server with a given init-managed Unix domain `name` +// Starts a Unix domain RPC server with an open raw socket file descriptor // and a given root IBinder object. -// The socket should be created in init.rc with the same `name`. +// The socket should be created and bound to an address. // Returns an opaque handle to the running server instance, or null if the server // could not be started. -[[nodiscard]] ARpcServer* ARpcServer_newInitUnixDomain(AIBinder* service, const char* name); +// The socket will be closed by the server once the server goes out of scope. +[[nodiscard]] ARpcServer* ARpcServer_newBoundSocket(AIBinder* service, int socketFd); // Starts an RPC server that bootstraps sessions using an existing Unix domain // socket pair, with a given root IBinder object. diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp index a167f235d5..f51cd9bc99 100644 --- a/libs/binder/libbinder_rpc_unstable.cpp +++ b/libs/binder/libbinder_rpc_unstable.cpp @@ -105,22 +105,15 @@ ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid, unsigned in return createObjectHandle(server); } -ARpcServer* ARpcServer_newInitUnixDomain(AIBinder* service, const char* name) { +ARpcServer* ARpcServer_newBoundSocket(AIBinder* service, int socketFd) { auto server = RpcServer::make(); - auto fd = unique_fd(android_get_control_socket(name)); + auto fd = unique_fd(socketFd); if (!fd.ok()) { - LOG(ERROR) << "Failed to get fd for the socket:" << name; + LOG(ERROR) << "Invalid socket fd " << socketFd; return nullptr; } - // Control socket fds are inherited from init, so they don't have O_CLOEXEC set. - // But we don't want any child processes to inherit the socket we are running - // the server on, so attempt to set the flag now. - if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { - LOG(WARNING) << "Failed to set CLOEXEC on control socket with name " << name - << " error: " << errno; - } if (status_t status = server->setupRawSocketServer(std::move(fd)); status != OK) { - LOG(ERROR) << "Failed to set up Unix Domain RPC server with name " << name + LOG(ERROR) << "Failed to set up RPC server with fd " << socketFd << " error: " << statusToString(status).c_str(); return nullptr; } diff --git a/libs/binder/libbinder_rpc_unstable.map.txt b/libs/binder/libbinder_rpc_unstable.map.txt index 63679c28d0..50f7deb7d9 100644 --- a/libs/binder/libbinder_rpc_unstable.map.txt +++ b/libs/binder/libbinder_rpc_unstable.map.txt @@ -3,7 +3,7 @@ LIBBINDER_RPC_UNSTABLE_SHIM { # platform-only ARpcServer_free; ARpcServer_join; ARpcServer_newInet; - ARpcServer_newInitUnixDomain; + ARpcServer_newBoundSocket; ARpcServer_newVsock; ARpcServer_shutdown; ARpcServer_start; diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs index c87876ac15..81f68f5a29 100644 --- a/libs/binder/rust/rpcbinder/src/server.rs +++ b/libs/binder/rust/rpcbinder/src/server.rs @@ -57,26 +57,17 @@ impl RpcServer { } /// Creates a binder RPC server, serving the supplied binder service implementation on the given - /// socket file name. The socket should be initialized in init.rc with the same name. - pub fn new_init_unix_domain( - mut service: SpIBinder, - socket_name: &str, - ) -> Result { - let socket_name = match CString::new(socket_name) { - Ok(s) => s, - Err(e) => { - log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e); - return Err(Error::from(ErrorKind::InvalidInput)); - } - }; + /// socket file descriptor. The socket should be bound to an address before calling this + /// function. + pub fn new_bound_socket(mut service: SpIBinder, socket_fd: OwnedFd) -> Result { let service = service.as_native_mut(); // SAFETY: Service ownership is transferring to the server and won't be valid afterward. // Plus the binder objects are threadsafe. + // The server takes ownership of the socket FD. unsafe { - Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newInitUnixDomain( - service, - socket_name.as_ptr(), + Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newBoundSocket( + service, socket_fd.into_raw_fd(), )) } } -- GitLab From 8d669dc15cb499b263aaeb542a1958bf8c944c06 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Fri, 2 Jun 2023 13:31:05 -0700 Subject: [PATCH 0167/1187] sensor_privacy: use waitForService instead of getService Test: build & boot Bug: 284487308 Change-Id: I462fb2f897e0b287c804d2afeac94976446fa66c --- libs/sensorprivacy/SensorPrivacyManager.cpp | 23 ++++----------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp index 2be98e7281..57c74ee565 100644 --- a/libs/sensorprivacy/SensorPrivacyManager.cpp +++ b/libs/sensorprivacy/SensorPrivacyManager.cpp @@ -32,27 +32,12 @@ SensorPrivacyManager::SensorPrivacyManager() sp SensorPrivacyManager::getService() { std::lock_guard scoped_lock(mLock); - int64_t startTime = 0; sp service = mService; - while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) { - sp binder = defaultServiceManager()->checkService(String16("sensor_privacy")); - if (binder == nullptr) { - // Wait for the sensor privacy service to come back... - if (startTime == 0) { - startTime = uptimeMillis(); - ALOGI("Waiting for sensor privacy service"); - } else if ((uptimeMillis() - startTime) > 1000000) { - ALOGW("Waiting too long for sensor privacy service, giving up"); - service = nullptr; - break; - } - usleep(25000); - } else { - service = interface_cast(binder); - mService = service; - } + if (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) { + sp binder = defaultServiceManager()->waitForService(String16("sensor_privacy")); + mService = interface_cast(binder); } - return service; + return mService; } bool SensorPrivacyManager::supportsSensorToggle(int toggleType, int sensor) { -- GitLab From a1456c16c894f7005808368fe8cb610c78ce7099 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Wed, 17 May 2023 12:11:15 -0700 Subject: [PATCH 0168/1187] SF: Add ro.surface_flinger.min_acquired_buffers This is a minimum count of buffers to indicate when computing the return value for ISurfaceComposer.getMaxAcquiredBufferCount(). The value is read from "ro.surface_flinger.min_acquired_buffers" if set, otherwise the default of value of 1 is used if not. Setting values larger than 1 affects how many buffers apps should allocate to keep the display pipeline busy. Bug: 239574096 Bug: 239575317 Test: Configuring "2" works. Test: atest libsurfaceflinger_unittest Change-Id: I4e3a441bdf94cddebb766e6bf73f7cdb82aacd0d --- services/surfaceflinger/SurfaceFlinger.cpp | 5 ++++- services/surfaceflinger/SurfaceFlinger.h | 4 ++++ .../sysprop/SurfaceFlingerProperties.sysprop | 12 +++++++++++- .../sysprop/api/SurfaceFlingerProperties-current.txt | 5 +++++ .../surfaceflinger/tests/unittests/SchedulerTest.cpp | 5 +++++ .../tests/unittests/TestableSurfaceFlinger.h | 2 ++ 6 files changed, 31 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1daa802b57..f07298bf31 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -324,6 +324,7 @@ int64_t SurfaceFlinger::dispSyncPresentTimeOffset; bool SurfaceFlinger::useHwcForRgbToYuv; bool SurfaceFlinger::hasSyncFramework; int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers; +int64_t SurfaceFlinger::minAcquiredBuffers = 1; uint32_t SurfaceFlinger::maxGraphicsWidth; uint32_t SurfaceFlinger::maxGraphicsHeight; bool SurfaceFlinger::useContextPriority; @@ -385,6 +386,8 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI useHwcForRgbToYuv = force_hwc_copy_for_virtual_displays(false); maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2); + minAcquiredBuffers = + SurfaceFlingerProperties::min_acquired_buffers().value_or(minAcquiredBuffers); maxGraphicsWidth = std::max(max_graphics_width(0), 0); maxGraphicsHeight = std::max(max_graphics_height(0), 0); @@ -7853,7 +7856,7 @@ int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate, if (presentLatency.count() % refreshRate.getPeriodNsecs()) { pipelineDepth++; } - return std::max(1ll, pipelineDepth - 1); + return std::max(minAcquiredBuffers, static_cast(pipelineDepth - 1)); } status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b7d2047671..9187168408 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -226,6 +226,10 @@ public: // FramebufferSurface static int64_t maxFrameBufferAcquiredBuffers; + // Controls the minimum acquired buffers SurfaceFlinger will suggest via + // ISurfaceComposer.getMaxAcquiredBufferCount(). + static int64_t minAcquiredBuffers; + // 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; diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index bcbe21a483..9b3d130563 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -470,4 +470,14 @@ prop { scope: Public access: Readonly prop_name: "ro.surface_flinger.ignore_hdr_camera_layers" -} \ No newline at end of file +} + +# Controls the minimum acquired buffers SurfaceFlinger will suggest via +# ISurfaceComposer.getMaxAcquiredBufferCount(). +prop { + api_name: "min_acquired_buffers" + type: Long + scope: Public + access: Readonly + prop_name: "ro.surface_flinger.min_acquired_buffers" +} diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt index 348a462038..41987fcffe 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -92,6 +92,11 @@ props { type: Long prop_name: "ro.surface_flinger.max_virtual_display_dimension" } + prop { + api_name: "min_acquired_buffers" + type: Long + prop_name: "ro.surface_flinger.min_acquired_buffers" + } prop { api_name: "present_time_offset_from_vsync_ns" type: Long diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 682c998542..fab3c0e887 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -249,6 +249,11 @@ TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) { EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 40ms)); EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms)); + + const auto savedMinAcquiredBuffers = mFlinger.mutableMinAcquiredBuffers(); + mFlinger.mutableMinAcquiredBuffers() = 2; + EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms)); + mFlinger.mutableMinAcquiredBuffers() = savedMinAcquiredBuffers; } MATCHER(Is120Hz, "") { diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 945e48842d..deb0957b97 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -605,6 +605,8 @@ public: return SurfaceFlinger::sActiveDisplayRotationFlags; } + auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; } + auto fromHandle(const sp& handle) { return LayerHandle::getLayer(handle); } ~TestableSurfaceFlinger() { -- GitLab From e986aed2b2554bf6a07590e3b10075c1b8249579 Mon Sep 17 00:00:00 2001 From: Josh Thielen Date: Thu, 1 Jun 2023 14:17:30 +0000 Subject: [PATCH 0169/1187] Fix touch reset due to viewport isActive changing when enableForInactiveViewport is 1 Test: Manual, and added unit test Bug: 267543995 Change-Id: Icb76efe7568728172ed16246356cea3fbfef151d --- .../reader/mapper/TouchInputMapper.cpp | 13 +++- .../inputflinger/tests/InputReader_test.cpp | 59 +++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index f4d50b8fa1..39a914d822 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -972,7 +972,18 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) (rawXResolution > 0 && rawYResolution > 0) ? (rawXResolution + rawYResolution) / 2 : 0; const DisplayViewport& newViewport = newViewportOpt.value_or(kUninitializedViewport); - const bool viewportChanged = mViewport != newViewport; + bool viewportChanged; + if (mParameters.enableForInactiveViewport) { + // When touch is enabled for an inactive viewport, ignore the + // viewport active status when checking whether the viewport has + // changed. + DisplayViewport tempViewport = mViewport; + tempViewport.isActive = newViewport.isActive; + viewportChanged = tempViewport != newViewport; + } else { + viewportChanged = mViewport != newViewport; + } + bool skipViewportUpdate = false; if (viewportChanged) { const bool viewportOrientationChanged = mViewport.orientation != newViewport.orientation; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index bbb166cc7e..81a51aeae9 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -9352,6 +9352,11 @@ TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreProcessed) { EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); } +/** + * When the viewport is deactivated (isActive transitions from true to false), + * and touch.enableForInactiveViewport is false, touches prior to the transition + * should be cancelled. + */ TEST_F(MultiTouchInputMapperTest, Process_DeactivateViewport_AbortTouches) { addConfigurationProperty("touch.deviceType", "touchScreen"); addConfigurationProperty("touch.enableForInactiveViewport", "0"); @@ -9403,6 +9408,60 @@ TEST_F(MultiTouchInputMapperTest, Process_DeactivateViewport_AbortTouches) { EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); } +/** + * When the viewport is deactivated (isActive transitions from true to false), + * and touch.enableForInactiveViewport is true, touches prior to the transition + * should not be cancelled. + */ +TEST_F(MultiTouchInputMapperTest, Process_DeactivateViewport_TouchesNotAborted) { + addConfigurationProperty("touch.deviceType", "touchScreen"); + addConfigurationProperty("touch.enableForInactiveViewport", "1"); + mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + /*isActive=*/true, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); + std::optional optionalDisplayViewport = + mFakePolicy->getDisplayViewportByUniqueId(UNIQUE_ID); + ASSERT_TRUE(optionalDisplayViewport.has_value()); + DisplayViewport displayViewport = *optionalDisplayViewport; + + configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO); + prepareAxes(POSITION); + MultiTouchInputMapper& mapper = constructAndAddMapper(); + + // Finger down + int32_t x = 100, y = 100; + processPosition(mapper, x, y); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( + WithMotionAction(AMOTION_EVENT_ACTION_DOWN))); + + // Deactivate display viewport + displayViewport.isActive = false; + ASSERT_TRUE(mFakePolicy->updateViewport(displayViewport)); + configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO); + + // The ongoing touch should not be canceled + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); + + // Finger move is not ignored + x += 10, y += 10; + processPosition(mapper, x, y); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE))); + + // Reactivate display viewport + displayViewport.isActive = true; + ASSERT_TRUE(mFakePolicy->updateViewport(displayViewport)); + configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO); + + // Finger move continues and does not start new gesture + x += 10, y += 10; + processPosition(mapper, x, y); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE))); +} + TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) { // Setup the first touch screen device. prepareAxes(POSITION | ID | SLOT); -- GitLab From 1dd5f38df2b9c4d0ed09b44bb210052befcd2ebc Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 1 Jun 2023 23:43:10 +0000 Subject: [PATCH 0170/1187] Adding AIDL fuzzer for SurfaceFlinger Test: m surfaceflinger_service_fuzzer && adb sync data && adb shell /data/fuzz/arm64/surfaceflinger_service_fuzzer/surfaceflinger_service_fuzzer Bug: 232439428 Change-Id: I89f3086123114a7e6f48705923d4d7ccf2ffe19b --- services/surfaceflinger/fuzzer/Android.bp | 15 +++++++++ .../fuzzer/surfaceflinger_service_fuzzer.cpp | 32 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp index f76a8d762a..0f9060dbdb 100644 --- a/services/surfaceflinger/fuzzer/Android.bp +++ b/services/surfaceflinger/fuzzer/Android.bp @@ -138,3 +138,18 @@ cc_fuzz { "surfaceflinger_frametracer_fuzzer.cpp", ], } + +cc_fuzz { + name: "surfaceflinger_service_fuzzer", + defaults: [ + "surfaceflinger_fuzz_defaults", + "service_fuzzer_defaults", + "fuzzer_disable_leaks", + ], + srcs: [ + "surfaceflinger_service_fuzzer.cpp", + ], + fuzz_config: { + triage_assignee: "waghpawan@google.com", + }, +} diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp new file mode 100644 index 0000000000..849a896ce2 --- /dev/null +++ b/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2023 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 + +#include "SurfaceFlinger.h" +#include "SurfaceFlingerDefaultFactory.h" + +using namespace android; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + DefaultFactory factory; + sp flinger = sp::make(factory); + flinger->init(); + + sp composerAIDL = sp::make(flinger); + fuzzService({flinger, composerAIDL}, FuzzedDataProvider(data, size)); + return 0; +} -- GitLab From 6b70c61c722abb8eb27e5639f2c5082ceb34a046 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Tue, 6 Jun 2023 20:58:50 +0000 Subject: [PATCH 0171/1187] Remove leak detection options Test: m wificond_service_fuzzer Bug: 286112918 Change-Id: I966282acf504ee66548bb2a5e77df5ede103e345 --- libs/binder/tests/Android.bp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 41856f9b79..24fd2a6048 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -804,12 +804,5 @@ cc_defaults { cc_defaults { name: "fuzzer_disable_leaks", - fuzz_config: { - asan_options: [ - "detect_leaks=0", - ], - hwasan_options: [ - "detect_leaks=0", - ], - }, + //TODO(b/286112918) : Readd leak detection options } -- GitLab From b2a116b84a08be2c96b1223a038ed4c06733266e Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Tue, 6 Jun 2023 22:06:33 +0000 Subject: [PATCH 0172/1187] Make Parcel::readOutVectorSizeWithCheck public There are still a few cases of manually defined binder interfaces and they need to check the size of the vectors against something. That something is defined here with kMaxAllocationSize. Test: libsensorserviceaidl_fuzzer Bug: None Change-Id: Ie33c74609f9a12212c2e02c81f76477d607a17c0 --- libs/binder/include/binder/Parcel.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index e28d374b26..eca084f878 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -538,6 +538,12 @@ public: template status_t resizeOutVector(std::unique_ptr>* val) const __attribute__((deprecated("use std::optional version instead"))); + // Retrieve the size of an out vector and check against internal limits to + // the size. + // The returned size may be negative so caller must handle appropriately. + // elemSize is the size of the element on the wire, if unknown use `1`. + status_t readOutVectorSizeWithCheck(size_t elmSize, int32_t* size) const; + // Like Parcel.java's readExceptionCode(). Reads the first int32 // off of a Parcel's header, returning 0 or the negative error // code on exceptions, but also deals with skipping over rich @@ -639,8 +645,6 @@ private: status_t flattenBinder(const sp& binder); status_t unflattenBinder(sp* out) const; - status_t readOutVectorSizeWithCheck(size_t elmSize, int32_t* size) const; - template status_t readAligned(T *pArg) const; -- GitLab From bdc293ac507b97a23747ff7a736de26c181370c5 Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Tue, 6 Jun 2023 22:09:02 +0000 Subject: [PATCH 0173/1187] ISensorServer: validate vector size before setCapacity If we don't check the size, we can run out of memory. Use the Parcel API that knows about the binder transaction size limits. Test: libsensorserviceaidl_fuzzer Bug: none Change-Id: I2d00e14e8c67e9899532577628c54e9a74f584d7 --- libs/sensor/ISensorServer.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp index 019d6cb070..634d35a5b8 100644 --- a/libs/sensor/ISensorServer.cpp +++ b/libs/sensor/ISensorServer.cpp @@ -64,6 +64,14 @@ public: Sensor s; Vector v; uint32_t n = reply.readUint32(); + // The size of the n Sensor elements on the wire is what we really want, but + // this is better than nothing. + if (n > reply.dataAvail()) { + ALOGE("Failed to get a reasonable size of the sensor list. This is likely a " + "malformed reply parcel. Number of elements: %d, data available in reply: %zu", + n, reply.dataAvail()); + return v; + } v.setCapacity(n); while (n) { n--; @@ -86,6 +94,14 @@ public: Sensor s; Vector v; uint32_t n = reply.readUint32(); + // The size of the n Sensor elements on the wire is what we really want, but + // this is better than nothing. + if (n > reply.dataAvail()) { + ALOGE("Failed to get a reasonable size of the sensor list. This is likely a " + "malformed reply parcel. Number of elements: %d, data available in reply: %zu", + n, reply.dataAvail()); + return v; + } v.setCapacity(n); while (n) { n--; @@ -109,6 +125,14 @@ public: Sensor s; Vector v; uint32_t n = reply.readUint32(); + // The size of the n Sensor elements on the wire is what we really want, but + // this is better than nothing. + if (n > reply.dataAvail()) { + ALOGE("Failed to get a reasonable size of the sensor list. This is likely a " + "malformed reply parcel. Number of elements: %d, data available in reply: %zu", + n, reply.dataAvail()); + return v; + } v.setCapacity(n); while (n) { n--; -- GitLab From d7a7681b9ead1f116f7f208a8bca8ee01b63aace Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Wed, 7 Jun 2023 20:35:58 +0000 Subject: [PATCH 0174/1187] Revert "Make Parcel::readOutVectorSizeWithCheck public" This reverts commit b2a116b84a08be2c96b1223a038ed4c06733266e. Reason for revert: Nevermind! We don't want to do this and we don't need to. Change-Id: I005a36d47b96ff137e81edc23e88724913c7d2a5 --- libs/binder/include/binder/Parcel.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index eca084f878..e28d374b26 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -538,12 +538,6 @@ public: template status_t resizeOutVector(std::unique_ptr>* val) const __attribute__((deprecated("use std::optional version instead"))); - // Retrieve the size of an out vector and check against internal limits to - // the size. - // The returned size may be negative so caller must handle appropriately. - // elemSize is the size of the element on the wire, if unknown use `1`. - status_t readOutVectorSizeWithCheck(size_t elmSize, int32_t* size) const; - // Like Parcel.java's readExceptionCode(). Reads the first int32 // off of a Parcel's header, returning 0 or the negative error // code on exceptions, but also deals with skipping over rich @@ -645,6 +639,8 @@ private: status_t flattenBinder(const sp& binder); status_t unflattenBinder(sp* out) const; + status_t readOutVectorSizeWithCheck(size_t elmSize, int32_t* size) const; + template status_t readAligned(T *pArg) const; -- GitLab From 12deef07bed630707b06240df5bec2bab03d9781 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 7 Jun 2023 22:13:28 +0000 Subject: [PATCH 0175/1187] libbinder_ndk_unit_test: unclear kExistingNonNdkService err If surfaceflinger crashes, this will produce really unclear errors, as may be occuring on presubmit. Bug: N/A Change-Id: Ic44081c91aeee19b73731daf460e7beb9e4e5999 Test: N/A --- libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index eba0556023..27ce615565 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -283,8 +283,8 @@ TEST(NdkBinder, CheckServiceThatDoesntExist) { TEST(NdkBinder, CheckServiceThatDoesExist) { AIBinder* binder = AServiceManager_checkService(kExistingNonNdkService); - EXPECT_NE(nullptr, binder); - EXPECT_EQ(STATUS_OK, AIBinder_ping(binder)); + ASSERT_NE(nullptr, binder) << "Could not get " << kExistingNonNdkService; + EXPECT_EQ(STATUS_OK, AIBinder_ping(binder)) << "Could not ping " << kExistingNonNdkService; AIBinder_decStrong(binder); } -- GitLab From 88930f96e88c4d23fa1265cca3e2fdb7aca4fb52 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 7 Jun 2023 10:32:08 -0700 Subject: [PATCH 0176/1187] SF: improve RenderThread jank classificaion Mark UI frames that didn't make it to their expected presentation due to RenderThread animations as dropped. Screenshot from Perfetto: https://screenshot.googleplex.com/3pQuNaDYAhHLYu7 Bug: 210605870 Test: manual Change-Id: Ibc91bcaac2f9296ec0bddd5deebb4289c5b5bf7e --- libs/gui/Surface.cpp | 23 ++++++------ libs/gui/SurfaceComposerClient.cpp | 20 ++--------- .../aidl/android/gui/FrameTimelineInfo.aidl | 6 ++++ libs/gui/include/gui/SurfaceComposerClient.h | 1 - libs/nativewindow/include/system/window.h | 31 +++++++++++++--- services/surfaceflinger/Layer.cpp | 36 +++++++++++++++++-- services/surfaceflinger/Layer.h | 6 ++-- .../fuzzer/surfaceflinger_layer_fuzzer.cpp | 2 +- 8 files changed, 85 insertions(+), 40 deletions(-) diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index ed691006e9..53a2f64d11 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1792,19 +1792,20 @@ int Surface::dispatchGetLastQueuedBuffer2(va_list args) { int Surface::dispatchSetFrameTimelineInfo(va_list args) { ATRACE_CALL(); - auto frameNumber = static_cast(va_arg(args, uint64_t)); - auto frameTimelineVsyncId = static_cast(va_arg(args, int64_t)); - auto inputEventId = static_cast(va_arg(args, int32_t)); - auto startTimeNanos = static_cast(va_arg(args, int64_t)); - auto useForRefreshRateSelection = static_cast(va_arg(args, int32_t)); - ALOGV("Surface::%s", __func__); + + const auto nativeWindowFtlInfo = static_cast( + va_arg(args, ANativeWindowFrameTimelineInfo)); + FrameTimelineInfo ftlInfo; - ftlInfo.vsyncId = frameTimelineVsyncId; - ftlInfo.inputEventId = inputEventId; - ftlInfo.startTimeNanos = startTimeNanos; - ftlInfo.useForRefreshRateSelection = useForRefreshRateSelection; - return setFrameTimelineInfo(frameNumber, ftlInfo); + ftlInfo.vsyncId = nativeWindowFtlInfo.frameTimelineVsyncId; + ftlInfo.inputEventId = nativeWindowFtlInfo.inputEventId; + ftlInfo.startTimeNanos = nativeWindowFtlInfo.startTimeNanos; + ftlInfo.useForRefreshRateSelection = nativeWindowFtlInfo.useForRefreshRateSelection; + ftlInfo.skippedFrameVsyncId = nativeWindowFtlInfo.skippedFrameVsyncId; + ftlInfo.skippedFrameStartTimeNanos = nativeWindowFtlInfo.skippedFrameStartTimeNanos; + + return setFrameTimelineInfo(nativeWindowFtlInfo.frameNumber, ftlInfo); } bool Surface::transformToDisplayInverse() const { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 0fda358b63..5bc05ef0d8 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1027,7 +1027,7 @@ void SurfaceComposerClient::Transaction::clear() { mEarlyWakeupEnd = false; mDesiredPresentTime = 0; mIsAutoTimestamp = true; - clearFrameTimelineInfo(mFrameTimelineInfo); + mFrameTimelineInfo = {}; mApplyToken = nullptr; mMergedTransactionIds.clear(); } @@ -2279,27 +2279,13 @@ void SurfaceComposerClient::Transaction::mergeFrameTimelineInfo(FrameTimelineInf if (t.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID && other.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { if (other.vsyncId > t.vsyncId) { - t.vsyncId = other.vsyncId; - t.inputEventId = other.inputEventId; - t.startTimeNanos = other.startTimeNanos; - t.useForRefreshRateSelection = other.useForRefreshRateSelection; + t = other; } } else if (t.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { - t.vsyncId = other.vsyncId; - t.inputEventId = other.inputEventId; - t.startTimeNanos = other.startTimeNanos; - t.useForRefreshRateSelection = other.useForRefreshRateSelection; + t = other; } } -// copied from FrameTimelineInfo::clear() -void SurfaceComposerClient::Transaction::clearFrameTimelineInfo(FrameTimelineInfo& t) { - t.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID; - t.inputEventId = os::IInputConstants::INVALID_INPUT_EVENT_ID; - t.startTimeNanos = 0; - t.useForRefreshRateSelection = false; -} - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrustedPresentationCallback( const sp& sc, TrustedPresentationCallback cb, diff --git a/libs/gui/aidl/android/gui/FrameTimelineInfo.aidl b/libs/gui/aidl/android/gui/FrameTimelineInfo.aidl index 6a86c6a5cd..4b647a4ad2 100644 --- a/libs/gui/aidl/android/gui/FrameTimelineInfo.aidl +++ b/libs/gui/aidl/android/gui/FrameTimelineInfo.aidl @@ -37,4 +37,10 @@ parcelable FrameTimelineInfo { // Whether this vsyncId should be used to heuristically select the display refresh rate // TODO(b/281695725): Clean this up once TextureView use setFrameRate API boolean useForRefreshRateSelection = false; + + // The VsyncId of a frame that was not drawn and squashed into this frame. + long skippedFrameVsyncId = INVALID_VSYNC_ID; + + // The start time of a frame that was not drawn and squashed into this frame. + long skippedFrameStartTimeNanos = 0; } diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index fb57f63dad..3cf57b11e9 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -410,7 +410,6 @@ public: static sp sApplyToken; void releaseBufferIfOverwriting(const layer_state_t& state); static void mergeFrameTimelineInfo(FrameTimelineInfo& t, const FrameTimelineInfo& other); - static void clearFrameTimelineInfo(FrameTimelineInfo& t); protected: std::unordered_map, ComposerState, IBinderHash> mComposerStates; diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 0fee3c112e..edaa422e55 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1066,12 +1066,33 @@ static inline int native_window_set_frame_rate(struct ANativeWindow* window, flo (int)compatibility, (int)changeFrameRateStrategy); } +struct ANativeWindowFrameTimelineInfo { + // Frame Id received from ANativeWindow_getNextFrameId. + uint64_t frameNumber; + + // VsyncId received from the Choreographer callback that started this frame. + int64_t frameTimelineVsyncId; + + // Input Event ID received from the input event that started this frame. + int32_t inputEventId; + + // The time which this frame rendering started (i.e. when Choreographer callback actually run) + int64_t startTimeNanos; + + // Whether or not to use the vsyncId to determine the refresh rate. Used for TextureView only. + int32_t useForRefreshRateSelection; + + // The VsyncId of a frame that was not drawn and squashed into this frame. + // Used for UI thread updates that were not picked up by RenderThread on time. + int64_t skippedFrameVsyncId; + + // The start time of a frame that was not drawn and squashed into this frame. + int64_t skippedFrameStartTimeNanos; +}; + static inline int native_window_set_frame_timeline_info( - struct ANativeWindow* window, uint64_t frameNumber, int64_t frameTimelineVsyncId, - int32_t inputEventId, int64_t startTimeNanos, int32_t useForRefreshRateSelection) { - return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, frameNumber, - frameTimelineVsyncId, inputEventId, startTimeNanos, - useForRefreshRateSelection); + struct ANativeWindow* window, struct ANativeWindowFrameTimelineInfo frameTimelineInfo) { + return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, frameTimelineInfo); } // ------------------------------------------------------------------------------------------------ diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index cf1b0184e7..f627501c4f 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1349,6 +1349,8 @@ void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& i mDrawingState.bufferSurfaceFrameTX = createSurfaceFrameForBuffer(info, postTime, mTransactionName); } + + setFrameTimelineVsyncForSkippedFrames(info, postTime, mTransactionName); } void Layer::setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info, @@ -1380,11 +1382,13 @@ void Layer::setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInf it->second = createSurfaceFrameForTransaction(info, postTime); } } + + setFrameTimelineVsyncForSkippedFrames(info, postTime, mTransactionName); } void Layer::addSurfaceFrameDroppedForBuffer( - std::shared_ptr& surfaceFrame) { - surfaceFrame->setDropTime(systemTime()); + std::shared_ptr& surfaceFrame, nsecs_t dropTime) { + surfaceFrame->setDropTime(dropTime); surfaceFrame->setPresentState(PresentState::Dropped); mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame); } @@ -1434,6 +1438,32 @@ std::shared_ptr Layer::createSurfaceFrameForBuffer( return surfaceFrame; } +void Layer::setFrameTimelineVsyncForSkippedFrames(const FrameTimelineInfo& info, nsecs_t postTime, + std::string debugName) { + if (info.skippedFrameVsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { + return; + } + + FrameTimelineInfo skippedFrameTimelineInfo = info; + skippedFrameTimelineInfo.vsyncId = info.skippedFrameVsyncId; + + auto surfaceFrame = + mFlinger->mFrameTimeline->createSurfaceFrameForToken(skippedFrameTimelineInfo, + mOwnerPid, mOwnerUid, + getSequence(), mName, debugName, + /*isBuffer*/ false, getGameMode()); + surfaceFrame->setActualStartTime(skippedFrameTimelineInfo.skippedFrameStartTimeNanos); + // For Transactions, the post time is considered to be both queue and acquire fence time. + surfaceFrame->setActualQueueTime(postTime); + surfaceFrame->setAcquireFenceTime(postTime); + const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); + if (fps) { + surfaceFrame->setRenderRate(*fps); + } + onSurfaceFrameCreated(surfaceFrame); + addSurfaceFrameDroppedForBuffer(surfaceFrame, postTime); +} + bool Layer::setFrameRateForLayerTreeLegacy(FrameRate frameRate) { if (mDrawingState.frameRateForLayerTree == frameRate) { return false; @@ -3067,7 +3097,7 @@ bool Layer::setBuffer(std::shared_ptr& buffer, decrementPendingBufferCount(); if (mDrawingState.bufferSurfaceFrameTX != nullptr && mDrawingState.bufferSurfaceFrameTX->getPresentState() != PresentState::Presented) { - addSurfaceFrameDroppedForBuffer(mDrawingState.bufferSurfaceFrameTX); + addSurfaceFrameDroppedForBuffer(mDrawingState.bufferSurfaceFrameTX, systemTime()); mDrawingState.bufferSurfaceFrameTX.reset(); } } else if (EARLY_RELEASE_ENABLED && mLastClientCompositionFence != nullptr) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index f34fdd9095..2fbbbdcb5c 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -785,8 +785,8 @@ public: void setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info, nsecs_t postTime); - void addSurfaceFrameDroppedForBuffer( - std::shared_ptr& surfaceFrame); + void addSurfaceFrameDroppedForBuffer(std::shared_ptr& surfaceFrame, + nsecs_t dropTime); void addSurfaceFramePresentedForBuffer( std::shared_ptr& surfaceFrame, nsecs_t acquireFenceTime, nsecs_t currentLatchTime); @@ -795,6 +795,8 @@ public: const FrameTimelineInfo& info, nsecs_t postTime); std::shared_ptr createSurfaceFrameForBuffer( const FrameTimelineInfo& info, nsecs_t queueTime, std::string debugName); + void setFrameTimelineVsyncForSkippedFrames(const FrameTimelineInfo& info, nsecs_t postTime, + std::string debugName); bool setTrustedPresentationInfo(TrustedPresentationThresholds const& thresholds, TrustedPresentationListener const& listener); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp index 921cae4e41..9f0bddea1e 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp @@ -106,7 +106,7 @@ void LayerFuzzer::invokeEffectLayer() { effectLayer->addSurfaceFramePresentedForBuffer(surfaceFrame, mFdp.ConsumeIntegral() /*acquireTime*/, mFdp.ConsumeIntegral() /*currentTime*/); - effectLayer->addSurfaceFrameDroppedForBuffer(surfaceFrame1); + effectLayer->addSurfaceFrameDroppedForBuffer(surfaceFrame1, mFdp.ConsumeIntegral()); parent.clear(); client.clear(); -- GitLab From 8eb9c553dd0789b72587e163023631df4426823a Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Thu, 8 Jun 2023 18:05:07 +0000 Subject: [PATCH 0177/1187] InputDispatcher: fix code for clang update After clang update, we got below errors: frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp:5882:27: error: declaration shadows a local variable [-Werror,-Wshadow-uncaptured-local] auto command = [this, application = std::move(application)]() REQUIRES(mLock) { ^ frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp:5877:75: note: previous declaration is here void InputDispatcher::onAnrLocked(std::shared_ptr application) { ^ frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp:5945:39: error: declaration shadows a local variable [-Werror,-Wshadow-uncaptured-local] auto command = [this, token, pid, reason = std::move(reason)]() REQUIRES(mLock) { ^ frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp:5944:71: note: previous declaration is here std::string reason) { ^ Bug: 280683256 Test: build with clang-r498229 Change-Id: I478067e4dff9e6d512e84ca5a9f394d4defb89ee --- services/inputflinger/dispatcher/InputDispatcher.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 96164c07f9..9b62894433 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -5879,9 +5879,9 @@ void InputDispatcher::onAnrLocked(std::shared_ptr applic StringPrintf("%s does not have a focused window", application->getName().c_str()); updateLastAnrStateLocked(*application, reason); - auto command = [this, application = std::move(application)]() REQUIRES(mLock) { + auto command = [this, app = std::move(application)]() REQUIRES(mLock) { scoped_unlock unlock(mLock); - mPolicy->notifyNoFocusedWindowAnr(application); + mPolicy->notifyNoFocusedWindowAnr(app); }; postCommandLocked(std::move(command)); } @@ -5942,9 +5942,9 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingCommand(const sp& void InputDispatcher::sendWindowUnresponsiveCommandLocked(const sp& token, std::optional pid, std::string reason) { - auto command = [this, token, pid, reason = std::move(reason)]() REQUIRES(mLock) { + auto command = [this, token, pid, r = std::move(reason)]() REQUIRES(mLock) { scoped_unlock unlock(mLock); - mPolicy->notifyWindowUnresponsive(token, pid, reason); + mPolicy->notifyWindowUnresponsive(token, pid, r); }; postCommandLocked(std::move(command)); } -- GitLab From 92ef86f1e43c83ce55d2c842633f7709d6c2c4d2 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 8 Jun 2023 20:13:55 +0000 Subject: [PATCH 0178/1187] binderRustNdkInteropTest: C++ in-process to Rust C++<->Rust FFI just got that much easier. Bug: 286246993 Test: binderRustNdkInteropTest Change-Id: I92ae9b7f2ff2988f6ac4d248eaa91606062f4709 --- libs/binder/rust/tests/binderRustNdkInteropTest.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/libs/binder/rust/tests/binderRustNdkInteropTest.cpp b/libs/binder/rust/tests/binderRustNdkInteropTest.cpp index 59ca6edf12..663b9bbe37 100644 --- a/libs/binder/rust/tests/binderRustNdkInteropTest.cpp +++ b/libs/binder/rust/tests/binderRustNdkInteropTest.cpp @@ -54,14 +54,12 @@ TEST(RustNdkInterop, NdkCanCallRust) { EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get())); auto interface = aidl::IBinderRustNdkInteropTest::fromBinder(binder); - // TODO(b/167723746): this test requires that fromBinder allow association - // with an already associated local binder by treating it as remote. - EXPECT_EQ(interface, nullptr); + EXPECT_NE(interface, nullptr); - // std::string in("testing"); - // std::string out; - // EXPECT_TRUE(interface->echo(in, &out).isOk()); - // EXPECT_EQ(in, out); + std::string in("testing"); + std::string out; + EXPECT_TRUE(interface->echo(in, &out).isOk()); + EXPECT_EQ(in, out); } int main(int argc, char** argv) { -- GitLab From 39a38d473fd5694c8439e93b8f1404bce47765a7 Mon Sep 17 00:00:00 2001 From: Sungtak Lee Date: Thu, 8 Jun 2023 21:43:19 +0000 Subject: [PATCH 0179/1187] Add toString() to HardwareBuffer Bug: N/A Test: m (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2ed5cf9a07889c97d9fc28471934f1115c72736f) Merged-In: I7452fd53876eacb0a062d5a5c601594de2190ee1 Change-Id: I7452fd53876eacb0a062d5a5c601594de2190ee1 --- .../include/android/hardware_buffer_aidl.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libs/nativewindow/include/android/hardware_buffer_aidl.h b/libs/nativewindow/include/android/hardware_buffer_aidl.h index 9fea21e34e..551a1a14dd 100644 --- a/libs/nativewindow/include/android/hardware_buffer_aidl.h +++ b/libs/nativewindow/include/android/hardware_buffer_aidl.h @@ -34,6 +34,10 @@ #include #include +#ifdef __cplusplus +#include +#endif + __BEGIN_DECLS /** @@ -135,6 +139,15 @@ public: return ret; } + inline std::string toString() const { + if (!mBuffer) { + return ""; + } + uint64_t id = 0; + AHardwareBuffer_getId(mBuffer, &id); + return ""; + } + private: HardwareBuffer(const HardwareBuffer& other) = delete; HardwareBuffer& operator=(const HardwareBuffer& other) = delete; -- GitLab From a203d7105ac02e20f3be6e78ba4ff5cf8dadaa2a Mon Sep 17 00:00:00 2001 From: Alex Buynytskyy Date: Thu, 8 Jun 2023 12:56:15 -0700 Subject: [PATCH 0180/1187] Add more tracing to pinpoint the perf regressions. Bug: 275468553 Test: presubmit Change-Id: I26ff01846181f9750cd9e1963eb77c960fe96016 --- cmds/installd/InstalldNativeService.cpp | 29 ++++++++++++++++++++----- cmds/installd/SysTrace.h | 12 ++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index bb6639e1a8..99f7669a57 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -416,10 +416,12 @@ status_t InstalldNativeService::dump(int fd, const Vector& /* args */) */ static int restorecon_app_data_lazy(const std::string& path, const std::string& seInfo, uid_t uid, bool existing) { + ScopedTrace tracer("restorecon-lazy"); int res = 0; char* before = nullptr; char* after = nullptr; if (!existing) { + ScopedTrace tracer("new-path"); if (selinux_android_restorecon_pkgdir(path.c_str(), seInfo.c_str(), uid, SELINUX_ANDROID_RESTORECON_RECURSE) < 0) { PLOG(ERROR) << "Failed recursive restorecon for " << path; @@ -446,6 +448,7 @@ static int restorecon_app_data_lazy(const std::string& path, const std::string& // If the initial top-level restorecon above changed the label, then go // back and restorecon everything recursively if (strcmp(before, after)) { + ScopedTrace tracer("label-change"); if (existing) { LOG(DEBUG) << "Detected label change from " << before << " to " << after << " at " << path << "; running recursive restorecon"; @@ -480,11 +483,15 @@ static bool internal_storage_has_project_id() { static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid, long project_id) { - if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) { - PLOG(ERROR) << "Failed to prepare " << path; - return -1; + { + ScopedTrace tracer("prepare-dir"); + if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) { + PLOG(ERROR) << "Failed to prepare " << path; + return -1; + } } if (internal_storage_has_project_id()) { + ScopedTrace tracer("set-quota"); return set_quota_project_id(path, project_id, true); } return 0; @@ -493,14 +500,20 @@ static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t ui static int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode, uid_t uid, gid_t gid, long project_id) { auto path = StringPrintf("%s/%s", parent.c_str(), name); - int ret = prepare_app_cache_dir(parent, name, target_mode, uid, gid); + int ret; + { + ScopedTrace tracer("prepare-cache-dir"); + ret = prepare_app_cache_dir(parent, name, target_mode, uid, gid); + } if (ret == 0 && internal_storage_has_project_id()) { + ScopedTrace tracer("set-quota-cache-dir"); return set_quota_project_id(path, project_id, true); } return ret; } static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) { + ScopedTrace tracer("prepare-app-profile"); int32_t uid = multiuser_get_uid(userId, appId); int shared_app_gid = multiuser_get_shared_gid(userId, appId); if (shared_app_gid == -1) { @@ -633,6 +646,7 @@ static binder::Status createAppDataDirs(const std::string& path, int32_t uid, in int32_t previousUid, int32_t cacheGid, const std::string& seInfo, mode_t targetMode, long projectIdApp, long projectIdCache) { + ScopedTrace tracer("create-dirs"); struct stat st{}; bool parent_dir_exists = (stat(path.c_str(), &st) == 0); @@ -709,6 +723,7 @@ binder::Status InstalldNativeService::createAppDataLocked( long projectIdCache = get_project_id(uid, PROJECT_ID_APP_CACHE_START); if (flags & FLAG_STORAGE_CE) { + ScopedTrace tracer("ce"); auto path = create_data_user_ce_package_path(uuid_, userId, pkgname); auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode, @@ -735,6 +750,7 @@ binder::Status InstalldNativeService::createAppDataLocked( } } if (flags & FLAG_STORAGE_DE) { + ScopedTrace tracer("de"); auto path = create_data_user_de_package_path(uuid_, userId, pkgname); auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode, @@ -752,13 +768,14 @@ binder::Status InstalldNativeService::createAppDataLocked( } if (flags & FLAG_STORAGE_SDK) { + ScopedTrace tracer("sdk"); // Safe to ignore status since we can retry creating this by calling reconcileSdkData auto ignore = createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId, flags); if (!ignore.isOk()) { PLOG(WARNING) << "Failed to create sdk data package directory for " << packageName; } - } else { + ScopedTrace tracer("destroy-sdk"); // Package does not need sdk storage. Remove it. destroySdkSandboxDataPackageDirectory(uuid, packageName, userId, flags); } @@ -1850,6 +1867,8 @@ binder::Status InstalldNativeService::createUserData(const std::optionalc_str() : nullptr; if (flags & FLAG_STORAGE_DE) { if (uuid_ == nullptr) { diff --git a/cmds/installd/SysTrace.h b/cmds/installd/SysTrace.h index 18506a9258..0deaeb4341 100644 --- a/cmds/installd/SysTrace.h +++ b/cmds/installd/SysTrace.h @@ -19,4 +19,16 @@ namespace android::installd { void atrace_pm_begin(const char*); void atrace_pm_end(); + +class ScopedTrace { +public: + explicit ScopedTrace(const char* label) { atrace_pm_begin(label); } + ~ScopedTrace() { atrace_pm_end(); } + +private: + ScopedTrace(const ScopedTrace&) = delete; + ScopedTrace& operator=(const ScopedTrace&) = delete; + ScopedTrace(ScopedTrace&&) = delete; + ScopedTrace& operator=(ScopedTrace&&) = delete; +}; } /* namespace android::installd */ -- GitLab From 672222b33e4b9bc9ecf7d9c46a4d2b3b430df337 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 9 Jun 2023 00:48:41 +0000 Subject: [PATCH 0181/1187] GraphicsBuffer: comparison operators All AIDL structures are comparable. It makes it possible to use them as keys in a map. We can define an order for any type on the computer, since we can always take the address. Though - this may not always be the most useful meaning. We didn't discover this earlier, because this was only ever used in an argument. Regardless, it seems like a useful thing to have. Also - we shouldn't add complexity to AIDL to make this optional. It has deep consequences, since any element, even 4-5 structures deep could cause a struct to not be comparable. If someone adds a non-comparable type to a structure in a later version, AIDL packages depending on it might find it impossible to upgrade without making their structures non-comparable, which could break client code. Bug: N/A Test: N/A (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2d4660083c7eb0ea56040745830abcb148d8de54) Merged-In: I627adbd110d037246ce307f4984739008fe91c33 Change-Id: I627adbd110d037246ce307f4984739008fe91c33 --- libs/nativewindow/include/android/hardware_buffer_aidl.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libs/nativewindow/include/android/hardware_buffer_aidl.h b/libs/nativewindow/include/android/hardware_buffer_aidl.h index 551a1a14dd..e269f0dddf 100644 --- a/libs/nativewindow/include/android/hardware_buffer_aidl.h +++ b/libs/nativewindow/include/android/hardware_buffer_aidl.h @@ -123,6 +123,13 @@ public: inline AHardwareBuffer* _Nullable get() const { return mBuffer; } inline explicit operator bool () const { return mBuffer != nullptr; } + inline bool operator!=(const HardwareBuffer& rhs) const { return get() != rhs.get(); } + inline bool operator<(const HardwareBuffer& rhs) const { return get() < rhs.get(); } + inline bool operator<=(const HardwareBuffer& rhs) const { return get() <= rhs.get(); } + inline bool operator==(const HardwareBuffer& rhs) const { return get() == rhs.get(); } + inline bool operator>(const HardwareBuffer& rhs) const { return get() > rhs.get(); } + inline bool operator>=(const HardwareBuffer& rhs) const { return get() >= rhs.get(); } + HardwareBuffer& operator=(HardwareBuffer&& other) noexcept { reset(other.release()); return *this; -- GitLab From cbbf330356a3845be4c48adb792aede9968c5934 Mon Sep 17 00:00:00 2001 From: Vinh Tran Date: Thu, 25 May 2023 09:19:56 -0400 Subject: [PATCH 0182/1187] Migrate aidl filegroup to aidl_library ag/22717101 uses aidl.deps prop in filegroup to include aidl headers. aosp/2571770 introduced aidl_library module type to better enforce explicit aidl headers in Android.bp. This CL moves the libgui_aidl modified in ag/22717101 to aidl_library so we can deprecate the aidl.deps prop in filegroup. Bug: 279960133 Test: m libgui Change-Id: I17b448607d27ede681ffc42dc35077109463b9d7 --- libs/gui/Android.bp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index bf34987b9e..72c6b1570a 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -129,13 +129,24 @@ cc_library_static { }, } -filegroup { +aidl_library { + name: "libgui_aidl_hdrs", + hdrs: [ + "android/gui/DisplayInfo.aidl", + "android/gui/FocusRequest.aidl", + "android/gui/InputApplicationInfo.aidl", + "android/gui/IWindowInfosListener.aidl", + "android/gui/IWindowInfosReportedListener.aidl", + "android/gui/WindowInfo.aidl", + "android/gui/WindowInfosUpdate.aidl", + ], +} + +aidl_library { name: "libgui_aidl", srcs: ["aidl/**/*.aidl"], - path: "aidl/", - aidl: { - deps: [":android_gui_aidl"], - }, + strip_import_prefix: "aidl", + deps: ["libgui_aidl_hdrs"], } filegroup { @@ -147,9 +158,6 @@ filegroup { cc_library_static { name: "libgui_aidl_static", vendor_available: true, - srcs: [ - ":libgui_aidl", - ], shared_libs: [ "libbinder", @@ -175,9 +183,7 @@ cc_library_static { aidl: { export_aidl_headers: true, - include_dirs: [ - "frameworks/native/libs/gui", - ], + libs: ["libgui_aidl"], }, } -- GitLab From 37d4dcbba2052f2906e19a4973b6801058bf76e9 Mon Sep 17 00:00:00 2001 From: Vinh Tran Date: Thu, 25 May 2023 09:19:56 -0400 Subject: [PATCH 0183/1187] Migrate aidl filegroup to aidl_library ag/22717101 uses aidl.deps prop in filegroup to include aidl headers. aosp/2571770 introduced aidl_library module type to better enforce explicit aidl headers in Android.bp. This CL moves the libgui_aidl modified in ag/22717101 to aidl_library so we can deprecate the aidl.deps prop in filegroup. Bug: 279960133 Test: m libgui Change-Id: I17b448607d27ede681ffc42dc35077109463b9d7 (cherry picked from commit cbbf330356a3845be4c48adb792aede9968c5934) --- libs/gui/Android.bp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index bf2d7b6243..342f132f0c 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -129,13 +129,24 @@ cc_library_static { }, } -filegroup { +aidl_library { + name: "libgui_aidl_hdrs", + hdrs: [ + "android/gui/DisplayInfo.aidl", + "android/gui/FocusRequest.aidl", + "android/gui/InputApplicationInfo.aidl", + "android/gui/IWindowInfosListener.aidl", + "android/gui/IWindowInfosReportedListener.aidl", + "android/gui/WindowInfo.aidl", + "android/gui/WindowInfosUpdate.aidl", + ], +} + +aidl_library { name: "libgui_aidl", srcs: ["aidl/**/*.aidl"], - path: "aidl/", - aidl: { - deps: [":android_gui_aidl"], - }, + strip_import_prefix: "aidl", + deps: ["libgui_aidl_hdrs"], } filegroup { @@ -147,9 +158,6 @@ filegroup { cc_library_static { name: "libgui_aidl_static", vendor_available: true, - srcs: [ - ":libgui_aidl", - ], shared_libs: [ "libbinder", @@ -175,9 +183,7 @@ cc_library_static { aidl: { export_aidl_headers: true, - include_dirs: [ - "frameworks/native/libs/gui", - ], + libs: ["libgui_aidl"], }, } -- GitLab From 1790bb5d5bd420047ed14ec0bfd2c73478c747d0 Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Sun, 11 Jun 2023 07:07:27 +0530 Subject: [PATCH 0184/1187] ultrahdr: do not select less accurate integer method during dct At high quality setting, less accurate integer method can have larger psnr drops. Switch to default setting Bug: 286617381 Test: ./libultrahdr_app -p inp_p010.yuv -y inp_420p.yuv -w 1920 -h 1080 -o 0 Change-Id: Ide126b87262e1c9a20edca7873b6ca27fc52b2cb --- libs/ultrahdr/jpegdecoderhelper.cpp | 2 +- libs/ultrahdr/jpegencoderhelper.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/ultrahdr/jpegdecoderhelper.cpp b/libs/ultrahdr/jpegdecoderhelper.cpp index fac90c503d..6c3a8c10b7 100644 --- a/libs/ultrahdr/jpegdecoderhelper.cpp +++ b/libs/ultrahdr/jpegdecoderhelper.cpp @@ -242,7 +242,7 @@ bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA) cinfo.raw_data_out = TRUE; } - cinfo.dct_method = JDCT_IFAST; + cinfo.dct_method = JDCT_ISLOW; jpeg_start_decompress(&cinfo); diff --git a/libs/ultrahdr/jpegencoderhelper.cpp b/libs/ultrahdr/jpegencoderhelper.cpp index 10a763035f..867ffbb4e9 100644 --- a/libs/ultrahdr/jpegencoderhelper.cpp +++ b/libs/ultrahdr/jpegencoderhelper.cpp @@ -139,7 +139,7 @@ void JpegEncoderHelper::setJpegCompressStruct(int width, int height, int quality jpeg_set_quality(cinfo, quality, TRUE); jpeg_set_colorspace(cinfo, isSingleChannel ? JCS_GRAYSCALE : JCS_YCbCr); cinfo->raw_data_in = TRUE; - cinfo->dct_method = JDCT_IFAST; + cinfo->dct_method = JDCT_ISLOW; if (!isSingleChannel) { // Configure sampling factors. The sampling factor is JPEG subsampling 420 because the -- GitLab From 5818c65aafcdef4feae6f57091e1083cd64247df Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 14 Jun 2023 00:53:20 +0000 Subject: [PATCH 0185/1187] Remove write permission from file mode of top-level user dirs https://r.android.com/2620458 and https://r.android.com/2617599 are removing the write mode bit from the top-level user directories, in order to make the DAC consistent with the SELinux policy. This commit makes the corresponding change to InstalldNativeService::tryMountDataMirror(). This method creates /data_mirror/data_ce/$volume_uuid and bind-mounts /data/user onto it, and similarly for several other directories. It should not really need to be changed, but the issue is that for adoptable storage it runs multiple times, so the modes it uses to prepare the directories with must match the modes of the corresponding bind-mounted directories. Bug: 285239971 Test: sm set-virtual-disk true sm partition disk:7,392 private Verified no error message from tryMountDataMirror() in log Change-Id: I17dfbe10909b34c2046a4d5b4ffd7764d5ae083b --- cmds/installd/InstalldNativeService.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 99f7669a57..e84428ee41 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -3574,22 +3574,22 @@ binder::Status InstalldNativeService::tryMountDataMirror( std::lock_guard lock(mMountsLock); std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_)); - if (fs_prepare_dir(mirrorVolCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) { + if (fs_prepare_dir(mirrorVolCePath.c_str(), 0511, AID_SYSTEM, AID_SYSTEM) != 0) { return error("Failed to create CE data mirror"); } std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_)); - if (fs_prepare_dir(mirrorVolDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) { + if (fs_prepare_dir(mirrorVolDePath.c_str(), 0511, AID_SYSTEM, AID_SYSTEM) != 0) { return error("Failed to create DE data mirror"); } std::string mirrorVolMiscCePath(StringPrintf("%s/%s", kMiscMirrorCePath, uuid_)); - if (fs_prepare_dir(mirrorVolMiscCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) { + if (fs_prepare_dir(mirrorVolMiscCePath.c_str(), 0511, AID_SYSTEM, AID_SYSTEM) != 0) { return error("Failed to create CE misc mirror"); } std::string mirrorVolMiscDePath(StringPrintf("%s/%s", kMiscMirrorDePath, uuid_)); - if (fs_prepare_dir(mirrorVolMiscDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) { + if (fs_prepare_dir(mirrorVolMiscDePath.c_str(), 0511, AID_SYSTEM, AID_SYSTEM) != 0) { return error("Failed to create DE misc mirror"); } -- GitLab From 0ebdaad0defde25b6391504ca96ca3c406777cc7 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 14 Jun 2023 19:33:37 +0000 Subject: [PATCH 0186/1187] binderRpcTest: threadpool race leak SessionWithIncomingThreadpoolDoesntLeak is flaking at 0.02%. This is another small fix to avoid noise in the tests. It's not great, but we know it works because OnewayCallExhaustion uses this solution and does not flake. Bug: 285206261 Test: binderRpcTest --gtest_filter="*SessionWithIncomingThreadpoolDoesntLeak*" Change-Id: I8a1678e9633db71cb4afda2f0f5c108ca784f803 --- libs/binder/tests/binderRpcTest.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 1ff1de4db8..d352ce5bca 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -691,7 +691,11 @@ TEST_P(BinderRpc, SessionWithIncomingThreadpoolDoesntLeak) { EXPECT_EQ(nullptr, session.promote()); - sleep(1); // give time for remote session to shutdown + // now that it has died, wait for the remote session to shutdown + std::vector remoteCounts; + do { + EXPECT_OK(proc.rootIface->countBinders(&remoteCounts)); + } while (remoteCounts.size() > 1); } TEST_P(BinderRpc, SingleDeathRecipient) { -- GitLab From 6b662769e7a3962772f5202628e1e494f5ffbfd5 Mon Sep 17 00:00:00 2001 From: Yeabkal Wubshit Date: Mon, 22 May 2023 23:07:31 -0700 Subject: [PATCH 0187/1187] Create Input SlopController Create a basic input slop controller, and use it for rotary inputs. Bug: 285957835 Test: atest SlopControllerTest Change-Id: I0cabfed1f064b849f8151f069e1241292cc374cf --- services/inputflinger/reader/Android.bp | 1 + .../mapper/RotaryEncoderInputMapper.cpp | 12 +++ .../reader/mapper/RotaryEncoderInputMapper.h | 2 + .../reader/mapper/SlopController.cpp | 81 +++++++++++++++ .../reader/mapper/SlopController.h | 55 +++++++++++ services/inputflinger/tests/Android.bp | 1 + .../tests/SlopController_test.cpp | 99 +++++++++++++++++++ 7 files changed, 251 insertions(+) create mode 100644 services/inputflinger/reader/mapper/SlopController.cpp create mode 100644 services/inputflinger/reader/mapper/SlopController.h create mode 100644 services/inputflinger/tests/SlopController_test.cpp diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index b0edb5746c..a896d26d54 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -52,6 +52,7 @@ filegroup { "mapper/RotaryEncoderInputMapper.cpp", "mapper/SensorInputMapper.cpp", "mapper/SingleTouchInputMapper.cpp", + "mapper/SlopController.cpp", "mapper/SwitchInputMapper.cpp", "mapper/TouchCursorInputMapperCommon.cpp", "mapper/TouchInputMapper.cpp", diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp index 13f2e59db9..5220b10211 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp @@ -30,6 +30,14 @@ RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDeviceContext& deviceCon const InputReaderConfiguration& readerConfig) : InputMapper(deviceContext, readerConfig), mOrientation(ui::ROTATION_0) { mSource = AINPUT_SOURCE_ROTARY_ENCODER; + + const PropertyMap& config = getDeviceContext().getConfiguration(); + float slopThreshold = config.getInt("rotary_encoder.slop_threshold").value_or(0); + int32_t slopDurationMs = config.getInt("rotary_encoder.slop_duration_ms").value_or(0); + if (slopThreshold > 0 && slopDurationMs > 0) { + mSlopController = std::make_unique(slopThreshold, + (nsecs_t)(slopDurationMs * 1000000)); + } } RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {} @@ -103,6 +111,10 @@ std::list RotaryEncoderInputMapper::sync(nsecs_t when, nsecs_t readT std::list out; float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel(); + if (mSlopController) { + scroll = mSlopController->consumeEvent(when, scroll); + } + bool scrolled = scroll != 0; // Send motion event. diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h index 9e2e8c4342..4732bcdb44 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h @@ -20,6 +20,7 @@ #include "CursorScrollAccumulator.h" #include "InputMapper.h" +#include "SlopController.h" namespace android { @@ -46,6 +47,7 @@ private: int32_t mSource; float mScalingFactor; ui::Rotation mOrientation; + std::unique_ptr mSlopController = nullptr; explicit RotaryEncoderInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig); diff --git a/services/inputflinger/reader/mapper/SlopController.cpp b/services/inputflinger/reader/mapper/SlopController.cpp new file mode 100644 index 0000000000..6f31d0ebe3 --- /dev/null +++ b/services/inputflinger/reader/mapper/SlopController.cpp @@ -0,0 +1,81 @@ +/* + * Copyright 2023 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. + */ + +// clang-format off +#include "../Macros.h" +// clang-format on + +#include "SlopController.h" + +namespace { +int signOf(float value) { + if (value == 0) return 0; + if (value > 0) return 1; + return -1; +} +} // namespace + +namespace android { + +SlopController::SlopController(float slopThreshold, nsecs_t slopDurationNanos) + : mSlopThreshold(slopThreshold), mSlopDurationNanos(slopDurationNanos) {} + +SlopController::~SlopController() {} + +float SlopController::consumeEvent(nsecs_t eventTimeNanos, float value) { + if (mSlopDurationNanos == 0) { + return value; + } + + if (shouldResetSlopTracking(eventTimeNanos, value)) { + mCumulativeValue = 0; + mHasSlopBeenMet = false; + } + + mLastEventTimeNanos = eventTimeNanos; + + if (mHasSlopBeenMet) { + // Since slop has already been met, we know that all of the current value would pass the + // slop threshold. So return that, without any further processing. + return value; + } + + mCumulativeValue += value; + + if (abs(mCumulativeValue) >= mSlopThreshold) { + mHasSlopBeenMet = true; + // Return the amount of value that exceeds the slop. + return signOf(value) * (abs(mCumulativeValue) - mSlopThreshold); + } + + return 0; +} + +bool SlopController::shouldResetSlopTracking(nsecs_t eventTimeNanos, float value) { + const nsecs_t ageNanos = eventTimeNanos - mLastEventTimeNanos; + if (ageNanos >= mSlopDurationNanos) { + return true; + } + if (value == 0) { + return false; + } + if (signOf(mCumulativeValue) != signOf(value)) { + return true; + } + return false; +} + +} // namespace android diff --git a/services/inputflinger/reader/mapper/SlopController.h b/services/inputflinger/reader/mapper/SlopController.h new file mode 100644 index 0000000000..bd6ee7770e --- /dev/null +++ b/services/inputflinger/reader/mapper/SlopController.h @@ -0,0 +1,55 @@ +/* + * Copyright 2023 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 + +namespace android { + +/** + * Controls a slop logic. Slop here refers to an approach to try and drop insignificant input + * events. This is helpful in cases where unintentional input events may cause unintended outcomes, + * like scrolling a screen or keeping the screen awake. + * + * Current slop logic: + * "If time since last event > Xns, then discard the next N values." + */ +class SlopController { +public: + SlopController(float slopThreshold, nsecs_t slopDurationNanos); + virtual ~SlopController(); + + /** + * Consumes an event with a given time and value for slop processing. + * Returns an amount <=value that should be consumed. + */ + float consumeEvent(nsecs_t eventTime, float value); + +private: + bool shouldResetSlopTracking(nsecs_t eventTimeNanos, float value); + + /** The amount of event values ignored after an inactivity of the slop duration. */ + const float mSlopThreshold; + /** The duration of inactivity that resets slop controlling. */ + const nsecs_t mSlopDurationNanos; + + nsecs_t mLastEventTimeNanos = 0; + float mCumulativeValue = 0; + bool mHasSlopBeenMet = false; +}; + +} // namespace android diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 300bb85630..370e971a91 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -59,6 +59,7 @@ cc_test { "NotifyArgs_test.cpp", "PreferStylusOverTouch_test.cpp", "PropertyProvider_test.cpp", + "SlopController_test.cpp", "SyncQueue_test.cpp", "TestInputListener.cpp", "TouchpadInputMapper_test.cpp", diff --git a/services/inputflinger/tests/SlopController_test.cpp b/services/inputflinger/tests/SlopController_test.cpp new file mode 100644 index 0000000000..f524acd025 --- /dev/null +++ b/services/inputflinger/tests/SlopController_test.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2023 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 "../reader/mapper/SlopController.h" + +#include + +namespace android { + +// --- SlopControllerTest --- + +TEST(SlopControllerTest, PositiveValues) { + SlopController controller = SlopController(/*slopThreshold=*/5, /*slopDurationNanos=*/100); + + ASSERT_EQ(0, controller.consumeEvent(1000, 1)); + ASSERT_EQ(0, controller.consumeEvent(1003, 3)); + ASSERT_EQ(2, controller.consumeEvent(1005, 3)); + ASSERT_EQ(4, controller.consumeEvent(1009, 4)); + + SlopController controller2 = SlopController(/*slopThreshold=*/5, /*slopDurationNanos=*/100); + + ASSERT_EQ(0, controller2.consumeEvent(1000, 5)); + ASSERT_EQ(3, controller2.consumeEvent(1003, 3)); + ASSERT_EQ(4, controller2.consumeEvent(1005, 4)); +} + +TEST(SlopControllerTest, NegativeValues) { + SlopController controller = SlopController(/*slopThreshold=*/5, /*slopDurationNanos=*/100); + + ASSERT_EQ(0, controller.consumeEvent(1000, -1)); + ASSERT_EQ(0, controller.consumeEvent(1003, -3)); + ASSERT_EQ(-2, controller.consumeEvent(1005, -3)); + ASSERT_EQ(-4, controller.consumeEvent(1009, -4)); + + SlopController controller2 = SlopController(/*slopThreshold=*/5, /*slopDurationNanos=*/100); + + ASSERT_EQ(0, controller2.consumeEvent(1000, -5)); + ASSERT_EQ(-3, controller2.consumeEvent(1003, -3)); + ASSERT_EQ(-4, controller2.consumeEvent(1005, -4)); +} + +TEST(SlopControllerTest, ZeroDoesNotResetSlop) { + SlopController controller = SlopController(/*slopThreshold=*/5, /*slopDurationNanos=*/100); + + ASSERT_EQ(1, controller.consumeEvent(1005, 6)); + ASSERT_EQ(0, controller.consumeEvent(1006, 0)); + ASSERT_EQ(2, controller.consumeEvent(1008, 2)); +} + +TEST(SlopControllerTest, SignChange_ResetsSlop) { + SlopController controller = SlopController(/*slopThreshold=*/5, /*slopDurationNanos=*/100); + + ASSERT_EQ(0, controller.consumeEvent(1000, 2)); + ASSERT_EQ(0, controller.consumeEvent(1001, -4)); + ASSERT_EQ(0, controller.consumeEvent(1002, 3)); + ASSERT_EQ(0, controller.consumeEvent(1003, -2)); + + ASSERT_EQ(1, controller.consumeEvent(1005, 6)); + ASSERT_EQ(0, controller.consumeEvent(1006, 0)); + ASSERT_EQ(2, controller.consumeEvent(1008, 2)); + + ASSERT_EQ(0, controller.consumeEvent(1010, -4)); + ASSERT_EQ(-1, controller.consumeEvent(1011, -2)); + + ASSERT_EQ(0, controller.consumeEvent(1015, 5)); + ASSERT_EQ(2, controller.consumeEvent(1016, 2)); + + ASSERT_EQ(0, controller.consumeEvent(1017, -5)); + ASSERT_EQ(-2, controller.consumeEvent(1018, -2)); +} + +TEST(SlopControllerTest, OldAge_ResetsSlop) { + SlopController controller = SlopController(/*slopThreshold=*/5, /*slopDurationNanos=*/100); + + ASSERT_EQ(1, controller.consumeEvent(1005, 6)); + ASSERT_EQ(0, controller.consumeEvent(1108, 2)); // age exceeds slop duration + + ASSERT_EQ(1, controller.consumeEvent(1110, 4)); + ASSERT_EQ(0, controller.consumeEvent(1210, 2)); // age equals slop duration + + ASSERT_EQ(0, controller.consumeEvent(1215, -3)); + ASSERT_EQ(-2, controller.consumeEvent(1216, -4)); + ASSERT_EQ(-5, controller.consumeEvent(1315, -5)); +} + +} // namespace android -- GitLab From 56fd71b0d4466983d8f5c11466a43df1c6c3a998 Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Thu, 15 Jun 2023 17:01:11 +0100 Subject: [PATCH 0188/1187] Also mount /sys/fs/selinux This mount point is required for apexd, which uses libselinux to adjust label of the compressed APEXes that are decompressed as part of the postinstall hook. Bug: 284277137 Test: m dist Test: system/update_engine/scripts/update_device.py out/dist/ota.zip Change-Id: Ia1a65a4e69b27351941a290210004a93470ae87f --- cmds/installd/otapreopt_chroot.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp index 1b7acabf70..c86993cb06 100644 --- a/cmds/installd/otapreopt_chroot.cpp +++ b/cmds/installd/otapreopt_chroot.cpp @@ -165,7 +165,8 @@ static int otapreopt_chroot(const int argc, char **arg) { // Bind mount necessary directories. constexpr const char* kBindMounts[] = { - "/data", "/dev", "/proc", "/sys" + "/data", "/dev", "/proc", "/sys", + "/sys/fs/selinux" /* Required for apexd which includes libselinux */ }; for (size_t i = 0; i < arraysize(kBindMounts); ++i) { std::string trg = StringPrintf("/postinstall%s", kBindMounts[i]); -- GitLab From 7772039cc5084247450f6113d9a18eca17f672aa Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 14 Jun 2023 23:20:26 +0000 Subject: [PATCH 0189/1187] Parcel: fdsan Marks FDs as owned by the Parcel for clearer errors if other things accidentally own them. Bug: 287093457 Test: boot Test: binderUnitTest Test: binder_parcel_fuzzer (several minutes on-device) Ignore-AOSP-First: this requires some fixes only in git_master to avoid crashing Change-Id: Ibbcc7fdf074a0a1a61ae11f61c8b11f8445aef20 --- libs/binder/Parcel.cpp | 52 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 0aca163eab..1312d223cc 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -69,6 +69,10 @@ typedef uintptr_t binder_uintptr_t; #endif // BINDER_WITH_KERNEL_IPC +#ifdef __BIONIC__ +#include +#endif + #define LOG_REFS(...) // #define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOG_ALLOC(...) @@ -109,6 +113,37 @@ constexpr size_t kMaxFds = 1024; // Maximum size of a blob to transfer in-place. static const size_t BLOB_INPLACE_LIMIT = 16 * 1024; +#if defined(__BIONIC__) +static void FdTag(int fd, const void* old_addr, const void* new_addr) { + if (android_fdsan_exchange_owner_tag) { + uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_PARCEL, + reinterpret_cast(old_addr)); + uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_PARCEL, + reinterpret_cast(new_addr)); + android_fdsan_exchange_owner_tag(fd, old_tag, new_tag); + } +} +static void FdTagClose(int fd, const void* addr) { + if (android_fdsan_close_with_tag) { + uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_PARCEL, + reinterpret_cast(addr)); + android_fdsan_close_with_tag(fd, tag); + } else { + close(fd); + } +} +#else +static void FdTag(int fd, const void* old_addr, const void* new_addr) { + (void)fd; + (void)old_addr; + (void)new_addr; +} +static void FdTagClose(int fd, const void* addr) { + (void)addr; + close(fd); +} +#endif + enum { BLOB_INPLACE = 0, BLOB_ASHMEM_IMMUTABLE = 1, @@ -134,6 +169,9 @@ static void acquire_object(const sp& proc, const flat_binder_objec return; } case BINDER_TYPE_FD: { + if (obj.cookie != 0) { // owned + FdTag(obj.handle, nullptr, who); + } return; } } @@ -159,8 +197,10 @@ static void release_object(const sp& proc, const flat_binder_objec return; } case BINDER_TYPE_FD: { + // note: this path is not used when mOwner, so the tag is also released + // in 'closeFileDescriptors' if (obj.cookie != 0) { // owned - close(obj.handle); + FdTagClose(obj.handle, who); } return; } @@ -554,7 +594,6 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { kernelFields->mObjectsSize++; flat_binder_object* flat = reinterpret_cast(mData + off); - acquire_object(proc, *flat, this); if (flat->hdr.type == BINDER_TYPE_FD) { // If this is a file descriptor, we need to dup it so the @@ -567,6 +606,8 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { err = FDS_NOT_ALLOWED; } } + + acquire_object(proc, *flat, this); } } #else @@ -2517,7 +2558,8 @@ void Parcel::closeFileDescriptors() { reinterpret_cast(mData + kernelFields->mObjects[i]); if (flat->hdr.type == BINDER_TYPE_FD) { // ALOGI("Closing fd: %ld", flat->handle); - close(flat->handle); + // FDs from the kernel are always owned + FdTagClose(flat->handle, this); } } #else // BINDER_WITH_KERNEL_IPC @@ -2598,6 +2640,10 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const bin kernelFields->mObjectsSize = 0; break; } + if (type == BINDER_TYPE_FD) { + // FDs from the kernel are always owned + FdTag(flat->handle, 0, this); + } minOffset = offset + sizeof(flat_binder_object); } scanForFds(); -- GitLab From 5b0ffe096f8b825ea42ff61de501fadc1d8ca418 Mon Sep 17 00:00:00 2001 From: Brian Lindahl Date: Thu, 15 Jun 2023 14:19:43 -0600 Subject: [PATCH 0190/1187] Force HALs to explicitly enable legacy method for clearing buffer caches Some HAL implementations can't support setLayerBuffer multiple times to clear the per-layer buffer caches. Therefore, default this behavior to disabled, and allow HALs to explcitily enable this behavior to obtain the necessary memory savings. Test: play videos with both true and false on both HIDL and AIDL Bug: 285561686 Change-Id: I928cef25e35cfc5337db4ceb8581bf5926b4fbe3 --- .../DisplayHardware/AidlComposerHal.cpp | 30 +++++++++++-------- .../DisplayHardware/AidlComposerHal.h | 2 ++ .../DisplayHardware/HidlComposerHal.cpp | 13 ++++++-- .../SurfaceFlingerProperties.cpp | 4 +++ .../surfaceflinger/SurfaceFlingerProperties.h | 2 ++ .../sysprop/SurfaceFlingerProperties.sysprop | 13 ++++++++ .../api/SurfaceFlingerProperties-current.txt | 4 +++ 7 files changed, 53 insertions(+), 15 deletions(-) diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index f7049b98e7..c0eb36dc02 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -20,6 +20,7 @@ #include "AidlComposerHal.h" +#include #include #include #include @@ -249,15 +250,18 @@ AidlComposer::AidlComposer(const std::string& serviceName) { ALOGE("getInterfaceVersion for AidlComposer constructor failed %s", status.getDescription().c_str()); } - if (version == 1) { - mClearSlotBuffer = sp::make(1, 1, PIXEL_FORMAT_RGBX_8888, - GraphicBuffer::USAGE_HW_COMPOSER | - GraphicBuffer::USAGE_SW_READ_OFTEN | - GraphicBuffer::USAGE_SW_WRITE_OFTEN, - "AidlComposer"); - if (!mClearSlotBuffer || mClearSlotBuffer->initCheck() != ::android::OK) { - LOG_ALWAYS_FATAL("Failed to allocate a buffer for clearing layer buffer slots"); - return; + mSupportsBufferSlotsToClear = version > 1; + if (!mSupportsBufferSlotsToClear) { + if (sysprop::clear_slots_with_set_layer_buffer(false)) { + mClearSlotBuffer = sp::make(1, 1, PIXEL_FORMAT_RGBX_8888, + GraphicBuffer::USAGE_HW_COMPOSER | + GraphicBuffer::USAGE_SW_READ_OFTEN | + GraphicBuffer::USAGE_SW_WRITE_OFTEN, + "AidlComposer"); + if (!mClearSlotBuffer || mClearSlotBuffer->initCheck() != ::android::OK) { + LOG_ALWAYS_FATAL("Failed to allocate a buffer for clearing layer buffer slots"); + return; + } } } @@ -844,12 +848,12 @@ Error AidlComposer::setLayerBufferSlotsToClear(Display display, Layer layer, Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { - // Backwards compatible way of clearing buffer is to set the layer buffer with a placeholder - // buffer, using the slot that needs to cleared... tricky. - if (mClearSlotBuffer == nullptr) { + if (mSupportsBufferSlotsToClear) { writer->get().setLayerBufferSlotsToClear(translate(display), translate(layer), slotsToClear); - } else { + // Backwards compatible way of clearing buffer slots is to set the layer buffer with a + // placeholder buffer, using the slot that needs to cleared... tricky. + } else if (mClearSlotBuffer != nullptr) { for (uint32_t slot : slotsToClear) { // Don't clear the active buffer slot because we need to restore the active buffer // after clearing the requested buffer slots with a placeholder buffer. diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index ded91be82c..8d21b491c3 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -285,6 +285,8 @@ private: // threading annotations. ftl::SharedMutex mMutex; + // Whether or not explicitly clearing buffer slots is supported. + bool mSupportsBufferSlotsToClear; // Buffer slots for layers are cleared by setting the slot buffer to this buffer. sp mClearSlotBuffer; diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index e0f6c45f70..9b41da5754 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -24,12 +24,14 @@ #include "HidlComposerHal.h" +#include #include #include #include #include #include #include + #include "HWC2.h" #include "Hal.h" @@ -189,6 +191,9 @@ std::vector translate(const hidl_vec& in) { } sp allocateClearSlotBuffer() { + if (!sysprop::clear_slots_with_set_layer_buffer(false)) { + return nullptr; + } sp buffer = sp::make(1, 1, PIXEL_FORMAT_RGBX_8888, GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_SW_READ_OFTEN | @@ -246,7 +251,7 @@ HidlComposer::HidlComposer(const std::string& serviceName) LOG_ALWAYS_FATAL("failed to create composer client"); } - if (!mClearSlotBuffer) { + if (!mClearSlotBuffer && sysprop::clear_slots_with_set_layer_buffer(false)) { LOG_ALWAYS_FATAL("Failed to allocate a buffer for clearing layer buffer slots"); return; } @@ -716,7 +721,11 @@ Error HidlComposer::setLayerBufferSlotsToClear(Display display, Layer layer, if (slotsToClear.empty()) { return Error::NONE; } - // Backwards compatible way of clearing buffer is to set the layer buffer with a placeholder + // This can be null when the HAL hasn't explicitly enabled this feature. + if (mClearSlotBuffer == nullptr) { + return Error::NONE; + } + // Backwards compatible way of clearing buffer is to set the layer buffer with a placeholder // buffer, using the slot that needs to cleared... tricky. for (uint32_t slot : slotsToClear) { // Don't clear the active buffer slot because we need to restore the active buffer after diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 20fa091730..96c8b54005 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -375,5 +375,9 @@ bool ignore_hdr_camera_layers(bool defaultValue) { return SurfaceFlingerProperties::ignore_hdr_camera_layers().value_or(defaultValue); } +bool clear_slots_with_set_layer_buffer(bool defaultValue) { + return SurfaceFlingerProperties::clear_slots_with_set_layer_buffer().value_or(defaultValue); +} + } // namespace sysprop } // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index 080feee686..951f8f8cb3 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -102,6 +102,8 @@ bool enable_sdr_dimming(bool defaultValue); bool ignore_hdr_camera_layers(bool defaultValue); +bool clear_slots_with_set_layer_buffer(bool defaultValue); + } // namespace sysprop } // namespace android #endif // SURFACEFLINGERPROPERTIES_H_ diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index 9b3d130563..5cac086c21 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -481,3 +481,16 @@ prop { access: Readonly prop_name: "ro.surface_flinger.min_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, +# Some HAL implementations may not support the additional setLayerBuffer commands used to clear +# the cache slots. +prop { + api_name: "clear_slots_with_set_layer_buffer" + type: Boolean + scope: Public + access: Readonly + prop_name: "ro.surface_flinger.clear_slots_with_set_layer_buffer" +} diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt index 41987fcffe..ba88acc2fb 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -1,5 +1,9 @@ props { module: "android.sysprop.SurfaceFlingerProperties" + prop { + api_name: "clear_slots_with_set_layer_buffer" + prop_name: "ro.surface_flinger.clear_slots_with_set_layer_buffer" + } prop { api_name: "color_space_agnostic_dataspace" type: Long -- GitLab From 3e9debc9b6054336d3a54272237aa3726ff53a9d Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 15 Jun 2023 00:35:29 +0000 Subject: [PATCH 0191/1187] libbinder: thread count startThreadPool spawn When startThreadPool is called, it spawns a thread which is not counted as part of the lazy kernel-started threads. This was discovered in fuzzers, and the test is updated. Bug: 286237215 Test: binderLibTest Change-Id: Ib0fa4484576f9d296b8f57f32ae536b17e5c6497 --- libs/binder/ProcessState.cpp | 34 ++++++++++++++++--- libs/binder/include/binder/IPCThreadState.h | 7 +++- libs/binder/include/binder/ProcessState.h | 23 +++++++++++-- .../include_platform/android/binder_process.h | 21 +++++++++--- libs/binder/rust/src/state.rs | 9 +++-- libs/binder/tests/binderLibTest.cpp | 28 +++++++++------ 6 files changed, 98 insertions(+), 24 deletions(-) diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 3fa686782a..02b0447304 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -192,6 +192,7 @@ void ProcessState::startThreadPool() AutoMutex _l(mLock); if (!mThreadPoolStarted) { if (mMaxThreads == 0) { + // see also getThreadPoolMaxTotalThreadCount ALOGW("Extra binder thread started, but 0 threads requested. Do not use " "*startThreadPool when zero threads are requested."); } @@ -407,6 +408,11 @@ void ProcessState::spawnPooledThread(bool isMain) mKernelStartedThreads++; pthread_mutex_unlock(&mThreadCountLock); } + // TODO: if startThreadPool is called on another thread after the process + // starts up, the kernel might think that it already requested those + // binder threads, and additional won't be started. This is likely to + // cause deadlocks, and it will also cause getThreadPoolMaxTotalThreadCount + // to return too high of a value. } status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) { @@ -426,12 +432,32 @@ size_t ProcessState::getThreadPoolMaxTotalThreadCount() const { pthread_mutex_lock(&mThreadCountLock); base::ScopeGuard detachGuard = [&]() { pthread_mutex_unlock(&mThreadCountLock); }; - // may actually be one more than this, if join is called if (mThreadPoolStarted) { - return mCurrentThreads < mKernelStartedThreads - ? mMaxThreads - : mMaxThreads + mCurrentThreads - mKernelStartedThreads; + LOG_ALWAYS_FATAL_IF(mKernelStartedThreads > mMaxThreads + 1, + "too many kernel-started threads: %zu > %zu + 1", mKernelStartedThreads, + mMaxThreads); + + // calling startThreadPool starts a thread + size_t threads = 1; + + // the kernel is configured to start up to mMaxThreads more threads + threads += mMaxThreads; + + // Users may call IPCThreadState::joinThreadPool directly. We don't + // currently have a way to count this directly (it could be added by + // adding a separate private joinKernelThread method in IPCThreadState). + // So, if we are in a race between the kernel thread variable being + // incremented in this file and mCurrentThreads being incremented + // in IPCThreadState, temporarily forget about the extra join threads. + // This is okay, because most callers of this method only care about + // having 0, 1, or more threads. + if (mCurrentThreads > mKernelStartedThreads) { + threads += mCurrentThreads - mKernelStartedThreads; + } + + return threads; } + // must not be initialized or maybe has poll thread setup, we // currently don't track this in libbinder LOG_ALWAYS_FATAL_IF(mKernelStartedThreads != 0, diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index d261c2143c..9347ce47a5 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -147,7 +147,12 @@ public: void flushCommands(); bool flushIfNeeded(); - // For main functions - dangerous for libraries to use + // Adds the current thread into the binder threadpool. + // + // This is in addition to any threads which are started + // with startThreadPool. Libraries should not call this + // function, as they may be loaded into processes which + // try to configure the threadpool differently. void joinThreadPool(bool isMain = true); // Stop the local process. diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index 81391e96e7..9dc370b412 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -52,7 +52,26 @@ public: sp getContextObject(const sp& caller); - // For main functions - dangerous for libraries to use + // This should be called before startThreadPool at the beginning + // of a program, and libraries should never call it because programs + // should configure their own threadpools. The threadpool size can + // never be decreased. + // + // The 'maxThreads' value refers to the total number of threads + // that will be started by the kernel. This is in addition to any + // threads started by 'startThreadPool' or 'joinRpcThreadpool'. + status_t setThreadPoolMaxThreadCount(size_t maxThreads); + + // Libraries should not call this, as processes should configure + // threadpools themselves. Should be called in the main function + // directly before any code executes or joins the threadpool. + // + // Starts one thread, PLUS those requested in setThreadPoolMaxThreadCount, + // PLUS those manually requested in joinThreadPool. + // + // For instance, if setThreadPoolMaxCount(3) is called and + // startThreadpPool (+1 thread) and joinThreadPool (+1 thread) + // are all called, then up to 5 threads can be started. void startThreadPool(); [[nodiscard]] bool becomeContextManager(); @@ -63,8 +82,6 @@ public: // TODO: deprecate. void spawnPooledThread(bool isMain); - // For main functions - dangerous for libraries to use - status_t setThreadPoolMaxThreadCount(size_t maxThreads); status_t enableOnewaySpamDetection(bool enable); // Set the name of the current thread to look like a threadpool diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h index 3fbe90d70a..68528e1004 100644 --- a/libs/binder/ndk/include_platform/android/binder_process.h +++ b/libs/binder/ndk/include_platform/android/binder_process.h @@ -24,7 +24,14 @@ __BEGIN_DECLS /** - * This creates a threadpool for incoming binder transactions if it has not already been created. + * This creates a threadpool for incoming binder transactions if it has not already been created, + * spawning one thread, and allowing the kernel to lazily start threads according to the count + * that is specified in ABinderProcess_setThreadPoolMaxThreadCount. + * + * For instance, if ABinderProcess_setThreadPoolMaxThreadCount(3) is called, + * ABinderProcess_startThreadPool() is called (+1 thread) then the main thread calls + * ABinderProcess_joinThreadPool() (+1 thread), up to *5* total threads will be started + * (2 directly, and 3 more if the kernel starts them lazily). * * When using this, it is expected that ABinderProcess_setupPolling and * ABinderProcess_handlePolledCommands are not used. @@ -36,7 +43,12 @@ void ABinderProcess_startThreadPool(void); /** * This sets the maximum number of threads that can be started in the threadpool. By default, after * startThreadPool is called, this is 15. If it is called additional times, it will only prevent - * the kernel from starting new threads and will not delete already existing threads. + * the kernel from starting new threads and will not delete already existing threads. This should + * be called once before startThreadPool. The number of threads can never decrease. + * + * This count refers to the number of threads that will be created lazily by the kernel, in + * addition to the threads created by ABinderProcess_startThreadPool or + * ABinderProcess_joinThreadPool. * * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main * function should be responsible for configuring the threadpool for the entire application. @@ -50,8 +62,9 @@ bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads); */ bool ABinderProcess_isThreadPoolStarted(void); /** - * This adds the current thread to the threadpool. This may cause the threadpool to exceed the - * maximum size. + * This adds the current thread to the threadpool. This thread will be in addition to the thread + * started by ABinderProcess_startThreadPool and the lazy kernel-started threads specified by + * ABinderProcess_setThreadPoolMaxThreadCount. * * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main * function should be responsible for configuring the threadpool for the entire application. diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs index cc18741a4e..b35511d74e 100644 --- a/libs/binder/rust/src/state.rs +++ b/libs/binder/rust/src/state.rs @@ -23,6 +23,9 @@ pub struct ProcessState; impl ProcessState { /// Start the Binder IPC thread pool + /// + /// Starts 1 thread, plus allows the kernel to lazily start up to 'num_threads' + /// additional threads as specified by set_thread_pool_max_thread_count. pub fn start_thread_pool() { unsafe { // Safety: Safe FFI @@ -33,8 +36,7 @@ impl ProcessState { /// Set the maximum number of threads that can be started in the threadpool. /// /// By default, after startThreadPool is called, this is 15. If it is called - /// additional times, it will only prevent the kernel from starting new - /// threads and will not delete already existing threads. + /// additional times, the thread pool size can only be increased. pub fn set_thread_pool_max_thread_count(num_threads: u32) { unsafe { // Safety: Safe FFI @@ -43,6 +45,9 @@ impl ProcessState { } /// Block on the Binder IPC thread pool + /// + /// This adds additional threads in addition to what is created by + /// set_thread_pool_max_thread_count and start_thread_pool. pub fn join_thread_pool() { unsafe { // Safety: Safe FFI diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index abc423b669..e021af0264 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -82,7 +82,7 @@ static char binderserverarg[] = "--binderserver"; static constexpr int kSchedPolicy = SCHED_RR; static constexpr int kSchedPriority = 7; static constexpr int kSchedPriorityMore = 8; -static constexpr int kKernelThreads = 15; +static constexpr int kKernelThreads = 17; // anything different than the default static String16 binderLibTestServiceName = String16("test.binderLib"); @@ -1357,17 +1357,20 @@ TEST_F(BinderLibTest, ThreadPoolAvailableThreads) { EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_MAX_THREAD_COUNT, data, &reply), StatusEq(NO_ERROR)); int32_t replyi = reply.readInt32(); - // Expect 16 threads: kKernelThreads = 15 + Pool thread == 16 - EXPECT_TRUE(replyi == kKernelThreads || replyi == kKernelThreads + 1); + // see getThreadPoolMaxTotalThreadCount for why there is a race + EXPECT_TRUE(replyi == kKernelThreads + 1 || replyi == kKernelThreads + 2) << replyi; + EXPECT_THAT(server->transact(BINDER_LIB_TEST_PROCESS_LOCK, data, &reply), NO_ERROR); /* - * This will use all threads in the pool expect the main pool thread. - * The service should run fine without locking, and the thread count should - * not exceed 16 (15 Max + pool thread). + * This will use all threads in the pool but one. There are actually kKernelThreads+2 + * available in the other process (startThreadPool, joinThreadPool, + the kernel- + * started threads from setThreadPoolMaxThreadCount + * + * Adding one more will cause it to deadlock. */ std::vector ts; - for (size_t i = 0; i < kKernelThreads; i++) { + for (size_t i = 0; i < kKernelThreads + 1; i++) { ts.push_back(std::thread([&] { Parcel local_reply; EXPECT_THAT(server->transact(BINDER_LIB_TEST_LOCK_UNLOCK, data, &local_reply), @@ -1375,8 +1378,13 @@ TEST_F(BinderLibTest, ThreadPoolAvailableThreads) { })); } - data.writeInt32(500); - // Give a chance for all threads to be used + // make sure all of the above calls will be queued in parallel. Otherwise, most of + // the time, the below call will pre-empt them (presumably because we have the + // scheduler timeslice already + scheduler hint). + sleep(1); + + data.writeInt32(1000); + // Give a chance for all threads to be used (kKernelThreads + 1 thread in use) EXPECT_THAT(server->transact(BINDER_LIB_TEST_UNLOCK_AFTER_MS, data, &reply), NO_ERROR); for (auto &t : ts) { @@ -1386,7 +1394,7 @@ TEST_F(BinderLibTest, ThreadPoolAvailableThreads) { EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_MAX_THREAD_COUNT, data, &reply), StatusEq(NO_ERROR)); replyi = reply.readInt32(); - EXPECT_EQ(replyi, kKernelThreads + 1); + EXPECT_EQ(replyi, kKernelThreads + 2); } TEST_F(BinderLibTest, ThreadPoolStarted) { -- GitLab From 4cba2b8a6f3b6a6ed767138c2d1ad07f1c33d57e Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 14 Jun 2023 20:00:12 +0000 Subject: [PATCH 0192/1187] Revert "example_service_fuzzer: explicit deps" This reverts commit 34aac2be4a653e86f29743b6caa9bf6347a191e8. Reason for revert: should no longer be needed b/280164233#comment18 Fixes: 280164233 Change-Id: I6ae6ef357387b6706fcc455cd9a4d8d01b09f29c --- .../parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp index f37cfca8a1..5cb406afc2 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp +++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp @@ -19,11 +19,6 @@ rust_fuzz { srcs: [ "service_fuzzer.rs", ], - shared_libs: [ - "libbinder", - "libbinder_ndk", - "libutils", - ], rustlibs: [ "libbinder_rs", "libbinder_random_parcel_rs", -- GitLab From a2f835d34d65eaab159a338735035812a92209af Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 15 Jun 2023 16:50:05 +0000 Subject: [PATCH 0193/1187] binderUnitTest: Parcel::appendFrom Coverage from this exists elsewhere and in Java, but it's helpful to have these tests easily accessible when working on C++ code here. Bug: 287093457 Test: binderUnitTest Change-Id: If393c90f972cacff36e1a04614635c1597d419f4 --- libs/binder/tests/binderParcelUnitTest.cpp | 161 +++++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/libs/binder/tests/binderParcelUnitTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp index 359c783de5..0a0dae0f59 100644 --- a/libs/binder/tests/binderParcelUnitTest.cpp +++ b/libs/binder/tests/binderParcelUnitTest.cpp @@ -29,6 +29,7 @@ using android::sp; using android::status_t; using android::String16; using android::String8; +using android::base::unique_fd; using android::binder::Status; TEST(Parcel, NonNullTerminatedString8) { @@ -112,6 +113,166 @@ TEST(Parcel, DebugReadAllFds) { EXPECT_EQ(ret[1], STDIN_FILENO); } +TEST(Parcel, AppendFromEmpty) { + Parcel p1; + Parcel p2; + p2.writeInt32(2); + + ASSERT_EQ(OK, p1.appendFrom(&p2, 0, p2.dataSize())); + + p1.setDataPosition(0); + ASSERT_EQ(2, p1.readInt32()); + + p2.setDataPosition(0); + ASSERT_EQ(2, p2.readInt32()); +} + +TEST(Parcel, AppendPlainData) { + Parcel p1; + p1.writeInt32(1); + Parcel p2; + p2.writeInt32(2); + + ASSERT_EQ(OK, p1.appendFrom(&p2, 0, p2.dataSize())); + + p1.setDataPosition(0); + ASSERT_EQ(1, p1.readInt32()); + ASSERT_EQ(2, p1.readInt32()); + + p2.setDataPosition(0); + ASSERT_EQ(2, p2.readInt32()); +} + +TEST(Parcel, AppendPlainDataPartial) { + Parcel p1; + p1.writeInt32(1); + Parcel p2; + p2.writeInt32(2); + p2.writeInt32(3); + p2.writeInt32(4); + + // only copy 8 bytes (two int32's worth) + ASSERT_EQ(OK, p1.appendFrom(&p2, 0, 8)); + + p1.setDataPosition(0); + ASSERT_EQ(1, p1.readInt32()); + ASSERT_EQ(2, p1.readInt32()); + ASSERT_EQ(3, p1.readInt32()); + ASSERT_EQ(0, p1.readInt32()); // not 4, end of Parcel + + p2.setDataPosition(0); + ASSERT_EQ(2, p2.readInt32()); +} + +TEST(Parcel, AppendWithBinder) { + sp b1 = sp::make(); + sp b2 = sp::make(); + + Parcel p1; + p1.writeInt32(1); + p1.writeStrongBinder(b1); + Parcel p2; + p2.writeInt32(2); + p2.writeStrongBinder(b2); + + ASSERT_EQ(OK, p1.appendFrom(&p2, 0, p2.dataSize())); + + p1.setDataPosition(0); + ASSERT_EQ(1, p1.readInt32()); + ASSERT_EQ(b1, p1.readStrongBinder()); + ASSERT_EQ(2, p1.readInt32()); + ASSERT_EQ(b2, p1.readStrongBinder()); + ASSERT_EQ(2, p1.objectsCount()); + + p2.setDataPosition(0); + ASSERT_EQ(2, p2.readInt32()); + ASSERT_EQ(b2, p2.readStrongBinder()); +} + +TEST(Parcel, AppendWithBinderPartial) { + sp b1 = sp::make(); + sp b2 = sp::make(); + + Parcel p1; + p1.writeInt32(1); + p1.writeStrongBinder(b1); + Parcel p2; + p2.writeInt32(2); + p2.writeStrongBinder(b2); + + ASSERT_EQ(OK, p1.appendFrom(&p2, 0, 8)); // BAD: 4 bytes into strong binder + + p1.setDataPosition(0); + ASSERT_EQ(1, p1.readInt32()); + ASSERT_EQ(b1, p1.readStrongBinder()); + ASSERT_EQ(2, p1.readInt32()); + ASSERT_EQ(1935813253, p1.readInt32()); // whatever garbage that is there (ABI) + ASSERT_EQ(1, p1.objectsCount()); + + p2.setDataPosition(0); + ASSERT_EQ(2, p2.readInt32()); + ASSERT_EQ(b2, p2.readStrongBinder()); +} + +TEST(Parcel, AppendWithFd) { + unique_fd fd1 = unique_fd(dup(0)); + unique_fd fd2 = unique_fd(dup(0)); + + Parcel p1; + p1.writeInt32(1); + p1.writeDupFileDescriptor(0); // with ownership + p1.writeFileDescriptor(fd1.get()); // without ownership + Parcel p2; + p2.writeInt32(2); + p2.writeDupFileDescriptor(0); // with ownership + p2.writeFileDescriptor(fd2.get()); // without ownership + + ASSERT_EQ(OK, p1.appendFrom(&p2, 0, p2.dataSize())); + + p1.setDataPosition(0); + ASSERT_EQ(1, p1.readInt32()); + ASSERT_NE(-1, p1.readFileDescriptor()); + ASSERT_NE(-1, p1.readFileDescriptor()); + ASSERT_EQ(2, p1.readInt32()); + ASSERT_NE(-1, p1.readFileDescriptor()); + ASSERT_NE(-1, p1.readFileDescriptor()); + ASSERT_EQ(4, p1.objectsCount()); + + p2.setDataPosition(0); + ASSERT_EQ(2, p2.readInt32()); + ASSERT_NE(-1, p1.readFileDescriptor()); + ASSERT_NE(-1, p1.readFileDescriptor()); +} + +TEST(Parcel, AppendWithFdPartial) { + unique_fd fd1 = unique_fd(dup(0)); + unique_fd fd2 = unique_fd(dup(0)); + + Parcel p1; + p1.writeInt32(1); + p1.writeDupFileDescriptor(0); // with ownership + p1.writeFileDescriptor(fd1.get()); // without ownership + Parcel p2; + p2.writeInt32(2); + p2.writeDupFileDescriptor(0); // with ownership + p2.writeFileDescriptor(fd2.get()); // without ownership + + ASSERT_EQ(OK, p1.appendFrom(&p2, 0, 8)); // BAD: 4 bytes into binder + + p1.setDataPosition(0); + ASSERT_EQ(1, p1.readInt32()); + ASSERT_NE(-1, p1.readFileDescriptor()); + ASSERT_NE(-1, p1.readFileDescriptor()); + ASSERT_EQ(2, p1.readInt32()); + ASSERT_EQ(1717840517, p1.readInt32()); // whatever garbage that is there (ABI) + ASSERT_EQ(2, p1.objectsCount()); + + p2.setDataPosition(0); + ASSERT_EQ(2, p2.readInt32()); + ASSERT_NE(-1, p1.readFileDescriptor()); + ASSERT_NE(-1, p1.readFileDescriptor()); +} + // Tests a second operation results in a parcel at the same location as it // started. void parcelOpSameLength(const std::function& a, const std::function& b) { -- GitLab From 8a478784162233c3ead9c4d70332506664c96367 Mon Sep 17 00:00:00 2001 From: viktor Date: Sat, 17 Jun 2023 09:06:40 +0800 Subject: [PATCH 0194/1187] Fix the description of InputDispatcherPolicyInterface The description of InputDispatcherPolicyInterface should be "dispatcher" instead of "reader" Test: make libinputdispatcher Change-Id: I768174ec97f14c6e9be2ae5571c4ba7144fc56d8 Signed-off-by: viktor --- .../dispatcher/include/InputDispatcherPolicyInterface.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h index 575b3d7059..fff1b03339 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h @@ -26,11 +26,10 @@ namespace android { - /* * Input dispatcher policy interface. * - * The input reader policy is used by the input reader to interact with the Window Manager + * The input dispatcher policy is used by the input dispatcher to interact with the Window Manager * and other system components. * * The actual implementation is partially supported by callbacks into the DVM -- GitLab From 8ea2c3df097602ef0405afd5ea747cc535716c51 Mon Sep 17 00:00:00 2001 From: Nergi Rahardi Date: Mon, 19 Jun 2023 16:51:47 +0900 Subject: [PATCH 0195/1187] Arrange include ordering in input/KeyLayoutMap.h utils/ lib has a dependency to #define constant (CONSTEXPR), which (may) gets #undef from other libs. There are many ways to fix this issue, but the most suitable one is to arrange the #include ordering, which also follows principle of "including the least-commonly used headers first". Bug: 287575652 Test: m Change-Id: I0f6841a083c37bc9245602fcc29a007f5ddc6894 --- include/input/KeyLayoutMap.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h index 8c3c74af20..b126abecea 100644 --- a/include/input/KeyLayoutMap.h +++ b/include/input/KeyLayoutMap.h @@ -17,13 +17,13 @@ #pragma once #include +#include + #include #include #include #include -#include - namespace android { struct AxisInfo { -- GitLab From 1ee05b62b77737785c9cbcf84bb4e0cb728d9630 Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Mon, 19 Jun 2023 13:49:06 +0000 Subject: [PATCH 0196/1187] TouchInputMapper: add missing newline in dump() Bug: 245989146 Test: presubmit Change-Id: I718be899ec44859db9eb54f8eeb4370514afe878 --- services/inputflinger/reader/mapper/TouchInputMapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 39a914d822..4366b3a45b 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -271,7 +271,7 @@ void TouchInputMapper::dump(std::string& dump) { toString(mFusedStylusPointerId).c_str()); dump += StringPrintf(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n", mExternalStylusFusionTimeout); - dump += StringPrintf(INDENT4 " External Stylus Buttons Applied: 0x%08x", + dump += StringPrintf(INDENT4 "External Stylus Buttons Applied: 0x%08x\n", mExternalStylusButtonsApplied); dump += INDENT3 "External Stylus State:\n"; dumpStylusState(dump, mExternalStylusState); -- GitLab From e3aaf3934b2be0bcc49fdfaed96bc1d9f70896fe Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Mon, 19 Jun 2023 17:13:43 +0000 Subject: [PATCH 0197/1187] TouchInputMapper: clarify the different touchpad modes The previous documentation comments were misleading, since UNSCALED is only actually used for touchpads that have been captured by an app. Bug: 280396539 Test: none Change-Id: I4658784a57a6f1349bd090a002f34a8718af24e0 --- services/inputflinger/reader/mapper/TouchInputMapper.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index d8b59ca39b..c5dfb00adb 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -195,9 +195,9 @@ protected: enum class DeviceMode { DISABLED, // input is disabled DIRECT, // direct mapping (touchscreen) - UNSCALED, // unscaled mapping (touchpad) + UNSCALED, // unscaled mapping (e.g. captured touchpad) NAVIGATION, // unscaled mapping with assist gesture (touch navigation) - POINTER, // pointer mapping (pointer) + POINTER, // pointer mapping (e.g. uncaptured touchpad, drawing tablet) ftl_last = POINTER }; -- GitLab From bad7588c909f6ebc5d88ee5cf3453fd336d2078d Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 16 Jun 2023 20:59:06 +0000 Subject: [PATCH 0198/1187] servicemanager: log isolated app violation Bug: 286851628 Test: servicemanager_test Change-Id: I3e95ce54418f36918b35909b986be3a23a55ac57 --- cmds/servicemanager/ServiceManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index e30cbd5a46..44ccf50ca1 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -291,6 +291,8 @@ sp ServiceManager::tryGetService(const std::string& name, bool startIfN service = &(it->second); if (!service->allowIsolated && is_multiuser_uid_isolated(ctx.uid)) { + LOG(WARNING) << "Isolated app with UID " << ctx.uid << " requested '" << name + << "', but the service is not allowed for isolated apps."; return nullptr; } out = service->binder; -- GitLab From efea66bc80fc52c5764dd99dfd73884339f9891c Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Sat, 17 Jun 2023 01:59:34 +0000 Subject: [PATCH 0199/1187] servicemanager: guaranteeClient on wait register When clients exit quickly, a client callback may not be registered yet. We should still keep guaranteeClient set, so that they will get the notification. Fixes: 285202885 Test: boot Test: aidl_lazy_test Test: libbinder_ndk_unit_test Change-Id: If50112a3b6c191afdadf7441638cc117fa1620ea --- cmds/servicemanager/ServiceManager.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 98a70ed973..cae9684cc4 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -404,14 +404,13 @@ Status ServiceManager::addService(const std::string& name, const sp& bi .allowIsolated = allowIsolated, .dumpPriority = dumpPriority, .hasClients = prevClients, // see b/279898063, matters if existing callbacks - .guaranteeClient = false, // handled below + .guaranteeClient = false, .ctx = ctx, }; if (auto it = mNameToRegistrationCallback.find(name); it != mNameToRegistrationCallback.end()) { - // TODO: this is only needed once - // See also getService - handles case where client never gets the service, - // we want the service to quit. + // If someone is currently waiting on the service, notify the service that + // we're waiting and flush it to the service. mNameToService[name].guaranteeClient = true; CHECK(handleServiceClientCallback(2 /* sm + transaction */, name, false)); mNameToService[name].guaranteeClient = true; @@ -714,6 +713,11 @@ Status ServiceManager::registerClientCallback(const std::string& name, const sp< mNameToClientCallback[name].push_back(cb); + // Flush updated info to client callbacks (especially if guaranteeClient + // and !hasClient, see b/285202885). We may or may not have clients at + // this point, so ignore the return value. + (void)handleServiceClientCallback(2 /* sm + transaction */, name, false); + return Status::ok(); } -- GitLab From 9e2d296038cc84e507ac5adca95e42388f1350cf Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Tue, 20 Jun 2023 23:43:24 +0000 Subject: [PATCH 0200/1187] Revert "Remove leak detection options" This reverts commit 6b70c61c722abb8eb27e5639f2c5082ceb34a046. Reason for revert: This options were not the issue for not receiving bugs from infra. Change-Id: I6bb9572d9bd76bdcd260ac0a30fbac17f0cd681c --- libs/binder/tests/Android.bp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 24fd2a6048..41856f9b79 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -804,5 +804,12 @@ cc_defaults { cc_defaults { name: "fuzzer_disable_leaks", - //TODO(b/286112918) : Readd leak detection options + fuzz_config: { + asan_options: [ + "detect_leaks=0", + ], + hwasan_options: [ + "detect_leaks=0", + ], + }, } -- GitLab From 19486a2ce17e7517a14a882649b286c23486cf08 Mon Sep 17 00:00:00 2001 From: Matt Delmage Date: Tue, 6 Jun 2023 21:48:40 +0000 Subject: [PATCH 0201/1187] Revert "Cancel dumpstate if client disconnects" This reverts commit 3d509846cfa9430575f9eb4dfb46957b04788638. Bug: 268200878 Test: Attempting BR during an existing BR will result in an error message and not abort the original Bug Report. Ignore-AOSP-First: This patch reverts a change which is not in AOSP at all Signed-off-by: Matt Delmage (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:7ed14b44b7f540c98a2b1e61d5b953e7bf36fd96) Merged-In: Idbb149b9e3f55bcb2426f1192b5239947055b4c9 Change-Id: Idbb149b9e3f55bcb2426f1192b5239947055b4c9 --- cmds/bugreportz/main.cpp | 17 ----------------- cmds/dumpstate/dumpstate.cpp | 6 +----- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/cmds/bugreportz/main.cpp b/cmds/bugreportz/main.cpp index 790556ce5a..cd2652c717 100644 --- a/cmds/bugreportz/main.cpp +++ b/cmds/bugreportz/main.cpp @@ -75,23 +75,6 @@ int main(int argc, char* argv[]) { return EXIT_FAILURE; } - // Wait a little while for dumpstatez to stop if it is running - bool dumpstate_running = false; - for (int i = 0; i < 20; i++) { - char buf[PROPERTY_VALUE_MAX]; - property_get("init.svc.dumpstatez", buf, ""); - dumpstate_running = strcmp(buf, "running") == 0; - - if (!dumpstate_running) break; - - sleep(1); - } - - if (dumpstate_running) { - fprintf(stderr, "FAIL:dumpstatez service is already running\n"); - return EXIT_FAILURE; - } - // TODO: code below was copy-and-pasted from bugreport.cpp (except by the // timeout value); // should be reused instead. diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index ed1885b5fa..8a337569c4 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -2602,11 +2602,7 @@ static void ShowUsage() { } static void register_sig_handler() { - signal(SIGPIPE, [](int) { - MYLOGE("Connection with client lost, canceling."); - ds.Cancel(); - abort(); - }); + signal(SIGPIPE, SIG_IGN); } bool Dumpstate::FinishZipFile() { -- GitLab From 64b5bc46af590fb1fb7131aad94d4afa901d8c38 Mon Sep 17 00:00:00 2001 From: Yiming Jing Date: Tue, 13 Jun 2023 11:44:47 -0700 Subject: [PATCH 0202/1187] Implement the clone trait for ParcelableHolder For the parity with the C++/NDK implementation, make the Rust ParcelableHolder cloneable. Bug: 210093811 Fix: 285042738 Test: m Test: declare a cloneable Parcelable with a ParcelableHolder and then check if build succeeds Change-Id: Iac161ec01007045cf1bee0632e56494e76f9c04a --- libs/binder/rust/src/parcel/parcelable_holder.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs index 383cc83509..eb82fb7fd6 100644 --- a/libs/binder/rust/src/parcel/parcelable_holder.rs +++ b/libs/binder/rust/src/parcel/parcelable_holder.rs @@ -161,6 +161,15 @@ impl ParcelableHolder { } } +impl Clone for ParcelableHolder { + fn clone(&self) -> ParcelableHolder { + ParcelableHolder { + data: Mutex::new(self.data.lock().unwrap().clone()), + stability: self.stability, + } + } +} + impl Serialize for ParcelableHolder { fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> { parcel.write(&NON_NULL_PARCELABLE_FLAG)?; -- GitLab From aeebeb4eca5967d2a893ac09464499301936a134 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 13 Jun 2023 19:53:03 +0000 Subject: [PATCH 0203/1187] Use a strongly typed Pid in WindowInfo Bug: 286428012 Test: presubmit Change-Id: I6a3572ff10b259feae74863c0203bb5f085f233f --- libs/gui/WindowInfo.cpp | 8 +- .../libgui_surfaceComposerClient_fuzzer.cpp | 2 +- libs/gui/include/gui/{Uid.h => PidUid.h} | 15 +++ libs/gui/include/gui/WindowInfo.h | 4 +- libs/gui/tests/WindowInfo_test.cpp | 2 +- .../benchmarks/InputDispatcher_benchmarks.cpp | 6 +- .../dispatcher/InputDispatcher.cpp | 34 +++---- .../inputflinger/dispatcher/InputDispatcher.h | 14 +-- services/inputflinger/dispatcher/Monitor.cpp | 2 +- services/inputflinger/dispatcher/Monitor.h | 5 +- .../include/InputDispatcherInterface.h | 4 +- .../include/InputDispatcherPolicyInterface.h | 4 +- .../tests/InputDispatcher_test.cpp | 95 ++++++++++--------- .../surfaceflinger/FrontEnd/LayerSnapshot.cpp | 2 +- .../FrontEnd/LayerSnapshotBuilder.cpp | 2 +- services/surfaceflinger/Layer.cpp | 2 +- 16 files changed, 110 insertions(+), 91 deletions(-) rename libs/gui/include/gui/{Uid.h => PidUid.h} (75%) diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index cd9b424e13..52af9d5114 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -92,6 +92,7 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { // Ensure that the size of custom types are what we expect for writing into the parcel. static_assert(sizeof(inputConfig) == 4u); + static_assert(sizeof(ownerPid.val()) == 4u); static_assert(sizeof(ownerUid.val()) == 4u); // clang-format off @@ -116,7 +117,7 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeFloat(transform.dsdy()) ?: parcel->writeFloat(transform.ty()) ?: parcel->writeInt32(static_cast(touchOcclusionMode)) ?: - parcel->writeInt32(ownerPid) ?: + parcel->writeInt32(ownerPid.val()) ?: parcel->writeInt32(ownerUid.val()) ?: parcel->writeUtf8AsUtf16(packageName) ?: parcel->writeInt32(inputConfig.get()) ?: @@ -148,7 +149,7 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { } float dsdx, dtdx, tx, dtdy, dsdy, ty; - int32_t lpFlags, lpType, touchOcclusionModeInt, inputConfigInt, ownerUidInt; + int32_t lpFlags, lpType, touchOcclusionModeInt, inputConfigInt, ownerPidInt, ownerUidInt; sp touchableRegionCropHandleSp; // clang-format off @@ -168,7 +169,7 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->readFloat(&dsdy) ?: parcel->readFloat(&ty) ?: parcel->readInt32(&touchOcclusionModeInt) ?: - parcel->readInt32(&ownerPid) ?: + parcel->readInt32(&ownerPidInt) ?: parcel->readInt32(&ownerUidInt) ?: parcel->readUtf8FromUtf16(&packageName) ?: parcel->readInt32(&inputConfigInt) ?: @@ -191,6 +192,7 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1}); touchOcclusionMode = static_cast(touchOcclusionModeInt); inputConfig = ftl::Flags(inputConfigInt); + ownerPid = Pid{ownerPidInt}; ownerUid = Uid{static_cast(ownerUidInt)}; touchableRegionCropHandle = touchableRegionCropHandleSp; diff --git a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp index 8482de3002..3e37e4850e 100644 --- a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp +++ b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp @@ -189,7 +189,7 @@ void SurfaceComposerClientFuzzer::getWindowInfo(gui::WindowInfo* windowInfo) { windowInfo->touchableRegion = Region(getRect(&mFdp)); windowInfo->replaceTouchableRegionWithCrop = mFdp.ConsumeBool(); windowInfo->touchOcclusionMode = mFdp.PickValueInArray(kMode); - windowInfo->ownerPid = mFdp.ConsumeIntegral(); + windowInfo->ownerPid = gui::Pid{mFdp.ConsumeIntegral()}; windowInfo->ownerUid = gui::Uid{mFdp.ConsumeIntegral()}; windowInfo->packageName = mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes); windowInfo->inputConfig = mFdp.PickValueInArray(kFeatures); diff --git a/libs/gui/include/gui/Uid.h b/libs/gui/include/gui/PidUid.h similarity index 75% rename from libs/gui/include/gui/Uid.h rename to libs/gui/include/gui/PidUid.h index 8e45ef53da..7930942882 100644 --- a/libs/gui/include/gui/Uid.h +++ b/libs/gui/include/gui/PidUid.h @@ -22,6 +22,21 @@ namespace android::gui { +// Type-safe wrapper for a PID. +struct Pid : ftl::Constructible, ftl::Equatable, ftl::Orderable { + using Constructible::Constructible; + + const static Pid INVALID; + + constexpr auto val() const { return ftl::to_underlying(*this); } + + constexpr bool isValid() const { return val() >= 0; } + + std::string toString() const { return std::to_string(val()); } +}; + +const inline Pid Pid::INVALID{-1}; + // Type-safe wrapper for a UID. // We treat the unsigned equivalent of -1 as a singular invalid value. struct Uid : ftl::Constructible, ftl::Equatable, ftl::Orderable { diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 666101eace..7ff73874ae 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -225,7 +225,7 @@ struct WindowInfo : public Parcelable { Region touchableRegion; TouchOcclusionMode touchOcclusionMode = TouchOcclusionMode::BLOCK_UNTRUSTED; - int32_t ownerPid = -1; + Pid ownerPid = Pid::INVALID; Uid ownerUid = Uid::INVALID; std::string packageName; ftl::Flags inputConfig; diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index e3a629e1cb..461fe4a4ce 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -61,7 +61,7 @@ TEST(WindowInfo, Parcelling) { i.alpha = 0.7; i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1}); i.touchOcclusionMode = TouchOcclusionMode::ALLOW; - i.ownerPid = 19; + i.ownerPid = gui::Pid{19}; i.ownerUid = gui::Uid{24}; i.packageName = "com.example.package"; i.inputConfig = WindowInfo::InputConfig::NOT_FOCUSABLE; diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index 1d6317d6c0..7a410831f6 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -36,7 +36,7 @@ namespace { constexpr int32_t DEVICE_ID = 1; // The default pid and uid for windows created by the test. -constexpr int32_t WINDOW_PID = 999; +constexpr gui::Pid WINDOW_PID{999}; constexpr gui::Uid WINDOW_UID{1001}; static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s; @@ -61,13 +61,13 @@ private: ALOGE("There is no focused window for %s", applicationHandle->getName().c_str()); } - void notifyWindowUnresponsive(const sp& connectionToken, std::optional pid, + void notifyWindowUnresponsive(const sp& connectionToken, std::optional pid, const std::string& reason) override { ALOGE("Window is not responding: %s", reason.c_str()); } void notifyWindowResponsive(const sp& connectionToken, - std::optional pid) override {} + std::optional pid) override {} void notifyInputChannelBroken(const sp&) override {} diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index b42ca31455..add9db7033 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -561,7 +561,7 @@ bool canReceiveForegroundTouches(const WindowInfo& info) { return !info.inputConfig.test(gui::WindowInfo::InputConfig::NOT_TOUCHABLE) && !info.isSpy(); } -bool isWindowOwnedBy(const sp& windowHandle, int32_t pid, gui::Uid uid) { +bool isWindowOwnedBy(const sp& windowHandle, gui::Pid pid, gui::Uid uid) { if (windowHandle == nullptr) { return false; } @@ -5355,16 +5355,16 @@ void InputDispatcher::setInputFilterEnabled(bool enabled) { mLooper->wake(); } -bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, gui::Uid uid, +bool InputDispatcher::setInTouchMode(bool inTouchMode, gui::Pid pid, gui::Uid uid, bool hasPermission, int32_t displayId) { bool needWake = false; { std::scoped_lock lock(mLock); ALOGD_IF(DEBUG_TOUCH_MODE, - "Request to change touch mode to %s (calling pid=%d, uid=%s, " + "Request to change touch mode to %s (calling pid=%s, uid=%s, " "hasPermission=%s, target displayId=%d, mTouchModePerDisplay[displayId]=%s)", - toString(inTouchMode), pid, uid.toString().c_str(), toString(hasPermission), - displayId, + toString(inTouchMode), pid.toString().c_str(), uid.toString().c_str(), + toString(hasPermission), displayId, mTouchModePerDisplay.count(displayId) == 0 ? "not set" : std::to_string(mTouchModePerDisplay[displayId]).c_str()); @@ -5376,9 +5376,9 @@ bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, gui::Uid uid if (!hasPermission) { if (!focusedWindowIsOwnedByLocked(pid, uid) && !recentWindowsAreOwnedByLocked(pid, uid)) { - ALOGD("Touch mode switch rejected, caller (pid=%d, uid=%s) doesn't own the focused " + ALOGD("Touch mode switch rejected, caller (pid=%s, uid=%s) doesn't own the focused " "window nor none of the previously interacted window", - pid, uid.toString().c_str()); + pid.toString().c_str(), uid.toString().c_str()); return false; } } @@ -5394,7 +5394,7 @@ bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, gui::Uid uid return true; } -bool InputDispatcher::focusedWindowIsOwnedByLocked(int32_t pid, gui::Uid uid) { +bool InputDispatcher::focusedWindowIsOwnedByLocked(gui::Pid pid, gui::Uid uid) { const sp focusedToken = mFocusResolver.getFocusedWindowToken(mFocusedDisplayId); if (focusedToken == nullptr) { return false; @@ -5403,7 +5403,7 @@ bool InputDispatcher::focusedWindowIsOwnedByLocked(int32_t pid, gui::Uid uid) { return isWindowOwnedBy(windowHandle, pid, uid); } -bool InputDispatcher::recentWindowsAreOwnedByLocked(int32_t pid, gui::Uid uid) { +bool InputDispatcher::recentWindowsAreOwnedByLocked(gui::Pid pid, gui::Uid uid) { return std::find_if(mInteractionConnectionTokens.begin(), mInteractionConnectionTokens.end(), [&](const sp& connectionToken) REQUIRES(mLock) { const sp windowHandle = @@ -5688,10 +5688,10 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) const { windowInfo->applicationInfo.name.c_str(), binderToString(windowInfo->applicationInfo.token).c_str()); dump += dumpRegion(windowInfo->touchableRegion); - dump += StringPrintf(", ownerPid=%d, ownerUid=%s, dispatchingTimeout=%" PRId64 + dump += StringPrintf(", ownerPid=%s, ownerUid=%s, dispatchingTimeout=%" PRId64 "ms, hasToken=%s, " "touchOcclusionMode=%s\n", - windowInfo->ownerPid, + windowInfo->ownerPid.toString().c_str(), windowInfo->ownerUid.toString().c_str(), millis(windowInfo->dispatchingTimeout), binderToString(windowInfo->token).c_str(), @@ -5884,7 +5884,7 @@ Result> InputDispatcher::createInputChannel(const Result> InputDispatcher::createInputMonitor(int32_t displayId, const std::string& name, - int32_t pid) { + gui::Pid pid) { std::shared_ptr serverChannel; std::unique_ptr clientChannel; status_t result = openInputChannelPair(name, serverChannel, clientChannel); @@ -6076,7 +6076,7 @@ void InputDispatcher::setDisplayEligibilityForPointerCapture(int32_t displayId, } // release lock } -std::optional InputDispatcher::findMonitorPidByTokenLocked(const sp& token) { +std::optional InputDispatcher::findMonitorPidByTokenLocked(const sp& token) { for (const auto& [_, monitors] : mGlobalMonitorsByDisplay) { for (const Monitor& monitor : monitors) { if (monitor.inputChannel->getConnectionToken() == token) { @@ -6296,7 +6296,7 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingCommand(const sp& } void InputDispatcher::sendWindowUnresponsiveCommandLocked(const sp& token, - std::optional pid, + std::optional pid, std::string reason) { auto command = [this, token, pid, r = std::move(reason)]() REQUIRES(mLock) { scoped_unlock unlock(mLock); @@ -6306,7 +6306,7 @@ void InputDispatcher::sendWindowUnresponsiveCommandLocked(const sp& tok } void InputDispatcher::sendWindowResponsiveCommandLocked(const sp& token, - std::optional pid) { + std::optional pid) { auto command = [this, token, pid]() REQUIRES(mLock) { scoped_unlock unlock(mLock); mPolicy.notifyWindowResponsive(token, pid); @@ -6322,7 +6322,7 @@ void InputDispatcher::sendWindowResponsiveCommandLocked(const sp& token void InputDispatcher::processConnectionUnresponsiveLocked(const Connection& connection, std::string reason) { const sp& connectionToken = connection.inputChannel->getConnectionToken(); - std::optional pid; + std::optional pid; if (connection.monitor) { ALOGW("Monitor %s is unresponsive: %s", connection.inputChannel->getName().c_str(), reason.c_str()); @@ -6344,7 +6344,7 @@ void InputDispatcher::processConnectionUnresponsiveLocked(const Connection& conn */ void InputDispatcher::processConnectionResponsiveLocked(const Connection& connection) { const sp& connectionToken = connection.inputChannel->getConnectionToken(); - std::optional pid; + std::optional pid; if (connection.monitor) { pid = findMonitorPidByTokenLocked(connectionToken); } else { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 21733dca82..130fd82958 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -119,7 +119,7 @@ public: void setFocusedDisplay(int32_t displayId) override; void setInputDispatchMode(bool enabled, bool frozen) override; void setInputFilterEnabled(bool enabled) override; - bool setInTouchMode(bool inTouchMode, int32_t pid, gui::Uid uid, bool hasPermission, + bool setInTouchMode(bool inTouchMode, gui::Pid pid, gui::Uid uid, bool hasPermission, int32_t displayId) override; void setMaximumObscuringOpacityForTouch(float opacity) override; @@ -132,7 +132,7 @@ public: void setFocusedWindow(const android::gui::FocusRequest&) override; base::Result> createInputMonitor(int32_t displayId, const std::string& name, - int32_t pid) override; + gui::Pid pid) override; status_t removeInputChannel(const sp& connectionToken) override; status_t pilferPointers(const sp& token) override; void requestPointerCapture(const sp& windowToken, bool enabled) override; @@ -271,7 +271,7 @@ private: mConnectionsByToken GUARDED_BY(mLock); // Find a monitor pid by the provided token. - std::optional findMonitorPidByTokenLocked(const sp& token) REQUIRES(mLock); + std::optional findMonitorPidByTokenLocked(const sp& token) REQUIRES(mLock); // Input channels that will receive a copy of all input events sent to the provided display. std::unordered_map> mGlobalMonitorsByDisplay GUARDED_BY(mLock); @@ -522,10 +522,10 @@ private: void processConnectionResponsiveLocked(const Connection& connection) REQUIRES(mLock); void sendWindowUnresponsiveCommandLocked(const sp& connectionToken, - std::optional pid, std::string reason) + std::optional pid, std::string reason) REQUIRES(mLock); void sendWindowResponsiveCommandLocked(const sp& connectionToken, - std::optional pid) REQUIRES(mLock); + std::optional pid) REQUIRES(mLock); // Optimization: AnrTracker is used to quickly find which connection is due for a timeout next. // AnrTracker must be kept in-sync with all responsive connection.waitQueues. @@ -703,8 +703,8 @@ private: void traceWaitQueueLength(const Connection& connection); // Check window ownership - bool focusedWindowIsOwnedByLocked(int32_t pid, gui::Uid uid) REQUIRES(mLock); - bool recentWindowsAreOwnedByLocked(int32_t pid, gui::Uid uid) REQUIRES(mLock); + bool focusedWindowIsOwnedByLocked(gui::Pid pid, gui::Uid uid) REQUIRES(mLock); + bool recentWindowsAreOwnedByLocked(gui::Pid pid, gui::Uid uid) REQUIRES(mLock); sp mReporter; diff --git a/services/inputflinger/dispatcher/Monitor.cpp b/services/inputflinger/dispatcher/Monitor.cpp index 43a82d5cca..204791eb03 100644 --- a/services/inputflinger/dispatcher/Monitor.cpp +++ b/services/inputflinger/dispatcher/Monitor.cpp @@ -19,7 +19,7 @@ namespace android::inputdispatcher { // --- Monitor --- -Monitor::Monitor(const std::shared_ptr& inputChannel, int32_t pid) +Monitor::Monitor(const std::shared_ptr& inputChannel, gui::Pid pid) : inputChannel(inputChannel), pid(pid) {} } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/Monitor.h b/services/inputflinger/dispatcher/Monitor.h index 7b511915d0..1b1eb3a593 100644 --- a/services/inputflinger/dispatcher/Monitor.h +++ b/services/inputflinger/dispatcher/Monitor.h @@ -16,6 +16,7 @@ #pragma once +#include #include namespace android::inputdispatcher { @@ -23,9 +24,9 @@ namespace android::inputdispatcher { struct Monitor { std::shared_ptr inputChannel; // never null - int32_t pid; + gui::Pid pid; - explicit Monitor(const std::shared_ptr& inputChannel, int32_t pid); + explicit Monitor(const std::shared_ptr& inputChannel, gui::Pid pid); }; } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index e9b737e3b5..419e3fb5e8 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -134,7 +134,7 @@ public: * * Returns true when changing touch mode state. */ - virtual bool setInTouchMode(bool inTouchMode, int32_t pid, gui::Uid uid, bool hasPermission, + virtual bool setInTouchMode(bool inTouchMode, gui::Pid pid, gui::Uid uid, bool hasPermission, int32_t displayId) = 0; /** @@ -182,7 +182,7 @@ public: */ virtual base::Result> createInputMonitor(int32_t displayId, const std::string& name, - int32_t pid) = 0; + gui::Pid pid) = 0; /* Removes input channels that will no longer receive input events. * diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h index 6592bca7b3..af28e48121 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h @@ -53,7 +53,7 @@ public: * pid of the owner. The string reason contains information about the input event that we * haven't received a response for. */ - virtual void notifyWindowUnresponsive(const sp& token, std::optional pid, + virtual void notifyWindowUnresponsive(const sp& token, std::optional pid, const std::string& reason) = 0; /* Notifies the system that a window just became responsive. This is only called after the @@ -61,7 +61,7 @@ public: * no longer should be shown to the user. The window is eligible to cause a new ANR in the * future. */ - virtual void notifyWindowResponsive(const sp& token, std::optional pid) = 0; + virtual void notifyWindowResponsive(const sp& token, std::optional pid) = 0; /* Notifies the system that an input channel is unrecoverably broken. */ virtual void notifyInputChannelBroken(const sp& token) = 0; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index c0da721264..9544da1d7b 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -95,15 +95,15 @@ static constexpr int32_t POINTER_2_UP = AMOTION_EVENT_ACTION_POINTER_UP | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); // The default pid and uid for windows created on the primary display by the test. -static constexpr int32_t WINDOW_PID = 999; +static constexpr gui::Pid WINDOW_PID{999}; static constexpr gui::Uid WINDOW_UID{1001}; // The default pid and uid for the windows created on the secondary display by the test. -static constexpr int32_t SECONDARY_WINDOW_PID = 1010; +static constexpr gui::Pid SECONDARY_WINDOW_PID{1010}; static constexpr gui::Uid SECONDARY_WINDOW_UID{1012}; // An arbitrary pid of the gesture monitor window -static constexpr int32_t MONITOR_PID = 2001; +static constexpr gui::Pid MONITOR_PID{2001}; static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms; @@ -206,7 +206,10 @@ MATCHER_P(WithPointers, pointers, "MotionEvent with specified pointers") { // --- FakeInputDispatcherPolicy --- class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { - using AnrResult = std::pair, int32_t /*pid*/>; + struct AnrResult { + sp token{}; + gui::Pid pid{gui::Pid::INVALID}; + }; public: FakeInputDispatcherPolicy() = default; @@ -296,15 +299,14 @@ public: void assertNotifyWindowUnresponsiveWasCalled(std::chrono::nanoseconds timeout, const sp& expectedToken, - int32_t expectedPid) { + gui::Pid expectedPid) { std::unique_lock lock(mLock); android::base::ScopedLockAssertion assumeLocked(mLock); AnrResult result; ASSERT_NO_FATAL_FAILURE(result = getAnrTokenLockedInterruptible(timeout, mAnrWindows, lock)); - const auto& [token, pid] = result; - ASSERT_EQ(expectedToken, token); - ASSERT_EQ(expectedPid, pid); + ASSERT_EQ(expectedToken, result.token); + ASSERT_EQ(expectedPid, result.pid); } /** Wrap call with ASSERT_NO_FATAL_FAILURE() to ensure the return value is valid. */ @@ -317,15 +319,14 @@ public: } void assertNotifyWindowResponsiveWasCalled(const sp& expectedToken, - int32_t expectedPid) { + gui::Pid expectedPid) { std::unique_lock lock(mLock); android::base::ScopedLockAssertion assumeLocked(mLock); AnrResult result; ASSERT_NO_FATAL_FAILURE( result = getAnrTokenLockedInterruptible(0s, mResponsiveWindows, lock)); - const auto& [token, pid] = result; - ASSERT_EQ(expectedToken, token); - ASSERT_EQ(expectedPid, pid); + ASSERT_EQ(expectedToken, result.token); + ASSERT_EQ(expectedPid, result.pid); } /** Wrap call with ASSERT_NO_FATAL_FAILURE() to ensure the return value is valid. */ @@ -500,7 +501,7 @@ private: mConfigurationChangedTime = when; } - void notifyWindowUnresponsive(const sp& connectionToken, std::optional pid, + void notifyWindowUnresponsive(const sp& connectionToken, std::optional pid, const std::string&) override { std::scoped_lock lock(mLock); ASSERT_TRUE(pid.has_value()); @@ -509,7 +510,7 @@ private: } void notifyWindowResponsive(const sp& connectionToken, - std::optional pid) override { + std::optional pid) override { std::scoped_lock lock(mLock); ASSERT_TRUE(pid.has_value()); mResponsiveWindows.push({connectionToken, *pid}); @@ -1434,12 +1435,12 @@ public: const std::string& getName() { return mName; } - void setOwnerInfo(int32_t ownerPid, gui::Uid ownerUid) { + void setOwnerInfo(gui::Pid ownerPid, gui::Uid ownerUid) { mInfo.ownerPid = ownerPid; mInfo.ownerUid = ownerUid; } - int32_t getPid() const { return mInfo.ownerPid; } + gui::Pid getPid() const { return mInfo.ownerPid; } void destroyReceiver() { mInputReceiver = nullptr; } @@ -5499,7 +5500,7 @@ TEST_F(InputDispatcherTest, DisplayRemoved) { * FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { - constexpr int32_t SLIPPERY_PID = WINDOW_PID + 1; + constexpr gui::Pid SLIPPERY_PID{WINDOW_PID.val() + 1}; constexpr gui::Uid SLIPPERY_UID{WINDOW_UID.val() + 1}; std::shared_ptr application = std::make_shared(); @@ -5587,19 +5588,19 @@ TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) { sp leftWindow = sp::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); leftWindow->setFrame(Rect(0, 0, 100, 100)); - leftWindow->setOwnerInfo(1, Uid{101}); + leftWindow->setOwnerInfo(gui::Pid{1}, Uid{101}); sp rightSpy = sp::make(application, mDispatcher, "Right spy", ADISPLAY_ID_DEFAULT); rightSpy->setFrame(Rect(100, 0, 200, 100)); - rightSpy->setOwnerInfo(2, Uid{102}); + rightSpy->setOwnerInfo(gui::Pid{2}, Uid{102}); rightSpy->setSpy(true); rightSpy->setTrustedOverlay(true); sp rightWindow = sp::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); rightWindow->setFrame(Rect(100, 0, 200, 100)); - rightWindow->setOwnerInfo(3, Uid{103}); + rightWindow->setOwnerInfo(gui::Pid{3}, Uid{103}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {rightSpy, rightWindow, leftWindow}}}); @@ -5664,7 +5665,7 @@ TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) { sp window = sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - window->setOwnerInfo(1, gui::Uid{101}); + window->setOwnerInfo(gui::Pid{1}, gui::Uid{101}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); setFocusedWindow(window); @@ -7901,7 +7902,7 @@ protected: sp window = sp::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT); // Generate an arbitrary PID based on the UID - window->setOwnerInfo(1777 + (uid.val() % 10000), uid); + window->setOwnerInfo(gui::Pid{static_cast(1777 + (uid.val() % 10000))}, uid); return window; } @@ -8747,13 +8748,13 @@ TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { sp::make(obscuringApplication, mDispatcher, "obscuringWindow", ADISPLAY_ID_DEFAULT); obscuringWindow->setFrame(Rect(0, 0, 50, 50)); - obscuringWindow->setOwnerInfo(111, gui::Uid{111}); + obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111}); obscuringWindow->setTouchable(false); std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); window->setDropInputIfObscured(true); - window->setOwnerInfo(222, gui::Uid{222}); + window->setOwnerInfo(gui::Pid{222}, gui::Uid{222}); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); @@ -8790,13 +8791,13 @@ TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) { sp::make(obscuringApplication, mDispatcher, "obscuringWindow", ADISPLAY_ID_DEFAULT); obscuringWindow->setFrame(Rect(0, 0, 50, 50)); - obscuringWindow->setOwnerInfo(111, gui::Uid{111}); + obscuringWindow->setOwnerInfo(gui::Pid{111}, gui::Uid{111}); obscuringWindow->setTouchable(false); std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, "Test window", ADISPLAY_ID_DEFAULT); window->setDropInputIfObscured(true); - window->setOwnerInfo(222, gui::Uid{222}); + window->setOwnerInfo(gui::Pid{222}, gui::Uid{222}); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); @@ -8873,7 +8874,7 @@ protected: } } - void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, int32_t pid, gui::Uid uid, + void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, gui::Pid pid, gui::Uid uid, bool hasPermission) { ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission, ADISPLAY_ID_DEFAULT)); @@ -8892,9 +8893,9 @@ TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) { TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) { const WindowInfo& windowInfo = *mWindow->getInfo(); - int32_t ownerPid = windowInfo.ownerPid; + gui::Pid ownerPid = windowInfo.ownerPid; gui::Uid ownerUid = windowInfo.ownerUid; - mWindow->setOwnerInfo(/*pid=*/-1, gui::Uid::INVALID); + mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID); ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid, ownerUid, /*hasPermission=*/false, ADISPLAY_ID_DEFAULT)); @@ -8904,9 +8905,9 @@ TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTo TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) { const WindowInfo& windowInfo = *mWindow->getInfo(); - int32_t ownerPid = windowInfo.ownerPid; + gui::Pid ownerPid = windowInfo.ownerPid; gui::Uid ownerUid = windowInfo.ownerUid; - mWindow->setOwnerInfo(/*pid=*/-1, gui::Uid::INVALID); + mWindow->setOwnerInfo(gui::Pid::INVALID, gui::Uid::INVALID); changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid, ownerUid, /*hasPermission=*/true); } @@ -9117,10 +9118,10 @@ TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) { */ TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { auto window = createForeground(); - window->setOwnerInfo(12, gui::Uid{34}); + window->setOwnerInfo(gui::Pid{12}, gui::Uid{34}); auto spy = createSpy(); spy->setWatchOutsideTouch(true); - spy->setOwnerInfo(56, gui::Uid{78}); + spy->setOwnerInfo(gui::Pid{56}, gui::Uid{78}); spy->setFrame(Rect{0, 0, 20, 20}); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -9533,7 +9534,7 @@ public: sp::make(overlayApplication, mDispatcher, "Stylus interceptor window", ADISPLAY_ID_DEFAULT); overlay->setFocusable(false); - overlay->setOwnerInfo(111, gui::Uid{111}); + overlay->setOwnerInfo(gui::Pid{111}, gui::Uid{111}); overlay->setTouchable(false); overlay->setInterceptsStylus(true); overlay->setTrustedOverlay(true); @@ -9544,7 +9545,7 @@ public: sp::make(application, mDispatcher, "Application window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); - window->setOwnerInfo(222, gui::Uid{222}); + window->setOwnerInfo(gui::Pid{222}, gui::Uid{222}); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); @@ -9654,12 +9655,12 @@ TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) { } struct User { - int32_t mPid; + gui::Pid mPid; gui::Uid mUid; uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS}; std::unique_ptr& mDispatcher; - User(std::unique_ptr& dispatcher, int32_t pid, gui::Uid uid) + User(std::unique_ptr& dispatcher, gui::Pid pid, gui::Uid uid) : mPid(pid), mUid(uid), mDispatcher(dispatcher) {} InputEventInjectionResult injectTargetedMotion(int32_t action) const { @@ -9692,7 +9693,7 @@ struct User { using InputDispatcherTargetedInjectionTest = InputDispatcherTest; TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) { - auto owner = User(mDispatcher, 10, gui::Uid{11}); + auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); auto window = owner.createWindow(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -9709,11 +9710,11 @@ TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) { } TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) { - auto owner = User(mDispatcher, 10, gui::Uid{11}); + auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); auto window = owner.createWindow(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); - auto rando = User(mDispatcher, 20, gui::Uid{21}); + auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21}); EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH, rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN)); @@ -9726,7 +9727,7 @@ TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) { } TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) { - auto owner = User(mDispatcher, 10, gui::Uid{11}); + auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); auto window = owner.createWindow(); auto spy = owner.createWindow(); spy->setSpy(true); @@ -9740,10 +9741,10 @@ TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) { } TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) { - auto owner = User(mDispatcher, 10, gui::Uid{11}); + auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); auto window = owner.createWindow(); - auto rando = User(mDispatcher, 20, gui::Uid{21}); + auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21}); auto randosSpy = rando.createWindow(); randosSpy->setSpy(true); randosSpy->setTrustedOverlay(true); @@ -9758,10 +9759,10 @@ TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) { } TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) { - auto owner = User(mDispatcher, 10, gui::Uid{11}); + auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); auto window = owner.createWindow(); - auto rando = User(mDispatcher, 20, gui::Uid{21}); + auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21}); auto randosSpy = rando.createWindow(); randosSpy->setSpy(true); randosSpy->setTrustedOverlay(true); @@ -9783,10 +9784,10 @@ TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTarget } TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherUids) { - auto owner = User(mDispatcher, 10, gui::Uid{11}); + auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); auto window = owner.createWindow(); - auto rando = User(mDispatcher, 20, gui::Uid{21}); + auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21}); auto randosWindow = rando.createWindow(); randosWindow->setFrame(Rect{-10, -10, -5, -5}); randosWindow->setWatchOutsideTouch(true); diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index f469a1f624..3caeebec2a 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -47,7 +47,7 @@ LayerSnapshot::LayerSnapshot(const RequestedLayerState& state, inputInfo.name = state.name; inputInfo.id = static_cast(uniqueSequence); inputInfo.ownerUid = gui::Uid{state.ownerUid}; - inputInfo.ownerPid = state.ownerPid; + inputInfo.ownerPid = gui::Pid{state.ownerPid}; uid = state.ownerUid; pid = state.ownerPid; changes = RequestedLayerState::Changes::Created; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 806b5024fe..a266493c38 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -1008,7 +1008,7 @@ void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot, // 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 = requested.ownerPid; + snapshot.inputInfo.ownerPid = gui::Pid{requested.ownerPid}; } snapshot.touchCropId = requested.touchCropId; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index a5d7ce7966..5a010e8af6 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2453,7 +2453,7 @@ WindowInfo Layer::fillInputInfo(const InputDisplayArgs& displayArgs) { if (!hasInputInfo()) { mDrawingState.inputInfo.name = getName(); mDrawingState.inputInfo.ownerUid = gui::Uid{mOwnerUid}; - mDrawingState.inputInfo.ownerPid = mOwnerPid; + mDrawingState.inputInfo.ownerPid = gui::Pid{mOwnerPid}; mDrawingState.inputInfo.inputConfig |= WindowInfo::InputConfig::NO_INPUT_CHANNEL; mDrawingState.inputInfo.displayId = getLayerStack().id; } -- GitLab From 89f7119821cad623418b6091fccab72d12e9cc01 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 15 Jun 2023 22:14:15 +0000 Subject: [PATCH 0204/1187] Link libinput as a shared library for host Since the rust dependencies in libinput are included as a whole_static_lib, if we add the same rust dependencies in another library (e.g. in libinputflinger), they will be included more than once in the binary, resulting in duplicate symbol errors from the linker. We can add it as a shared lib dependency to get around the duplicate symbols. Bug: 278783893 Test: build Change-Id: I92897f3465852d7be030dbce995435edff9b54fd --- libs/input/Android.bp | 3 --- services/inputflinger/Android.bp | 10 ++-------- services/inputflinger/dispatcher/Android.bp | 3 +-- services/inputflinger/reader/Android.bp | 3 +-- services/inputflinger/tests/Android.bp | 4 ---- 5 files changed, 4 insertions(+), 19 deletions(-) diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 80a8c8d84e..30e4afe27d 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -274,9 +274,6 @@ cc_library { ], }, host: { - shared: { - enabled: false, - }, include_dirs: [ "bionic/libc/kernel/android/uapi/", "bionic/libc/kernel/uapi", diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index dc7c75a775..b007fd32ac 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -79,6 +79,7 @@ cc_defaults { "libcrypto", "libcutils", "libhidlbase", + "libinput", "libkll", "liblog", "libprotobuf-cpp-lite", @@ -95,14 +96,12 @@ cc_defaults { android: { shared_libs: [ "libgui", - "libinput", "libstatspull", "libstatssocket", ], }, host: { static_libs: [ - "libinput", "libstatspull", "libstatssocket", ], @@ -179,6 +178,7 @@ cc_defaults { "libbase", "libbinder", "libcutils", + "libinput", "liblog", "libutils", ], @@ -186,14 +186,8 @@ cc_defaults { "libinputflinger_headers", ], target: { - android: { - shared_libs: [ - "libinput", - ], - }, host: { static_libs: [ - "libinput", "libui-types", ], }, diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp index 492551ec06..8b57730b92 100644 --- a/services/inputflinger/dispatcher/Android.bp +++ b/services/inputflinger/dispatcher/Android.bp @@ -59,6 +59,7 @@ cc_defaults { "libbase", "libcrypto", "libcutils", + "libinput", "libkll", "liblog", "libprotobuf-cpp-lite", @@ -74,14 +75,12 @@ cc_defaults { android: { shared_libs: [ "libgui", - "libinput", "libstatspull", "libstatssocket", ], }, host: { static_libs: [ - "libinput", "libstatspull", "libstatssocket", ], diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index e594e4057d..c0c6d1f7e1 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -80,6 +80,7 @@ cc_defaults { "libcrypto", "libcutils", "libjsoncpp", + "libinput", "liblog", "libPlatformProperties", "libstatslog", @@ -98,13 +99,11 @@ cc_defaults { target: { android: { shared_libs: [ - "libinput", "libstatspull", ], }, host: { static_libs: [ - "libinput", "libbinder", "libstatspull", ], diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 370e971a91..187bc0ad7a 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -75,7 +75,6 @@ cc_test { target: { android: { shared_libs: [ - "libinput", "libvintf", ], }, @@ -90,9 +89,6 @@ cc_test { cflags: [ "-D__ANDROID_HOST__", ], - static_libs: [ - "libinput", - ], }, }, sanitize: { -- GitLab From 734537727237ec6217241520f66229630359d303 Mon Sep 17 00:00:00 2001 From: Priyanka Advani Date: Thu, 22 Jun 2023 21:22:35 +0000 Subject: [PATCH 0205/1187] Revert "Parcel: fdsan" Revert submission 23699976-fdsan-parcel Reason for revert: Possible culprit for b/288448299 Reverted changes: /q/submissionid:23699976-fdsan-parcel Change-Id: I8d7b4e222598436271ee03cfc8826910327c98aa --- libs/binder/Parcel.cpp | 52 +++--------------------------------------- 1 file changed, 3 insertions(+), 49 deletions(-) diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 1312d223cc..0aca163eab 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -69,10 +69,6 @@ typedef uintptr_t binder_uintptr_t; #endif // BINDER_WITH_KERNEL_IPC -#ifdef __BIONIC__ -#include -#endif - #define LOG_REFS(...) // #define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOG_ALLOC(...) @@ -113,37 +109,6 @@ constexpr size_t kMaxFds = 1024; // Maximum size of a blob to transfer in-place. static const size_t BLOB_INPLACE_LIMIT = 16 * 1024; -#if defined(__BIONIC__) -static void FdTag(int fd, const void* old_addr, const void* new_addr) { - if (android_fdsan_exchange_owner_tag) { - uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_PARCEL, - reinterpret_cast(old_addr)); - uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_PARCEL, - reinterpret_cast(new_addr)); - android_fdsan_exchange_owner_tag(fd, old_tag, new_tag); - } -} -static void FdTagClose(int fd, const void* addr) { - if (android_fdsan_close_with_tag) { - uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_PARCEL, - reinterpret_cast(addr)); - android_fdsan_close_with_tag(fd, tag); - } else { - close(fd); - } -} -#else -static void FdTag(int fd, const void* old_addr, const void* new_addr) { - (void)fd; - (void)old_addr; - (void)new_addr; -} -static void FdTagClose(int fd, const void* addr) { - (void)addr; - close(fd); -} -#endif - enum { BLOB_INPLACE = 0, BLOB_ASHMEM_IMMUTABLE = 1, @@ -169,9 +134,6 @@ static void acquire_object(const sp& proc, const flat_binder_objec return; } case BINDER_TYPE_FD: { - if (obj.cookie != 0) { // owned - FdTag(obj.handle, nullptr, who); - } return; } } @@ -197,10 +159,8 @@ static void release_object(const sp& proc, const flat_binder_objec return; } case BINDER_TYPE_FD: { - // note: this path is not used when mOwner, so the tag is also released - // in 'closeFileDescriptors' if (obj.cookie != 0) { // owned - FdTagClose(obj.handle, who); + close(obj.handle); } return; } @@ -594,6 +554,7 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { kernelFields->mObjectsSize++; flat_binder_object* flat = reinterpret_cast(mData + off); + acquire_object(proc, *flat, this); if (flat->hdr.type == BINDER_TYPE_FD) { // If this is a file descriptor, we need to dup it so the @@ -606,8 +567,6 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { err = FDS_NOT_ALLOWED; } } - - acquire_object(proc, *flat, this); } } #else @@ -2558,8 +2517,7 @@ void Parcel::closeFileDescriptors() { reinterpret_cast(mData + kernelFields->mObjects[i]); if (flat->hdr.type == BINDER_TYPE_FD) { // ALOGI("Closing fd: %ld", flat->handle); - // FDs from the kernel are always owned - FdTagClose(flat->handle, this); + close(flat->handle); } } #else // BINDER_WITH_KERNEL_IPC @@ -2640,10 +2598,6 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const bin kernelFields->mObjectsSize = 0; break; } - if (type == BINDER_TYPE_FD) { - // FDs from the kernel are always owned - FdTag(flat->handle, 0, this); - } minOffset = offset + sizeof(flat_binder_object); } scanForFds(); -- GitLab From 02f736f8fae26e192bf2a0c767e98d7e4da900e2 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 22 Jun 2023 23:03:57 +0000 Subject: [PATCH 0206/1187] Revert^2 "Parcel: fdsan" 734537727237ec6217241520f66229630359d303 Change-Id: I8e3df46d474c857a76fb00ab195d73dbea282520 --- libs/binder/Parcel.cpp | 52 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 0aca163eab..1312d223cc 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -69,6 +69,10 @@ typedef uintptr_t binder_uintptr_t; #endif // BINDER_WITH_KERNEL_IPC +#ifdef __BIONIC__ +#include +#endif + #define LOG_REFS(...) // #define LOG_REFS(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOG_ALLOC(...) @@ -109,6 +113,37 @@ constexpr size_t kMaxFds = 1024; // Maximum size of a blob to transfer in-place. static const size_t BLOB_INPLACE_LIMIT = 16 * 1024; +#if defined(__BIONIC__) +static void FdTag(int fd, const void* old_addr, const void* new_addr) { + if (android_fdsan_exchange_owner_tag) { + uint64_t old_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_PARCEL, + reinterpret_cast(old_addr)); + uint64_t new_tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_PARCEL, + reinterpret_cast(new_addr)); + android_fdsan_exchange_owner_tag(fd, old_tag, new_tag); + } +} +static void FdTagClose(int fd, const void* addr) { + if (android_fdsan_close_with_tag) { + uint64_t tag = android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_PARCEL, + reinterpret_cast(addr)); + android_fdsan_close_with_tag(fd, tag); + } else { + close(fd); + } +} +#else +static void FdTag(int fd, const void* old_addr, const void* new_addr) { + (void)fd; + (void)old_addr; + (void)new_addr; +} +static void FdTagClose(int fd, const void* addr) { + (void)addr; + close(fd); +} +#endif + enum { BLOB_INPLACE = 0, BLOB_ASHMEM_IMMUTABLE = 1, @@ -134,6 +169,9 @@ static void acquire_object(const sp& proc, const flat_binder_objec return; } case BINDER_TYPE_FD: { + if (obj.cookie != 0) { // owned + FdTag(obj.handle, nullptr, who); + } return; } } @@ -159,8 +197,10 @@ static void release_object(const sp& proc, const flat_binder_objec return; } case BINDER_TYPE_FD: { + // note: this path is not used when mOwner, so the tag is also released + // in 'closeFileDescriptors' if (obj.cookie != 0) { // owned - close(obj.handle); + FdTagClose(obj.handle, who); } return; } @@ -554,7 +594,6 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { kernelFields->mObjectsSize++; flat_binder_object* flat = reinterpret_cast(mData + off); - acquire_object(proc, *flat, this); if (flat->hdr.type == BINDER_TYPE_FD) { // If this is a file descriptor, we need to dup it so the @@ -567,6 +606,8 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { err = FDS_NOT_ALLOWED; } } + + acquire_object(proc, *flat, this); } } #else @@ -2517,7 +2558,8 @@ void Parcel::closeFileDescriptors() { reinterpret_cast(mData + kernelFields->mObjects[i]); if (flat->hdr.type == BINDER_TYPE_FD) { // ALOGI("Closing fd: %ld", flat->handle); - close(flat->handle); + // FDs from the kernel are always owned + FdTagClose(flat->handle, this); } } #else // BINDER_WITH_KERNEL_IPC @@ -2598,6 +2640,10 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const bin kernelFields->mObjectsSize = 0; break; } + if (type == BINDER_TYPE_FD) { + // FDs from the kernel are always owned + FdTag(flat->handle, 0, this); + } minOffset = offset + sizeof(flat_binder_object); } scanForFds(); -- GitLab From 8117c1a78d49c3e02f2ece22b994ace03c200153 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Wed, 24 May 2023 15:12:15 -0700 Subject: [PATCH 0207/1187] SF: Introduce struct surfaceflinger::Config This pulls out all the individual configuration constants read by SurfaceFlinger in its constructor, and moves them to a new surfaceflinger::Config structure which is passed to the constructor. All the initialization is the functionally the same, a few values turned out to not be used, so were removed (mMaxGraphicBufferProducerListSize, mGraphicBufferProducerListSizeLogThreshold). Otherwise all properties read for the new structure consistently use android-base/properties.h to read them. To keep the argument count down, the SurfaceFlinger factory argument to the constructor was moved to be stored in the new Config structure. As a result of the change, SurfaceFlinger now only has one constructor. The tests were using the other constructor (passing SurfaceFlinger::skipInitiailization) to skip over the property reads to help ensure a hermetic configuration of SurfaceFlinger. The tests can now instead create create a minimally configured Config structure, and pass that the structure. The other changes were then to switch over to using the values in the Config structure, both internally to SurfaceFlinger, as well as in other files including Layer.cpp and DisplayDevice.cpp. In some cases, those changes required altering the arguments to the function being called to obtain the values, since originally some of the values where static member data in SurfaceFlinger. There were similar changes required for the tests and the fuzzers, to switch over, including how some tests mutated the configuration values so that they overall coverage was the same. No new tests/fuzzing was added, though it should now be easier to extend coverage. Test: atest libsurfaceflinger_unittest Bug: None Change-Id: I8dc3c2317a92b256e58ec45190e24463032c2f8e --- services/surfaceflinger/Android.bp | 1 + services/surfaceflinger/DisplayDevice.cpp | 24 +- services/surfaceflinger/DisplayDevice.h | 3 +- .../DisplayHardware/FramebufferSurface.cpp | 6 +- .../DisplayHardware/FramebufferSurface.h | 2 +- .../DisplayHardware/VirtualDisplaySurface.cpp | 4 +- .../DisplayHardware/VirtualDisplaySurface.h | 3 +- services/surfaceflinger/Layer.cpp | 6 +- services/surfaceflinger/LayerRenderArea.cpp | 2 +- .../surfaceflinger/RegionSamplingThread.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 321 ++++++------------ services/surfaceflinger/SurfaceFlinger.h | 113 +----- .../surfaceflinger/SurfaceFlingerConfig.cpp | 162 +++++++++ .../surfaceflinger/SurfaceFlingerConfig.h | 145 ++++++++ .../surfaceflinger/SurfaceFlingerFactory.cpp | 11 +- .../surfaceflinger_displayhardware_fuzzer.cpp | 6 +- .../fuzzer/surfaceflinger_fuzzer.cpp | 30 +- .../fuzzer/surfaceflinger_fuzzers_utils.h | 16 +- .../fuzzer/surfaceflinger_service_fuzzer.cpp | 4 +- .../unittests/DisplayTransactionTest.cpp | 2 +- .../unittests/DisplayTransactionTestHelpers.h | 4 +- .../tests/unittests/SchedulerTest.cpp | 4 +- ...eFlinger_GetDisplayNativePrimariesTest.cpp | 4 +- ...nger_SetupNewDisplayDeviceInternalTest.cpp | 2 +- .../tests/unittests/TestableSurfaceFlinger.h | 17 +- 25 files changed, 491 insertions(+), 403 deletions(-) create mode 100644 services/surfaceflinger/SurfaceFlingerConfig.cpp create mode 100644 services/surfaceflinger/SurfaceFlingerConfig.h diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 89c80bc83a..bf07f7253f 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -195,6 +195,7 @@ filegroup { "ScreenCaptureOutput.cpp", "StartPropertySetThread.cpp", "SurfaceFlinger.cpp", + "SurfaceFlingerConfig.cpp", "SurfaceFlingerDefaultFactory.cpp", "Tracing/LayerTracing.cpp", "Tracing/TransactionTracing.cpp", diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index f6ca9e2856..2789fa6bf2 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -78,18 +78,19 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) .setDisplayHeight(ANativeWindow_getHeight(args.nativeWindow.get())) .setNativeWindow(std::move(args.nativeWindow)) .setDisplaySurface(std::move(args.displaySurface)) - .setMaxTextureCacheSize( - static_cast(SurfaceFlinger::maxFrameBufferAcquiredBuffers)) + .setMaxTextureCacheSize(static_cast( + mFlinger->getConfig().maxFrameBufferAcquiredBuffers)) .build()); - if (!mFlinger->mDisableClientCompositionCache && - SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) { + if (!mFlinger->getConfig().disableClientCompositionCache && + mFlinger->getConfig().maxFrameBufferAcquiredBuffers > 0) { mCompositionDisplay->createClientCompositionCache( - static_cast(SurfaceFlinger::maxFrameBufferAcquiredBuffers)); + static_cast(mFlinger->getConfig().maxFrameBufferAcquiredBuffers)); } - mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy); - mCompositionDisplay->setTreat170mAsSrgb(mFlinger->mTreat170mAsSrgb); + mCompositionDisplay->setPredictCompositionStrategy( + mFlinger->getConfig().predictCompositionStrategy); + mCompositionDisplay->setTreat170mAsSrgb(mFlinger->getConfig().treat170mAsSrgb); mCompositionDisplay->createDisplayColorProfile( compositionengine::DisplayColorProfileCreationArgsBuilder() .setHasWideColorGamut(args.hasWideColorGamut) @@ -411,23 +412,22 @@ HdrCapabilities DisplayDevice::getHdrCapabilities() const { capabilities.getDesiredMinLuminance()); } -void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner, - bool showRenderRate, bool showInMiddle) { +void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc) { if (!enable) { mRefreshRateOverlay.reset(); return; } ftl::Flags features; - if (showSpinner) { + if (mFlinger->getConfig().refreshRateOverlay.showSpinner) { features |= RefreshRateOverlay::Features::Spinner; } - if (showRenderRate) { + if (mFlinger->getConfig().refreshRateOverlay.showRenderRate) { features |= RefreshRateOverlay::Features::RenderRate; } - if (showInMiddle) { + if (mFlinger->getConfig().refreshRateOverlay.showInMiddle) { features |= RefreshRateOverlay::Features::ShowInMiddle; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index dc5f8a85af..d2a9fb685a 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -236,8 +236,7 @@ public: } // Enables an overlay to be displayed with the current refresh rate - void enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner, bool showRenderRate, - bool showInMiddle) REQUIRES(kMainThreadContext); + void enableRefreshRateOverlay(bool enable, bool setByHwc) REQUIRES(kMainThreadContext); void updateRefreshRateOverlayRate(Fps displayFps, Fps renderFps, bool setByHwc = false); bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; } bool onKernelTimerChanged(std::optional, bool timerExpired); diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index ce602a8ad9..14fff772db 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -50,7 +50,8 @@ using ui::Dataspace; FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId, const sp& consumer, - const ui::Size& size, const ui::Size& maxSize) + const ui::Size& size, const ui::Size& maxSize, + int maxAcquiredBufferCount) : ConsumerBase(consumer), mDisplayId(displayId), mMaxSize(maxSize), @@ -70,8 +71,7 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displa GRALLOC_USAGE_HW_COMPOSER); const auto limitedSize = limitSize(size); mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height); - mConsumer->setMaxAcquiredBufferCount( - SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1); + mConsumer->setMaxAcquiredBufferCount(maxAcquiredBufferCount); for (size_t i = 0; i < sizeof(mHwcBufferIds) / sizeof(mHwcBufferIds[0]); ++i) { mHwcBufferIds[i] = UINT64_MAX; diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index 0b863daf47..5a1d14fdfe 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -42,7 +42,7 @@ class FramebufferSurface : public ConsumerBase, public compositionengine::Displa public: FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId, const sp& consumer, const ui::Size& size, - const ui::Size& maxSize); + const ui::Size& maxSize, int maxAcquiredBufferCount); virtual status_t beginFrame(bool mustRecompose); virtual status_t prepareFrame(CompositionType compositionType); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index d62075ec65..d759c12612 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -50,7 +50,7 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, VirtualDisplayId d const sp& sink, const sp& bqProducer, const sp& bqConsumer, - const std::string& name) + const std::string& name, bool useHwcForRgbToYuv) : ConsumerBase(bqConsumer), mHwc(hwc), mDisplayId(displayId), @@ -69,7 +69,7 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, VirtualDisplayId d mOutputFence(Fence::NO_FENCE), mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT), mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT), - mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv) { + mForceHwcCopy(useHwcForRgbToYuv) { mSource[SOURCE_SINK] = sink; mSource[SOURCE_SCRATCH] = bqProducer; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index be06e2bb10..8a56d5f7b5 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -77,7 +77,8 @@ class VirtualDisplaySurface : public compositionengine::DisplaySurface, public: VirtualDisplaySurface(HWComposer&, VirtualDisplayId, const sp& sink, const sp& bqProducer, - const sp& bqConsumer, const std::string& name); + const sp& bqConsumer, const std::string& name, + bool useHwcForRgbToYuv); // // DisplaySurface interface diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index fabcd6168c..fd93ae219a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2562,7 +2562,7 @@ bool Layer::hasInputInfo() const { compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( const DisplayDevice* display) const { if (!display) return nullptr; - if (!mFlinger->mLayerLifecycleManagerEnabled) { + if (!mFlinger->getConfig().layerLifecycleManagerEnabled) { return display->getCompositionDisplay()->getOutputLayerForLayer( getCompositionEngineLayerFE()); } @@ -2907,7 +2907,7 @@ void Layer::onSurfaceFrameCreated( void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) { for (const auto& handle : mDrawingState.callbackHandles) { - if (mFlinger->mLayerLifecycleManagerEnabled) { + if (mFlinger->getConfig().layerLifecycleManagerEnabled) { handle->transformHint = mTransformHint; } else { handle->transformHint = mSkipReportingTransformHint @@ -3162,7 +3162,7 @@ bool Layer::setBuffer(std::shared_ptr& buffer, mFlinger->mTimeStats->setPostTime(layerId, mDrawingState.frameNumber, getName().c_str(), mOwnerUid, postTime, getGameMode()); - if (mFlinger->mLegacyFrontEndEnabled) { + if (mFlinger->getConfig().legacyFrontEndEnabled) { recordLayerHistoryBufferUpdate(getLayerProps()); } diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp index 51d4ff854f..9c1944b122 100644 --- a/services/surfaceflinger/LayerRenderArea.cpp +++ b/services/surfaceflinger/LayerRenderArea.cpp @@ -78,7 +78,7 @@ void LayerRenderArea::render(std::function drawLayers) { mTransform = mLayerTransform.inverse(); } - if (mFlinger.mLayerLifecycleManagerEnabled) { + if (mFlinger.getConfig().layerLifecycleManagerEnabled) { drawLayers(); return; } diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 8f658d5a09..03f3b402c9 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -322,7 +322,7 @@ void RegionSamplingThread::captureSample() { }; std::function>>()> getLayerSnapshots; - if (mFlinger.mLayerLifecycleManagerEnabled) { + if (mFlinger.getConfig().layerLifecycleManagerEnabled) { auto filterFn = [&](const frontend::LayerSnapshot& snapshot, bool& outStopTraversal) -> bool { const Rect bounds = diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 975b54a27d..ae1b095206 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -213,16 +213,6 @@ static constexpr int FOUR_K_HEIGHT = 2160; // TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity. constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV; -float getDensityFromProperty(const char* property, bool required) { - char value[PROPERTY_VALUE_MAX]; - const float density = property_get(property, value, nullptr) > 0 ? std::atof(value) : 0.f; - if (!density && required) { - ALOGE("%s must be defined as a build property", property); - return FALLBACK_DENSITY; - } - return density; -} - // Currently we only support V0_SRGB and DISPLAY_P3 as composition preference. bool validateCompositionDataspace(Dataspace dataspace) { return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3; @@ -321,18 +311,6 @@ const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled static const int MAX_TRACING_MEMORY = 1024 * 1024 * 1024; // 1GB // --------------------------------------------------------------------------- -int64_t SurfaceFlinger::dispSyncPresentTimeOffset; -bool SurfaceFlinger::useHwcForRgbToYuv; -bool SurfaceFlinger::hasSyncFramework; -int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers; -int64_t SurfaceFlinger::minAcquiredBuffers = 1; -uint32_t SurfaceFlinger::maxGraphicsWidth; -uint32_t SurfaceFlinger::maxGraphicsHeight; -bool SurfaceFlinger::useContextPriority; -Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB; -ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888; -Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB; -ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; LatchUnsignaledConfig SurfaceFlinger::enableLatchUnsignaledConfig; std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { @@ -359,136 +337,35 @@ bool callingThreadHasPermission(const String16& permission) { ui::Transform::RotationFlags SurfaceFlinger::sActiveDisplayRotationFlags = ui::Transform::ROT_0; -SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) - : mFactory(factory), - mPid(getpid()), +SurfaceFlinger::SurfaceFlinger(surfaceflinger::Config& config) + : mConfig(&config), + mDebugFlashDelay(base::GetUintProperty("debug.sf.showupdates"s, 0u)), mTimeStats(std::make_shared()), - mFrameTracer(mFactory.createFrameTracer()), - mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, mPid)), - mCompositionEngine(mFactory.createCompositionEngine()), - mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)), + mFrameTracer(mConfig->factory->createFrameTracer()), + mFrameTimeline(mConfig->factory->createFrameTimeline(mTimeStats, mConfig->pid)), + mCompositionEngine(mConfig->factory->createCompositionEngine()), mTunnelModeEnabledReporter(sp::make()), - mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)), - mInternalDisplayDensity( - getDensityFromProperty("ro.sf.lcd_density", !mEmulatedDisplayDensity)), mPowerAdvisor(std::make_unique(*this)), mWindowInfosListenerInvoker(sp::make()) { - ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str()); -} - -SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) { ATRACE_CALL(); - ALOGI("SurfaceFlinger is starting"); - - hasSyncFramework = running_without_sync_framework(true); - - dispSyncPresentTimeOffset = present_time_offset_from_vsync_ns(0); - - useHwcForRgbToYuv = force_hwc_copy_for_virtual_displays(false); - - maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2); - minAcquiredBuffers = - SurfaceFlingerProperties::min_acquired_buffers().value_or(minAcquiredBuffers); - - maxGraphicsWidth = std::max(max_graphics_width(0), 0); - maxGraphicsHeight = std::max(max_graphics_height(0), 0); - - mSupportsWideColor = has_wide_color_display(false); - mDefaultCompositionDataspace = - static_cast(default_composition_dataspace(Dataspace::V0_SRGB)); - mWideColorGamutCompositionDataspace = static_cast(wcg_composition_dataspace( - mSupportsWideColor ? Dataspace::DISPLAY_P3 : Dataspace::V0_SRGB)); - defaultCompositionDataspace = mDefaultCompositionDataspace; - wideColorGamutCompositionDataspace = mWideColorGamutCompositionDataspace; - defaultCompositionPixelFormat = static_cast( - default_composition_pixel_format(ui::PixelFormat::RGBA_8888)); - wideColorGamutCompositionPixelFormat = - static_cast(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888)); - - mColorSpaceAgnosticDataspace = - static_cast(color_space_agnostic_dataspace(Dataspace::UNKNOWN)); - - mLayerCachingEnabled = [] { - const bool enable = - android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false); - return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable); - }(); - - useContextPriority = use_context_priority(true); - - mInternalDisplayPrimaries = sysprop::getDisplayNativePrimaries(); + ALOGI("SurfaceFlinger is starting."); + ALOGI("Using HWComposer service: %s", mConfig->hwcServiceName.c_str()); + ALOGI_IF(mConfig->backpressureGpuComposition, "Enabling backpressure for GPU composition"); + ALOGI_IF(!mConfig->supportsBlur, "Disabling blur effects, they are not supported."); + ALOGI_IF(mConfig->trebleTestingOverride, "Enabling Treble testing override"); - // debugging stuff... - char value[PROPERTY_VALUE_MAX]; - - property_get("ro.build.type", value, "user"); - mIsUserBuild = strcmp(value, "user") == 0; - - mDebugFlashDelay = base::GetUintProperty("debug.sf.showupdates"s, 0u); - - mBackpressureGpuComposition = base::GetBoolProperty("debug.sf.enable_gl_backpressure"s, true); - ALOGI_IF(mBackpressureGpuComposition, "Enabling backpressure for GPU composition"); - - property_get("ro.surface_flinger.supports_background_blur", value, "0"); - bool supportsBlurs = atoi(value); - mSupportsBlur = supportsBlurs; - ALOGI_IF(!mSupportsBlur, "Disabling blur effects, they are not supported."); - - const size_t defaultListSize = MAX_LAYERS; - auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize)); - mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize; - mGraphicBufferProducerListSizeLogThreshold = - std::max(static_cast(0.95 * - static_cast(mMaxGraphicBufferProducerListSize)), - 1); - - property_get("debug.sf.luma_sampling", value, "1"); - mLumaSampling = atoi(value); - - property_get("debug.sf.disable_client_composition_cache", value, "0"); - mDisableClientCompositionCache = atoi(value); - - property_get("debug.sf.predict_hwc_composition_strategy", value, "1"); - mPredictCompositionStrategy = atoi(value); - - property_get("debug.sf.treat_170m_as_sRGB", value, "0"); - mTreat170mAsSrgb = atoi(value); - - mIgnoreHwcPhysicalDisplayOrientation = - base::GetBoolProperty("debug.sf.ignore_hwc_physical_display_orientation"s, false); - - // We should be reading 'persist.sys.sf.color_saturation' here - // but since /data may be encrypted, we need to wait until after vold - // comes online to attempt to read the property. The property is - // instead read after the boot animation - - if (base::GetBoolProperty("debug.sf.treble_testing_override"s, false)) { + if (mConfig->trebleTestingOverride) { // Without the override SurfaceFlinger cannot connect to HIDL // services that are not listed in the manifests. Considered // deriving the setting from the set service name, but it // would be brittle if the name that's not 'default' is used // for production purposes later on. - ALOGI("Enabling Treble testing override"); android::hardware::details::setTrebleTestingOverride(true); } - // TODO (b/270966065) Update the HWC based refresh rate overlay to support spinner - mRefreshRateOverlaySpinner = property_get_bool("debug.sf.show_refresh_rate_overlay_spinner", 0); - mRefreshRateOverlayRenderRate = - property_get_bool("debug.sf.show_refresh_rate_overlay_render_rate", 0); - mRefreshRateOverlayShowInMiddle = - property_get_bool("debug.sf.show_refresh_rate_overlay_in_middle", 0); - - if (!mIsUserBuild && base::GetBoolProperty("debug.sf.enable_transaction_tracing"s, true)) { + if (!mConfig->isUserBuild && mConfig->enableTransactionTracing) { mTransactionTracing.emplace(); } - - mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false); - - mLayerLifecycleManagerEnabled = - base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false); - mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled || - base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); } LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { @@ -815,17 +692,18 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { // Get a RenderEngine for the given display / config (can't fail) // TODO(b/77156734): We need to stop casting and use HAL types when possible. // Sending maxFrameBufferAcquiredBuffers as the cache size is tightly tuned to single-display. - auto builder = renderengine::RenderEngineCreationArgs::Builder() - .setPixelFormat(static_cast(defaultCompositionPixelFormat)) - .setImageCacheSize(maxFrameBufferAcquiredBuffers) - .setUseColorManagerment(useColorManagement) - .setEnableProtectedContext(enable_protected_contents(false)) - .setPrecacheToneMapperShaderOnly(false) - .setSupportsBackgroundBlur(mSupportsBlur) - .setContextPriority( - useContextPriority - ? renderengine::RenderEngine::ContextPriority::REALTIME - : renderengine::RenderEngine::ContextPriority::MEDIUM); + auto builder = + renderengine::RenderEngineCreationArgs::Builder() + .setPixelFormat(static_cast(mConfig->defaultCompositionPixelFormat)) + .setImageCacheSize(mConfig->maxFrameBufferAcquiredBuffers) + .setUseColorManagerment(useColorManagement) + .setEnableProtectedContext(enable_protected_contents(false)) + .setPrecacheToneMapperShaderOnly(false) + .setSupportsBackgroundBlur(mConfig->supportsBlur) + .setContextPriority( + mConfig->useContextPriority + ? renderengine::RenderEngine::ContextPriority::REALTIME + : renderengine::RenderEngine::ContextPriority::MEDIUM); if (auto type = chooseRenderEngineTypeViaSysProp()) { builder.setRenderEngineType(type.value()); } @@ -840,7 +718,7 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { } mCompositionEngine->setTimeStats(mTimeStats); - mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName)); + mCompositionEngine->setHwComposer(getFactory().createHWComposer(mConfig->hwcServiceName)); mCompositionEngine->getHwComposer().setCallback(*this); ClientCache::getInstance().setRenderEngine(&getRenderEngine()); @@ -1032,11 +910,11 @@ status_t SurfaceFlinger::getStaticDisplayInfo(int64_t displayId, ui::StaticDispl info->connectionType = snapshot.connectionType(); info->deviceProductInfo = snapshot.deviceProductInfo(); - if (mEmulatedDisplayDensity) { - info->density = mEmulatedDisplayDensity; + if (mConfig->emulatedDisplayDensity) { + info->density = mConfig->emulatedDisplayDensity; } else { info->density = info->connectionType == ui::DisplayConnectionType::Internal - ? mInternalDisplayDensity + ? mConfig->internalDisplayDensity : FALLBACK_DENSITY; } info->density /= ACONFIGURATION_DENSITY_MEDIUM; @@ -1099,7 +977,7 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info info->supportedDisplayModes.push_back(outMode); } - info->supportedColorModes = snapshot.filterColorModes(mSupportsWideColor); + info->supportedColorModes = snapshot.filterColorModes(mConfig->supportsWideColor); const PhysicalDisplayId displayId = snapshot.displayId(); @@ -1497,7 +1375,7 @@ status_t SurfaceFlinger::getDisplayNativePrimaries(const sp& displayTok } // TODO(b/229846990): For now, assume that all internal displays have the same primaries. - primaries = mInternalDisplayPrimaries; + primaries = mConfig->internalDisplayPrimaries; return NO_ERROR; } @@ -1521,7 +1399,7 @@ status_t SurfaceFlinger::setActiveColorMode(const sp& displayToken, ui: const auto& [display, snapshotRef] = *displayOpt; const auto& snapshot = snapshotRef.get(); - const auto modes = snapshot.filterColorModes(mSupportsWideColor); + const auto modes = snapshot.filterColorModes(mConfig->supportsWideColor); const bool exists = std::find(modes.begin(), modes.end(), mode) != modes.end(); if (mode < ui::ColorMode::NATIVE || !exists) { @@ -1827,7 +1705,7 @@ status_t SurfaceFlinger::isWideColorDisplay(const sp& displayToken, } *outIsWideColorDisplay = - display->isPrimary() ? mSupportsWideColor : display->hasWideColorGamut(); + display->isPrimary() ? mConfig->supportsWideColor : display->hasWideColorGamut(); return NO_ERROR; } @@ -1848,10 +1726,12 @@ status_t SurfaceFlinger::getCompositionPreference( Dataspace* outDataspace, ui::PixelFormat* outPixelFormat, Dataspace* outWideColorGamutDataspace, ui::PixelFormat* outWideColorGamutPixelFormat) const { - *outDataspace = mDefaultCompositionDataspace; - *outPixelFormat = defaultCompositionPixelFormat; - *outWideColorGamutDataspace = mWideColorGamutCompositionDataspace; - *outWideColorGamutPixelFormat = wideColorGamutCompositionPixelFormat; + *outDataspace = + mOverrideDefaultCompositionDataspace.value_or(mConfig->defaultCompositionDataspace); + *outPixelFormat = mConfig->defaultCompositionPixelFormat; + *outWideColorGamutDataspace = mOverrideWideColorGamutCompositionDataspace.value_or( + mConfig->wideColorGamutCompositionDataspace); + *outWideColorGamutPixelFormat = mConfig->wideColorGamutCompositionPixelFormat; return NO_ERROR; } @@ -2259,7 +2139,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& upd .displays = mFrontEndDisplayInfos, .displayChanges = mFrontEndDisplayInfosChanged, .globalShadowSettings = mDrawingState.globalShadowSettings, - .supportsBlur = mSupportsBlur, + .supportsBlur = mConfig->supportsBlur, .forceFullDamage = mForceFullDamage, .supportedLayerGenericMetadata = getHwComposer().getSupportedLayerGenericMetadata(), @@ -2279,7 +2159,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& upd mustComposite |= mLayerLifecycleManager.getGlobalChanges().get() != 0; bool newDataLatched = false; - if (!mLegacyFrontEndEnabled) { + if (!mConfig->legacyFrontEndEnabled) { ATRACE_NAME("DisplayCallbackAndStatsUpdates"); applyTransactions(update.transactions, vsyncId); const nsecs_t latchTime = systemTime(); @@ -2373,7 +2253,7 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) } if (pacesetterFrameTarget.isFramePending()) { - if (mBackpressureGpuComposition || pacesetterFrameTarget.didMissHwcFrame()) { + if (mConfig->backpressureGpuComposition || pacesetterFrameTarget.didMissHwcFrame()) { scheduleCommit(FrameHint::kNone); return false; } @@ -2404,7 +2284,7 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) mPowerAdvisor->updateTargetWorkDuration(idealVsyncPeriod); } - if (mRefreshRateOverlaySpinner) { + if (mConfig->refreshRateOverlay.showSpinner) { Mutex::Autolock lock(mStateLock); if (const auto display = getDefaultDisplayDeviceLocked()) { display->animateRefreshRateOverlay(); @@ -2431,11 +2311,11 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) } } bool transactionsAreEmpty; - if (mLegacyFrontEndEnabled) { + if (mConfig->legacyFrontEndEnabled) { mustComposite |= updateLayerSnapshotsLegacy(vsyncId, updates, flushTransactions, transactionsAreEmpty); } - if (mLayerLifecycleManagerEnabled) { + if (mConfig->layerLifecycleManagerEnabled) { mustComposite |= updateLayerSnapshots(vsyncId, updates, flushTransactions, transactionsAreEmpty); } @@ -2539,7 +2419,7 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr refreshArgs.outputColorSetting = useColorManagement ? mDisplayColorSetting : compositionengine::OutputColorSetting::kUnmanaged; - refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace; + refreshArgs.colorSpaceAgnosticDataspace = mConfig->colorSpaceAgnosticDataspace; refreshArgs.forceOutputColorMode = mForceColorMode; refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty; @@ -2693,7 +2573,7 @@ bool SurfaceFlinger::isHdrLayer(const frontend::LayerSnapshot& snapshot) const { // Even though the camera layer may be using an HDR transfer function or otherwise be "HDR" // the device may need to avoid boosting the brightness as a result of these layers to // reduce power consumption during camera recording - if (mIgnoreHdrCameraLayers) { + if (mConfig->ignoreHdrCameraLayers) { if (snapshot.externalTexture && (snapshot.externalTexture->getUsage() & GRALLOC_USAGE_HW_CAMERA_WRITE) != 0) { return false; @@ -2724,7 +2604,7 @@ ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(DisplayId displayId, if (!id) { return ui::ROTATION_0; } - if (!mIgnoreHwcPhysicalDisplayOrientation && + if (!mConfig->ignoreHwcPhysicalDisplayOrientation && getHwComposer().getComposer()->isSupported( Hwc2::Composer::OptionalFeature::PhysicalDisplayOrientation)) { switch (getHwComposer().getPhysicalDisplayOrientation(*id)) { @@ -2919,7 +2799,7 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa const bool isDisplayConnected = defaultDisplay && getHwComposer().isConnected(defaultDisplay->getPhysicalId()); - if (!hasSyncFramework) { + if (!mConfig->hasSyncFramework) { if (isDisplayConnected && defaultDisplay->isPoweredOn()) { mScheduler->enableHardwareVsync(defaultDisplay->getPhysicalId()); } @@ -2960,7 +2840,7 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa if (!layer->hasTrustedPresentationListener()) { return; } - const frontend::LayerSnapshot* snapshot = mLayerLifecycleManagerEnabled + const frontend::LayerSnapshot* snapshot = mConfig->layerLifecycleManagerEnabled ? mLayerSnapshotBuilder.getSnapshot(layer->sequence) : layer->getLayerSnapshot(); std::optional displayOpt = std::nullopt; @@ -3355,7 +3235,7 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, builder.setPowerAdvisor(mPowerAdvisor.get()); builder.setName(state.displayName); auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); - compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled); + compositionDisplay->setLayerCachingEnabled(mConfig->layerCachingEnabled); sp displaySurface; sp producer; @@ -3367,7 +3247,8 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, const auto displayId = VirtualDisplayId::tryCast(compositionDisplay->getId()); LOG_FATAL_IF(!displayId); auto surface = sp::make(getHwComposer(), *displayId, state.surface, - bqProducer, bqConsumer, state.displayName); + bqProducer, bqConsumer, state.displayName, + mConfig->useHwcForRgbToYuv); displaySurface = surface; producer = std::move(surface); } else { @@ -3377,10 +3258,11 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, state.surface.get()); const auto displayId = PhysicalDisplayId::tryCast(compositionDisplay->getId()); LOG_FATAL_IF(!displayId); - displaySurface = - sp::make(getHwComposer(), *displayId, bqConsumer, - state.physical->activeMode->getResolution(), - ui::Size(maxGraphicsWidth, maxGraphicsHeight)); + displaySurface = sp::make(getHwComposer(), *displayId, bqConsumer, + state.physical->activeMode->getResolution(), + ui::Size(mConfig->maxGraphicsWidth, + mConfig->maxGraphicsHeight), + mConfig->maxFrameBufferAcquiredBuffers); producer = bqProducer; } @@ -3561,7 +3443,7 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { // Commit display transactions. const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded; mFrontEndDisplayInfosChanged = displayTransactionNeeded; - if (displayTransactionNeeded && !mLayerLifecycleManagerEnabled) { + if (displayTransactionNeeded && !mConfig->layerLifecycleManagerEnabled) { processDisplayChangesLocked(); mFrontEndDisplayInfos.clear(); for (const auto& [_, display] : mDisplays) { @@ -3761,7 +3643,7 @@ void SurfaceFlinger::buildWindowInfos(std::vector& outWindowInfos, outWindowInfos.reserve(sNumWindowInfos); sNumWindowInfos = 0; - if (mLayerLifecycleManagerEnabled) { + if (mConfig->layerLifecycleManagerEnabled) { mLayerSnapshotBuilder.forEachInputSnapshot( [&outWindowInfos](const frontend::LayerSnapshot& snapshot) { outWindowInfos.push_back(snapshot.inputInfo); @@ -3881,7 +3763,7 @@ void SurfaceFlinger::initScheduler(const sp& display) { if (display->refreshRateSelector().kernelIdleTimerController()) { features |= Feature::kKernelIdleTimer; } - if (mBackpressureGpuComposition) { + if (mConfig->backpressureGpuComposition) { features |= Feature::kBackpressureGpuComposition; } @@ -4554,7 +4436,7 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin const std::vector& listenerCallbacks, int originPid, int originUid, uint64_t transactionId) { uint32_t transactionFlags = 0; - if (!mLayerLifecycleManagerEnabled) { + if (!mConfig->layerLifecycleManagerEnabled) { for (DisplayState& display : displays) { transactionFlags |= setDisplayStateLocked(display); } @@ -4569,12 +4451,12 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin uint32_t clientStateFlags = 0; for (auto& resolvedState : states) { - if (mLegacyFrontEndEnabled) { + if (mConfig->legacyFrontEndEnabled) { clientStateFlags |= setClientStateLocked(frameTimelineInfo, resolvedState, desiredPresentTime, isAutoTimestamp, postTime, transactionId); - } else /*mLayerLifecycleManagerEnabled*/ { + } else /* mConfig->layerLifecycleManagerEnabled */ { clientStateFlags |= updateLayerCallbacksAndStats(frameTimelineInfo, resolvedState, desiredPresentTime, isAutoTimestamp, postTime, transactionId); @@ -4648,7 +4530,7 @@ bool SurfaceFlinger::applyAndCommitDisplayTransactionStates( } mFrontEndDisplayInfosChanged = mTransactionFlags & eDisplayTransactionNeeded; - if (mFrontEndDisplayInfosChanged && !mLegacyFrontEndEnabled) { + if (mFrontEndDisplayInfosChanged && !mConfig->legacyFrontEndEnabled) { processDisplayChangesLocked(); mFrontEndDisplayInfos.clear(); for (const auto& [_, display] : mDisplays) { @@ -4851,7 +4733,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (layer->setCornerRadius(s.cornerRadius)) flags |= eTraversalNeeded; } - if (what & layer_state_t::eBackgroundBlurRadiusChanged && mSupportsBlur) { + if (what & layer_state_t::eBackgroundBlurRadiusChanged && mConfig->supportsBlur) { if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded; } if (what & layer_state_t::eBlurRegionsChanged) { @@ -5255,7 +5137,7 @@ status_t SurfaceFlinger::mirrorDisplay(DisplayId displayId, const LayerCreationA return result; } - if (mLegacyFrontEndEnabled) { + if (mConfig->legacyFrontEndEnabled) { std::scoped_lock lock(mMirrorDisplayLock); mMirrorDisplays.emplace_back(layerStack, outResult.handle, args.client); } @@ -5362,9 +5244,10 @@ void SurfaceFlinger::initializeDisplays() { const nsecs_t now = systemTime(); state.desiredPresentTime = now; state.postTime = now; - state.originPid = mPid; + state.originPid = mConfig->pid; state.originUid = static_cast(getuid()); - const uint64_t transactionId = (static_cast(mPid) << 32) | mUniqueTransactionId++; + const uint64_t transactionId = + (static_cast(mConfig->pid) << 32) | mUniqueTransactionId++; state.id = transactionId; // reset screen orientation and use primary layer stack @@ -5384,7 +5267,7 @@ void SurfaceFlinger::initializeDisplays() { std::vector transactions; transactions.emplace_back(state); - if (mLegacyFrontEndEnabled) { + if (mConfig->legacyFrontEndEnabled) { applyTransactions(transactions, VsyncId{0}); } else { applyAndCommitDisplayTransactionStates(transactions); @@ -5680,13 +5563,13 @@ void SurfaceFlinger::logFrameStats(TimePoint now) { void SurfaceFlinger::appendSfConfigString(std::string& result) const { result.append(" [sf"); - StringAppendF(&result, " PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset); - StringAppendF(&result, " FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv); + StringAppendF(&result, " PRESENT_TIME_OFFSET=%" PRId64, mConfig->dispSyncPresentTimeOffset); + StringAppendF(&result, " FORCE_HWC_FOR_RBG_TO_YUV=%d", mConfig->useHwcForRgbToYuv); StringAppendF(&result, " MAX_VIRT_DISPLAY_DIM=%zu", getHwComposer().getMaxVirtualDisplayDimension()); - StringAppendF(&result, " RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework); + StringAppendF(&result, " RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !mConfig->hasSyncFramework); StringAppendF(&result, " NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64, - maxFrameBufferAcquiredBuffers); + mConfig->maxFrameBufferAcquiredBuffers); result.append("]"); } @@ -5706,7 +5589,7 @@ void SurfaceFlinger::dumpScheduler(std::string& result) const { StringAppendF(&result, " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n", - dispSyncPresentTimeOffset, getVsyncPeriodFromHWC()); + mConfig->dispSyncPresentTimeOffset, getVsyncPeriodFromHWC()); } void SurfaceFlinger::dumpEvents(std::string& result) const { @@ -5805,7 +5688,7 @@ void SurfaceFlinger::dumpRawDisplayIdentificationData(const DumpArgs& args, } void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { - StringAppendF(&result, "Device supports wide color: %d\n", mSupportsWideColor); + StringAppendF(&result, "Device supports wide color: %d\n", mConfig->supportsWideColor); StringAppendF(&result, "Device uses color management: %d\n", useColorManagement); StringAppendF(&result, "DisplayColorSetting: %s\n", decodeDisplayColorSetting(mDisplayColorSetting).c_str()); @@ -5839,7 +5722,7 @@ LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { } } - if (mLegacyFrontEndEnabled) { + if (mConfig->legacyFrontEndEnabled) { LayersProto layersProto; for (const sp& layer : mDrawingState.layersSortedByZ) { if (stackIdsToSkip.find(layer->getLayerStack().id) != stackIdsToSkip.end()) { @@ -6496,7 +6379,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r if (!validateCompositionDataspace(dataspace)) { return BAD_VALUE; } - mDefaultCompositionDataspace = dataspace; + mOverrideDefaultCompositionDataspace = dataspace; } n = data.readInt32(); if (n) { @@ -6504,12 +6387,12 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r if (!validateCompositionDataspace(dataspace)) { return BAD_VALUE; } - mWideColorGamutCompositionDataspace = dataspace; + mOverrideWideColorGamutCompositionDataspace = dataspace; } } else { - // restore composition data space. - mDefaultCompositionDataspace = defaultCompositionDataspace; - mWideColorGamutCompositionDataspace = wideColorGamutCompositionDataspace; + // Reset data space overrides. + mOverrideDefaultCompositionDataspace.reset(); + mOverrideWideColorGamutCompositionDataspace.reset(); } return NO_ERROR; } @@ -6648,10 +6531,10 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } { Mutex::Autolock lock(mStateLock); - mLayerCachingEnabled = n != 0; + mConfig->layerCachingEnabled = n != 0; for (const auto& [_, display] : mDisplays) { if (!inputId || *inputId == display->getPhysicalId()) { - display->enableLayerCaching(mLayerCachingEnabled); + display->enableLayerCaching(mConfig->layerCachingEnabled); } } } @@ -6976,7 +6859,7 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, }); GetLayerSnapshotsFunction getLayerSnapshots; - if (mLayerLifecycleManagerEnabled) { + if (mConfig->layerLifecycleManagerEnabled) { getLayerSnapshots = getLayerSnapshotsForScreenshots(layerStack, args.uid, std::move(excludeLayerIds)); } else { @@ -7019,7 +6902,7 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId, }); GetLayerSnapshotsFunction getLayerSnapshots; - if (mLayerLifecycleManagerEnabled) { + if (mConfig->layerLifecycleManagerEnabled) { getLayerSnapshots = getLayerSnapshotsForScreenshots(layerStack, CaptureArgs::UNSET_UID, /*snapshotFilterFn=*/nullptr); } else { @@ -7115,7 +6998,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, RenderAreaFuture renderAreaFuture = ftl::defer([=]() -> std::unique_ptr { ui::Transform layerTransform; Rect layerBufferSize; - if (mLayerLifecycleManagerEnabled) { + if (mConfig->layerLifecycleManagerEnabled) { frontend::LayerSnapshot* snapshot = mLayerSnapshotBuilder.getSnapshot(parent->getSequence()); if (!snapshot) { @@ -7135,7 +7018,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, args.hintForSeamlessTransition); }); GetLayerSnapshotsFunction getLayerSnapshots; - if (mLayerLifecycleManagerEnabled) { + if (mConfig->layerLifecycleManagerEnabled) { std::optional parentCrop = std::nullopt; if (args.childrenOnly) { parentCrop = crop.isEmpty() ? FloatRect(0, 0, reqSize.width, reqSize.height) @@ -7388,7 +7271,7 @@ ftl::SharedFuture SurfaceFlinger::renderScreenImpl( layerStack, regionSampling, renderArea = std::move(renderArea), renderIntent]() -> FenceResult { std::unique_ptr compositionEngine = - mFactory.createCompositionEngine(); + mConfig->factory->createCompositionEngine(); compositionEngine->setRenderEngine(mRenderEngine.get()); compositionengine::Output::ColorProfile colorProfile{.dataspace = dataspace, @@ -7458,7 +7341,7 @@ ftl::SharedFuture SurfaceFlinger::renderScreenImpl( } void SurfaceFlinger::traverseLegacyLayers(const LayerVector::Visitor& visitor) const { - if (mLayerLifecycleManagerEnabled) { + if (mConfig->layerLifecycleManagerEnabled) { for (auto& layer : mLegacyLayers) { visitor(layer.second.get()); } @@ -7780,9 +7663,7 @@ void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { } if (const auto device = getDisplayDeviceLocked(id)) { - device->enableRefreshRateOverlay(enable, setByHwc, mRefreshRateOverlaySpinner, - mRefreshRateOverlayRenderRate, - mRefreshRateOverlayShowInMiddle); + device->enableRefreshRateOverlay(enable, setByHwc); } } } @@ -7793,12 +7674,12 @@ int SurfaceFlinger::getGpuContextPriority() { } int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate, - std::chrono::nanoseconds presentLatency) { + std::chrono::nanoseconds presentLatency) const { auto pipelineDepth = presentLatency.count() / refreshRate.getPeriodNsecs(); if (presentLatency.count() % refreshRate.getPeriodNsecs()) { pipelineDepth++; } - return std::max(minAcquiredBuffers, static_cast(pipelineDepth - 1)); + return std::max(mConfig->minAcquiredBuffers, static_cast(pipelineDepth - 1)); } status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const { @@ -7880,7 +7761,7 @@ void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state, Vs } void SurfaceFlinger::sample() { - if (!mLumaSampling || !mRegionSamplingThread) { + if (!mConfig->lumaSampling || !mRegionSamplingThread) { return; } @@ -8072,7 +7953,7 @@ void SurfaceFlinger::updateLayerMetadataSnapshot() { void SurfaceFlinger::moveSnapshotsFromCompositionArgs( compositionengine::CompositionRefreshArgs& refreshArgs, const std::vector>& layers) { - if (mLayerLifecycleManagerEnabled) { + if (mConfig->layerLifecycleManagerEnabled) { std::vector>& snapshots = mLayerSnapshotBuilder.getSnapshots(); for (auto [_, layerFE] : layers) { @@ -8080,7 +7961,7 @@ void SurfaceFlinger::moveSnapshotsFromCompositionArgs( snapshots[i] = std::move(layerFE->mSnapshot); } } - if (mLegacyFrontEndEnabled && !mLayerLifecycleManagerEnabled) { + if (mConfig->legacyFrontEndEnabled && !mConfig->layerLifecycleManagerEnabled) { for (auto [layer, layerFE] : layers) { layer->updateLayerSnapshot(std::move(layerFE->mSnapshot)); } @@ -8090,7 +7971,7 @@ void SurfaceFlinger::moveSnapshotsFromCompositionArgs( std::vector> SurfaceFlinger::moveSnapshotsToCompositionArgs( compositionengine::CompositionRefreshArgs& refreshArgs, bool cursorOnly) { std::vector> layers; - if (mLayerLifecycleManagerEnabled) { + if (mConfig->layerLifecycleManagerEnabled) { nsecs_t currentTime = systemTime(); mLayerSnapshotBuilder.forEachVisibleSnapshot( [&](std::unique_ptr& snapshot) { @@ -8116,7 +7997,7 @@ std::vector> SurfaceFlinger::moveSnapshotsToComposit layers.emplace_back(legacyLayer.get(), layerFE.get()); }); } - if (mLegacyFrontEndEnabled && !mLayerLifecycleManagerEnabled) { + if (mConfig->legacyFrontEndEnabled && !mConfig->layerLifecycleManagerEnabled) { auto moveSnapshots = [&layers, &refreshArgs, cursorOnly](Layer* layer) { if (const auto& layerFE = layer->getCompositionEngineLayerFE()) { if (cursorOnly && @@ -8208,7 +8089,7 @@ SurfaceFlinger::getLayerSnapshotsForScreenshots(std::optional la .displays = mFrontEndDisplayInfos, .displayChanges = true, .globalShadowSettings = mDrawingState.globalShadowSettings, - .supportsBlur = mSupportsBlur, + .supportsBlur = mConfig->supportsBlur, .forceFullDamage = mForceFullDamage, .excludeLayerIds = std::move(excludeLayerIds), .supportedLayerGenericMetadata = @@ -8242,7 +8123,7 @@ SurfaceFlinger::getLayerSnapshotsForScreenshots(uint32_t rootLayerId, uint32_t u .displays = mFrontEndDisplayInfos, .displayChanges = true, .globalShadowSettings = mDrawingState.globalShadowSettings, - .supportsBlur = mSupportsBlur, + .supportsBlur = mConfig->supportsBlur, .forceFullDamage = mForceFullDamage, .parentCrop = parentCrop, .excludeLayerIds = std::move(excludeLayerIds), diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index fd050167f7..31df2dfa43 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -63,6 +63,7 @@ #include #include +#include "Client.h" #include "Display/PhysicalDisplay.h" #include "DisplayDevice.h" #include "DisplayHardware/HWC2.h" @@ -81,6 +82,7 @@ #include "Scheduler/RefreshRateSelector.h" #include "Scheduler/RefreshRateStats.h" #include "Scheduler/Scheduler.h" +#include "SurfaceFlingerConfig.h" #include "SurfaceFlingerFactory.h" #include "ThreadContext.h" #include "Tracing/LayerTracing.h" @@ -107,7 +109,6 @@ #include #include -#include "Client.h" using namespace android::surfaceflinger; @@ -196,10 +197,7 @@ class SurfaceFlinger : public BnSurfaceComposer, private ICompositor, private scheduler::ISchedulerCallback { public: - struct SkipInitializationTag {}; - - SurfaceFlinger(surfaceflinger::Factory&, SkipInitializationTag) ANDROID_API; - explicit SurfaceFlinger(surfaceflinger::Factory&) ANDROID_API; + explicit SurfaceFlinger(surfaceflinger::Config&) ANDROID_API; // set main thread scheduling policy static status_t setSchedFifo(bool enabled) ANDROID_API; @@ -209,51 +207,9 @@ public: static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; } - // If fences from sync Framework are supported. - static bool hasSyncFramework; - - // The offset in nanoseconds to use when VsyncController timestamps present fence - // signaling time. - static int64_t dispSyncPresentTimeOffset; - - // Some hardware can do RGB->YUV conversion more efficiently in hardware - // controlled by HWC than in hardware controlled by the video encoder. - // This instruct VirtualDisplaySurface to use HWC for such conversion on - // GL composition. - static bool useHwcForRgbToYuv; - - // Controls the number of buffers SurfaceFlinger will allocate for use in - // FramebufferSurface - static int64_t maxFrameBufferAcquiredBuffers; - - // Controls the minimum acquired buffers SurfaceFlinger will suggest via - // ISurfaceComposer.getMaxAcquiredBufferCount(). - static int64_t minAcquiredBuffers; - - // 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; - static uint32_t maxGraphicsHeight; - // Indicate if device wants color management on its display. static const constexpr bool useColorManagement = true; - static bool useContextPriority; - - // The data space and pixel format that SurfaceFlinger expects hardware composer - // to composite efficiently. Meaning under most scenarios, hardware composer - // will accept layers with the data space and pixel format. - static ui::Dataspace defaultCompositionDataspace; - static ui::PixelFormat defaultCompositionPixelFormat; - - // The data space and pixel format that SurfaceFlinger expects hardware composer - // to composite efficiently for wide color gamut surfaces. Meaning under most scenarios, - // hardware composer will accept layers with the data space and pixel format. - static ui::Dataspace wideColorGamutCompositionDataspace; - static ui::PixelFormat wideColorGamutCompositionPixelFormat; - - static constexpr SkipInitializationTag SkipInitialization; - static LatchUnsignaledConfig enableLatchUnsignaledConfig; // must be called before clients can connect @@ -274,7 +230,8 @@ public: // Schedule sampling independently from commit or composite. void scheduleSample(); - surfaceflinger::Factory& getFactory() { return mFactory; } + const surfaceflinger::Config& getConfig() { return *mConfig; } + surfaceflinger::Factory& getFactory() { return *mConfig->factory; } // The CompositionEngine encapsulates all composition related interfaces and actions. compositionengine::CompositionEngine& getCompositionEngine() const; @@ -306,10 +263,6 @@ public: return mTransactionCallbackInvoker; } - // If set, disables reusing client composition buffers. This can be set by - // debug.sf.disable_client_composition_cache - bool mDisableClientCompositionCache = false; - // Disables expensive rendering for all displays // This is scheduled on the main thread void disableExpensiveRendering(); @@ -320,17 +273,6 @@ public: // run parallel to the hwc validateDisplay call and re-run if the predition is incorrect. bool mPredictCompositionStrategy = false; - // If true, then any layer with a SMPTE 170M transfer function is decoded using the sRGB - // transfer instead. This is mainly to preserve legacy behavior, where implementations treated - // SMPTE 170M as sRGB prior to color management being implemented, and now implementations rely - // on this behavior to increase contrast for some media sources. - bool mTreat170mAsSrgb = false; - - // Allows to ignore physical orientation provided through hwc API in favour of - // 'ro.surface_flinger.primary_display_orientation'. - // TODO(b/246793311): Clean up a temporary property - bool mIgnoreHwcPhysicalDisplayOrientation = false; - void forceFutureUpdate(int delayInMs); const DisplayDevice* getDisplayFromLayerStack(ui::LayerStack) REQUIRES(mStateLock, kMainThreadContext); @@ -662,12 +604,6 @@ private: // Keeps track of whether the kernel idle timer is currently enabled, so we don't have to // make calls to sys prop each time. bool mKernelIdleTimerEnabled = false; - // Show spinner with refresh rate overlay - bool mRefreshRateOverlaySpinner = false; - // Show render rate with refresh rate overlay - bool mRefreshRateOverlayRenderRate = false; - // Show render rate overlay offseted to the middle of the screen (e.g. for circular displays) - bool mRefreshRateOverlayShowInMiddle = false; void setDesiredActiveMode(display::DisplayModeRequest&&, bool force = false) REQUIRES(mStateLock); @@ -1101,8 +1037,8 @@ private: */ const std::unordered_map& getGenericLayerMetadataKeyMap() const; - static int calculateMaxAcquiredBufferCount(Fps refreshRate, - std::chrono::nanoseconds presentLatency); + int calculateMaxAcquiredBufferCount(Fps refreshRate, + std::chrono::nanoseconds presentLatency) const; int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const; bool isHdrLayer(const frontend::LayerSnapshot& snapshot) const; @@ -1112,8 +1048,7 @@ private: void traverseLegacyLayers(const LayerVector::Visitor& visitor) const; sp mStartPropertySetThread; - surfaceflinger::Factory& mFactory; - pid_t mPid; + surfaceflinger::Config* const mConfig = nullptr; std::future mRenderEnginePrimeCacheFuture; // mStateLock has conventions related to the current thread, because only @@ -1140,12 +1075,6 @@ private: float mGlobalSaturationFactor = 1.0f; mat4 mClientColorMatrix; - size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS; - // If there are more GraphicBufferProducers tracked by SurfaceFlinger than - // this threshold, then begin logging. - size_t mGraphicBufferProducerListSizeLogThreshold = - static_cast(0.95 * static_cast(MAX_LAYERS)); - // protected by mStateLock (but we could use another lock) bool mLayersRemoved = false; bool mLayersAdded = false; @@ -1155,7 +1084,6 @@ private: // constant members (no synchronization needed for access) const nsecs_t mBootTime = systemTime(); - bool mIsUserBuild = true; // Can only accessed from the main thread, these members // don't need synchronization @@ -1167,7 +1095,6 @@ private: // Used to ensure we omit a callback when HDR layer info listener is newly added but the // scene hasn't changed bool mAddingHDRLayerInfoListener = false; - bool mIgnoreHdrCameraLayers = false; // Set during transaction application stage to track if the input info or children // for a layer has changed. @@ -1226,9 +1153,6 @@ private: std::atomic mDebugInTransaction = 0; std::atomic_bool mForceFullDamage = false; - bool mLayerCachingEnabled = false; - bool mBackpressureGpuComposition = false; - LayerTracing mLayerTracing; bool mLayerTracingEnabled = false; @@ -1241,9 +1165,6 @@ private: VsyncId mLastCommittedVsyncId; - // If blurs should be enabled on this device. - bool mSupportsBlur = false; - TransactionCallbackInvoker mTransactionCallbackInvoker; // We maintain a pool of pre-generated texture names to hand out to avoid @@ -1275,13 +1196,9 @@ private: // This property can be used to force SurfaceFlinger to always pick a certain color mode. ui::ColorMode mForceColorMode = ui::ColorMode::NATIVE; - // Whether to enable wide color gamut (e.g. Display P3) for internal displays that support it. - // If false, wide color modes are filtered out for all internal displays. - bool mSupportsWideColor = false; + std::optional mOverrideDefaultCompositionDataspace; + std::optional mOverrideWideColorGamutCompositionDataspace; - ui::Dataspace mDefaultCompositionDataspace; - ui::Dataspace mWideColorGamutCompositionDataspace; - ui::Dataspace mColorSpaceAgnosticDataspace; float mDimmingRatio = -1.f; std::unique_ptr mRenderEngine; @@ -1295,8 +1212,6 @@ private: // any mutex. size_t mMaxRenderTargetSize{1}; - const std::string mHwcServiceName; - /* * Scheduler */ @@ -1313,14 +1228,9 @@ private: // below flags are set by main thread only bool mSetActiveModePending = false; - bool mLumaSampling = true; sp mRegionSamplingThread; sp mFpsReporter; sp mTunnelModeEnabledReporter; - ui::DisplayPrimaries mInternalDisplayPrimaries; - - const float mEmulatedDisplayDensity; - const float mInternalDisplayDensity; // Should only be accessed by the main thread. sp mInputFlinger; @@ -1397,9 +1307,6 @@ private: bool mPowerHintSessionEnabled; - bool mLayerLifecycleManagerEnabled = false; - bool mLegacyFrontEndEnabled = true; - frontend::LayerLifecycleManager mLayerLifecycleManager; frontend::LayerHierarchyBuilder mLayerHierarchyBuilder{{}}; frontend::LayerSnapshotBuilder mLayerSnapshotBuilder; diff --git a/services/surfaceflinger/SurfaceFlingerConfig.cpp b/services/surfaceflinger/SurfaceFlingerConfig.cpp new file mode 100644 index 0000000000..0b25a4462d --- /dev/null +++ b/services/surfaceflinger/SurfaceFlingerConfig.cpp @@ -0,0 +1,162 @@ +/* + * Copyright 2023 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 + +#include +#include +#include +#include + +#include "SurfaceFlingerConfig.h" + +namespace android::surfaceflinger { + +using namespace std::string_literals; + +namespace { + +// TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity. +constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV; + +float getDensityFromProperty(const std::string& key, bool required) { + std::string value = base::GetProperty(key, ""s); + const float density = static_cast(std::atof(value.c_str())); + if (density == 0.f && required) { + ALOGE("%s must be defined as a build property", key.c_str()); + return FALLBACK_DENSITY; + } + return density; +} + +} // namespace + +Config::Config() = default; + +Config Config::makeDefault(Factory* factory) { + Config cfg{}; + + // Note: The values set here will affect tests. + // To keep tests hermetic, do not set values here based on runtime values. + + cfg.factory = factory; + cfg.hwcServiceName = "default"s; + cfg.pid = getpid(); // Exception to the hermetic rules. Allow the pid to be cached. + + return cfg; +} + +Config Config::makeProduction(Factory* factory) { + Config cfg = makeDefault(factory); + + cfg.hwcServiceName = base::GetProperty("debug.sf.hwc_service_name"s, "default"s); + + cfg.emulatedDisplayDensity = getDensityFromProperty("qemu.sf.lcd_density"s, false), + cfg.internalDisplayDensity = + getDensityFromProperty("ro.sf.lcd_density"s, cfg.emulatedDisplayDensity == 0.f), + + cfg.hasSyncFramework = sysprop::running_without_sync_framework(cfg.hasSyncFramework); + cfg.dispSyncPresentTimeOffset = + sysprop::present_time_offset_from_vsync_ns(cfg.dispSyncPresentTimeOffset); + cfg.useHwcForRgbToYuv = sysprop::force_hwc_copy_for_virtual_displays(cfg.useHwcForRgbToYuv); + cfg.maxFrameBufferAcquiredBuffers = + sysprop::max_frame_buffer_acquired_buffers(cfg.maxFrameBufferAcquiredBuffers); + cfg.minAcquiredBuffers = sysprop::SurfaceFlingerProperties::min_acquired_buffers().value_or( + cfg.minAcquiredBuffers); + + cfg.maxGraphicsWidth = std::max(static_cast(sysprop::max_graphics_width( + static_cast(cfg.maxGraphicsWidth))), + 0u); + cfg.maxGraphicsHeight = std::max(static_cast(sysprop::max_graphics_height( + static_cast(cfg.maxGraphicsHeight))), + 0u); + + cfg.supportsWideColor = sysprop::has_wide_color_display(cfg.supportsWideColor); + + cfg.defaultCompositionDataspace = static_cast( + sysprop::default_composition_dataspace(cfg.defaultCompositionDataspace)); + cfg.defaultCompositionPixelFormat = static_cast( + sysprop::default_composition_pixel_format(cfg.defaultCompositionPixelFormat)); + + cfg.wideColorGamutCompositionDataspace = + static_cast(sysprop::wcg_composition_dataspace( + cfg.supportsWideColor ? ui::Dataspace::DISPLAY_P3 : ui::Dataspace::V0_SRGB)); + cfg.wideColorGamutCompositionPixelFormat = static_cast( + sysprop::wcg_composition_pixel_format(cfg.wideColorGamutCompositionPixelFormat)); + + cfg.colorSpaceAgnosticDataspace = static_cast( + sysprop::color_space_agnostic_dataspace(cfg.colorSpaceAgnosticDataspace)); + + cfg.internalDisplayPrimaries = sysprop::getDisplayNativePrimaries(); + + cfg.layerCachingEnabled = + base::GetBoolProperty("debug.sf.enable_layer_caching"s, + android::sysprop::SurfaceFlingerProperties::enable_layer_caching() + .value_or(cfg.layerCachingEnabled)); + cfg.useContextPriority = sysprop::use_context_priority(cfg.useContextPriority); + + cfg.isUserBuild = "user"s == base::GetProperty("ro.build.type"s, "user"s); + + cfg.backpressureGpuComposition = base::GetBoolProperty("debug.sf.enable_gl_backpressure"s, + cfg.backpressureGpuComposition); + cfg.supportsBlur = + base::GetBoolProperty("ro.surface_flinger.supports_background_blur"s, cfg.supportsBlur); + + cfg.lumaSampling = base::GetBoolProperty("debug.sf.luma_sampling"s, cfg.lumaSampling); + + cfg.disableClientCompositionCache = + base::GetBoolProperty("debug.sf.disable_client_composition_cache"s, + cfg.disableClientCompositionCache); + + cfg.predictCompositionStrategy = + base::GetBoolProperty("debug.sf.predict_hwc_composition_strategy"s, + cfg.predictCompositionStrategy); + + cfg.treat170mAsSrgb = + base::GetBoolProperty("debug.sf.treat_170m_as_sRGB"s, cfg.treat170mAsSrgb); + + cfg.ignoreHwcPhysicalDisplayOrientation = + base::GetBoolProperty("debug.sf.ignore_hwc_physical_display_orientation"s, + cfg.ignoreHwcPhysicalDisplayOrientation); + + cfg.trebleTestingOverride = + base::GetBoolProperty("debug.sf.treble_testing_override"s, cfg.trebleTestingOverride); + + // TODO (b/270966065) Update the HWC based refresh rate overlay to support spinner + cfg.refreshRateOverlay.showSpinner = + base::GetBoolProperty("debug.sf.show_refresh_rate_overlay_spinner"s, + cfg.refreshRateOverlay.showSpinner); + cfg.refreshRateOverlay.showRenderRate = + base::GetBoolProperty("debug.sf.show_refresh_rate_overlay_render_rate"s, + cfg.refreshRateOverlay.showRenderRate); + cfg.refreshRateOverlay.showInMiddle = + base::GetBoolProperty("debug.sf.show_refresh_rate_overlay_in_middle"s, + cfg.refreshRateOverlay.showInMiddle); + + cfg.ignoreHdrCameraLayers = sysprop::ignore_hdr_camera_layers(cfg.ignoreHdrCameraLayers); + + cfg.enableTransactionTracing = base::GetBoolProperty("debug.sf.enable_transaction_tracing"s, + cfg.enableTransactionTracing); + cfg.layerLifecycleManagerEnabled = + base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, + cfg.layerLifecycleManagerEnabled); + cfg.legacyFrontEndEnabled = !cfg.layerLifecycleManagerEnabled || + base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); + + return cfg; +} + +} // namespace android::surfaceflinger \ No newline at end of file diff --git a/services/surfaceflinger/SurfaceFlingerConfig.h b/services/surfaceflinger/SurfaceFlingerConfig.h new file mode 100644 index 0000000000..7c3348e3bd --- /dev/null +++ b/services/surfaceflinger/SurfaceFlingerConfig.h @@ -0,0 +1,145 @@ +/* + * Copyright 2023 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 + +#include +#include + +namespace android::surfaceflinger { + +class Factory; + +struct Config final { + Factory* factory = nullptr; + + std::string hwcServiceName; + pid_t pid; + + float emulatedDisplayDensity = 0; + float internalDisplayDensity = 0; + + // If fences from sync Framework are supported. + bool hasSyncFramework = true; + + // The offset in nanoseconds to use when VsyncController timestamps present + // fence signaling time. + int64_t dispSyncPresentTimeOffset = 0; + + // Some hardware can do RGB->YUV conversion more efficiently in hardware + // controlled by HWC than in hardware controlled by the video encoder. This + // instruct VirtualDisplaySurface to use HWC for such conversion on GL + // composition. + bool useHwcForRgbToYuv = false; + + // Controls the number of buffers SurfaceFlinger will allocate for use in + // FramebufferSurface + int64_t maxFrameBufferAcquiredBuffers = 2; + + // Controls the minimum acquired buffers SurfaceFlinger will suggest via + // ISurfaceComposer.getMaxAcquiredBufferCount(). + int64_t minAcquiredBuffers = 1; + + // 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. + uint32_t maxGraphicsWidth = 0; + uint32_t maxGraphicsHeight = 0; + + // Whether to enable wide color gamut (e.g. Display P3) for internal + // displays that support it. If false, wide color modes are filtered out + // for all internal displays. + bool mSupportsWideColor = false; + bool supportsWideColor = false; + + // The data space and pixel format that SurfaceFlinger expects hardware + // composer to composite efficiently. Meaning under most scenarios, + // hardware composer will accept layers with the data space and pixel + // format. + ui::Dataspace defaultCompositionDataspace = ui::Dataspace::V0_SRGB; + ui::PixelFormat defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888; + + // The data space and pixel format that SurfaceFlinger expects hardware + // composer to composite efficiently for wide color gamut surfaces. Meaning + // under most scenarios, hardware composer will accept layers with the data + // space and pixel format. + ui::Dataspace wideColorGamutCompositionDataspace = ui::Dataspace::V0_SRGB; + ui::PixelFormat wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; + + ui::Dataspace colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; + + ui::DisplayPrimaries internalDisplayPrimaries{}; + + bool layerCachingEnabled = false; + bool useContextPriority = true; + bool isUserBuild = true; + bool backpressureGpuComposition = true; + + // If blurs should be enabled on this device. + bool supportsBlur = false; + bool lumaSampling = true; + + // If set, disables reusing client composition buffers. This can be set by + // debug.sf.disable_client_composition_cache + bool disableClientCompositionCache = false; + + // If set, composition engine tries to predict the composition strategy + // provided by HWC based on the previous frame. If the strategy can be + // predicted, gpu composition will run parallel to the hwc validateDisplay + // call and re-run if the predition is incorrect. + bool predictCompositionStrategy = true; + + // If true, then any layer with a SMPTE 170M transfer function is decoded + // using the sRGB transfer instead. This is mainly to preserve legacy + // behavior, where implementations treated SMPTE 170M as sRGB prior to + // color management being implemented, and now implementations rely on this + // behavior to increase contrast for some media sources. + bool treat170mAsSrgb = false; + + // Allows to ignore physical orientation provided through hwc API in favour + // of 'ro.surface_flinger.primary_display_orientation'. + // TODO(b/246793311): Clean up a temporary property + bool ignoreHwcPhysicalDisplayOrientation = false; + + bool trebleTestingOverride = false; + + struct { + // Show spinner with refresh rate overlay + bool showSpinner = false; + + // Show render rate with refresh rate overlay + bool showRenderRate = false; + + // Show render rate overlay offseted to the middle of the screen (e.g. + // for circular displays) + bool showInMiddle = false; + } refreshRateOverlay; + + bool ignoreHdrCameraLayers = false; + bool enableTransactionTracing = true; + bool layerLifecycleManagerEnabled = false; + bool legacyFrontEndEnabled = true; + + static Config makeDefault(Factory* factory); + static Config makeProduction(Factory* factory); + +private: + Config(); +}; + +} // namespace android::surfaceflinger diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp index 7bd6cf69f3..ac351cb1d7 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp @@ -14,22 +14,17 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - #include "SurfaceFlinger.h" +#include "SurfaceFlingerConfig.h" #include "SurfaceFlingerDefaultFactory.h" namespace android::surfaceflinger { sp createSurfaceFlinger() { static DefaultFactory factory; + static Config config = Config::makeProduction(&factory); - return sp::make(factory); + return sp::make(config); } } // namespace android::surfaceflinger - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp index 9fac14ed4c..d296c47237 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp @@ -481,7 +481,8 @@ void DisplayHardwareFuzzer::invokeFrameBufferSurface() { sp surface = sp::make(mHwc, mPhysicalDisplayId, bqConsumer, - getFuzzedSize() /*size*/, getFuzzedSize() /*maxSize*/); + getFuzzedSize() /*size*/, getFuzzedSize() /*maxSize*/, + mFdp.PickValueInArray(kMaxFrameBufferAcquiredBuffers)); surface->beginFrame(mFdp.ConsumeBool()); surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes)); @@ -515,7 +516,8 @@ void DisplayHardwareFuzzer::invokeVirtualDisplaySurface() { auto surface = sp::make(mHwc, VirtualDisplayId, sink, bqProducer, bqConsumer, - mFdp.ConsumeRandomLengthString().c_str() /*name*/); + mFdp.ConsumeRandomLengthString().c_str() /*name*/, + mFdp.ConsumeBool() /* useHwcForRgbToYuv */); surface->beginFrame(mFdp.ConsumeBool()); surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes)); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp index 80943b5b63..df342dcd8e 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp @@ -124,19 +124,20 @@ void SurfaceFlingerFuzzer::invokeFlinger() { mFlinger->setSchedFifo(mFdp.ConsumeBool()); mFlinger->setSchedAttr(mFdp.ConsumeBool()); mFlinger->getServiceName(); - mFlinger->hasSyncFramework = mFdp.ConsumeBool(); - mFlinger->dispSyncPresentTimeOffset = mFdp.ConsumeIntegral(); - mFlinger->useHwcForRgbToYuv = mFdp.ConsumeBool(); - mFlinger->maxFrameBufferAcquiredBuffers = mFdp.ConsumeIntegral(); - mFlinger->maxGraphicsWidth = mFdp.ConsumeIntegral(); - mFlinger->maxGraphicsHeight = mFdp.ConsumeIntegral(); - mTestableFlinger.mutableSupportsWideColor() = mFdp.ConsumeBool(); - mFlinger->useContextPriority = mFdp.ConsumeBool(); - - mFlinger->defaultCompositionDataspace = mFdp.PickValueInArray(kDataspaces); - mFlinger->defaultCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats); - mFlinger->wideColorGamutCompositionDataspace = mFdp.PickValueInArray(kDataspaces); - mFlinger->wideColorGamutCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats); + + auto& config = mTestableFlinger.mutableConfig(); + config.hasSyncFramework = mFdp.ConsumeBool(); + config.dispSyncPresentTimeOffset = mFdp.ConsumeIntegral(); + config.useHwcForRgbToYuv = mFdp.ConsumeBool(); + config.maxFrameBufferAcquiredBuffers = mFdp.ConsumeIntegral(); + config.maxGraphicsWidth = mFdp.ConsumeIntegral(); + config.maxGraphicsHeight = mFdp.ConsumeIntegral(); + config.supportsWideColor = mFdp.ConsumeBool(); + config.useContextPriority = mFdp.ConsumeBool(); + config.defaultCompositionDataspace = mFdp.PickValueInArray(kDataspaces); + config.defaultCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats); + config.wideColorGamutCompositionDataspace = mFdp.PickValueInArray(kDataspaces); + config.wideColorGamutCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats); mFlinger->enableLatchUnsignaledConfig = mFdp.PickValueInArray(kLatchUnsignaledConfig); @@ -155,7 +156,7 @@ void SurfaceFlingerFuzzer::invokeFlinger() { } void SurfaceFlingerFuzzer::setInternalDisplayPrimaries() { - ui::DisplayPrimaries primaries; + auto& primaries = mTestableFlinger.mutableConfig().internalDisplayPrimaries; primaries.red.X = mFdp.ConsumeFloatingPoint(); primaries.red.Y = mFdp.ConsumeFloatingPoint(); primaries.red.Z = mFdp.ConsumeFloatingPoint(); @@ -168,7 +169,6 @@ void SurfaceFlingerFuzzer::setInternalDisplayPrimaries() { primaries.white.X = mFdp.ConsumeFloatingPoint(); primaries.white.Y = mFdp.ConsumeFloatingPoint(); primaries.white.Z = mFdp.ConsumeFloatingPoint(); - mTestableFlinger.setInternalDisplayPrimaries(primaries); } void SurfaceFlingerFuzzer::setTransactionState() { diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 0c9a16bee3..97cb5d35e3 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -46,6 +46,7 @@ #include "Scheduler/VsyncModulator.h" #include "StartPropertySetThread.h" #include "SurfaceFlinger.h" +#include "SurfaceFlingerConfig.h" #include "SurfaceFlingerDefaultFactory.h" #include "ThreadContext.h" #include "TimeStats/TimeStats.h" @@ -150,6 +151,8 @@ static constexpr ui::PixelFormat kPixelFormats[] = {ui::PixelFormat::RGBA_8888, ui::PixelFormat::YCBCR_P010, ui::PixelFormat::HSV_888}; +static constexpr int kMaxFrameBufferAcquiredBuffers[] = {2, 3, 4}; + inline VsyncId getFuzzedVsyncId(FuzzedDataProvider& fdp) { return VsyncId{fdp.ConsumeIntegral()}; } @@ -404,6 +407,8 @@ public: SurfaceFlinger *flinger() { return mFlinger.get(); } scheduler::TestableScheduler *scheduler() { return mScheduler; } + auto& mutableConfig() { return mConfig; } + void initializeDisplays() { FTL_FAKE_GUARD(kMainThreadContext, mFlinger->initializeDisplays()); } @@ -695,10 +700,6 @@ public: mFactory.mCreateNativeWindowSurface = f; } - void setInternalDisplayPrimaries(const ui::DisplayPrimaries &primaries) { - memcpy(&mFlinger->mInternalDisplayPrimaries, &primaries, sizeof(ui::DisplayPrimaries)); - } - static auto &mutableLayerDrawingState(const sp &layer) { return layer->mDrawingState; } auto &mutableStateLock() { return mFlinger->mStateLock; } @@ -764,13 +765,12 @@ public: auto calculateMaxAcquiredBufferCount(Fps refreshRate, std::chrono::nanoseconds presentLatency) const { - return SurfaceFlinger::calculateMaxAcquiredBufferCount(refreshRate, presentLatency); + return mFlinger->calculateMaxAcquiredBufferCount(refreshRate, presentLatency); } /* Read-write access to private data to set up preconditions and assert * post-conditions. */ - auto& mutableSupportsWideColor() { return mFlinger->mSupportsWideColor; } auto& mutableCurrentState() { return mFlinger->mCurrentState; } auto& mutableDisplays() { return mFlinger->mDisplays; } auto& mutableDrawingState() { return mFlinger->mDrawingState; } @@ -794,8 +794,8 @@ private: void triggerOnFrameRateOverridesChanged() override {} surfaceflinger::test::Factory mFactory; - sp mFlinger = - sp::make(mFactory, SurfaceFlinger::SkipInitialization); + surfaceflinger::Config mConfig = surfaceflinger::Config::makeDefault(&mFactory); + sp mFlinger = sp::make(mConfig); scheduler::TestableScheduler *mScheduler = nullptr; std::shared_ptr mRefreshRateSelector; }; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp index 849a896ce2..c16a005f0d 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp @@ -17,13 +17,15 @@ #include #include "SurfaceFlinger.h" +#include "SurfaceFlingerConfig.h" #include "SurfaceFlingerDefaultFactory.h" using namespace android; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { DefaultFactory factory; - sp flinger = sp::make(factory); + surfaceflinger::Config config = surfaceflinger::Config::makeDefault(&factory); + sp flinger = sp::make(config); flinger->init(); sp composerAIDL = sp::make(flinger); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index e32cf8863b..7124f879e9 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -34,7 +34,7 @@ DisplayTransactionTest::DisplayTransactionTest(bool withMockScheduler) { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - mFlinger.mutableSupportsWideColor() = false; + mFlinger.mutableConfig().supportsWideColor = false; mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged; mFlinger.setCreateBufferQueueFunction([](auto, auto, auto) { diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index ee12276994..5599a7a600 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -684,7 +684,7 @@ struct WideColorNotSupportedVariant { static constexpr bool WIDE_COLOR_SUPPORTED = false; static void injectConfigChange(DisplayTransactionTest* test) { - test->mFlinger.mutableSupportsWideColor() = true; + test->mFlinger.mutableConfig().supportsWideColor = true; } static void setupComposerCallExpectations(DisplayTransactionTest* test) { @@ -699,7 +699,7 @@ struct WideColorSupportNotConfiguredVariant { static constexpr bool WIDE_COLOR_SUPPORTED = false; static void injectConfigChange(DisplayTransactionTest* test) { - test->mFlinger.mutableSupportsWideColor() = false; + test->mFlinger.mutableConfig().supportsWideColor = false; test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged; } diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index fab3c0e887..6c14f6e1c1 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -250,10 +250,8 @@ TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) { EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms)); - const auto savedMinAcquiredBuffers = mFlinger.mutableMinAcquiredBuffers(); - mFlinger.mutableMinAcquiredBuffers() = 2; + mFlinger.mutableConfig().minAcquiredBuffers = 2; EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms)); - mFlinger.mutableMinAcquiredBuffers() = savedMinAcquiredBuffers; } MATCHER(Is120Hz, "") { diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp index 5951c9893f..fe383846d1 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp @@ -84,9 +84,7 @@ TEST_F(GetDisplayNativePrimaries, internalDisplayWithPrimariesData) { injector.inject(); auto internalDisplayToken = injector.token(); - ui::DisplayPrimaries expectedPrimaries; - populateDummyDisplayNativePrimaries(expectedPrimaries); - mFlinger.setInternalDisplayPrimaries(expectedPrimaries); + populateDummyDisplayNativePrimaries(mFlinger.mutableConfig().internalDisplayPrimaries); ui::DisplayPrimaries primaries; EXPECT_EQ(NO_ERROR, mFlinger.getDisplayNativePrimaries(internalDisplayToken, primaries)); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp index c0796df6cb..61891c14c7 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp @@ -36,7 +36,7 @@ struct WideColorP3ColorimetricSupportedVariant { static constexpr bool WIDE_COLOR_SUPPORTED = true; static void injectConfigChange(DisplayTransactionTest* test) { - test->mFlinger.mutableSupportsWideColor() = true; + test->mFlinger.mutableConfig().supportsWideColor = true; test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged; } diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 156c40a721..099abf59b4 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -45,6 +45,8 @@ #include "Scheduler/RefreshRateSelector.h" #include "StartPropertySetThread.h" #include "SurfaceFlinger.h" +#include "SurfaceFlingerConfig.h" +#include "SurfaceFlingerDefaultFactory.h" #include "TestableScheduler.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/DisplayHardware/MockDisplayMode.h" @@ -168,13 +170,15 @@ public: TestableSurfaceFlinger(sp flinger = nullptr) : mFlinger(flinger) { if (!mFlinger) { - mFlinger = sp::make(mFactory, SurfaceFlinger::SkipInitialization); + mFlinger = sp::make(mConfig); } } SurfaceFlinger* flinger() { return mFlinger.get(); } scheduler::TestableScheduler* scheduler() { return mScheduler; } + auto& mutableConfig() { return mConfig; } + // Extend this as needed for accessing SurfaceFlinger private (and public) // functions. @@ -312,10 +316,6 @@ public: mFactory.mCreateNativeWindowSurface = f; } - void setInternalDisplayPrimaries(const ui::DisplayPrimaries& primaries) { - memcpy(&mFlinger->mInternalDisplayPrimaries, &primaries, sizeof(ui::DisplayPrimaries)); - } - static auto& mutableLayerDrawingState(const sp& layer) { return layer->mDrawingState; } auto& mutableStateLock() { return mFlinger->mStateLock; } @@ -513,7 +513,7 @@ public: auto calculateMaxAcquiredBufferCount(Fps refreshRate, std::chrono::nanoseconds presentLatency) const { - return SurfaceFlinger::calculateMaxAcquiredBufferCount(refreshRate, presentLatency); + return mFlinger->calculateMaxAcquiredBufferCount(refreshRate, presentLatency); } auto setDesiredDisplayModeSpecs(const sp& displayToken, @@ -596,8 +596,6 @@ public: const auto& hwcPhysicalDisplayIdMap() const { return getHwComposer().mPhysicalDisplayIdMap; } const auto& hwcDisplayData() const { return getHwComposer().mDisplayData; } - auto& mutableSupportsWideColor() { return mFlinger->mSupportsWideColor; } - auto& mutableCurrentState() { return mFlinger->mCurrentState; } auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; } auto& mutableDisplays() { return mFlinger->mDisplays; } @@ -622,8 +620,6 @@ public: return SurfaceFlinger::sActiveDisplayRotationFlags; } - auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; } - auto fromHandle(const sp& handle) { return LayerHandle::getLayer(handle); } ~TestableSurfaceFlinger() { @@ -1008,6 +1004,7 @@ private: static constexpr VsyncId kVsyncId{123}; surfaceflinger::test::Factory mFactory; + surfaceflinger::Config mConfig = surfaceflinger::Config::makeDefault(&mFactory); sp mFlinger; scheduler::mock::SchedulerCallback mSchedulerCallback; scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback; -- GitLab From cdc0f1fad0aa6e73ee7d9acb513fe282717363e4 Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Tue, 20 Jun 2023 16:45:09 +0530 Subject: [PATCH 0208/1187] ultrahdr: make decodeJPEGR behaviour synonymous with getJPEGRInfo For a given image, if getJPEGRInfo returns with error, then its best to ensure decodeJPEGR exhibits identical behaviour. Currently decodeJPEGR is decoding primary image directly. If getJPEGRInfo fails with error, then it is not possible for client to allocate space for dest for decodeJPEGR. Ignoring the error, if the client allocates some space and calls decodeJPEGR, its possible we see SIGSEGV issues. Bug: 286208319 Test: ./ultrahdr_dec_fuzzer Change-Id: I04f70a6bf895efce0c0f0ec62ca0fcda2f78acbc --- libs/ultrahdr/include/ultrahdr/jpegr.h | 10 -- .../include/ultrahdr/jpegrerrorcode.h | 1 + libs/ultrahdr/jpegr.cpp | 161 ++++++++---------- 3 files changed, 74 insertions(+), 98 deletions(-) diff --git a/libs/ultrahdr/include/ultrahdr/jpegr.h b/libs/ultrahdr/include/ultrahdr/jpegr.h index a35fd30634..f80496a758 100644 --- a/libs/ultrahdr/include/ultrahdr/jpegr.h +++ b/libs/ultrahdr/include/ultrahdr/jpegr.h @@ -348,16 +348,6 @@ private: status_t extractPrimaryImageAndGainMap(jr_compressed_ptr compressed_jpegr_image, jr_compressed_ptr primary_image, jr_compressed_ptr gain_map); - /* - * This method is called in the decoding pipeline. It will read XMP metadata to find the start - * position of the compressed gain map, and will extract the compressed gain map. - * - * @param compressed_jpegr_image compressed JPEGR image - * @param dest destination of compressed gain map - * @return NO_ERROR if calculation succeeds, error code if error occurs. - */ - status_t extractGainMap(jr_compressed_ptr compressed_jpegr_image, - jr_compressed_ptr dest); /* * This method is called in the encoding pipeline. It will take the standard 8-bit JPEG image, diff --git a/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h b/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h index 064123210f..5420e1c9cf 100644 --- a/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h +++ b/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h @@ -44,6 +44,7 @@ enum { ERROR_JPEGR_INVALID_TRANS_FUNC = JPEGR_IO_ERROR_BASE - 6, ERROR_JPEGR_INVALID_METADATA = JPEGR_IO_ERROR_BASE - 7, ERROR_JPEGR_UNSUPPORTED_METADATA = JPEGR_IO_ERROR_BASE - 8, + ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND = JPEGR_IO_ERROR_BASE - 9, JPEGR_RUNTIME_ERROR_BASE = -20000, ERROR_JPEGR_ENCODE_ERROR = JPEGR_RUNTIME_ERROR_BASE - 1, diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp index 9c57f34c2a..fb24c9d206 100644 --- a/libs/ultrahdr/jpegr.cpp +++ b/libs/ultrahdr/jpegr.cpp @@ -539,9 +539,12 @@ status_t JpegR::getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image, jr_info_p return ERROR_JPEGR_INVALID_NULL_PTR; } - jpegr_compressed_struct primary_image, gain_map; - JPEGR_CHECK(extractPrimaryImageAndGainMap(compressed_jpegr_image, - &primary_image, &gain_map)); + jpegr_compressed_struct primary_image, gainmap_image; + status_t status = + extractPrimaryImageAndGainMap(compressed_jpegr_image, &primary_image, &gainmap_image); + if (status != NO_ERROR && status != ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND) { + return status; + } JpegDecoderHelper jpeg_decoder; if (!jpeg_decoder.getCompressedImageParameters(primary_image.data, primary_image.length, @@ -550,7 +553,7 @@ status_t JpegR::getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image, jr_info_p return ERROR_JPEGR_DECODE_ERROR; } - return NO_ERROR; + return status; } /* Decode API */ @@ -586,45 +589,56 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, return ERROR_JPEGR_INVALID_INPUT_TYPE; } + jpegr_compressed_struct primary_image, gainmap_image; + status_t status = + extractPrimaryImageAndGainMap(compressed_jpegr_image, &primary_image, &gainmap_image); + if (status != NO_ERROR) { + if (output_format != ULTRAHDR_OUTPUT_SDR || status != ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND) { + ALOGE("received invalid compressed jpegr image"); + return status; + } + } + + JpegDecoderHelper jpeg_decoder; + if (!jpeg_decoder.decompressImage(primary_image.data, primary_image.length, + (output_format == ULTRAHDR_OUTPUT_SDR))) { + return ERROR_JPEGR_DECODE_ERROR; + } + if (output_format == ULTRAHDR_OUTPUT_SDR) { - JpegDecoderHelper jpeg_decoder; - if (!jpeg_decoder.decompressImage(compressed_jpegr_image->data, compressed_jpegr_image->length, - true)) { - return ERROR_JPEGR_DECODE_ERROR; + if ((jpeg_decoder.getDecompressedImageWidth() * + jpeg_decoder.getDecompressedImageHeight() * 4) > + jpeg_decoder.getDecompressedImageSize()) { + return ERROR_JPEGR_CALCULATION_ERROR; } - jpegr_uncompressed_struct uncompressed_rgba_image; - uncompressed_rgba_image.data = jpeg_decoder.getDecompressedImagePtr(); - uncompressed_rgba_image.width = jpeg_decoder.getDecompressedImageWidth(); - uncompressed_rgba_image.height = jpeg_decoder.getDecompressedImageHeight(); - memcpy(dest->data, uncompressed_rgba_image.data, - uncompressed_rgba_image.width * uncompressed_rgba_image.height * 4); - dest->width = uncompressed_rgba_image.width; - dest->height = uncompressed_rgba_image.height; - - if (gain_map == nullptr && exif == nullptr) { - return NO_ERROR; + } else { + if ((jpeg_decoder.getDecompressedImageWidth() * + jpeg_decoder.getDecompressedImageHeight() * 3 / 2) > + jpeg_decoder.getDecompressedImageSize()) { + return ERROR_JPEGR_CALCULATION_ERROR; } + } - if (exif != nullptr) { - if (exif->data == nullptr) { - return ERROR_JPEGR_INVALID_NULL_PTR; - } - if (exif->length < jpeg_decoder.getEXIFSize()) { - return ERROR_JPEGR_BUFFER_TOO_SMALL; - } - memcpy(exif->data, jpeg_decoder.getEXIFPtr(), jpeg_decoder.getEXIFSize()); - exif->length = jpeg_decoder.getEXIFSize(); + if (exif != nullptr) { + if (exif->data == nullptr) { + return ERROR_JPEGR_INVALID_NULL_PTR; } - if (gain_map == nullptr) { - return NO_ERROR; + if (exif->length < jpeg_decoder.getEXIFSize()) { + return ERROR_JPEGR_BUFFER_TOO_SMALL; } + memcpy(exif->data, jpeg_decoder.getEXIFPtr(), jpeg_decoder.getEXIFSize()); + exif->length = jpeg_decoder.getEXIFSize(); } - jpegr_compressed_struct compressed_map; - JPEGR_CHECK(extractGainMap(compressed_jpegr_image, &compressed_map)); + if (output_format == ULTRAHDR_OUTPUT_SDR) { + dest->width = jpeg_decoder.getDecompressedImageWidth(); + dest->height = jpeg_decoder.getDecompressedImageHeight(); + memcpy(dest->data, jpeg_decoder.getDecompressedImagePtr(), dest->width * dest->height * 4); + return NO_ERROR; + } JpegDecoderHelper gain_map_decoder; - if (!gain_map_decoder.decompressImage(compressed_map.data, compressed_map.length)) { + if (!gain_map_decoder.decompressImage(gainmap_image.data, gainmap_image.length)) { return ERROR_JPEGR_DECODE_ERROR; } if ((gain_map_decoder.getDecompressedImageWidth() * @@ -633,12 +647,17 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, return ERROR_JPEGR_CALCULATION_ERROR; } + jpegr_uncompressed_struct map; + map.data = gain_map_decoder.getDecompressedImagePtr(); + map.width = gain_map_decoder.getDecompressedImageWidth(); + map.height = gain_map_decoder.getDecompressedImageHeight(); + if (gain_map != nullptr) { - gain_map->width = gain_map_decoder.getDecompressedImageWidth(); - gain_map->height = gain_map_decoder.getDecompressedImageHeight(); + gain_map->width = map.width; + gain_map->height = map.height; int size = gain_map->width * gain_map->height; gain_map->data = malloc(size); - memcpy(gain_map->data, gain_map_decoder.getDecompressedImagePtr(), size); + memcpy(gain_map->data, map.data, size); } ultrahdr_metadata_struct uhdr_metadata; @@ -648,46 +667,16 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, } if (metadata != nullptr) { - metadata->version = uhdr_metadata.version; - metadata->minContentBoost = uhdr_metadata.minContentBoost; - metadata->maxContentBoost = uhdr_metadata.maxContentBoost; - metadata->gamma = uhdr_metadata.gamma; - metadata->offsetSdr = uhdr_metadata.offsetSdr; - metadata->offsetHdr = uhdr_metadata.offsetHdr; - metadata->hdrCapacityMin = uhdr_metadata.hdrCapacityMin; - metadata->hdrCapacityMax = uhdr_metadata.hdrCapacityMax; - } - - if (output_format == ULTRAHDR_OUTPUT_SDR) { - return NO_ERROR; + metadata->version = uhdr_metadata.version; + metadata->minContentBoost = uhdr_metadata.minContentBoost; + metadata->maxContentBoost = uhdr_metadata.maxContentBoost; + metadata->gamma = uhdr_metadata.gamma; + metadata->offsetSdr = uhdr_metadata.offsetSdr; + metadata->offsetHdr = uhdr_metadata.offsetHdr; + metadata->hdrCapacityMin = uhdr_metadata.hdrCapacityMin; + metadata->hdrCapacityMax = uhdr_metadata.hdrCapacityMax; } - JpegDecoderHelper jpeg_decoder; - if (!jpeg_decoder.decompressImage(compressed_jpegr_image->data, compressed_jpegr_image->length)) { - return ERROR_JPEGR_DECODE_ERROR; - } - if ((jpeg_decoder.getDecompressedImageWidth() * - jpeg_decoder.getDecompressedImageHeight() * 3 / 2) > - jpeg_decoder.getDecompressedImageSize()) { - return ERROR_JPEGR_CALCULATION_ERROR; - } - - if (exif != nullptr) { - if (exif->data == nullptr) { - return ERROR_JPEGR_INVALID_NULL_PTR; - } - if (exif->length < jpeg_decoder.getEXIFSize()) { - return ERROR_JPEGR_BUFFER_TOO_SMALL; - } - memcpy(exif->data, jpeg_decoder.getEXIFPtr(), jpeg_decoder.getEXIFSize()); - exif->length = jpeg_decoder.getEXIFSize(); - } - - jpegr_uncompressed_struct map; - map.data = gain_map_decoder.getDecompressedImagePtr(); - map.width = gain_map_decoder.getDecompressedImageWidth(); - map.height = gain_map_decoder.getDecompressedImageHeight(); - jpegr_uncompressed_struct uncompressed_yuv_420_image; uncompressed_yuv_420_image.data = jpeg_decoder.getDecompressedImagePtr(); uncompressed_yuv_420_image.width = jpeg_decoder.getDecompressedImageWidth(); @@ -1131,12 +1120,8 @@ status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr compressed_jpegr const auto& jpeg_info = jpeg_info_builder.GetInfo(); const auto& image_ranges = jpeg_info.GetImageRanges(); - if (image_ranges.empty()) { - return ERROR_JPEGR_INVALID_INPUT_TYPE; - } - if (image_ranges.size() != 2) { - // Must be 2 JPEG Images + if (image_ranges.empty()) { return ERROR_JPEGR_INVALID_INPUT_TYPE; } @@ -1146,23 +1131,23 @@ status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr compressed_jpegr primary_image->length = image_ranges[0].GetLength(); } + if (image_ranges.size() == 1) { + return ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND; + } + if (gain_map != nullptr) { gain_map->data = static_cast(compressed_jpegr_image->data) + image_ranges[1].GetBegin(); gain_map->length = image_ranges[1].GetLength(); } - return NO_ERROR; -} - - -status_t JpegR::extractGainMap(jr_compressed_ptr compressed_jpegr_image, - jr_compressed_ptr dest) { - if (compressed_jpegr_image == nullptr || dest == nullptr) { - return ERROR_JPEGR_INVALID_NULL_PTR; + // TODO: choose primary image and gain map image carefully + if (image_ranges.size() > 2) { + ALOGW("Number of jpeg images present %d, primary, gain map images may not be correctly chosen", + (int)image_ranges.size()); } - return extractPrimaryImageAndGainMap(compressed_jpegr_image, nullptr, dest); + return NO_ERROR; } // JPEG/R structure: -- GitLab From 0762b1f7ddcdc92b4175fa858028c752a930e61a Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 22 Jun 2023 23:08:18 +0000 Subject: [PATCH 0209/1187] Re-organize and export libinput_rust as a rust library We export some definitions from libinput_rust as the "input" crate so they can be used directly by other rust libraries. Bug: 278783893 Test: atest libinput_rust_test Change-Id: Icba79b67103f710d8bb1cb8892016bbd4e3e6ff9 --- libs/input/Android.bp | 61 +------ libs/input/InputVerifier.cpp | 2 +- libs/input/rust/Android.bp | 72 ++++++++ libs/input/rust/input.rs | 126 ++++++++++++++ libs/input/{ => rust}/input_verifier.rs | 208 ++++-------------------- libs/input/rust/lib.rs | 88 ++++++++++ 6 files changed, 319 insertions(+), 238 deletions(-) create mode 100644 libs/input/rust/Android.bp create mode 100644 libs/input/rust/input.rs rename libs/input/{ => rust}/input_verifier.rs (57%) create mode 100644 libs/input/rust/lib.rs diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 30e4afe27d..f9f3d47301 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -109,62 +109,6 @@ cc_library_static { ], } -genrule { - name: "libinput_cxx_bridge_code", - tools: ["cxxbridge"], - cmd: "$(location cxxbridge) $(in) >> $(out)", - srcs: ["input_verifier.rs"], - out: ["inputverifier_generated.cpp"], -} - -genrule { - name: "libinput_cxx_bridge_header", - tools: ["cxxbridge"], - cmd: "$(location cxxbridge) $(in) --header >> $(out)", - srcs: ["input_verifier.rs"], - out: ["input_verifier.rs.h"], -} - -rust_defaults { - name: "libinput_rust_defaults", - srcs: ["input_verifier.rs"], - host_supported: true, - rustlibs: [ - "libbitflags", - "libcxx", - "libinput_bindgen", - "liblogger", - "liblog_rust", - "inputconstants-rust", - ], - - shared_libs: [ - "libbase", - "liblog", - ], -} - -rust_ffi_static { - name: "libinput_rust", - crate_name: "input", - defaults: ["libinput_rust_defaults"], -} - -rust_test { - name: "libinput_rust_test", - defaults: ["libinput_rust_defaults"], - whole_static_libs: [ - "libinput_from_rust_to_cpp", - ], - test_options: { - unit_test: true, - }, - test_suites: ["device_tests"], - sanitize: { - hwaddress: true, - }, -} - cc_library { name: "libinput", cpp_std: "c++20", @@ -176,7 +120,6 @@ cc_library { "-Wno-unused-parameter", ], srcs: [ - "FromRustToCpp.cpp", "Input.cpp", "InputDevice.cpp", "InputEventLabels.cpp", @@ -208,8 +151,6 @@ cc_library { "toolbox_input_labels", ], - generated_sources: ["libinput_cxx_bridge_code"], - shared_libs: [ "libbase", "libcutils", @@ -235,7 +176,7 @@ cc_library { ], whole_static_libs: [ - "libinput_rust", + "libinput_rust_ffi", ], export_static_lib_headers: [ diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp index 32b4ca0fc1..b0546a5243 100644 --- a/libs/input/InputVerifier.cpp +++ b/libs/input/InputVerifier.cpp @@ -18,7 +18,7 @@ #include #include -#include "input_verifier.rs.h" +#include "input_cxx_bridge.rs.h" using android::base::Error; using android::base::Result; diff --git a/libs/input/rust/Android.bp b/libs/input/rust/Android.bp new file mode 100644 index 0000000000..018d199ce2 --- /dev/null +++ b/libs/input/rust/Android.bp @@ -0,0 +1,72 @@ +// Copyright 2023 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. + +rust_defaults { + name: "libinput_rust_defaults", + crate_name: "input", + srcs: ["lib.rs"], + host_supported: true, + rustlibs: [ + "libbitflags", + "libcxx", + "libinput_bindgen", + "liblogger", + "liblog_rust", + "inputconstants-rust", + ], + whole_static_libs: [ + "libinput_from_rust_to_cpp", + ], + shared_libs: [ + "libbase", + ], +} + +rust_library { + name: "libinput_rust", + defaults: ["libinput_rust_defaults"], +} + +rust_ffi_static { + name: "libinput_rust_ffi", + defaults: ["libinput_rust_defaults"], +} + +rust_test { + name: "libinput_rust_test", + defaults: ["libinput_rust_defaults"], + test_options: { + unit_test: true, + }, + test_suites: ["device_tests"], + sanitize: { + hwaddress: true, + }, +} + +genrule { + name: "libinput_cxx_bridge_code", + tools: ["cxxbridge"], + cmd: "$(location cxxbridge) $(in) >> $(out)", + srcs: ["lib.rs"], + out: ["input_cxx_bridge_generated.cpp"], +} + +genrule { + name: "libinput_cxx_bridge_header", + tools: ["cxxbridge"], + cmd: "$(location cxxbridge) $(in) --header >> $(out)", + srcs: ["lib.rs"], + out: ["input_cxx_bridge.rs.h"], +} diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs new file mode 100644 index 0000000000..a308c26b2e --- /dev/null +++ b/libs/input/rust/input.rs @@ -0,0 +1,126 @@ +/* + * Copyright 2023 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. + */ + +//! Common definitions of the Android Input Framework in rust. + +use bitflags::bitflags; +use std::fmt; + +/// The InputDevice ID. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct DeviceId(pub i32); + +/// A rust enum representation of a MotionEvent action. +#[repr(u32)] +pub enum MotionAction { + /// ACTION_DOWN + Down = input_bindgen::AMOTION_EVENT_ACTION_DOWN, + /// ACTION_UP + Up = input_bindgen::AMOTION_EVENT_ACTION_UP, + /// ACTION_MOVE + Move = input_bindgen::AMOTION_EVENT_ACTION_MOVE, + /// ACTION_CANCEL + Cancel = input_bindgen::AMOTION_EVENT_ACTION_CANCEL, + /// ACTION_OUTSIDE + Outside = input_bindgen::AMOTION_EVENT_ACTION_OUTSIDE, + /// ACTION_POINTER_DOWN + PointerDown { + /// The index of the affected pointer. + action_index: usize, + } = input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN, + /// ACTION_POINTER_UP + PointerUp { + /// The index of the affected pointer. + action_index: usize, + } = input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP, + /// ACTION_HOVER_ENTER + HoverEnter = input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + /// ACTION_HOVER_MOVE + HoverMove = input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE, + /// ACTION_HOVER_EXIT + HoverExit = input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT, + /// ACTION_SCROLL + Scroll = input_bindgen::AMOTION_EVENT_ACTION_SCROLL, + /// ACTION_BUTTON_PRESS + ButtonPress = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, + /// ACTION_BUTTON_RELEASE + ButtonRelease = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE, +} + +impl fmt::Display for MotionAction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MotionAction::Down => write!(f, "DOWN"), + MotionAction::Up => write!(f, "UP"), + MotionAction::Move => write!(f, "MOVE"), + MotionAction::Cancel => write!(f, "CANCEL"), + MotionAction::Outside => write!(f, "OUTSIDE"), + MotionAction::PointerDown { action_index } => { + write!(f, "POINTER_DOWN({})", action_index) + } + MotionAction::PointerUp { action_index } => write!(f, "POINTER_UP({})", action_index), + MotionAction::HoverMove => write!(f, "HOVER_MOVE"), + MotionAction::Scroll => write!(f, "SCROLL"), + MotionAction::HoverEnter => write!(f, "HOVER_ENTER"), + MotionAction::HoverExit => write!(f, "HOVER_EXIT"), + MotionAction::ButtonPress => write!(f, "BUTTON_PRESS"), + MotionAction::ButtonRelease => write!(f, "BUTTON_RELEASE"), + } + } +} + +impl From for MotionAction { + fn from(action: u32) -> Self { + let (action_masked, action_index) = MotionAction::breakdown_action(action); + match action_masked { + input_bindgen::AMOTION_EVENT_ACTION_DOWN => MotionAction::Down, + input_bindgen::AMOTION_EVENT_ACTION_UP => MotionAction::Up, + input_bindgen::AMOTION_EVENT_ACTION_MOVE => MotionAction::Move, + input_bindgen::AMOTION_EVENT_ACTION_CANCEL => MotionAction::Cancel, + input_bindgen::AMOTION_EVENT_ACTION_OUTSIDE => MotionAction::Outside, + input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN => { + MotionAction::PointerDown { action_index } + } + input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP => { + MotionAction::PointerUp { action_index } + } + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER => MotionAction::HoverEnter, + input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE => MotionAction::HoverMove, + input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT => MotionAction::HoverExit, + input_bindgen::AMOTION_EVENT_ACTION_SCROLL => MotionAction::Scroll, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS => MotionAction::ButtonPress, + input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE => MotionAction::ButtonRelease, + _ => panic!("Unknown action: {}", action), + } + } +} + +impl MotionAction { + fn breakdown_action(action: u32) -> (u32, usize) { + let action_masked = action & input_bindgen::AMOTION_EVENT_ACTION_MASK; + let index = (action & input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) + >> input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + (action_masked, index.try_into().unwrap()) + } +} + +bitflags! { + /// MotionEvent flags. + pub struct MotionFlags: i32 { + /// FLAG_CANCELED + const CANCELED = input_bindgen::AMOTION_EVENT_FLAG_CANCELED; + } +} diff --git a/libs/input/input_verifier.rs b/libs/input/rust/input_verifier.rs similarity index 57% rename from libs/input/input_verifier.rs rename to libs/input/rust/input_verifier.rs index 2e05a63149..1cc11297b6 100644 --- a/libs/input/input_verifier.rs +++ b/libs/input/rust/input_verifier.rs @@ -14,191 +14,45 @@ * limitations under the License. */ -//! Validate the incoming motion stream. -//! This class is not thread-safe. -//! State is stored in the "InputVerifier" object -//! that can be created via the 'create' method. -//! Usage: -//! Box verifier = create("inputChannel name"); -//! result = process_movement(verifier, ...); -//! if (result) { -//! crash(result.error_message()); -//! } +//! Contains the InputVerifier, used to validate a stream of input events. +use crate::ffi::RustPointerProperties; +use crate::input::{DeviceId, MotionAction, MotionFlags}; +use log::info; use std::collections::HashMap; use std::collections::HashSet; -use bitflags::bitflags; -use log::info; - -#[cxx::bridge(namespace = "android::input")] -mod ffi { - #[namespace = "android"] - unsafe extern "C++" { - include!("ffi/FromRustToCpp.h"); - fn shouldLog(tag: &str) -> bool; - } - #[namespace = "android::input::verifier"] - extern "Rust" { - type InputVerifier; - - fn create(name: String) -> Box; - fn process_movement( - verifier: &mut InputVerifier, - device_id: i32, - action: u32, - pointer_properties: &[RustPointerProperties], - flags: i32, - ) -> String; - } - - pub struct RustPointerProperties { - id: i32, - } -} - -use crate::ffi::shouldLog; -use crate::ffi::RustPointerProperties; - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -struct DeviceId(i32); - -fn process_movement( - verifier: &mut InputVerifier, - device_id: i32, - action: u32, - pointer_properties: &[RustPointerProperties], - flags: i32, -) -> String { - let result = verifier.process_movement( - DeviceId(device_id), - action, - pointer_properties, - Flags::from_bits(flags).unwrap(), - ); - match result { - Ok(()) => "".to_string(), - Err(e) => e, - } -} - -fn create(name: String) -> Box { - Box::new(InputVerifier::new(&name)) -} - -#[repr(u32)] -enum MotionAction { - Down = input_bindgen::AMOTION_EVENT_ACTION_DOWN, - Up = input_bindgen::AMOTION_EVENT_ACTION_UP, - Move = input_bindgen::AMOTION_EVENT_ACTION_MOVE, - Cancel = input_bindgen::AMOTION_EVENT_ACTION_CANCEL, - Outside = input_bindgen::AMOTION_EVENT_ACTION_OUTSIDE, - PointerDown { action_index: usize } = input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN, - PointerUp { action_index: usize } = input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP, - HoverEnter = input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, - HoverMove = input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE, - HoverExit = input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT, - Scroll = input_bindgen::AMOTION_EVENT_ACTION_SCROLL, - ButtonPress = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS, - ButtonRelease = input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE, -} - -fn get_action_index(action: u32) -> usize { - let index = (action & input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - index.try_into().unwrap() -} - -impl From for MotionAction { - fn from(action: u32) -> Self { - let action_masked = action & input_bindgen::AMOTION_EVENT_ACTION_MASK; - let action_index = get_action_index(action); - match action_masked { - input_bindgen::AMOTION_EVENT_ACTION_DOWN => MotionAction::Down, - input_bindgen::AMOTION_EVENT_ACTION_UP => MotionAction::Up, - input_bindgen::AMOTION_EVENT_ACTION_MOVE => MotionAction::Move, - input_bindgen::AMOTION_EVENT_ACTION_CANCEL => MotionAction::Cancel, - input_bindgen::AMOTION_EVENT_ACTION_OUTSIDE => MotionAction::Outside, - input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN => { - MotionAction::PointerDown { action_index } - } - input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP => { - MotionAction::PointerUp { action_index } - } - input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER => MotionAction::HoverEnter, - input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE => MotionAction::HoverMove, - input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT => MotionAction::HoverExit, - input_bindgen::AMOTION_EVENT_ACTION_SCROLL => MotionAction::Scroll, - input_bindgen::AMOTION_EVENT_ACTION_BUTTON_PRESS => MotionAction::ButtonPress, - input_bindgen::AMOTION_EVENT_ACTION_BUTTON_RELEASE => MotionAction::ButtonRelease, - _ => panic!("Unknown action: {}", action), - } - } -} - -bitflags! { - struct Flags: i32 { - const CANCELED = input_bindgen::AMOTION_EVENT_FLAG_CANCELED; - } -} - -fn motion_action_to_string(action: u32) -> String { - match action.into() { - MotionAction::Down => "DOWN".to_string(), - MotionAction::Up => "UP".to_string(), - MotionAction::Move => "MOVE".to_string(), - MotionAction::Cancel => "CANCEL".to_string(), - MotionAction::Outside => "OUTSIDE".to_string(), - MotionAction::PointerDown { action_index } => { - format!("POINTER_DOWN({})", action_index) - } - MotionAction::PointerUp { action_index } => { - format!("POINTER_UP({})", action_index) - } - MotionAction::HoverMove => "HOVER_MOVE".to_string(), - MotionAction::Scroll => "SCROLL".to_string(), - MotionAction::HoverEnter => "HOVER_ENTER".to_string(), - MotionAction::HoverExit => "HOVER_EXIT".to_string(), - MotionAction::ButtonPress => "BUTTON_PRESS".to_string(), - MotionAction::ButtonRelease => "BUTTON_RELEASE".to_string(), - } -} - -/** - * Log all of the movements that are sent to this verifier. Helps to identify the streams that lead - * to inconsistent events. - * Enable this via "adb shell setprop log.tag.InputVerifierLogEvents DEBUG" - */ -fn log_events() -> bool { - shouldLog("InputVerifierLogEvents") -} - -struct InputVerifier { +/// The InputVerifier is used to validate a stream of input events. +pub struct InputVerifier { name: String, + should_log: bool, touching_pointer_ids_by_device: HashMap>, } impl InputVerifier { - fn new(name: &str) -> Self { + /// Create a new InputVerifier. + pub fn new(name: &str, should_log: bool) -> Self { logger::init( logger::Config::default() .with_tag_on_device("InputVerifier") .with_min_level(log::Level::Trace), ); - Self { name: name.to_owned(), touching_pointer_ids_by_device: HashMap::new() } + Self { name: name.to_owned(), should_log, touching_pointer_ids_by_device: HashMap::new() } } - fn process_movement( + /// Process a pointer movement event from an InputDevice. + /// If the event is not valid, we return an error string that describes the issue. + pub fn process_movement( &mut self, device_id: DeviceId, action: u32, pointer_properties: &[RustPointerProperties], - flags: Flags, + flags: MotionFlags, ) -> Result<(), String> { - if log_events() { + if self.should_log { info!( "Processing {} for device {:?} ({} pointer{}) on {}", - motion_action_to_string(action), + MotionAction::from(action).to_string(), device_id, pointer_properties.len(), if pointer_properties.len() == 1 { "" } else { "s" }, @@ -284,7 +138,7 @@ impl InputVerifier { it.clear(); } MotionAction::Cancel => { - if flags.contains(Flags::CANCELED) { + if flags.contains(MotionFlags::CANCELED) { return Err(format!( "{}: For ACTION_CANCEL, must set FLAG_CANCELED", self.name @@ -325,20 +179,20 @@ impl InputVerifier { #[cfg(test)] mod tests { + use crate::input_verifier::InputVerifier; use crate::DeviceId; - use crate::Flags; - use crate::InputVerifier; + use crate::MotionFlags; use crate::RustPointerProperties; #[test] fn single_pointer_stream() { - let mut verifier = InputVerifier::new("Test"); + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier .process_movement( DeviceId(1), input_bindgen::AMOTION_EVENT_ACTION_DOWN, &pointer_properties, - Flags::empty(), + MotionFlags::empty(), ) .is_ok()); assert!(verifier @@ -346,7 +200,7 @@ mod tests { DeviceId(1), input_bindgen::AMOTION_EVENT_ACTION_MOVE, &pointer_properties, - Flags::empty(), + MotionFlags::empty(), ) .is_ok()); assert!(verifier @@ -354,21 +208,21 @@ mod tests { DeviceId(1), input_bindgen::AMOTION_EVENT_ACTION_UP, &pointer_properties, - Flags::empty(), + MotionFlags::empty(), ) .is_ok()); } #[test] fn multi_device_stream() { - let mut verifier = InputVerifier::new("Test"); + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier .process_movement( DeviceId(1), input_bindgen::AMOTION_EVENT_ACTION_DOWN, &pointer_properties, - Flags::empty(), + MotionFlags::empty(), ) .is_ok()); assert!(verifier @@ -376,7 +230,7 @@ mod tests { DeviceId(1), input_bindgen::AMOTION_EVENT_ACTION_MOVE, &pointer_properties, - Flags::empty(), + MotionFlags::empty(), ) .is_ok()); assert!(verifier @@ -384,7 +238,7 @@ mod tests { DeviceId(2), input_bindgen::AMOTION_EVENT_ACTION_DOWN, &pointer_properties, - Flags::empty(), + MotionFlags::empty(), ) .is_ok()); assert!(verifier @@ -392,7 +246,7 @@ mod tests { DeviceId(2), input_bindgen::AMOTION_EVENT_ACTION_MOVE, &pointer_properties, - Flags::empty(), + MotionFlags::empty(), ) .is_ok()); assert!(verifier @@ -400,21 +254,21 @@ mod tests { DeviceId(1), input_bindgen::AMOTION_EVENT_ACTION_UP, &pointer_properties, - Flags::empty(), + MotionFlags::empty(), ) .is_ok()); } #[test] fn test_invalid_up() { - let mut verifier = InputVerifier::new("Test"); + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier .process_movement( DeviceId(1), input_bindgen::AMOTION_EVENT_ACTION_UP, &pointer_properties, - Flags::empty(), + MotionFlags::empty(), ) .is_err()); } diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs new file mode 100644 index 0000000000..25b2ecbcda --- /dev/null +++ b/libs/input/rust/lib.rs @@ -0,0 +1,88 @@ +/* + * Copyright 2023 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. + */ + +//! The rust component of libinput. + +mod input; +mod input_verifier; + +pub use input::{DeviceId, MotionAction, MotionFlags}; +pub use input_verifier::InputVerifier; + +#[cxx::bridge(namespace = "android::input")] +mod ffi { + #[namespace = "android"] + unsafe extern "C++" { + include!("ffi/FromRustToCpp.h"); + fn shouldLog(tag: &str) -> bool; + } + + #[namespace = "android::input::verifier"] + extern "Rust" { + /// Used to validate the incoming motion stream. + /// This class is not thread-safe. + /// State is stored in the "InputVerifier" object + /// that can be created via the 'create' method. + /// Usage: + /// + /// ```ignore + /// Box verifier = create("inputChannel name"); + /// result = process_movement(verifier, ...); + /// if (result) { + /// crash(result.error_message()); + /// } + /// ``` + type InputVerifier; + fn create(name: String) -> Box; + fn process_movement( + verifier: &mut InputVerifier, + device_id: i32, + action: u32, + pointer_properties: &[RustPointerProperties], + flags: i32, + ) -> String; + } + + #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] + pub struct RustPointerProperties { + pub id: i32, + } +} + +use crate::ffi::RustPointerProperties; + +fn process_movement( + verifier: &mut InputVerifier, + device_id: i32, + action: u32, + pointer_properties: &[RustPointerProperties], + flags: i32, +) -> String { + let result = verifier.process_movement( + DeviceId(device_id), + action, + pointer_properties, + MotionFlags::from_bits(flags).unwrap(), + ); + match result { + Ok(()) => "".to_string(), + Err(e) => e, + } +} + +fn create(name: String) -> Box { + Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents"))) +} -- GitLab From 0ea47b50a6f37e703390e0ac6b8e36d98187a2c8 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Thu, 22 Jun 2023 13:27:20 -0700 Subject: [PATCH 0210/1187] Optimize the way of calling setDisplayBrightness. - Only call it when display brightness difference ratio is over than threshold. Bug: 267262025 Test: play with Youtube HDR video Change-Id: I24cf0f01db342711d6b2a160b384c006c44fdad4 --- services/surfaceflinger/SurfaceFlinger.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3165b9e270..a97b5e4fca 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1830,8 +1830,21 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, float currentDimmingRatio = compositionDisplay->editState().sdrWhitePointNits / compositionDisplay->editState().displayBrightnessNits; - compositionDisplay->setDisplayBrightness(brightness.sdrWhitePointNits, - brightness.displayBrightnessNits); + static constexpr float kDimmingThreshold = 0.02f; + if (brightness.sdrWhitePointNits == 0.f || + abs(brightness.sdrWhitePointNits - brightness.displayBrightnessNits) / + brightness.sdrWhitePointNits >= + kDimmingThreshold) { + // to optimize, skip brightness setter if the brightness difference ratio + // is lower than threshold + compositionDisplay + ->setDisplayBrightness(brightness.sdrWhitePointNits, + brightness.displayBrightnessNits); + } else { + compositionDisplay->setDisplayBrightness(brightness.sdrWhitePointNits, + brightness.sdrWhitePointNits); + } + FTL_FAKE_GUARD(kMainThreadContext, display->stageBrightness(brightness.displayBrightness)); -- GitLab From 69d00bf5dc268ff09ca596660d77d2c3ab207d44 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 23 Jun 2023 19:55:18 +0000 Subject: [PATCH 0211/1187] Dispatcher: Do not cancel touches when a window's orientation changes Bug: 284312855 Test: atest inputflinger_tests Change-Id: I8cc7105e80eb504caba2a77a9d062bf7f846ca23 --- .../dispatcher/InputDispatcher.cpp | 24 ------------------- .../tests/InputDispatcher_test.cpp | 15 +++++++----- 2 files changed, 9 insertions(+), 30 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index b42ca31455..5803fd414e 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -5126,13 +5126,6 @@ void InputDispatcher::setInputWindowsLocked( // Copy old handles for release if they are no longer present. const std::vector> oldWindowHandles = getWindowHandlesLocked(displayId); - // Save the old windows' orientation by ID before it gets updated. - std::unordered_map oldWindowOrientations; - for (const sp& handle : oldWindowHandles) { - oldWindowOrientations.emplace(handle->getId(), - handle->getInfo()->transform.getOrientation()); - } - updateWindowHandlesForDisplayLocked(windowInfoHandles, displayId); const std::vector>& windowHandles = getWindowHandlesLocked(displayId); @@ -5186,23 +5179,6 @@ void InputDispatcher::setInputWindowsLocked( } } - // Determine if the orientation of any of the input windows have changed, and cancel all - // pointer events if necessary. - for (const sp& oldWindowHandle : oldWindowHandles) { - const sp newWindowHandle = getWindowHandleLocked(oldWindowHandle); - if (newWindowHandle != nullptr && - newWindowHandle->getInfo()->transform.getOrientation() != - oldWindowOrientations[oldWindowHandle->getId()]) { - std::shared_ptr inputChannel = - getInputChannelLocked(newWindowHandle->getToken()); - if (inputChannel != nullptr) { - CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, - "touched window's orientation changed"); - synthesizeCancelationEventsForInputChannelLocked(inputChannel, options); - } - } - } - // Release information for windows that are no longer present. // This ensures that unused input channels are released promptly. // Otherwise, they might stick around until the window handle is destroyed diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index c0da721264..e41df7c8df 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -3929,9 +3929,7 @@ TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) { /** * Send a two-pointer gesture to a single window. The window's orientation changes in response to * the first pointer. - * Ensure that the second pointer is not sent to the window. - * - * The subsequent gesture should be correctly delivered to the window. + * Ensure that the second pointer and the subsequent gesture is correctly delivered to the window. */ TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) { std::shared_ptr application = std::make_shared(); @@ -3961,8 +3959,6 @@ TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) { mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowDup}}}); - window->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); - mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .downTime(baseTime + 10) .eventTime(baseTime + 30) @@ -3970,19 +3966,26 @@ TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) { .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200)) .build()); - // Finish the gesture and start a new one. Ensure the new gesture is sent to the window + window->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN)); + + // Finish the gesture and start a new one. Ensure all events are sent to the window. mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) .downTime(baseTime + 10) .eventTime(baseTime + 40) .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .pointer(PointerBuilder(1, ToolType::FINGER).x(200).y(200)) .build()); + + window->consumeMotionEvent(WithMotionAction(POINTER_1_UP)); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .downTime(baseTime + 10) .eventTime(baseTime + 50) .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_UP)); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .downTime(baseTime + 60) .eventTime(baseTime + 60) -- GitLab From 48c7a6dbb470da6b62ee53e71d3676837b774834 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 23 Jun 2023 18:47:16 +0000 Subject: [PATCH 0212/1187] Add some logging in KawaseBlurFilter Specifically, if we would have attempted to dereference a nullptr, instead fatal log with a diagnostic message Bug: 275754150 Change-Id: Icb23ed31d8dcddc8efd358276f1e99134a655a7b --- libs/renderengine/skia/filters/KawaseBlurFilter.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp index d1d92e5c6e..061ec5f8a3 100644 --- a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp +++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp @@ -57,6 +57,8 @@ KawaseBlurFilter::KawaseBlurFilter(): BlurFilter() { sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius, const sk_sp input, const SkRect& blurRect) const { + + LOG_ALWAYS_FATAL_IF(input == nullptr, "%s: Invalid input image", __func__); // Kawase is an approximation of Gaussian, but it behaves differently from it. // A radius transformation is required for approximating them, and also to introduce // non-integer steps, necessary to smoothly interpolate large radii. @@ -85,6 +87,7 @@ sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, const uin // And now we'll build our chain of scaled blur stages for (auto i = 1; i < numberOfPasses; i++) { + LOG_ALWAYS_FATAL_IF(tmpBlur == nullptr, "%s: tmpBlur is null for pass %d", __func__, i); blurBuilder.child("child") = tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear); blurBuilder.uniform("in_blurOffset") = (float) i * radiusByPasses * kInputScale; -- GitLab From 4d9cef90b63391b797b70e7054600ddd205460ee Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Sat, 24 Jun 2023 22:34:41 +0000 Subject: [PATCH 0213/1187] [sf] update transaction handler filter to use new front end Instead of looking at drawing state, get the data from RequestedLayerState. Bug: 238781169 Test: presubmit Change-Id: I760900ca23c8d8717b1a0bc5afa8cfee36013a0b --- .../FrontEnd/RequestedLayerState.cpp | 46 ++++ .../FrontEnd/RequestedLayerState.h | 2 + .../FrontEnd/TransactionHandler.cpp | 4 +- .../FrontEnd/TransactionHandler.h | 2 + services/surfaceflinger/SurfaceFlinger.cpp | 221 ++++++++++++++---- services/surfaceflinger/SurfaceFlinger.h | 13 +- services/surfaceflinger/TransactionState.h | 2 +- .../unittests/TransactionApplicationTest.cpp | 1 + 8 files changed, 241 insertions(+), 50 deletions(-) diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 5738262bf0..065b8956c5 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -19,6 +19,7 @@ #undef LOG_TAG #define LOG_TAG "SurfaceFlinger" +#include #include #include #include @@ -507,6 +508,51 @@ bool RequestedLayerState::willReleaseBufferOnLatch() const { return changes.test(Changes::Buffer) && !externalTexture; } +bool RequestedLayerState::backpressureEnabled() const { + return flags & layer_state_t::eEnableBackpressure; +} + +bool RequestedLayerState::isSimpleBufferUpdate(const layer_state_t& s) const { + static constexpr uint64_t requiredFlags = layer_state_t::eBufferChanged; + if ((s.what & requiredFlags) != requiredFlags) { + ATRACE_FORMAT_INSTANT("%s: false [missing required flags 0x%" PRIx64 "]", __func__, + (s.what | requiredFlags) & ~s.what); + return false; + } + + static constexpr uint64_t deniedFlags = layer_state_t::eProducerDisconnect | + layer_state_t::eLayerChanged | layer_state_t::eRelativeLayerChanged | + layer_state_t::eTransparentRegionChanged | layer_state_t::eFlagsChanged | + layer_state_t::eBlurRegionsChanged | layer_state_t::eLayerStackChanged | + layer_state_t::eAutoRefreshChanged | layer_state_t::eReparent; + if (s.what & deniedFlags) { + ATRACE_FORMAT_INSTANT("%s: false [has denied flags 0x%" PRIx64 "]", __func__, + s.what & deniedFlags); + return false; + } + + bool changedFlags = diff(s); + static constexpr auto deniedChanges = layer_state_t::ePositionChanged | + layer_state_t::eAlphaChanged | layer_state_t::eColorTransformChanged | + layer_state_t::eBackgroundColorChanged | layer_state_t::eMatrixChanged | + layer_state_t::eCornerRadiusChanged | layer_state_t::eBackgroundBlurRadiusChanged | + layer_state_t::eBufferTransformChanged | + layer_state_t::eTransformToDisplayInverseChanged | layer_state_t::eCropChanged | + layer_state_t::eDataspaceChanged | layer_state_t::eHdrMetadataChanged | + layer_state_t::eSidebandStreamChanged | layer_state_t::eColorSpaceAgnosticChanged | + layer_state_t::eShadowRadiusChanged | layer_state_t::eFixedTransformHintChanged | + layer_state_t::eTrustedOverlayChanged | layer_state_t::eStretchChanged | + layer_state_t::eBufferCropChanged | layer_state_t::eDestinationFrameChanged | + layer_state_t::eDimmingEnabledChanged | layer_state_t::eExtendedRangeBrightnessChanged; + if (changedFlags & deniedChanges) { + ATRACE_FORMAT_INSTANT("%s: false [has denied changes flags 0x%" PRIx64 "]", __func__, + s.what & deniedChanges); + return false; + } + + return true; +} + void RequestedLayerState::clearChanges() { what = 0; changes.clear(); diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h index 02e3bac18b..8ca1cd6323 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h @@ -82,6 +82,8 @@ struct RequestedLayerState : layer_state_t { bool hasReadyFrame() const; bool hasSidebandStreamFrame() const; bool willReleaseBufferOnLatch() const; + bool backpressureEnabled() const; + bool isSimpleBufferUpdate(const layer_state_t&) const; // Layer serial number. This gives layers an explicit ordering, so we // have a stable sort order when their layer stack and Z-order are diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp index fa8eb3cf13..0d3c6ebd47 100644 --- a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp +++ b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp @@ -33,7 +33,7 @@ void TransactionHandler::queueTransaction(TransactionState&& state) { ATRACE_INT("TransactionQueue", static_cast(mPendingTransactionCount.load())); } -std::vector TransactionHandler::flushTransactions() { +void TransactionHandler::collectTransactions() { while (!mLocklessTransactionQueue.isEmpty()) { auto maybeTransaction = mLocklessTransactionQueue.pop(); if (!maybeTransaction.has_value()) { @@ -42,7 +42,9 @@ std::vector TransactionHandler::flushTransactions() { auto transaction = maybeTransaction.value(); mPendingTransactionQueues[transaction.applyToken].emplace(std::move(transaction)); } +} +std::vector TransactionHandler::flushTransactions() { // Collect transaction that are ready to be applied. std::vector transactions; TransactionFlushState flushState; diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.h b/services/surfaceflinger/FrontEnd/TransactionHandler.h index 865835f92d..04183bcdb8 100644 --- a/services/surfaceflinger/FrontEnd/TransactionHandler.h +++ b/services/surfaceflinger/FrontEnd/TransactionHandler.h @@ -58,6 +58,8 @@ public: using TransactionFilter = std::function; bool hasPendingTransactions(); + // Moves transactions from the lockless queue. + void collectTransactions(); std::vector flushTransactions(); void addTransactionReadyFilter(TransactionFilter&&); void queueTransaction(TransactionState&&); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 81d48973be..85b7c83a30 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2054,12 +2054,22 @@ void SurfaceFlinger::configure() FTL_FAKE_GUARD(kMainThreadContext) { } } -bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, frontend::Update& update, - bool transactionsFlushed, +bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, nsecs_t frameTimeNs, + bool flushTransactions, bool& outTransactionsAreEmpty) { ATRACE_CALL(); + frontend::Update update; + if (flushTransactions) { + update = flushLifecycleUpdates(); + if (mTransactionTracing) { + mTransactionTracing->addCommittedTransactions(ftl::to_underlying(vsyncId), frameTimeNs, + update, mFrontEndDisplayInfos, + mFrontEndDisplayInfosChanged); + } + } + bool needsTraversal = false; - if (transactionsFlushed) { + if (flushTransactions) { needsTraversal |= commitMirrorDisplays(vsyncId); needsTraversal |= commitCreatedLayers(vsyncId, update.layerCreatedStates); needsTraversal |= applyTransactions(update.transactions, vsyncId); @@ -2107,12 +2117,43 @@ void SurfaceFlinger::updateLayerHistory(const frontend::LayerSnapshot& snapshot) } } -bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& update, - bool transactionsFlushed, bool& outTransactionsAreEmpty) { +bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, + bool flushTransactions, bool& outTransactionsAreEmpty) { using Changes = frontend::RequestedLayerState::Changes; ATRACE_CALL(); - { + frontend::Update update; + if (flushTransactions) { + ATRACE_NAME("TransactionHandler:flushTransactions"); + // Locking: + // 1. to prevent onHandleDestroyed from being called while the state lock is held, + // we must keep a copy of the transactions (specifically the composer + // states) around outside the scope of the lock. + // 2. Transactions and created layers do not share a lock. To prevent applying + // transactions with layers still in the createdLayer queue, collect the transactions + // before committing the created layers. + // 3. Transactions can only be flushed after adding layers, since the layer can be a newly + // created one + mTransactionHandler.collectTransactions(); + { + // TODO(b/238781169) lockless queue this and keep order. + std::scoped_lock lock(mCreatedLayersLock); + update.layerCreatedStates = std::move(mCreatedLayers); + mCreatedLayers.clear(); + update.newLayers = std::move(mNewLayers); + mNewLayers.clear(); + update.layerCreationArgs = std::move(mNewLayerArgs); + mNewLayerArgs.clear(); + update.destroyedHandles = std::move(mDestroyedHandles); + mDestroyedHandles.clear(); + } + mLayerLifecycleManager.addLayers(std::move(update.newLayers)); + update.transactions = mTransactionHandler.flushTransactions(); + if (mTransactionTracing) { + mTransactionTracing->addCommittedTransactions(ftl::to_underlying(vsyncId), frameTimeNs, + update, mFrontEndDisplayInfos, + mFrontEndDisplayInfosChanged); + } mLayerLifecycleManager.applyTransactions(update.transactions); mLayerLifecycleManager.onHandlesDestroyed(update.destroyedHandles); for (auto& legacyLayer : update.layerCreatedStates) { @@ -2121,11 +2162,11 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& upd mLegacyLayers[layer->sequence] = layer; } } - } - if (mLayerLifecycleManager.getGlobalChanges().test(Changes::Hierarchy)) { - ATRACE_NAME("LayerHierarchyBuilder:update"); - mLayerHierarchyBuilder.update(mLayerLifecycleManager.getLayers(), - mLayerLifecycleManager.getDestroyedLayers()); + if (mLayerLifecycleManager.getGlobalChanges().test(Changes::Hierarchy)) { + ATRACE_NAME("LayerHierarchyBuilder:update"); + mLayerHierarchyBuilder.update(mLayerLifecycleManager.getLayers(), + mLayerLifecycleManager.getDestroyedLayers()); + } } bool mustComposite = false; @@ -2299,25 +2340,16 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) Fps::fromPeriodNsecs(vsyncPeriod.ns())); const bool flushTransactions = clearTransactionFlags(eTransactionFlushNeeded); - frontend::Update updates; - if (flushTransactions) { - updates = flushLifecycleUpdates(); - if (mTransactionTracing) { - mTransactionTracing - ->addCommittedTransactions(ftl::to_underlying(vsyncId), - pacesetterFrameTarget.frameBeginTime().ns(), - updates, mFrontEndDisplayInfos, - mFrontEndDisplayInfosChanged); - } - } bool transactionsAreEmpty; if (mConfig->legacyFrontEndEnabled) { - mustComposite |= updateLayerSnapshotsLegacy(vsyncId, updates, flushTransactions, - transactionsAreEmpty); + mustComposite |= + updateLayerSnapshotsLegacy(vsyncId, pacesetterFrameTarget.frameBeginTime().ns(), + flushTransactions, transactionsAreEmpty); } if (mConfig->layerLifecycleManagerEnabled) { mustComposite |= - updateLayerSnapshots(vsyncId, updates, flushTransactions, transactionsAreEmpty); + updateLayerSnapshots(vsyncId, pacesetterFrameTarget.frameBeginTime().ns(), + flushTransactions, transactionsAreEmpty); } if (transactionFlushNeeded()) { @@ -4123,18 +4155,16 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyTimelin return TransactionReadiness::Ready; } -TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheck( +TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheckLegacy( const TransactionHandler::TransactionFlushState& flushState) { using TransactionReadiness = TransactionHandler::TransactionReadiness; auto ready = TransactionReadiness::Ready; - flushState.transaction->traverseStatesWithBuffersWhileTrue([&](const layer_state_t& s, - const std::shared_ptr< - renderengine:: - ExternalTexture>& - externalTexture) - -> bool { - sp layer = LayerHandle::getLayer(s.surface); + flushState.transaction->traverseStatesWithBuffersWhileTrue([&](const ResolvedComposerState& + resolvedState) -> bool { + sp layer = LayerHandle::getLayer(resolvedState.state.surface); + const auto& transaction = *flushState.transaction; + const auto& s = resolvedState.state; // check for barrier frames if (s.bufferData->hasBarrier) { // The current producerId is already a newer producer than the buffer that has a @@ -4142,7 +4172,7 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC // don't wait on the barrier since we know that's stale information. if (layer->getDrawingState().barrierProducerId > s.bufferData->producerId) { layer->callReleaseBufferCallback(s.bufferData->releaseBufferListener, - externalTexture->getBuffer(), + resolvedState.externalTexture->getBuffer(), s.bufferData->frameNumber, s.bufferData->acquireFence); // Delete the entire state at this point and not just release the buffer because @@ -4188,9 +4218,10 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC s.bufferData->acquireFence->getStatus() != Fence::Status::Unsignaled; if (!fenceSignaled) { // check fence status - const bool allowLatchUnsignaled = - shouldLatchUnsignaled(layer, s, transaction.states.size(), - flushState.firstTransaction); + const bool allowLatchUnsignaled = shouldLatchUnsignaled(s, transaction.states.size(), + flushState.firstTransaction) && + layer->isSimpleBufferUpdate(s); + if (allowLatchUnsignaled) { ATRACE_FORMAT("fence unsignaled try allowLatchUnsignaled %s", layer->getDebugName()); @@ -4215,15 +4246,120 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC return ready; } +TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferCheck( + const TransactionHandler::TransactionFlushState& flushState) { + using TransactionReadiness = TransactionHandler::TransactionReadiness; + auto ready = TransactionReadiness::Ready; + flushState.transaction->traverseStatesWithBuffersWhileTrue([&](const ResolvedComposerState& + resolvedState) -> bool { + const frontend::RequestedLayerState* layer = + mLayerLifecycleManager.getLayerFromId(resolvedState.layerId); + const auto& transaction = *flushState.transaction; + const auto& s = resolvedState.state; + // check for barrier frames + if (s.bufferData->hasBarrier) { + // The current producerId is already a newer producer than the buffer that has a + // barrier. This means the incoming buffer is older and we can release it here. We + // don't wait on the barrier since we know that's stale information. + if (layer->barrierProducerId > s.bufferData->producerId) { + if (s.bufferData->releaseBufferListener) { + uint32_t currentMaxAcquiredBufferCount = + getMaxAcquiredBufferCountForCurrentRefreshRate(layer->ownerUid.val()); + ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, + layer->name.c_str(), s.bufferData->frameNumber); + s.bufferData->releaseBufferListener + ->onReleaseBuffer({resolvedState.externalTexture->getBuffer()->getId(), + s.bufferData->frameNumber}, + s.bufferData->acquireFence + ? s.bufferData->acquireFence + : Fence::NO_FENCE, + currentMaxAcquiredBufferCount); + } + + // Delete the entire state at this point and not just release the buffer because + // everything associated with the Layer in this Transaction is now out of date. + ATRACE_FORMAT("DeleteStaleBuffer %s barrierProducerId:%d > %d", layer->name.c_str(), + layer->barrierProducerId, s.bufferData->producerId); + return TraverseBuffersReturnValues::DELETE_AND_CONTINUE_TRAVERSAL; + } + + if (layer->barrierFrameNumber < s.bufferData->barrierFrameNumber) { + const bool willApplyBarrierFrame = + flushState.bufferLayersReadyToPresent.contains(s.surface.get()) && + ((flushState.bufferLayersReadyToPresent.get(s.surface.get()) >= + s.bufferData->barrierFrameNumber)); + if (!willApplyBarrierFrame) { + ATRACE_FORMAT("NotReadyBarrier %s barrierFrameNumber:%" PRId64 " > %" PRId64, + layer->name.c_str(), layer->barrierFrameNumber, + s.bufferData->barrierFrameNumber); + ready = TransactionReadiness::NotReadyBarrier; + return TraverseBuffersReturnValues::STOP_TRAVERSAL; + } + } + } + + // If backpressure is enabled and we already have a buffer to commit, keep + // the transaction in the queue. + const bool hasPendingBuffer = + flushState.bufferLayersReadyToPresent.contains(s.surface.get()); + if (layer->backpressureEnabled() && hasPendingBuffer && transaction.isAutoTimestamp) { + ATRACE_FORMAT("hasPendingBuffer %s", layer->name.c_str()); + ready = TransactionReadiness::NotReady; + return TraverseBuffersReturnValues::STOP_TRAVERSAL; + } + + // ignore the acquire fence if LatchUnsignaledConfig::Always is set. + const bool checkAcquireFence = enableLatchUnsignaledConfig != LatchUnsignaledConfig::Always; + const bool acquireFenceAvailable = s.bufferData && + s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) && + s.bufferData->acquireFence; + const bool fenceSignaled = !checkAcquireFence || !acquireFenceAvailable || + s.bufferData->acquireFence->getStatus() != Fence::Status::Unsignaled; + if (!fenceSignaled) { + // check fence status + const bool allowLatchUnsignaled = shouldLatchUnsignaled(s, transaction.states.size(), + flushState.firstTransaction) && + layer->isSimpleBufferUpdate(s); + if (allowLatchUnsignaled) { + ATRACE_FORMAT("fence unsignaled try allowLatchUnsignaled %s", layer->name.c_str()); + ready = TransactionReadiness::NotReadyUnsignaled; + } else { + ready = TransactionReadiness::NotReady; + auto& listener = s.bufferData->releaseBufferListener; + if (listener && + (flushState.queueProcessTime - transaction.postTime) > + std::chrono::nanoseconds(4s).count()) { + mTransactionHandler + .onTransactionQueueStalled(transaction.id, listener, + "Buffer processing hung up due to stuck " + "fence. Indicates GPU hang"); + } + ATRACE_FORMAT("fence unsignaled %s", layer->name.c_str()); + return TraverseBuffersReturnValues::STOP_TRAVERSAL; + } + } + return TraverseBuffersReturnValues::CONTINUE_TRAVERSAL; + }); + return ready; +} + void SurfaceFlinger::addTransactionReadyFilters() { mTransactionHandler.addTransactionReadyFilter( std::bind(&SurfaceFlinger::transactionReadyTimelineCheck, this, std::placeholders::_1)); - mTransactionHandler.addTransactionReadyFilter( - std::bind(&SurfaceFlinger::transactionReadyBufferCheck, this, std::placeholders::_1)); + if (mConfig->layerLifecycleManagerEnabled) { + mTransactionHandler.addTransactionReadyFilter( + std::bind(&SurfaceFlinger::transactionReadyBufferCheck, this, + std::placeholders::_1)); + } else { + mTransactionHandler.addTransactionReadyFilter( + std::bind(&SurfaceFlinger::transactionReadyBufferCheckLegacy, this, + std::placeholders::_1)); + } } // For tests only bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) { + mTransactionHandler.collectTransactions(); std::vector transactions = mTransactionHandler.flushTransactions(); return applyTransactions(transactions, vsyncId); } @@ -4276,8 +4412,8 @@ bool SurfaceFlinger::frameIsEarly(TimePoint expectedPresentTime, VsyncId vsyncId predictedPresentTime - expectedPresentTime >= earlyLatchVsyncThreshold; } -bool SurfaceFlinger::shouldLatchUnsignaled(const sp& layer, const layer_state_t& state, - size_t numStates, bool firstTransaction) const { +bool SurfaceFlinger::shouldLatchUnsignaled(const layer_state_t& state, size_t numStates, + bool firstTransaction) const { if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) { ATRACE_FORMAT_INSTANT("%s: false (LatchUnsignaledConfig::Disabled)", __func__); return false; @@ -4314,7 +4450,7 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const sp& layer, const layer_s } } - return layer->isSimpleBufferUpdate(state); + return true; } status_t SurfaceFlinger::setTransactionState( @@ -8158,6 +8294,7 @@ frontend::Update SurfaceFlinger::flushLifecycleUpdates() { // 2. Transactions and created layers do not share a lock. To prevent applying // transactions with layers still in the createdLayer queue, flush the transactions // before committing the created layers. + mTransactionHandler.collectTransactions(); update.transactions = mTransactionHandler.flushTransactions(); { // TODO(b/238781169) lockless queue this and keep order. diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 79102971d4..55e1b758b7 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -654,10 +654,9 @@ private: compositionengine::CompositionRefreshArgs& refreshArgs, bool cursorOnly); void moveSnapshotsFromCompositionArgs(compositionengine::CompositionRefreshArgs& refreshArgs, const std::vector>& layers); - bool updateLayerSnapshotsLegacy(VsyncId vsyncId, frontend::Update& update, - bool transactionsFlushed, bool& out) - REQUIRES(kMainThreadContext); - bool updateLayerSnapshots(VsyncId vsyncId, frontend::Update& update, bool transactionsFlushed, + bool updateLayerSnapshotsLegacy(VsyncId vsyncId, nsecs_t frameTimeNs, bool transactionsFlushed, + bool& out) REQUIRES(kMainThreadContext); + bool updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, bool transactionsFlushed, bool& out) REQUIRES(kMainThreadContext); void updateLayerHistory(const frontend::LayerSnapshot& snapshot); frontend::Update flushLifecycleUpdates() REQUIRES(kMainThreadContext); @@ -701,6 +700,9 @@ private: TransactionHandler::TransactionReadiness transactionReadyTimelineCheck( const TransactionHandler::TransactionFlushState& flushState) REQUIRES(kMainThreadContext); + TransactionHandler::TransactionReadiness transactionReadyBufferCheckLegacy( + const TransactionHandler::TransactionFlushState& flushState) + REQUIRES(kMainThreadContext); TransactionHandler::TransactionReadiness transactionReadyBufferCheck( const TransactionHandler::TransactionFlushState& flushState) REQUIRES(kMainThreadContext); @@ -725,8 +727,7 @@ private: void commitOffscreenLayers(); static LatchUnsignaledConfig getLatchUnsignaledConfig(); - bool shouldLatchUnsignaled(const sp& layer, const layer_state_t&, size_t numStates, - bool firstTransaction) const; + bool shouldLatchUnsignaled(const layer_state_t&, size_t numStates, bool firstTransaction) const; bool applyTransactionsLocked(std::vector& transactions, VsyncId) REQUIRES(mStateLock); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h index 7132a59016..31cd2d7eb6 100644 --- a/services/surfaceflinger/TransactionState.h +++ b/services/surfaceflinger/TransactionState.h @@ -89,7 +89,7 @@ struct TransactionState { void traverseStatesWithBuffersWhileTrue(Visitor&& visitor) { for (auto state = states.begin(); state != states.end();) { if (state->state.hasBufferChanges() && state->externalTexture && state->state.surface) { - int result = visitor(state->state, state->externalTexture); + int result = visitor(*state); if (result == STOP_TRAVERSAL) return; if (result == DELETE_AND_CONTINUE_TRAVERSAL) { state = states.erase(state); diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index afb8efbfff..e936ee0b29 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -1082,6 +1082,7 @@ TEST(TransactionHandlerTest, QueueTransaction) { transaction.applyToken = sp::make(); transaction.id = 42; handler.queueTransaction(std::move(transaction)); + handler.collectTransactions(); std::vector transactionsReadyToBeApplied = handler.flushTransactions(); EXPECT_EQ(transactionsReadyToBeApplied.size(), 1u); -- GitLab From 9a5463a2732651df0e7a6595ee07e6b7ca777805 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Sat, 17 Jun 2023 12:18:36 -0700 Subject: [PATCH 0214/1187] [sf] Update hdrlisteners to use new frontend Bug: 238781169 Test: play hdr content Change-Id: If2ae2a8d06e2a14093e906c47d998b04385f54b9 --- services/surfaceflinger/SurfaceFlinger.cpp | 70 +++++++++++++++------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 85b7c83a30..2bea826e15 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2776,31 +2776,55 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa for (auto& [compositionDisplay, listener] : hdrInfoListeners) { HdrLayerInfoReporter::HdrLayerInfo info; int32_t maxArea = 0; - mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) { - const auto layerFe = layer->getCompositionEngineLayerFE(); - const frontend::LayerSnapshot& snapshot = *layer->getLayerSnapshot(); - if (snapshot.isVisible && - compositionDisplay->includesLayer(snapshot.outputFilter)) { - if (isHdrLayer(snapshot)) { - const auto* outputLayer = - compositionDisplay->getOutputLayerForLayer(layerFe); - if (outputLayer) { - const float desiredHdrSdrRatio = snapshot.desiredHdrSdrRatio <= 1.f - ? std::numeric_limits::infinity() - : snapshot.desiredHdrSdrRatio; - info.mergeDesiredRatio(desiredHdrSdrRatio); - info.numberOfHdrLayers++; - const auto displayFrame = outputLayer->getState().displayFrame; - const int32_t area = displayFrame.width() * displayFrame.height(); - if (area > maxArea) { - maxArea = area; - info.maxW = displayFrame.width(); - info.maxH = displayFrame.height(); + auto updateInfoFn = + [&](const std::shared_ptr& compositionDisplay, + const frontend::LayerSnapshot& snapshot, const sp& layerFe) { + if (snapshot.isVisible && + compositionDisplay->includesLayer(snapshot.outputFilter)) { + if (isHdrLayer(snapshot)) { + const auto* outputLayer = + compositionDisplay->getOutputLayerForLayer(layerFe); + if (outputLayer) { + const float desiredHdrSdrRatio = + snapshot.desiredHdrSdrRatio <= 1.f + ? std::numeric_limits::infinity() + : snapshot.desiredHdrSdrRatio; + info.mergeDesiredRatio(desiredHdrSdrRatio); + info.numberOfHdrLayers++; + const auto displayFrame = outputLayer->getState().displayFrame; + const int32_t area = + displayFrame.width() * displayFrame.height(); + if (area > maxArea) { + maxArea = area; + info.maxW = displayFrame.width(); + info.maxH = displayFrame.height(); + } + } } } - } - } - }); + }; + + if (mConfig->layerLifecycleManagerEnabled) { + mLayerSnapshotBuilder.forEachVisibleSnapshot( + [&, compositionDisplay = compositionDisplay]( + std::unique_ptr& snapshot) { + auto it = mLegacyLayers.find(snapshot->sequence); + LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), + "Couldnt find layer object for %s", + snapshot->getDebugString().c_str()); + auto& legacyLayer = it->second; + sp layerFe = + legacyLayer->getCompositionEngineLayerFE(snapshot->path); + + updateInfoFn(compositionDisplay, *snapshot, layerFe); + }); + } else { + mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) { + const auto layerFe = layer->getCompositionEngineLayerFE(); + const frontend::LayerSnapshot& snapshot = *layer->getLayerSnapshot(); + updateInfoFn(compositionDisplay, snapshot, layerFe); + }); + } listener->dispatchHdrLayerInfo(info); } } -- GitLab From 1dd1333d9d5824db1f0b0f1a909627c7e3277bd1 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Mon, 26 Jun 2023 22:29:22 +0000 Subject: [PATCH 0215/1187] Bindgen 0.65.1 no longer supports size_t-is-usize The flag has been a default, and now is not accepted. Test: Treehugger, m rust Bug: 279198502 Bug: 276464273 Change-Id: I38ed1734ff0cdba21c4d63c784cd13512a6474f5 --- libs/binder/rust/rpcbinder/Android.bp | 1 - libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp | 1 - 2 files changed, 2 deletions(-) diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp index 0067a20484..788abc4617 100644 --- a/libs/binder/rust/rpcbinder/Android.bp +++ b/libs/binder/rust/rpcbinder/Android.bp @@ -75,7 +75,6 @@ rust_bindgen { visibility: [":__subpackages__"], source_stem: "bindings", bindgen_flags: [ - "--size_t-is-usize", "--blocklist-type", "AIBinder", "--raw-line", diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp index 43a309409d..5cac6475cf 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp +++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp @@ -11,7 +11,6 @@ rust_bindgen { source_stem: "bindings", visibility: [":__subpackages__"], bindgen_flags: [ - "--size_t-is-usize", "--allowlist-function", "createRandomParcel", "--allowlist-function", -- GitLab From 30db640d22bcfaa25d17c7c7bab8fa179d060a75 Mon Sep 17 00:00:00 2001 From: Lloyd Pique Date: Mon, 26 Jun 2023 18:56:51 +0000 Subject: [PATCH 0216/1187] Revert "SF: Introduce struct surfaceflinger::Config" Revert submission 23423266-SF-Config Reason for revert: UIBench Jank Regression reported in b/288665387 Reverted changes: /q/submissionid:23423266-SF-Config Change-Id: I0942f99fec1f211e607e3ff44da2dfa0e30d34c2 --- services/surfaceflinger/Android.bp | 1 - services/surfaceflinger/DisplayDevice.cpp | 24 +- services/surfaceflinger/DisplayDevice.h | 3 +- .../DisplayHardware/FramebufferSurface.cpp | 6 +- .../DisplayHardware/FramebufferSurface.h | 2 +- .../DisplayHardware/VirtualDisplaySurface.cpp | 4 +- .../DisplayHardware/VirtualDisplaySurface.h | 3 +- services/surfaceflinger/Layer.cpp | 6 +- services/surfaceflinger/LayerRenderArea.cpp | 2 +- .../surfaceflinger/RegionSamplingThread.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 325 ++++++++++++------ services/surfaceflinger/SurfaceFlinger.h | 113 +++++- .../surfaceflinger/SurfaceFlingerConfig.cpp | 162 --------- .../surfaceflinger/SurfaceFlingerConfig.h | 145 -------- .../surfaceflinger/SurfaceFlingerFactory.cpp | 11 +- .../surfaceflinger_displayhardware_fuzzer.cpp | 6 +- .../fuzzer/surfaceflinger_fuzzer.cpp | 30 +- .../fuzzer/surfaceflinger_fuzzers_utils.h | 16 +- .../fuzzer/surfaceflinger_service_fuzzer.cpp | 4 +- .../unittests/DisplayTransactionTest.cpp | 2 +- .../unittests/DisplayTransactionTestHelpers.h | 4 +- .../tests/unittests/SchedulerTest.cpp | 4 +- ...eFlinger_GetDisplayNativePrimariesTest.cpp | 4 +- ...nger_SetupNewDisplayDeviceInternalTest.cpp | 2 +- .../tests/unittests/TestableSurfaceFlinger.h | 17 +- 25 files changed, 405 insertions(+), 493 deletions(-) delete mode 100644 services/surfaceflinger/SurfaceFlingerConfig.cpp delete mode 100644 services/surfaceflinger/SurfaceFlingerConfig.h diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index bf07f7253f..89c80bc83a 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -195,7 +195,6 @@ filegroup { "ScreenCaptureOutput.cpp", "StartPropertySetThread.cpp", "SurfaceFlinger.cpp", - "SurfaceFlingerConfig.cpp", "SurfaceFlingerDefaultFactory.cpp", "Tracing/LayerTracing.cpp", "Tracing/TransactionTracing.cpp", diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 2789fa6bf2..f6ca9e2856 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -78,19 +78,18 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args) .setDisplayHeight(ANativeWindow_getHeight(args.nativeWindow.get())) .setNativeWindow(std::move(args.nativeWindow)) .setDisplaySurface(std::move(args.displaySurface)) - .setMaxTextureCacheSize(static_cast( - mFlinger->getConfig().maxFrameBufferAcquiredBuffers)) + .setMaxTextureCacheSize( + static_cast(SurfaceFlinger::maxFrameBufferAcquiredBuffers)) .build()); - if (!mFlinger->getConfig().disableClientCompositionCache && - mFlinger->getConfig().maxFrameBufferAcquiredBuffers > 0) { + if (!mFlinger->mDisableClientCompositionCache && + SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) { mCompositionDisplay->createClientCompositionCache( - static_cast(mFlinger->getConfig().maxFrameBufferAcquiredBuffers)); + static_cast(SurfaceFlinger::maxFrameBufferAcquiredBuffers)); } - mCompositionDisplay->setPredictCompositionStrategy( - mFlinger->getConfig().predictCompositionStrategy); - mCompositionDisplay->setTreat170mAsSrgb(mFlinger->getConfig().treat170mAsSrgb); + mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy); + mCompositionDisplay->setTreat170mAsSrgb(mFlinger->mTreat170mAsSrgb); mCompositionDisplay->createDisplayColorProfile( compositionengine::DisplayColorProfileCreationArgsBuilder() .setHasWideColorGamut(args.hasWideColorGamut) @@ -412,22 +411,23 @@ HdrCapabilities DisplayDevice::getHdrCapabilities() const { capabilities.getDesiredMinLuminance()); } -void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc) { +void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner, + bool showRenderRate, bool showInMiddle) { if (!enable) { mRefreshRateOverlay.reset(); return; } ftl::Flags features; - if (mFlinger->getConfig().refreshRateOverlay.showSpinner) { + if (showSpinner) { features |= RefreshRateOverlay::Features::Spinner; } - if (mFlinger->getConfig().refreshRateOverlay.showRenderRate) { + if (showRenderRate) { features |= RefreshRateOverlay::Features::RenderRate; } - if (mFlinger->getConfig().refreshRateOverlay.showInMiddle) { + if (showInMiddle) { features |= RefreshRateOverlay::Features::ShowInMiddle; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index d2a9fb685a..dc5f8a85af 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -236,7 +236,8 @@ public: } // Enables an overlay to be displayed with the current refresh rate - void enableRefreshRateOverlay(bool enable, bool setByHwc) REQUIRES(kMainThreadContext); + void enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner, bool showRenderRate, + bool showInMiddle) REQUIRES(kMainThreadContext); void updateRefreshRateOverlayRate(Fps displayFps, Fps renderFps, bool setByHwc = false); bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; } bool onKernelTimerChanged(std::optional, bool timerExpired); diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 14fff772db..ce602a8ad9 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -50,8 +50,7 @@ using ui::Dataspace; FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId, const sp& consumer, - const ui::Size& size, const ui::Size& maxSize, - int maxAcquiredBufferCount) + const ui::Size& size, const ui::Size& maxSize) : ConsumerBase(consumer), mDisplayId(displayId), mMaxSize(maxSize), @@ -71,7 +70,8 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displa GRALLOC_USAGE_HW_COMPOSER); const auto limitedSize = limitSize(size); mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height); - mConsumer->setMaxAcquiredBufferCount(maxAcquiredBufferCount); + mConsumer->setMaxAcquiredBufferCount( + SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1); for (size_t i = 0; i < sizeof(mHwcBufferIds) / sizeof(mHwcBufferIds[0]); ++i) { mHwcBufferIds[i] = UINT64_MAX; diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index 5a1d14fdfe..0b863daf47 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -42,7 +42,7 @@ class FramebufferSurface : public ConsumerBase, public compositionengine::Displa public: FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId, const sp& consumer, const ui::Size& size, - const ui::Size& maxSize, int maxAcquiredBufferCount); + const ui::Size& maxSize); virtual status_t beginFrame(bool mustRecompose); virtual status_t prepareFrame(CompositionType compositionType); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index d759c12612..d62075ec65 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -50,7 +50,7 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, VirtualDisplayId d const sp& sink, const sp& bqProducer, const sp& bqConsumer, - const std::string& name, bool useHwcForRgbToYuv) + const std::string& name) : ConsumerBase(bqConsumer), mHwc(hwc), mDisplayId(displayId), @@ -69,7 +69,7 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, VirtualDisplayId d mOutputFence(Fence::NO_FENCE), mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT), mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT), - mForceHwcCopy(useHwcForRgbToYuv) { + mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv) { mSource[SOURCE_SINK] = sink; mSource[SOURCE_SCRATCH] = bqProducer; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 8a56d5f7b5..be06e2bb10 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -77,8 +77,7 @@ class VirtualDisplaySurface : public compositionengine::DisplaySurface, public: VirtualDisplaySurface(HWComposer&, VirtualDisplayId, const sp& sink, const sp& bqProducer, - const sp& bqConsumer, const std::string& name, - bool useHwcForRgbToYuv); + const sp& bqConsumer, const std::string& name); // // DisplaySurface interface diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 8e1b8f2c00..5a010e8af6 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2562,7 +2562,7 @@ bool Layer::hasInputInfo() const { compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( const DisplayDevice* display) const { if (!display) return nullptr; - if (!mFlinger->getConfig().layerLifecycleManagerEnabled) { + if (!mFlinger->mLayerLifecycleManagerEnabled) { return display->getCompositionDisplay()->getOutputLayerForLayer( getCompositionEngineLayerFE()); } @@ -2907,7 +2907,7 @@ void Layer::onSurfaceFrameCreated( void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) { for (const auto& handle : mDrawingState.callbackHandles) { - if (mFlinger->getConfig().layerLifecycleManagerEnabled) { + if (mFlinger->mLayerLifecycleManagerEnabled) { handle->transformHint = mTransformHint; } else { handle->transformHint = mSkipReportingTransformHint @@ -3162,7 +3162,7 @@ bool Layer::setBuffer(std::shared_ptr& buffer, mFlinger->mTimeStats->setPostTime(layerId, mDrawingState.frameNumber, getName().c_str(), mOwnerUid, postTime, getGameMode()); - if (mFlinger->getConfig().legacyFrontEndEnabled) { + if (mFlinger->mLegacyFrontEndEnabled) { recordLayerHistoryBufferUpdate(getLayerProps()); } diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp index 9c1944b122..51d4ff854f 100644 --- a/services/surfaceflinger/LayerRenderArea.cpp +++ b/services/surfaceflinger/LayerRenderArea.cpp @@ -78,7 +78,7 @@ void LayerRenderArea::render(std::function drawLayers) { mTransform = mLayerTransform.inverse(); } - if (mFlinger.getConfig().layerLifecycleManagerEnabled) { + if (mFlinger.mLayerLifecycleManagerEnabled) { drawLayers(); return; } diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 03f3b402c9..8f658d5a09 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -322,7 +322,7 @@ void RegionSamplingThread::captureSample() { }; std::function>>()> getLayerSnapshots; - if (mFlinger.getConfig().layerLifecycleManagerEnabled) { + if (mFlinger.mLayerLifecycleManagerEnabled) { auto filterFn = [&](const frontend::LayerSnapshot& snapshot, bool& outStopTraversal) -> bool { const Rect bounds = diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 60c09049cf..ba13293a8f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -214,6 +214,16 @@ static constexpr int FOUR_K_HEIGHT = 2160; // TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity. constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV; +float getDensityFromProperty(const char* property, bool required) { + char value[PROPERTY_VALUE_MAX]; + const float density = property_get(property, value, nullptr) > 0 ? std::atof(value) : 0.f; + if (!density && required) { + ALOGE("%s must be defined as a build property", property); + return FALLBACK_DENSITY; + } + return density; +} + // Currently we only support V0_SRGB and DISPLAY_P3 as composition preference. bool validateCompositionDataspace(Dataspace dataspace) { return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3; @@ -312,6 +322,18 @@ const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled static const int MAX_TRACING_MEMORY = 1024 * 1024 * 1024; // 1GB // --------------------------------------------------------------------------- +int64_t SurfaceFlinger::dispSyncPresentTimeOffset; +bool SurfaceFlinger::useHwcForRgbToYuv; +bool SurfaceFlinger::hasSyncFramework; +int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers; +int64_t SurfaceFlinger::minAcquiredBuffers = 1; +uint32_t SurfaceFlinger::maxGraphicsWidth; +uint32_t SurfaceFlinger::maxGraphicsHeight; +bool SurfaceFlinger::useContextPriority; +Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB; +ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888; +Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB; +ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; LatchUnsignaledConfig SurfaceFlinger::enableLatchUnsignaledConfig; std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { @@ -338,35 +360,136 @@ bool callingThreadHasPermission(const String16& permission) { ui::Transform::RotationFlags SurfaceFlinger::sActiveDisplayRotationFlags = ui::Transform::ROT_0; -SurfaceFlinger::SurfaceFlinger(surfaceflinger::Config& config) - : mConfig(&config), - mDebugFlashDelay(base::GetUintProperty("debug.sf.showupdates"s, 0u)), +SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) + : mFactory(factory), + mPid(getpid()), mTimeStats(std::make_shared()), - mFrameTracer(mConfig->factory->createFrameTracer()), - mFrameTimeline(mConfig->factory->createFrameTimeline(mTimeStats, mConfig->pid)), - mCompositionEngine(mConfig->factory->createCompositionEngine()), + mFrameTracer(mFactory.createFrameTracer()), + mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, mPid)), + mCompositionEngine(mFactory.createCompositionEngine()), + mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)), mTunnelModeEnabledReporter(sp::make()), + mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)), + mInternalDisplayDensity( + getDensityFromProperty("ro.sf.lcd_density", !mEmulatedDisplayDensity)), mPowerAdvisor(std::make_unique(*this)), mWindowInfosListenerInvoker(sp::make()) { + ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str()); +} + +SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) { ATRACE_CALL(); - ALOGI("SurfaceFlinger is starting."); - ALOGI("Using HWComposer service: %s", mConfig->hwcServiceName.c_str()); - ALOGI_IF(mConfig->backpressureGpuComposition, "Enabling backpressure for GPU composition"); - ALOGI_IF(!mConfig->supportsBlur, "Disabling blur effects, they are not supported."); - ALOGI_IF(mConfig->trebleTestingOverride, "Enabling Treble testing override"); + ALOGI("SurfaceFlinger is starting"); + + hasSyncFramework = running_without_sync_framework(true); + + dispSyncPresentTimeOffset = present_time_offset_from_vsync_ns(0); + + useHwcForRgbToYuv = force_hwc_copy_for_virtual_displays(false); + + maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2); + minAcquiredBuffers = + SurfaceFlingerProperties::min_acquired_buffers().value_or(minAcquiredBuffers); + + maxGraphicsWidth = std::max(max_graphics_width(0), 0); + maxGraphicsHeight = std::max(max_graphics_height(0), 0); + + mSupportsWideColor = has_wide_color_display(false); + mDefaultCompositionDataspace = + static_cast(default_composition_dataspace(Dataspace::V0_SRGB)); + mWideColorGamutCompositionDataspace = static_cast(wcg_composition_dataspace( + mSupportsWideColor ? Dataspace::DISPLAY_P3 : Dataspace::V0_SRGB)); + defaultCompositionDataspace = mDefaultCompositionDataspace; + wideColorGamutCompositionDataspace = mWideColorGamutCompositionDataspace; + defaultCompositionPixelFormat = static_cast( + default_composition_pixel_format(ui::PixelFormat::RGBA_8888)); + wideColorGamutCompositionPixelFormat = + static_cast(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888)); + + mColorSpaceAgnosticDataspace = + static_cast(color_space_agnostic_dataspace(Dataspace::UNKNOWN)); + + mLayerCachingEnabled = [] { + const bool enable = + android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false); + return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable); + }(); + + useContextPriority = use_context_priority(true); + + mInternalDisplayPrimaries = sysprop::getDisplayNativePrimaries(); - if (mConfig->trebleTestingOverride) { + // debugging stuff... + char value[PROPERTY_VALUE_MAX]; + + property_get("ro.build.type", value, "user"); + mIsUserBuild = strcmp(value, "user") == 0; + + mDebugFlashDelay = base::GetUintProperty("debug.sf.showupdates"s, 0u); + + mBackpressureGpuComposition = base::GetBoolProperty("debug.sf.enable_gl_backpressure"s, true); + ALOGI_IF(mBackpressureGpuComposition, "Enabling backpressure for GPU composition"); + + property_get("ro.surface_flinger.supports_background_blur", value, "0"); + bool supportsBlurs = atoi(value); + mSupportsBlur = supportsBlurs; + ALOGI_IF(!mSupportsBlur, "Disabling blur effects, they are not supported."); + + const size_t defaultListSize = MAX_LAYERS; + auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize)); + mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize; + mGraphicBufferProducerListSizeLogThreshold = + std::max(static_cast(0.95 * + static_cast(mMaxGraphicBufferProducerListSize)), + 1); + + property_get("debug.sf.luma_sampling", value, "1"); + mLumaSampling = atoi(value); + + property_get("debug.sf.disable_client_composition_cache", value, "0"); + mDisableClientCompositionCache = atoi(value); + + property_get("debug.sf.predict_hwc_composition_strategy", value, "1"); + mPredictCompositionStrategy = atoi(value); + + property_get("debug.sf.treat_170m_as_sRGB", value, "0"); + mTreat170mAsSrgb = atoi(value); + + mIgnoreHwcPhysicalDisplayOrientation = + base::GetBoolProperty("debug.sf.ignore_hwc_physical_display_orientation"s, false); + + // We should be reading 'persist.sys.sf.color_saturation' here + // but since /data may be encrypted, we need to wait until after vold + // comes online to attempt to read the property. The property is + // instead read after the boot animation + + if (base::GetBoolProperty("debug.sf.treble_testing_override"s, false)) { // Without the override SurfaceFlinger cannot connect to HIDL // services that are not listed in the manifests. Considered // deriving the setting from the set service name, but it // would be brittle if the name that's not 'default' is used // for production purposes later on. + ALOGI("Enabling Treble testing override"); android::hardware::details::setTrebleTestingOverride(true); } - if (!mConfig->isUserBuild && mConfig->enableTransactionTracing) { + // TODO (b/270966065) Update the HWC based refresh rate overlay to support spinner + mRefreshRateOverlaySpinner = property_get_bool("debug.sf.show_refresh_rate_overlay_spinner", 0); + mRefreshRateOverlayRenderRate = + property_get_bool("debug.sf.show_refresh_rate_overlay_render_rate", 0); + mRefreshRateOverlayShowInMiddle = + property_get_bool("debug.sf.show_refresh_rate_overlay_in_middle", 0); + + if (!mIsUserBuild && base::GetBoolProperty("debug.sf.enable_transaction_tracing"s, true)) { mTransactionTracing.emplace(); } + + mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false); + + mLayerLifecycleManagerEnabled = + base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false); + mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled || + base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); } LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { @@ -693,18 +816,17 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { // Get a RenderEngine for the given display / config (can't fail) // TODO(b/77156734): We need to stop casting and use HAL types when possible. // Sending maxFrameBufferAcquiredBuffers as the cache size is tightly tuned to single-display. - auto builder = - renderengine::RenderEngineCreationArgs::Builder() - .setPixelFormat(static_cast(mConfig->defaultCompositionPixelFormat)) - .setImageCacheSize(mConfig->maxFrameBufferAcquiredBuffers) - .setUseColorManagerment(useColorManagement) - .setEnableProtectedContext(enable_protected_contents(false)) - .setPrecacheToneMapperShaderOnly(false) - .setSupportsBackgroundBlur(mConfig->supportsBlur) - .setContextPriority( - mConfig->useContextPriority - ? renderengine::RenderEngine::ContextPriority::REALTIME - : renderengine::RenderEngine::ContextPriority::MEDIUM); + auto builder = renderengine::RenderEngineCreationArgs::Builder() + .setPixelFormat(static_cast(defaultCompositionPixelFormat)) + .setImageCacheSize(maxFrameBufferAcquiredBuffers) + .setUseColorManagerment(useColorManagement) + .setEnableProtectedContext(enable_protected_contents(false)) + .setPrecacheToneMapperShaderOnly(false) + .setSupportsBackgroundBlur(mSupportsBlur) + .setContextPriority( + useContextPriority + ? renderengine::RenderEngine::ContextPriority::REALTIME + : renderengine::RenderEngine::ContextPriority::MEDIUM); if (auto type = chooseRenderEngineTypeViaSysProp()) { builder.setRenderEngineType(type.value()); } @@ -719,7 +841,7 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { } mCompositionEngine->setTimeStats(mTimeStats); - mCompositionEngine->setHwComposer(getFactory().createHWComposer(mConfig->hwcServiceName)); + mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName)); mCompositionEngine->getHwComposer().setCallback(*this); ClientCache::getInstance().setRenderEngine(&getRenderEngine()); @@ -909,11 +1031,11 @@ status_t SurfaceFlinger::getStaticDisplayInfo(int64_t displayId, ui::StaticDispl info->connectionType = snapshot.connectionType(); info->deviceProductInfo = snapshot.deviceProductInfo(); - if (mConfig->emulatedDisplayDensity) { - info->density = mConfig->emulatedDisplayDensity; + if (mEmulatedDisplayDensity) { + info->density = mEmulatedDisplayDensity; } else { info->density = info->connectionType == ui::DisplayConnectionType::Internal - ? mConfig->internalDisplayDensity + ? mInternalDisplayDensity : FALLBACK_DENSITY; } info->density /= ACONFIGURATION_DENSITY_MEDIUM; @@ -976,7 +1098,7 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info info->supportedDisplayModes.push_back(outMode); } - info->supportedColorModes = snapshot.filterColorModes(mConfig->supportsWideColor); + info->supportedColorModes = snapshot.filterColorModes(mSupportsWideColor); const PhysicalDisplayId displayId = snapshot.displayId(); @@ -1374,7 +1496,7 @@ status_t SurfaceFlinger::getDisplayNativePrimaries(const sp& displayTok } // TODO(b/229846990): For now, assume that all internal displays have the same primaries. - primaries = mConfig->internalDisplayPrimaries; + primaries = mInternalDisplayPrimaries; return NO_ERROR; } @@ -1398,7 +1520,7 @@ status_t SurfaceFlinger::setActiveColorMode(const sp& displayToken, ui: const auto& [display, snapshotRef] = *displayOpt; const auto& snapshot = snapshotRef.get(); - const auto modes = snapshot.filterColorModes(mConfig->supportsWideColor); + const auto modes = snapshot.filterColorModes(mSupportsWideColor); const bool exists = std::find(modes.begin(), modes.end(), mode) != modes.end(); if (mode < ui::ColorMode::NATIVE || !exists) { @@ -1704,7 +1826,7 @@ status_t SurfaceFlinger::isWideColorDisplay(const sp& displayToken, } *outIsWideColorDisplay = - display->isPrimary() ? mConfig->supportsWideColor : display->hasWideColorGamut(); + display->isPrimary() ? mSupportsWideColor : display->hasWideColorGamut(); return NO_ERROR; } @@ -1725,12 +1847,10 @@ status_t SurfaceFlinger::getCompositionPreference( Dataspace* outDataspace, ui::PixelFormat* outPixelFormat, Dataspace* outWideColorGamutDataspace, ui::PixelFormat* outWideColorGamutPixelFormat) const { - *outDataspace = - mOverrideDefaultCompositionDataspace.value_or(mConfig->defaultCompositionDataspace); - *outPixelFormat = mConfig->defaultCompositionPixelFormat; - *outWideColorGamutDataspace = mOverrideWideColorGamutCompositionDataspace.value_or( - mConfig->wideColorGamutCompositionDataspace); - *outWideColorGamutPixelFormat = mConfig->wideColorGamutCompositionPixelFormat; + *outDataspace = mDefaultCompositionDataspace; + *outPixelFormat = defaultCompositionPixelFormat; + *outWideColorGamutDataspace = mWideColorGamutCompositionDataspace; + *outWideColorGamutPixelFormat = wideColorGamutCompositionPixelFormat; return NO_ERROR; } @@ -2193,7 +2313,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, .displays = mFrontEndDisplayInfos, .displayChanges = mFrontEndDisplayInfosChanged, .globalShadowSettings = mDrawingState.globalShadowSettings, - .supportsBlur = mConfig->supportsBlur, + .supportsBlur = mSupportsBlur, .forceFullDamage = mForceFullDamage, .supportedLayerGenericMetadata = getHwComposer().getSupportedLayerGenericMetadata(), @@ -2213,7 +2333,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, mustComposite |= mLayerLifecycleManager.getGlobalChanges().get() != 0; bool newDataLatched = false; - if (!mConfig->legacyFrontEndEnabled) { + if (!mLegacyFrontEndEnabled) { ATRACE_NAME("DisplayCallbackAndStatsUpdates"); applyTransactions(update.transactions, vsyncId); const nsecs_t latchTime = systemTime(); @@ -2307,7 +2427,7 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) } if (pacesetterFrameTarget.isFramePending()) { - if (mConfig->backpressureGpuComposition || pacesetterFrameTarget.didMissHwcFrame()) { + if (mBackpressureGpuComposition || pacesetterFrameTarget.didMissHwcFrame()) { scheduleCommit(FrameHint::kNone); return false; } @@ -2338,7 +2458,7 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) mPowerAdvisor->updateTargetWorkDuration(idealVsyncPeriod); } - if (mConfig->refreshRateOverlay.showSpinner) { + if (mRefreshRateOverlaySpinner) { Mutex::Autolock lock(mStateLock); if (const auto display = getDefaultDisplayDeviceLocked()) { display->animateRefreshRateOverlay(); @@ -2354,12 +2474,12 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) const bool flushTransactions = clearTransactionFlags(eTransactionFlushNeeded); bool transactionsAreEmpty; - if (mConfig->legacyFrontEndEnabled) { + if (mLegacyFrontEndEnabled) { mustComposite |= updateLayerSnapshotsLegacy(vsyncId, pacesetterFrameTarget.frameBeginTime().ns(), flushTransactions, transactionsAreEmpty); } - if (mConfig->layerLifecycleManagerEnabled) { + if (mLayerLifecycleManagerEnabled) { mustComposite |= updateLayerSnapshots(vsyncId, pacesetterFrameTarget.frameBeginTime().ns(), flushTransactions, transactionsAreEmpty); @@ -2465,7 +2585,7 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr refreshArgs.outputColorSetting = useColorManagement ? mDisplayColorSetting : compositionengine::OutputColorSetting::kUnmanaged; - refreshArgs.colorSpaceAgnosticDataspace = mConfig->colorSpaceAgnosticDataspace; + refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace; refreshArgs.forceOutputColorMode = mForceColorMode; refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty; @@ -2619,7 +2739,7 @@ bool SurfaceFlinger::isHdrLayer(const frontend::LayerSnapshot& snapshot) const { // Even though the camera layer may be using an HDR transfer function or otherwise be "HDR" // the device may need to avoid boosting the brightness as a result of these layers to // reduce power consumption during camera recording - if (mConfig->ignoreHdrCameraLayers) { + if (mIgnoreHdrCameraLayers) { if (snapshot.externalTexture && (snapshot.externalTexture->getUsage() & GRALLOC_USAGE_HW_CAMERA_WRITE) != 0) { return false; @@ -2650,7 +2770,7 @@ ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(DisplayId displayId, if (!id) { return ui::ROTATION_0; } - if (!mConfig->ignoreHwcPhysicalDisplayOrientation && + if (!mIgnoreHwcPhysicalDisplayOrientation && getHwComposer().getComposer()->isSupported( Hwc2::Composer::OptionalFeature::PhysicalDisplayOrientation)) { switch (getHwComposer().getPhysicalDisplayOrientation(*id)) { @@ -2817,7 +2937,7 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa } }; - if (mConfig->layerLifecycleManagerEnabled) { + if (mLayerLifecycleManagerEnabled) { mLayerSnapshotBuilder.forEachVisibleSnapshot( [&, compositionDisplay = compositionDisplay]( std::unique_ptr& snapshot) { @@ -2869,7 +2989,7 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa const bool isDisplayConnected = defaultDisplay && getHwComposer().isConnected(defaultDisplay->getPhysicalId()); - if (!mConfig->hasSyncFramework) { + if (!hasSyncFramework) { if (isDisplayConnected && defaultDisplay->isPoweredOn()) { mScheduler->enableHardwareVsync(defaultDisplay->getPhysicalId()); } @@ -2910,7 +3030,7 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa if (!layer->hasTrustedPresentationListener()) { return; } - const frontend::LayerSnapshot* snapshot = mConfig->layerLifecycleManagerEnabled + const frontend::LayerSnapshot* snapshot = mLayerLifecycleManagerEnabled ? mLayerSnapshotBuilder.getSnapshot(layer->sequence) : layer->getLayerSnapshot(); std::optional displayOpt = std::nullopt; @@ -3305,7 +3425,7 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, builder.setPowerAdvisor(mPowerAdvisor.get()); builder.setName(state.displayName); auto compositionDisplay = getCompositionEngine().createDisplay(builder.build()); - compositionDisplay->setLayerCachingEnabled(mConfig->layerCachingEnabled); + compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled); sp displaySurface; sp producer; @@ -3317,8 +3437,7 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, const auto displayId = VirtualDisplayId::tryCast(compositionDisplay->getId()); LOG_FATAL_IF(!displayId); auto surface = sp::make(getHwComposer(), *displayId, state.surface, - bqProducer, bqConsumer, state.displayName, - mConfig->useHwcForRgbToYuv); + bqProducer, bqConsumer, state.displayName); displaySurface = surface; producer = std::move(surface); } else { @@ -3328,11 +3447,10 @@ void SurfaceFlinger::processDisplayAdded(const wp& displayToken, state.surface.get()); const auto displayId = PhysicalDisplayId::tryCast(compositionDisplay->getId()); LOG_FATAL_IF(!displayId); - displaySurface = sp::make(getHwComposer(), *displayId, bqConsumer, - state.physical->activeMode->getResolution(), - ui::Size(mConfig->maxGraphicsWidth, - mConfig->maxGraphicsHeight), - mConfig->maxFrameBufferAcquiredBuffers); + displaySurface = + sp::make(getHwComposer(), *displayId, bqConsumer, + state.physical->activeMode->getResolution(), + ui::Size(maxGraphicsWidth, maxGraphicsHeight)); producer = bqProducer; } @@ -3513,7 +3631,7 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { // Commit display transactions. const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded; mFrontEndDisplayInfosChanged = displayTransactionNeeded; - if (displayTransactionNeeded && !mConfig->layerLifecycleManagerEnabled) { + if (displayTransactionNeeded && !mLayerLifecycleManagerEnabled) { processDisplayChangesLocked(); mFrontEndDisplayInfos.clear(); for (const auto& [_, display] : mDisplays) { @@ -3713,7 +3831,7 @@ void SurfaceFlinger::buildWindowInfos(std::vector& outWindowInfos, outWindowInfos.reserve(sNumWindowInfos); sNumWindowInfos = 0; - if (mConfig->layerLifecycleManagerEnabled) { + if (mLayerLifecycleManagerEnabled) { mLayerSnapshotBuilder.forEachInputSnapshot( [&outWindowInfos](const frontend::LayerSnapshot& snapshot) { outWindowInfos.push_back(snapshot.inputInfo); @@ -3837,7 +3955,7 @@ void SurfaceFlinger::initScheduler(const sp& display) { if (display->refreshRateSelector().kernelIdleTimerController()) { features |= Feature::kKernelIdleTimer; } - if (mConfig->backpressureGpuComposition) { + if (mBackpressureGpuComposition) { features |= Feature::kBackpressureGpuComposition; } @@ -4383,7 +4501,7 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC void SurfaceFlinger::addTransactionReadyFilters() { mTransactionHandler.addTransactionReadyFilter( std::bind(&SurfaceFlinger::transactionReadyTimelineCheck, this, std::placeholders::_1)); - if (mConfig->layerLifecycleManagerEnabled) { + if (mLayerLifecycleManagerEnabled) { mTransactionHandler.addTransactionReadyFilter( std::bind(&SurfaceFlinger::transactionReadyBufferCheck, this, std::placeholders::_1)); @@ -4614,7 +4732,7 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin const std::vector& listenerCallbacks, int originPid, int originUid, uint64_t transactionId) { uint32_t transactionFlags = 0; - if (!mConfig->layerLifecycleManagerEnabled) { + if (!mLayerLifecycleManagerEnabled) { for (DisplayState& display : displays) { transactionFlags |= setDisplayStateLocked(display); } @@ -4629,12 +4747,12 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin uint32_t clientStateFlags = 0; for (auto& resolvedState : states) { - if (mConfig->legacyFrontEndEnabled) { + if (mLegacyFrontEndEnabled) { clientStateFlags |= setClientStateLocked(frameTimelineInfo, resolvedState, desiredPresentTime, isAutoTimestamp, postTime, transactionId); - } else /* mConfig->layerLifecycleManagerEnabled */ { + } else /*mLayerLifecycleManagerEnabled*/ { clientStateFlags |= updateLayerCallbacksAndStats(frameTimelineInfo, resolvedState, desiredPresentTime, isAutoTimestamp, postTime, transactionId); @@ -4708,7 +4826,7 @@ bool SurfaceFlinger::applyAndCommitDisplayTransactionStates( } mFrontEndDisplayInfosChanged = mTransactionFlags & eDisplayTransactionNeeded; - if (mFrontEndDisplayInfosChanged && !mConfig->legacyFrontEndEnabled) { + if (mFrontEndDisplayInfosChanged && !mLegacyFrontEndEnabled) { processDisplayChangesLocked(); mFrontEndDisplayInfos.clear(); for (const auto& [_, display] : mDisplays) { @@ -4911,7 +5029,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (layer->setCornerRadius(s.cornerRadius)) flags |= eTraversalNeeded; } - if (what & layer_state_t::eBackgroundBlurRadiusChanged && mConfig->supportsBlur) { + if (what & layer_state_t::eBackgroundBlurRadiusChanged && mSupportsBlur) { if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded; } if (what & layer_state_t::eBlurRegionsChanged) { @@ -5315,7 +5433,7 @@ status_t SurfaceFlinger::mirrorDisplay(DisplayId displayId, const LayerCreationA return result; } - if (mConfig->legacyFrontEndEnabled) { + if (mLegacyFrontEndEnabled) { std::scoped_lock lock(mMirrorDisplayLock); mMirrorDisplays.emplace_back(layerStack, outResult.handle, args.client); } @@ -5422,10 +5540,9 @@ void SurfaceFlinger::initializeDisplays() { const nsecs_t now = systemTime(); state.desiredPresentTime = now; state.postTime = now; - state.originPid = mConfig->pid; + state.originPid = mPid; state.originUid = static_cast(getuid()); - const uint64_t transactionId = - (static_cast(mConfig->pid) << 32) | mUniqueTransactionId++; + const uint64_t transactionId = (static_cast(mPid) << 32) | mUniqueTransactionId++; state.id = transactionId; // reset screen orientation and use primary layer stack @@ -5445,7 +5562,7 @@ void SurfaceFlinger::initializeDisplays() { std::vector transactions; transactions.emplace_back(state); - if (mConfig->legacyFrontEndEnabled) { + if (mLegacyFrontEndEnabled) { applyTransactions(transactions, VsyncId{0}); } else { applyAndCommitDisplayTransactionStates(transactions); @@ -5741,13 +5858,13 @@ void SurfaceFlinger::logFrameStats(TimePoint now) { void SurfaceFlinger::appendSfConfigString(std::string& result) const { result.append(" [sf"); - StringAppendF(&result, " PRESENT_TIME_OFFSET=%" PRId64, mConfig->dispSyncPresentTimeOffset); - StringAppendF(&result, " FORCE_HWC_FOR_RBG_TO_YUV=%d", mConfig->useHwcForRgbToYuv); + StringAppendF(&result, " PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset); + StringAppendF(&result, " FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv); StringAppendF(&result, " MAX_VIRT_DISPLAY_DIM=%zu", getHwComposer().getMaxVirtualDisplayDimension()); - StringAppendF(&result, " RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !mConfig->hasSyncFramework); + StringAppendF(&result, " RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework); StringAppendF(&result, " NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64, - mConfig->maxFrameBufferAcquiredBuffers); + maxFrameBufferAcquiredBuffers); result.append("]"); } @@ -5767,7 +5884,7 @@ void SurfaceFlinger::dumpScheduler(std::string& result) const { StringAppendF(&result, " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n", - mConfig->dispSyncPresentTimeOffset, getVsyncPeriodFromHWC()); + dispSyncPresentTimeOffset, getVsyncPeriodFromHWC()); } void SurfaceFlinger::dumpEvents(std::string& result) const { @@ -5866,7 +5983,7 @@ void SurfaceFlinger::dumpRawDisplayIdentificationData(const DumpArgs& args, } void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { - StringAppendF(&result, "Device supports wide color: %d\n", mConfig->supportsWideColor); + StringAppendF(&result, "Device supports wide color: %d\n", mSupportsWideColor); StringAppendF(&result, "Device uses color management: %d\n", useColorManagement); StringAppendF(&result, "DisplayColorSetting: %s\n", decodeDisplayColorSetting(mDisplayColorSetting).c_str()); @@ -5900,7 +6017,7 @@ LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const { } } - if (mConfig->legacyFrontEndEnabled) { + if (mLegacyFrontEndEnabled) { LayersProto layersProto; for (const sp& layer : mDrawingState.layersSortedByZ) { if (stackIdsToSkip.find(layer->getLayerStack().id) != stackIdsToSkip.end()) { @@ -6557,7 +6674,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r if (!validateCompositionDataspace(dataspace)) { return BAD_VALUE; } - mOverrideDefaultCompositionDataspace = dataspace; + mDefaultCompositionDataspace = dataspace; } n = data.readInt32(); if (n) { @@ -6565,12 +6682,12 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r if (!validateCompositionDataspace(dataspace)) { return BAD_VALUE; } - mOverrideWideColorGamutCompositionDataspace = dataspace; + mWideColorGamutCompositionDataspace = dataspace; } } else { - // Reset data space overrides. - mOverrideDefaultCompositionDataspace.reset(); - mOverrideWideColorGamutCompositionDataspace.reset(); + // restore composition data space. + mDefaultCompositionDataspace = defaultCompositionDataspace; + mWideColorGamutCompositionDataspace = wideColorGamutCompositionDataspace; } return NO_ERROR; } @@ -6709,10 +6826,10 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } { Mutex::Autolock lock(mStateLock); - mConfig->layerCachingEnabled = n != 0; + mLayerCachingEnabled = n != 0; for (const auto& [_, display] : mDisplays) { if (!inputId || *inputId == display->getPhysicalId()) { - display->enableLayerCaching(mConfig->layerCachingEnabled); + display->enableLayerCaching(mLayerCachingEnabled); } } } @@ -7037,7 +7154,7 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, }); GetLayerSnapshotsFunction getLayerSnapshots; - if (mConfig->layerLifecycleManagerEnabled) { + if (mLayerLifecycleManagerEnabled) { getLayerSnapshots = getLayerSnapshotsForScreenshots(layerStack, args.uid, std::move(excludeLayerIds)); } else { @@ -7080,7 +7197,7 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId, }); GetLayerSnapshotsFunction getLayerSnapshots; - if (mConfig->layerLifecycleManagerEnabled) { + if (mLayerLifecycleManagerEnabled) { getLayerSnapshots = getLayerSnapshotsForScreenshots(layerStack, CaptureArgs::UNSET_UID, /*snapshotFilterFn=*/nullptr); } else { @@ -7176,7 +7293,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, RenderAreaFuture renderAreaFuture = ftl::defer([=]() -> std::unique_ptr { ui::Transform layerTransform; Rect layerBufferSize; - if (mConfig->layerLifecycleManagerEnabled) { + if (mLayerLifecycleManagerEnabled) { frontend::LayerSnapshot* snapshot = mLayerSnapshotBuilder.getSnapshot(parent->getSequence()); if (!snapshot) { @@ -7196,7 +7313,7 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, args.hintForSeamlessTransition); }); GetLayerSnapshotsFunction getLayerSnapshots; - if (mConfig->layerLifecycleManagerEnabled) { + if (mLayerLifecycleManagerEnabled) { std::optional parentCrop = std::nullopt; if (args.childrenOnly) { parentCrop = crop.isEmpty() ? FloatRect(0, 0, reqSize.width, reqSize.height) @@ -7449,7 +7566,7 @@ ftl::SharedFuture SurfaceFlinger::renderScreenImpl( layerStack, regionSampling, renderArea = std::move(renderArea), renderIntent]() -> FenceResult { std::unique_ptr compositionEngine = - mConfig->factory->createCompositionEngine(); + mFactory.createCompositionEngine(); compositionEngine->setRenderEngine(mRenderEngine.get()); compositionengine::Output::ColorProfile colorProfile{.dataspace = dataspace, @@ -7519,7 +7636,7 @@ ftl::SharedFuture SurfaceFlinger::renderScreenImpl( } void SurfaceFlinger::traverseLegacyLayers(const LayerVector::Visitor& visitor) const { - if (mConfig->layerLifecycleManagerEnabled) { + if (mLayerLifecycleManagerEnabled) { for (auto& layer : mLegacyLayers) { visitor(layer.second.get()); } @@ -7841,7 +7958,9 @@ void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { } if (const auto device = getDisplayDeviceLocked(id)) { - device->enableRefreshRateOverlay(enable, setByHwc); + device->enableRefreshRateOverlay(enable, setByHwc, mRefreshRateOverlaySpinner, + mRefreshRateOverlayRenderRate, + mRefreshRateOverlayShowInMiddle); } } } @@ -7852,12 +7971,12 @@ int SurfaceFlinger::getGpuContextPriority() { } int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate, - std::chrono::nanoseconds presentLatency) const { + std::chrono::nanoseconds presentLatency) { auto pipelineDepth = presentLatency.count() / refreshRate.getPeriodNsecs(); if (presentLatency.count() % refreshRate.getPeriodNsecs()) { pipelineDepth++; } - return std::max(mConfig->minAcquiredBuffers, static_cast(pipelineDepth - 1)); + return std::max(minAcquiredBuffers, static_cast(pipelineDepth - 1)); } status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const { @@ -7939,7 +8058,7 @@ void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state, Vs } void SurfaceFlinger::sample() { - if (!mConfig->lumaSampling || !mRegionSamplingThread) { + if (!mLumaSampling || !mRegionSamplingThread) { return; } @@ -8131,7 +8250,7 @@ void SurfaceFlinger::updateLayerMetadataSnapshot() { void SurfaceFlinger::moveSnapshotsFromCompositionArgs( compositionengine::CompositionRefreshArgs& refreshArgs, const std::vector>& layers) { - if (mConfig->layerLifecycleManagerEnabled) { + if (mLayerLifecycleManagerEnabled) { std::vector>& snapshots = mLayerSnapshotBuilder.getSnapshots(); for (auto [_, layerFE] : layers) { @@ -8139,7 +8258,7 @@ void SurfaceFlinger::moveSnapshotsFromCompositionArgs( snapshots[i] = std::move(layerFE->mSnapshot); } } - if (mConfig->legacyFrontEndEnabled && !mConfig->layerLifecycleManagerEnabled) { + if (mLegacyFrontEndEnabled && !mLayerLifecycleManagerEnabled) { for (auto [layer, layerFE] : layers) { layer->updateLayerSnapshot(std::move(layerFE->mSnapshot)); } @@ -8149,7 +8268,7 @@ void SurfaceFlinger::moveSnapshotsFromCompositionArgs( std::vector> SurfaceFlinger::moveSnapshotsToCompositionArgs( compositionengine::CompositionRefreshArgs& refreshArgs, bool cursorOnly) { std::vector> layers; - if (mConfig->layerLifecycleManagerEnabled) { + if (mLayerLifecycleManagerEnabled) { nsecs_t currentTime = systemTime(); mLayerSnapshotBuilder.forEachVisibleSnapshot( [&](std::unique_ptr& snapshot) { @@ -8175,7 +8294,7 @@ std::vector> SurfaceFlinger::moveSnapshotsToComposit layers.emplace_back(legacyLayer.get(), layerFE.get()); }); } - if (mConfig->legacyFrontEndEnabled && !mConfig->layerLifecycleManagerEnabled) { + if (mLegacyFrontEndEnabled && !mLayerLifecycleManagerEnabled) { auto moveSnapshots = [&layers, &refreshArgs, cursorOnly](Layer* layer) { if (const auto& layerFE = layer->getCompositionEngineLayerFE()) { if (cursorOnly && @@ -8267,7 +8386,7 @@ SurfaceFlinger::getLayerSnapshotsForScreenshots(std::optional la .displays = mFrontEndDisplayInfos, .displayChanges = true, .globalShadowSettings = mDrawingState.globalShadowSettings, - .supportsBlur = mConfig->supportsBlur, + .supportsBlur = mSupportsBlur, .forceFullDamage = mForceFullDamage, .excludeLayerIds = std::move(excludeLayerIds), .supportedLayerGenericMetadata = @@ -8301,7 +8420,7 @@ SurfaceFlinger::getLayerSnapshotsForScreenshots(uint32_t rootLayerId, uint32_t u .displays = mFrontEndDisplayInfos, .displayChanges = true, .globalShadowSettings = mDrawingState.globalShadowSettings, - .supportsBlur = mConfig->supportsBlur, + .supportsBlur = mSupportsBlur, .forceFullDamage = mForceFullDamage, .parentCrop = parentCrop, .excludeLayerIds = std::move(excludeLayerIds), diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 55e1b758b7..5c57abdb32 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -63,7 +63,6 @@ #include #include -#include "Client.h" #include "Display/PhysicalDisplay.h" #include "DisplayDevice.h" #include "DisplayHardware/HWC2.h" @@ -82,7 +81,6 @@ #include "Scheduler/RefreshRateSelector.h" #include "Scheduler/RefreshRateStats.h" #include "Scheduler/Scheduler.h" -#include "SurfaceFlingerConfig.h" #include "SurfaceFlingerFactory.h" #include "ThreadContext.h" #include "Tracing/LayerTracing.h" @@ -109,6 +107,7 @@ #include #include +#include "Client.h" using namespace android::surfaceflinger; @@ -198,7 +197,10 @@ class SurfaceFlinger : public BnSurfaceComposer, private scheduler::ISchedulerCallback, private compositionengine::ICEPowerCallback { public: - explicit SurfaceFlinger(surfaceflinger::Config&) ANDROID_API; + struct SkipInitializationTag {}; + + 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; @@ -208,9 +210,51 @@ public: static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; } + // If fences from sync Framework are supported. + static bool hasSyncFramework; + + // The offset in nanoseconds to use when VsyncController timestamps present fence + // signaling time. + static int64_t dispSyncPresentTimeOffset; + + // Some hardware can do RGB->YUV conversion more efficiently in hardware + // controlled by HWC than in hardware controlled by the video encoder. + // This instruct VirtualDisplaySurface to use HWC for such conversion on + // GL composition. + static bool useHwcForRgbToYuv; + + // Controls the number of buffers SurfaceFlinger will allocate for use in + // FramebufferSurface + static int64_t maxFrameBufferAcquiredBuffers; + + // Controls the minimum acquired buffers SurfaceFlinger will suggest via + // ISurfaceComposer.getMaxAcquiredBufferCount(). + static int64_t minAcquiredBuffers; + + // 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; + static uint32_t maxGraphicsHeight; + // Indicate if device wants color management on its display. static const constexpr bool useColorManagement = true; + static bool useContextPriority; + + // The data space and pixel format that SurfaceFlinger expects hardware composer + // to composite efficiently. Meaning under most scenarios, hardware composer + // will accept layers with the data space and pixel format. + static ui::Dataspace defaultCompositionDataspace; + static ui::PixelFormat defaultCompositionPixelFormat; + + // The data space and pixel format that SurfaceFlinger expects hardware composer + // to composite efficiently for wide color gamut surfaces. Meaning under most scenarios, + // hardware composer will accept layers with the data space and pixel format. + static ui::Dataspace wideColorGamutCompositionDataspace; + static ui::PixelFormat wideColorGamutCompositionPixelFormat; + + static constexpr SkipInitializationTag SkipInitialization; + static LatchUnsignaledConfig enableLatchUnsignaledConfig; // must be called before clients can connect @@ -231,8 +275,7 @@ public: // Schedule sampling independently from commit or composite. void scheduleSample(); - const surfaceflinger::Config& getConfig() { return *mConfig; } - surfaceflinger::Factory& getFactory() { return *mConfig->factory; } + surfaceflinger::Factory& getFactory() { return mFactory; } // The CompositionEngine encapsulates all composition related interfaces and actions. compositionengine::CompositionEngine& getCompositionEngine() const; @@ -264,6 +307,10 @@ public: return mTransactionCallbackInvoker; } + // If set, disables reusing client composition buffers. This can be set by + // debug.sf.disable_client_composition_cache + bool mDisableClientCompositionCache = false; + // Disables expensive rendering for all displays // This is scheduled on the main thread void disableExpensiveRendering(); @@ -274,6 +321,17 @@ public: // run parallel to the hwc validateDisplay call and re-run if the predition is incorrect. bool mPredictCompositionStrategy = false; + // If true, then any layer with a SMPTE 170M transfer function is decoded using the sRGB + // transfer instead. This is mainly to preserve legacy behavior, where implementations treated + // SMPTE 170M as sRGB prior to color management being implemented, and now implementations rely + // on this behavior to increase contrast for some media sources. + bool mTreat170mAsSrgb = false; + + // Allows to ignore physical orientation provided through hwc API in favour of + // 'ro.surface_flinger.primary_display_orientation'. + // TODO(b/246793311): Clean up a temporary property + bool mIgnoreHwcPhysicalDisplayOrientation = false; + void forceFutureUpdate(int delayInMs); const DisplayDevice* getDisplayFromLayerStack(ui::LayerStack) REQUIRES(mStateLock, kMainThreadContext); @@ -608,6 +666,12 @@ private: // Keeps track of whether the kernel idle timer is currently enabled, so we don't have to // make calls to sys prop each time. bool mKernelIdleTimerEnabled = false; + // Show spinner with refresh rate overlay + bool mRefreshRateOverlaySpinner = false; + // Show render rate with refresh rate overlay + bool mRefreshRateOverlayRenderRate = false; + // Show render rate overlay offseted to the middle of the screen (e.g. for circular displays) + bool mRefreshRateOverlayShowInMiddle = false; void setDesiredActiveMode(display::DisplayModeRequest&&, bool force = false) REQUIRES(mStateLock); @@ -1042,8 +1106,8 @@ private: */ const std::unordered_map& getGenericLayerMetadataKeyMap() const; - int calculateMaxAcquiredBufferCount(Fps refreshRate, - std::chrono::nanoseconds presentLatency) const; + static int calculateMaxAcquiredBufferCount(Fps refreshRate, + std::chrono::nanoseconds presentLatency); int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const; bool isHdrLayer(const frontend::LayerSnapshot& snapshot) const; @@ -1053,7 +1117,8 @@ private: void traverseLegacyLayers(const LayerVector::Visitor& visitor) const; sp mStartPropertySetThread; - surfaceflinger::Config* const mConfig = nullptr; + surfaceflinger::Factory& mFactory; + pid_t mPid; std::future mRenderEnginePrimeCacheFuture; // mStateLock has conventions related to the current thread, because only @@ -1080,6 +1145,12 @@ private: float mGlobalSaturationFactor = 1.0f; mat4 mClientColorMatrix; + size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS; + // If there are more GraphicBufferProducers tracked by SurfaceFlinger than + // this threshold, then begin logging. + size_t mGraphicBufferProducerListSizeLogThreshold = + static_cast(0.95 * static_cast(MAX_LAYERS)); + // protected by mStateLock (but we could use another lock) bool mLayersRemoved = false; bool mLayersAdded = false; @@ -1089,6 +1160,7 @@ private: // constant members (no synchronization needed for access) const nsecs_t mBootTime = systemTime(); + bool mIsUserBuild = true; // Can only accessed from the main thread, these members // don't need synchronization @@ -1100,6 +1172,7 @@ private: // Used to ensure we omit a callback when HDR layer info listener is newly added but the // scene hasn't changed bool mAddingHDRLayerInfoListener = false; + bool mIgnoreHdrCameraLayers = false; // Set during transaction application stage to track if the input info or children // for a layer has changed. @@ -1158,6 +1231,9 @@ private: std::atomic mDebugInTransaction = 0; std::atomic_bool mForceFullDamage = false; + bool mLayerCachingEnabled = false; + bool mBackpressureGpuComposition = false; + LayerTracing mLayerTracing; bool mLayerTracingEnabled = false; @@ -1170,6 +1246,9 @@ private: VsyncId mLastCommittedVsyncId; + // If blurs should be enabled on this device. + bool mSupportsBlur = false; + TransactionCallbackInvoker mTransactionCallbackInvoker; // We maintain a pool of pre-generated texture names to hand out to avoid @@ -1201,9 +1280,13 @@ private: // This property can be used to force SurfaceFlinger to always pick a certain color mode. ui::ColorMode mForceColorMode = ui::ColorMode::NATIVE; - std::optional mOverrideDefaultCompositionDataspace; - std::optional mOverrideWideColorGamutCompositionDataspace; + // Whether to enable wide color gamut (e.g. Display P3) for internal displays that support it. + // If false, wide color modes are filtered out for all internal displays. + bool mSupportsWideColor = false; + ui::Dataspace mDefaultCompositionDataspace; + ui::Dataspace mWideColorGamutCompositionDataspace; + ui::Dataspace mColorSpaceAgnosticDataspace; float mDimmingRatio = -1.f; std::unique_ptr mRenderEngine; @@ -1217,6 +1300,8 @@ private: // any mutex. size_t mMaxRenderTargetSize{1}; + const std::string mHwcServiceName; + /* * Scheduler */ @@ -1233,9 +1318,14 @@ private: // below flags are set by main thread only bool mSetActiveModePending = false; + bool mLumaSampling = true; sp mRegionSamplingThread; sp mFpsReporter; sp mTunnelModeEnabledReporter; + ui::DisplayPrimaries mInternalDisplayPrimaries; + + const float mEmulatedDisplayDensity; + const float mInternalDisplayDensity; // Should only be accessed by the main thread. sp mInputFlinger; @@ -1312,6 +1402,9 @@ private: bool mPowerHintSessionEnabled; + bool mLayerLifecycleManagerEnabled = false; + bool mLegacyFrontEndEnabled = true; + frontend::LayerLifecycleManager mLayerLifecycleManager; frontend::LayerHierarchyBuilder mLayerHierarchyBuilder{{}}; frontend::LayerSnapshotBuilder mLayerSnapshotBuilder; diff --git a/services/surfaceflinger/SurfaceFlingerConfig.cpp b/services/surfaceflinger/SurfaceFlingerConfig.cpp deleted file mode 100644 index 0b25a4462d..0000000000 --- a/services/surfaceflinger/SurfaceFlingerConfig.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2023 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 - -#include -#include -#include -#include - -#include "SurfaceFlingerConfig.h" - -namespace android::surfaceflinger { - -using namespace std::string_literals; - -namespace { - -// TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity. -constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV; - -float getDensityFromProperty(const std::string& key, bool required) { - std::string value = base::GetProperty(key, ""s); - const float density = static_cast(std::atof(value.c_str())); - if (density == 0.f && required) { - ALOGE("%s must be defined as a build property", key.c_str()); - return FALLBACK_DENSITY; - } - return density; -} - -} // namespace - -Config::Config() = default; - -Config Config::makeDefault(Factory* factory) { - Config cfg{}; - - // Note: The values set here will affect tests. - // To keep tests hermetic, do not set values here based on runtime values. - - cfg.factory = factory; - cfg.hwcServiceName = "default"s; - cfg.pid = getpid(); // Exception to the hermetic rules. Allow the pid to be cached. - - return cfg; -} - -Config Config::makeProduction(Factory* factory) { - Config cfg = makeDefault(factory); - - cfg.hwcServiceName = base::GetProperty("debug.sf.hwc_service_name"s, "default"s); - - cfg.emulatedDisplayDensity = getDensityFromProperty("qemu.sf.lcd_density"s, false), - cfg.internalDisplayDensity = - getDensityFromProperty("ro.sf.lcd_density"s, cfg.emulatedDisplayDensity == 0.f), - - cfg.hasSyncFramework = sysprop::running_without_sync_framework(cfg.hasSyncFramework); - cfg.dispSyncPresentTimeOffset = - sysprop::present_time_offset_from_vsync_ns(cfg.dispSyncPresentTimeOffset); - cfg.useHwcForRgbToYuv = sysprop::force_hwc_copy_for_virtual_displays(cfg.useHwcForRgbToYuv); - cfg.maxFrameBufferAcquiredBuffers = - sysprop::max_frame_buffer_acquired_buffers(cfg.maxFrameBufferAcquiredBuffers); - cfg.minAcquiredBuffers = sysprop::SurfaceFlingerProperties::min_acquired_buffers().value_or( - cfg.minAcquiredBuffers); - - cfg.maxGraphicsWidth = std::max(static_cast(sysprop::max_graphics_width( - static_cast(cfg.maxGraphicsWidth))), - 0u); - cfg.maxGraphicsHeight = std::max(static_cast(sysprop::max_graphics_height( - static_cast(cfg.maxGraphicsHeight))), - 0u); - - cfg.supportsWideColor = sysprop::has_wide_color_display(cfg.supportsWideColor); - - cfg.defaultCompositionDataspace = static_cast( - sysprop::default_composition_dataspace(cfg.defaultCompositionDataspace)); - cfg.defaultCompositionPixelFormat = static_cast( - sysprop::default_composition_pixel_format(cfg.defaultCompositionPixelFormat)); - - cfg.wideColorGamutCompositionDataspace = - static_cast(sysprop::wcg_composition_dataspace( - cfg.supportsWideColor ? ui::Dataspace::DISPLAY_P3 : ui::Dataspace::V0_SRGB)); - cfg.wideColorGamutCompositionPixelFormat = static_cast( - sysprop::wcg_composition_pixel_format(cfg.wideColorGamutCompositionPixelFormat)); - - cfg.colorSpaceAgnosticDataspace = static_cast( - sysprop::color_space_agnostic_dataspace(cfg.colorSpaceAgnosticDataspace)); - - cfg.internalDisplayPrimaries = sysprop::getDisplayNativePrimaries(); - - cfg.layerCachingEnabled = - base::GetBoolProperty("debug.sf.enable_layer_caching"s, - android::sysprop::SurfaceFlingerProperties::enable_layer_caching() - .value_or(cfg.layerCachingEnabled)); - cfg.useContextPriority = sysprop::use_context_priority(cfg.useContextPriority); - - cfg.isUserBuild = "user"s == base::GetProperty("ro.build.type"s, "user"s); - - cfg.backpressureGpuComposition = base::GetBoolProperty("debug.sf.enable_gl_backpressure"s, - cfg.backpressureGpuComposition); - cfg.supportsBlur = - base::GetBoolProperty("ro.surface_flinger.supports_background_blur"s, cfg.supportsBlur); - - cfg.lumaSampling = base::GetBoolProperty("debug.sf.luma_sampling"s, cfg.lumaSampling); - - cfg.disableClientCompositionCache = - base::GetBoolProperty("debug.sf.disable_client_composition_cache"s, - cfg.disableClientCompositionCache); - - cfg.predictCompositionStrategy = - base::GetBoolProperty("debug.sf.predict_hwc_composition_strategy"s, - cfg.predictCompositionStrategy); - - cfg.treat170mAsSrgb = - base::GetBoolProperty("debug.sf.treat_170m_as_sRGB"s, cfg.treat170mAsSrgb); - - cfg.ignoreHwcPhysicalDisplayOrientation = - base::GetBoolProperty("debug.sf.ignore_hwc_physical_display_orientation"s, - cfg.ignoreHwcPhysicalDisplayOrientation); - - cfg.trebleTestingOverride = - base::GetBoolProperty("debug.sf.treble_testing_override"s, cfg.trebleTestingOverride); - - // TODO (b/270966065) Update the HWC based refresh rate overlay to support spinner - cfg.refreshRateOverlay.showSpinner = - base::GetBoolProperty("debug.sf.show_refresh_rate_overlay_spinner"s, - cfg.refreshRateOverlay.showSpinner); - cfg.refreshRateOverlay.showRenderRate = - base::GetBoolProperty("debug.sf.show_refresh_rate_overlay_render_rate"s, - cfg.refreshRateOverlay.showRenderRate); - cfg.refreshRateOverlay.showInMiddle = - base::GetBoolProperty("debug.sf.show_refresh_rate_overlay_in_middle"s, - cfg.refreshRateOverlay.showInMiddle); - - cfg.ignoreHdrCameraLayers = sysprop::ignore_hdr_camera_layers(cfg.ignoreHdrCameraLayers); - - cfg.enableTransactionTracing = base::GetBoolProperty("debug.sf.enable_transaction_tracing"s, - cfg.enableTransactionTracing); - cfg.layerLifecycleManagerEnabled = - base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, - cfg.layerLifecycleManagerEnabled); - cfg.legacyFrontEndEnabled = !cfg.layerLifecycleManagerEnabled || - base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); - - return cfg; -} - -} // namespace android::surfaceflinger \ No newline at end of file diff --git a/services/surfaceflinger/SurfaceFlingerConfig.h b/services/surfaceflinger/SurfaceFlingerConfig.h deleted file mode 100644 index 7c3348e3bd..0000000000 --- a/services/surfaceflinger/SurfaceFlingerConfig.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2023 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 - -#include -#include - -namespace android::surfaceflinger { - -class Factory; - -struct Config final { - Factory* factory = nullptr; - - std::string hwcServiceName; - pid_t pid; - - float emulatedDisplayDensity = 0; - float internalDisplayDensity = 0; - - // If fences from sync Framework are supported. - bool hasSyncFramework = true; - - // The offset in nanoseconds to use when VsyncController timestamps present - // fence signaling time. - int64_t dispSyncPresentTimeOffset = 0; - - // Some hardware can do RGB->YUV conversion more efficiently in hardware - // controlled by HWC than in hardware controlled by the video encoder. This - // instruct VirtualDisplaySurface to use HWC for such conversion on GL - // composition. - bool useHwcForRgbToYuv = false; - - // Controls the number of buffers SurfaceFlinger will allocate for use in - // FramebufferSurface - int64_t maxFrameBufferAcquiredBuffers = 2; - - // Controls the minimum acquired buffers SurfaceFlinger will suggest via - // ISurfaceComposer.getMaxAcquiredBufferCount(). - int64_t minAcquiredBuffers = 1; - - // 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. - uint32_t maxGraphicsWidth = 0; - uint32_t maxGraphicsHeight = 0; - - // Whether to enable wide color gamut (e.g. Display P3) for internal - // displays that support it. If false, wide color modes are filtered out - // for all internal displays. - bool mSupportsWideColor = false; - bool supportsWideColor = false; - - // The data space and pixel format that SurfaceFlinger expects hardware - // composer to composite efficiently. Meaning under most scenarios, - // hardware composer will accept layers with the data space and pixel - // format. - ui::Dataspace defaultCompositionDataspace = ui::Dataspace::V0_SRGB; - ui::PixelFormat defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888; - - // The data space and pixel format that SurfaceFlinger expects hardware - // composer to composite efficiently for wide color gamut surfaces. Meaning - // under most scenarios, hardware composer will accept layers with the data - // space and pixel format. - ui::Dataspace wideColorGamutCompositionDataspace = ui::Dataspace::V0_SRGB; - ui::PixelFormat wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; - - ui::Dataspace colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; - - ui::DisplayPrimaries internalDisplayPrimaries{}; - - bool layerCachingEnabled = false; - bool useContextPriority = true; - bool isUserBuild = true; - bool backpressureGpuComposition = true; - - // If blurs should be enabled on this device. - bool supportsBlur = false; - bool lumaSampling = true; - - // If set, disables reusing client composition buffers. This can be set by - // debug.sf.disable_client_composition_cache - bool disableClientCompositionCache = false; - - // If set, composition engine tries to predict the composition strategy - // provided by HWC based on the previous frame. If the strategy can be - // predicted, gpu composition will run parallel to the hwc validateDisplay - // call and re-run if the predition is incorrect. - bool predictCompositionStrategy = true; - - // If true, then any layer with a SMPTE 170M transfer function is decoded - // using the sRGB transfer instead. This is mainly to preserve legacy - // behavior, where implementations treated SMPTE 170M as sRGB prior to - // color management being implemented, and now implementations rely on this - // behavior to increase contrast for some media sources. - bool treat170mAsSrgb = false; - - // Allows to ignore physical orientation provided through hwc API in favour - // of 'ro.surface_flinger.primary_display_orientation'. - // TODO(b/246793311): Clean up a temporary property - bool ignoreHwcPhysicalDisplayOrientation = false; - - bool trebleTestingOverride = false; - - struct { - // Show spinner with refresh rate overlay - bool showSpinner = false; - - // Show render rate with refresh rate overlay - bool showRenderRate = false; - - // Show render rate overlay offseted to the middle of the screen (e.g. - // for circular displays) - bool showInMiddle = false; - } refreshRateOverlay; - - bool ignoreHdrCameraLayers = false; - bool enableTransactionTracing = true; - bool layerLifecycleManagerEnabled = false; - bool legacyFrontEndEnabled = true; - - static Config makeDefault(Factory* factory); - static Config makeProduction(Factory* factory); - -private: - Config(); -}; - -} // namespace android::surfaceflinger diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp index ac351cb1d7..7bd6cf69f3 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp @@ -14,17 +14,22 @@ * limitations under the License. */ +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" + #include "SurfaceFlinger.h" -#include "SurfaceFlingerConfig.h" #include "SurfaceFlingerDefaultFactory.h" namespace android::surfaceflinger { sp createSurfaceFlinger() { static DefaultFactory factory; - static Config config = Config::makeProduction(&factory); - return sp::make(config); + return sp::make(factory); } } // namespace android::surfaceflinger + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp index d296c47237..9fac14ed4c 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp @@ -481,8 +481,7 @@ void DisplayHardwareFuzzer::invokeFrameBufferSurface() { sp surface = sp::make(mHwc, mPhysicalDisplayId, bqConsumer, - getFuzzedSize() /*size*/, getFuzzedSize() /*maxSize*/, - mFdp.PickValueInArray(kMaxFrameBufferAcquiredBuffers)); + getFuzzedSize() /*size*/, getFuzzedSize() /*maxSize*/); surface->beginFrame(mFdp.ConsumeBool()); surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes)); @@ -516,8 +515,7 @@ void DisplayHardwareFuzzer::invokeVirtualDisplaySurface() { auto surface = sp::make(mHwc, VirtualDisplayId, sink, bqProducer, bqConsumer, - mFdp.ConsumeRandomLengthString().c_str() /*name*/, - mFdp.ConsumeBool() /* useHwcForRgbToYuv */); + mFdp.ConsumeRandomLengthString().c_str() /*name*/); surface->beginFrame(mFdp.ConsumeBool()); surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes)); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp index df342dcd8e..80943b5b63 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp @@ -124,20 +124,19 @@ void SurfaceFlingerFuzzer::invokeFlinger() { mFlinger->setSchedFifo(mFdp.ConsumeBool()); mFlinger->setSchedAttr(mFdp.ConsumeBool()); mFlinger->getServiceName(); - - auto& config = mTestableFlinger.mutableConfig(); - config.hasSyncFramework = mFdp.ConsumeBool(); - config.dispSyncPresentTimeOffset = mFdp.ConsumeIntegral(); - config.useHwcForRgbToYuv = mFdp.ConsumeBool(); - config.maxFrameBufferAcquiredBuffers = mFdp.ConsumeIntegral(); - config.maxGraphicsWidth = mFdp.ConsumeIntegral(); - config.maxGraphicsHeight = mFdp.ConsumeIntegral(); - config.supportsWideColor = mFdp.ConsumeBool(); - config.useContextPriority = mFdp.ConsumeBool(); - config.defaultCompositionDataspace = mFdp.PickValueInArray(kDataspaces); - config.defaultCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats); - config.wideColorGamutCompositionDataspace = mFdp.PickValueInArray(kDataspaces); - config.wideColorGamutCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats); + mFlinger->hasSyncFramework = mFdp.ConsumeBool(); + mFlinger->dispSyncPresentTimeOffset = mFdp.ConsumeIntegral(); + mFlinger->useHwcForRgbToYuv = mFdp.ConsumeBool(); + mFlinger->maxFrameBufferAcquiredBuffers = mFdp.ConsumeIntegral(); + mFlinger->maxGraphicsWidth = mFdp.ConsumeIntegral(); + mFlinger->maxGraphicsHeight = mFdp.ConsumeIntegral(); + mTestableFlinger.mutableSupportsWideColor() = mFdp.ConsumeBool(); + mFlinger->useContextPriority = mFdp.ConsumeBool(); + + mFlinger->defaultCompositionDataspace = mFdp.PickValueInArray(kDataspaces); + mFlinger->defaultCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats); + mFlinger->wideColorGamutCompositionDataspace = mFdp.PickValueInArray(kDataspaces); + mFlinger->wideColorGamutCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats); mFlinger->enableLatchUnsignaledConfig = mFdp.PickValueInArray(kLatchUnsignaledConfig); @@ -156,7 +155,7 @@ void SurfaceFlingerFuzzer::invokeFlinger() { } void SurfaceFlingerFuzzer::setInternalDisplayPrimaries() { - auto& primaries = mTestableFlinger.mutableConfig().internalDisplayPrimaries; + ui::DisplayPrimaries primaries; primaries.red.X = mFdp.ConsumeFloatingPoint(); primaries.red.Y = mFdp.ConsumeFloatingPoint(); primaries.red.Z = mFdp.ConsumeFloatingPoint(); @@ -169,6 +168,7 @@ void SurfaceFlingerFuzzer::setInternalDisplayPrimaries() { primaries.white.X = mFdp.ConsumeFloatingPoint(); primaries.white.Y = mFdp.ConsumeFloatingPoint(); primaries.white.Z = mFdp.ConsumeFloatingPoint(); + mTestableFlinger.setInternalDisplayPrimaries(primaries); } void SurfaceFlingerFuzzer::setTransactionState() { diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 97cb5d35e3..0c9a16bee3 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -46,7 +46,6 @@ #include "Scheduler/VsyncModulator.h" #include "StartPropertySetThread.h" #include "SurfaceFlinger.h" -#include "SurfaceFlingerConfig.h" #include "SurfaceFlingerDefaultFactory.h" #include "ThreadContext.h" #include "TimeStats/TimeStats.h" @@ -151,8 +150,6 @@ static constexpr ui::PixelFormat kPixelFormats[] = {ui::PixelFormat::RGBA_8888, ui::PixelFormat::YCBCR_P010, ui::PixelFormat::HSV_888}; -static constexpr int kMaxFrameBufferAcquiredBuffers[] = {2, 3, 4}; - inline VsyncId getFuzzedVsyncId(FuzzedDataProvider& fdp) { return VsyncId{fdp.ConsumeIntegral()}; } @@ -407,8 +404,6 @@ public: SurfaceFlinger *flinger() { return mFlinger.get(); } scheduler::TestableScheduler *scheduler() { return mScheduler; } - auto& mutableConfig() { return mConfig; } - void initializeDisplays() { FTL_FAKE_GUARD(kMainThreadContext, mFlinger->initializeDisplays()); } @@ -700,6 +695,10 @@ public: mFactory.mCreateNativeWindowSurface = f; } + void setInternalDisplayPrimaries(const ui::DisplayPrimaries &primaries) { + memcpy(&mFlinger->mInternalDisplayPrimaries, &primaries, sizeof(ui::DisplayPrimaries)); + } + static auto &mutableLayerDrawingState(const sp &layer) { return layer->mDrawingState; } auto &mutableStateLock() { return mFlinger->mStateLock; } @@ -765,12 +764,13 @@ public: auto calculateMaxAcquiredBufferCount(Fps refreshRate, std::chrono::nanoseconds presentLatency) const { - return mFlinger->calculateMaxAcquiredBufferCount(refreshRate, presentLatency); + return SurfaceFlinger::calculateMaxAcquiredBufferCount(refreshRate, presentLatency); } /* Read-write access to private data to set up preconditions and assert * post-conditions. */ + auto& mutableSupportsWideColor() { return mFlinger->mSupportsWideColor; } auto& mutableCurrentState() { return mFlinger->mCurrentState; } auto& mutableDisplays() { return mFlinger->mDisplays; } auto& mutableDrawingState() { return mFlinger->mDrawingState; } @@ -794,8 +794,8 @@ private: void triggerOnFrameRateOverridesChanged() override {} surfaceflinger::test::Factory mFactory; - surfaceflinger::Config mConfig = surfaceflinger::Config::makeDefault(&mFactory); - sp mFlinger = sp::make(mConfig); + sp mFlinger = + sp::make(mFactory, SurfaceFlinger::SkipInitialization); scheduler::TestableScheduler *mScheduler = nullptr; std::shared_ptr mRefreshRateSelector; }; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp index c16a005f0d..849a896ce2 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp @@ -17,15 +17,13 @@ #include #include "SurfaceFlinger.h" -#include "SurfaceFlingerConfig.h" #include "SurfaceFlingerDefaultFactory.h" using namespace android; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { DefaultFactory factory; - surfaceflinger::Config config = surfaceflinger::Config::makeDefault(&factory); - sp flinger = sp::make(config); + sp flinger = sp::make(factory); flinger->init(); sp composerAIDL = sp::make(flinger); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 7124f879e9..e32cf8863b 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -34,7 +34,7 @@ DisplayTransactionTest::DisplayTransactionTest(bool withMockScheduler) { ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); - mFlinger.mutableConfig().supportsWideColor = false; + mFlinger.mutableSupportsWideColor() = false; mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged; mFlinger.setCreateBufferQueueFunction([](auto, auto, auto) { diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index 5599a7a600..ee12276994 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -684,7 +684,7 @@ struct WideColorNotSupportedVariant { static constexpr bool WIDE_COLOR_SUPPORTED = false; static void injectConfigChange(DisplayTransactionTest* test) { - test->mFlinger.mutableConfig().supportsWideColor = true; + test->mFlinger.mutableSupportsWideColor() = true; } static void setupComposerCallExpectations(DisplayTransactionTest* test) { @@ -699,7 +699,7 @@ struct WideColorSupportNotConfiguredVariant { static constexpr bool WIDE_COLOR_SUPPORTED = false; static void injectConfigChange(DisplayTransactionTest* test) { - test->mFlinger.mutableConfig().supportsWideColor = false; + test->mFlinger.mutableSupportsWideColor() = false; test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged; } diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 6c14f6e1c1..fab3c0e887 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -250,8 +250,10 @@ TEST_F(SchedulerTest, calculateMaxAcquiredBufferCount) { EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms)); - mFlinger.mutableConfig().minAcquiredBuffers = 2; + const auto savedMinAcquiredBuffers = mFlinger.mutableMinAcquiredBuffers(); + mFlinger.mutableMinAcquiredBuffers() = 2; EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms)); + mFlinger.mutableMinAcquiredBuffers() = savedMinAcquiredBuffers; } MATCHER(Is120Hz, "") { diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp index fe383846d1..5951c9893f 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp @@ -84,7 +84,9 @@ TEST_F(GetDisplayNativePrimaries, internalDisplayWithPrimariesData) { injector.inject(); auto internalDisplayToken = injector.token(); - populateDummyDisplayNativePrimaries(mFlinger.mutableConfig().internalDisplayPrimaries); + ui::DisplayPrimaries expectedPrimaries; + populateDummyDisplayNativePrimaries(expectedPrimaries); + mFlinger.setInternalDisplayPrimaries(expectedPrimaries); ui::DisplayPrimaries primaries; EXPECT_EQ(NO_ERROR, mFlinger.getDisplayNativePrimaries(internalDisplayToken, primaries)); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp index 61891c14c7..c0796df6cb 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp @@ -36,7 +36,7 @@ struct WideColorP3ColorimetricSupportedVariant { static constexpr bool WIDE_COLOR_SUPPORTED = true; static void injectConfigChange(DisplayTransactionTest* test) { - test->mFlinger.mutableConfig().supportsWideColor = true; + test->mFlinger.mutableSupportsWideColor() = true; test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged; } diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 099abf59b4..156c40a721 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -45,8 +45,6 @@ #include "Scheduler/RefreshRateSelector.h" #include "StartPropertySetThread.h" #include "SurfaceFlinger.h" -#include "SurfaceFlingerConfig.h" -#include "SurfaceFlingerDefaultFactory.h" #include "TestableScheduler.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/DisplayHardware/MockDisplayMode.h" @@ -170,15 +168,13 @@ public: TestableSurfaceFlinger(sp flinger = nullptr) : mFlinger(flinger) { if (!mFlinger) { - mFlinger = sp::make(mConfig); + mFlinger = sp::make(mFactory, SurfaceFlinger::SkipInitialization); } } SurfaceFlinger* flinger() { return mFlinger.get(); } scheduler::TestableScheduler* scheduler() { return mScheduler; } - auto& mutableConfig() { return mConfig; } - // Extend this as needed for accessing SurfaceFlinger private (and public) // functions. @@ -316,6 +312,10 @@ public: mFactory.mCreateNativeWindowSurface = f; } + void setInternalDisplayPrimaries(const ui::DisplayPrimaries& primaries) { + memcpy(&mFlinger->mInternalDisplayPrimaries, &primaries, sizeof(ui::DisplayPrimaries)); + } + static auto& mutableLayerDrawingState(const sp& layer) { return layer->mDrawingState; } auto& mutableStateLock() { return mFlinger->mStateLock; } @@ -513,7 +513,7 @@ public: auto calculateMaxAcquiredBufferCount(Fps refreshRate, std::chrono::nanoseconds presentLatency) const { - return mFlinger->calculateMaxAcquiredBufferCount(refreshRate, presentLatency); + return SurfaceFlinger::calculateMaxAcquiredBufferCount(refreshRate, presentLatency); } auto setDesiredDisplayModeSpecs(const sp& displayToken, @@ -596,6 +596,8 @@ public: const auto& hwcPhysicalDisplayIdMap() const { return getHwComposer().mPhysicalDisplayIdMap; } const auto& hwcDisplayData() const { return getHwComposer().mDisplayData; } + auto& mutableSupportsWideColor() { return mFlinger->mSupportsWideColor; } + auto& mutableCurrentState() { return mFlinger->mCurrentState; } auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; } auto& mutableDisplays() { return mFlinger->mDisplays; } @@ -620,6 +622,8 @@ public: return SurfaceFlinger::sActiveDisplayRotationFlags; } + auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; } + auto fromHandle(const sp& handle) { return LayerHandle::getLayer(handle); } ~TestableSurfaceFlinger() { @@ -1004,7 +1008,6 @@ private: static constexpr VsyncId kVsyncId{123}; surfaceflinger::test::Factory mFactory; - surfaceflinger::Config mConfig = surfaceflinger::Config::makeDefault(&mFactory); sp mFlinger; scheduler::mock::SchedulerCallback mSchedulerCallback; scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback; -- GitLab From 3e0a87e4241f30924da964bb059484278a37132c Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 27 Jun 2023 00:53:52 +0000 Subject: [PATCH 0217/1187] Remove redundant libui-types dependency This dependency is already specific for all targets, so there's no need for a separate host-specific entry. Bug: 288572564 Change-Id: Iecd5f6ced8ae9b1a349c807ea82f5bd7e247a671 Test: presubmit --- services/inputflinger/Android.bp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index b007fd32ac..8f62629aa3 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -185,13 +185,6 @@ cc_defaults { header_libs: [ "libinputflinger_headers", ], - target: { - host: { - static_libs: [ - "libui-types", - ], - }, - }, } cc_library_shared { -- GitLab From 4648fea6aa637aac44a369e1014d230483342bae Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 27 Jun 2023 01:00:12 +0000 Subject: [PATCH 0218/1187] Increase injection timeout for InputFilterInjectionPolicyTest This test is flaky. The test currently fails because there's no event. To fix the test, try increasing the timeout, under the suspicion that the host is slow. Note: this is a speculative fix. Bug: 282837934 Change-Id: I2f6c16013be54b38a231d721cfaea52841571a57 Test: presubmit --- services/inputflinger/tests/InputDispatcher_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index f408204bad..295065610d 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -6184,7 +6184,7 @@ protected: POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_DISABLE_KEY_REPEAT; ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, - InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, + InputEventInjectionSync::WAIT_FOR_RESULT, 100ms, policyFlags | additionalPolicyFlags)); InputEvent* received = mWindow->consume(); @@ -6219,7 +6219,7 @@ protected: const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER; ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, - InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, + InputEventInjectionSync::WAIT_FOR_RESULT, 100ms, policyFlags | additionalPolicyFlags)); InputEvent* received = mWindow->consume(); -- GitLab From f1ed70553d479609b8ca360339e7f208f745d565 Mon Sep 17 00:00:00 2001 From: Yeabkal Wubshit Date: Fri, 16 Jun 2023 10:01:53 -0700 Subject: [PATCH 0219/1187] Updates to SlopController - Addressed comments in ag/23670464 - Moved the creation of the controller from the rotary input mapper constructor, to its `populateDeviceInfo`, since the slop params were not being read in the constructor (since the device property map is not initialized when the input mapper is created). - Added logs to note the slop params Bug: 285957835 Test: atest SlopControllerTest Change-Id: Id1bd77b52c9d93d30d3d2594662e19ccc40a1bb6 --- .../mapper/RotaryEncoderInputMapper.cpp | 20 +++++++++++-------- .../reader/mapper/RotaryEncoderInputMapper.h | 2 +- .../reader/mapper/SlopController.cpp | 4 +--- .../reader/mapper/SlopController.h | 5 ++--- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp index 5220b10211..7251830fa9 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp @@ -20,6 +20,7 @@ #include "RotaryEncoderInputMapper.h" +#include #include #include "CursorScrollAccumulator.h" @@ -30,14 +31,6 @@ RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDeviceContext& deviceCon const InputReaderConfiguration& readerConfig) : InputMapper(deviceContext, readerConfig), mOrientation(ui::ROTATION_0) { mSource = AINPUT_SOURCE_ROTARY_ENCODER; - - const PropertyMap& config = getDeviceContext().getConfiguration(); - float slopThreshold = config.getInt("rotary_encoder.slop_threshold").value_or(0); - int32_t slopDurationMs = config.getInt("rotary_encoder.slop_duration_ms").value_or(0); - if (slopThreshold > 0 && slopDurationMs > 0) { - mSlopController = std::make_unique(slopThreshold, - (nsecs_t)(slopDurationMs * 1000000)); - } } RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {} @@ -70,6 +63,7 @@ void RotaryEncoderInputMapper::dump(std::string& dump) { dump += INDENT2 "Rotary Encoder Input Mapper:\n"; dump += StringPrintf(INDENT3 "HaveWheel: %s\n", toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel())); + dump += StringPrintf(INDENT3 "HaveSlopController: %s\n", toString(mSlopController != nullptr)); } std::list RotaryEncoderInputMapper::reconfigure(nsecs_t when, @@ -78,6 +72,16 @@ std::list RotaryEncoderInputMapper::reconfigure(nsecs_t when, std::list out = InputMapper::reconfigure(when, config, changes); if (!changes.any()) { mRotaryEncoderScrollAccumulator.configure(getDeviceContext()); + + const PropertyMap& propertyMap = getDeviceContext().getConfiguration(); + float slopThreshold = propertyMap.getInt("rotary_encoder.slop_threshold").value_or(0); + int32_t slopDurationNs = milliseconds_to_nanoseconds( + propertyMap.getInt("rotary_encoder.slop_duration_ms").value_or(0)); + if (slopThreshold > 0 && slopDurationNs > 0) { + mSlopController = std::make_unique(slopThreshold, slopDurationNs); + } else { + mSlopController = nullptr; + } } if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO)) { std::optional internalViewport = diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h index 4732bcdb44..fe5d152cef 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h @@ -47,7 +47,7 @@ private: int32_t mSource; float mScalingFactor; ui::Rotation mOrientation; - std::unique_ptr mSlopController = nullptr; + std::unique_ptr mSlopController; explicit RotaryEncoderInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig); diff --git a/services/inputflinger/reader/mapper/SlopController.cpp b/services/inputflinger/reader/mapper/SlopController.cpp index 6f31d0ebe3..f79219f151 100644 --- a/services/inputflinger/reader/mapper/SlopController.cpp +++ b/services/inputflinger/reader/mapper/SlopController.cpp @@ -33,8 +33,6 @@ namespace android { SlopController::SlopController(float slopThreshold, nsecs_t slopDurationNanos) : mSlopThreshold(slopThreshold), mSlopDurationNanos(slopDurationNanos) {} -SlopController::~SlopController() {} - float SlopController::consumeEvent(nsecs_t eventTimeNanos, float value) { if (mSlopDurationNanos == 0) { return value; @@ -64,7 +62,7 @@ float SlopController::consumeEvent(nsecs_t eventTimeNanos, float value) { return 0; } -bool SlopController::shouldResetSlopTracking(nsecs_t eventTimeNanos, float value) { +bool SlopController::shouldResetSlopTracking(nsecs_t eventTimeNanos, float value) const { const nsecs_t ageNanos = eventTimeNanos - mLastEventTimeNanos; if (ageNanos >= mSlopDurationNanos) { return true; diff --git a/services/inputflinger/reader/mapper/SlopController.h b/services/inputflinger/reader/mapper/SlopController.h index bd6ee7770e..c1064102e8 100644 --- a/services/inputflinger/reader/mapper/SlopController.h +++ b/services/inputflinger/reader/mapper/SlopController.h @@ -28,10 +28,9 @@ namespace android { * Current slop logic: * "If time since last event > Xns, then discard the next N values." */ -class SlopController { +class SlopController final { public: SlopController(float slopThreshold, nsecs_t slopDurationNanos); - virtual ~SlopController(); /** * Consumes an event with a given time and value for slop processing. @@ -40,7 +39,7 @@ public: float consumeEvent(nsecs_t eventTime, float value); private: - bool shouldResetSlopTracking(nsecs_t eventTimeNanos, float value); + bool shouldResetSlopTracking(nsecs_t eventTimeNanos, float value) const; /** The amount of event values ignored after an inactivity of the slop duration. */ const float mSlopThreshold; -- GitLab From deaecdc77d49c1a723772574469f015adc162858 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Mon, 26 Jun 2023 15:31:40 +0000 Subject: [PATCH 0220/1187] Inline code to turn an SkRuntimeBuilder -> SkImage This appears to be the only use of SkRuntimeEffect::makeImage This also removes a very small amount of code size and very slightly reduces parse time by removing whitespace from the shader code. Change-Id: I51b1b11f1cb49717ab5c069f9f5cb4e66c0b93ff --- .../skia/filters/KawaseBlurFilter.cpp | 74 ++++++++++++++----- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp index 061ec5f8a3..0c7335c05d 100644 --- a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp +++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp @@ -17,14 +17,20 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "KawaseBlurFilter.h" +#include +#include #include +#include #include #include #include +#include #include #include #include #include +#include +#include #include #include @@ -33,19 +39,18 @@ namespace renderengine { namespace skia { KawaseBlurFilter::KawaseBlurFilter(): BlurFilter() { - SkString blurString(R"( - uniform shader child; - uniform float in_blurOffset; - - half4 main(float2 xy) { - half4 c = child.eval(xy); - c += child.eval(xy + float2(+in_blurOffset, +in_blurOffset)); - c += child.eval(xy + float2(+in_blurOffset, -in_blurOffset)); - c += child.eval(xy + float2(-in_blurOffset, -in_blurOffset)); - c += child.eval(xy + float2(-in_blurOffset, +in_blurOffset)); - return half4(c.rgb * 0.2, 1.0); - } - )"); + SkString blurString( + "uniform shader child;" + "uniform float in_blurOffset;" + + "half4 main(float2 xy) {" + "half4 c = child.eval(xy);" + "c += child.eval(xy + float2(+in_blurOffset, +in_blurOffset));" + "c += child.eval(xy + float2(+in_blurOffset, -in_blurOffset));" + "c += child.eval(xy + float2(-in_blurOffset, -in_blurOffset));" + "c += child.eval(xy + float2(-in_blurOffset, +in_blurOffset));" + "return half4(c.rgb * 0.2, 1.0);" + "}"); auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString); if (!blurEffect) { @@ -54,10 +59,43 @@ KawaseBlurFilter::KawaseBlurFilter(): BlurFilter() { mBlurEffect = std::move(blurEffect); } -sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius, - const sk_sp input, const SkRect& blurRect) - const { +// Draws the given runtime shader on a GPU (Ganesh) surface and returns the result as an +// SkImage. +static sk_sp makeImage(GrRecordingContext* context, SkRuntimeShaderBuilder* builder, + const SkImageInfo& resultInfo) { + if (resultInfo.alphaType() == kUnpremul_SkAlphaType || + resultInfo.alphaType() == kUnknown_SkAlphaType) { + return nullptr; + } + constexpr int kSampleCount = 1; + constexpr bool kMipmapped = false; + + sk_sp surface = SkSurfaces::RenderTarget(context, + skgpu::Budgeted::kYes, + resultInfo, + kSampleCount, + kTopLeft_GrSurfaceOrigin, + nullptr, + kMipmapped); + if (!surface) { + return nullptr; + } + sk_sp shader = builder->makeShader(nullptr); + if (!shader) { + return nullptr; + } + SkPaint paint; + paint.setShader(std::move(shader)); + paint.setBlendMode(SkBlendMode::kSrc); + surface->getCanvas()->drawPaint(paint); + return surface->makeImageSnapshot(); +} +sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, + const uint32_t blurRadius, + const sk_sp input, + const SkRect& blurRect) const { + LOG_ALWAYS_FATAL_IF(context == nullptr, "%s: Needs GPU context", __func__); LOG_ALWAYS_FATAL_IF(input == nullptr, "%s: Invalid input image", __func__); // Kawase is an approximation of Gaussian, but it behaves differently from it. // A radius transformation is required for approximating them, and also to introduce @@ -83,7 +121,7 @@ sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, const uin input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix); blurBuilder.uniform("in_blurOffset") = radiusByPasses * kInputScale; - sk_sp tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false)); + sk_sp tmpBlur = makeImage(context, &blurBuilder, scaledInfo); // And now we'll build our chain of scaled blur stages for (auto i = 1; i < numberOfPasses; i++) { @@ -91,7 +129,7 @@ sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, const uin blurBuilder.child("child") = tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear); blurBuilder.uniform("in_blurOffset") = (float) i * radiusByPasses * kInputScale; - tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false); + tmpBlur = makeImage(context, &blurBuilder, scaledInfo); } return tmpBlur; -- GitLab From 6786299a625bf6e109bb76a0132de03350e769ff Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Thu, 22 Jun 2023 15:56:05 +0530 Subject: [PATCH 0221/1187] ultrahdr: tune lut tables qstep for quality ultrahdr input is either 8 and/or 10 bit. This would correspond to 256/1024 distinct float values. During generateGainMap, the yuv pixel is converted to rgb and then *InvOetf is applied. If *InvOetf were to be applied on a yuv pel, then 256/1024 lut would suffice. However the *InvOetf is applied on an rgb transformed value. If the csc was integral, then 256/1024 yuv sample will map to 256/1024 rgb sample and 256/1024 lut size will be sufficient. As csc operation is not integral, it is possible that rgb pel values not necessarily map to 256/1024 values always. It may be beneficial to have a slightly higher precision than input depth for *InvOetf luts. *Oetfs require a much larger precision because the inputs to function although in range 0-1, but can be of any value not just the 256/1024 states. Further, if the slope of a curve is small, then larger qstep will not have a huge effect on the error of f'(x). But as slope increases small changes in x can greatly effect f'(x). So if qstep is not large enough then error can be pronounced. The current luts are quantizing the region 0-1 uniformly so we need to increase the lut size. TODO: segment luts basing on slope. Bug: 288383792 Test: ./libultrahdr_app -p inp_1920x1080_p010.yuv \ -y inp_1920x1080_420p.yuv -w 1920 -h 1080 -o 2 -t 2 -c 0 Change-Id: I7517340a2c1e32d9e3c602a67397e17e48fa62b3 --- libs/ultrahdr/include/ultrahdr/gainmapmath.h | 8 ++++---- libs/ultrahdr/jpegr.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/ultrahdr/include/ultrahdr/gainmapmath.h b/libs/ultrahdr/include/ultrahdr/gainmapmath.h index edf152d8ed..d594a0da90 100644 --- a/libs/ultrahdr/include/ultrahdr/gainmapmath.h +++ b/libs/ultrahdr/include/ultrahdr/gainmapmath.h @@ -312,7 +312,7 @@ Color hlgOetf(Color e); float hlgOetfLUT(float e); Color hlgOetfLUT(Color e); -constexpr size_t kHlgOETFPrecision = 10; +constexpr size_t kHlgOETFPrecision = 16; constexpr size_t kHlgOETFNumEntries = 1 << kHlgOETFPrecision; /* @@ -325,7 +325,7 @@ Color hlgInvOetf(Color e_gamma); float hlgInvOetfLUT(float e_gamma); Color hlgInvOetfLUT(Color e_gamma); -constexpr size_t kHlgInvOETFPrecision = 10; +constexpr size_t kHlgInvOETFPrecision = 12; constexpr size_t kHlgInvOETFNumEntries = 1 << kHlgInvOETFPrecision; /* @@ -338,7 +338,7 @@ Color pqOetf(Color e); float pqOetfLUT(float e); Color pqOetfLUT(Color e); -constexpr size_t kPqOETFPrecision = 10; +constexpr size_t kPqOETFPrecision = 16; constexpr size_t kPqOETFNumEntries = 1 << kPqOETFPrecision; /* @@ -351,7 +351,7 @@ Color pqInvOetf(Color e_gamma); float pqInvOetfLUT(float e_gamma); Color pqInvOetfLUT(Color e_gamma); -constexpr size_t kPqInvOETFPrecision = 10; +constexpr size_t kPqInvOETFPrecision = 12; constexpr size_t kPqInvOETFNumEntries = 1 << kPqInvOETFPrecision; diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp index 9c57f34c2a..af95891e88 100644 --- a/libs/ultrahdr/jpegr.cpp +++ b/libs/ultrahdr/jpegr.cpp @@ -1070,7 +1070,7 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, } case ULTRAHDR_OUTPUT_HDR_PQ: { -#if USE_HLG_OETF_LUT +#if USE_PQ_OETF_LUT ColorTransformFn hdrOetf = pqOetfLUT; #else ColorTransformFn hdrOetf = pqOetf; -- GitLab From 4d2b74aea167407305f2e95047ea8fcc96bf80a5 Mon Sep 17 00:00:00 2001 From: Dichen Zhang Date: Wed, 14 Jun 2023 22:58:09 +0000 Subject: [PATCH 0222/1187] ultrahdr icc: update transfer function Bug: 286444758 Test: jpegr_test.cpp Manual test: (1) append icc package to red-noicc.jpeg (attached in the bug comment #1), then open the image with digital color meter, color measurement should be close to (255, 0, 0). (2) Dump icc into a file and open the icc file on Mac, read data of each component (wtpt, r/g/bXYZ, r/g/bTRC) that should be the same as the samples in comment #10 Change-Id: I3b4a2b7d283fc143207d2dbce570eadf7568ebec --- libs/ultrahdr/icc.cpp | 45 +++++++++++++------- libs/ultrahdr/include/ultrahdr/gainmapmath.h | 17 ++++++++ libs/ultrahdr/include/ultrahdr/icc.h | 3 +- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/libs/ultrahdr/icc.cpp b/libs/ultrahdr/icc.cpp index 1ab3c7c793..e41b645cce 100644 --- a/libs/ultrahdr/icc.cpp +++ b/libs/ultrahdr/icc.cpp @@ -19,7 +19,6 @@ #endif #include -#include #include #include @@ -218,8 +217,8 @@ sp IccHelper::write_trc_tag(const int table_entries, const void* tab total_length = (((total_length + 2) >> 2) << 2); // 4 aligned sp dataStruct = sp::make(total_length); dataStruct->write32(Endian_SwapBE32(kTAG_CurveType)); // Type - dataStruct->write32(0); // Reserved - dataStruct->write32(Endian_SwapBE32(table_entries)); // Value count + dataStruct->write32(0); // Reserved + dataStruct->write32(Endian_SwapBE32(table_entries)); // Value count for (size_t i = 0; i < table_entries; ++i) { uint16_t value = reinterpret_cast(table_16)[i]; dataStruct->write16(value); @@ -227,14 +226,30 @@ sp IccHelper::write_trc_tag(const int table_entries, const void* tab return dataStruct; } -sp IccHelper::write_trc_tag_for_linear() { - int total_length = 16; - sp dataStruct = sp::make(total_length); - dataStruct->write32(Endian_SwapBE32(kTAG_ParaCurveType)); // Type - dataStruct->write32(0); // Reserved - dataStruct->write32(Endian_SwapBE16(kExponential_ParaCurveType)); - dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(1.0))); +sp IccHelper::write_trc_tag(const TransferFunction& fn) { + if (fn.a == 1.f && fn.b == 0.f && fn.c == 0.f + && fn.d == 0.f && fn.e == 0.f && fn.f == 0.f) { + int total_length = 16; + sp dataStruct = new DataStruct(total_length); + dataStruct->write32(Endian_SwapBE32(kTAG_ParaCurveType)); // Type + dataStruct->write32(0); // Reserved + dataStruct->write32(Endian_SwapBE16(kExponential_ParaCurveType)); + dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.g))); + return dataStruct; + } + int total_length = 40; + sp dataStruct = new DataStruct(total_length); + dataStruct->write32(Endian_SwapBE32(kTAG_ParaCurveType)); // Type + dataStruct->write32(0); // Reserved + dataStruct->write32(Endian_SwapBE16(kGABCDEF_ParaCurveType)); + dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.g))); + dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.a))); + dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.b))); + dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.c))); + dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.d))); + dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.e))); + dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.f))); return dataStruct; } @@ -349,7 +364,7 @@ sp IccHelper::write_mAB_or_mBA_tag(uint32_t type, // The "B" curve is required. for (size_t i = 0; i < kNumChannels; ++i) { - b_curves_data[i] = write_trc_tag_for_linear(); + b_curves_data[i] = write_trc_tag(kLinear_TransFun); } // The "A" curve and CLUT are optional. @@ -362,7 +377,7 @@ sp IccHelper::write_mAB_or_mBA_tag(uint32_t type, a_curves_offset = clut_offset + clut->getLength(); for (size_t i = 0; i < kNumChannels; ++i) { - a_curves_data[i] = write_trc_tag_for_linear(); + a_curves_data[i] = write_trc_tag(kLinear_TransFun); } } @@ -460,9 +475,9 @@ sp IccHelper::writeIccProfile(ultrahdr_transfer_function tf, tags.emplace_back(kTAG_bTRC, write_trc_tag(kTrcTableSize, reinterpret_cast(trc_table.data()))); } else { - tags.emplace_back(kTAG_rTRC, write_trc_tag_for_linear()); - tags.emplace_back(kTAG_gTRC, write_trc_tag_for_linear()); - tags.emplace_back(kTAG_bTRC, write_trc_tag_for_linear()); + tags.emplace_back(kTAG_rTRC, write_trc_tag(kSRGB_TransFun)); + tags.emplace_back(kTAG_gTRC, write_trc_tag(kSRGB_TransFun)); + tags.emplace_back(kTAG_bTRC, write_trc_tag(kSRGB_TransFun)); } } diff --git a/libs/ultrahdr/include/ultrahdr/gainmapmath.h b/libs/ultrahdr/include/ultrahdr/gainmapmath.h index edf152d8ed..6115dfe3b5 100644 --- a/libs/ultrahdr/include/ultrahdr/gainmapmath.h +++ b/libs/ultrahdr/include/ultrahdr/gainmapmath.h @@ -51,6 +51,23 @@ struct Color { typedef Color (*ColorTransformFn)(Color); typedef float (*ColorCalculationFn)(Color); +// A transfer function mapping encoded values to linear values, +// represented by this 7-parameter piecewise function: +// +// linear = sign(encoded) * (c*|encoded| + f) , 0 <= |encoded| < d +// = sign(encoded) * ((a*|encoded| + b)^g + e), d <= |encoded| +// +// (A simple gamma transfer function sets g to gamma and a to 1.) +typedef struct TransferFunction { + float g, a,b,c,d,e,f; +} TransferFunction; + +static constexpr TransferFunction kSRGB_TransFun = + { 2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0.0f, 0.0f }; + +static constexpr TransferFunction kLinear_TransFun = + { 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; + inline Color operator+=(Color& lhs, const Color& rhs) { lhs.r += rhs.r; lhs.g += rhs.g; diff --git a/libs/ultrahdr/include/ultrahdr/icc.h b/libs/ultrahdr/include/ultrahdr/icc.h index 7f047f8f5b..971b267fe4 100644 --- a/libs/ultrahdr/include/ultrahdr/icc.h +++ b/libs/ultrahdr/include/ultrahdr/icc.h @@ -17,6 +17,7 @@ #ifndef ANDROID_ULTRAHDR_ICC_H #define ANDROID_ULTRAHDR_ICC_H +#include #include #include #include @@ -222,7 +223,7 @@ private: const ultrahdr_color_gamut gamut); static sp write_xyz_tag(float x, float y, float z); static sp write_trc_tag(const int table_entries, const void* table_16); - static sp write_trc_tag_for_linear(); + static sp write_trc_tag(const TransferFunction& fn); static float compute_tone_map_gain(const ultrahdr_transfer_function tf, float L); static sp write_cicp_tag(uint32_t color_primaries, uint32_t transfer_characteristics); -- GitLab From 656e0ada355c23c7643999a57332d199fc511eb2 Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Fri, 16 Jun 2023 16:39:55 +0000 Subject: [PATCH 0223/1187] inputflinger fuzzers: add function for creating RawEvents The exact same logic was being repeated in five different places, so let's make a helper function for it. Bug: 264582512 Test: build and run inputflinger_multitouch_input_fuzzer Change-Id: I870c762fd849dcde338be00918da766911e56c04 --- .../tests/fuzzers/CursorInputFuzzer.cpp | 14 ++------- .../tests/fuzzers/KeyboardInputFuzzer.cpp | 13 ++------- .../tests/fuzzers/MapperHelpers.h | 29 +++++++++++-------- .../tests/fuzzers/MultiTouchInputFuzzer.cpp | 12 ++------ .../tests/fuzzers/SwitchInputFuzzer.cpp | 12 ++------ 5 files changed, 25 insertions(+), 55 deletions(-) diff --git a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp index 8098ef2edd..993f6a8e5c 100644 --- a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp @@ -16,6 +16,7 @@ #include #include +#include namespace android { @@ -65,22 +66,11 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { mapper.populateDeviceInfo(info); }, [&]() -> void { - int32_t type, code; - type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes) - : fdp->ConsumeIntegral(); - code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes) - : fdp->ConsumeIntegral(); - // Need to reconfigure with 0 or you risk a NPE. std::list unused = mapper.reconfigure(fdp->ConsumeIntegral(), policyConfig, InputReaderConfiguration::Change(0)); - RawEvent rawEvent{fdp->ConsumeIntegral(), - fdp->ConsumeIntegral(), - fdp->ConsumeIntegral(), - type, - code, - fdp->ConsumeIntegral()}; + RawEvent rawEvent = getFuzzedRawEvent(*fdp); unused += mapper.process(&rawEvent); }, [&]() -> void { diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp index 616e870811..d11e8ae24a 100644 --- a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp @@ -16,6 +16,7 @@ #include #include +#include namespace android { @@ -72,17 +73,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::list unused = mapper.reset(fdp->ConsumeIntegral()); }, [&]() -> void { - int32_t type, code; - type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes) - : fdp->ConsumeIntegral(); - code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes) - : fdp->ConsumeIntegral(); - RawEvent rawEvent{fdp->ConsumeIntegral(), - fdp->ConsumeIntegral(), - fdp->ConsumeIntegral(), - type, - code, - fdp->ConsumeIntegral()}; + RawEvent rawEvent = getFuzzedRawEvent(*fdp); std::list unused = mapper.process(&rawEvent); }, [&]() -> void { diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index 1e44e0fba0..698daf555a 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -74,6 +74,22 @@ ToolType getFuzzedToolType(Fdp& fdp) { return static_cast(toolType); } +template +RawEvent getFuzzedRawEvent(Fdp& fdp) { + const int32_t type = fdp.ConsumeBool() ? fdp.PickValueInArray(kValidTypes) + : fdp.template ConsumeIntegral(); + const int32_t code = fdp.ConsumeBool() ? fdp.PickValueInArray(kValidCodes) + : fdp.template ConsumeIntegral(); + return RawEvent{ + .when = fdp.template ConsumeIntegral(), + .readTime = fdp.template ConsumeIntegral(), + .deviceId = fdp.template ConsumeIntegral(), + .type = type, + .code = code, + .value = fdp.template ConsumeIntegral(), + }; +} + class FuzzEventHub : public EventHubInterface { InputDeviceIdentifier mIdentifier; std::vector mVideoFrames; @@ -118,18 +134,7 @@ public: std::vector events; const size_t count = mFdp->ConsumeIntegralInRange(0, kMaxSize); for (size_t i = 0; i < count; ++i) { - int32_t type = mFdp->ConsumeBool() ? mFdp->PickValueInArray(kValidTypes) - : mFdp->ConsumeIntegral(); - int32_t code = mFdp->ConsumeBool() ? mFdp->PickValueInArray(kValidCodes) - : mFdp->ConsumeIntegral(); - events.push_back({ - .when = mFdp->ConsumeIntegral(), - .readTime = mFdp->ConsumeIntegral(), - .deviceId = mFdp->ConsumeIntegral(), - .type = type, - .code = code, - .value = mFdp->ConsumeIntegral(), - }); + events.push_back(getFuzzedRawEvent(*mFdp)); } return events; } diff --git a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp index 212462d700..494b0efe79 100644 --- a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp @@ -15,6 +15,7 @@ */ #include +#include #include namespace android { @@ -87,16 +88,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::list unused = mapper.reset(fdp->ConsumeIntegral()); }, [&]() -> void { - int32_t type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes) - : fdp->ConsumeIntegral(); - int32_t code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes) - : fdp->ConsumeIntegral(); - RawEvent rawEvent{fdp->ConsumeIntegral(), - fdp->ConsumeIntegral(), - fdp->ConsumeIntegral(), - type, - code, - fdp->ConsumeIntegral()}; + RawEvent rawEvent = getFuzzedRawEvent(*fdp); std::list unused = mapper.process(&rawEvent); }, [&]() -> void { diff --git a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp index 590207ea22..381e7b5f8f 100644 --- a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp @@ -15,6 +15,7 @@ */ #include +#include #include namespace android { @@ -36,16 +37,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { }, [&]() -> void { mapper.getSources(); }, [&]() -> void { - int32_t type = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidTypes) - : fdp->ConsumeIntegral(); - int32_t code = fdp->ConsumeBool() ? fdp->PickValueInArray(kValidCodes) - : fdp->ConsumeIntegral(); - RawEvent rawEvent{fdp->ConsumeIntegral(), - fdp->ConsumeIntegral(), - fdp->ConsumeIntegral(), - type, - code, - fdp->ConsumeIntegral()}; + RawEvent rawEvent = getFuzzedRawEvent(*fdp); std::list unused = mapper.process(&rawEvent); }, [&]() -> void { -- GitLab From 9d2b527b61b6696b50177ef85869ee8b99515dfe Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Fri, 23 Jun 2023 13:09:28 +0000 Subject: [PATCH 0224/1187] FuzzContainer: fix parameter name comment format Bug: 245989146 Test: $ SANITIZE_TARGET=hwaddress \ make inputflinger_multitouch_input_fuzzer Change-Id: Ibf42623a826b3ffd7e90a82e68f231ffe04ab46b --- services/inputflinger/tests/fuzzers/FuzzContainer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h index b9929289f1..fd14e024c6 100644 --- a/services/inputflinger/tests/fuzzers/FuzzContainer.h +++ b/services/inputflinger/tests/fuzzers/FuzzContainer.h @@ -38,7 +38,7 @@ public: std::string deviceName = mFdp->ConsumeRandomLengthString(16); std::string deviceLocation = mFdp->ConsumeRandomLengthString(12); int32_t deviceID = mFdp->ConsumeIntegralInRange(0, 5); - int32_t deviceGeneration = mFdp->ConsumeIntegralInRange(/*from*/ 0, /*to*/ 5); + int32_t deviceGeneration = mFdp->ConsumeIntegralInRange(/*from=*/0, /*to=*/5); // Create mocked objects. mFuzzEventHub = std::make_shared(mFdp); -- GitLab From 2fbfc68d97b3e4ae77fa209d54a9382bb4c1c645 Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Fri, 23 Jun 2023 12:57:02 +0000 Subject: [PATCH 0225/1187] inputflinger fuzzers: tidy up kValid{Types,Codes} SYN_REPORT is not a valid event type (i.e. it's not an evdev axis or one of the additional event codes added by EventHub), so it shouldn't be in kValidTypes. Also remove a duplication of SYNC_MT_REPORT from kValidCodes. Bug: 264582512 Test: build and run inputflinger_multitouch_input_fuzzer Change-Id: I5f9219b7060d0b5cf0f36746502d7a400556a5cf --- services/inputflinger/tests/fuzzers/MapperHelpers.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index 698daf555a..4a2c98ccae 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -22,7 +22,6 @@ constexpr size_t kValidTypes[] = {EV_SW, EV_SYN, - SYN_REPORT, EV_ABS, EV_KEY, EV_MSC, @@ -46,7 +45,6 @@ constexpr size_t kValidCodes[] = { ABS_MT_PRESSURE, ABS_MT_DISTANCE, ABS_MT_TOOL_TYPE, - SYN_MT_REPORT, MSC_SCAN, REL_X, REL_Y, -- GitLab From a5d3d28952a66de3a8c5629ca6a6678e88e92b47 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Wed, 21 Jun 2023 19:56:15 -0700 Subject: [PATCH 0226/1187] [sf] enable new sf frontend Test: presubmit Bug: 238781169 Change-Id: I7356114484168faa59a4f0ad4aa51e082700431d --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ba13293a8f..927a826cba 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -487,7 +487,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false); mLayerLifecycleManagerEnabled = - base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false); + base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, true); mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled || base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); } -- GitLab From 3c00cbc0f119c3f59325aa6d5061529feb58462b Mon Sep 17 00:00:00 2001 From: sergiuferentz Date: Mon, 26 Jun 2023 18:01:47 +0000 Subject: [PATCH 0227/1187] Fix for heap-use-after-free in GPUService.cpp This adds a unit test and fix for the bug reported by libfuzzer. Changes made: * Expose GPUService as testable code. * Update main_gpuservice.cpp to use the new GpuService now located at gpuservice/GpuService.h * Make initializer threads members of GpuService * Join the threads in destructor to prevent heap-use-after-free. * Add unit test that waits 3 seconds after deallocation to ensure no wrong access is made. Bug: 282919145 Test: Added unit test and ran on device with ASAN Change-Id: I4d1d2d4658b575bf2c8f425f91f68f03114ad029 --- services/gpuservice/Android.bp | 1 + services/gpuservice/GpuService.cpp | 14 +++-- .../{ => include/gpuservice}/GpuService.h | 4 ++ services/gpuservice/main_gpuservice.cpp | 2 +- .../tests/fuzzers/GpuServiceFuzzer.cpp | 2 +- .../gpuservice/tests/unittests/Android.bp | 2 + .../tests/unittests/GpuServiceTest.cpp | 52 +++++++++++++++++++ 7 files changed, 70 insertions(+), 7 deletions(-) rename services/gpuservice/{ => include/gpuservice}/GpuService.h (95%) create mode 100644 services/gpuservice/tests/unittests/GpuServiceTest.cpp diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp index fba64c7569..052efb6bbb 100644 --- a/services/gpuservice/Android.bp +++ b/services/gpuservice/Android.bp @@ -71,6 +71,7 @@ filegroup { cc_library_shared { name: "libgpuservice", defaults: ["libgpuservice_production_defaults"], + export_include_dirs: ["include"], srcs: [ ":libgpuservice_sources", ], diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 5e7b2e8df8..4a08c11c14 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -16,7 +16,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include "GpuService.h" +#include "gpuservice/GpuService.h" #include #include @@ -35,6 +35,7 @@ #include #include +#include namespace android { @@ -58,18 +59,21 @@ GpuService::GpuService() mGpuStats(std::make_unique()), mGpuMemTracer(std::make_unique()) { - std::thread gpuMemAsyncInitThread([this]() { + mGpuMemAsyncInitThread = std::make_unique([this] (){ mGpuMem->initialize(); mGpuMemTracer->initialize(mGpuMem); }); - gpuMemAsyncInitThread.detach(); - std::thread gpuWorkAsyncInitThread([this]() { + mGpuWorkAsyncInitThread = std::make_unique([this]() { mGpuWork->initialize(); }); - gpuWorkAsyncInitThread.detach(); }; +GpuService::~GpuService() { + mGpuWorkAsyncInitThread->join(); + mGpuMemAsyncInitThread->join(); +} + void GpuService::setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/include/gpuservice/GpuService.h similarity index 95% rename from services/gpuservice/GpuService.h rename to services/gpuservice/include/gpuservice/GpuService.h index 0e559f2c34..54f8f666bc 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/include/gpuservice/GpuService.h @@ -24,6 +24,7 @@ #include #include +#include #include namespace android { @@ -41,6 +42,7 @@ public: static const char* const SERVICE_NAME ANDROID_API; GpuService() ANDROID_API; + ~GpuService(); protected: status_t shellCommand(int in, int out, int err, std::vector& args) override; @@ -90,6 +92,8 @@ private: std::unique_ptr mGpuMemTracer; std::mutex mLock; std::string mDeveloperDriverPath; + std::unique_ptr mGpuMemAsyncInitThread; + std::unique_ptr mGpuWorkAsyncInitThread; }; } // namespace android diff --git a/services/gpuservice/main_gpuservice.cpp b/services/gpuservice/main_gpuservice.cpp index 64aafcab6a..200237219e 100644 --- a/services/gpuservice/main_gpuservice.cpp +++ b/services/gpuservice/main_gpuservice.cpp @@ -18,7 +18,7 @@ #include #include #include -#include "GpuService.h" +#include "gpuservice/GpuService.h" using namespace android; diff --git a/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp index c2574a3fd3..241b8646e1 100644 --- a/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp +++ b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp @@ -16,7 +16,7 @@ #include -#include "GpuService.h" +#include "gpuservice/GpuService.h" using ::android::fuzzService; using ::android::GpuService; diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp index 51642f9472..c870b17b79 100644 --- a/services/gpuservice/tests/unittests/Android.bp +++ b/services/gpuservice/tests/unittests/Android.bp @@ -28,6 +28,7 @@ cc_test { "GpuMemTest.cpp", "GpuMemTracerTest.cpp", "GpuStatsTest.cpp", + "GpuServiceTest.cpp", ], header_libs: ["bpf_headers"], shared_libs: [ @@ -45,6 +46,7 @@ cc_test { "libstatslog", "libstatspull", "libutils", + "libgpuservice", ], static_libs: [ "libgmock", diff --git a/services/gpuservice/tests/unittests/GpuServiceTest.cpp b/services/gpuservice/tests/unittests/GpuServiceTest.cpp new file mode 100644 index 0000000000..62b3e53f53 --- /dev/null +++ b/services/gpuservice/tests/unittests/GpuServiceTest.cpp @@ -0,0 +1,52 @@ +#undef LOG_TAG +#define LOG_TAG "gpuservice_unittest" + +#include "gpuservice/GpuService.h" + +#include +#include + +#include +#include + +namespace android { +namespace { + +class GpuServiceTest : public testing::Test { +public: + GpuServiceTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + } + + ~GpuServiceTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); + } + +}; + + +/* +* The behaviour before this test + fixes was UB caused by threads accessing deallocated memory. +* +* This test creates the service (which initializes the culprit threads), +* deallocates it immediately and sleeps. +* +* GpuService's destructor gets called and joins the threads. +* If we haven't crashed by the time the sleep time has elapsed, we're good +* Let the test pass. +*/ +TEST_F(GpuServiceTest, onInitializeShouldNotCauseUseAfterFree) { + sp service = new GpuService(); + service.clear(); + std::this_thread::sleep_for(std::chrono::seconds(3)); + + // If we haven't crashed yet due to threads accessing freed up memory, let the test pass + EXPECT_TRUE(true); +} + +} // namespace +} // namespace android -- GitLab From ae3e9ae7ce09db3e93be5b0243e318653b6d9327 Mon Sep 17 00:00:00 2001 From: "hyejin.kim" Date: Tue, 20 Jun 2023 19:42:57 +0900 Subject: [PATCH 0228/1187] Adjust obb path to be able calculate external's codeSize well wo/quota Without quota, installd doesn't not calculate codeSize correctly use Android/obb, So we adjust to Android/obb. And we needed to remove external's codeSize from dataSize. - Test: run cts -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.StorageHostTest#testVerifyStats Change-Id: I253c62ef4a9171242e10c0bcf57047c207278868 --- cmds/installd/InstalldNativeService.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index e84428ee41..c6132e8ceb 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -2374,11 +2374,15 @@ static void collectManualExternalStatsForUser(const std::string& path, struct st p->fts_number = p->fts_parent->fts_number; switch (p->fts_info) { case FTS_D: - if (p->fts_level == 4 + if (p->fts_level == 3 + && !strcmp(p->fts_parent->fts_name, "obb") + && !strcmp(p->fts_parent->fts_parent->fts_name, "Android")) { + p->fts_number = 1; + } else if (p->fts_level == 4 && !strcmp(p->fts_name, "cache") && !strcmp(p->fts_parent->fts_parent->fts_name, "data") && !strcmp(p->fts_parent->fts_parent->fts_parent->fts_name, "Android")) { - p->fts_number = 1; + p->fts_number = 2; } [[fallthrough]]; // to count the directory case FTS_DEFAULT: @@ -2387,9 +2391,13 @@ static void collectManualExternalStatsForUser(const std::string& path, struct st case FTS_SLNONE: int64_t size = (p->fts_statp->st_blocks * 512); if (p->fts_number == 1) { - stats->cacheSize += size; + stats->codeSize += size; + } else { + if (p->fts_number == 2) { + stats->cacheSize += size; + } + stats->dataSize += size; } - stats->dataSize += size; break; } } @@ -2735,11 +2743,6 @@ binder::Status InstalldNativeService::getUserSize(const std::optional Date: Tue, 13 Jun 2023 19:46:05 -0400 Subject: [PATCH 0229/1187] libs: Add an empty-ish folder for libbufferstreams Bug: 285321812 Ignore-AOSP-First: new OWNERS file, no need to synchronize Test: n/a Change-Id: I3b7665b18a203fdf1a457593fd8827528bb7b079 --- libs/bufferstreams/Android.bp | 17 +++++++++++++++++ libs/bufferstreams/OWNERS | 7 +++++++ 2 files changed, 24 insertions(+) create mode 100644 libs/bufferstreams/Android.bp create mode 100644 libs/bufferstreams/OWNERS diff --git a/libs/bufferstreams/Android.bp b/libs/bufferstreams/Android.bp new file mode 100644 index 0000000000..e1dc9bafca --- /dev/null +++ b/libs/bufferstreams/Android.bp @@ -0,0 +1,17 @@ +// Copyright (C) 2023 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. + +package { + default_applicable_licenses: ["frameworks_native_license"], +} diff --git a/libs/bufferstreams/OWNERS b/libs/bufferstreams/OWNERS new file mode 100644 index 0000000000..32b72b8592 --- /dev/null +++ b/libs/bufferstreams/OWNERS @@ -0,0 +1,7 @@ +carlosmr@google.com +hibrian@google.com +jreck@google.com +jshargo@google.com + +file:/services/surfaceflinger/OWNERS + -- GitLab From fdf5481309c7d1752f72fbc3ce1ed2b984ab3859 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Wed, 28 Jun 2023 14:14:35 -0700 Subject: [PATCH 0230/1187] Binder tests: add explicit constructor to initialize ProcessSession Bug: 289151149 Test: binder_rpc_test Change-Id: I95da79d6707b77cfb7071aa91a65a25504a48fb3 --- libs/binder/tests/binderRpcTestFixture.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h index 6cde9f7f8d..0b8920b5a6 100644 --- a/libs/binder/tests/binderRpcTestFixture.h +++ b/libs/binder/tests/binderRpcTestFixture.h @@ -79,6 +79,7 @@ struct BinderRpcTestProcessSession { expectAlreadyShutdown = true; } + BinderRpcTestProcessSession(std::unique_ptr proc) : proc(std::move(proc)){}; BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default; ~BinderRpcTestProcessSession() { if (!expectAlreadyShutdown) { @@ -138,9 +139,7 @@ public: } BinderRpcTestProcessSession createRpcTestSocketServerProcess(const BinderRpcOptions& options) { - BinderRpcTestProcessSession ret{ - .proc = createRpcTestSocketServerProcessEtc(options), - }; + BinderRpcTestProcessSession ret(createRpcTestSocketServerProcessEtc(options)); ret.rootBinder = ret.proc->sessions.empty() ? nullptr : ret.proc->sessions.at(0).root; ret.rootIface = interface_cast(ret.rootBinder); -- GitLab From 6b93306d72c104eaa820302b0da01b1ee060fd66 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Wed, 28 Jun 2023 13:45:13 -0700 Subject: [PATCH 0231/1187] Deprecate function declarations, not definitions. Also, switch to the [[]] style. Bug: 289151149 Test: binder_rpc_test Change-Id: I8ea37fec636237b9360c7db23e9018b8edce9622 --- libs/binder/include/binder/Parcel.h | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 15bb325459..b879650056 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -265,7 +265,8 @@ public: status_t writeEnumVector(const std::optional>& val) { return writeData(val); } template && std::is_same_v,int8_t>, bool> = 0> - status_t writeEnumVector(const std::unique_ptr>& val) __attribute__((deprecated("use std::optional version instead"))) + [[deprecated("use std::optional version instead")]] // + status_t writeEnumVector(const std::unique_ptr>& val) { return writeData(val); } // Write an Enum vector with underlying type != int8_t. template && !std::is_same_v,int8_t>, bool> = 0> @@ -275,17 +276,20 @@ public: status_t writeEnumVector(const std::optional>& val) { return writeData(val); } template && !std::is_same_v,int8_t>, bool> = 0> - status_t writeEnumVector(const std::unique_ptr>& val) __attribute__((deprecated("use std::optional version instead"))) + [[deprecated("use std::optional version instead")]] // + status_t writeEnumVector(const std::unique_ptr>& val) { return writeData(val); } template status_t writeParcelableVector(const std::optional>>& val) { return writeData(val); } template - status_t writeParcelableVector(const std::unique_ptr>>& val) __attribute__((deprecated("use std::optional version instead"))) + [[deprecated("use std::optional version instead")]] // + status_t writeParcelableVector(const std::unique_ptr>>& val) { return writeData(val); } template - status_t writeParcelableVector(const std::shared_ptr>>& val) __attribute__((deprecated("use std::optional version instead"))) + [[deprecated("use std::optional version instead")]] // + status_t writeParcelableVector(const std::shared_ptr>>& val) { return writeData(val); } template status_t writeParcelableVector(const std::shared_ptr>>& val) @@ -421,7 +425,8 @@ public: status_t readEnumVector(std::vector* val) const { return readData(val); } template && std::is_same_v,int8_t>, bool> = 0> - status_t readEnumVector(std::unique_ptr>* val) const __attribute__((deprecated("use std::optional version instead"))) + [[deprecated("use std::optional version instead")]] // + status_t readEnumVector(std::unique_ptr>* val) const { return readData(val); } template && std::is_same_v,int8_t>, bool> = 0> status_t readEnumVector(std::optional>* val) const @@ -431,7 +436,8 @@ public: status_t readEnumVector(std::vector* val) const { return readData(val); } template && !std::is_same_v,int8_t>, bool> = 0> - status_t readEnumVector(std::unique_ptr>* val) const __attribute__((deprecated("use std::optional version instead"))) + [[deprecated("use std::optional version instead")]] // + status_t readEnumVector(std::unique_ptr>* val) const { return readData(val); } template && !std::is_same_v,int8_t>, bool> = 0> status_t readEnumVector(std::optional>* val) const @@ -442,8 +448,9 @@ public: std::optional>>* val) const { return readData(val); } template + [[deprecated("use std::optional version instead")]] // status_t readParcelableVector( - std::unique_ptr>>* val) const __attribute__((deprecated("use std::optional version instead"))) + std::unique_ptr>>* val) const { return readData(val); } template status_t readParcelableVector(std::vector* val) const -- GitLab From 418914a7c54f4aa0418b6ddbb5096b66286cd80e Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 28 Jun 2023 21:47:14 +0000 Subject: [PATCH 0232/1187] libbinder_ndk: fwd fuzzing status to NDK binders When passing binders into NDK backend services, we always type check them immediately. This allows errors to show up earlier there, but may be inefficient because the type will also be checked on every transaction. Anyway... This poses a problem for our automatic fuzzers because callbacks passed into services (e.g. RandomBinder) will be ignored for NDK backend fuzzers unless they correctly guess their interface descriptor. There are a few things we could do: - use random strings from the environment - export a list of possible interface descriptors from AIDL - generate our corpuses from other data However, the simplest thing we can do is ignore the check, which this CL does. Of course, it isn't great to continue differentiated fuzzer behavior from actual behavior, so we'd like to revert this once we have a more comprehensive solution. However, callbacks are a fundamental AIDL building blocks, so forcing good fuzzer coverage for these pieces seems justified. Bug: N/A Test: I added an abort in an NDK backend service. Without this change, that path is never found, but with this change, it was hit after only ~6,000 iterations. Change-Id: I4cbe5c56b93b9300fbd57e72e24075c02df38ba9 --- libs/binder/Parcel.cpp | 4 ++++ libs/binder/include/binder/Parcel.h | 1 + libs/binder/ndk/ibinder.cpp | 2 +- libs/binder/ndk/ibinder_internal.h | 4 ++++ libs/binder/ndk/parcel.cpp | 7 +++++++ 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 2c2a1b636e..9b685f9145 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -992,6 +992,10 @@ void Parcel::setServiceFuzzing() { mServiceFuzzing = true; } +bool Parcel::isServiceFuzzing() const { + return mServiceFuzzing; +} + binder::Status Parcel::enforceNoDataAvail() const { if (!mEnforceNoDataAvail) { return binder::Status::ok(); diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 15bb325459..87b63e5a50 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -152,6 +152,7 @@ public: // When fuzzing, we want to remove certain ABI checks that cause significant // lost coverage, and we also want to avoid logs that cost too much to write. void setServiceFuzzing(); + bool isServiceFuzzing() const; void freeData(); diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp index d0de7b96b5..f7dd9c9715 100644 --- a/libs/binder/ndk/ibinder.cpp +++ b/libs/binder/ndk/ibinder.cpp @@ -137,7 +137,7 @@ bool AIBinder::associateClass(const AIBinder_Class* clazz) { // since it's an error condition. Do the comparison after we take the lock and // check the pointer equality fast path. By always taking the lock, it's also // more flake-proof. However, the check is not dependent on the lock. - if (descriptor != newDescriptor) { + if (descriptor != newDescriptor && !(asABpBinder() && asABpBinder()->isServiceFuzzing())) { if (getBinder()->isBinderAlive()) { LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor << "' but descriptor is actually '" << SanitizeString(descriptor) << "'."; diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h index 67bb092f0f..9d5368f674 100644 --- a/libs/binder/ndk/ibinder_internal.h +++ b/libs/binder/ndk/ibinder_internal.h @@ -104,10 +104,14 @@ struct ABpBinder : public AIBinder { ::android::sp<::android::IBinder> getBinder() override { return mRemote; } ABpBinder* asABpBinder() override { return this; } + bool isServiceFuzzing() const { return mServiceFuzzing; } + void setServiceFuzzing() { mServiceFuzzing = true; } + private: friend android::sp; explicit ABpBinder(const ::android::sp<::android::IBinder>& binder); ::android::sp<::android::IBinder> mRemote; + bool mServiceFuzzing = false; }; struct AIBinder_Class { diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp index b5a2e2ff0b..037aa2e120 100644 --- a/libs/binder/ndk/parcel.cpp +++ b/libs/binder/ndk/parcel.cpp @@ -270,6 +270,13 @@ binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binde } sp ret = ABpBinder::lookupOrCreateFromBinder(readBinder); AIBinder_incStrong(ret.get()); + + if (ret.get() != nullptr && parcel->get()->isServiceFuzzing()) { + if (auto bp = ret->asABpBinder(); bp != nullptr) { + bp->setServiceFuzzing(); + } + } + *binder = ret.get(); return PruneStatusT(status); } -- GitLab From 7b5430b3290dd2575f7648a91a019ef2b2222480 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Wed, 28 Jun 2023 14:04:51 -0700 Subject: [PATCH 0233/1187] Make sure to handle new RpcSession::FileDescriptorTransportMode Bug: 289151149 Test: binder_rpc_test Change-Id: I0944e94e52219c6f040c304f50e70a16f5ae25cd --- libs/binder/RpcState.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 5c1b2305a6..bac2808b26 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -63,6 +63,7 @@ static bool enableAncillaryFds(RpcSession::FileDescriptorTransportMode mode) { case RpcSession::FileDescriptorTransportMode::TRUSTY: return true; } + LOG_ALWAYS_FATAL("Invalid FileDescriptorTransportMode: %d", static_cast(mode)); } RpcState::RpcState() {} -- GitLab From 359568888e7a923efc71cf43e68cdde124210278 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 28 Jun 2023 22:21:04 +0000 Subject: [PATCH 0234/1187] libbinder_ndk: document dump FD ownership The ownership here wasn't documented. Bug: 288448299 Test: N/A Change-Id: Id8339ebf3236bf0896c663346eccce50501a23b7 --- libs/binder/ndk/include_cpp/android/binder_interface_utils.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h index 9949de2aac..62738041ba 100644 --- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h +++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h @@ -138,6 +138,8 @@ class ICInterface : public SharedRefBase { /** * Dumps information about the interface. By default, dumps nothing. + * + * This method is not given ownership of the FD. */ virtual inline binder_status_t dump(int fd, const char** args, uint32_t numArgs); -- GitLab From cac842765a5bed53b7888bbd6017bba7eeb373a8 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 28 Jun 2023 14:43:25 -0700 Subject: [PATCH 0235/1187] Build libinputflinger for host We don't have a usecase for it today, but the main motivation here is to unify the target and host build parameters. Also, this exposed an issue where ::write wasn't wrapped. The host build produced an error: frameworks/native/services/inputflinger/InputManager.cpp:189:5: error: ignoring return value of function declared with 'warn_unused_result' attribute [-Werror,-Wunused-result] ::write(fd, dump.c_str(), dump.size()); Bug: 271455682 Test: m libinputflinger Change-Id: If1abc85b230f8e928422dab4c6bb33834b6393ee --- libs/input/Android.bp | 34 ++++---------------------- services/inputflinger/Android.bp | 1 + services/inputflinger/InputManager.cpp | 2 +- 3 files changed, 7 insertions(+), 30 deletions(-) diff --git a/libs/input/Android.bp b/libs/input/Android.bp index f777f2fe3e..6db7b47150 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -120,9 +120,11 @@ cc_library { "-Wno-unused-parameter", ], srcs: [ + "android/os/IInputFlinger.aidl", "Input.cpp", "InputDevice.cpp", "InputEventLabels.cpp", + "InputTransport.cpp", "InputVerifier.cpp", "Keyboard.cpp", "KeyCharacterMap.cpp", @@ -153,6 +155,7 @@ cc_library { shared_libs: [ "libbase", + "libbinder", "libcutils", "liblog", "libPlatformProperties", @@ -172,6 +175,7 @@ cc_library { static_libs: [ "inputconstants-cpp", + "libgui_window_info_static", "libui-types", "libtflite_static", ], @@ -181,6 +185,7 @@ cc_library { ], export_static_lib_headers: [ + "libgui_window_info_static", "libui-types", ], @@ -191,24 +196,10 @@ cc_library { target: { android: { - srcs: [ - "InputTransport.cpp", - "android/os/IInputFlinger.aidl", - ], - export_shared_lib_headers: ["libbinder"], shared_libs: [ "libutils", - "libbinder", - ], - - static_libs: [ - "libgui_window_info_static", - ], - - export_static_lib_headers: [ - "libgui_window_info_static", ], required: [ @@ -223,21 +214,6 @@ cc_library { "frameworks/native/libs/arect/include", ], }, - host_linux: { - srcs: [ - "InputTransport.cpp", - ], - static_libs: [ - "libgui_window_info_static", - ], - shared_libs: [ - "libbinder", - ], - - export_static_lib_headers: [ - "libgui_window_info_static", - ], - }, }, aidl: { diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 8f62629aa3..f4aab3b2de 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -118,6 +118,7 @@ cc_defaults { cc_library_shared { name: "libinputflinger", + host_supported: true, defaults: [ "inputflinger_defaults", "libinputflinger_defaults", diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index 1a9f47d934..09c88ba8dd 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -186,7 +186,7 @@ status_t InputManager::dump(int fd, const Vector& args) { dump += " InputFlinger dump\n"; - ::write(fd, dump.c_str(), dump.size()); + TEMP_FAILURE_RETRY(::write(fd, dump.c_str(), dump.size())); return NO_ERROR; } -- GitLab From 70a860470d3a9b9e7647b9b3ae9791220051f008 Mon Sep 17 00:00:00 2001 From: Trevor Black Date: Thu, 29 Jun 2023 14:26:30 +0000 Subject: [PATCH 0236/1187] Added Serdar to the GpuService OWNERS file Bug: 289078535 Change-Id: I4a8e8e5e78bb3440bad0fa7eb140049236502d7b Test: Land a CL at a later date --- services/gpuservice/OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/services/gpuservice/OWNERS b/services/gpuservice/OWNERS index 0ff65bf4ae..07c681f1f4 100644 --- a/services/gpuservice/OWNERS +++ b/services/gpuservice/OWNERS @@ -4,3 +4,4 @@ alecmouri@google.com lfy@google.com paulthomson@google.com pbaiget@google.com +kocdemir@google.com -- GitLab From e03e8b1cd7f68b19e82c8f332c117731154188dc Mon Sep 17 00:00:00 2001 From: Yeabkal Wubshit Date: Tue, 27 Jun 2023 16:23:12 -0700 Subject: [PATCH 0237/1187] Add support for device.wake InputDevice Property This change adds support for a device.wake InputDevice property. This property can be set to "1" by an InputDevice's IDC file, and the system would read that and sets wake flags (if applicable) to the events generated by the InputDevice. Bug: 289118119 Test: added "device.wake = 1" to a rotary-encoder IDC, and verified that the wake flag is sent to the WM policy Change-Id: I3ac8babefe7f241336080d2a3094489aa2b91e05 --- services/inputflinger/reader/InputDevice.cpp | 19 +++++ .../inputflinger/reader/include/InputDevice.h | 5 ++ .../inputflinger/tests/InputReader_test.cpp | 78 ++++++++++++++++++- 3 files changed, 101 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 0a64a1c4a8..2aaddf59bb 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -48,6 +48,7 @@ InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t genera mIdentifier(identifier), mClasses(0), mSources(0), + mIsWaking(false), mIsExternal(false), mHasMic(false), mDropUntilNextSync(false) {} @@ -101,6 +102,7 @@ void InputDevice::dump(std::string& dump, const std::string& eventHubDevStr) { dump += StringPrintf(INDENT "%s", eventHubDevStr.c_str()); dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration); dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); + dump += StringPrintf(INDENT2 "IsWaking: %s\n", toString(mIsWaking)); dump += StringPrintf(INDENT2 "AssociatedDisplayPort: "); if (mAssociatedDisplayPort) { dump += StringPrintf("%" PRIu8 "\n", *mAssociatedDisplayPort); @@ -220,6 +222,7 @@ std::list InputDevice::configure(nsecs_t when, mAssociatedDeviceType = getValueByKey(readerConfig.deviceTypeAssociations, mIdentifier.location); + mIsWaking = mConfiguration.getBool("device.wake").value_or(false); } if (!changes.any() || changes.test(Change::KEYBOARD_LAYOUTS)) { @@ -376,9 +379,25 @@ std::list InputDevice::process(const RawEvent* rawEvents, size_t cou } --count; } + postProcess(out); return out; } +void InputDevice::postProcess(std::list& args) const { + if (mIsWaking) { + // Update policy flags to request wake for the `NotifyArgs` that come from waking devices. + for (auto& arg : args) { + if (const auto notifyMotionArgs = std::get_if(&arg)) { + notifyMotionArgs->policyFlags |= POLICY_FLAG_WAKE; + } else if (const auto notifySwitchArgs = std::get_if(&arg)) { + notifySwitchArgs->policyFlags |= POLICY_FLAG_WAKE; + } else if (const auto notifyKeyArgs = std::get_if(&arg)) { + notifyKeyArgs->policyFlags |= POLICY_FLAG_WAKE; + } + } + } +} + std::list InputDevice::timeoutExpired(nsecs_t when) { std::list out; for_each_mapper([&](InputMapper& mapper) { out += mapper.timeoutExpired(when); }); diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 2f8e5bd6cf..aae3fe79e0 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -191,6 +191,7 @@ private: std::unique_ptr mController; uint32_t mSources; + bool mIsWaking; bool mIsExternal; std::optional mAssociatedDisplayPort; std::optional mAssociatedDisplayUniqueId; @@ -207,6 +208,10 @@ private: PropertyMap mConfiguration; + // Runs logic post a `process` call. This can be used to update the generated `NotifyArgs` as + // per the properties of the InputDevice. + void postProcess(std::list& args) const; + // helpers to interate over the devices collection // run a function against every mapper on every subdevice inline void for_each_mapper(std::function f) { diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 5fb364d185..e751c89c4e 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -161,6 +161,7 @@ class FakeInputMapper : public InputMapper { // fake mapping which would normally come from keyCharacterMap std::unordered_map mKeyCodeMapping; std::vector mSupportedKeyCodes; + std::list mProcessResult; std::mutex mLock; std::condition_variable mStateChangedCondition; @@ -191,6 +192,14 @@ public: mMetaState = metaState; } + // Sets the return value for the `process` call. + void setProcessResult(std::list notifyArgs) { + mProcessResult.clear(); + for (auto notifyArg : notifyArgs) { + mProcessResult.push_back(notifyArg); + } + } + void assertConfigureWasCalled() { std::unique_lock lock(mLock); base::ScopedLockAssertion assumeLocked(mLock); @@ -291,7 +300,7 @@ private: mLastEvent = *rawEvent; mProcessWasCalled = true; mStateChangedCondition.notify_all(); - return {}; + return mProcessResult; } int32_t getKeyCodeState(uint32_t, int32_t keyCode) override { @@ -2475,6 +2484,73 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe ASSERT_NO_FATAL_FAILURE(mapper2.assertProcessWasCalled()); } +TEST_F(InputDeviceTest, WakeDevice_AddsWakeFlagToProcessNotifyArgs) { + mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "device.wake", "1"); + FakeInputMapper& mapper = + mDevice->addMapper(EVENTHUB_ID, mFakePolicy->getReaderConfiguration(), + AINPUT_SOURCE_KEYBOARD); + NotifyMotionArgs args1; + NotifySwitchArgs args2; + NotifyKeyArgs args3; + mapper.setProcessResult({args1, args2, args3}); + + InputReaderConfiguration config; + std::list unused = mDevice->configure(ARBITRARY_TIME, config, /*changes=*/{}); + + RawEvent event; + event.deviceId = EVENTHUB_ID; + std::list notifyArgs = mDevice->process(&event, 1); + + for (auto& arg : notifyArgs) { + if (const auto notifyMotionArgs = std::get_if(&arg)) { + ASSERT_EQ(POLICY_FLAG_WAKE, notifyMotionArgs->policyFlags); + } else if (const auto notifySwitchArgs = std::get_if(&arg)) { + ASSERT_EQ(POLICY_FLAG_WAKE, notifySwitchArgs->policyFlags); + } else if (const auto notifyKeyArgs = std::get_if(&arg)) { + ASSERT_EQ(POLICY_FLAG_WAKE, notifyKeyArgs->policyFlags); + } + } +} + +TEST_F(InputDeviceTest, NotWakeDevice_DoesNotAddWakeFlagToProcessNotifyArgs) { + mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "device.wake", "0"); + FakeInputMapper& mapper = + mDevice->addMapper(EVENTHUB_ID, mFakePolicy->getReaderConfiguration(), + AINPUT_SOURCE_KEYBOARD); + NotifyMotionArgs args; + mapper.setProcessResult({args}); + + InputReaderConfiguration config; + std::list unused = mDevice->configure(ARBITRARY_TIME, config, /*changes=*/{}); + + RawEvent event; + event.deviceId = EVENTHUB_ID; + std::list notifyArgs = mDevice->process(&event, 1); + + // POLICY_FLAG_WAKE is not added to the NotifyArgs. + ASSERT_EQ(0u, std::get(notifyArgs.front()).policyFlags); +} + +TEST_F(InputDeviceTest, NotWakeDevice_DoesNotRemoveExistingWakeFlagFromProcessNotifyArgs) { + mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "device.wake", "0"); + FakeInputMapper& mapper = + mDevice->addMapper(EVENTHUB_ID, mFakePolicy->getReaderConfiguration(), + AINPUT_SOURCE_KEYBOARD); + NotifyMotionArgs args; + args.policyFlags = POLICY_FLAG_WAKE; + mapper.setProcessResult({args}); + + InputReaderConfiguration config; + std::list unused = mDevice->configure(ARBITRARY_TIME, config, /*changes=*/{}); + + RawEvent event; + event.deviceId = EVENTHUB_ID; + std::list notifyArgs = mDevice->process(&event, 1); + + // The POLICY_FLAG_WAKE is preserved, despite the device being a non-wake device. + ASSERT_EQ(POLICY_FLAG_WAKE, std::get(notifyArgs.front()).policyFlags); +} + // A single input device is associated with a specific display. Check that: // 1. Device is disabled if the viewport corresponding to the associated display is not found // 2. Device is disabled when setEnabled API is called -- GitLab From d38bc3a69623a5bc60607a2dbb3ba7bf7ce7a937 Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Thu, 29 Jun 2023 15:48:28 -0700 Subject: [PATCH 0238/1187] Add the build and aconfig default values to bugreports. Bug: 288892759 Test: adb bugreport Change-Id: Idbc82ba85ab52ffd0ebbab218200d250b8e665cc --- cmds/dumpstate/dumpstate.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index dc0e26b9a3..5cd58056fc 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1750,6 +1750,20 @@ static Dumpstate::RunStatus dumpstate() { RunCommand("SYSTEM PROPERTIES", {"getprop"}); + DumpFile("SYSTEM BUILD-TIME RELEASE FLAGS", "/system/etc/build_flags.json"); + DumpFile("SYSTEM_EXT BUILD-TIME RELEASE FLAGS", "/system_ext/etc/build_flags.json"); + DumpFile("PRODUCT BUILD-TIME RELEASE FLAGS", "/product/etc/build_flags.json"); + DumpFile("VENDOR BUILD-TIME RELEASE FLAGS", "/vendor/etc/build_flags.json"); + + DumpFile("SYSTEM BUILD-TIME ACONFIG FLAGS (check dumpstate build_config for runtime values)", + "/system/etc/aconfig_flags.textproto"); + DumpFile("SYSTEM_EXT BUILD-TIME ACONFIG FLAGS (check dumpstate build_config for runtime" + " values)", "/system_ext/etc/aconfig_flags.textproto"); + DumpFile("PRODUCT BUILD-TIME ACONFIG FLAGS (check dumpstate build_config for runtime values)", + "/product/etc/aconfig_flags.textproto"); + DumpFile("VENDOR BUILD-TIME ACONFIG FLAGS (check dumpstate build_config for runtime values)", + "/vendor/etc/aconfig_flags.textproto"); + RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"}); RunCommand("FILESYSTEMS & FREE SPACE", {"df"}); -- GitLab From 17362f1d16dd8202be61f23c5712c3e38c48b948 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 29 Jun 2023 23:42:56 +0000 Subject: [PATCH 0239/1187] Enable crashing fuzzer on infra Test: m test_service_fuzzer_should_crash Bug: 289438990 Change-Id: I3b1be2003c03d8ec43043ada67852d0cec922793 --- libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp index 690c39afc9..96092b10d3 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp @@ -36,8 +36,8 @@ cc_fuzz { triage_assignee: "waghpawan@google.com", // This fuzzer should be used only test fuzzService locally - fuzz_on_haiku_host: false, - fuzz_on_haiku_device: false, + fuzz_on_haiku_host: true, + fuzz_on_haiku_device: true, }, } -- GitLab From 866043a015be26d53463c42a1ad3a93957537a09 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 29 Jun 2023 23:20:42 +0000 Subject: [PATCH 0240/1187] Revert "Delete fds and binders in fuzzService" This reverts commit d6e4ebb75557d7fabc0e788db39084f607a26a81. Reason for revert: Debugging changes on infra leading to lesser fuzzer bugs Test: atest -c fuzz_service_test Change-Id: I6272086c267c9f56db5ff28945d0d5057cb0ab4d --- .../tests/parcel_fuzzer/libbinder_driver.cpp | 97 +++++++------------ 1 file changed, 35 insertions(+), 62 deletions(-) diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index 24a9345193..9078676031 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -43,72 +43,45 @@ void fuzzService(const std::vector>& binders, FuzzedDataProvider&& p } while (provider.remaining_bytes() > 0) { - provider.PickValueInArray>({ - [&]() { - // Most of the AIDL services will have small set of transaction codes. - uint32_t code = provider.ConsumeBool() - ? provider.ConsumeIntegral() - : provider.ConsumeIntegralInRange(0, 100); - uint32_t flags = provider.ConsumeIntegral(); - Parcel data; - // for increased fuzz coverage - data.setEnforceNoDataAvail(false); - data.setServiceFuzzing(); + // Most of the AIDL services will have small set of transaction codes. + uint32_t code = provider.ConsumeBool() ? provider.ConsumeIntegral() + : provider.ConsumeIntegralInRange(0, 100); + uint32_t flags = provider.ConsumeIntegral(); + Parcel data; + // for increased fuzz coverage + data.setEnforceNoDataAvail(false); + data.setServiceFuzzing(); - sp target = options.extraBinders.at( - provider.ConsumeIntegralInRange(0, - options.extraBinders.size() - - 1)); - options.writeHeader = [&target](Parcel* p, FuzzedDataProvider& provider) { - // most code will be behind checks that the head of the Parcel - // is exactly this, so make it easier for fuzzers to reach this - if (provider.ConsumeBool()) { - p->writeInterfaceToken(target->getInterfaceDescriptor()); - } - }; + sp target = options.extraBinders.at( + provider.ConsumeIntegralInRange(0, options.extraBinders.size() - 1)); + options.writeHeader = [&target](Parcel* p, FuzzedDataProvider& provider) { + // most code will be behind checks that the head of the Parcel + // is exactly this, so make it easier for fuzzers to reach this + if (provider.ConsumeBool()) { + p->writeInterfaceToken(target->getInterfaceDescriptor()); + } + }; - std::vector subData = provider.ConsumeBytes( - provider.ConsumeIntegralInRange(0, provider.remaining_bytes())); - fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), - &options); + std::vector subData = provider.ConsumeBytes( + provider.ConsumeIntegralInRange(0, provider.remaining_bytes())); + fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), &options); - Parcel reply; - // for increased fuzz coverage - reply.setEnforceNoDataAvail(false); - reply.setServiceFuzzing(); - (void)target->transact(code, data, &reply, flags); + Parcel reply; + // for increased fuzz coverage + reply.setEnforceNoDataAvail(false); + reply.setServiceFuzzing(); + (void)target->transact(code, data, &reply, flags); - // feed back in binders and fds that are returned from the service, so that - // we can fuzz those binders, and use the fds and binders to feed back into - // the binders - auto retBinders = reply.debugReadAllStrongBinders(); - options.extraBinders.insert(options.extraBinders.end(), retBinders.begin(), - retBinders.end()); - auto retFds = reply.debugReadAllFileDescriptors(); - for (size_t i = 0; i < retFds.size(); i++) { - options.extraFds.push_back(base::unique_fd(dup(retFds[i]))); - } - }, - [&]() { - if (options.extraFds.size() == 0) { - return; - } - uint32_t toDelete = - provider.ConsumeIntegralInRange(0, - options.extraFds.size() - 1); - options.extraFds.erase(options.extraFds.begin() + toDelete); - }, - [&]() { - if (options.extraBinders.size() <= 1) { - return; - } - uint32_t toDelete = - provider.ConsumeIntegralInRange(0, - options.extraBinders.size() - - 1); - options.extraBinders.erase(options.extraBinders.begin() + toDelete); - }, - })(); + // feed back in binders and fds that are returned from the service, so that + // we can fuzz those binders, and use the fds and binders to feed back into + // the binders + auto retBinders = reply.debugReadAllStrongBinders(); + options.extraBinders.insert(options.extraBinders.end(), retBinders.begin(), + retBinders.end()); + auto retFds = reply.debugReadAllFileDescriptors(); + for (size_t i = 0; i < retFds.size(); i++) { + options.extraFds.push_back(base::unique_fd(dup(retFds[i]))); + } } // invariants -- GitLab From 6981fe0a043f01b45525cec07c2b30a6a4047b0c Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 29 Jun 2023 23:54:10 +0000 Subject: [PATCH 0241/1187] libbinder fuzzer driver: clear calling identity This gets set in thread local state. Bug: N/A Test: servicemanager fuzzer will test past SELinux checks (gives even mix of this and specifically set UID) Change-Id: I42d39eecd3ceca6e702dec1df725e5f7e83b6a26 --- libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index 24a9345193..5905f7b7c1 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -33,6 +33,10 @@ void fuzzService(const std::vector>& binders, FuzzedDataProvider&& p .extraFds = {}, }; + // always refresh the calling identity, because we sometimes set it below, but also, + // the code we're fuzzing might reset it + IPCThreadState::self()->clearCallingIdentity(); + // Always take so that a perturbation of just the one ConsumeBool byte will always // take the same path, but with a different UID. Without this, the fuzzer needs to // guess both the change in value and the shift at the same time. -- GitLab From acd87a55e3724d675ae4f3c1778a12a7a53ddfae Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 30 Jun 2023 01:14:55 +0000 Subject: [PATCH 0242/1187] fuzz_service_test: test restore calling ID Test for recently changed libbinder driver code. Bug: N/A Test: atest fuzz_service_test Change-Id: I6669c4002b2cf1f2bf43d8a48ff674d05765b67d --- .../test_fuzzer/ITestService.aidl | 4 +- .../test_fuzzer/TestServiceFuzzer.cpp | 87 ++++++++++++++++--- .../test_fuzzer/run_fuzz_service_test.sh | 24 ++--- 3 files changed, 93 insertions(+), 22 deletions(-) mode change 100644 => 100755 libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/ITestService.aidl b/libs/binder/tests/parcel_fuzzer/test_fuzzer/ITestService.aidl index 3eadc02387..5089ae5004 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/ITestService.aidl +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/ITestService.aidl @@ -21,4 +21,6 @@ interface ITestService { void setCharData(char input); void setBooleanData(boolean input); -} \ No newline at end of file + + void setService(ITestService service); +} diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp index 8907ea0c54..7fbf2d0670 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp @@ -17,35 +17,102 @@ #include #include +#include #include -using android::fuzzService; -using android::sp; using android::binder::Status; namespace android { + +enum class CrashType { + NONE, + ON_PLAIN, + ON_BINDER, + ON_KNOWN_UID, +}; + // This service is to verify that fuzzService is functioning properly class TestService : public BnTestService { public: - Status setIntData(int /*input*/) { - LOG_ALWAYS_FATAL("Expected crash in setIntData"); + TestService(CrashType crash) : mCrash(crash) {} + + void onData() { + switch (mCrash) { + case CrashType::ON_PLAIN: { + LOG_ALWAYS_FATAL("Expected crash, PLAIN."); + break; + } + case CrashType::ON_KNOWN_UID: { + if (IPCThreadState::self()->getCallingUid() == getuid()) { + LOG_ALWAYS_FATAL("Expected crash, KNOWN_UID."); + } + break; + } + default: + break; + } + } + + Status setIntData(int /*input*/) override { + onData(); return Status::ok(); } - Status setCharData(char16_t /*input*/) { - LOG_ALWAYS_FATAL("Expected crash in setCharData"); + Status setCharData(char16_t /*input*/) override { + onData(); return Status::ok(); } - Status setBooleanData(bool /*input*/) { - LOG_ALWAYS_FATAL("Expected crash in setBooleanData"); + Status setBooleanData(bool /*input*/) override { + onData(); return Status::ok(); } + + Status setService(const sp& service) override { + onData(); + if (mCrash == CrashType::ON_BINDER && service != nullptr) { + LOG_ALWAYS_FATAL("Expected crash, BINDER."); + } + return Status::ok(); + } + +private: + CrashType mCrash; }; -} // namespace android + +CrashType gCrashType = CrashType::NONE; + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + if (*argc < 2) { + printf("You must specify at least one argument\n"); + exit(0); // success because this is a crash test + } + + std::string arg = std::string((*argv)[1]); + + // ignore first argument, because we consume it + (*argv)[1] = (*argv[0]); + (*argc)--; + (*argv)++; + + if (arg == "PLAIN") { + gCrashType = CrashType::ON_PLAIN; + } else if (arg == "KNOWN_UID") { + gCrashType = CrashType::ON_KNOWN_UID; + } else if (arg == "BINDER") { + gCrashType = CrashType::ON_BINDER; + } else { + printf("INVALID ARG\n"); + exit(0); // success because this is a crash test + } + + return 0; +} extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - auto service = sp::make(); + auto service = sp::make(gCrashType); fuzzService(service, FuzzedDataProvider(data, size)); return 0; } + +} // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh old mode 100644 new mode 100755 index cec52fd6e7..e568035af1 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh @@ -27,16 +27,18 @@ then exit 1 fi -echo "INFO: Running fuzzer : test_service_fuzzer_should_crash" +for CRASH_TYPE in PLAIN KNOWN_UID BINDER; do + echo "INFO: Running fuzzer : test_service_fuzzer_should_crash $CRASH_TYPE" -./test_service_fuzzer_should_crash -max_total_time=30 &>${FUZZER_OUT} + ./test_service_fuzzer_should_crash "$CRASH_TYPE" -max_total_time=30 &>"$FUZZER_OUT" -echo "INFO: Searching fuzzer output for expected crashes" -if grep -q "Expected crash in set" ${FUZZER_OUT}; -then - echo -e "${color_success}Success: Found expected crash. fuzzService test successful!" -else - echo -e "${color_failed}Failed: Unable to find successful fuzzing output from test_service_fuzzer_should_crash" - echo "${color_reset}" - exit 1 -fi + echo "INFO: Searching fuzzer output for expected crashes" + if grep -q "Expected crash, $CRASH_TYPE." "$FUZZER_OUT" + then + echo -e "${color_success}Success: Found expected crash. fuzzService test successful!" + else + echo -e "${color_failed}Failed: Unable to find successful fuzzing output from test_service_fuzzer_should_crash" + echo "${color_reset}" + exit 1 + fi +done -- GitLab From 1fd9bfca9d86a3b0d0ff46596ec948b147f44619 Mon Sep 17 00:00:00 2001 From: Ying Wei Date: Thu, 29 Jun 2023 16:47:00 +0000 Subject: [PATCH 0243/1187] Remove debug.sf.latch_unsignaled sysprop and LatchUnsignaledConfig::ALWAYS Test: atest TransactionApplicationTest BUG: b/198190129 Change-Id: I23c61b9adc4f828c846c8dbe2c54dc4f3ee88953 --- services/surfaceflinger/SurfaceFlinger.cpp | 17 +- .../fuzzer/surfaceflinger_fuzzer.cpp | 1 - .../unittests/TransactionApplicationTest.cpp | 223 +----------------- 3 files changed, 3 insertions(+), 238 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 927a826cba..8cc858e1e1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -497,10 +497,6 @@ LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { return LatchUnsignaledConfig::AutoSingleLayer; } - if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) { - return LatchUnsignaledConfig::Always; - } - return LatchUnsignaledConfig::Disabled; } @@ -4364,12 +4360,10 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC return TraverseBuffersReturnValues::STOP_TRAVERSAL; } - // ignore the acquire fence if LatchUnsignaledConfig::Always is set. - const bool checkAcquireFence = enableLatchUnsignaledConfig != LatchUnsignaledConfig::Always; const bool acquireFenceAvailable = s.bufferData && s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) && s.bufferData->acquireFence; - const bool fenceSignaled = !checkAcquireFence || !acquireFenceAvailable || + const bool fenceSignaled = !acquireFenceAvailable || s.bufferData->acquireFence->getStatus() != Fence::Status::Unsignaled; if (!fenceSignaled) { // check fence status @@ -4463,12 +4457,10 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC return TraverseBuffersReturnValues::STOP_TRAVERSAL; } - // ignore the acquire fence if LatchUnsignaledConfig::Always is set. - const bool checkAcquireFence = enableLatchUnsignaledConfig != LatchUnsignaledConfig::Always; const bool acquireFenceAvailable = s.bufferData && s.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged) && s.bufferData->acquireFence; - const bool fenceSignaled = !checkAcquireFence || !acquireFenceAvailable || + const bool fenceSignaled = !acquireFenceAvailable || s.bufferData->acquireFence->getStatus() != Fence::Status::Unsignaled; if (!fenceSignaled) { // check fence status @@ -4574,11 +4566,6 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const layer_state_t& state, size_t nu return false; } - if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Always) { - ATRACE_FORMAT_INSTANT("%s: true (LatchUnsignaledConfig::Always)", __func__); - return true; - } - // We only want to latch unsignaled when a single layer is updated in this // transaction (i.e. not a blast sync transaction). if (numStates != 1) { diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp index 80943b5b63..b2d4131b5d 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp @@ -24,7 +24,6 @@ namespace android::fuzz { static constexpr LatchUnsignaledConfig kLatchUnsignaledConfig[] = { - LatchUnsignaledConfig::Always, LatchUnsignaledConfig::AutoSingleLayer, LatchUnsignaledConfig::Disabled, }; diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index e936ee0b29..644b8c70c6 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -15,7 +15,7 @@ */ #undef LOG_TAG -#define LOG_TAG "CompositionTest" +#define LOG_TAG "TransactionApplicationTest" #include #include @@ -855,227 +855,6 @@ TEST_F(LatchUnsignaledDisabledTest, Flush_KeepInTheUnsignaledTheQueue) { kExpectedTransactionsPending); } -class LatchUnsignaledAlwaysTest : public LatchUnsignaledTest { -public: - void SetUp() override { - LatchUnsignaledTest::SetUp(); - SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; - } -}; - -TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesSignaledFromTheQueue) { - const sp kApplyToken = - IInterface::asBinder(TransactionCompletedListener::getIInstance()); - const auto kLayerId = 1; - const auto kExpectedTransactionsPending = 0u; - - const auto signaledTransaction = - createTransactionInfo(kApplyToken, - {createComposerState(kLayerId, fence(Fence::Status::Signaled), - layer_state_t::eBufferChanged)}); - setTransactionStates({signaledTransaction}, kExpectedTransactionsPending); -} - -TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueue) { - const sp kApplyToken = - IInterface::asBinder(TransactionCompletedListener::getIInstance()); - const auto kLayerId = 1; - const auto kExpectedTransactionsPending = 0u; - - const auto unsignaledTransaction = - createTransactionInfo(kApplyToken, - {createComposerState(kLayerId, fence(Fence::Status::Unsignaled), - layer_state_t::eBufferChanged)}); - setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending); -} - -TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueSameLayerId) { - const sp kApplyToken = - IInterface::asBinder(TransactionCompletedListener::getIInstance()); - const auto kLayerId = 1; - const auto kExpectedTransactionsPending = 0u; - - const auto mixedTransaction = - createTransactionInfo(kApplyToken, - {createComposerState(kLayerId, fence(Fence::Status::Unsignaled), - layer_state_t::eBufferChanged), - createComposerState(kLayerId, fence(Fence::Status::Signaled), - layer_state_t::eBufferChanged)}); - setTransactionStates({mixedTransaction}, kExpectedTransactionsPending); -} - -TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueDifferentLayerId) { - const sp kApplyToken = - IInterface::asBinder(TransactionCompletedListener::getIInstance()); - const auto kLayerId1 = 1; - const auto kLayerId2 = 2; - const auto kExpectedTransactionsPending = 0u; - - const auto mixedTransaction = - createTransactionInfo(kApplyToken, - {createComposerState(kLayerId1, fence(Fence::Status::Unsignaled), - layer_state_t::eBufferChanged), - createComposerState(kLayerId2, fence(Fence::Status::Signaled), - layer_state_t::eBufferChanged)}); - setTransactionStates({mixedTransaction}, kExpectedTransactionsPending); -} - -TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesSignaledFromTheQueue_MultipleLayers) { - const sp kApplyToken = - IInterface::asBinder(TransactionCompletedListener::getIInstance()); - const auto kLayerId1 = 1; - const auto kLayerId2 = 2; - const auto kExpectedTransactionsPending = 0u; - - const auto signaledTransaction = - createTransactionInfo(kApplyToken, - { - createComposerState(kLayerId1, - fence(Fence::Status::Signaled), - layer_state_t::eBufferChanged), - }); - const auto signaledTransaction2 = - createTransactionInfo(kApplyToken, - { - createComposerState(kLayerId2, - fence(Fence::Status::Signaled), - layer_state_t::eBufferChanged), - }); - setTransactionStates({signaledTransaction, signaledTransaction2}, kExpectedTransactionsPending); -} - -TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesFromTheQueueDifferentApplyToken) { - const sp kApplyToken1 = - IInterface::asBinder(TransactionCompletedListener::getIInstance()); - const sp kApplyToken2 = sp::make(); - const auto kLayerId1 = 1; - const auto kLayerId2 = 2; - const auto kExpectedTransactionsPending = 0u; - - const auto signaledTransaction = - createTransactionInfo(kApplyToken1, - { - createComposerState(kLayerId1, - fence(Fence::Status::Signaled), - layer_state_t::eBufferChanged), - }); - const auto unsignaledTransaction = - createTransactionInfo(kApplyToken2, - { - createComposerState(kLayerId2, - fence(Fence::Status::Unsignaled), - layer_state_t::eBufferChanged), - }); - setTransactionStates({signaledTransaction, unsignaledTransaction}, - kExpectedTransactionsPending); -} - -TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesUnsignaledFromTheQueueSameApplyToken) { - const sp kApplyToken = - IInterface::asBinder(TransactionCompletedListener::getIInstance()); - const auto kLayerId1 = 1; - const auto kLayerId2 = 2; - const auto kExpectedTransactionsPending = 0u; - - const auto unsignaledTransaction = - createTransactionInfo(kApplyToken, - { - createComposerState(kLayerId1, - fence(Fence::Status::Unsignaled), - layer_state_t::eBufferChanged), - }); - const auto signaledTransaction = - createTransactionInfo(kApplyToken, - { - createComposerState(kLayerId2, - fence(Fence::Status::Signaled), - layer_state_t::eBufferChanged), - }); - setTransactionStates({unsignaledTransaction, signaledTransaction}, - kExpectedTransactionsPending); -} - -TEST_F(LatchUnsignaledAlwaysTest, Flush_RemovesUnsignaledFromTheQueue) { - const sp kApplyToken1 = - IInterface::asBinder(TransactionCompletedListener::getIInstance()); - const sp kApplyToken2 = sp::make(); - const auto kLayerId1 = 1; - const auto kLayerId2 = 2; - const auto kExpectedTransactionsPending = 0u; - - const auto unsignaledTransaction = - createTransactionInfo(kApplyToken1, - { - createComposerState(kLayerId1, - fence(Fence::Status::Unsignaled), - layer_state_t::eBufferChanged), - }); - const auto unsignaledTransaction2 = - createTransactionInfo(kApplyToken2, - { - createComposerState(kLayerId2, - fence(Fence::Status::Unsignaled), - layer_state_t::eBufferChanged), - }); - setTransactionStates({unsignaledTransaction, unsignaledTransaction2}, - kExpectedTransactionsPending); -} - -TEST_F(LatchUnsignaledAlwaysTest, RespectsBackPressureFlag) { - const sp kApplyToken1 = - IInterface::asBinder(TransactionCompletedListener::getIInstance()); - const sp kApplyToken2 = sp::make(); - const auto kLayerId1 = 1; - const auto kExpectedTransactionsPending = 1u; - auto layer = - sp::make(LayerCreationArgs(mFlinger.flinger(), nullptr, "TestLayer", 0, {})); - auto layerHandle = layer->getHandle(); - const auto setBackPressureFlagTransaction = - createTransactionInfo(kApplyToken1, - {createComposerState(kLayerId1, fence(Fence::Status::Unsignaled), - layer_state_t::eBufferChanged | - layer_state_t::eFlagsChanged, - {layerHandle})}); - setTransactionStates({setBackPressureFlagTransaction}, 0u); - - const auto unsignaledTransaction = - createTransactionInfo(kApplyToken1, - { - createComposerState(kLayerId1, - fence(Fence::Status::Unsignaled), - layer_state_t::eBufferChanged, - {layerHandle}), - }); - const auto unsignaledTransaction2 = - createTransactionInfo(kApplyToken1, - { - createComposerState(kLayerId1, - fence(Fence::Status::Unsignaled), - layer_state_t::eBufferChanged, - {layerHandle}), - }); - setTransactionStates({unsignaledTransaction, unsignaledTransaction2}, - kExpectedTransactionsPending); -} - -TEST_F(LatchUnsignaledAlwaysTest, LatchUnsignaledWhenEarlyOffset) { - const sp kApplyToken = - IInterface::asBinder(TransactionCompletedListener::getIInstance()); - const auto kLayerId = 1; - const auto kExpectedTransactionsPending = 0u; - - const auto unsignaledTransaction = - createTransactionInfo(kApplyToken, - { - createComposerState(kLayerId, - fence(Fence::Status::Unsignaled), - layer_state_t::eBufferChanged), - }); - - modulateVsync(); - setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending); -} - TEST(TransactionHandlerTest, QueueTransaction) { TransactionHandler handler; TransactionState transaction; -- GitLab From 3cc15a4f1d6cf72afbb4d883e038ebf9108c78a9 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 30 Jun 2023 06:20:22 +0000 Subject: [PATCH 0244/1187] [sf] add debug dump for new front end Test: window type populated correctly in sf dump Test: dumpsys SurfaceFlinger Bug: 238781169 Change-Id: I86e475393c8b157496862fa34420c13fc80d681c --- .../FrontEnd/LayerHierarchy.cpp | 32 ++++-- .../surfaceflinger/FrontEnd/LayerHierarchy.h | 9 +- .../surfaceflinger/FrontEnd/LayerSnapshot.cpp | 92 +++++++++++++++- .../surfaceflinger/FrontEnd/LayerSnapshot.h | 3 +- .../FrontEnd/RequestedLayerState.cpp | 17 +++ .../FrontEnd/RequestedLayerState.h | 2 + services/surfaceflinger/Layer.cpp | 58 +++++++++- services/surfaceflinger/Layer.h | 9 +- services/surfaceflinger/SurfaceFlinger.cpp | 102 +++++++++++++++--- services/surfaceflinger/SurfaceFlinger.h | 3 +- 10 files changed, 296 insertions(+), 31 deletions(-) diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp index 163d34575c..ab4c15d670 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp @@ -149,13 +149,33 @@ std::string LayerHierarchy::getDebugStringShort() const { return debug + "}"; } -std::string LayerHierarchy::getDebugString(const char* prefix) const { - std::string debug = prefix + getDebugStringShort(); - for (auto& [child, childVariant] : mChildren) { - std::string childPrefix = " " + std::string(prefix) + " " + std::to_string(childVariant); - debug += "\n" + child->getDebugString(childPrefix.c_str()); +void LayerHierarchy::dump(std::ostream& out, const std::string& prefix, + LayerHierarchy::Variant variant, bool isLastChild) const { + if (!mLayer) { + out << " ROOT"; + } else { + out << prefix + (isLastChild ? "└─ " : "├─ "); + if (variant == LayerHierarchy::Variant::Relative) { + out << "(Relative) "; + } else if (variant == LayerHierarchy::Variant::Mirror) { + out << "(Mirroring) " << *mLayer << "\n" + prefix + " └─ ..."; + return; + } + out << *mLayer; } - return debug; + + for (size_t i = 0; i < mChildren.size(); i++) { + auto& [child, childVariant] = mChildren[i]; + if (childVariant == LayerHierarchy::Variant::Detached) continue; + const bool lastChild = i == (mChildren.size() - 1); + std::string childPrefix = prefix; + if (mLayer) { + childPrefix += (isLastChild ? " " : "│ "); + } + out << "\n"; + child->dump(out, childPrefix, childVariant, lastChild); + } + return; } bool LayerHierarchy::hasRelZLoop(uint32_t& outInvalidRelativeRoot) const { diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h index 5389adab6a..1e4838727b 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h @@ -156,7 +156,12 @@ public: const RequestedLayerState* getLayer() const; const LayerHierarchy* getRelativeParent() const; const LayerHierarchy* getParent() const; - std::string getDebugString(const char* prefix = "") const; + friend std::ostream& operator<<(std::ostream& os, const LayerHierarchy& obj) { + std::string prefix = " "; + obj.dump(os, prefix, LayerHierarchy::Variant::Attached, /*isLastChild=*/false); + return os; + } + std::string getDebugStringShort() const; // Traverse the hierarchy and return true if loops are found. The outInvalidRelativeRoot // will contain the first relative root that was visited twice in a traversal. @@ -172,6 +177,8 @@ private: void updateChild(LayerHierarchy*, LayerHierarchy::Variant); void traverseInZOrder(const Visitor& visitor, LayerHierarchy::TraversalPath& parent) const; void traverse(const Visitor& visitor, LayerHierarchy::TraversalPath& parent) const; + void dump(std::ostream& out, const std::string& prefix, LayerHierarchy::Variant variant, + bool isLastChild) const; const RequestedLayerState* mLayer; LayerHierarchy* mParent = nullptr; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index f0826c6db3..6f68a92e66 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -39,6 +39,63 @@ void updateSurfaceDamage(const RequestedLayerState& requested, bool hasReadyFram } } +std::ostream& operator<<(std::ostream& os, const ui::Transform& transform) { + const uint32_t type = transform.getType(); + const uint32_t orientation = transform.getOrientation(); + if (type == ui::Transform::IDENTITY) { + return os; + } + + if (type & ui::Transform::UNKNOWN) { + std::string out; + transform.dump(out, "", ""); + os << out; + return os; + } + + if (type & ui::Transform::ROTATE) { + switch (orientation) { + case ui::Transform::ROT_0: + os << "ROT_0"; + break; + case ui::Transform::FLIP_H: + os << "FLIP_H"; + break; + case ui::Transform::FLIP_V: + os << "FLIP_V"; + break; + case ui::Transform::ROT_90: + os << "ROT_90"; + break; + case ui::Transform::ROT_180: + os << "ROT_180"; + break; + case ui::Transform::ROT_270: + os << "ROT_270"; + break; + case ui::Transform::ROT_INVALID: + default: + os << "ROT_INVALID"; + break; + } + } + + if (type & ui::Transform::SCALE) { + std::string out; + android::base::StringAppendF(&out, " scale x=%.4f y=%.4f ", transform.getScaleX(), + transform.getScaleY()); + os << out; + } + + if (type & ui::Transform::TRANSLATE) { + std::string out; + android::base::StringAppendF(&out, " tx=%.4f ty=%.4f ", transform.tx(), transform.ty()); + os << out; + } + + return os; +} + } // namespace LayerSnapshot::LayerSnapshot(const RequestedLayerState& state, @@ -59,6 +116,7 @@ LayerSnapshot::LayerSnapshot(const RequestedLayerState& state, } sequence = static_cast(state.id); name = state.name; + debugName = state.debugName; textureName = state.textureName; premultipliedAlpha = state.premultipliedAlpha; inputInfo.name = state.name; @@ -180,13 +238,13 @@ std::string LayerSnapshot::getIsVisibleReason() const { if (handleSkipScreenshotFlag & outputFilter.toInternalDisplay) return "eLayerSkipScreenshot"; if (invalidTransform) return "invalidTransform"; if (color.a == 0.0f && !hasBlur()) return "alpha = 0 and no blur"; - if (!hasSomethingToDraw()) return "!hasSomethingToDraw"; + if (!hasSomethingToDraw()) return "nothing to draw"; // visible std::stringstream reason; if (sidebandStream != nullptr) reason << " sidebandStream"; if (externalTexture != nullptr) - reason << " buffer:" << externalTexture->getId() << " frame:" << frameNumber; + reason << " buffer=" << externalTexture->getId() << " frame=" << frameNumber; if (fillsColor() || color.a > 0.0f) reason << " color{" << color << "}"; if (drawShadows()) reason << " shadowSettings.length=" << shadowSettings.length; if (backgroundBlurRadius > 0) reason << " backgroundBlurRadius=" << backgroundBlurRadius; @@ -232,6 +290,36 @@ std::string LayerSnapshot::getDebugString() const { return debug.str(); } +std::ostream& operator<<(std::ostream& out, const LayerSnapshot& obj) { + out << "Layer [" << obj.path.id; + if (obj.path.mirrorRootId != UNASSIGNED_LAYER_ID) { + out << " mirrored from " << obj.path.mirrorRootId; + } + out << "] " << obj.name << "\n " << (obj.isVisible ? "visible" : "invisible") + << " reason=" << obj.getIsVisibleReason(); + + if (!obj.geomLayerBounds.isEmpty()) { + out << "\n bounds={" << obj.transformedBounds.left << "," << obj.transformedBounds.top + << "," << obj.transformedBounds.bottom << "," << obj.transformedBounds.right << "}"; + } + + if (obj.geomLayerTransform.getType() != ui::Transform::IDENTITY) { + out << " toDisplayTransform={" << obj.geomLayerTransform << "}"; + } + + if (obj.hasInputInfo()) { + out << "\n input{" + << "(" << obj.inputInfo.inputConfig.string() << ")"; + if (obj.touchCropId != UNASSIGNED_LAYER_ID) out << " touchCropId=" << obj.touchCropId; + if (obj.inputInfo.replaceTouchableRegionWithCrop) out << " replaceTouchableRegionWithCrop"; + auto touchableRegion = obj.inputInfo.touchableRegion.getBounds(); + out << " touchableRegion={" << touchableRegion.left << "," << touchableRegion.top << "," + << touchableRegion.bottom << "," << touchableRegion.right << "}" + << "}"; + } + return out; +} + FloatRect LayerSnapshot::sourceBounds() const { if (!externalTexture) { return geomLayerBounds; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 2f45d52162..9f0822c4ac 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -67,6 +67,7 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { // generated from the same layer, for example when mirroring. int32_t sequence; std::string name; + std::string debugName; uint32_t textureName; bool contentOpaque; bool layerOpaqueFlagSet; @@ -145,7 +146,7 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { bool hasInputInfo() const; FloatRect sourceBounds() const; Hwc2::IComposerClient::BlendMode getBlendMode(const RequestedLayerState& requested) const; - + friend std::ostream& operator<<(std::ostream& os, const LayerSnapshot& obj); void merge(const RequestedLayerState& requested, bool forceUpdate, bool displayChanges, bool forceFullDamage, uint32_t displayRotationFlags); }; diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 065b8956c5..a4777d1148 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -127,6 +127,16 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) gameMode = gui::GameMode::Unsupported; requestedFrameRate = {}; cachingHint = gui::CachingHint::Enabled; + + if (name.length() > 77) { + std::string shortened; + shortened.append(name, 0, 36); + shortened.append("[...]"); + shortened.append(name, name.length() - 36); + debugName = std::move(shortened); + } else { + debugName = name; + } } void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerState) { @@ -371,6 +381,13 @@ std::string RequestedLayerState::getDebugString() const { return debug.str(); } +std::ostream& operator<<(std::ostream& out, const RequestedLayerState& obj) { + out << obj.debugName; + if (obj.relativeParentId != UNASSIGNED_LAYER_ID) out << " parent=" << obj.parentId; + if (!obj.handleAlive) out << " handleNotAlive"; + return out; +} + std::string RequestedLayerState::getDebugStringShort() const { return "[" + std::to_string(id) + "]" + name; } diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h index 8ca1cd6323..1c19d6d5fc 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h @@ -74,6 +74,7 @@ struct RequestedLayerState : layer_state_t { Rect getBufferCrop() const; std::string getDebugString() const; std::string getDebugStringShort() const; + friend std::ostream& operator<<(std::ostream& os, const RequestedLayerState& obj); aidl::android::hardware::graphics::composer3::Composition getCompositionType() const; bool hasValidRelativeParent() const; bool hasInputInfo() const; @@ -118,6 +119,7 @@ struct RequestedLayerState : layer_state_t { uint32_t bgColorLayerId = UNASSIGNED_LAYER_ID; uint64_t barrierFrameNumber = 0; uint32_t barrierProducerId = 0; + std::string debugName; // book keeping states bool handleAlive = true; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5a010e8af6..a430074e9c 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -402,7 +402,7 @@ void Layer::updateTrustedPresentationState(const DisplayDevice* display, mLastComputedTrustedPresentationState = false; if (!leaveState) { - const auto outputLayer = findOutputLayerForDisplay(display); + const auto outputLayer = findOutputLayerForDisplay(display, snapshot->path); if (outputLayer != nullptr) { if (outputLayer->getState().coveredRegionExcludingDisplayOverlays) { Region coveredRegion = @@ -741,6 +741,11 @@ const char* Layer::getDebugName() const { aidl::android::hardware::graphics::composer3::Composition Layer::getCompositionType( const DisplayDevice& display) const { const auto outputLayer = findOutputLayerForDisplay(&display); + return getCompositionType(outputLayer); +} + +aidl::android::hardware::graphics::composer3::Composition Layer::getCompositionType( + const compositionengine::OutputLayer* outputLayer) const { if (outputLayer == nullptr) { return aidl::android::hardware::graphics::composer3::Composition::INVALID; } @@ -1611,7 +1616,7 @@ void Layer::miniDumpHeader(std::string& result) { result.append("\n"); } -void Layer::miniDump(std::string& result, const DisplayDevice& display) const { +void Layer::miniDumpLegacy(std::string& result, const DisplayDevice& display) const { const auto outputLayer = findOutputLayerForDisplay(&display); if (!outputLayer) { return; @@ -1662,6 +1667,41 @@ void Layer::miniDump(std::string& result, const DisplayDevice& display) const { result.append("\n"); } +void Layer::miniDump(std::string& result, const frontend::LayerSnapshot& snapshot, + const DisplayDevice& display) const { + const auto outputLayer = findOutputLayerForDisplay(&display, snapshot.path); + if (!outputLayer) { + return; + } + + StringAppendF(&result, " %s\n", snapshot.debugName.c_str()); + StringAppendF(&result, " %10zu | ", snapshot.globalZ); + StringAppendF(&result, " %10d | ", + snapshot.layerMetadata.getInt32(gui::METADATA_WINDOW_TYPE, 0)); + StringAppendF(&result, "%10s | ", toString(getCompositionType(outputLayer)).c_str()); + const auto& outputLayerState = outputLayer->getState(); + StringAppendF(&result, "%10s | ", toString(outputLayerState.bufferTransform).c_str()); + const Rect& frame = outputLayerState.displayFrame; + StringAppendF(&result, "%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom); + const FloatRect& crop = outputLayerState.sourceCrop; + StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f | ", crop.left, crop.top, crop.right, + crop.bottom); + const auto frameRate = snapshot.frameRate; + if (frameRate.rate.isValid() || frameRate.type != FrameRateCompatibility::Default) { + StringAppendF(&result, "%s %15s %17s", to_string(frameRate.rate).c_str(), + ftl::enum_string(frameRate.type).c_str(), + ftl::enum_string(frameRate.seamlessness).c_str()); + } else { + result.append(41, ' '); + } + + const auto focused = isLayerFocusedBasedOnPriority(snapshot.frameRateSelectionPriority); + StringAppendF(&result, " [%s]\n", focused ? "*" : " "); + + result.append(kDumpTableRowLength, '-'); + result.append("\n"); +} + void Layer::dumpFrameStats(std::string& result) const { mFrameTracker.dumpStats(result); } @@ -2578,6 +2618,20 @@ compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( return display->getCompositionDisplay()->getOutputLayerForLayer(layerFE); } +compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( + const DisplayDevice* display, const frontend::LayerHierarchy::TraversalPath& path) const { + if (!display) return nullptr; + sp layerFE; + for (auto& [p, layer] : mLayerFEs) { + if (p == path) { + layerFE = layer; + } + } + + if (!layerFE) return nullptr; + return display->getCompositionDisplay()->getOutputLayerForLayer(layerFE); +} + Region Layer::getVisibleRegion(const DisplayDevice* display) const { const auto outputLayer = findOutputLayerForDisplay(display); return outputLayer ? outputLayer->getState().visibleRegion : Region(); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 2fbbbdcb5c..5d77657415 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -343,6 +343,7 @@ public: virtual sp getCompositionEngineLayerFE() const; virtual sp copyCompositionEngineLayerFE() const; sp getCompositionEngineLayerFE(const frontend::LayerHierarchy::TraversalPath&); + sp getOrCreateCompositionEngineLayerFE(const frontend::LayerHierarchy::TraversalPath&); const frontend::LayerSnapshot* getLayerSnapshot() const; frontend::LayerSnapshot* editLayerSnapshot(); @@ -692,7 +693,8 @@ public: gui::LayerDebugInfo getLayerDebugInfo(const DisplayDevice*) const; - void miniDump(std::string& result, const DisplayDevice&) const; + void miniDumpLegacy(std::string& result, const DisplayDevice&) const; + void miniDump(std::string& result, const frontend::LayerSnapshot&, const DisplayDevice&) const; void dumpFrameStats(std::string& result) const; void dumpOffscreenDebugInfo(std::string& result) const; void clearFrameStats(); @@ -960,6 +962,8 @@ protected: void addZOrderRelative(const wp& relative); void removeZOrderRelative(const wp& relative); compositionengine::OutputLayer* findOutputLayerForDisplay(const DisplayDevice*) const; + compositionengine::OutputLayer* findOutputLayerForDisplay( + const DisplayDevice*, const frontend::LayerHierarchy::TraversalPath& path) const; bool usingRelativeZ(LayerVector::StateSet) const; virtual ui::Transform getInputTransform() const; @@ -1064,7 +1068,8 @@ private: aidl::android::hardware::graphics::composer3::Composition getCompositionType( const DisplayDevice&) const; - + aidl::android::hardware::graphics::composer3::Composition getCompositionType( + const compositionengine::OutputLayer*) const; /** * Returns an unsorted vector of all layers that are part of this tree. * That includes the current layer and all its descendants. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 927a826cba..c17ba73824 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5735,7 +5735,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { {"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)}, {"--events"s, dumper(&SurfaceFlinger::dumpEvents)}, {"--frametimeline"s, argsDumper(&SurfaceFlinger::dumpFrameTimeline)}, - {"--hwclayers"s, dumper(&SurfaceFlinger::dumpHwcLayersMinidumpLocked)}, + {"--hwclayers"s, dumper(&SurfaceFlinger::dumpHwcLayersMinidumpLockedLegacy)}, {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)}, {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)}, {"--list"s, dumper(&SurfaceFlinger::listLayersLocked)}, @@ -5753,17 +5753,56 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { // traversals, which can result in use-after-frees. std::string compositionLayers; mScheduler - ->schedule([&] { - StringAppendF(&compositionLayers, "Composition layers\n"); - mDrawingState.traverseInZOrder([&](Layer* layer) { - auto* compositionState = layer->getCompositionState(); - if (!compositionState || !compositionState->isVisible) return; - - android::base::StringAppendF(&compositionLayers, "* Layer %p (%s)\n", layer, - layer->getDebugName() ? layer->getDebugName() - : ""); - compositionState->dump(compositionLayers); - }); + ->schedule([&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(kMainThreadContext) { + if (!mLayerLifecycleManagerEnabled) { + StringAppendF(&compositionLayers, "Composition layers\n"); + mDrawingState.traverseInZOrder([&](Layer* layer) { + auto* compositionState = layer->getCompositionState(); + if (!compositionState || !compositionState->isVisible) return; + android::base::StringAppendF(&compositionLayers, "* Layer %p (%s)\n", + layer, + layer->getDebugName() + ? layer->getDebugName() + : ""); + compositionState->dump(compositionLayers); + }); + } else { + std::ostringstream out; + out << "\nComposition list\n"; + ui::LayerStack lastPrintedLayerStackHeader = ui::INVALID_LAYER_STACK; + mLayerSnapshotBuilder.forEachVisibleSnapshot( + [&](std::unique_ptr& snapshot) { + if (snapshot->hasSomethingToDraw()) { + if (lastPrintedLayerStackHeader != + snapshot->outputFilter.layerStack) { + lastPrintedLayerStackHeader = + snapshot->outputFilter.layerStack; + out << "LayerStack=" << lastPrintedLayerStackHeader.id + << "\n"; + } + out << " " << *snapshot << "\n"; + } + }); + + out << "\nInput list\n"; + lastPrintedLayerStackHeader = ui::INVALID_LAYER_STACK; + mLayerSnapshotBuilder.forEachInputSnapshot( + [&](const frontend::LayerSnapshot& snapshot) { + if (lastPrintedLayerStackHeader != + snapshot.outputFilter.layerStack) { + lastPrintedLayerStackHeader = + snapshot.outputFilter.layerStack; + out << "LayerStack=" << lastPrintedLayerStackHeader.id + << "\n"; + } + out << " " << snapshot << "\n"; + }); + + out << "\nLayer Hierarchy\n" + << mLayerHierarchyBuilder.getHierarchy() << "\n\n"; + compositionLayers = out.str(); + dumpHwcLayersMinidump(compositionLayers); + } }) .get(); @@ -6093,7 +6132,7 @@ void SurfaceFlinger::dumpOffscreenLayers(std::string& result) { result.append(future.get()); } -void SurfaceFlinger::dumpHwcLayersMinidumpLocked(std::string& result) const { +void SurfaceFlinger::dumpHwcLayersMinidumpLockedLegacy(std::string& result) const { for (const auto& [token, display] : mDisplays) { const auto displayId = HalDisplayId::tryCast(display->getId()); if (!displayId) { @@ -6105,7 +6144,33 @@ void SurfaceFlinger::dumpHwcLayersMinidumpLocked(std::string& result) const { Layer::miniDumpHeader(result); const DisplayDevice& ref = *display; - mDrawingState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, ref); }); + mDrawingState.traverseInZOrder([&](Layer* layer) { layer->miniDumpLegacy(result, ref); }); + result.append("\n"); + } +} + +void SurfaceFlinger::dumpHwcLayersMinidump(std::string& result) const { + for (const auto& [token, display] : mDisplays) { + const auto displayId = HalDisplayId::tryCast(display->getId()); + if (!displayId) { + continue; + } + + StringAppendF(&result, "Display %s (%s) HWC layers:\n", to_string(*displayId).c_str(), + displayId == mActiveDisplayId ? "active" : "inactive"); + Layer::miniDumpHeader(result); + + const DisplayDevice& ref = *display; + mLayerSnapshotBuilder.forEachVisibleSnapshot([&](const frontend::LayerSnapshot& snapshot) { + if (!snapshot.hasSomethingToDraw() || + ref.getLayerStack() != snapshot.outputFilter.layerStack) { + return; + } + auto it = mLegacyLayers.find(snapshot.sequence); + LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), "Couldnt find layer object for %s", + snapshot.getDebugString().c_str()); + it->second->miniDump(result, snapshot, ref); + }); result.append("\n"); } } @@ -6154,7 +6219,10 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp * Dump the visible layer list */ colorizer.bold(result); - StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers.load()); + StringAppendF(&result, "SurfaceFlinger New Frontend Enabled:%s\n", + mLayerLifecycleManagerEnabled ? "true" : "false"); + StringAppendF(&result, "Active Layers - layers with client handles (count = %zu)\n", + mNumLayers.load()); colorizer.reset(result); result.append(compositionLayers); @@ -6227,7 +6295,9 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp } result.push_back('\n'); - dumpHwcLayersMinidumpLocked(result); + if (mLegacyFrontEndEnabled) { + dumpHwcLayersMinidumpLockedLegacy(result); + } { DumpArgs plannerArgs; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 5c57abdb32..d97a7478dd 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1049,7 +1049,8 @@ private: */ void dumpAllLocked(const DumpArgs& args, const std::string& compositionLayers, std::string& result) const REQUIRES(mStateLock); - void dumpHwcLayersMinidumpLocked(std::string& result) const REQUIRES(mStateLock); + void dumpHwcLayersMinidump(std::string& result) const REQUIRES(mStateLock, kMainThreadContext); + void dumpHwcLayersMinidumpLockedLegacy(std::string& result) const REQUIRES(mStateLock); void appendSfConfigString(std::string& result) const; void listLayersLocked(std::string& result) const; -- GitLab From 3d8565aa9db1c38172b0f0bbc579810881e28815 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 30 Jun 2023 07:23:24 +0000 Subject: [PATCH 0245/1187] [sf] propagate FrameRateSelectionPriority to child layers Fixes an issue found with new fe where we did not pass the FrameRateSelectionPriority to child layers. Also populate the metadata from the requested state when creating the layer snapshots. Test: window type populated correctly in sf dump Test: presubmit Bug: 238781169 Change-Id: I74d970bad8079b1465764ebba34a3154ecf7ff59 --- libs/gui/include/gui/LayerState.h | 3 +- .../surfaceflinger/FrontEnd/LayerSnapshot.cpp | 2 + .../surfaceflinger/FrontEnd/LayerSnapshot.h | 2 +- .../FrontEnd/LayerSnapshotBuilder.cpp | 8 ++++ .../tests/unittests/LayerHierarchyTest.h | 11 +++++ .../tests/unittests/LayerSnapshotTest.cpp | 45 +++++++++++++++++++ 6 files changed, 69 insertions(+), 2 deletions(-) diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 62e5f89d21..7aa7068538 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -267,7 +267,8 @@ struct layer_state_t { layer_state_t::HIERARCHY_CHANGES | layer_state_t::eAlphaChanged | layer_state_t::eColorTransformChanged | layer_state_t::eCornerRadiusChanged | layer_state_t::eFlagsChanged | layer_state_t::eTrustedOverlayChanged | - layer_state_t::eFrameRateChanged | layer_state_t::eFixedTransformHintChanged; + layer_state_t::eFrameRateChanged | layer_state_t::eFrameRateSelectionPriority | + layer_state_t::eFixedTransformHintChanged; // Changes affecting data sent to input. static constexpr uint64_t INPUT_CHANGES = layer_state_t::eInputInfoChanged | diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index 6f68a92e66..d389a799ad 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -131,6 +131,8 @@ LayerSnapshot::LayerSnapshot(const RequestedLayerState& state, ? path : LayerHierarchy::TraversalPath::ROOT; reachablilty = LayerSnapshot::Reachablilty::Unreachable; + frameRateSelectionPriority = state.frameRateSelectionPriority; + layerMetadata = state.metadata; } // As documented in libhardware header, formats in the range diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 9f0822c4ac..1416872f95 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -94,7 +94,7 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { ui::Transform::RotationFlags fixedTransformHint; std::optional transformHint; bool handleSkipScreenshotFlag = false; - int32_t frameRateSelectionPriority; + int32_t frameRateSelectionPriority = -1; LayerHierarchy::TraversalPath mirrorRootPath; uint32_t touchCropId; gui::Uid uid = gui::Uid::INVALID; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 21f0a672b7..3a19d0b389 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -29,6 +29,7 @@ #include "DisplayHardware/HWC2.h" #include "DisplayHardware/Hal.h" +#include "Layer.h" // eFrameRateSelectionPriority constants #include "LayerLog.h" #include "LayerSnapshotBuilder.h" #include "TimeStats/TimeStats.h" @@ -819,6 +820,13 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a : parentSnapshot.frameRate; } + if (forceUpdate || snapshot.clientChanges & layer_state_t::eFrameRateSelectionPriority) { + snapshot.frameRateSelectionPriority = + (requested.frameRateSelectionPriority == Layer::PRIORITY_UNSET) + ? parentSnapshot.frameRateSelectionPriority + : requested.frameRateSelectionPriority; + } + if (forceUpdate || snapshot.clientChanges & (layer_state_t::eBackgroundBlurRadiusChanged | layer_state_t::eBlurRegionsChanged | diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index 43011863ff..3234483f14 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -308,6 +308,17 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setFrameRateSelectionPriority(uint32_t id, int32_t priority) { + std::vector transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = layer_state_t::eFrameRateSelectionPriority; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.frameRateSelectionPriority = priority; + mLifecycleManager.applyTransactions(transactions); + } + LayerLifecycleManager mLifecycleManager; }; diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 5da893ee62..d6c4b7229e 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -20,6 +20,7 @@ #include "FrontEnd/LayerHierarchy.h" #include "FrontEnd/LayerLifecycleManager.h" #include "FrontEnd/LayerSnapshotBuilder.h" +#include "Layer.h" #include "LayerHierarchyTest.h" #define UPDATE_AND_VERIFY(BUILDER, ...) \ @@ -467,4 +468,48 @@ TEST_F(LayerSnapshotTest, cleanUpUnreachableSnapshotsAfterLayerDestruction) { EXPECT_LE(startingNumSnapshots - 2, mSnapshotBuilder.getSnapshots().size()); } +TEST_F(LayerSnapshotTest, snashotContainsMetadataFromLayerCreationArgs) { + LayerCreationArgs args(std::make_optional(200)); + args.name = "testlayer"; + args.addToRoot = true; + args.metadata.setInt32(42, 24); + + std::vector> layers; + layers.emplace_back(std::make_unique(args)); + EXPECT_TRUE(layers.back()->metadata.has(42)); + EXPECT_EQ(layers.back()->metadata.getInt32(42, 0), 24); + mLifecycleManager.addLayers(std::move(layers)); + + std::vector expected = STARTING_ZORDER; + expected.push_back(200); + UPDATE_AND_VERIFY(mSnapshotBuilder, expected); + + EXPECT_TRUE(mSnapshotBuilder.getSnapshot(200)->layerMetadata.has(42)); + EXPECT_EQ(mSnapshotBuilder.getSnapshot(200)->layerMetadata.getInt32(42, 0), 24); +} + +TEST_F(LayerSnapshotTest, frameRateSelectionPriorityPassedToChildLayers) { + setFrameRateSelectionPriority(11, 1); + + setFrameRateSelectionPriority(12, 2); + + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot({.id = 1})->frameRateSelectionPriority, Layer::PRIORITY_UNSET); + EXPECT_EQ(getSnapshot({.id = 11})->frameRateSelectionPriority, 1); + EXPECT_EQ(getSnapshot({.id = 12})->frameRateSelectionPriority, 2); + EXPECT_EQ(getSnapshot({.id = 122})->frameRateSelectionPriority, 2); + EXPECT_EQ(getSnapshot({.id = 1221})->frameRateSelectionPriority, 2); + + // reparent and verify the child gets the new parent's framerate selection priority + reparentLayer(122, 11); + + std::vector expected = {1, 11, 111, 122, 1221, 12, 121, 13, 2}; + UPDATE_AND_VERIFY(mSnapshotBuilder, expected); + EXPECT_EQ(getSnapshot({.id = 1})->frameRateSelectionPriority, Layer::PRIORITY_UNSET); + EXPECT_EQ(getSnapshot({.id = 11})->frameRateSelectionPriority, 1); + EXPECT_EQ(getSnapshot({.id = 12})->frameRateSelectionPriority, 2); + EXPECT_EQ(getSnapshot({.id = 122})->frameRateSelectionPriority, 1); + EXPECT_EQ(getSnapshot({.id = 1221})->frameRateSelectionPriority, 1); +} + } // namespace android::surfaceflinger::frontend -- GitLab From 6081795a4d8bced410364186124549a3fd2c51c0 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Fri, 30 Jun 2023 17:58:35 +0000 Subject: [PATCH 0246/1187] Revert "Enable crashing fuzzer on infra" This reverts commit 17362f1d16dd8202be61f23c5712c3e38c48b948. Reason for revert: Bugs are filed for this fuzzer Change-Id: I581ac3181e2461c3c03d447bbfc39c2432c90d2c --- libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp index 96092b10d3..690c39afc9 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp @@ -36,8 +36,8 @@ cc_fuzz { triage_assignee: "waghpawan@google.com", // This fuzzer should be used only test fuzzService locally - fuzz_on_haiku_host: true, - fuzz_on_haiku_device: true, + fuzz_on_haiku_host: false, + fuzz_on_haiku_device: false, }, } -- GitLab From 67b2ab5963297af41e784be8d0a50f3f37577ae6 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 30 Jun 2023 18:48:44 +0000 Subject: [PATCH 0247/1187] Add OWNERS to libinput Bug: 289544381 Test: Upload Change-Id: I0b0c5c5ed44398c3684a3b5ca5294f1a12a4da3f --- libs/input/OWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 libs/input/OWNERS diff --git a/libs/input/OWNERS b/libs/input/OWNERS new file mode 100644 index 0000000000..c88bfe97ca --- /dev/null +++ b/libs/input/OWNERS @@ -0,0 +1 @@ +include platform/frameworks/base:/INPUT_OWNERS -- GitLab From e9ee0003a7324aeffdcab5e8f6d8ed19198ad9b2 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Sat, 1 Jul 2023 03:14:51 +0000 Subject: [PATCH 0248/1187] Revert "[sf] enable new sf frontend" This reverts commit a5d3d28952a66de3a8c5629ca6a6678e88e92b47. Reason for revert: b/289421905 Change-Id: I86b9677b8a1d73f70f04247a7a0c66314411b867 --- services/surfaceflinger/Layer.cpp | 4 ++++ services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index a430074e9c..3a41f1599b 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2621,6 +2621,10 @@ compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( compositionengine::OutputLayer* Layer::findOutputLayerForDisplay( const DisplayDevice* display, const frontend::LayerHierarchy::TraversalPath& path) const { if (!display) return nullptr; + if (!mFlinger->mLayerLifecycleManagerEnabled) { + return display->getCompositionDisplay()->getOutputLayerForLayer( + getCompositionEngineLayerFE()); + } sp layerFE; for (auto& [p, layer] : mLayerFEs) { if (p == path) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 116ef37e07..c46da11a03 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -487,7 +487,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false); mLayerLifecycleManagerEnabled = - base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, true); + base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false); mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled || base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); } -- GitLab From fee5863f00181e179859b1f69a844d38489bfd70 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Thu, 22 Jun 2023 17:36:48 +0000 Subject: [PATCH 0249/1187] Improve Rust documentation of Binder thread pool. Bug: 181953084 Test: m rustdoc Change-Id: I80c0bbf7300091313a34ae3a8196df43a8fb7db5 --- libs/binder/rust/src/binder.rs | 9 ++++++++- libs/binder/rust/src/state.rs | 31 ++++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index b90b40bac8..993bdca4a5 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -260,7 +260,14 @@ pub trait IBinder { /// Trying to use this function on a local binder will result in an /// INVALID_OPERATION code being returned and nothing happening. /// - /// This link always holds a weak reference to its recipient. + /// This link only holds a weak reference to its recipient. If the + /// `DeathRecipient` is dropped then it will be unlinked. + /// + /// Note that the notifications won't work if you don't first start at least + /// one Binder thread by calling + /// [`ProcessState::start_thread_pool`](crate::ProcessState::start_thread_pool) + /// or + /// [`ProcessState::join_thread_pool`](crate::ProcessState::join_thread_pool). fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()>; /// Remove a previously registered death notification. diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs index b35511d74e..4886c5fe86 100644 --- a/libs/binder/rust/src/state.rs +++ b/libs/binder/rust/src/state.rs @@ -22,10 +22,18 @@ use libc::{pid_t, uid_t}; pub struct ProcessState; impl ProcessState { - /// Start the Binder IPC thread pool + /// Starts the Binder IPC thread pool. /// - /// Starts 1 thread, plus allows the kernel to lazily start up to 'num_threads' - /// additional threads as specified by set_thread_pool_max_thread_count. + /// Starts 1 thread, plus allows the kernel to lazily start up to + /// `num_threads` additional threads as specified by + /// [`set_thread_pool_max_thread_count`](Self::set_thread_pool_max_thread_count). + /// + /// This should be done before creating any Binder client or server. If + /// neither this nor [`join_thread_pool`](Self::join_thread_pool) are + /// called, then some things (such as callbacks and + /// [`IBinder::link_to_death`](crate::IBinder::link_to_death)) will silently + /// not work: the callbacks will be queued but never called as there is no + /// thread to call them on. pub fn start_thread_pool() { unsafe { // Safety: Safe FFI @@ -33,10 +41,12 @@ impl ProcessState { } } - /// Set the maximum number of threads that can be started in the threadpool. + /// Sets the maximum number of threads that can be started in the + /// threadpool. /// - /// By default, after startThreadPool is called, this is 15. If it is called - /// additional times, the thread pool size can only be increased. + /// By default, after [`start_thread_pool`](Self::start_thread_pool) is + /// called, this is 15. If it is called additional times, the thread pool + /// size can only be increased. pub fn set_thread_pool_max_thread_count(num_threads: u32) { unsafe { // Safety: Safe FFI @@ -44,10 +54,13 @@ impl ProcessState { } } - /// Block on the Binder IPC thread pool + /// Blocks on the Binder IPC thread pool by adding the current thread to the + /// pool. /// - /// This adds additional threads in addition to what is created by - /// set_thread_pool_max_thread_count and start_thread_pool. + /// Note that this adds the current thread in addition to those that are + /// created by + /// [`set_thread_pool_max_thread_count`](Self::set_thread_pool_max_thread_count) + /// and [`start_thread_pool`](Self::start_thread_pool). pub fn join_thread_pool() { unsafe { // Safety: Safe FFI -- GitLab From 4c155eb91206da8493dd4dd087497f74476d4290 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 30 Jun 2023 11:47:12 -0700 Subject: [PATCH 0250/1187] Some input build rule fixes Small fixes in this CL: * build for host by default * fix sp::make usage * add more warnings as errors to match inputflinger Bug: 271455682 Test: m checkinput Change-Id: Ib296589b2b2c7c3f5ab178f3b6677be5a6ce1ac1 --- libs/input/Android.bp | 13 ++++++------ libs/input/InputTransport.cpp | 2 +- services/inputflinger/Android.bp | 23 ++++++++++++++------- services/inputflinger/benchmarks/Android.bp | 1 + services/inputflinger/tests/Android.bp | 12 ----------- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 6db7b47150..769677c6ff 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -118,6 +118,11 @@ cc_library { "-Wextra", "-Werror", "-Wno-unused-parameter", + "-Wthread-safety", + "-Wshadow", + "-Wshadow-field-in-constructor-modified", + "-Wshadow-uncaptured-local", + "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", ], srcs: [ "android/os/IInputFlinger.aidl", @@ -160,6 +165,7 @@ cc_library { "liblog", "libPlatformProperties", "libtinyxml2", + "libutils", "libvintf", ], @@ -196,12 +202,6 @@ cc_library { target: { android: { - export_shared_lib_headers: ["libbinder"], - - shared_libs: [ - "libutils", - ], - required: [ "motion_predictor_model_prebuilt", "motion_predictor_model_config", @@ -211,7 +211,6 @@ cc_library { include_dirs: [ "bionic/libc/kernel/android/uapi/", "bionic/libc/kernel/uapi", - "frameworks/native/libs/arect/include", ], }, }, diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 4d3d8bc31c..0b0309e27b 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -409,7 +409,7 @@ status_t InputChannel::openInputChannelPair(const std::string& name, setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); - sp token = new BBinder(); + sp token = sp::make(); std::string serverChannelName = name + " (server)"; android::base::unique_fd serverFd(sockets[0]); diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index f4aab3b2de..ee03d947db 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -28,6 +28,7 @@ inputflinger_tidy_checks = [ cc_defaults { name: "inputflinger_defaults", + host_supported: true, cpp_std: "c++20", cflags: [ "-Wall", @@ -50,6 +51,20 @@ cc_defaults { "-*", // Disable all checks not explicitly enabled for now ] + inputflinger_tidy_checks, tidy_checks_as_errors: inputflinger_tidy_checks, + target: { + host: { + sanitize: { + address: true, + }, + include_dirs: [ + "bionic/libc/kernel/android/uapi/", + "bionic/libc/kernel/uapi", + ], + cflags: [ + "-D__ANDROID_HOST__", + ], + }, + }, } ///////////////////////////////////////////////// @@ -105,13 +120,6 @@ cc_defaults { "libstatspull", "libstatssocket", ], - include_dirs: [ - "bionic/libc/kernel/android/uapi/", - "bionic/libc/kernel/uapi", - ], - cflags: [ - "-D__ANDROID_HOST__", - ], }, }, } @@ -212,6 +220,7 @@ phony { // native targets "libgui_test", "libinput", + "libinputreader_static", "libinputflinger", "inputflinger_tests", "inputflinger_benchmarks", diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp index 4e2a6fbf87..e200f8b303 100644 --- a/services/inputflinger/benchmarks/Android.bp +++ b/services/inputflinger/benchmarks/Android.bp @@ -19,6 +19,7 @@ cc_benchmark { shared_libs: [ "libbase", "libbinder", + "libbinder_ndk", "libcrypto", "libcutils", "libinputflinger_base", diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 187bc0ad7a..38640b3f02 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -78,18 +78,6 @@ cc_test { "libvintf", ], }, - host: { - sanitize: { - address: true, - }, - include_dirs: [ - "bionic/libc/kernel/android/uapi/", - "bionic/libc/kernel/uapi", - ], - cflags: [ - "-D__ANDROID_HOST__", - ], - }, }, sanitize: { hwaddress: true, -- GitLab From 1160ecdfa295225f9eec1a20212746e412ca5c29 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 28 Jun 2023 15:57:47 -0700 Subject: [PATCH 0251/1187] Add hovering support to verifier In order to allow fuzzing of dispatcher, we need to be able to avoid incorrect hover sequences sent to the listener. Add hovering support for verifier in this CL. Bug: 211379801 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: If7ee8ecb62044768915acc4657029366e193c6db --- include/input/InputVerifier.h | 2 + libs/input/InputVerifier.cpp | 9 +- libs/input/rust/input_verifier.rs | 131 +++++++++++++++++- libs/input/rust/lib.rs | 9 +- .../dispatcher/InputDispatcher.cpp | 4 + 5 files changed, 150 insertions(+), 5 deletions(-) diff --git a/include/input/InputVerifier.h b/include/input/InputVerifier.h index 3715408388..b8574829f3 100644 --- a/include/input/InputVerifier.h +++ b/include/input/InputVerifier.h @@ -51,6 +51,8 @@ public: const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, int32_t flags); + void resetDevice(int32_t deviceId); + private: rust::Box mVerifier; }; diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp index b0546a5243..851babfb54 100644 --- a/libs/input/InputVerifier.cpp +++ b/libs/input/InputVerifier.cpp @@ -24,6 +24,8 @@ using android::base::Error; using android::base::Result; using android::input::RustPointerProperties; +using DeviceId = int32_t; + namespace android { // --- InputVerifier --- @@ -31,7 +33,8 @@ namespace android { InputVerifier::InputVerifier(const std::string& name) : mVerifier(android::input::verifier::create(name)){}; -Result InputVerifier::processMovement(int32_t deviceId, int32_t action, uint32_t pointerCount, +Result InputVerifier::processMovement(DeviceId deviceId, int32_t action, + uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, int32_t flags) { std::vector rpp; @@ -49,4 +52,8 @@ Result InputVerifier::processMovement(int32_t deviceId, int32_t action, ui } } +void InputVerifier::resetDevice(DeviceId deviceId) { + android::input::verifier::reset_device(*mVerifier, deviceId); +} + } // namespace android diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs index 1cc11297b6..fdb623033b 100644 --- a/libs/input/rust/input_verifier.rs +++ b/libs/input/rust/input_verifier.rs @@ -27,6 +27,7 @@ pub struct InputVerifier { name: String, should_log: bool, touching_pointer_ids_by_device: HashMap>, + hovering_pointer_ids_by_device: HashMap>, } impl InputVerifier { @@ -37,7 +38,12 @@ impl InputVerifier { .with_tag_on_device("InputVerifier") .with_min_level(log::Level::Trace), ); - Self { name: name.to_owned(), should_log, touching_pointer_ids_by_device: HashMap::new() } + Self { + name: name.to_owned(), + should_log, + touching_pointer_ids_by_device: HashMap::new(), + hovering_pointer_ids_by_device: HashMap::new(), + } } /// Process a pointer movement event from an InputDevice. @@ -135,7 +141,7 @@ impl InputVerifier { self.name, pointer_id, it, device_id )); } - it.clear(); + self.touching_pointer_ids_by_device.remove(&device_id); } MotionAction::Cancel => { if flags.contains(MotionFlags::CANCELED) { @@ -153,11 +159,68 @@ impl InputVerifier { } self.touching_pointer_ids_by_device.remove(&device_id); } + /* + * The hovering protocol currently supports a single pointer only, because we do not + * have ACTION_HOVER_POINTER_ENTER or ACTION_HOVER_POINTER_EXIT. + * Still, we are keeping the infrastructure here pretty general in case that is + * eventually supported. + */ + MotionAction::HoverEnter => { + if self.hovering_pointer_ids_by_device.contains_key(&device_id) { + return Err(format!( + "{}: Invalid HOVER_ENTER event - pointers already hovering for device {:?}:\ + {:?}", + self.name, device_id, self.hovering_pointer_ids_by_device + )); + } + let it = self + .hovering_pointer_ids_by_device + .entry(device_id) + .or_insert_with(HashSet::new); + it.insert(pointer_properties[0].id); + } + MotionAction::HoverMove => { + // For compatibility reasons, we allow HOVER_MOVE without a prior HOVER_ENTER. + // If there was no prior HOVER_ENTER, just start a new hovering pointer. + let it = self + .hovering_pointer_ids_by_device + .entry(device_id) + .or_insert_with(HashSet::new); + it.insert(pointer_properties[0].id); + } + MotionAction::HoverExit => { + if !self.hovering_pointer_ids_by_device.contains_key(&device_id) { + return Err(format!( + "{}: Invalid HOVER_EXIT event - no pointers are hovering for device {:?}", + self.name, device_id + )); + } + let pointer_id = pointer_properties[0].id; + let it = self.hovering_pointer_ids_by_device.get_mut(&device_id).unwrap(); + it.remove(&pointer_id); + + if !it.is_empty() { + return Err(format!( + "{}: Removed hovering pointer {}, but pointers are still\ + hovering for device {:?}: {:?}", + self.name, pointer_id, device_id, it + )); + } + self.hovering_pointer_ids_by_device.remove(&device_id); + } _ => return Ok(()), } Ok(()) } + /// Notify the verifier that the device has been reset, which will cause the verifier to erase + /// the current internal state for this device. Subsequent events from this device are expected + //// to start a new gesture. + pub fn reset_device(&mut self, device_id: DeviceId) { + self.touching_pointer_ids_by_device.remove(&device_id); + self.hovering_pointer_ids_by_device.remove(&device_id); + } + fn ensure_touching_pointers_match( &self, device_id: DeviceId, @@ -272,4 +335,68 @@ mod tests { ) .is_err()); } + + #[test] + fn correct_hover_sequence() { + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + } + + #[test] + fn double_hover_enter() { + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + &pointer_properties, + MotionFlags::empty(), + ) + .is_err()); + } } diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs index 25b2ecbcda..892f558da6 100644 --- a/libs/input/rust/lib.rs +++ b/libs/input/rust/lib.rs @@ -54,6 +54,7 @@ mod ffi { pointer_properties: &[RustPointerProperties], flags: i32, ) -> String; + fn reset_device(verifier: &mut InputVerifier, device_id: i32); } #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] @@ -64,6 +65,10 @@ mod ffi { use crate::ffi::RustPointerProperties; +fn create(name: String) -> Box { + Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents"))) +} + fn process_movement( verifier: &mut InputVerifier, device_id: i32, @@ -83,6 +88,6 @@ fn process_movement( } } -fn create(name: String) -> Box { - Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents"))) +fn reset_device(verifier: &mut InputVerifier, device_id: i32) { + verifier.reset_device(DeviceId(device_id)); } diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 29c4e469ea..482e23f043 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4516,6 +4516,10 @@ void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs& args) { std::unique_ptr newEntry = std::make_unique(args.id, args.eventTime, args.deviceId); needWake = enqueueInboundEventLocked(std::move(newEntry)); + + for (auto& [_, verifier] : mVerifiersByDisplay) { + verifier.resetDevice(args.deviceId); + } } // release lock if (needWake) { -- GitLab From e65fa7569a5d0b69744e44d996e23fe20dc0c6ec Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 28 Jun 2023 14:09:09 -0700 Subject: [PATCH 0252/1187] Fix cancel flag check The check inside the verifier for the presence of flag_canceled is incorrect. Fix it in this CL. Bug: 211379801 Test: TEST=libinput_rust_test; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: I6880922b21cc9cb629a98e0c8071f1c4d5130aa5 --- libs/input/rust/input_verifier.rs | 48 +++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs index fdb623033b..64c0466687 100644 --- a/libs/input/rust/input_verifier.rs +++ b/libs/input/rust/input_verifier.rs @@ -144,7 +144,7 @@ impl InputVerifier { self.touching_pointer_ids_by_device.remove(&device_id); } MotionAction::Cancel => { - if flags.contains(MotionFlags::CANCELED) { + if !flags.contains(MotionFlags::CANCELED) { return Err(format!( "{}: For ACTION_CANCEL, must set FLAG_CANCELED", self.name @@ -323,7 +323,51 @@ mod tests { } #[test] - fn test_invalid_up() { + fn action_cancel() { + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_DOWN, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_CANCEL, + &pointer_properties, + MotionFlags::CANCELED, + ) + .is_ok()); + } + + #[test] + fn invalid_action_cancel() { + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_DOWN, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_CANCEL, + &pointer_properties, + MotionFlags::empty(), // forgot to set FLAG_CANCELED + ) + .is_err()); + } + + #[test] + fn invalid_up() { let mut verifier = InputVerifier::new("Test", /*should_log*/ false); let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); assert!(verifier -- GitLab From e1ada27b72eec468dab5326ee1c834213aa2a162 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 3 Nov 2022 10:47:08 -0700 Subject: [PATCH 0253/1187] Add outside targets explicitly Before this CL, the action of adding outside targets was a by-product of finding the touched window. In this CL, the change is made to add these targets explicitly. This simplifies some of the code and allows us to stop generating targets for cases where isDown is false. Eventually, we may consider adding the outside targets back into touch state to unify the security checks. Bug: 211379801 Test: atest inputflinger_tests Change-Id: I1373c28d306e154dac8b35879bb7d0497d1ff832 --- .../dispatcher/InputDispatcher.cpp | 47 ++++++++++++++----- .../inputflinger/dispatcher/InputDispatcher.h | 9 ++-- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 482e23f043..cc3f4d2fea 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -1106,7 +1106,8 @@ bool InputDispatcher::shouldPruneInboundQueueLocked(const MotionEntry& motionEnt const auto [x, y] = resolveTouchedPosition(motionEntry); const bool isStylus = isPointerFromStylus(motionEntry, /*pointerIndex=*/0); - auto [touchedWindowHandle, _] = findTouchedWindowAtLocked(displayId, x, y, isStylus); + sp touchedWindowHandle = + findTouchedWindowAtLocked(displayId, x, y, isStylus); if (touchedWindowHandle != nullptr && touchedWindowHandle->getApplicationToken() != mAwaitedFocusedApplication->getApplicationToken()) { @@ -1230,11 +1231,10 @@ void InputDispatcher::addRecentEventLocked(std::shared_ptr entry) { } } -std::pair, std::vector> -InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, float x, float y, bool isStylus, - bool ignoreDragWindow) const { +sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, float x, float y, + bool isStylus, + bool ignoreDragWindow) const { // Traverse windows from front to back to find touched window. - std::vector outsideTargets; const auto& windowHandles = getWindowHandlesLocked(displayId); for (const sp& windowHandle : windowHandles) { if (ignoreDragWindow && haveSameToken(windowHandle, mDragState->dragWindow)) { @@ -1244,16 +1244,35 @@ InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, float x, float y, const WindowInfo& info = *windowHandle->getInfo(); if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y, isStylus, getTransformLocked(displayId))) { - return {windowHandle, outsideTargets}; + return windowHandle; + } + } + return nullptr; +} + +std::vector InputDispatcher::findOutsideTargetsLocked( + int32_t displayId, const sp& touchedWindow) const { + if (touchedWindow == nullptr) { + return {}; + } + // Traverse windows from front to back until we encounter the touched window. + std::vector outsideTargets; + const auto& windowHandles = getWindowHandlesLocked(displayId); + for (const sp& windowHandle : windowHandles) { + if (windowHandle == touchedWindow) { + // Stop iterating once we found a touched window. Any WATCH_OUTSIDE_TOUCH window + // below the touched window will not get ACTION_OUTSIDE event. + return outsideTargets; } + const WindowInfo& info = *windowHandle->getInfo(); if (info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) { addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_OUTSIDE, /*pointerIds=*/{}, /*firstDownTimeInTarget=*/std::nullopt, outsideTargets); } } - return {nullptr, {}}; + return outsideTargets; } std::vector> InputDispatcher::findTouchedSpyWindowsAtLocked( @@ -2311,11 +2330,11 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( // Outside targets should be added upon first dispatched DOWN event. That means, this should // be a pointer that would generate ACTION_DOWN, *and* touch should not already be down. const bool isStylus = isPointerFromStylus(entry, pointerIndex); - auto [newTouchedWindowHandle, outsideTargets] = + sp newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, isStylus); if (isDown) { - targets += outsideTargets; + targets += findOutsideTargetsLocked(displayId, newTouchedWindowHandle); } // Handle the case where we did not find a window. if (newTouchedWindowHandle == nullptr) { @@ -2489,7 +2508,8 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( sp oldTouchedWindowHandle = tempTouchState.getFirstForegroundWindowHandle(); LOG_ALWAYS_FATAL_IF(oldTouchedWindowHandle == nullptr); - auto [newTouchedWindowHandle, _] = findTouchedWindowAtLocked(displayId, x, y, isStylus); + sp newTouchedWindowHandle = + findTouchedWindowAtLocked(displayId, x, y, isStylus); // Verify targeted injection. if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) { @@ -2747,7 +2767,7 @@ void InputDispatcher::finishDragAndDrop(int32_t displayId, float x, float y) { // have an explicit reason to support it. constexpr bool isStylus = false; - auto [dropWindow, _] = + sp dropWindow = findTouchedWindowAtLocked(displayId, x, y, isStylus, /*ignoreDragWindow=*/true); if (dropWindow) { vec2 local = dropWindow->getInfo()->transform.transform(x, y); @@ -2801,8 +2821,9 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { // until we have an explicit reason to support it. constexpr bool isStylus = false; - auto [hoverWindowHandle, _] = findTouchedWindowAtLocked(entry.displayId, x, y, isStylus, - /*ignoreDragWindow=*/true); + sp hoverWindowHandle = + findTouchedWindowAtLocked(entry.displayId, x, y, isStylus, + /*ignoreDragWindow=*/true); // enqueue drag exit if needed. if (hoverWindowHandle != mDragState->dragHoverWindowHandle && !haveSameToken(hoverWindowHandle, mDragState->dragHoverWindowHandle)) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 9cd1666a80..ad05525d04 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -242,9 +242,12 @@ private: // to transfer focus to a new application. std::shared_ptr mNextUnblockedEvent GUARDED_BY(mLock); - std::pair, std::vector> - findTouchedWindowAtLocked(int32_t displayId, float x, float y, bool isStylus = false, - bool ignoreDragWindow = false) const REQUIRES(mLock); + sp findTouchedWindowAtLocked( + int32_t displayId, float x, float y, bool isStylus = false, + bool ignoreDragWindow = false) const REQUIRES(mLock); + std::vector findOutsideTargetsLocked( + int32_t displayId, const sp& touchedWindow) const + REQUIRES(mLock); std::vector> findTouchedSpyWindowsAtLocked( int32_t displayId, float x, float y, bool isStylus) const REQUIRES(mLock); -- GitLab From dccefce9c2981d059f1d70eb3f78f760358d84a8 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Thu, 6 Jul 2023 02:25:08 +0000 Subject: [PATCH 0254/1187] Add FEATURE_TELEPHONY_SATELLITE feature definition Bug: 260644201 Test: atest VtsHalRadioTargetTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:186a1948be57ce5b7cd6dd1475cedaa86a57a1ef) Merged-In: I73e0f8b0e20b308e85afd123d9169f827c963c12 Merged-In: I6bf11bf9165a97145adc1f786a7f7aadd8c1977b Change-Id: I73e0f8b0e20b308e85afd123d9169f827c963c12 --- data/etc/Android.bp | 6 ++++++ .../android.hardware.telephony.satellite.xml | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 data/etc/android.hardware.telephony.satellite.xml diff --git a/data/etc/Android.bp b/data/etc/Android.bp index bdd5172e60..a737bd3fb7 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -166,6 +166,12 @@ prebuilt_etc { defaults: ["frameworks_native_data_etc_defaults"], } +prebuilt_etc { + name: "android.hardware.telephony.satellite.prebuilt.xml", + src: "android.hardware.telephony.satellite.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + prebuilt_etc { name: "android.hardware.usb.accessory.prebuilt.xml", src: "android.hardware.usb.accessory.xml", diff --git a/data/etc/android.hardware.telephony.satellite.xml b/data/etc/android.hardware.telephony.satellite.xml new file mode 100644 index 0000000000..5966cba277 --- /dev/null +++ b/data/etc/android.hardware.telephony.satellite.xml @@ -0,0 +1,20 @@ + + + + + + + -- GitLab From 4d3d265d77c2e5ea09306480b009967e819dfb15 Mon Sep 17 00:00:00 2001 From: Kangping Dong Date: Thu, 25 May 2023 23:56:16 +0800 Subject: [PATCH 0255/1187] [Thread] define the ThreadNetwork hardware feature FR: b/235016403 Bug: 284296494 Merged-In: Ie86f2711e673d99a8e1832ce5bbaecb1454d4199 Change-Id: Ie86f2711e673d99a8e1832ce5bbaecb1454d4199 --- data/etc/Android.bp | 6 ++++++ data/etc/android.hardware.threadnetwork.xml | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 data/etc/android.hardware.threadnetwork.xml diff --git a/data/etc/Android.bp b/data/etc/Android.bp index a737bd3fb7..92dc46ed8d 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -172,6 +172,12 @@ prebuilt_etc { defaults: ["frameworks_native_data_etc_defaults"], } +prebuilt_etc { + name: "android.hardware.threadnetwork.prebuilt.xml", + src: "android.hardware.threadnetwork.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + prebuilt_etc { name: "android.hardware.usb.accessory.prebuilt.xml", src: "android.hardware.usb.accessory.xml", diff --git a/data/etc/android.hardware.threadnetwork.xml b/data/etc/android.hardware.threadnetwork.xml new file mode 100644 index 0000000000..9cbdc905fb --- /dev/null +++ b/data/etc/android.hardware.threadnetwork.xml @@ -0,0 +1,19 @@ + + + + + + -- GitLab From 3123d5905c8ae2c1c8a20159e36f189ea901fdb9 Mon Sep 17 00:00:00 2001 From: sergiuferentz Date: Mon, 26 Jun 2023 18:01:47 +0000 Subject: [PATCH 0256/1187] Fix for heap-use-after-free in GPUService.cpp This adds a unit test and fix for the bug reported by libfuzzer. Changes made: * Expose GPUService as testable code. * Update main_gpuservice.cpp to use the new GpuService now located at gpuservice/GpuService.h * Make initializer threads members of GpuService * Join the threads in destructor to prevent heap-use-after-free. * Add unit test that waits 3 seconds after deallocation to ensure no wrong access is made. Merged-In: I4d1d2d4658b575bf2c8f425f91f68f03114ad029 Bug: 282919145 Test: Added unit test and ran on device with ASAN Change-Id: I4d1d2d4658b575bf2c8f425f91f68f03114ad029 (cherry picked from commit 3c00cbc0f119c3f59325aa6d5061529feb58462b) --- services/gpuservice/Android.bp | 1 + services/gpuservice/GpuService.cpp | 14 +++-- .../{ => include/gpuservice}/GpuService.h | 4 ++ services/gpuservice/main_gpuservice.cpp | 2 +- .../tests/fuzzers/GpuServiceFuzzer.cpp | 2 +- .../gpuservice/tests/unittests/Android.bp | 2 + .../tests/unittests/GpuServiceTest.cpp | 52 +++++++++++++++++++ 7 files changed, 70 insertions(+), 7 deletions(-) rename services/gpuservice/{ => include/gpuservice}/GpuService.h (94%) create mode 100644 services/gpuservice/tests/unittests/GpuServiceTest.cpp diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp index fba64c7569..052efb6bbb 100644 --- a/services/gpuservice/Android.bp +++ b/services/gpuservice/Android.bp @@ -71,6 +71,7 @@ filegroup { cc_library_shared { name: "libgpuservice", defaults: ["libgpuservice_production_defaults"], + export_include_dirs: ["include"], srcs: [ ":libgpuservice_sources", ], diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 7b9782f4e8..5643940a6e 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -16,7 +16,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include "GpuService.h" +#include "gpuservice/GpuService.h" #include #include @@ -34,6 +34,7 @@ #include #include +#include namespace android { @@ -55,18 +56,21 @@ GpuService::GpuService() mGpuStats(std::make_unique()), mGpuMemTracer(std::make_unique()) { - std::thread gpuMemAsyncInitThread([this]() { + mGpuMemAsyncInitThread = std::make_unique([this] (){ mGpuMem->initialize(); mGpuMemTracer->initialize(mGpuMem); }); - gpuMemAsyncInitThread.detach(); - std::thread gpuWorkAsyncInitThread([this]() { + mGpuWorkAsyncInitThread = std::make_unique([this]() { mGpuWork->initialize(); }); - gpuWorkAsyncInitThread.detach(); }; +GpuService::~GpuService() { + mGpuWorkAsyncInitThread->join(); + mGpuMemAsyncInitThread->join(); +} + void GpuService::setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/include/gpuservice/GpuService.h similarity index 94% rename from services/gpuservice/GpuService.h rename to services/gpuservice/include/gpuservice/GpuService.h index d7313d165e..3e0ae66f39 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/include/gpuservice/GpuService.h @@ -24,6 +24,7 @@ #include #include +#include #include namespace android { @@ -41,6 +42,7 @@ public: static const char* const SERVICE_NAME ANDROID_API; GpuService() ANDROID_API; + ~GpuService(); protected: status_t shellCommand(int in, int out, int err, std::vector& args) override; @@ -86,6 +88,8 @@ private: std::unique_ptr mGpuMemTracer; std::mutex mLock; std::string mDeveloperDriverPath; + std::unique_ptr mGpuMemAsyncInitThread; + std::unique_ptr mGpuWorkAsyncInitThread; }; } // namespace android diff --git a/services/gpuservice/main_gpuservice.cpp b/services/gpuservice/main_gpuservice.cpp index 64aafcab6a..200237219e 100644 --- a/services/gpuservice/main_gpuservice.cpp +++ b/services/gpuservice/main_gpuservice.cpp @@ -18,7 +18,7 @@ #include #include #include -#include "GpuService.h" +#include "gpuservice/GpuService.h" using namespace android; diff --git a/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp index c2574a3fd3..241b8646e1 100644 --- a/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp +++ b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp @@ -16,7 +16,7 @@ #include -#include "GpuService.h" +#include "gpuservice/GpuService.h" using ::android::fuzzService; using ::android::GpuService; diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp index 51642f9472..c870b17b79 100644 --- a/services/gpuservice/tests/unittests/Android.bp +++ b/services/gpuservice/tests/unittests/Android.bp @@ -28,6 +28,7 @@ cc_test { "GpuMemTest.cpp", "GpuMemTracerTest.cpp", "GpuStatsTest.cpp", + "GpuServiceTest.cpp", ], header_libs: ["bpf_headers"], shared_libs: [ @@ -45,6 +46,7 @@ cc_test { "libstatslog", "libstatspull", "libutils", + "libgpuservice", ], static_libs: [ "libgmock", diff --git a/services/gpuservice/tests/unittests/GpuServiceTest.cpp b/services/gpuservice/tests/unittests/GpuServiceTest.cpp new file mode 100644 index 0000000000..62b3e53f53 --- /dev/null +++ b/services/gpuservice/tests/unittests/GpuServiceTest.cpp @@ -0,0 +1,52 @@ +#undef LOG_TAG +#define LOG_TAG "gpuservice_unittest" + +#include "gpuservice/GpuService.h" + +#include +#include + +#include +#include + +namespace android { +namespace { + +class GpuServiceTest : public testing::Test { +public: + GpuServiceTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + } + + ~GpuServiceTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); + } + +}; + + +/* +* The behaviour before this test + fixes was UB caused by threads accessing deallocated memory. +* +* This test creates the service (which initializes the culprit threads), +* deallocates it immediately and sleeps. +* +* GpuService's destructor gets called and joins the threads. +* If we haven't crashed by the time the sleep time has elapsed, we're good +* Let the test pass. +*/ +TEST_F(GpuServiceTest, onInitializeShouldNotCauseUseAfterFree) { + sp service = new GpuService(); + service.clear(); + std::this_thread::sleep_for(std::chrono::seconds(3)); + + // If we haven't crashed yet due to threads accessing freed up memory, let the test pass + EXPECT_TRUE(true); +} + +} // namespace +} // namespace android -- GitLab From 00af2d2e9b4142e23554b42f15a145867626e93b Mon Sep 17 00:00:00 2001 From: sergiuferentz Date: Mon, 26 Jun 2023 18:01:47 +0000 Subject: [PATCH 0257/1187] Fix for heap-use-after-free in GPUService.cpp This adds a unit test and fix for the bug reported by libfuzzer. Changes made: * Expose GPUService as testable code. * Update main_gpuservice.cpp to use the new GpuService now located at gpuservice/GpuService.h * Make initializer threads members of GpuService * Join the threads in destructor to prevent heap-use-after-free. * Add unit test that waits 3 seconds after deallocation to ensure no wrong access is made. Merged-In: I4d1d2d4658b575bf2c8f425f91f68f03114ad029 Bug: 282919145 Test: Added unit test and ran on device with ASAN Change-Id: I4d1d2d4658b575bf2c8f425f91f68f03114ad029 (cherry picked from commit 3c00cbc0f119c3f59325aa6d5061529feb58462b) --- services/gpuservice/Android.bp | 1 + services/gpuservice/GpuService.cpp | 14 +++-- .../{ => include/gpuservice}/GpuService.h | 4 ++ services/gpuservice/main_gpuservice.cpp | 2 +- .../tests/fuzzers/GpuServiceFuzzer.cpp | 2 +- .../gpuservice/tests/unittests/Android.bp | 2 + .../tests/unittests/GpuServiceTest.cpp | 52 +++++++++++++++++++ 7 files changed, 70 insertions(+), 7 deletions(-) rename services/gpuservice/{ => include/gpuservice}/GpuService.h (95%) create mode 100644 services/gpuservice/tests/unittests/GpuServiceTest.cpp diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp index fba64c7569..052efb6bbb 100644 --- a/services/gpuservice/Android.bp +++ b/services/gpuservice/Android.bp @@ -71,6 +71,7 @@ filegroup { cc_library_shared { name: "libgpuservice", defaults: ["libgpuservice_production_defaults"], + export_include_dirs: ["include"], srcs: [ ":libgpuservice_sources", ], diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 5e7b2e8df8..4a08c11c14 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -16,7 +16,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include "GpuService.h" +#include "gpuservice/GpuService.h" #include #include @@ -35,6 +35,7 @@ #include #include +#include namespace android { @@ -58,18 +59,21 @@ GpuService::GpuService() mGpuStats(std::make_unique()), mGpuMemTracer(std::make_unique()) { - std::thread gpuMemAsyncInitThread([this]() { + mGpuMemAsyncInitThread = std::make_unique([this] (){ mGpuMem->initialize(); mGpuMemTracer->initialize(mGpuMem); }); - gpuMemAsyncInitThread.detach(); - std::thread gpuWorkAsyncInitThread([this]() { + mGpuWorkAsyncInitThread = std::make_unique([this]() { mGpuWork->initialize(); }); - gpuWorkAsyncInitThread.detach(); }; +GpuService::~GpuService() { + mGpuWorkAsyncInitThread->join(); + mGpuMemAsyncInitThread->join(); +} + void GpuService::setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/include/gpuservice/GpuService.h similarity index 95% rename from services/gpuservice/GpuService.h rename to services/gpuservice/include/gpuservice/GpuService.h index 0e559f2c34..54f8f666bc 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/include/gpuservice/GpuService.h @@ -24,6 +24,7 @@ #include #include +#include #include namespace android { @@ -41,6 +42,7 @@ public: static const char* const SERVICE_NAME ANDROID_API; GpuService() ANDROID_API; + ~GpuService(); protected: status_t shellCommand(int in, int out, int err, std::vector& args) override; @@ -90,6 +92,8 @@ private: std::unique_ptr mGpuMemTracer; std::mutex mLock; std::string mDeveloperDriverPath; + std::unique_ptr mGpuMemAsyncInitThread; + std::unique_ptr mGpuWorkAsyncInitThread; }; } // namespace android diff --git a/services/gpuservice/main_gpuservice.cpp b/services/gpuservice/main_gpuservice.cpp index 64aafcab6a..200237219e 100644 --- a/services/gpuservice/main_gpuservice.cpp +++ b/services/gpuservice/main_gpuservice.cpp @@ -18,7 +18,7 @@ #include #include #include -#include "GpuService.h" +#include "gpuservice/GpuService.h" using namespace android; diff --git a/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp index c2574a3fd3..241b8646e1 100644 --- a/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp +++ b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp @@ -16,7 +16,7 @@ #include -#include "GpuService.h" +#include "gpuservice/GpuService.h" using ::android::fuzzService; using ::android::GpuService; diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp index 51642f9472..c870b17b79 100644 --- a/services/gpuservice/tests/unittests/Android.bp +++ b/services/gpuservice/tests/unittests/Android.bp @@ -28,6 +28,7 @@ cc_test { "GpuMemTest.cpp", "GpuMemTracerTest.cpp", "GpuStatsTest.cpp", + "GpuServiceTest.cpp", ], header_libs: ["bpf_headers"], shared_libs: [ @@ -45,6 +46,7 @@ cc_test { "libstatslog", "libstatspull", "libutils", + "libgpuservice", ], static_libs: [ "libgmock", diff --git a/services/gpuservice/tests/unittests/GpuServiceTest.cpp b/services/gpuservice/tests/unittests/GpuServiceTest.cpp new file mode 100644 index 0000000000..62b3e53f53 --- /dev/null +++ b/services/gpuservice/tests/unittests/GpuServiceTest.cpp @@ -0,0 +1,52 @@ +#undef LOG_TAG +#define LOG_TAG "gpuservice_unittest" + +#include "gpuservice/GpuService.h" + +#include +#include + +#include +#include + +namespace android { +namespace { + +class GpuServiceTest : public testing::Test { +public: + GpuServiceTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + } + + ~GpuServiceTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); + } + +}; + + +/* +* The behaviour before this test + fixes was UB caused by threads accessing deallocated memory. +* +* This test creates the service (which initializes the culprit threads), +* deallocates it immediately and sleeps. +* +* GpuService's destructor gets called and joins the threads. +* If we haven't crashed by the time the sleep time has elapsed, we're good +* Let the test pass. +*/ +TEST_F(GpuServiceTest, onInitializeShouldNotCauseUseAfterFree) { + sp service = new GpuService(); + service.clear(); + std::this_thread::sleep_for(std::chrono::seconds(3)); + + // If we haven't crashed yet due to threads accessing freed up memory, let the test pass + EXPECT_TRUE(true); +} + +} // namespace +} // namespace android -- GitLab From 9e094716a8521f5de1d562ab1945d0a1e5ce9d3b Mon Sep 17 00:00:00 2001 From: sergiuferentz Date: Mon, 26 Jun 2023 18:01:47 +0000 Subject: [PATCH 0258/1187] Fix for heap-use-after-free in GPUService.cpp This adds a unit test and fix for the bug reported by libfuzzer. Changes made: * Expose GPUService as testable code. * Update main_gpuservice.cpp to use the new GpuService now located at gpuservice/GpuService.h * Make initializer threads members of GpuService * Join the threads in destructor to prevent heap-use-after-free. * Add unit test that waits 3 seconds after deallocation to ensure no wrong access is made. Merged-In: I4d1d2d4658b575bf2c8f425f91f68f03114ad029 Bug: 282919145 Test: Added unit test and ran on device with ASAN Change-Id: I4d1d2d4658b575bf2c8f425f91f68f03114ad029 (cherry picked from commit 3c00cbc0f119c3f59325aa6d5061529feb58462b) --- services/gpuservice/Android.bp | 1 + services/gpuservice/GpuService.cpp | 14 +++-- .../{ => include/gpuservice}/GpuService.h | 4 ++ services/gpuservice/main_gpuservice.cpp | 2 +- .../tests/fuzzers/GpuServiceFuzzer.cpp | 2 +- .../gpuservice/tests/unittests/Android.bp | 2 + .../tests/unittests/GpuServiceTest.cpp | 52 +++++++++++++++++++ 7 files changed, 70 insertions(+), 7 deletions(-) rename services/gpuservice/{ => include/gpuservice}/GpuService.h (95%) create mode 100644 services/gpuservice/tests/unittests/GpuServiceTest.cpp diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp index fba64c7569..052efb6bbb 100644 --- a/services/gpuservice/Android.bp +++ b/services/gpuservice/Android.bp @@ -71,6 +71,7 @@ filegroup { cc_library_shared { name: "libgpuservice", defaults: ["libgpuservice_production_defaults"], + export_include_dirs: ["include"], srcs: [ ":libgpuservice_sources", ], diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 5e7b2e8df8..4a08c11c14 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -16,7 +16,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include "GpuService.h" +#include "gpuservice/GpuService.h" #include #include @@ -35,6 +35,7 @@ #include #include +#include namespace android { @@ -58,18 +59,21 @@ GpuService::GpuService() mGpuStats(std::make_unique()), mGpuMemTracer(std::make_unique()) { - std::thread gpuMemAsyncInitThread([this]() { + mGpuMemAsyncInitThread = std::make_unique([this] (){ mGpuMem->initialize(); mGpuMemTracer->initialize(mGpuMem); }); - gpuMemAsyncInitThread.detach(); - std::thread gpuWorkAsyncInitThread([this]() { + mGpuWorkAsyncInitThread = std::make_unique([this]() { mGpuWork->initialize(); }); - gpuWorkAsyncInitThread.detach(); }; +GpuService::~GpuService() { + mGpuWorkAsyncInitThread->join(); + mGpuMemAsyncInitThread->join(); +} + void GpuService::setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/include/gpuservice/GpuService.h similarity index 95% rename from services/gpuservice/GpuService.h rename to services/gpuservice/include/gpuservice/GpuService.h index 0e559f2c34..54f8f666bc 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/include/gpuservice/GpuService.h @@ -24,6 +24,7 @@ #include #include +#include #include namespace android { @@ -41,6 +42,7 @@ public: static const char* const SERVICE_NAME ANDROID_API; GpuService() ANDROID_API; + ~GpuService(); protected: status_t shellCommand(int in, int out, int err, std::vector& args) override; @@ -90,6 +92,8 @@ private: std::unique_ptr mGpuMemTracer; std::mutex mLock; std::string mDeveloperDriverPath; + std::unique_ptr mGpuMemAsyncInitThread; + std::unique_ptr mGpuWorkAsyncInitThread; }; } // namespace android diff --git a/services/gpuservice/main_gpuservice.cpp b/services/gpuservice/main_gpuservice.cpp index 64aafcab6a..200237219e 100644 --- a/services/gpuservice/main_gpuservice.cpp +++ b/services/gpuservice/main_gpuservice.cpp @@ -18,7 +18,7 @@ #include #include #include -#include "GpuService.h" +#include "gpuservice/GpuService.h" using namespace android; diff --git a/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp index c2574a3fd3..241b8646e1 100644 --- a/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp +++ b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp @@ -16,7 +16,7 @@ #include -#include "GpuService.h" +#include "gpuservice/GpuService.h" using ::android::fuzzService; using ::android::GpuService; diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp index 51642f9472..c870b17b79 100644 --- a/services/gpuservice/tests/unittests/Android.bp +++ b/services/gpuservice/tests/unittests/Android.bp @@ -28,6 +28,7 @@ cc_test { "GpuMemTest.cpp", "GpuMemTracerTest.cpp", "GpuStatsTest.cpp", + "GpuServiceTest.cpp", ], header_libs: ["bpf_headers"], shared_libs: [ @@ -45,6 +46,7 @@ cc_test { "libstatslog", "libstatspull", "libutils", + "libgpuservice", ], static_libs: [ "libgmock", diff --git a/services/gpuservice/tests/unittests/GpuServiceTest.cpp b/services/gpuservice/tests/unittests/GpuServiceTest.cpp new file mode 100644 index 0000000000..62b3e53f53 --- /dev/null +++ b/services/gpuservice/tests/unittests/GpuServiceTest.cpp @@ -0,0 +1,52 @@ +#undef LOG_TAG +#define LOG_TAG "gpuservice_unittest" + +#include "gpuservice/GpuService.h" + +#include +#include + +#include +#include + +namespace android { +namespace { + +class GpuServiceTest : public testing::Test { +public: + GpuServiceTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + } + + ~GpuServiceTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); + } + +}; + + +/* +* The behaviour before this test + fixes was UB caused by threads accessing deallocated memory. +* +* This test creates the service (which initializes the culprit threads), +* deallocates it immediately and sleeps. +* +* GpuService's destructor gets called and joins the threads. +* If we haven't crashed by the time the sleep time has elapsed, we're good +* Let the test pass. +*/ +TEST_F(GpuServiceTest, onInitializeShouldNotCauseUseAfterFree) { + sp service = new GpuService(); + service.clear(); + std::this_thread::sleep_for(std::chrono::seconds(3)); + + // If we haven't crashed yet due to threads accessing freed up memory, let the test pass + EXPECT_TRUE(true); +} + +} // namespace +} // namespace android -- GitLab From 2f82934ea7ce43e984ddd26d5ea0cb5cdb824bac Mon Sep 17 00:00:00 2001 From: sergiuferentz Date: Mon, 26 Jun 2023 18:01:47 +0000 Subject: [PATCH 0259/1187] Fix for heap-use-after-free in GPUService.cpp This adds a unit test and fix for the bug reported by libfuzzer. Changes made: * Expose GPUService as testable code. * Update main_gpuservice.cpp to use the new GpuService now located at gpuservice/GpuService.h * Make initializer threads members of GpuService * Join the threads in destructor to prevent heap-use-after-free. * Add unit test that waits 3 seconds after deallocation to ensure no wrong access is made. Merged-In: I4d1d2d4658b575bf2c8f425f91f68f03114ad029 Bug: 282919145 Test: Added unit test and ran on device with ASAN Change-Id: I4d1d2d4658b575bf2c8f425f91f68f03114ad029 (cherry picked from commit 3c00cbc0f119c3f59325aa6d5061529feb58462b) --- services/gpuservice/Android.bp | 1 + services/gpuservice/GpuService.cpp | 14 +++-- .../{ => include/gpuservice}/GpuService.h | 4 ++ services/gpuservice/main_gpuservice.cpp | 2 +- .../tests/fuzzers/GpuServiceFuzzer.cpp | 2 +- .../gpuservice/tests/unittests/Android.bp | 2 + .../tests/unittests/GpuServiceTest.cpp | 52 +++++++++++++++++++ 7 files changed, 70 insertions(+), 7 deletions(-) rename services/gpuservice/{ => include/gpuservice}/GpuService.h (95%) create mode 100644 services/gpuservice/tests/unittests/GpuServiceTest.cpp diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp index fba64c7569..052efb6bbb 100644 --- a/services/gpuservice/Android.bp +++ b/services/gpuservice/Android.bp @@ -71,6 +71,7 @@ filegroup { cc_library_shared { name: "libgpuservice", defaults: ["libgpuservice_production_defaults"], + export_include_dirs: ["include"], srcs: [ ":libgpuservice_sources", ], diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 5e7b2e8df8..4a08c11c14 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -16,7 +16,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include "GpuService.h" +#include "gpuservice/GpuService.h" #include #include @@ -35,6 +35,7 @@ #include #include +#include namespace android { @@ -58,18 +59,21 @@ GpuService::GpuService() mGpuStats(std::make_unique()), mGpuMemTracer(std::make_unique()) { - std::thread gpuMemAsyncInitThread([this]() { + mGpuMemAsyncInitThread = std::make_unique([this] (){ mGpuMem->initialize(); mGpuMemTracer->initialize(mGpuMem); }); - gpuMemAsyncInitThread.detach(); - std::thread gpuWorkAsyncInitThread([this]() { + mGpuWorkAsyncInitThread = std::make_unique([this]() { mGpuWork->initialize(); }); - gpuWorkAsyncInitThread.detach(); }; +GpuService::~GpuService() { + mGpuWorkAsyncInitThread->join(); + mGpuMemAsyncInitThread->join(); +} + void GpuService::setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/include/gpuservice/GpuService.h similarity index 95% rename from services/gpuservice/GpuService.h rename to services/gpuservice/include/gpuservice/GpuService.h index 0e559f2c34..54f8f666bc 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/include/gpuservice/GpuService.h @@ -24,6 +24,7 @@ #include #include +#include #include namespace android { @@ -41,6 +42,7 @@ public: static const char* const SERVICE_NAME ANDROID_API; GpuService() ANDROID_API; + ~GpuService(); protected: status_t shellCommand(int in, int out, int err, std::vector& args) override; @@ -90,6 +92,8 @@ private: std::unique_ptr mGpuMemTracer; std::mutex mLock; std::string mDeveloperDriverPath; + std::unique_ptr mGpuMemAsyncInitThread; + std::unique_ptr mGpuWorkAsyncInitThread; }; } // namespace android diff --git a/services/gpuservice/main_gpuservice.cpp b/services/gpuservice/main_gpuservice.cpp index 64aafcab6a..200237219e 100644 --- a/services/gpuservice/main_gpuservice.cpp +++ b/services/gpuservice/main_gpuservice.cpp @@ -18,7 +18,7 @@ #include #include #include -#include "GpuService.h" +#include "gpuservice/GpuService.h" using namespace android; diff --git a/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp index c2574a3fd3..241b8646e1 100644 --- a/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp +++ b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp @@ -16,7 +16,7 @@ #include -#include "GpuService.h" +#include "gpuservice/GpuService.h" using ::android::fuzzService; using ::android::GpuService; diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp index 51642f9472..c870b17b79 100644 --- a/services/gpuservice/tests/unittests/Android.bp +++ b/services/gpuservice/tests/unittests/Android.bp @@ -28,6 +28,7 @@ cc_test { "GpuMemTest.cpp", "GpuMemTracerTest.cpp", "GpuStatsTest.cpp", + "GpuServiceTest.cpp", ], header_libs: ["bpf_headers"], shared_libs: [ @@ -45,6 +46,7 @@ cc_test { "libstatslog", "libstatspull", "libutils", + "libgpuservice", ], static_libs: [ "libgmock", diff --git a/services/gpuservice/tests/unittests/GpuServiceTest.cpp b/services/gpuservice/tests/unittests/GpuServiceTest.cpp new file mode 100644 index 0000000000..62b3e53f53 --- /dev/null +++ b/services/gpuservice/tests/unittests/GpuServiceTest.cpp @@ -0,0 +1,52 @@ +#undef LOG_TAG +#define LOG_TAG "gpuservice_unittest" + +#include "gpuservice/GpuService.h" + +#include +#include + +#include +#include + +namespace android { +namespace { + +class GpuServiceTest : public testing::Test { +public: + GpuServiceTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); + } + + ~GpuServiceTest() { + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); + } + +}; + + +/* +* The behaviour before this test + fixes was UB caused by threads accessing deallocated memory. +* +* This test creates the service (which initializes the culprit threads), +* deallocates it immediately and sleeps. +* +* GpuService's destructor gets called and joins the threads. +* If we haven't crashed by the time the sleep time has elapsed, we're good +* Let the test pass. +*/ +TEST_F(GpuServiceTest, onInitializeShouldNotCauseUseAfterFree) { + sp service = new GpuService(); + service.clear(); + std::this_thread::sleep_for(std::chrono::seconds(3)); + + // If we haven't crashed yet due to threads accessing freed up memory, let the test pass + EXPECT_TRUE(true); +} + +} // namespace +} // namespace android -- GitLab From 101ee9b65b5a61a40625e0a7f5039b41228537be Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Thu, 6 Jul 2023 18:04:14 +0000 Subject: [PATCH 0260/1187] inputflinger: fix format of parameter name comments The Google C++ style guide [0] suggests that parameter name comments should be of the form `/*paramName=*/value`. This potentially allows tooling to check that the parameter names are correct, too. [0]: https://google.github.io/styleguide/cppguide.html#Function_Argument_Comments Bug: 245989146 Test: presubmit Change-Id: I6239599692ada74438ebd8141adc05afacec915d --- .../dispatcher/InputDispatcher.cpp | 7 +- .../reader/mapper/CursorInputMapper.cpp | 10 +- .../reader/mapper/JoystickInputMapper.cpp | 2 +- .../mapper/RotaryEncoderInputMapper.cpp | 4 +- .../reader/mapper/TouchInputMapper.cpp | 18 +-- .../tests/InputDispatcher_test.cpp | 77 ++++++------ .../tests/UnwantedInteractionBlocker_test.cpp | 111 +++++++++--------- 7 files changed, 113 insertions(+), 116 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index d3c29a75f9..abb0610667 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2980,7 +2980,7 @@ InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLo !haveSameApplicationToken(windowInfo, otherInfo)) { if (DEBUG_TOUCH_OCCLUSION) { info.debugInfo.push_back( - dumpWindowForTouchOcclusion(otherInfo, /* isTouchedWindow */ false)); + dumpWindowForTouchOcclusion(otherInfo, /*isTouchedWindow=*/false)); } // canBeObscuredBy() has returned true above, which means this window is untrusted, so // we perform the checks below to see if the touch can be propagated or not based on the @@ -3008,8 +3008,7 @@ InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLo } } if (DEBUG_TOUCH_OCCLUSION) { - info.debugInfo.push_back( - dumpWindowForTouchOcclusion(windowInfo, /* isTouchedWindow */ true)); + info.debugInfo.push_back(dumpWindowForTouchOcclusion(windowInfo, /*isTouchedWindow=*/true)); } return info; } @@ -6705,7 +6704,7 @@ void InputDispatcher::displayRemoved(int32_t displayId) { { // acquire lock std::scoped_lock _l(mLock); // Set an empty list to remove all handles from the specific display. - setInputWindowsLocked(/* window handles */ {}, displayId); + setInputWindowsLocked(/*windowInfoHandles=*/{}, displayId); setFocusedApplicationLocked(displayId, nullptr); // Call focus resolver to clean up stale requests. This must be called after input windows // have been removed for the removed display. diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index c684ed40b6..79f07a5f7c 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -347,7 +347,7 @@ std::list CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, - /* videoFrames */ {})); + /*videoFrames=*/{})); } } @@ -357,7 +357,7 @@ std::list CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, - /* videoFrames */ {})); + /*videoFrames=*/{})); if (buttonsPressed) { BitSet32 pressed(buttonsPressed); @@ -371,7 +371,7 @@ std::list CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, - /* videoFrames */ {})); + /*videoFrames=*/{})); } } @@ -386,7 +386,7 @@ std::list CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, - /* videoFrames */ {})); + /*videoFrames=*/{})); } // Send scroll events. @@ -401,7 +401,7 @@ std::list CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime, - /* videoFrames */ {})); + /*videoFrames=*/{})); } } diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp index 099a95541e..8a9ea75a97 100644 --- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp +++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp @@ -352,7 +352,7 @@ std::list JoystickInputMapper::sync(nsecs_t when, nsecs_t readTime, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {})); + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /*videoFrames=*/{})); return out; } diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp index 7251830fa9..07ae5b1cac 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp @@ -148,10 +148,10 @@ std::list RotaryEncoderInputMapper::sync(nsecs_t when, nsecs_t readT out.push_back( NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, - metaState, /* buttonState */ 0, MotionClassification::NONE, + metaState, /*buttonState=*/0, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {})); + AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /*videoFrames=*/{})); } mRotaryEncoderScrollAccumulator.finishSync(); diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 44538f1434..f48ff4cb00 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -2744,7 +2744,7 @@ std::list TouchInputMapper::dispatchPointerGestures(nsecs_t when, ns buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, x, y, mPointerGesture.downTime, - /* videoFrames */ {})); + /*videoFrames=*/{})); } // Update state. @@ -3643,7 +3643,7 @@ std::list TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsec mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.lastCursorX, mPointerSimple.lastCursorY, mPointerSimple.downTime, - /* videoFrames */ {})); + /*videoFrames=*/{})); } if (mPointerSimple.hovering && !hovering) { @@ -3658,7 +3658,7 @@ std::list TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsec &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.lastCursorX, mPointerSimple.lastCursorY, mPointerSimple.downTime, - /* videoFrames */ {})); + /*videoFrames=*/{})); } if (down) { @@ -3675,7 +3675,7 @@ std::list TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsec &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, cursorPosition.x, cursorPosition.y, - mPointerSimple.downTime, /* videoFrames */ {})); + mPointerSimple.downTime, /*videoFrames=*/{})); } // Send move. @@ -3686,7 +3686,7 @@ std::list TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsec &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, cursorPosition.x, cursorPosition.y, - mPointerSimple.downTime, /* videoFrames */ {})); + mPointerSimple.downTime, /*videoFrames=*/{})); } if (hovering) { @@ -3702,7 +3702,7 @@ std::list TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsec &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, cursorPosition.x, cursorPosition.y, - mPointerSimple.downTime, /* videoFrames */ {})); + mPointerSimple.downTime, /*videoFrames=*/{})); } // Send hover move. @@ -3713,7 +3713,7 @@ std::list TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsec MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, cursorPosition.x, - cursorPosition.y, mPointerSimple.downTime, /* videoFrames */ {})); + cursorPosition.y, mPointerSimple.downTime, /*videoFrames=*/{})); } if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) { @@ -3735,7 +3735,7 @@ std::list TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsec &mPointerSimple.currentProperties, &pointerCoords, mOrientedXPrecision, mOrientedYPrecision, cursorPosition.x, cursorPosition.y, mPointerSimple.downTime, - /* videoFrames */ {})); + /*videoFrames=*/{})); } // Save state. @@ -3766,7 +3766,7 @@ std::list TouchInputMapper::abortPointerSimple(nsecs_t when, nsecs_t mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.lastCursorX, mPointerSimple.lastCursorY, mPointerSimple.downTime, - /* videoFrames */ {})); + /*videoFrames=*/{})); if (mPointerController != nullptr) { mPointerController->fade(PointerControllerInterface::Transition::GRADUAL); } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 295065610d..6a6312ec78 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -641,7 +641,7 @@ protected: void SetUp() override { mFakePolicy = std::make_unique(); mDispatcher = std::make_unique(*mFakePolicy, STALE_EVENT_TIMEOUT); - mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); + mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false); // Start InputDispatcher thread ASSERT_EQ(OK, mDispatcher->start()); } @@ -682,7 +682,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) { // Rejects undefined key actions. event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, INVALID_HMAC, - /*action*/ -1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, + /*action=*/-1, 0, AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, @@ -718,11 +718,11 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { ui::Transform identityTransform; // Rejects undefined motion actions. event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC, - /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, + /*action=*/-1, 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); + /*pointerCount=*/1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, 0ms, 0)) @@ -734,7 +734,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); + /*pointerCount=*/1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, 0ms, 0)) @@ -746,7 +746,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); + /*pointerCount=*/1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, 0ms, 0)) @@ -758,7 +758,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); + /*pointerCount=*/1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, 0ms, 0)) @@ -770,7 +770,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { 0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); + /*pointerCount=*/1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, 0ms, 0)) @@ -782,7 +782,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 0, pointerProperties, pointerCoords); + /*pointerCount=*/0, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, 0ms, 0)) @@ -793,7 +793,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords); + /*pointerCount=*/MAX_POINTERS + 1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, 0ms, 0)) @@ -806,7 +806,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); + /*pointerCount=*/1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, 0ms, 0)) @@ -818,7 +818,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 1, pointerProperties, pointerCoords); + /*pointerCount=*/1, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, 0ms, 0)) @@ -832,7 +832,7 @@ TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesMotionEvents) { identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME, ARBITRARY_TIME, - /*pointerCount*/ 2, pointerProperties, pointerCoords); + /*pointerCount=*/2, pointerProperties, pointerCoords); ASSERT_EQ(InputEventInjectionResult::FAILED, mDispatcher->injectInputEvent(&event, /*targetUid=*/{}, InputEventInjectionSync::NONE, 0ms, 0)) @@ -1551,8 +1551,8 @@ static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLA nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid key event. NotifyKeyArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, AINPUT_SOURCE_KEYBOARD, - displayId, POLICY_FLAG_PASS_TO_USER, action, /* flags */ 0, AKEYCODE_A, - KEY_A, AMETA_NONE, currentTime); + displayId, POLICY_FLAG_PASS_TO_USER, action, /*flags=*/0, AKEYCODE_A, KEY_A, + AMETA_NONE, currentTime); return args; } @@ -1562,7 +1562,7 @@ static NotifyKeyArgs generateSystemShortcutArgs(int32_t action, nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid key event. NotifyKeyArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, AINPUT_SOURCE_KEYBOARD, - displayId, 0, action, /* flags */ 0, AKEYCODE_C, KEY_C, AMETA_META_ON, + displayId, 0, action, /*flags=*/0, AKEYCODE_C, KEY_C, AMETA_META_ON, currentTime); return args; @@ -1573,7 +1573,7 @@ static NotifyKeyArgs generateAssistantKeyArgs(int32_t action, nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid key event. NotifyKeyArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, AINPUT_SOURCE_KEYBOARD, - displayId, 0, action, /* flags */ 0, AKEYCODE_ASSIST, KEY_ASSISTANT, + displayId, 0, action, /*flags=*/0, AKEYCODE_ASSIST, KEY_ASSISTANT, AMETA_NONE, currentTime); return args; @@ -1603,12 +1603,12 @@ static NotifyKeyArgs generateAssistantKeyArgs(int32_t action, nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid motion event. NotifyMotionArgs args(/*id=*/0, currentTime, /*readTime=*/0, DEVICE_ID, source, displayId, - POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0, - AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE, + POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0, /*flags=*/0, + AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties, - pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0, + pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /* videoFrames */ {}); + AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /*videoFrames=*/{}); return args; } @@ -1923,8 +1923,7 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/* id */ 1, - ToolType::FINGER) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) .x(100) .y(100)) .build(), @@ -5700,7 +5699,7 @@ protected: virtual void SetUp() override { mFakePolicy = std::make_unique(); mDispatcher = std::make_unique(*mFakePolicy); - mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false); + mDispatcher->setInputDispatchMode(/*enabled=*/true, /*frozen=*/false); mDispatcher->setKeyRepeatConfiguration(KEY_REPEAT_TIMEOUT, KEY_REPEAT_DELAY); ASSERT_EQ(OK, mDispatcher->start()); @@ -6092,36 +6091,36 @@ protected: // Test InputFilter for MotionEvent TEST_F(InputFilterTest, MotionEvent_InputFilter) { // Since the InputFilter is disabled by default, check if touch events aren't filtered. - testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered*/ false); - testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered*/ false); + testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false); + testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false); // Enable InputFilter mDispatcher->setInputFilterEnabled(true); // Test touch on both primary and second display, and check if both events are filtered. - testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered*/ true); - testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered*/ true); + testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true); + testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true); // Disable InputFilter mDispatcher->setInputFilterEnabled(false); // Test touch on both primary and second display, and check if both events aren't filtered. - testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered*/ false); - testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered*/ false); + testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/false); + testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/false); } // Test InputFilter for KeyEvent TEST_F(InputFilterTest, KeyEvent_InputFilter) { // Since the InputFilter is disabled by default, check if key event aren't filtered. - testNotifyKey(/*expectToBeFiltered*/ false); + testNotifyKey(/*expectToBeFiltered=*/false); // Enable InputFilter mDispatcher->setInputFilterEnabled(true); // Send a key event, and check if it is filtered. - testNotifyKey(/*expectToBeFiltered*/ true); + testNotifyKey(/*expectToBeFiltered=*/true); // Disable InputFilter mDispatcher->setInputFilterEnabled(false); // Send a key event, and check if it isn't filtered. - testNotifyKey(/*expectToBeFiltered*/ false); + testNotifyKey(/*expectToBeFiltered=*/false); } // Ensure that MotionEvents sent to the InputFilter through InputListener are converted to the @@ -6144,8 +6143,8 @@ TEST_F(InputFilterTest, MotionEvent_UsesLogicalDisplayCoordinates_notifyMotion) mDispatcher->setInputFilterEnabled(true); // Ensure the correct transforms are used for the displays. - testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered*/ true, firstDisplayTransform); - testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered*/ true, secondDisplayTransform); + testNotifyMotion(ADISPLAY_ID_DEFAULT, /*expectToBeFiltered=*/true, firstDisplayTransform); + testNotifyMotion(SECOND_DISPLAY_ID, /*expectToBeFiltered=*/true, secondDisplayTransform); } class InputFilterInjectionPolicyTest : public InputDispatcherTest { @@ -6214,7 +6213,7 @@ protected: identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime, eventTime, - /*pointerCount*/ 1, pointerProperties, pointerCoords); + /*pointerCount=*/1, pointerProperties, pointerCoords); const int32_t additionalPolicyFlags = POLICY_FLAG_PASS_TO_USER; ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -6763,7 +6762,7 @@ TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) { // Define a valid key down event that is stale (too old). event.initialize(InputEvent::nextId(), DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, - INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /* flags */ 0, AKEYCODE_A, KEY_A, + INVALID_HMAC, AKEY_EVENT_ACTION_DOWN, /*flags=*/0, AKEYCODE_A, KEY_A, AMETA_NONE, /*repeatCount=*/1, eventTime, eventTime); const int32_t policyFlags = POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER; @@ -9435,8 +9434,8 @@ TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) { // Spy window pilfers the pointers. EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); - window->consumeMotionPointerUp(/* idx */ 2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); - window->consumeMotionPointerUp(/* idx */ 1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); + window->consumeMotionPointerUp(/*idx=*/2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); + window->consumeMotionPointerUp(/*idx=*/1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); spy->assertNoEvents(); window->assertNoEvents(); diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp index da0815f088..7cfcf718d9 100644 --- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp +++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp @@ -88,14 +88,13 @@ static NotifyMotionArgs generateMotionArgs(nsecs_t downTime, nsecs_t eventTime, } // Define a valid motion event. - NotifyMotionArgs args(/* id */ 0, eventTime, /*readTime=*/0, DEVICE_ID, - AINPUT_SOURCE_TOUCHSCREEN, /*displayId=*/0, POLICY_FLAG_PASS_TO_USER, - action, /* actionButton */ 0, - /* flags */ 0, AMETA_NONE, /* buttonState */ 0, - MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, - pointerProperties, pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0, + NotifyMotionArgs args(/*id=*/0, eventTime, /*readTime=*/0, DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, + /*displayId=*/0, POLICY_FLAG_PASS_TO_USER, action, /*actionButton=*/0, + /*flags=*/0, AMETA_NONE, /*buttonState=*/0, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount, pointerProperties, + pointerCoords, /*xPrecision=*/0, /*yPrecision=*/0, AMOTION_EVENT_INVALID_CURSOR_POSITION, - AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, /* videoFrames */ {}); + AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime, /*videoFrames=*/{}); return args; } @@ -104,15 +103,15 @@ static InputDeviceInfo generateTestDeviceInfo() { InputDeviceIdentifier identifier; auto info = InputDeviceInfo(); - info.initialize(DEVICE_ID, /*generation*/ 1, /*controllerNumber*/ 1, identifier, "alias", - /*isExternal*/ false, /*hasMic*/ false, ADISPLAY_ID_NONE); + info.initialize(DEVICE_ID, /*generation=*/1, /*controllerNumber=*/1, identifier, "alias", + /*isExternal=*/false, /*hasMic=*/false, ADISPLAY_ID_NONE); info.addSource(AINPUT_SOURCE_TOUCHSCREEN); - info.addMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHSCREEN, 0, 1599, /*flat*/ 0, - /*fuzz*/ 0, X_RESOLUTION); - info.addMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHSCREEN, 0, 2559, /*flat*/ 0, - /*fuzz*/ 0, Y_RESOLUTION); + info.addMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHSCREEN, 0, 1599, /*flat=*/0, + /*fuzz=*/0, X_RESOLUTION); + info.addMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHSCREEN, 0, 2559, /*flat=*/0, + /*fuzz=*/0, Y_RESOLUTION); info.addMotionRange(AMOTION_EVENT_AXIS_TOUCH_MAJOR, AINPUT_SOURCE_TOUCHSCREEN, 0, 255, - /*flat*/ 0, /*fuzz*/ 0, MAJOR_RESOLUTION); + /*flat=*/0, /*fuzz=*/0, MAJOR_RESOLUTION); return info; } @@ -152,7 +151,7 @@ static void assertArgs(const NotifyMotionArgs& args, int32_t action, } TEST(RemovePointerIdsTest, RemoveOnePointer) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, AMOTION_EVENT_ACTION_MOVE, {{1, 2, 3}, {4, 5, 6}}); NotifyMotionArgs pointer1Only = removePointerIds(args, {0}); @@ -167,7 +166,7 @@ TEST(RemovePointerIdsTest, RemoveOnePointer) { */ TEST(RemovePointerIdsTest, RemoveTwoPointers) { NotifyMotionArgs args = - generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, AMOTION_EVENT_ACTION_MOVE, + generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, AMOTION_EVENT_ACTION_MOVE, {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); NotifyMotionArgs pointer1Only = removePointerIds(args, {0, 2}); @@ -179,7 +178,7 @@ TEST(RemovePointerIdsTest, RemoveTwoPointers) { * pointer during a POINTER_DOWN event. */ TEST(RemovePointerIdsTest, ActionPointerDown) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_DOWN, + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_1_DOWN, {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); NotifyMotionArgs pointers0And2 = removePointerIds(args, {1}); @@ -193,7 +192,7 @@ TEST(RemovePointerIdsTest, ActionPointerDown) { * Remove all pointers during a MOVE event. */ TEST(RemovePointerIdsTest, RemoveAllPointersDuringMove) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, AMOTION_EVENT_ACTION_MOVE, {{1, 2, 3}, {4, 5, 6}}); NotifyMotionArgs noPointers = removePointerIds(args, {0, 1}); @@ -205,7 +204,7 @@ TEST(RemovePointerIdsTest, RemoveAllPointersDuringMove) { * then we should just have ACTION_DOWN. Likewise, a POINTER_UP event should become an UP event. */ TEST(RemovePointerIdsTest, PointerDownBecomesDown) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_DOWN, + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_1_DOWN, {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); NotifyMotionArgs pointer1 = removePointerIds(args, {0, 2}); @@ -220,11 +219,11 @@ TEST(RemovePointerIdsTest, PointerDownBecomesDown) { * If a pointer that is now going down is canceled, then we can just drop the POINTER_DOWN event. */ TEST(CancelSuppressedPointersTest, CanceledPointerDownIsDropped) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_DOWN, + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_1_DOWN, {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); std::vector result = - cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {}, - /*newSuppressedPointerIds*/ {1}); + cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{}, + /*newSuppressedPointerIds=*/{1}); ASSERT_TRUE(result.empty()); } @@ -232,11 +231,11 @@ TEST(CancelSuppressedPointersTest, CanceledPointerDownIsDropped) { * If a pointer is already suppressed, the POINTER_UP event for this pointer should be dropped */ TEST(CancelSuppressedPointersTest, SuppressedPointerUpIsDropped) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_UP, + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_1_UP, {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); std::vector result = - cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {1}, - /*newSuppressedPointerIds*/ {1}); + cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{1}, + /*newSuppressedPointerIds=*/{1}); ASSERT_TRUE(result.empty()); } @@ -244,11 +243,11 @@ TEST(CancelSuppressedPointersTest, SuppressedPointerUpIsDropped) { * If a pointer is already suppressed, it should be removed from a MOVE event. */ TEST(CancelSuppressedPointersTest, SuppressedPointerIsRemovedDuringMove) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, MOVE, + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, MOVE, {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); std::vector result = - cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {1}, - /*newSuppressedPointerIds*/ {1}); + cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{1}, + /*newSuppressedPointerIds=*/{1}); ASSERT_EQ(1u, result.size()); assertArgs(result[0], MOVE, {{0, {1, 2, 3}}, {2, {7, 8, 9}}}); } @@ -259,11 +258,11 @@ TEST(CancelSuppressedPointersTest, SuppressedPointerIsRemovedDuringMove) { * 2) A MOVE event without this pointer */ TEST(CancelSuppressedPointersTest, NewlySuppressedPointerIsCanceled) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, MOVE, + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, MOVE, {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); std::vector result = - cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {}, - /*newSuppressedPointerIds*/ {1}); + cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{}, + /*newSuppressedPointerIds=*/{1}); ASSERT_EQ(2u, result.size()); assertArgs(result[0], POINTER_1_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}, {2, {7, 8, 9}}}); ASSERT_EQ(FLAG_CANCELED, result[0].flags); @@ -275,10 +274,10 @@ TEST(CancelSuppressedPointersTest, NewlySuppressedPointerIsCanceled) { * should be canceled with ACTION_CANCEL. */ TEST(CancelSuppressedPointersTest, SingleSuppressedPointerIsCanceled) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, MOVE, {{1, 2, 3}}); + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, MOVE, {{1, 2, 3}}); std::vector result = - cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {}, - /*newSuppressedPointerIds*/ {0}); + cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{}, + /*newSuppressedPointerIds=*/{0}); ASSERT_EQ(1u, result.size()); assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}}); ASSERT_EQ(FLAG_CANCELED, result[0].flags); @@ -289,11 +288,11 @@ TEST(CancelSuppressedPointersTest, SingleSuppressedPointerIsCanceled) { * but this event should also have FLAG_CANCELED to indicate that this pointer was unintentional. */ TEST(CancelSuppressedPointersTest, SuppressedPointer1GoingUpIsCanceled) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_UP, + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_1_UP, {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); std::vector result = - cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {}, - /*newSuppressedPointerIds*/ {1}); + cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{}, + /*newSuppressedPointerIds=*/{1}); ASSERT_EQ(1u, result.size()); assertArgs(result[0], POINTER_1_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}, {2, {7, 8, 9}}}); ASSERT_EQ(FLAG_CANCELED, result[0].flags); @@ -304,11 +303,11 @@ TEST(CancelSuppressedPointersTest, SuppressedPointer1GoingUpIsCanceled) { * errors with handling pointer index inside the action. */ TEST(CancelSuppressedPointersTest, SuppressedPointer0GoingUpIsCanceled) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_0_UP, + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_0_UP, {{1, 2, 3}, {4, 5, 6}}); std::vector result = - cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {}, - /*newSuppressedPointerIds*/ {0}); + cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{}, + /*newSuppressedPointerIds=*/{0}); ASSERT_EQ(1u, result.size()); assertArgs(result[0], POINTER_0_UP, {{0, {1, 2, 3}}, {1, {4, 5, 6}}}); ASSERT_EQ(FLAG_CANCELED, result[0].flags); @@ -320,10 +319,10 @@ TEST(CancelSuppressedPointersTest, SuppressedPointer0GoingUpIsCanceled) { */ TEST(CancelSuppressedPointersTest, TwoNewlySuppressedPointersAreBothCanceled) { NotifyMotionArgs args = - generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, MOVE, {{1, 2, 3}, {4, 5, 6}}); + generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, MOVE, {{1, 2, 3}, {4, 5, 6}}); std::vector result = - cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {}, - /*newSuppressedPointerIds*/ {0, 1}); + cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{}, + /*newSuppressedPointerIds=*/{0, 1}); ASSERT_EQ(1u, result.size()); assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}, {1, {4, 5, 6}}}); ASSERT_EQ(FLAG_CANCELED, result[0].flags); @@ -335,11 +334,11 @@ TEST(CancelSuppressedPointersTest, TwoNewlySuppressedPointersAreBothCanceled) { * would undo the entire gesture. */ TEST(CancelSuppressedPointersTest, TwoPointersAreCanceledDuringPointerUp) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_1_UP, + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_1_UP, {{1, 2, 3}, {4, 5, 6}}); std::vector result = - cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {1}, - /*newSuppressedPointerIds*/ {0, 1}); + cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{1}, + /*newSuppressedPointerIds=*/{0, 1}); ASSERT_EQ(1u, result.size()); assertArgs(result[0], CANCEL, {{0, {1, 2, 3}}}); ASSERT_EQ(FLAG_CANCELED, result[0].flags); @@ -350,11 +349,11 @@ TEST(CancelSuppressedPointersTest, TwoPointersAreCanceledDuringPointerUp) { * this should become a regular DOWN event because it's the only pointer that will be valid now. */ TEST(CancelSuppressedPointersTest, NewPointerDownBecomesDown) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, POINTER_2_DOWN, + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, POINTER_2_DOWN, {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}); std::vector result = - cancelSuppressedPointers(args, /*oldSuppressedPointerIds*/ {0, 1}, - /*newSuppressedPointerIds*/ {0, 1}); + cancelSuppressedPointers(args, /*oldSuppressedPointerIds=*/{0, 1}, + /*newSuppressedPointerIds=*/{0, 1}); ASSERT_EQ(1u, result.size()); assertArgs(result[0], DOWN, {{2, {7, 8, 9}}}); ASSERT_EQ(0, result[0].flags); @@ -365,7 +364,7 @@ TEST(CancelSuppressedPointersTest, NewPointerDownBecomesDown) { * struct is populated as expected. */ TEST(GetTouchesTest, ConvertDownEvent) { - NotifyMotionArgs args = generateMotionArgs(/*downTime*/ 0, /*eventTime*/ 0, DOWN, {{1, 2, 3}}); + NotifyMotionArgs args = generateMotionArgs(/*downTime=*/0, /*eventTime=*/0, DOWN, {{1, 2, 3}}); AndroidPalmFilterDeviceInfo deviceInfo = generatePalmFilterDeviceInfo(); SlotState slotState; SlotState oldSlotState = slotState; @@ -1024,7 +1023,7 @@ TEST_F(PalmRejectorFakeFilterTest, TwoPointersCanceledWhenOnePointerGoesUp) { mPalmRejector->processMotion( generateMotionArgs(downTime, downTime, DOWN, {{1342.0, 613.0, 79.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_1_DOWN, + generateMotionArgs(downTime, /*eventTime=*/1, POINTER_1_DOWN, {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}})); // Suppress both pointers!! suppressPointerAtPosition(1414, 702); @@ -1058,13 +1057,13 @@ TEST_F(PalmRejectorFakeFilterTest, CancelTwoPointers) { mPalmRejector->processMotion( generateMotionArgs(downTime, downTime, DOWN, {{1342.0, 613.0, 79.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_1_DOWN, + generateMotionArgs(downTime, /*eventTime=*/1, POINTER_1_DOWN, {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}})); // Suppress second pointer (pointer 1) suppressPointerAtPosition(1060, 700); argsList = mPalmRejector->processMotion( - generateMotionArgs(downTime, /*eventTime*/ 1, MOVE, + generateMotionArgs(downTime, /*eventTime=*/1, MOVE, {{1417.0, 685.0, 41.0}, {1060, 700, 10.0}})); ASSERT_EQ(2u, argsList.size()); ASSERT_EQ(POINTER_1_UP, argsList[0].action); @@ -1076,20 +1075,20 @@ TEST_F(PalmRejectorFakeFilterTest, CancelTwoPointers) { // A new pointer goes down and gets suppressed right away. It should just be dropped suppressPointerAtPosition(1001, 601); argsList = mPalmRejector->processMotion( - generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_2_DOWN, + generateMotionArgs(downTime, /*eventTime=*/1, POINTER_2_DOWN, {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}, {1001, 601, 5}})); ASSERT_EQ(0u, argsList.size()); // Likewise, pointer that's already canceled should be ignored argsList = mPalmRejector->processMotion( - generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_2_UP, + generateMotionArgs(downTime, /*eventTime=*/1, POINTER_2_UP, {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}, {1001, 601, 5}})); ASSERT_EQ(0u, argsList.size()); // Cancel all pointers when pointer 1 goes up. Pointer 1 was already canceled earlier. suppressPointerAtPosition(1417, 685); argsList = mPalmRejector->processMotion( - generateMotionArgs(downTime, /*eventTime*/ 1, POINTER_1_UP, + generateMotionArgs(downTime, /*eventTime=*/1, POINTER_1_UP, {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}})); ASSERT_EQ(1u, argsList.size()); ASSERT_EQ(CANCEL, argsList[0].action); -- GitLab From 3694536c9b7a8ccb2e97000f323ddf59e7875798 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 5 Jul 2023 20:29:10 +0000 Subject: [PATCH 0261/1187] installd: error on too high user Otherwise, it crashes on bad input. Fixes: 284424098 Test: installd_corpus_fuzzer Change-Id: I539ca1dcbe747219beee9252bad2bd1d8fb38aab --- cmds/installd/InstalldNativeService.cpp | 43 +++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index c6132e8ceb..b302f52f3e 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -236,6 +236,16 @@ binder::Status checkArgumentFileName(const std::string& path) { } \ } +// we could have tighter checks, but this is only to avoid hard errors. Negative values are defined +// in UserHandle.java and carry specific meanings that may not be handled by certain APIs here. +#define ENFORCE_VALID_USER(userId) \ + { \ + if (static_cast(std::abs(userId)) >= \ + std::numeric_limits::max() / AID_USER_OFFSET) { \ + return error("userId invalid: " + std::to_string(userId)); \ + } \ + } + #define CHECK_ARGUMENT_UUID(uuid) { \ binder::Status status = checkArgumentUuid((uuid)); \ if (!status.isOk()) { \ @@ -696,6 +706,7 @@ binder::Status InstalldNativeService::createAppDataLocked( int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); @@ -790,6 +801,8 @@ binder::Status InstalldNativeService::createAppDataLocked( binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory( const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t appId, int32_t flags) { + ENFORCE_VALID_USER(userId); + int32_t sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId); if (sdkSandboxUid == -1) { // There no valid sdk sandbox process for this app. Skip creation of data directory @@ -828,6 +841,7 @@ binder::Status InstalldNativeService::createAppData( int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); LOCK_PACKAGE_USER(); @@ -839,6 +853,7 @@ binder::Status InstalldNativeService::createAppData( const android::os::CreateAppDataArgs& args, android::os::CreateAppDataResult* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(args.userId); // Locking is performed depeer in the callstack. int64_t ceDataInode = -1; @@ -854,6 +869,10 @@ binder::Status InstalldNativeService::createAppDataBatched( const std::vector& args, std::vector* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + for (const auto& arg : args) { + ENFORCE_VALID_USER(arg.userId); + } + // Locking is performed depeer in the callstack. std::vector results; @@ -868,6 +887,7 @@ binder::Status InstalldNativeService::createAppDataBatched( binder::Status InstalldNativeService::reconcileSdkData( const android::os::ReconcileSdkDataArgs& args) { + ENFORCE_VALID_USER(args.userId); // Locking is performed depeer in the callstack. return reconcileSdkData(args.uuid, args.packageName, args.subDirNames, args.userId, args.appId, @@ -891,6 +911,7 @@ binder::Status InstalldNativeService::reconcileSdkData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); LOCK_PACKAGE_USER(); @@ -1041,6 +1063,7 @@ binder::Status InstalldNativeService::clearAppProfiles(const std::string& packag binder::Status InstalldNativeService::clearAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); LOCK_PACKAGE_USER(); @@ -1132,6 +1155,7 @@ binder::Status InstalldNativeService::clearAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags) { + ENFORCE_VALID_USER(userId); const char* uuid_ = uuid ? uuid->c_str() : nullptr; const char* pkgname = packageName.c_str(); @@ -1218,6 +1242,7 @@ binder::Status InstalldNativeService::deleteReferenceProfile(const std::string& binder::Status InstalldNativeService::destroyAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); LOCK_PACKAGE_USER(); @@ -1288,6 +1313,8 @@ binder::Status InstalldNativeService::destroyAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags) { + ENFORCE_VALID_USER(userId); + const char* uuid_ = uuid ? uuid->c_str() : nullptr; const char* pkgname = packageName.c_str(); @@ -1435,6 +1462,7 @@ binder::Status InstalldNativeService::snapshotAppData(const std::optional& volumeUuid, const int32_t userId, const std::vector& retainSnapshotIds) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid); LOCK_USER(); @@ -1864,6 +1895,7 @@ fail: binder::Status InstalldNativeService::createUserData(const std::optional& uuid, int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); LOCK_USER(); @@ -1884,6 +1916,7 @@ binder::Status InstalldNativeService::createUserData(const std::optional& uuid, int32_t userId, int32_t flags) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); LOCK_USER(); @@ -2671,6 +2704,7 @@ binder::Status InstalldNativeService::getUserSize(const std::optional& appIds, std::vector* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); // NOTE: Locking is relaxed on this method, since it's limited to // read-only measurements without mutation. @@ -2806,6 +2840,7 @@ binder::Status InstalldNativeService::getExternalSize(const std::optional& appIds, std::vector* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); // NOTE: Locking is relaxed on this method, since it's limited to // read-only measurements without mutation. @@ -2926,6 +2961,7 @@ binder::Status InstalldNativeService::getAppCrates( const std::vector& packageNames, int32_t userId, std::optional>>* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); for (const auto& packageName : packageNames) { CHECK_ARGUMENT_PACKAGE_NAME(packageName); @@ -2975,6 +3011,7 @@ binder::Status InstalldNativeService::getUserCrates( const std::optional& uuid, int32_t userId, std::optional>>* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); #ifdef ENABLE_STORAGE_CRATES LOCK_USER(); @@ -3018,6 +3055,7 @@ binder::Status InstalldNativeService::getUserCrates( binder::Status InstalldNativeService::setAppQuota(const std::optional& uuid, int32_t userId, int32_t appId, int64_t cacheQuota) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); std::lock_guard lock(mQuotasLock); @@ -3261,6 +3299,7 @@ binder::Status InstalldNativeService::restoreconAppData(const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, const std::string& seInfo) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); @@ -3302,6 +3342,7 @@ binder::Status InstalldNativeService::restoreconSdkDataLocked( const std::optional& uuid, const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, const std::string& seInfo) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_UUID(uuid); CHECK_ARGUMENT_PACKAGE_NAME(packageName); @@ -3753,6 +3794,7 @@ binder::Status InstalldNativeService::prepareAppProfile(const std::string& packa int32_t userId, int32_t appId, const std::string& profileName, const std::string& codePath, const std::optional& dexMetadata, bool* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + ENFORCE_VALID_USER(userId); CHECK_ARGUMENT_PACKAGE_NAME(packageName); CHECK_ARGUMENT_PATH(codePath); LOCK_PACKAGE_USER(); @@ -3775,6 +3817,7 @@ binder::Status InstalldNativeService::migrateLegacyObbData() { binder::Status InstalldNativeService::cleanupInvalidPackageDirs( const std::optional& uuid, int32_t userId, int32_t flags) { + ENFORCE_VALID_USER(userId); const char* uuid_cstr = uuid ? uuid->c_str() : nullptr; if (flags & FLAG_STORAGE_CE) { -- GitLab From 3e9c13a27415662116be71af003d311daf9e03a9 Mon Sep 17 00:00:00 2001 From: Andrei Homescu Date: Tue, 9 May 2023 02:48:22 +0000 Subject: [PATCH 0262/1187] libbinder_rs: Fix broken documentation links Building libbinder_rs on Trusty with rustdoc enabled exposed some broken links in doc comments. Fix these broken links. Bug: 242243245 Test: build in Trusty Change-Id: Ib1337c7d8362be858191809d5aa335b974c635be --- libs/binder/rust/src/binder.rs | 10 +++++----- libs/binder/rust/src/parcel.rs | 4 ++-- libs/binder/rust/src/parcel/parcelable.rs | 11 +++++------ libs/binder/rust/src/proxy.rs | 8 ++++---- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 993bdca4a5..e8f6447a57 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -97,8 +97,8 @@ where /// Interface stability promise /// -/// An interface can promise to be a stable vendor interface ([`Vintf`]), or -/// makes no stability guarantees ([`Local`]). [`Local`] is +/// An interface can promise to be a stable vendor interface ([`Stability::Vintf`]), +/// or makes no stability guarantees ([`Stability::Local`]). [`Stability::Local`] is /// currently the default stability. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] pub enum Stability { @@ -139,8 +139,8 @@ impl TryFrom for Stability { /// via `Binder::new(object)`. /// /// This is a low-level interface that should normally be automatically -/// generated from AIDL via the [`declare_binder_interface!`] macro. When using -/// the AIDL backend, users need only implement the high-level AIDL-defined +/// generated from AIDL via the [`crate::declare_binder_interface!`] macro. +/// When using the AIDL backend, users need only implement the high-level AIDL-defined /// interface. The AIDL compiler then generates a container struct that wraps /// the user-defined service and implements `Remotable`. pub trait Remotable: Send + Sync { @@ -297,7 +297,7 @@ impl InterfaceClass { /// Note: the returned pointer will not be constant. Calling this method /// multiple times for the same type will result in distinct class /// pointers. A static getter for this value is implemented in - /// [`declare_binder_interface!`]. + /// [`crate::declare_binder_interface!`]. pub fn new() -> InterfaceClass { let descriptor = CString::new(I::get_descriptor()).unwrap(); let ptr = unsafe { diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs index e4c568eab2..11b7ec0ffc 100644 --- a/libs/binder/rust/src/parcel.rs +++ b/libs/binder/rust/src/parcel.rs @@ -461,7 +461,7 @@ impl<'a> BorrowedParcel<'a> { /// and call a closure with the sub-parcel as its parameter. /// The closure can keep reading data from the sub-parcel /// until it runs out of input data. The closure is responsible - /// for calling [`ReadableSubParcel::has_more_data`] to check for + /// for calling `ReadableSubParcel::has_more_data` to check for /// more data before every read, at least until Rust generators /// are stabilized. /// After the closure returns, skip to the end of the current @@ -595,7 +595,7 @@ impl Parcel { /// and call a closure with the sub-parcel as its parameter. /// The closure can keep reading data from the sub-parcel /// until it runs out of input data. The closure is responsible - /// for calling [`ReadableSubParcel::has_more_data`] to check for + /// for calling `ReadableSubParcel::has_more_data` to check for /// more data before every read, at least until Rust generators /// are stabilized. /// After the closure returns, skip to the end of the current diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs index 5d8c11cf94..9b3228258b 100644 --- a/libs/binder/rust/src/parcel/parcelable.rs +++ b/libs/binder/rust/src/parcel/parcelable.rs @@ -50,14 +50,14 @@ pub trait Parcelable { fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()>; } -/// A struct whose instances can be written to a [`Parcel`]. +/// A struct whose instances can be written to a [`crate::parcel::Parcel`]. // Might be able to hook this up as a serde backend in the future? pub trait Serialize { - /// Serialize this instance into the given [`Parcel`]. + /// Serialize this instance into the given [`crate::parcel::Parcel`]. fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>; } -/// A struct whose instances can be restored from a [`Parcel`]. +/// A struct whose instances can be restored from a [`crate::parcel::Parcel`]. // Might be able to hook this up as a serde backend in the future? pub trait Deserialize: Sized { /// Type for the uninitialized value of this type. Will be either `Self` @@ -80,10 +80,10 @@ pub trait Deserialize: Sized { /// Convert an initialized value of type `Self` into `Self::UninitType`. fn from_init(value: Self) -> Self::UninitType; - /// Deserialize an instance from the given [`Parcel`]. + /// Deserialize an instance from the given [`crate::parcel::Parcel`]. fn deserialize(parcel: &BorrowedParcel<'_>) -> Result; - /// Deserialize an instance from the given [`Parcel`] onto the + /// Deserialize an instance from the given [`crate::parcel::Parcel`] onto the /// current object. This operation will overwrite the old value /// partially or completely, depending on how much data is available. fn deserialize_from(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> { @@ -880,7 +880,6 @@ impl Deserialize for Option { /// `Serialize`, `SerializeArray` and `SerializeOption` for /// structured parcelables. The target type must implement the /// `Parcelable` trait. -/// ``` #[macro_export] macro_rules! impl_serialize_for_parcelable { ($parcelable:ident) => { diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs index 036f6b4f01..8d41e9d5dc 100644 --- a/libs/binder/rust/src/proxy.rs +++ b/libs/binder/rust/src/proxy.rs @@ -574,7 +574,7 @@ impl Drop for WpIBinder { /// Rust wrapper around DeathRecipient objects. /// -/// The cookie in this struct represents an Arc for the owned callback. +/// The cookie in this struct represents an `Arc` for the owned callback. /// This struct owns a ref-count of it, and so does every binder that we /// have been linked with. /// @@ -667,7 +667,7 @@ impl DeathRecipient { /// /// # Safety /// - /// The `cookie` parameter must be the cookie for an Arc and + /// The `cookie` parameter must be the cookie for an `Arc` and /// the caller must hold a ref-count to it. unsafe extern "C" fn binder_died(cookie: *mut c_void) where @@ -682,7 +682,7 @@ impl DeathRecipient { /// /// # Safety /// - /// The `cookie` parameter must be the cookie for an Arc and + /// The `cookie` parameter must be the cookie for an `Arc` and /// the owner must give up a ref-count to it. unsafe extern "C" fn cookie_decr_refcount(cookie: *mut c_void) where @@ -695,7 +695,7 @@ impl DeathRecipient { /// /// # Safety /// - /// The `cookie` parameter must be the cookie for an Arc and + /// The `cookie` parameter must be the cookie for an `Arc` and /// the owner must handle the created ref-count properly. unsafe extern "C" fn cookie_incr_refcount(cookie: *mut c_void) where -- GitLab From 0bed76acb1e4cc8c18b779cc964c5c711ba5694d Mon Sep 17 00:00:00 2001 From: Akshata Kadam Date: Fri, 7 Jul 2023 15:19:32 +0530 Subject: [PATCH 0263/1187] binder_rpc_fuzzer: improve speed by reducing the no of connections To limit the creation of socket connections,reduce the value of kMaxConnections to 10. This will reduce the time it takes for a socket to connect and disconnect for a large number of times. exec/s : 68 Test: ./binder_rpc_fuzzer Bug: 247837809 Change-Id: I23ea3e80f2c63152c00b2e7ec83d8ccb067bcf0b --- libs/binder/tests/rpc_fuzzer/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp index b8ae84d5c0..dcc8b8ebf7 100644 --- a/libs/binder/tests/rpc_fuzzer/main.cpp +++ b/libs/binder/tests/rpc_fuzzer/main.cpp @@ -135,7 +135,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // b/260736889 - limit arbitrarily, due to thread resource exhaustion, which currently // aborts. Servers should consider RpcServer::setConnectionFilter instead. - constexpr size_t kMaxConnections = 1000; + constexpr size_t kMaxConnections = 10; while (provider.remaining_bytes() > 0) { if (connections.empty() || -- GitLab From 73e6d3788d4e904b927b1185cb7a299160a0268e Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 6 Jul 2023 18:07:21 -0700 Subject: [PATCH 0264/1187] Remove PointerProperties::copyFrom Remove copyFrom in favor of default-generated operator=. Bug: 271455682 Test: m checkinput Change-Id: Ie00d027bcbf0a994e04e6b79a107c32077c3a3d8 --- include/input/Input.h | 4 +-- libs/input/Input.cpp | 13 --------- libs/input/InputTransport.cpp | 14 ++++----- services/inputflinger/NotifyArgs.cpp | 4 +-- services/inputflinger/dispatcher/Entry.cpp | 4 +-- .../dispatcher/InputDispatcher.cpp | 6 ++-- .../inputflinger/dispatcher/InputState.cpp | 21 +++++++------- .../reader/mapper/TouchInputMapper.cpp | 29 +++++++++---------- 8 files changed, 39 insertions(+), 56 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index ea856c8f43..1fc9cb1207 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -493,12 +493,12 @@ struct PointerProperties { toolType = ToolType::UNKNOWN; } - bool operator==(const PointerProperties& other) const; + bool operator==(const PointerProperties& other) const = default; inline bool operator!=(const PointerProperties& other) const { return !(*this == other); } - void copyFrom(const PointerProperties& other); + PointerProperties& operator=(const PointerProperties&) = default; }; /* diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index 00925ba555..c1274110d3 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -497,19 +497,6 @@ void PointerCoords::transform(const ui::Transform& transform) { } } -// --- PointerProperties --- - -bool PointerProperties::operator==(const PointerProperties& other) const { - return id == other.id - && toolType == other.toolType; -} - -void PointerProperties::copyFrom(const PointerProperties& other) { - id = other.id; - toolType = other.toolType; -} - - // --- MotionEvent --- void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 0b0309e27b..d9b7700f4f 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -692,8 +692,8 @@ status_t InputPublisher::publishMotionEvent( msg.body.motion.eventTime = eventTime; msg.body.motion.pointerCount = pointerCount; for (uint32_t i = 0; i < pointerCount; i++) { - msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]); - msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]); + msg.body.motion.pointers[i].properties = pointerProperties[i]; + msg.body.motion.pointers[i].coords = pointerCoords[i]; } return mChannel->sendMessage(&msg); @@ -1270,13 +1270,13 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, // We know here that the coordinates for the pointer haven't changed because we // would've cleared the resampled bit in rewriteMessage if they had. We can't modify // lastResample in place becasue the mapping from pointer ID to index may have changed. - touchState.lastResample.pointers[i].copyFrom(oldLastResample.getPointerById(id)); + touchState.lastResample.pointers[i] = oldLastResample.getPointerById(id); continue; } PointerCoords& resampledCoords = touchState.lastResample.pointers[i]; const PointerCoords& currentCoords = current->getPointerById(id); - resampledCoords.copyFrom(currentCoords); + resampledCoords = currentCoords; if (other->idBits.hasBit(id) && shouldResampleTool(event->getToolType(i))) { const PointerCoords& otherCoords = other->getPointerById(id); resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X, @@ -1454,8 +1454,8 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; for (uint32_t i = 0; i < pointerCount; i++) { - pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties); - pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); + pointerProperties[i] = msg->body.motion.pointers[i].properties; + pointerCoords[i] = msg->body.motion.pointers[i].coords; } ui::Transform transform; @@ -1484,7 +1484,7 @@ void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) { uint32_t pointerCount = msg->body.motion.pointerCount; PointerCoords pointerCoords[pointerCount]; for (uint32_t i = 0; i < pointerCount; i++) { - pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); + pointerCoords[i] = msg->body.motion.pointers[i].coords; } event->setMetaState(event->getMetaState() | msg->body.motion.metaState); diff --git a/services/inputflinger/NotifyArgs.cpp b/services/inputflinger/NotifyArgs.cpp index 0fa47d1a7c..c34cd5346e 100644 --- a/services/inputflinger/NotifyArgs.cpp +++ b/services/inputflinger/NotifyArgs.cpp @@ -91,8 +91,8 @@ NotifyMotionArgs::NotifyMotionArgs( readTime(readTime), videoFrames(videoFrames) { for (uint32_t i = 0; i < pointerCount; i++) { - this->pointerProperties.push_back(pointerProperties[i]); - this->pointerCoords.push_back(pointerCoords[i]); + this->pointerProperties.emplace_back(pointerProperties[i]); + this->pointerCoords.emplace_back(pointerCoords[i]); } } diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index a670ebe04e..a0f0dcb221 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -235,8 +235,8 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 downTime(downTime), pointerCount(pointerCount) { for (uint32_t i = 0; i < pointerCount; i++) { - this->pointerProperties[i].copyFrom(pointerProperties[i]); - this->pointerCoords[i].copyFrom(pointerCoords[i]); + this->pointerProperties[i] = pointerProperties[i]; + this->pointerCoords[i] = pointerCoords[i]; } } diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index abb0610667..1d9c5b4228 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4093,9 +4093,9 @@ std::unique_ptr InputDispatcher::splitMotionEvent( uint32_t pointerId = uint32_t(pointerProperties.id); if (pointerIds.test(pointerId)) { splitPointerIndexMap[splitPointerCount] = originalPointerIndex; - splitPointerProperties[splitPointerCount].copyFrom(pointerProperties); - splitPointerCoords[splitPointerCount].copyFrom( - originalMotionEntry.pointerCoords[originalPointerIndex]); + splitPointerProperties[splitPointerCount] = pointerProperties; + splitPointerCoords[splitPointerCount] = + originalMotionEntry.pointerCoords[originalPointerIndex]; splitPointerCount += 1; } } diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index 2fcb89a731..fe0b89c025 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -240,8 +240,8 @@ void InputState::MotionMemento::setPointers(const MotionEntry& entry) { continue; } } - pointerProperties[pointerCount].copyFrom(entry.pointerProperties[i]); - pointerCoords[pointerCount].copyFrom(entry.pointerCoords[i]); + pointerProperties[pointerCount] = entry.pointerProperties[i]; + pointerCoords[pointerCount] = entry.pointerCoords[i]; pointerCount++; } } @@ -251,8 +251,8 @@ void InputState::MotionMemento::mergePointerStateTo(MotionMemento& other) const if (other.firstNewPointerIdx < 0) { other.firstNewPointerIdx = other.pointerCount; } - other.pointerProperties[other.pointerCount].copyFrom(pointerProperties[i]); - other.pointerCoords[other.pointerCount].copyFrom(pointerCoords[i]); + other.pointerProperties[other.pointerCount] = pointerProperties[i]; + other.pointerCoords[other.pointerCount] = pointerCoords[i]; other.pointerCount++; } } @@ -324,17 +324,16 @@ std::vector> InputState::synthesizePointerDownEvents // We will deliver all pointers the target already knows about for (uint32_t i = 0; i < static_cast(memento.firstNewPointerIdx); i++) { - pointerProperties[i].copyFrom(memento.pointerProperties[i]); - pointerCoords[i].copyFrom(memento.pointerCoords[i]); + pointerProperties[i] = memento.pointerProperties[i]; + pointerCoords[i] = memento.pointerCoords[i]; pointerCount++; } // We will send explicit events for all pointers the target doesn't know about for (uint32_t i = static_cast(memento.firstNewPointerIdx); i < memento.pointerCount; i++) { - - pointerProperties[i].copyFrom(memento.pointerProperties[i]); - pointerCoords[i].copyFrom(memento.pointerCoords[i]); + pointerProperties[i] = memento.pointerProperties[i]; + pointerCoords[i] = memento.pointerCoords[i]; pointerCount++; // Down only if the first pointer, pointer down otherwise @@ -370,8 +369,8 @@ std::vector> InputState::synthesizeCancelationEvent std::vector pointerCoords(MAX_POINTERS); for (uint32_t pointerIdx = 0; pointerIdx < memento.pointerCount; pointerIdx++) { uint32_t pointerId = uint32_t(memento.pointerProperties[pointerIdx].id); - pointerProperties[pointerIdx].copyFrom(memento.pointerProperties[pointerIdx]); - pointerCoords[pointerIdx].copyFrom(memento.pointerCoords[pointerIdx]); + pointerProperties[pointerIdx] = memento.pointerProperties[pointerIdx]; + pointerCoords[pointerIdx] = memento.pointerCoords[pointerIdx]; if (pointerIds.test(pointerId)) { canceledPointerIndices.push_back(pointerIdx); } diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index f48ff4cb00..b565454805 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -2009,12 +2009,12 @@ static bool updateMovedPointers(const PropertiesArray& inProperties, CoordsArray PointerCoords& curOutCoords = outCoords[outIndex]; if (curInProperties != curOutProperties) { - curOutProperties.copyFrom(curInProperties); + curOutProperties = curInProperties; changed = true; } if (curInCoords != curOutCoords) { - curOutCoords.copyFrom(curInCoords); + curOutCoords = curInCoords; changed = true; } } @@ -2756,10 +2756,9 @@ std::list TouchInputMapper::dispatchPointerGestures(nsecs_t when, ns for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty();) { uint32_t id = idBits.clearFirstMarkedBit(); uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; - mPointerGesture.lastGestureProperties[index].copyFrom( - mPointerGesture.currentGestureProperties[index]); - mPointerGesture.lastGestureCoords[index].copyFrom( - mPointerGesture.currentGestureCoords[index]); + mPointerGesture.lastGestureProperties[index] = + mPointerGesture.currentGestureProperties[index]; + mPointerGesture.lastGestureCoords[index] = mPointerGesture.currentGestureCoords[index]; mPointerGesture.lastGestureIdToIndex[id] = index; } } @@ -3543,8 +3542,7 @@ std::list TouchInputMapper::dispatchPointerStylus(nsecs_t when, nsec std::tie(x, y) = mPointerController->getPosition(); } - mPointerSimple.currentCoords.copyFrom( - mCurrentCookedState.cookedPointerData.pointerCoords[index]); + mPointerSimple.currentCoords = mCurrentCookedState.cookedPointerData.pointerCoords[index]; mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentProperties.id = 0; @@ -3582,8 +3580,8 @@ std::list TouchInputMapper::dispatchPointerMouse(nsecs_t when, nsecs const auto [x, y] = mPointerController->getPosition(); const uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id]; - mPointerSimple.currentCoords.copyFrom( - mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); + mPointerSimple.currentCoords = + mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]; mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, @@ -3723,8 +3721,7 @@ std::list TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsec mWheelXVelocityControl.move(when, &hscroll, nullptr); // Send scroll. - PointerCoords pointerCoords; - pointerCoords.copyFrom(mPointerSimple.currentCoords); + PointerCoords pointerCoords = mPointerSimple.currentCoords; pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); @@ -3740,8 +3737,8 @@ std::list TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsec // Save state. if (down || hovering) { - mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords); - mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties); + mPointerSimple.lastCoords = mPointerSimple.currentCoords; + mPointerSimple.lastProperties = mPointerSimple.currentProperties; mPointerSimple.displayId = displayId; mPointerSimple.source = mSource; mPointerSimple.lastCursorX = cursorPosition.x; @@ -3795,8 +3792,8 @@ NotifyMotionArgs TouchInputMapper::dispatchMotion( while (!idBits.isEmpty()) { uint32_t id = idBits.clearFirstMarkedBit(); uint32_t index = idToIndex[id]; - pointerProperties[pointerCount].copyFrom(properties[index]); - pointerCoords[pointerCount].copyFrom(coords[index]); + pointerProperties[pointerCount] = properties[index]; + pointerCoords[pointerCount] = coords[index]; if (changedId >= 0 && id == uint32_t(changedId)) { action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; -- GitLab From 2f3ff9f6e4f557a247cf0866a003b4ba08322e07 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Fri, 7 Jul 2023 16:58:13 +0100 Subject: [PATCH 0265/1187] Standardise safety comments for unsafe blocks, and add some more. These will soon be required by a lint. Bug: 290018030 Test: m vm virtmgr Change-Id: Ifd034f53ef1009a312796a5282760c12762844ee --- libs/binder/rust/rpcbinder/src/server.rs | 21 +- libs/binder/rust/rpcbinder/src/session.rs | 16 +- libs/binder/rust/src/binder.rs | 52 +- libs/binder/rust/src/error.rs | 166 +++---- libs/binder/rust/src/native.rs | 189 ++++---- libs/binder/rust/src/parcel.rs | 123 +++-- .../binder/rust/src/parcel/file_descriptor.rs | 51 +- libs/binder/rust/src/parcel/parcelable.rs | 208 ++++---- .../rust/src/parcel/parcelable_holder.rs | 14 +- libs/binder/rust/src/proxy.rs | 452 ++++++++---------- libs/binder/rust/src/state.rs | 24 +- 11 files changed, 632 insertions(+), 684 deletions(-) diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs index 81f68f5a29..6fda878d07 100644 --- a/libs/binder/rust/rpcbinder/src/server.rs +++ b/libs/binder/rust/rpcbinder/src/server.rs @@ -33,9 +33,9 @@ foreign_type! { pub struct RpcServerRef; } -/// SAFETY - The opaque handle can be cloned freely. +/// SAFETY: The opaque handle can be cloned freely. unsafe impl Send for RpcServer {} -/// SAFETY - The underlying C++ RpcServer class is thread-safe. +/// SAFETY: The underlying C++ RpcServer class is thread-safe. unsafe impl Sync for RpcServer {} impl RpcServer { @@ -59,7 +59,10 @@ impl RpcServer { /// Creates a binder RPC server, serving the supplied binder service implementation on the given /// socket file descriptor. The socket should be bound to an address before calling this /// function. - pub fn new_bound_socket(mut service: SpIBinder, socket_fd: OwnedFd) -> Result { + pub fn new_bound_socket( + mut service: SpIBinder, + socket_fd: OwnedFd, + ) -> Result { let service = service.as_native_mut(); // SAFETY: Service ownership is transferring to the server and won't be valid afterward. @@ -67,7 +70,8 @@ impl RpcServer { // The server takes ownership of the socket FD. unsafe { Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newBoundSocket( - service, socket_fd.into_raw_fd(), + service, + socket_fd.into_raw_fd(), )) } } @@ -120,7 +124,9 @@ impl RpcServer { if ptr.is_null() { return Err(Error::new(ErrorKind::Other, "Failed to start server")); } - Ok(RpcServer::from_ptr(ptr)) + // SAFETY: Our caller must pass us a valid or null pointer, and we've checked that it's not + // null. + Ok(unsafe { RpcServer::from_ptr(ptr) }) } } @@ -130,7 +136,7 @@ impl RpcServerRef { &self, modes: &[FileDescriptorTransportMode], ) { - // SAFETY - Does not keep the pointer after returning does, nor does it + // SAFETY: Does not keep the pointer after returning does, nor does it // read past its boundary. Only passes the 'self' pointer as an opaque handle. unsafe { binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes( @@ -143,18 +149,21 @@ impl RpcServerRef { /// Starts a new background thread and calls join(). Returns immediately. pub fn start(&self) { + // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer. unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) }; } /// Joins the RpcServer thread. The call blocks until the server terminates. /// This must be called from exactly one thread. pub fn join(&self) { + // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer. unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) }; } /// Shuts down the running RpcServer. Can be called multiple times and from /// multiple threads. Called automatically during drop(). pub fn shutdown(&self) -> Result<(), Error> { + // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer. if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } { Ok(()) } else { diff --git a/libs/binder/rust/rpcbinder/src/session.rs b/libs/binder/rust/rpcbinder/src/session.rs index 28c5390665..79a951073e 100644 --- a/libs/binder/rust/rpcbinder/src/session.rs +++ b/libs/binder/rust/rpcbinder/src/session.rs @@ -36,15 +36,15 @@ foreign_type! { pub struct RpcSessionRef; } -/// SAFETY - The opaque handle can be cloned freely. +/// SAFETY: The opaque handle can be cloned freely. unsafe impl Send for RpcSession {} -/// SAFETY - The underlying C++ RpcSession class is thread-safe. +/// SAFETY: The underlying C++ RpcSession class is thread-safe. unsafe impl Sync for RpcSession {} impl RpcSession { /// Allocates a new RpcSession object. pub fn new() -> RpcSession { - // SAFETY - Takes ownership of the returned handle, which has correct refcount. + // SAFETY: Takes ownership of the returned handle, which has correct refcount. unsafe { RpcSession::from_ptr(binder_rpc_unstable_bindgen::ARpcSession_new()) } } } @@ -58,7 +58,7 @@ impl Default for RpcSession { impl RpcSessionRef { /// Sets the file descriptor transport mode for this session. pub fn set_file_descriptor_transport_mode(&self, mode: FileDescriptorTransportMode) { - // SAFETY - Only passes the 'self' pointer as an opaque handle. + // SAFETY: Only passes the 'self' pointer as an opaque handle. unsafe { binder_rpc_unstable_bindgen::ARpcSession_setFileDescriptorTransportMode( self.as_ptr(), @@ -69,7 +69,7 @@ impl RpcSessionRef { /// Sets the maximum number of incoming threads. pub fn set_max_incoming_threads(&self, threads: usize) { - // SAFETY - Only passes the 'self' pointer as an opaque handle. + // SAFETY: Only passes the 'self' pointer as an opaque handle. unsafe { binder_rpc_unstable_bindgen::ARpcSession_setMaxIncomingThreads(self.as_ptr(), threads) }; @@ -77,7 +77,7 @@ impl RpcSessionRef { /// Sets the maximum number of outgoing connections. pub fn set_max_outgoing_connections(&self, connections: usize) { - // SAFETY - Only passes the 'self' pointer as an opaque handle. + // SAFETY: Only passes the 'self' pointer as an opaque handle. unsafe { binder_rpc_unstable_bindgen::ARpcSession_setMaxOutgoingConnections( self.as_ptr(), @@ -210,10 +210,10 @@ impl RpcSessionRef { type RequestFd<'a> = &'a mut dyn FnMut() -> Option; unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int { + let request_fd_ptr = param as *mut RequestFd; // 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_ptr = param as *mut RequestFd; - let request_fd = request_fd_ptr.as_mut().unwrap(); + let request_fd = unsafe { request_fd_ptr.as_mut().unwrap() }; request_fd().unwrap_or(-1) } diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 993bdca4a5..5f7a044e0b 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -300,15 +300,14 @@ impl InterfaceClass { /// [`declare_binder_interface!`]. pub fn new() -> InterfaceClass { let descriptor = CString::new(I::get_descriptor()).unwrap(); + // Safety: `AIBinder_Class_define` expects a valid C string, and three + // valid callback functions, all non-null pointers. The C string is + // copied and need not be valid for longer than the call, so we can drop + // it after the call. We can safely assign null to the onDump and + // handleShellCommand callbacks as long as the class pointer was + // non-null. Rust None for a Option is guaranteed to be a NULL + // pointer. Rust retains ownership of the pointer after it is defined. let ptr = unsafe { - // Safety: `AIBinder_Class_define` expects a valid C string, and - // three valid callback functions, all non-null pointers. The C - // string is copied and need not be valid for longer than the call, - // so we can drop it after the call. We can safely assign null to - // the onDump and handleShellCommand callbacks as long as the class - // pointer was non-null. Rust None for a Option is guaranteed to - // be a NULL pointer. Rust retains ownership of the pointer after it - // is defined. let class = sys::AIBinder_Class_define( descriptor.as_ptr(), Some(I::on_create), @@ -338,13 +337,12 @@ impl InterfaceClass { /// Get the interface descriptor string of this class. pub fn get_descriptor(&self) -> String { + // SAFETY: The descriptor returned by AIBinder_Class_getDescriptor is + // always a two-byte null terminated sequence of u16s. Thus, we can + // continue reading from the pointer until we hit a null value, and this + // pointer can be a valid slice if the slice length is <= the number of + // u16 elements before the null terminator. unsafe { - // SAFETY: The descriptor returned by AIBinder_Class_getDescriptor - // is always a two-byte null terminated sequence of u16s. Thus, we - // can continue reading from the pointer until we hit a null value, - // and this pointer can be a valid slice if the slice length is <= - // the number of u16 elements before the null terminator. - let raw_descriptor: *const c_char = sys::AIBinder_Class_getDescriptor(self.0); CStr::from_ptr(raw_descriptor) .to_str() @@ -542,17 +540,15 @@ macro_rules! binder_fn_get_class { static CLASS_INIT: std::sync::Once = std::sync::Once::new(); static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None; + // Safety: This assignment is guarded by the `CLASS_INIT` `Once` + // variable, and therefore is thread-safe, as it can only occur + // once. CLASS_INIT.call_once(|| unsafe { - // Safety: This assignment is guarded by the `CLASS_INIT` `Once` - // variable, and therefore is thread-safe, as it can only occur - // once. CLASS = Some($constructor); }); - unsafe { - // Safety: The `CLASS` variable can only be mutated once, above, - // and is subsequently safe to read from any thread. - CLASS.unwrap() - } + // Safety: The `CLASS` variable can only be mutated once, above, and + // is subsequently safe to read from any thread. + unsafe { CLASS.unwrap() } } }; } @@ -664,6 +660,8 @@ pub unsafe trait AsNative { fn as_native_mut(&mut self) -> *mut T; } +// Safety: If V is a valid Android C++ type then we can either use that or a +// null pointer. unsafe impl> AsNative for Option { fn as_native(&self) -> *const T { self.as_ref().map_or(ptr::null(), |v| v.as_native()) @@ -924,15 +922,15 @@ macro_rules! declare_binder_interface { static CLASS_INIT: std::sync::Once = std::sync::Once::new(); static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None; + // Safety: This assignment is guarded by the `CLASS_INIT` `Once` + // variable, and therefore is thread-safe, as it can only occur + // once. CLASS_INIT.call_once(|| unsafe { - // Safety: This assignment is guarded by the `CLASS_INIT` `Once` - // variable, and therefore is thread-safe, as it can only occur - // once. CLASS = Some($crate::binder_impl::InterfaceClass::new::<$crate::binder_impl::Binder<$native>>()); }); + // Safety: The `CLASS` variable can only be mutated once, above, + // and is subsequently safe to read from any thread. unsafe { - // Safety: The `CLASS` variable can only be mutated once, above, - // and is subsequently safe to read from any thread. CLASS.unwrap() } } diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs index ba260624bc..8d9ce0e731 100644 --- a/libs/binder/rust/src/error.rs +++ b/libs/binder/rust/src/error.rs @@ -112,41 +112,35 @@ fn to_cstring>(message: T) -> Option { impl Status { /// Create a status object representing a successful transaction. pub fn ok() -> Self { - let ptr = unsafe { - // Safety: `AStatus_newOk` always returns a new, heap allocated - // pointer to an `ASTatus` object, so we know this pointer will be - // valid. - // - // Rust takes ownership of the returned pointer. - sys::AStatus_newOk() - }; + // Safety: `AStatus_newOk` always returns a new, heap allocated + // pointer to an `ASTatus` object, so we know this pointer will be + // valid. + // + // Rust takes ownership of the returned pointer. + let ptr = unsafe { sys::AStatus_newOk() }; Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } /// Create a status object from a service specific error pub fn new_service_specific_error(err: i32, message: Option<&CStr>) -> Status { let ptr = if let Some(message) = message { - unsafe { - // Safety: Any i32 is a valid service specific error for the - // error code parameter. We construct a valid, null-terminated - // `CString` from the message, which must be a valid C-style - // string to pass as the message. This function always returns a - // new, heap allocated pointer to an `AStatus` object, so we - // know the returned pointer will be valid. - // - // Rust takes ownership of the returned pointer. - sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr()) - } + // Safety: Any i32 is a valid service specific error for the + // error code parameter. We construct a valid, null-terminated + // `CString` from the message, which must be a valid C-style + // string to pass as the message. This function always returns a + // new, heap allocated pointer to an `AStatus` object, so we + // know the returned pointer will be valid. + // + // Rust takes ownership of the returned pointer. + unsafe { sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr()) } } else { - unsafe { - // Safety: Any i32 is a valid service specific error for the - // error code parameter. This function always returns a new, - // heap allocated pointer to an `AStatus` object, so we know the - // returned pointer will be valid. - // - // Rust takes ownership of the returned pointer. - sys::AStatus_fromServiceSpecificError(err) - } + // Safety: Any i32 is a valid service specific error for the + // error code parameter. This function always returns a new, + // heap allocated pointer to an `AStatus` object, so we know the + // returned pointer will be valid. + // + // Rust takes ownership of the returned pointer. + unsafe { sys::AStatus_fromServiceSpecificError(err) } }; Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } @@ -159,6 +153,8 @@ impl Status { /// Create a status object from an exception code pub fn new_exception(exception: ExceptionCode, message: Option<&CStr>) -> Status { if let Some(message) = message { + // Safety: the C string pointer is valid and not retained by the + // function. let ptr = unsafe { sys::AStatus_fromExceptionCodeWithMessage(exception as i32, message.as_ptr()) }; @@ -187,37 +183,31 @@ impl Status { /// Returns `true` if this status represents a successful transaction. pub fn is_ok(&self) -> bool { - unsafe { - // Safety: `Status` always contains a valid `AStatus` pointer, so we - // are always passing a valid pointer to `AStatus_isOk` here. - sys::AStatus_isOk(self.as_native()) - } + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to `AStatus_isOk` here. + unsafe { sys::AStatus_isOk(self.as_native()) } } /// Returns a description of the status. pub fn get_description(&self) -> String { - let description_ptr = unsafe { - // Safety: `Status` always contains a valid `AStatus` pointer, so we - // are always passing a valid pointer to `AStatus_getDescription` - // here. - // - // `AStatus_getDescription` always returns a valid pointer to a null - // terminated C string. Rust is responsible for freeing this pointer - // via `AStatus_deleteDescription`. - sys::AStatus_getDescription(self.as_native()) - }; - let description = unsafe { - // Safety: `AStatus_getDescription` always returns a valid C string, - // which can be safely converted to a `CStr`. - CStr::from_ptr(description_ptr) - }; + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to `AStatus_getDescription` + // here. + // + // `AStatus_getDescription` always returns a valid pointer to a null + // terminated C string. Rust is responsible for freeing this pointer + // via `AStatus_deleteDescription`. + let description_ptr = unsafe { sys::AStatus_getDescription(self.as_native()) }; + // Safety: `AStatus_getDescription` always returns a valid C string, + // which can be safely converted to a `CStr`. + let description = unsafe { CStr::from_ptr(description_ptr) }; let description = description.to_string_lossy().to_string(); + // Safety: `description_ptr` was returned from + // `AStatus_getDescription` above, and must be freed via + // `AStatus_deleteDescription`. We must not access the pointer after + // this call, so we copy it into an owned string above and return + // that string. unsafe { - // Safety: `description_ptr` was returned from - // `AStatus_getDescription` above, and must be freed via - // `AStatus_deleteDescription`. We must not access the pointer after - // this call, so we copy it into an owned string above and return - // that string. sys::AStatus_deleteDescription(description_ptr); } description @@ -225,12 +215,10 @@ impl Status { /// Returns the exception code of the status. pub fn exception_code(&self) -> ExceptionCode { - let code = unsafe { - // Safety: `Status` always contains a valid `AStatus` pointer, so we - // are always passing a valid pointer to `AStatus_getExceptionCode` - // here. - sys::AStatus_getExceptionCode(self.as_native()) - }; + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to `AStatus_getExceptionCode` + // here. + let code = unsafe { sys::AStatus_getExceptionCode(self.as_native()) }; parse_exception_code(code) } @@ -241,11 +229,9 @@ impl Status { /// exception or a service specific error. To find out if this transaction /// as a whole is okay, use [`is_ok`](Self::is_ok) instead. pub fn transaction_error(&self) -> StatusCode { - let code = unsafe { - // Safety: `Status` always contains a valid `AStatus` pointer, so we - // are always passing a valid pointer to `AStatus_getStatus` here. - sys::AStatus_getStatus(self.as_native()) - }; + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to `AStatus_getStatus` here. + let code = unsafe { sys::AStatus_getStatus(self.as_native()) }; parse_status_code(code) } @@ -258,12 +244,10 @@ impl Status { /// find out if this transaction as a whole is okay, use /// [`is_ok`](Self::is_ok) instead. pub fn service_specific_error(&self) -> i32 { - unsafe { - // Safety: `Status` always contains a valid `AStatus` pointer, so we - // are always passing a valid pointer to - // `AStatus_getServiceSpecificError` here. - sys::AStatus_getServiceSpecificError(self.as_native()) - } + // Safety: `Status` always contains a valid `AStatus` pointer, so we + // are always passing a valid pointer to + // `AStatus_getServiceSpecificError` here. + unsafe { sys::AStatus_getServiceSpecificError(self.as_native()) } } /// Calls `op` if the status was ok, otherwise returns an `Err` value of @@ -321,24 +305,20 @@ impl From for Status { impl From for Status { fn from(status: status_t) -> Status { - let ptr = unsafe { - // Safety: `AStatus_fromStatus` expects any `status_t` integer, so - // this is a safe FFI call. Unknown values will be coerced into - // UNKNOWN_ERROR. - sys::AStatus_fromStatus(status) - }; + // Safety: `AStatus_fromStatus` expects any `status_t` integer, so + // this is a safe FFI call. Unknown values will be coerced into + // UNKNOWN_ERROR. + let ptr = unsafe { sys::AStatus_fromStatus(status) }; Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } } impl From for Status { fn from(code: ExceptionCode) -> Status { - let ptr = unsafe { - // Safety: `AStatus_fromExceptionCode` expects any - // `binder_exception_t` (i32) integer, so this is a safe FFI call. - // Unknown values will be coerced into EX_TRANSACTION_FAILED. - sys::AStatus_fromExceptionCode(code as i32) - }; + // Safety: `AStatus_fromExceptionCode` expects any + // `binder_exception_t` (i32) integer, so this is a safe FFI call. + // Unknown values will be coerced into EX_TRANSACTION_FAILED. + let ptr = unsafe { sys::AStatus_fromExceptionCode(code as i32) }; Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer")) } } @@ -363,20 +343,18 @@ impl From for status_t { impl Drop for Status { fn drop(&mut self) { + // Safety: `Status` manages the lifetime of its inner `AStatus` + // pointee, so we need to delete it here. We know that the pointer + // will be valid here since `Status` always contains a valid pointer + // while it is alive. unsafe { - // Safety: `Status` manages the lifetime of its inner `AStatus` - // pointee, so we need to delete it here. We know that the pointer - // will be valid here since `Status` always contains a valid pointer - // while it is alive. sys::AStatus_delete(self.0.as_mut()); } } } -/// # Safety -/// -/// `Status` always contains a valid pointer to an `AStatus` object, so we can -/// trivially convert it to a correctly-typed raw pointer. +/// Safety: `Status` always contains a valid pointer to an `AStatus` object, so +/// we can trivially convert it to a correctly-typed raw pointer. /// /// Care must be taken that the returned pointer is only dereferenced while the /// `Status` object is still alive. @@ -386,11 +364,9 @@ unsafe impl AsNative for Status { } fn as_native_mut(&mut self) -> *mut sys::AStatus { - unsafe { - // Safety: The pointer will be valid here since `Status` always - // contains a valid and initialized pointer while it is alive. - self.0.as_mut() - } + // Safety: The pointer will be valid here since `Status` always contains + // a valid and initialized pointer while it is alive. + unsafe { self.0.as_mut() } } } diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs index 5557168055..b248f5eb28 100644 --- a/libs/binder/rust/src/native.rs +++ b/libs/binder/rust/src/native.rs @@ -42,7 +42,7 @@ pub struct Binder { rust_object: *mut T, } -/// # Safety +/// Safety: /// /// A `Binder` is a pair of unique owning pointers to two values: /// * a C++ ABBinder which the C++ API guarantees can be passed between threads @@ -54,7 +54,7 @@ pub struct Binder { /// to how `Box` is `Send` if `T` is `Send`. unsafe impl Send for Binder {} -/// # Safety +/// Safety: /// /// A `Binder` is a pair of unique owning pointers to two values: /// * a C++ ABBinder which is thread-safe, i.e. `Send + Sync` @@ -89,15 +89,13 @@ impl Binder { pub fn new_with_stability(rust_object: T, stability: Stability) -> Binder { let class = T::get_class(); let rust_object = Box::into_raw(Box::new(rust_object)); - let ibinder = unsafe { - // Safety: `AIBinder_new` expects a valid class pointer (which we - // initialize via `get_class`), and an arbitrary pointer - // argument. The caller owns the returned `AIBinder` pointer, which - // is a strong reference to a `BBinder`. This reference should be - // decremented via `AIBinder_decStrong` when the reference lifetime - // ends. - sys::AIBinder_new(class.into(), rust_object as *mut c_void) - }; + // Safety: `AIBinder_new` expects a valid class pointer (which we + // initialize via `get_class`), and an arbitrary pointer + // argument. The caller owns the returned `AIBinder` pointer, which + // is a strong reference to a `BBinder`. This reference should be + // decremented via `AIBinder_decStrong` when the reference lifetime + // ends. + let ibinder = unsafe { sys::AIBinder_new(class.into(), rust_object as *mut c_void) }; let mut binder = Binder { ibinder, rust_object }; binder.mark_stability(stability); binder @@ -176,15 +174,14 @@ impl Binder { /// } /// # } pub fn set_extension(&mut self, extension: &mut SpIBinder) -> Result<()> { - let status = unsafe { - // Safety: `AIBinder_setExtension` expects two valid, mutable - // `AIBinder` pointers. We are guaranteed that both `self` and - // `extension` contain valid `AIBinder` pointers, because they - // cannot be initialized without a valid - // pointer. `AIBinder_setExtension` does not take ownership of - // either parameter. - sys::AIBinder_setExtension(self.as_native_mut(), extension.as_native_mut()) - }; + let status = + // Safety: `AIBinder_setExtension` expects two valid, mutable + // `AIBinder` pointers. We are guaranteed that both `self` and + // `extension` contain valid `AIBinder` pointers, because they + // cannot be initialized without a valid + // pointer. `AIBinder_setExtension` does not take ownership of + // either parameter. + unsafe { sys::AIBinder_setExtension(self.as_native_mut(), extension.as_native_mut()) }; status_result(status) } @@ -199,9 +196,9 @@ impl Binder { match stability { Stability::Local => self.mark_local_stability(), Stability::Vintf => { + // Safety: Self always contains a valid `AIBinder` pointer, so + // we can always call this C API safely. unsafe { - // Safety: Self always contains a valid `AIBinder` pointer, so - // we can always call this C API safely. sys::AIBinder_markVintfStability(self.as_native_mut()); } } @@ -212,9 +209,9 @@ impl Binder { /// building for android_vendor and system otherwise. #[cfg(android_vendor)] fn mark_local_stability(&mut self) { + // Safety: Self always contains a valid `AIBinder` pointer, so we can + // always call this C API safely. unsafe { - // Safety: Self always contains a valid `AIBinder` pointer, so - // we can always call this C API safely. sys::AIBinder_markVendorStability(self.as_native_mut()); } } @@ -223,9 +220,9 @@ impl Binder { /// building for android_vendor and system otherwise. #[cfg(not(android_vendor))] fn mark_local_stability(&mut self) { + // Safety: Self always contains a valid `AIBinder` pointer, so we can + // always call this C API safely. unsafe { - // Safety: Self always contains a valid `AIBinder` pointer, so - // we can always call this C API safely. sys::AIBinder_markSystemStability(self.as_native_mut()); } } @@ -239,13 +236,13 @@ impl Interface for Binder { /// remotable object, which will prevent the object from being dropped while /// the `SpIBinder` is alive. fn as_binder(&self) -> SpIBinder { + // Safety: `self.ibinder` is guaranteed to always be a valid pointer + // to an `AIBinder` by the `Binder` constructor. We are creating a + // copy of the `self.ibinder` strong reference, but + // `SpIBinder::from_raw` assumes it receives an owned pointer with + // its own strong reference. We first increment the reference count, + // so that the new `SpIBinder` will be tracked as a new reference. unsafe { - // Safety: `self.ibinder` is guaranteed to always be a valid pointer - // to an `AIBinder` by the `Binder` constructor. We are creating a - // copy of the `self.ibinder` strong reference, but - // `SpIBinder::from_raw` assumes it receives an owned pointer with - // its own strong reference. We first increment the reference count, - // so that the new `SpIBinder` will be tracked as a new reference. sys::AIBinder_incStrong(self.ibinder); SpIBinder::from_raw(self.ibinder).unwrap() } @@ -275,10 +272,20 @@ impl InterfaceClassMethods for Binder { reply: *mut sys::AParcel, ) -> status_t { let res = { - let mut reply = BorrowedParcel::from_raw(reply).unwrap(); - let data = BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap(); - let object = sys::AIBinder_getUserData(binder); - let binder: &T = &*(object as *const T); + // Safety: The caller must give us a parcel pointer which is either + // null or valid at least for the duration of this function call. We + // don't keep the resulting value beyond the function. + let mut reply = unsafe { BorrowedParcel::from_raw(reply).unwrap() }; + // Safety: The caller must give us a parcel pointer which is either + // null or valid at least for the duration of this function call. We + // don't keep the resulting value beyond the function. + let data = unsafe { BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap() }; + // Safety: Our caller promised that `binder` is a non-null, valid + // pointer to a local `AIBinder`. + let object = unsafe { sys::AIBinder_getUserData(binder) }; + // Safety: Our caller promised that the binder has a `T` pointer in + // its user data. + let binder: &T = unsafe { &*(object as *const T) }; binder.on_transact(code, &data, &mut reply) }; match res { @@ -295,7 +302,9 @@ impl InterfaceClassMethods for Binder { /// Must be called with a valid pointer to a `T` object. After this call, /// the pointer will be invalid and should not be dereferenced. unsafe extern "C" fn on_destroy(object: *mut c_void) { - drop(Box::from_raw(object as *mut T)); + // Safety: Our caller promised that `object` is a valid pointer to a + // `T`. + drop(unsafe { Box::from_raw(object as *mut T) }); } /// Called whenever a new, local `AIBinder` object is needed of a specific @@ -320,7 +329,7 @@ impl InterfaceClassMethods for Binder { /// Must be called with a non-null, valid pointer to a local `AIBinder` that /// contains a `T` pointer in its user data. fd should be a non-owned file /// descriptor, and args must be an array of null-terminated string - /// poiinters with length num_args. + /// pointers with length num_args. unsafe extern "C" fn on_dump( binder: *mut sys::AIBinder, fd: i32, @@ -330,8 +339,9 @@ impl InterfaceClassMethods for Binder { if fd < 0 { return StatusCode::UNEXPECTED_NULL as status_t; } - // We don't own this file, so we need to be careful not to drop it. - let file = ManuallyDrop::new(File::from_raw_fd(fd)); + // Safety: Our caller promised that fd is a file descriptor. We don't + // own this file descriptor, so we need to be careful not to drop it. + let file = unsafe { ManuallyDrop::new(File::from_raw_fd(fd)) }; if args.is_null() && num_args != 0 { return StatusCode::UNEXPECTED_NULL as status_t; @@ -340,14 +350,22 @@ impl InterfaceClassMethods for Binder { let args = if args.is_null() || num_args == 0 { vec![] } else { - slice::from_raw_parts(args, num_args as usize) - .iter() - .map(|s| CStr::from_ptr(*s)) - .collect() + // Safety: Our caller promised that `args` is an array of + // null-terminated string pointers with length `num_args`. + unsafe { + slice::from_raw_parts(args, num_args as usize) + .iter() + .map(|s| CStr::from_ptr(*s)) + .collect() + } }; - let object = sys::AIBinder_getUserData(binder); - let binder: &T = &*(object as *const T); + // Safety: Our caller promised that `binder` is a non-null, valid + // pointer to a local `AIBinder`. + let object = unsafe { sys::AIBinder_getUserData(binder) }; + // Safety: Our caller promised that the binder has a `T` pointer in its + // user data. + let binder: &T = unsafe { &*(object as *const T) }; let res = binder.on_dump(&file, &args); match res { @@ -363,11 +381,11 @@ impl Drop for Binder { // actually destroys the object, it calls `on_destroy` and we can drop the // `rust_object` then. fn drop(&mut self) { + // Safety: When `self` is dropped, we can no longer access the + // reference, so can decrement the reference count. `self.ibinder` is + // always a valid `AIBinder` pointer, so is valid to pass to + // `AIBinder_decStrong`. unsafe { - // Safety: When `self` is dropped, we can no longer access the - // reference, so can decrement the reference count. `self.ibinder` - // is always a valid `AIBinder` pointer, so is valid to pass to - // `AIBinder_decStrong`. sys::AIBinder_decStrong(self.ibinder); } } @@ -377,14 +395,11 @@ impl Deref for Binder { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { - // Safety: While `self` is alive, the reference count of the - // underlying object is > 0 and therefore `on_destroy` cannot be - // called. Therefore while `self` is alive, we know that - // `rust_object` is still a valid pointer to a heap allocated object - // of type `T`. - &*self.rust_object - } + // Safety: While `self` is alive, the reference count of the underlying + // object is > 0 and therefore `on_destroy` cannot be called. Therefore + // while `self` is alive, we know that `rust_object` is still a valid + // pointer to a heap allocated object of type `T`. + unsafe { &*self.rust_object } } } @@ -405,13 +420,10 @@ impl TryFrom for Binder { if Some(class) != ibinder.get_class() { return Err(StatusCode::BAD_TYPE); } - let userdata = unsafe { - // Safety: `SpIBinder` always holds a valid pointer pointer to an - // `AIBinder`, which we can safely pass to - // `AIBinder_getUserData`. `ibinder` retains ownership of the - // returned pointer. - sys::AIBinder_getUserData(ibinder.as_native_mut()) - }; + // Safety: `SpIBinder` always holds a valid pointer pointer to an + // `AIBinder`, which we can safely pass to `AIBinder_getUserData`. + // `ibinder` retains ownership of the returned pointer. + let userdata = unsafe { sys::AIBinder_getUserData(ibinder.as_native_mut()) }; if userdata.is_null() { return Err(StatusCode::UNEXPECTED_NULL); } @@ -422,12 +434,10 @@ impl TryFrom for Binder { } } -/// # Safety -/// -/// The constructor for `Binder` guarantees that `self.ibinder` will contain a -/// valid, non-null pointer to an `AIBinder`, so this implementation is type -/// safe. `self.ibinder` will remain valid for the entire lifetime of `self` -/// because we hold a strong reference to the `AIBinder` until `self` is +/// Safety: The constructor for `Binder` guarantees that `self.ibinder` will +/// contain a valid, non-null pointer to an `AIBinder`, so this implementation +/// is type safe. `self.ibinder` will remain valid for the entire lifetime of +/// `self` because we hold a strong reference to the `AIBinder` until `self` is /// dropped. unsafe impl AsNative for Binder { fn as_native(&self) -> *const sys::AIBinder { @@ -447,14 +457,12 @@ unsafe impl AsNative for Binder { /// This function will panic if the identifier contains a 0 byte (NUL). pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> { let instance = CString::new(identifier).unwrap(); - let status = unsafe { - // Safety: `AServiceManager_addService` expects valid `AIBinder` and C - // string pointers. Caller retains ownership of both - // pointers. `AServiceManager_addService` creates a new strong reference - // and copies the string, so both pointers need only be valid until the - // call returns. - sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr()) - }; + let status = + // Safety: `AServiceManager_addService` expects valid `AIBinder` and C + // string pointers. Caller retains ownership of both pointers. + // `AServiceManager_addService` creates a new strong reference and copies + // the string, so both pointers need only be valid until the call returns. + unsafe { sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr()) }; status_result(status) } @@ -470,13 +478,12 @@ pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> { /// This function will panic if the identifier contains a 0 byte (NUL). pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result<()> { let instance = CString::new(identifier).unwrap(); + // Safety: `AServiceManager_registerLazyService` expects valid `AIBinder` and C + // string pointers. Caller retains ownership of both + // pointers. `AServiceManager_registerLazyService` creates a new strong reference + // and copies the string, so both pointers need only be valid until the + // call returns. let status = unsafe { - // Safety: `AServiceManager_registerLazyService` expects valid `AIBinder` and C - // string pointers. Caller retains ownership of both - // pointers. `AServiceManager_registerLazyService` creates a new strong reference - // and copies the string, so both pointers need only be valid until the - // call returns. - sys::AServiceManager_registerLazyService(binder.as_native_mut(), instance.as_ptr()) }; status_result(status) @@ -491,10 +498,8 @@ pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result< /// /// Consider using [`LazyServiceGuard`] rather than calling this directly. pub fn force_lazy_services_persist(persist: bool) { - unsafe { - // Safety: No borrowing or transfer of ownership occurs here. - sys::AServiceManager_forceLazyServicesPersist(persist) - } + // Safety: No borrowing or transfer of ownership occurs here. + unsafe { sys::AServiceManager_forceLazyServicesPersist(persist) } } /// An RAII object to ensure a process which registers lazy services is not killed. During the @@ -576,8 +581,6 @@ impl Interface for () {} /// Determine whether the current thread is currently executing an incoming /// transaction. pub fn is_handling_transaction() -> bool { - unsafe { - // Safety: This method is always safe to call. - sys::AIBinder_isHandlingTransaction() - } + // Safety: This method is always safe to call. + unsafe { sys::AIBinder_isHandlingTransaction() } } diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs index e4c568eab2..f09aef6fad 100644 --- a/libs/binder/rust/src/parcel.rs +++ b/libs/binder/rust/src/parcel.rs @@ -52,11 +52,8 @@ pub struct Parcel { ptr: NonNull, } -/// # Safety -/// -/// This type guarantees that it owns the AParcel and that all access to -/// the AParcel happens through the Parcel, so it is ok to send across -/// threads. +/// Safety: This type guarantees that it owns the AParcel and that all access to +/// the AParcel happens through the Parcel, so it is ok to send across threads. unsafe impl Send for Parcel {} /// Container for a message (data and object references) that can be sent @@ -73,11 +70,9 @@ pub struct BorrowedParcel<'a> { impl Parcel { /// Create a new empty `Parcel`. pub fn new() -> Parcel { - let ptr = unsafe { - // Safety: If `AParcel_create` succeeds, it always returns - // a valid pointer. If it fails, the process will crash. - sys::AParcel_create() - }; + // Safety: If `AParcel_create` succeeds, it always returns + // a valid pointer. If it fails, the process will crash. + let ptr = unsafe { sys::AParcel_create() }; Self { ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer") } } @@ -171,10 +166,8 @@ impl<'a> BorrowedParcel<'a> { } } -/// # Safety -/// -/// The `Parcel` constructors guarantee that a `Parcel` object will always -/// contain a valid pointer to an `AParcel`. +/// Safety: The `Parcel` constructors guarantee that a `Parcel` object will +/// always contain a valid pointer to an `AParcel`. unsafe impl AsNative for Parcel { fn as_native(&self) -> *const sys::AParcel { self.ptr.as_ptr() @@ -185,10 +178,8 @@ unsafe impl AsNative for Parcel { } } -/// # Safety -/// -/// The `BorrowedParcel` constructors guarantee that a `BorrowedParcel` object -/// will always contain a valid pointer to an `AParcel`. +/// Safety: The `BorrowedParcel` constructors guarantee that a `BorrowedParcel` +/// object will always contain a valid pointer to an `AParcel`. unsafe impl<'a> AsNative for BorrowedParcel<'a> { fn as_native(&self) -> *const sys::AParcel { self.ptr.as_ptr() @@ -203,10 +194,8 @@ unsafe impl<'a> AsNative for BorrowedParcel<'a> { impl<'a> BorrowedParcel<'a> { /// Data written to parcelable is zero'd before being deleted or reallocated. pub fn mark_sensitive(&mut self) { - unsafe { - // Safety: guaranteed to have a parcel object, and this method never fails - sys::AParcel_markSensitive(self.as_native()) - } + // Safety: guaranteed to have a parcel object, and this method never fails + unsafe { sys::AParcel_markSensitive(self.as_native()) } } /// Write a type that implements [`Serialize`] to the parcel. @@ -265,11 +254,15 @@ impl<'a> BorrowedParcel<'a> { f(&mut subparcel)?; } let end = self.get_data_position(); + // Safety: start is less than the current size of the parcel data + // buffer, because we just got it with `get_data_position`. unsafe { self.set_data_position(start)?; } assert!(end >= start); self.write(&(end - start))?; + // Safety: end is less than the current size of the parcel data + // buffer, because we just got it with `get_data_position`. unsafe { self.set_data_position(end)?; } @@ -278,20 +271,16 @@ impl<'a> BorrowedParcel<'a> { /// Returns the current position in the parcel data. pub fn get_data_position(&self) -> i32 { - unsafe { - // Safety: `BorrowedParcel` always contains a valid pointer to an - // `AParcel`, and this call is otherwise safe. - sys::AParcel_getDataPosition(self.as_native()) - } + // Safety: `BorrowedParcel` always contains a valid pointer to an + // `AParcel`, and this call is otherwise safe. + unsafe { sys::AParcel_getDataPosition(self.as_native()) } } /// Returns the total size of the parcel. pub fn get_data_size(&self) -> i32 { - unsafe { - // Safety: `BorrowedParcel` always contains a valid pointer to an - // `AParcel`, and this call is otherwise safe. - sys::AParcel_getDataSize(self.as_native()) - } + // Safety: `BorrowedParcel` always contains a valid pointer to an + // `AParcel`, and this call is otherwise safe. + unsafe { sys::AParcel_getDataSize(self.as_native()) } } /// Move the current read/write position in the parcel. @@ -304,7 +293,9 @@ impl<'a> BorrowedParcel<'a> { /// accesses are bounds checked, this call is still safe, but we can't rely /// on that. pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> { - status_result(sys::AParcel_setDataPosition(self.as_native(), pos)) + // Safety: `BorrowedParcel` always contains a valid pointer to an + // `AParcel`, and the caller guarantees that `pos` is within bounds. + status_result(unsafe { sys::AParcel_setDataPosition(self.as_native(), pos) }) } /// Append a subset of another parcel. @@ -317,10 +308,10 @@ impl<'a> BorrowedParcel<'a> { start: i32, size: i32, ) -> Result<()> { + // Safety: `Parcel::appendFrom` from C++ checks that `start` + // and `size` are in bounds, and returns an error otherwise. + // Both `self` and `other` always contain valid pointers. let status = unsafe { - // Safety: `Parcel::appendFrom` from C++ checks that `start` - // and `size` are in bounds, and returns an error otherwise. - // Both `self` and `other` always contain valid pointers. sys::AParcel_appendFrom(other.as_native(), self.as_native_mut(), start, size) }; status_result(status) @@ -418,7 +409,9 @@ impl Parcel { /// accesses are bounds checked, this call is still safe, but we can't rely /// on that. pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> { - self.borrowed_ref().set_data_position(pos) + // Safety: We have the same safety requirements as + // `BorrowedParcel::set_data_position`. + unsafe { self.borrowed_ref().set_data_position(pos) } } /// Append a subset of another parcel. @@ -504,7 +497,10 @@ impl<'a> BorrowedParcel<'a> { f(subparcel)?; // Advance the data position to the actual end, - // in case the closure read less data than was available + // in case the closure read less data than was available. + // + // Safety: end must be less than the current size of the parcel, because + // we checked above against `get_data_size`. unsafe { self.set_data_position(end)?; } @@ -649,17 +645,17 @@ impl Parcel { // Internal APIs impl<'a> BorrowedParcel<'a> { pub(crate) fn write_binder(&mut self, binder: Option<&SpIBinder>) -> Result<()> { + // Safety: `BorrowedParcel` always contains a valid pointer to an + // `AParcel`. `AsNative` for `Option will either return + // null or a valid pointer to an `AIBinder`, both of which are + // valid, safe inputs to `AParcel_writeStrongBinder`. + // + // This call does not take ownership of the binder. However, it does + // require a mutable pointer, which we cannot extract from an + // immutable reference, so we clone the binder, incrementing the + // refcount before the call. The refcount will be immediately + // decremented when this temporary is dropped. unsafe { - // Safety: `BorrowedParcel` always contains a valid pointer to an - // `AParcel`. `AsNative` for `Option will either return - // null or a valid pointer to an `AIBinder`, both of which are - // valid, safe inputs to `AParcel_writeStrongBinder`. - // - // This call does not take ownership of the binder. However, it does - // require a mutable pointer, which we cannot extract from an - // immutable reference, so we clone the binder, incrementing the - // refcount before the call. The refcount will be immediately - // decremented when this temporary is dropped. status_result(sys::AParcel_writeStrongBinder( self.as_native_mut(), binder.cloned().as_native_mut(), @@ -669,33 +665,28 @@ impl<'a> BorrowedParcel<'a> { pub(crate) fn read_binder(&self) -> Result> { let mut binder = ptr::null_mut(); - let status = unsafe { - // Safety: `BorrowedParcel` always contains a valid pointer to an - // `AParcel`. We pass a valid, mutable out pointer to the `binder` - // parameter. After this call, `binder` will be either null or a - // valid pointer to an `AIBinder` owned by the caller. - sys::AParcel_readStrongBinder(self.as_native(), &mut binder) - }; + // Safety: `BorrowedParcel` always contains a valid pointer to an + // `AParcel`. We pass a valid, mutable out pointer to the `binder` + // parameter. After this call, `binder` will be either null or a + // valid pointer to an `AIBinder` owned by the caller. + let status = unsafe { sys::AParcel_readStrongBinder(self.as_native(), &mut binder) }; status_result(status)?; - Ok(unsafe { - // Safety: `binder` is either null or a valid, owned pointer at this - // point, so can be safely passed to `SpIBinder::from_raw`. - SpIBinder::from_raw(binder) - }) + // Safety: `binder` is either null or a valid, owned pointer at this + // point, so can be safely passed to `SpIBinder::from_raw`. + Ok(unsafe { SpIBinder::from_raw(binder) }) } } impl Drop for Parcel { fn drop(&mut self) { // Run the C++ Parcel complete object destructor - unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. Since we own the parcel, we can safely delete it - // here. - sys::AParcel_delete(self.ptr.as_ptr()) - } + // + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. Since we own the parcel, we can safely delete it + // here. + unsafe { sys::AParcel_delete(self.ptr.as_ptr()) } } } diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs index 7fe37f3b68..5c688fa71b 100644 --- a/libs/binder/rust/src/parcel/file_descriptor.rs +++ b/libs/binder/rust/src/parcel/file_descriptor.rs @@ -73,14 +73,12 @@ impl Eq for ParcelFileDescriptor {} impl Serialize for ParcelFileDescriptor { fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> { let fd = self.0.as_raw_fd(); - let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. Likewise, `ParcelFileDescriptor` always contains a - // valid file, so we can borrow a valid file - // descriptor. `AParcel_writeParcelFileDescriptor` does NOT take - // ownership of the fd, so we need not duplicate it first. - sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), fd) - }; + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. Likewise, `ParcelFileDescriptor` always contains a + // valid file, so we can borrow a valid file + // descriptor. `AParcel_writeParcelFileDescriptor` does NOT take + // ownership of the fd, so we need not duplicate it first. + let status = unsafe { sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), fd) }; status_result(status) } } @@ -92,13 +90,12 @@ impl SerializeOption for ParcelFileDescriptor { if let Some(f) = this { f.serialize(parcel) } else { - let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. `AParcel_writeParcelFileDescriptor` accepts the - // value `-1` as the file descriptor to signify serializing a - // null file descriptor. - sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), -1i32) - }; + let status = + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. `AParcel_writeParcelFileDescriptor` accepts the + // value `-1` as the file descriptor to signify serializing a + // null file descriptor. + unsafe { sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), -1i32) }; status_result(status) } } @@ -107,25 +104,23 @@ impl SerializeOption for ParcelFileDescriptor { impl DeserializeOption for ParcelFileDescriptor { fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result> { let mut fd = -1i32; + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. We pass a valid mutable pointer to an i32, which + // `AParcel_readParcelFileDescriptor` assigns the valid file + // descriptor into, or `-1` if deserializing a null file + // descriptor. The read function passes ownership of the file + // descriptor to its caller if it was non-null, so we must take + // ownership of the file and ensure that it is eventually closed. unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. We pass a valid mutable pointer to an i32, which - // `AParcel_readParcelFileDescriptor` assigns the valid file - // descriptor into, or `-1` if deserializing a null file - // descriptor. The read function passes ownership of the file - // descriptor to its caller if it was non-null, so we must take - // ownership of the file and ensure that it is eventually closed. status_result(sys::AParcel_readParcelFileDescriptor(parcel.as_native(), &mut fd))?; } if fd < 0 { Ok(None) } else { - let file = unsafe { - // Safety: At this point, we know that the file descriptor was - // not -1, so must be a valid, owned file descriptor which we - // can safely turn into a `File`. - File::from_raw_fd(fd) - }; + // Safety: At this point, we know that the file descriptor was + // not -1, so must be a valid, owned file descriptor which we + // can safely turn into a `File`. + let file = unsafe { File::from_raw_fd(fd) }; Ok(Some(ParcelFileDescriptor::new(file))) } } diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs index 5d8c11cf94..be7350a7ec 100644 --- a/libs/binder/rust/src/parcel/parcelable.rs +++ b/libs/binder/rust/src/parcel/parcelable.rs @@ -102,8 +102,8 @@ pub trait Deserialize: Sized { pub trait SerializeArray: Serialize + Sized { /// Serialize an array of this type into the given parcel. fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> { + // Safety: Safe FFI, slice will always be a safe pointer to pass. let res = unsafe { - // Safety: Safe FFI, slice will always be a safe pointer to pass. sys::AParcel_writeParcelableArray( parcel.as_native_mut(), slice.as_ptr() as *const c_void, @@ -117,7 +117,9 @@ pub trait SerializeArray: Serialize + Sized { /// Callback to serialize an element of a generic parcelable array. /// -/// Safety: We are relying on binder_ndk to not overrun our slice. As long as it +/// # Safety +/// +/// We are relying on binder_ndk to not overrun our slice. As long as it /// doesn't provide an index larger than the length of the original slice in /// serialize_array, this operation is safe. The index provided is zero-based. unsafe extern "C" fn serialize_element( @@ -125,9 +127,14 @@ unsafe extern "C" fn serialize_element( array: *const c_void, index: usize, ) -> status_t { - let slice: &[T] = slice::from_raw_parts(array.cast(), index + 1); - - let mut parcel = match BorrowedParcel::from_raw(parcel) { + // Safety: The caller guarantees that `array` is a valid pointer of the + // appropriate type. + let slice: &[T] = unsafe { slice::from_raw_parts(array.cast(), index + 1) }; + + // Safety: The caller must give us a parcel pointer which is either null or + // valid at least for the duration of this function call. We don't keep the + // resulting value beyond the function. + let mut parcel = match unsafe { BorrowedParcel::from_raw(parcel) } { None => return StatusCode::UNEXPECTED_NULL as status_t, Some(p) => p, }; @@ -142,9 +149,9 @@ pub trait DeserializeArray: Deserialize { /// Deserialize an array of type from the given parcel. fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result>> { let mut vec: Option> = None; + // Safety: Safe FFI, vec is the correct opaque type expected by + // allocate_vec and deserialize_element. let res = unsafe { - // Safety: Safe FFI, vec is the correct opaque type expected by - // allocate_vec and deserialize_element. sys::AParcel_readParcelableArray( parcel.as_native(), &mut vec as *mut _ as *mut c_void, @@ -153,21 +160,21 @@ pub trait DeserializeArray: Deserialize { ) }; status_result(res)?; - let vec: Option> = unsafe { - // Safety: We are assuming that the NDK correctly initialized every - // element of the vector by now, so we know that all the - // UninitTypes are now properly initialized. We can transmute from - // Vec to Vec because T::UninitType has the same - // alignment and size as T, so the pointer to the vector allocation - // will be compatible. - mem::transmute(vec) - }; + // Safety: We are assuming that the NDK correctly initialized every + // element of the vector by now, so we know that all the + // UninitTypes are now properly initialized. We can transmute from + // Vec to Vec because T::UninitType has the same + // alignment and size as T, so the pointer to the vector allocation + // will be compatible. + let vec: Option> = unsafe { mem::transmute(vec) }; Ok(vec) } } /// Callback to deserialize a parcelable element. /// +/// # Safety +/// /// The opaque array data pointer must be a mutable pointer to an /// `Option>` with at least enough elements for `index` to be valid /// (zero-based). @@ -176,13 +183,18 @@ unsafe extern "C" fn deserialize_element( array: *mut c_void, index: usize, ) -> status_t { - let vec = &mut *(array as *mut Option>); + // Safety: The caller guarantees that `array` is a valid pointer of the + // appropriate type. + let vec = unsafe { &mut *(array as *mut Option>) }; let vec = match vec { Some(v) => v, None => return StatusCode::BAD_INDEX as status_t, }; - let parcel = match BorrowedParcel::from_raw(parcel as *mut _) { + // Safety: The caller must give us a parcel pointer which is either null or + // valid at least for the duration of this function call. We don't keep the + // resulting value beyond the function. + let parcel = match unsafe { BorrowedParcel::from_raw(parcel as *mut _) } { None => return StatusCode::UNEXPECTED_NULL as status_t, Some(p) => p, }; @@ -254,16 +266,21 @@ pub trait DeserializeOption: Deserialize { /// /// The opaque data pointer passed to the array read function must be a mutable /// pointer to an `Option>`. `buffer` will be assigned a mutable pointer -/// to the allocated vector data if this function returns true. +/// to the allocated vector data if this function returns true. `buffer` must be a valid pointer. unsafe extern "C" fn allocate_vec_with_buffer( data: *mut c_void, len: i32, buffer: *mut *mut T, ) -> bool { - let res = allocate_vec::(data, len); - let vec = &mut *(data as *mut Option>); + // Safety: We have the same safety requirements as `allocate_vec` for `data`. + let res = unsafe { allocate_vec::(data, len) }; + // Safety: The caller guarantees that `data` is a valid mutable pointer to the appropriate type. + let vec = unsafe { &mut *(data as *mut Option>) }; if let Some(new_vec) = vec { - *buffer = new_vec.as_mut_ptr() as *mut T; + // Safety: The caller guarantees that `buffer` is a valid pointer. + unsafe { + *buffer = new_vec.as_mut_ptr() as *mut T; + } } res } @@ -275,7 +292,8 @@ unsafe extern "C" fn allocate_vec_with_buffer( /// The opaque data pointer passed to the array read function must be a mutable /// pointer to an `Option>`. unsafe extern "C" fn allocate_vec(data: *mut c_void, len: i32) -> bool { - let vec = &mut *(data as *mut Option>); + // Safety: The caller guarantees that `data` is a valid mutable pointer to the appropriate type. + let vec = unsafe { &mut *(data as *mut Option>) }; if len < 0 { *vec = None; return true; @@ -286,7 +304,10 @@ unsafe extern "C" fn allocate_vec(data: *mut c_void, len: i32) - let mut new_vec: Vec = Vec::with_capacity(len as usize); new_vec.resize_with(len as usize, T::uninit); - ptr::write(vec, Some(new_vec)); + // Safety: The caller guarantees that vec is a valid mutable pointer to the appropriate type. + unsafe { + ptr::write(vec, Some(new_vec)); + } true } @@ -305,21 +326,21 @@ unsafe fn vec_assume_init(vec: Vec) -> Vec { // Assert at compile time that `T` and `T::UninitType` have the same size and alignment. let _ = T::ASSERT_UNINIT_SIZE_AND_ALIGNMENT; - // We can convert from Vec to Vec because T::UninitType - // has the same alignment and size as T, so the pointer to the vector - // allocation will be compatible. let mut vec = ManuallyDrop::new(vec); - Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity()) + // Safety: We can convert from Vec to Vec because + // T::UninitType has the same alignment and size as T, so the pointer to the + // vector allocation will be compatible. + unsafe { Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity()) } } macro_rules! impl_parcelable { {Serialize, $ty:ty, $write_fn:path} => { impl Serialize for $ty { fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`, and any `$ty` literal value is safe to pass to + // `$write_fn`. unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`, and any `$ty` literal value is safe to pass to - // `$write_fn`. status_result($write_fn(parcel.as_native_mut(), *self)) } } @@ -333,11 +354,11 @@ macro_rules! impl_parcelable { fn from_init(value: Self) -> Self::UninitType { value } fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { let mut val = Self::default(); + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. We pass a valid, mutable pointer to `val`, a + // literal of type `$ty`, and `$read_fn` will write the + // value read into `val` if successful unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. We pass a valid, mutable pointer to `val`, a - // literal of type `$ty`, and `$read_fn` will write the - // value read into `val` if successful status_result($read_fn(parcel.as_native(), &mut val))? }; Ok(val) @@ -348,13 +369,13 @@ macro_rules! impl_parcelable { {SerializeArray, $ty:ty, $write_array_fn:path} => { impl SerializeArray for $ty { fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` + // will be a valid pointer to an array of elements of type + // `$ty`. If the slice length is 0, `slice.as_ptr()` may be + // dangling, but this is safe since the pointer is not + // dereferenced if the length parameter is 0. let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` - // will be a valid pointer to an array of elements of type - // `$ty`. If the slice length is 0, `slice.as_ptr()` may be - // dangling, but this is safe since the pointer is not - // dereferenced if the length parameter is 0. $write_array_fn( parcel.as_native_mut(), slice.as_ptr(), @@ -373,11 +394,11 @@ macro_rules! impl_parcelable { impl DeserializeArray for $ty { fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result>> { let mut vec: Option> = None; + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. `allocate_vec` expects the opaque pointer to + // be of type `*mut Option>`, so `&mut vec` is + // correct for it. let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. `allocate_vec` expects the opaque pointer to - // be of type `*mut Option>`, so `&mut vec` is - // correct for it. $read_array_fn( parcel.as_native(), &mut vec as *mut _ as *mut c_void, @@ -385,11 +406,11 @@ macro_rules! impl_parcelable { ) }; status_result(status)?; + // Safety: We are assuming that the NDK correctly + // initialized every element of the vector by now, so we + // know that all the UninitTypes are now properly + // initialized. let vec: Option> = unsafe { - // Safety: We are assuming that the NDK correctly - // initialized every element of the vector by now, so we - // know that all the UninitTypes are now properly - // initialized. vec.map(|vec| vec_assume_init(vec)) }; Ok(vec) @@ -479,13 +500,13 @@ impl Deserialize for u8 { impl SerializeArray for u8 { fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a + // valid pointer to an array of elements of type `$ty`. If the slice + // length is 0, `slice.as_ptr()` may be dangling, but this is safe + // since the pointer is not dereferenced if the length parameter is + // 0. let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a - // valid pointer to an array of elements of type `$ty`. If the slice - // length is 0, `slice.as_ptr()` may be dangling, but this is safe - // since the pointer is not dereferenced if the length parameter is - // 0. sys::AParcel_writeByteArray( parcel.as_native_mut(), slice.as_ptr() as *const i8, @@ -518,13 +539,13 @@ impl Deserialize for i16 { impl SerializeArray for i16 { fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a + // valid pointer to an array of elements of type `$ty`. If the slice + // length is 0, `slice.as_ptr()` may be dangling, but this is safe + // since the pointer is not dereferenced if the length parameter is + // 0. let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a - // valid pointer to an array of elements of type `$ty`. If the slice - // length is 0, `slice.as_ptr()` may be dangling, but this is safe - // since the pointer is not dereferenced if the length parameter is - // 0. sys::AParcel_writeCharArray( parcel.as_native_mut(), slice.as_ptr() as *const u16, @@ -538,22 +559,22 @@ impl SerializeArray for i16 { impl SerializeOption for str { fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> { match this { + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. If the string pointer is null, + // `AParcel_writeString` requires that the length is -1 to + // indicate that we want to serialize a null string. None => unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. If the string pointer is null, - // `AParcel_writeString` requires that the length is -1 to - // indicate that we want to serialize a null string. status_result(sys::AParcel_writeString(parcel.as_native_mut(), ptr::null(), -1)) }, + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. `AParcel_writeString` assumes that we pass a utf-8 + // string pointer of `length` bytes, which is what str in Rust + // is. The docstring for `AParcel_writeString` says that the + // string input should be null-terminated, but it doesn't + // actually rely on that fact in the code. If this ever becomes + // necessary, we will need to null-terminate the str buffer + // before sending it. Some(s) => unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. `AParcel_writeString` assumes that we pass a utf-8 - // string pointer of `length` bytes, which is what str in Rust - // is. The docstring for `AParcel_writeString` says that the - // string input should be null-terminated, but it doesn't - // actually rely on that fact in the code. If this ever becomes - // necessary, we will need to null-terminate the str buffer - // before sending it. status_result(sys::AParcel_writeString( parcel.as_native_mut(), s.as_ptr() as *const c_char, @@ -597,11 +618,11 @@ impl Deserialize for Option { fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { let mut vec: Option> = None; + // Safety: `Parcel` always contains a valid pointer to an `AParcel`. + // `Option>` is equivalent to the expected `Option>` + // for `allocate_vec`, so `vec` is safe to pass as the opaque data + // pointer on platforms where char is signed. let status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an `AParcel`. - // `Option>` is equivalent to the expected `Option>` - // for `allocate_vec`, so `vec` is safe to pass as the opaque data - // pointer on platforms where char is signed. sys::AParcel_readString( parcel.as_native(), &mut vec as *mut _ as *mut c_void, @@ -751,11 +772,11 @@ impl Deserialize for Stability { impl Serialize for Status { fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> { + // Safety: `Parcel` always contains a valid pointer to an `AParcel` + // and `Status` always contains a valid pointer to an `AStatus`, so + // both parameters are valid and safe. This call does not take + // ownership of either of its parameters. unsafe { - // Safety: `Parcel` always contains a valid pointer to an `AParcel` - // and `Status` always contains a valid pointer to an `AStatus`, so - // both parameters are valid and safe. This call does not take - // ownership of either of its parameters. status_result(sys::AParcel_writeStatusHeader(parcel.as_native_mut(), self.as_native())) } } @@ -772,21 +793,18 @@ impl Deserialize for Status { fn deserialize(parcel: &BorrowedParcel<'_>) -> Result { let mut status_ptr = ptr::null_mut(); - let ret_status = unsafe { - // Safety: `Parcel` always contains a valid pointer to an - // `AParcel`. We pass a mutable out pointer which will be - // assigned a valid `AStatus` pointer if the function returns - // status OK. This function passes ownership of the status - // pointer to the caller, if it was assigned. - sys::AParcel_readStatusHeader(parcel.as_native(), &mut status_ptr) - }; + let ret_status = + // Safety: `Parcel` always contains a valid pointer to an + // `AParcel`. We pass a mutable out pointer which will be + // assigned a valid `AStatus` pointer if the function returns + // status OK. This function passes ownership of the status + // pointer to the caller, if it was assigned. + unsafe { sys::AParcel_readStatusHeader(parcel.as_native(), &mut status_ptr) }; status_result(ret_status)?; - Ok(unsafe { - // Safety: At this point, the return status of the read call was ok, - // so we know that `status_ptr` is a valid, owned pointer to an - // `AStatus`, from which we can safely construct a `Status` object. - Status::from_ptr(status_ptr) - }) + // Safety: At this point, the return status of the read call was ok, + // so we know that `status_ptr` is a valid, owned pointer to an + // `AStatus`, from which we can safely construct a `Status` object. + Ok(unsafe { Status::from_ptr(status_ptr) }) } } diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs index eb82fb7fd6..f90611361f 100644 --- a/libs/binder/rust/src/parcel/parcelable_holder.rs +++ b/libs/binder/rust/src/parcel/parcelable_holder.rs @@ -133,8 +133,8 @@ impl ParcelableHolder { } } ParcelableHolderData::Parcel(ref mut parcel) => { + // Safety: 0 should always be a valid position. unsafe { - // Safety: 0 should always be a valid position. parcel.set_data_position(0)?; } @@ -214,15 +214,15 @@ impl Parcelable for ParcelableHolder { parcelable.write_to_parcel(parcel)?; let end = parcel.get_data_position(); + // Safety: we got the position from `get_data_position`. unsafe { - // Safety: we got the position from `get_data_position`. parcel.set_data_position(length_start)?; } assert!(end >= data_start); parcel.write(&(end - data_start))?; + // Safety: we got the position from `get_data_position`. unsafe { - // Safety: we got the position from `get_data_position`. parcel.set_data_position(end)?; } @@ -260,11 +260,11 @@ impl Parcelable for ParcelableHolder { new_parcel.append_from(parcel, data_start, data_size)?; *self.data.get_mut().unwrap() = ParcelableHolderData::Parcel(new_parcel); + // Safety: `append_from` checks if `data_size` overflows + // `parcel` and returns `BAD_VALUE` if that happens. We also + // explicitly check for negative and zero `data_size` above, + // so `data_end` is guaranteed to be greater than `data_start`. unsafe { - // Safety: `append_from` checks if `data_size` overflows - // `parcel` and returns `BAD_VALUE` if that happens. We also - // explicitly check for negative and zero `data_size` above, - // so `data_end` is guaranteed to be greater than `data_start`. parcel.set_data_position(data_end)?; } diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs index 036f6b4f01..e55f48b989 100644 --- a/libs/binder/rust/src/proxy.rs +++ b/libs/binder/rust/src/proxy.rs @@ -49,14 +49,12 @@ impl fmt::Debug for SpIBinder { } } -/// # Safety -/// -/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe +/// Safety: An `SpIBinder` is an immutable handle to a C++ IBinder, which is +/// thread-safe. unsafe impl Send for SpIBinder {} -/// # Safety -/// -/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe +/// Safety: An `SpIBinder` is an immutable handle to a C++ IBinder, which is +/// thread-safe. unsafe impl Sync for SpIBinder {} impl SpIBinder { @@ -97,11 +95,9 @@ impl SpIBinder { /// Return true if this binder object is hosted in a different process than /// the current one. pub fn is_remote(&self) -> bool { - unsafe { - // Safety: `SpIBinder` guarantees that it always contains a valid - // `AIBinder` pointer. - sys::AIBinder_isRemote(self.as_native()) - } + // Safety: `SpIBinder` guarantees that it always contains a valid + // `AIBinder` pointer. + unsafe { sys::AIBinder_isRemote(self.as_native()) } } /// Try to convert this Binder object into a trait object for the given @@ -116,12 +112,12 @@ impl SpIBinder { /// Return the interface class of this binder object, if associated with /// one. pub fn get_class(&mut self) -> Option { + // Safety: `SpIBinder` guarantees that it always contains a valid + // `AIBinder` pointer. `AIBinder_getClass` returns either a null + // pointer or a valid pointer to an `AIBinder_Class`. After mapping + // null to None, we can safely construct an `InterfaceClass` if the + // pointer was non-null. unsafe { - // Safety: `SpIBinder` guarantees that it always contains a valid - // `AIBinder` pointer. `AIBinder_getClass` returns either a null - // pointer or a valid pointer to an `AIBinder_Class`. After mapping - // null to None, we can safely construct an `InterfaceClass` if the - // pointer was non-null. let class = sys::AIBinder_getClass(self.as_native_mut()); class.as_ref().map(|p| InterfaceClass::from_ptr(p)) } @@ -152,7 +148,8 @@ pub mod unstable_api { /// /// See `SpIBinder::from_raw`. pub unsafe fn new_spibinder(ptr: *mut sys::AIBinder) -> Option { - SpIBinder::from_raw(ptr) + // Safety: The caller makes the same guarantees as this requires. + unsafe { SpIBinder::from_raw(ptr) } } } @@ -171,30 +168,24 @@ pub trait AssociateClass { impl AssociateClass for SpIBinder { fn associate_class(&mut self, class: InterfaceClass) -> bool { - unsafe { - // Safety: `SpIBinder` guarantees that it always contains a valid - // `AIBinder` pointer. An `InterfaceClass` can always be converted - // into a valid `AIBinder_Class` pointer, so these parameters are - // always safe. - sys::AIBinder_associateClass(self.as_native_mut(), class.into()) - } + // Safety: `SpIBinder` guarantees that it always contains a valid + // `AIBinder` pointer. An `InterfaceClass` can always be converted + // into a valid `AIBinder_Class` pointer, so these parameters are + // always safe. + unsafe { sys::AIBinder_associateClass(self.as_native_mut(), class.into()) } } } impl Ord for SpIBinder { fn cmp(&self, other: &Self) -> Ordering { - let less_than = unsafe { - // Safety: SpIBinder always holds a valid `AIBinder` pointer, so - // this pointer is always safe to pass to `AIBinder_lt` (null is - // also safe to pass to this function, but we should never do that). - sys::AIBinder_lt(self.0.as_ptr(), other.0.as_ptr()) - }; - let greater_than = unsafe { - // Safety: SpIBinder always holds a valid `AIBinder` pointer, so - // this pointer is always safe to pass to `AIBinder_lt` (null is - // also safe to pass to this function, but we should never do that). - sys::AIBinder_lt(other.0.as_ptr(), self.0.as_ptr()) - }; + // Safety: SpIBinder always holds a valid `AIBinder` pointer, so this + // pointer is always safe to pass to `AIBinder_lt` (null is also safe to + // pass to this function, but we should never do that). + let less_than = unsafe { sys::AIBinder_lt(self.0.as_ptr(), other.0.as_ptr()) }; + // Safety: SpIBinder always holds a valid `AIBinder` pointer, so this + // pointer is always safe to pass to `AIBinder_lt` (null is also safe to + // pass to this function, but we should never do that). + let greater_than = unsafe { sys::AIBinder_lt(other.0.as_ptr(), self.0.as_ptr()) }; if !less_than && !greater_than { Ordering::Equal } else if less_than { @@ -221,10 +212,10 @@ impl Eq for SpIBinder {} impl Clone for SpIBinder { fn clone(&self) -> Self { + // Safety: Cloning a strong reference must increment the reference + // count. We are guaranteed by the `SpIBinder` constructor + // invariants that `self.0` is always a valid `AIBinder` pointer. unsafe { - // Safety: Cloning a strong reference must increment the reference - // count. We are guaranteed by the `SpIBinder` constructor - // invariants that `self.0` is always a valid `AIBinder` pointer. sys::AIBinder_incStrong(self.0.as_ptr()); } Self(self.0) @@ -235,9 +226,9 @@ impl Drop for SpIBinder { // We hold a strong reference to the IBinder in SpIBinder and need to give up // this reference on drop. fn drop(&mut self) { + // Safety: SpIBinder always holds a valid `AIBinder` pointer, so we + // know this pointer is safe to pass to `AIBinder_decStrong` here. unsafe { - // Safety: SpIBinder always holds a valid `AIBinder` pointer, so we - // know this pointer is safe to pass to `AIBinder_decStrong` here. sys::AIBinder_decStrong(self.as_native_mut()); } } @@ -246,26 +237,24 @@ impl Drop for SpIBinder { impl> IBinderInternal for T { fn prepare_transact(&self) -> Result { let mut input = ptr::null_mut(); + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. It is safe to cast from an + // immutable pointer to a mutable pointer here, because + // `AIBinder_prepareTransaction` only calls immutable `AIBinder` + // methods but the parameter is unfortunately not marked as const. + // + // After the call, input will be either a valid, owned `AParcel` + // pointer, or null. let status = unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. It is safe to cast from an - // immutable pointer to a mutable pointer here, because - // `AIBinder_prepareTransaction` only calls immutable `AIBinder` - // methods but the parameter is unfortunately not marked as const. - // - // After the call, input will be either a valid, owned `AParcel` - // pointer, or null. sys::AIBinder_prepareTransaction(self.as_native() as *mut sys::AIBinder, &mut input) }; status_result(status)?; - unsafe { - // Safety: At this point, `input` is either a valid, owned `AParcel` - // pointer, or null. `OwnedParcel::from_raw` safely handles both cases, - // taking ownership of the parcel. - Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL) - } + // Safety: At this point, `input` is either a valid, owned `AParcel` + // pointer, or null. `OwnedParcel::from_raw` safely handles both cases, + // taking ownership of the parcel. + unsafe { Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL) } } fn submit_transact( @@ -275,23 +264,23 @@ impl> IBinderInternal for T { flags: TransactionFlags, ) -> Result { let mut reply = ptr::null_mut(); + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. Although `IBinder::transact` is + // not a const method, it is still safe to cast our immutable + // pointer to mutable for the call. First, `IBinder::transact` is + // thread-safe, so concurrency is not an issue. The only way that + // `transact` can affect any visible, mutable state in the current + // process is by calling `onTransact` for a local service. However, + // in order for transactions to be thread-safe, this method must + // dynamically lock its data before modifying it. We enforce this + // property in Rust by requiring `Sync` for remotable objects and + // only providing `on_transact` with an immutable reference to + // `self`. + // + // This call takes ownership of the `data` parcel pointer, and + // passes ownership of the `reply` out parameter to its caller. It + // does not affect ownership of the `binder` parameter. let status = unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. Although `IBinder::transact` is - // not a const method, it is still safe to cast our immutable - // pointer to mutable for the call. First, `IBinder::transact` is - // thread-safe, so concurrency is not an issue. The only way that - // `transact` can affect any visible, mutable state in the current - // process is by calling `onTransact` for a local service. However, - // in order for transactions to be thread-safe, this method must - // dynamically lock its data before modifying it. We enforce this - // property in Rust by requiring `Sync` for remotable objects and - // only providing `on_transact` with an immutable reference to - // `self`. - // - // This call takes ownership of the `data` parcel pointer, and - // passes ownership of the `reply` out parameter to its caller. It - // does not affect ownership of the `binder` parameter. sys::AIBinder_transact( self.as_native() as *mut sys::AIBinder, code, @@ -302,45 +291,45 @@ impl> IBinderInternal for T { }; status_result(status)?; - unsafe { - // Safety: `reply` is either a valid `AParcel` pointer or null - // after the call to `AIBinder_transact` above, so we can - // construct a `Parcel` out of it. `AIBinder_transact` passes - // ownership of the `reply` parcel to Rust, so we need to - // construct an owned variant. - Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL) - } + // Safety: `reply` is either a valid `AParcel` pointer or null + // after the call to `AIBinder_transact` above, so we can + // construct a `Parcel` out of it. `AIBinder_transact` passes + // ownership of the `reply` parcel to Rust, so we need to + // construct an owned variant. + unsafe { Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL) } } fn is_binder_alive(&self) -> bool { - unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. - // - // This call does not affect ownership of its pointer parameter. - sys::AIBinder_isAlive(self.as_native()) - } + // Safety: `SpIBinder` guarantees that `self` always contains a valid + // pointer to an `AIBinder`. + // + // This call does not affect ownership of its pointer parameter. + unsafe { sys::AIBinder_isAlive(self.as_native()) } } #[cfg(not(android_vndk))] fn set_requesting_sid(&mut self, enable: bool) { + // Safety: `SpIBinder` guarantees that `self` always contains a valid + // pointer to an `AIBinder`. + // + // This call does not affect ownership of its pointer parameter. unsafe { sys::AIBinder_setRequestingSid(self.as_native_mut(), enable) }; } fn dump(&mut self, fp: &F, args: &[&str]) -> Result<()> { let args: Vec<_> = args.iter().map(|a| CString::new(*a).unwrap()).collect(); let mut arg_ptrs: Vec<_> = args.iter().map(|a| a.as_ptr()).collect(); + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. `AsRawFd` guarantees that the + // file descriptor parameter is always be a valid open file. The + // `args` pointer parameter is a valid pointer to an array of C + // strings that will outlive the call since `args` lives for the + // whole function scope. + // + // This call does not affect ownership of its binder pointer + // parameter and does not take ownership of the file or args array + // parameters. let status = unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. `AsRawFd` guarantees that the - // file descriptor parameter is always be a valid open file. The - // `args` pointer parameter is a valid pointer to an array of C - // strings that will outlive the call since `args` lives for the - // whole function scope. - // - // This call does not affect ownership of its binder pointer - // parameter and does not take ownership of the file or args array - // parameters. sys::AIBinder_dump( self.as_native_mut(), fp.as_raw_fd(), @@ -353,22 +342,18 @@ impl> IBinderInternal for T { fn get_extension(&mut self) -> Result> { let mut out = ptr::null_mut(); - let status = unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. After this call, the `out` - // parameter will be either null, or a valid pointer to an - // `AIBinder`. - // - // This call passes ownership of the out pointer to its caller - // (assuming it is set to a non-null value). - sys::AIBinder_getExtension(self.as_native_mut(), &mut out) - }; - let ibinder = unsafe { - // Safety: The call above guarantees that `out` is either null or a - // valid, owned pointer to an `AIBinder`, both of which are safe to - // pass to `SpIBinder::from_raw`. - SpIBinder::from_raw(out) - }; + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. After this call, the `out` + // parameter will be either null, or a valid pointer to an + // `AIBinder`. + // + // This call passes ownership of the out pointer to its caller + // (assuming it is set to a non-null value). + let status = unsafe { sys::AIBinder_getExtension(self.as_native_mut(), &mut out) }; + // Safety: The call above guarantees that `out` is either null or a + // valid, owned pointer to an `AIBinder`, both of which are safe to + // pass to `SpIBinder::from_raw`. + let ibinder = unsafe { SpIBinder::from_raw(out) }; status_result(status)?; Ok(ibinder) @@ -377,17 +362,17 @@ impl> IBinderInternal for T { impl> IBinder for T { fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> { + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. `recipient` can always be + // converted into a valid pointer to an + // `AIBinder_DeathRecipient`. + // + // The cookie is also the correct pointer, and by calling new_cookie, + // we have created a new ref-count to the cookie, which linkToDeath + // takes ownership of. Once the DeathRecipient is unlinked for any + // reason (including if this call fails), the onUnlinked callback + // will consume that ref-count. status_result(unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. `recipient` can always be - // converted into a valid pointer to an - // `AIBinder_DeathRecipient`. - // - // The cookie is also the correct pointer, and by calling new_cookie, - // we have created a new ref-count to the cookie, which linkToDeath - // takes ownership of. Once the DeathRecipient is unlinked for any - // reason (including if this call fails), the onUnlinked callback - // will consume that ref-count. sys::AIBinder_linkToDeath( self.as_native_mut(), recipient.as_native_mut(), @@ -397,13 +382,13 @@ impl> IBinder for T { } fn unlink_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> { + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. `recipient` can always be + // converted into a valid pointer to an + // `AIBinder_DeathRecipient`. Any value is safe to pass as the + // cookie, although we depend on this value being set by + // `get_cookie` when the death recipient callback is called. status_result(unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. `recipient` can always be - // converted into a valid pointer to an - // `AIBinder_DeathRecipient`. Any value is safe to pass as the - // cookie, although we depend on this value being set by - // `get_cookie` when the death recipient callback is called. sys::AIBinder_unlinkToDeath( self.as_native_mut(), recipient.as_native_mut(), @@ -413,13 +398,11 @@ impl> IBinder for T { } fn ping_binder(&mut self) -> Result<()> { - let status = unsafe { - // Safety: `SpIBinder` guarantees that `self` always contains a - // valid pointer to an `AIBinder`. - // - // This call does not affect ownership of its pointer parameter. - sys::AIBinder_ping(self.as_native_mut()) - }; + // Safety: `SpIBinder` guarantees that `self` always contains a + // valid pointer to an `AIBinder`. + // + // This call does not affect ownership of its pointer parameter. + let status = unsafe { sys::AIBinder_ping(self.as_native_mut()) }; status_result(status) } } @@ -472,35 +455,31 @@ impl fmt::Debug for WpIBinder { } } -/// # Safety -/// -/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe. +/// Safety: A `WpIBinder` is an immutable handle to a C++ IBinder, which is +/// thread-safe. unsafe impl Send for WpIBinder {} -/// # Safety -/// -/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe. +/// Safety: A `WpIBinder` is an immutable handle to a C++ IBinder, which is +/// thread-safe. unsafe impl Sync for WpIBinder {} impl WpIBinder { /// Create a new weak reference from an object that can be converted into a /// raw `AIBinder` pointer. fn new>(binder: &mut B) -> WpIBinder { - let ptr = unsafe { - // Safety: `SpIBinder` guarantees that `binder` always contains a - // valid pointer to an `AIBinder`. - sys::AIBinder_Weak_new(binder.as_native_mut()) - }; + // Safety: `SpIBinder` guarantees that `binder` always contains a valid + // pointer to an `AIBinder`. + let ptr = unsafe { sys::AIBinder_Weak_new(binder.as_native_mut()) }; Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_new")) } /// Promote this weak reference to a strong reference to the binder object. pub fn promote(&self) -> Option { + // Safety: `WpIBinder` always contains a valid weak reference, so we can + // pass this pointer to `AIBinder_Weak_promote`. Returns either null or + // an AIBinder owned by the caller, both of which are valid to pass to + // `SpIBinder::from_raw`. unsafe { - // Safety: `WpIBinder` always contains a valid weak reference, so we - // can pass this pointer to `AIBinder_Weak_promote`. Returns either - // null or an AIBinder owned by the caller, both of which are valid - // to pass to `SpIBinder::from_raw`. let ptr = sys::AIBinder_Weak_promote(self.0.as_ptr()); SpIBinder::from_raw(ptr) } @@ -509,35 +488,27 @@ impl WpIBinder { impl Clone for WpIBinder { fn clone(&self) -> Self { - let ptr = unsafe { - // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, - // so this pointer is always safe to pass to `AIBinder_Weak_clone` - // (although null is also a safe value to pass to this API). - // - // We get ownership of the returned pointer, so can construct a new - // WpIBinder object from it. - sys::AIBinder_Weak_clone(self.0.as_ptr()) - }; + // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so + // this pointer is always safe to pass to `AIBinder_Weak_clone` + // (although null is also a safe value to pass to this API). + // + // We get ownership of the returned pointer, so can construct a new + // WpIBinder object from it. + let ptr = unsafe { sys::AIBinder_Weak_clone(self.0.as_ptr()) }; Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_clone")) } } impl Ord for WpIBinder { fn cmp(&self, other: &Self) -> Ordering { - let less_than = unsafe { - // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, - // so this pointer is always safe to pass to `AIBinder_Weak_lt` - // (null is also safe to pass to this function, but we should never - // do that). - sys::AIBinder_Weak_lt(self.0.as_ptr(), other.0.as_ptr()) - }; - let greater_than = unsafe { - // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, - // so this pointer is always safe to pass to `AIBinder_Weak_lt` - // (null is also safe to pass to this function, but we should never - // do that). - sys::AIBinder_Weak_lt(other.0.as_ptr(), self.0.as_ptr()) - }; + // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so + // this pointer is always safe to pass to `AIBinder_Weak_lt` (null is + // also safe to pass to this function, but we should never do that). + let less_than = unsafe { sys::AIBinder_Weak_lt(self.0.as_ptr(), other.0.as_ptr()) }; + // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so + // this pointer is always safe to pass to `AIBinder_Weak_lt` (null is + // also safe to pass to this function, but we should never do that). + let greater_than = unsafe { sys::AIBinder_Weak_lt(other.0.as_ptr(), self.0.as_ptr()) }; if !less_than && !greater_than { Ordering::Equal } else if less_than { @@ -564,9 +535,9 @@ impl Eq for WpIBinder {} impl Drop for WpIBinder { fn drop(&mut self) { + // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we + // know this pointer is safe to pass to `AIBinder_Weak_delete` here. unsafe { - // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we - // know this pointer is safe to pass to `AIBinder_Weak_delete` here. sys::AIBinder_Weak_delete(self.0.as_ptr()); } } @@ -592,17 +563,13 @@ struct DeathRecipientVtable { cookie_decr_refcount: unsafe extern "C" fn(*mut c_void), } -/// # Safety -/// -/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer -/// to a `Fn` which is `Sync` and `Send` (the cookie field). As +/// Safety: A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and +/// a pointer to a `Fn` which is `Sync` and `Send` (the cookie field). As /// `AIBinder_DeathRecipient` is threadsafe, this structure is too. unsafe impl Send for DeathRecipient {} -/// # Safety -/// -/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer -/// to a `Fn` which is `Sync` and `Send` (the cookie field). As +/// Safety: A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and +/// a pointer to a `Fn` which is `Sync` and `Send` (the cookie field). As /// `AIBinder_DeathRecipient` is threadsafe, this structure is too. unsafe impl Sync for DeathRecipient {} @@ -614,19 +581,17 @@ impl DeathRecipient { F: Fn() + Send + Sync + 'static, { let callback: *const F = Arc::into_raw(Arc::new(callback)); - let recipient = unsafe { - // Safety: The function pointer is a valid death recipient callback. - // - // This call returns an owned `AIBinder_DeathRecipient` pointer - // which must be destroyed via `AIBinder_DeathRecipient_delete` when - // no longer needed. - sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::)) - }; + // Safety: The function pointer is a valid death recipient callback. + // + // This call returns an owned `AIBinder_DeathRecipient` pointer which + // must be destroyed via `AIBinder_DeathRecipient_delete` when no longer + // needed. + let recipient = unsafe { sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::)) }; + // Safety: The function pointer is a valid onUnlinked callback. + // + // All uses of linkToDeath in this file correctly increment the + // ref-count that this onUnlinked callback will decrement. unsafe { - // Safety: The function pointer is a valid onUnlinked callback. - // - // All uses of linkToDeath in this file correctly increment the - // ref-count that this onUnlinked callback will decrement. sys::AIBinder_DeathRecipient_setOnUnlinked( recipient, Some(Self::cookie_decr_refcount::), @@ -648,7 +613,12 @@ impl DeathRecipient { /// /// The caller must handle the returned ref-count correctly. unsafe fn new_cookie(&self) -> *mut c_void { - (self.vtable.cookie_incr_refcount)(self.cookie); + // Safety: `cookie_incr_refcount` points to + // `Self::cookie_incr_refcount`, and `self.cookie` is the cookie for an + // Arc. + unsafe { + (self.vtable.cookie_incr_refcount)(self.cookie); + } // Return a raw pointer with ownership of a ref-count self.cookie @@ -673,7 +643,8 @@ impl DeathRecipient { where F: Fn() + Send + Sync + 'static, { - let callback = (cookie as *const F).as_ref().unwrap(); + // Safety: The caller promises that `cookie` is for an Arc. + let callback = unsafe { (cookie as *const F).as_ref().unwrap() }; callback(); } @@ -688,7 +659,8 @@ impl DeathRecipient { where F: Fn() + Send + Sync + 'static, { - drop(Arc::from_raw(cookie as *const F)); + // Safety: The caller promises that `cookie` is for an Arc. + drop(unsafe { Arc::from_raw(cookie as *const F) }); } /// Callback that increments the ref-count. @@ -701,15 +673,14 @@ impl DeathRecipient { where F: Fn() + Send + Sync + 'static, { - let arc = mem::ManuallyDrop::new(Arc::from_raw(cookie as *const F)); + // Safety: The caller promises that `cookie` is for an Arc. + let arc = mem::ManuallyDrop::new(unsafe { Arc::from_raw(cookie as *const F) }); mem::forget(Arc::clone(&arc)); } } -/// # Safety -/// -/// A `DeathRecipient` is always constructed with a valid raw pointer to an -/// `AIBinder_DeathRecipient`, so it is always type-safe to extract this +/// Safety: A `DeathRecipient` is always constructed with a valid raw pointer to +/// an `AIBinder_DeathRecipient`, so it is always type-safe to extract this /// pointer. unsafe impl AsNative for DeathRecipient { fn as_native(&self) -> *const sys::AIBinder_DeathRecipient { @@ -723,18 +694,19 @@ unsafe impl AsNative for DeathRecipient { impl Drop for DeathRecipient { fn drop(&mut self) { + // Safety: `self.recipient` is always a valid, owned + // `AIBinder_DeathRecipient` pointer returned by + // `AIBinder_DeathRecipient_new` when `self` was created. This delete + // method can only be called once when `self` is dropped. unsafe { - // Safety: `self.recipient` is always a valid, owned - // `AIBinder_DeathRecipient` pointer returned by - // `AIBinder_DeathRecipient_new` when `self` was created. This - // delete method can only be called once when `self` is dropped. sys::AIBinder_DeathRecipient_delete(self.recipient); + } - // Safety: We own a ref-count to the cookie, and so does every - // linked binder. This call gives up our ref-count. The linked - // binders should already have given up their ref-count, or should - // do so shortly. - (self.vtable.cookie_decr_refcount)(self.cookie) + // Safety: We own a ref-count to the cookie, and so does every linked + // binder. This call gives up our ref-count. The linked binders should + // already have given up their ref-count, or should do so shortly. + unsafe { + (self.vtable.cookie_decr_refcount)(self.cookie); } } } @@ -754,11 +726,9 @@ pub trait Proxy: Sized + Interface { fn from_binder(binder: SpIBinder) -> Result; } -/// # Safety -/// -/// This is a convenience method that wraps `AsNative` for `SpIBinder` to allow -/// invocation of `IBinder` methods directly from `Interface` objects. It shares -/// the same safety as the implementation for `SpIBinder`. +/// Safety: This is a convenience method that wraps `AsNative` for `SpIBinder` +/// to allow invocation of `IBinder` methods directly from `Interface` objects. +/// It shares the same safety as the implementation for `SpIBinder`. unsafe impl AsNative for T { fn as_native(&self) -> *const sys::AIBinder { self.as_binder().as_native() @@ -773,24 +743,20 @@ unsafe impl AsNative for T { /// exist. pub fn get_service(name: &str) -> Option { let name = CString::new(name).ok()?; - unsafe { - // Safety: `AServiceManager_getService` returns either a null pointer or - // a valid pointer to an owned `AIBinder`. Either of these values is - // safe to pass to `SpIBinder::from_raw`. - SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr())) - } + // Safety: `AServiceManager_getService` returns either a null pointer or a + // valid pointer to an owned `AIBinder`. Either of these values is safe to + // pass to `SpIBinder::from_raw`. + unsafe { SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr())) } } /// Retrieve an existing service, or start it if it is configured as a dynamic /// service and isn't yet started. pub fn wait_for_service(name: &str) -> Option { let name = CString::new(name).ok()?; - unsafe { - // Safety: `AServiceManager_waitforService` returns either a null - // pointer or a valid pointer to an owned `AIBinder`. Either of these - // values is safe to pass to `SpIBinder::from_raw`. - SpIBinder::from_raw(sys::AServiceManager_waitForService(name.as_ptr())) - } + // Safety: `AServiceManager_waitforService` returns either a null pointer or + // a valid pointer to an owned `AIBinder`. Either of these values is safe to + // pass to `SpIBinder::from_raw`. + unsafe { SpIBinder::from_raw(sys::AServiceManager_waitForService(name.as_ptr())) } } /// Retrieve an existing service for a particular interface, blocking for a few @@ -809,12 +775,10 @@ pub fn wait_for_interface(name: &str) -> Result Result { let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?; - unsafe { - // Safety: `interface` is a valid null-terminated C-style string and is - // only borrowed for the lifetime of the call. The `interface` local - // outlives this call as it lives for the function scope. - Ok(sys::AServiceManager_isDeclared(interface.as_ptr())) - } + // Safety: `interface` is a valid null-terminated C-style string and is only + // borrowed for the lifetime of the call. The `interface` local outlives + // this call as it lives for the function scope. + unsafe { Ok(sys::AServiceManager_isDeclared(interface.as_ptr())) } } /// Retrieve all declared instances for a particular interface @@ -827,11 +791,13 @@ pub fn get_declared_instances(interface: &str) -> Result> { // CString, and outlives this callback. The null handling here is just // to avoid the possibility of unwinding across C code if this crate is // ever compiled with panic=unwind. - if let Some(instances) = opaque.cast::>().as_mut() { + if let Some(instances) = unsafe { opaque.cast::>().as_mut() } { // Safety: instance is a valid null-terminated C string with a // lifetime at least as long as this function, and we immediately // copy it into an owned CString. - instances.push(CStr::from_ptr(instance).to_owned()); + unsafe { + instances.push(CStr::from_ptr(instance).to_owned()); + } } else { eprintln!("Opaque pointer was null in get_declared_instances callback!"); } @@ -839,10 +805,10 @@ pub fn get_declared_instances(interface: &str) -> Result> { let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?; let mut instances: Vec = vec![]; + // Safety: `interface` and `instances` are borrowed for the length of this + // call and both outlive the call. `interface` is guaranteed to be a valid + // null-terminated C-style string. unsafe { - // Safety: `interface` and `instances` are borrowed for the length of - // this call and both outlive the call. `interface` is guaranteed to be - // a valid null-terminated C-style string. sys::AServiceManager_forEachDeclaredInstance( interface.as_ptr(), &mut instances as *mut _ as *mut c_void, @@ -860,10 +826,8 @@ pub fn get_declared_instances(interface: &str) -> Result> { }) } -/// # Safety -/// -/// `SpIBinder` guarantees that `binder` always contains a valid pointer to an -/// `AIBinder`, so we can trivially extract this pointer here. +/// Safety: `SpIBinder` guarantees that `binder` always contains a valid pointer +/// to an `AIBinder`, so we can trivially extract this pointer here. unsafe impl AsNative for SpIBinder { fn as_native(&self) -> *const sys::AIBinder { self.0.as_ptr() diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs index 4886c5fe86..a3a2562eb1 100644 --- a/libs/binder/rust/src/state.rs +++ b/libs/binder/rust/src/state.rs @@ -35,8 +35,8 @@ impl ProcessState { /// not work: the callbacks will be queued but never called as there is no /// thread to call them on. pub fn start_thread_pool() { + // Safety: Safe FFI unsafe { - // Safety: Safe FFI sys::ABinderProcess_startThreadPool(); } } @@ -48,8 +48,8 @@ impl ProcessState { /// called, this is 15. If it is called additional times, the thread pool /// size can only be increased. pub fn set_thread_pool_max_thread_count(num_threads: u32) { + // Safety: Safe FFI unsafe { - // Safety: Safe FFI sys::ABinderProcess_setThreadPoolMaxThreadCount(num_threads); } } @@ -62,8 +62,8 @@ impl ProcessState { /// [`set_thread_pool_max_thread_count`](Self::set_thread_pool_max_thread_count) /// and [`start_thread_pool`](Self::start_thread_pool). pub fn join_thread_pool() { + // Safety: Safe FFI unsafe { - // Safety: Safe FFI sys::ABinderProcess_joinThreadPool(); } } @@ -86,10 +86,8 @@ impl ThreadState { /// \return calling uid or the current process's UID if this thread isn't /// processing a transaction. pub fn get_calling_uid() -> uid_t { - unsafe { - // Safety: Safe FFI - sys::AIBinder_getCallingUid() - } + // Safety: Safe FFI + unsafe { sys::AIBinder_getCallingUid() } } /// This returns the calling PID assuming that this thread is called from a @@ -111,10 +109,8 @@ impl ThreadState { /// If the transaction being processed is a oneway transaction, then this /// method will return 0. pub fn get_calling_pid() -> pid_t { - unsafe { - // Safety: Safe FFI - sys::AIBinder_getCallingPid() - } + // Safety: Safe FFI + unsafe { sys::AIBinder_getCallingPid() } } /// Determine whether the current thread is currently executing an incoming transaction. @@ -122,10 +118,8 @@ impl ThreadState { /// \return true if the current thread is currently executing an incoming transaction, and false /// otherwise. pub fn is_handling_transaction() -> bool { - unsafe { - // Safety: Safe FFI - sys::AIBinder_isHandlingTransaction() - } + // Safety: Safe FFI + unsafe { sys::AIBinder_isHandlingTransaction() } } /// This function makes the client's security context available to the -- GitLab From f83c6934fb16f4fb31423df29a787480a35d6e24 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 7 Jul 2023 17:48:10 -0700 Subject: [PATCH 0266/1187] Increase timeouts for ANR tests This should help reduce the flake rate. The flakes are not reproducible on host locally, but are flaking remotely, with an overall flake rate of ~ 1% or less. In the future, we can consider refactoring the dispatcher by providing it a clock source that we can control, in order to make these faster and completely remove flakes. Bug: 282837934 Test: atest inputflinger_tests Change-Id: I12fdc3ee1a823ede0e90256c54833d8d52aed636 --- .../tests/InputDispatcher_test.cpp | 57 +++++++++---------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 6a6312ec78..19167287a8 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -6606,11 +6606,11 @@ class InputDispatcherSingleWindowAnr : public InputDispatcherTest { InputDispatcherTest::SetUp(); mApplication = std::make_shared(); - mApplication->setDispatchingTimeout(20ms); + mApplication->setDispatchingTimeout(100ms); mWindow = sp::make(mApplication, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT); mWindow->setFrame(Rect(0, 0, 30, 30)); - mWindow->setDispatchingTimeout(30ms); + mWindow->setDispatchingTimeout(100ms); mWindow->setFocusable(true); // Set focused application. @@ -6676,7 +6676,7 @@ TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) { InputEventInjectionResult result = injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE, /*injectionTimeout=*/10ms, + InputEventInjectionSync::NONE, /*injectionTimeout=*/50ms, /*allowKeyRepeat=*/false); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); // Key will not go to window because we have no focused window. @@ -6740,7 +6740,7 @@ TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) { // injection times out (instead of failing). const InputEventInjectionResult result = injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, /*allowKeyRepeat=*/false); + InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication); @@ -6791,7 +6791,7 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) // injection times out (instead of failing). const InputEventInjectionResult result = injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::WAIT_FOR_RESULT, 10ms, /*allowKeyRepeat=*/false); + InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); const std::chrono::duration appTimeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); @@ -6815,7 +6815,7 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) { // Once a focused event arrives, we get an ANR for this application const InputEventInjectionResult result = injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::WAIT_FOR_RESULT, 10ms); + InputEventInjectionSync::WAIT_FOR_RESULT, 50ms); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); @@ -7031,7 +7031,7 @@ TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) { InputEventInjectionResult result = injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::WAIT_FOR_RESULT, 10ms); + InputEventInjectionSync::WAIT_FOR_RESULT, 50ms); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); // Key will not be sent to the window, yet, because the window is still processing events // and the key remains pending, waiting for the touch events to be processed @@ -7136,7 +7136,7 @@ class InputDispatcherMultiWindowAnr : public InputDispatcherTest { InputDispatcherTest::SetUp(); mApplication = std::make_shared(); - mApplication->setDispatchingTimeout(10ms); + mApplication->setDispatchingTimeout(100ms); mUnfocusedWindow = sp::make(mApplication, mDispatcher, "Unfocused", ADISPLAY_ID_DEFAULT); mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30)); @@ -7145,7 +7145,7 @@ class InputDispatcherMultiWindowAnr : public InputDispatcherTest { mFocusedWindow = sp::make(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT); - mFocusedWindow->setDispatchingTimeout(30ms); + mFocusedWindow->setDispatchingTimeout(100ms); mFocusedWindow->setFrame(Rect(50, 50, 100, 100)); // Set focused application. @@ -7231,20 +7231,21 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) { // But we should receive ANR for both. TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout) { // Set the timeout for unfocused window to match the focused window - mUnfocusedWindow->setDispatchingTimeout(10ms); + mUnfocusedWindow->setDispatchingTimeout( + mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}}); tapOnFocusedWindow(); // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window - sp anrConnectionToken1, anrConnectionToken2; - ASSERT_NO_FATAL_FAILURE(anrConnectionToken1 = mFakePolicy->getUnresponsiveWindowToken(10ms)); - ASSERT_NO_FATAL_FAILURE(anrConnectionToken2 = mFakePolicy->getUnresponsiveWindowToken(0ms)); - // We don't know which window will ANR first. But both of them should happen eventually. - ASSERT_TRUE(mFocusedWindow->getToken() == anrConnectionToken1 || - mFocusedWindow->getToken() == anrConnectionToken2); - ASSERT_TRUE(mUnfocusedWindow->getToken() == anrConnectionToken1 || - mUnfocusedWindow->getToken() == anrConnectionToken2); + std::array, 2> anrConnectionTokens = {mFakePolicy->getUnresponsiveWindowToken( + mFocusedWindow->getDispatchingTimeout( + DISPATCHING_TIMEOUT)), + mFakePolicy->getUnresponsiveWindowToken(0ms)}; + + ASSERT_THAT(anrConnectionTokens, + ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()), + testing::Eq(mUnfocusedWindow->getToken()))); ASSERT_TRUE(mDispatcher->waitForIdle()); mFakePolicy->assertNotifyAnrWasNotCalled(); @@ -7253,15 +7254,13 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout mFocusedWindow->consumeMotionUp(); mUnfocusedWindow->consumeMotionOutside(); - sp responsiveToken1, responsiveToken2; - ASSERT_NO_FATAL_FAILURE(responsiveToken1 = mFakePolicy->getResponsiveWindowToken()); - ASSERT_NO_FATAL_FAILURE(responsiveToken2 = mFakePolicy->getResponsiveWindowToken()); + std::array, 2> responsiveTokens = {mFakePolicy->getResponsiveWindowToken(), + mFakePolicy->getResponsiveWindowToken()}; // Both applications should be marked as responsive, in any order - ASSERT_TRUE(mFocusedWindow->getToken() == responsiveToken1 || - mFocusedWindow->getToken() == responsiveToken2); - ASSERT_TRUE(mUnfocusedWindow->getToken() == responsiveToken1 || - mUnfocusedWindow->getToken() == responsiveToken2); + ASSERT_THAT(responsiveTokens, + ::testing::UnorderedElementsAre(testing::Eq(mFocusedWindow->getToken()), + testing::Eq(mUnfocusedWindow->getToken()))); mFakePolicy->assertNotifyAnrWasNotCalled(); } @@ -7361,7 +7360,7 @@ TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) { InputEventInjectionResult result = injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE, /*injectionTimeout=*/10ms); + InputEventInjectionSync::NONE, /*injectionTimeout=*/50ms); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); // Key will not be sent to the window, yet, because the window is still processing events // and the key remains pending, waiting for the touch events to be processed @@ -7449,7 +7448,7 @@ TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) { TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) { std::shared_ptr focusedApplication = std::make_shared(); - focusedApplication->setDispatchingTimeout(60ms); + focusedApplication->setDispatchingTimeout(100ms); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication); // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused. mFocusedWindow->setFocusable(false); @@ -7462,7 +7461,7 @@ TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_ // Key will not be sent anywhere because we have no focused window. It will remain pending. InputEventInjectionResult result = injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE, /*injectionTimeout=*/10ms, + InputEventInjectionSync::NONE, /*injectionTimeout=*/50ms, /*allowKeyRepeat=*/false); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); @@ -7473,7 +7472,7 @@ TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_ // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'. // For this test, it means that the key would get delivered to the window once it becomes // focused. - std::this_thread::sleep_for(10ms); + std::this_thread::sleep_for(50ms); // Touch unfocused window. This should force the pending key to get dropped. mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, -- GitLab From 21c49252bf1039465ca5654fcdd3335f40c7ac49 Mon Sep 17 00:00:00 2001 From: wanghuan16 Date: Sun, 9 Jul 2023 18:52:43 +0800 Subject: [PATCH 0267/1187] Correcting spelling errors in logs When ALOOPER_POLL_ERROR appears, replace the original output log information with ALOOPER_POLL_ERROR. Change-Id: I445a7a5b2b98da5d748f223bd7a39681ba0d3160 Signed-off-by: wanghuan16 --- services/sensorservice/tests/sensorservicetest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp index caf7f03361..1406bb38e7 100644 --- a/services/sensorservice/tests/sensorservicetest.cpp +++ b/services/sensorservice/tests/sensorservicetest.cpp @@ -130,7 +130,7 @@ int main() { printf("ALOOPER_POLL_TIMEOUT\n"); break; case ALOOPER_POLL_ERROR: - printf("ALOOPER_POLL_TIMEOUT\n"); + printf("ALOOPER_POLL_ERROR\n"); break; default: printf("ugh? poll returned %d\n", ret); -- GitLab From 822ecbd418536e86a03a90f664c60713b42027fe Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 7 Jul 2023 16:16:09 -0700 Subject: [PATCH 0268/1187] SF: Move AttachedChoreographer to Scheduler Updadate AttachedChoreographer from applyPolicy, considering the layer hierarchy. Change-Id: Ic4bad94d64280009915b9a79d6d293ef81d15d95 Test: android.view.choreographertests.AttachedChoreographerTest Bug: 260898223 --- .../Scheduler/ISchedulerCallback.h | 1 + .../surfaceflinger/Scheduler/LayerHistory.cpp | 22 -- .../surfaceflinger/Scheduler/LayerHistory.h | 7 - .../Scheduler/RefreshRateSelector.cpp | 2 + .../surfaceflinger/Scheduler/Scheduler.cpp | 161 +++++++- services/surfaceflinger/Scheduler/Scheduler.h | 27 +- services/surfaceflinger/SurfaceFlinger.cpp | 22 +- services/surfaceflinger/SurfaceFlinger.h | 2 + .../fuzzer/surfaceflinger_fuzzers_utils.h | 1 + .../tests/unittests/SchedulerTest.cpp | 358 +++++++++++++++++- .../tests/unittests/TestableScheduler.h | 9 +- .../tests/unittests/TestableSurfaceFlinger.h | 3 + .../unittests/mock/MockSchedulerCallback.h | 2 + 13 files changed, 563 insertions(+), 54 deletions(-) diff --git a/services/surfaceflinger/Scheduler/ISchedulerCallback.h b/services/surfaceflinger/Scheduler/ISchedulerCallback.h index badbf53753..3b61de7e83 100644 --- a/services/surfaceflinger/Scheduler/ISchedulerCallback.h +++ b/services/surfaceflinger/Scheduler/ISchedulerCallback.h @@ -29,6 +29,7 @@ struct ISchedulerCallback { virtual void requestDisplayModes(std::vector) = 0; virtual void kernelTimerChanged(bool expired) = 0; virtual void triggerOnFrameRateOverridesChanged() = 0; + virtual void onChoreographerAttached() = 0; protected: ~ISchedulerCallback() = default; diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index beaf9724a3..5d00a26031 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -131,22 +131,6 @@ void LayerHistory::record(int32_t id, const LayerProps& layerProps, nsecs_t pres const auto& info = layerPair->second; info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps); - // Set frame rate to attached choreographer. - // TODO(b/260898223): Change to use layer hierarchy and handle frame rate vote. - if (updateType == LayerUpdateType::SetFrameRate) { - auto range = mAttachedChoreographers.equal_range(id); - auto it = range.first; - while (it != range.second) { - sp choreographerConnection = it->second.promote(); - if (choreographerConnection) { - choreographerConnection->frameRate = layerProps.setFrameRateVote.rate; - it++; - } else { - it = mAttachedChoreographers.erase(it); - } - } - } - // Activate layer if inactive. if (found == LayerStatus::LayerInInactiveMap) { mActiveLayerInfos.insert( @@ -301,12 +285,6 @@ float LayerHistory::getLayerFramerate(nsecs_t now, int32_t id) const { return 0.f; } -void LayerHistory::attachChoreographer(int32_t layerId, - const sp& choreographerConnection) { - std::lock_guard lock(mLock); - mAttachedChoreographers.insert({layerId, wp(choreographerConnection)}); -} - auto LayerHistory::findLayer(int32_t id) -> std::pair { // the layer could be in either the active or inactive map, try both auto it = mActiveLayerInfos.find(id); diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 69caf9ffd2..d083fa2955 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -84,9 +84,6 @@ public: // return the frames per second of the layer with the given sequence id. float getLayerFramerate(nsecs_t now, int32_t id) const; - void attachChoreographer(int32_t layerId, - const sp& choreographerConnection); - private: friend class LayerHistoryTest; friend class TestableScheduler; @@ -124,10 +121,6 @@ private: LayerInfos mActiveLayerInfos GUARDED_BY(mLock); LayerInfos mInactiveLayerInfos GUARDED_BY(mLock); - // Map keyed by layer ID (sequence) to choreographer connections. - std::unordered_multimap> mAttachedChoreographers - GUARDED_BY(mLock); - uint32_t mDisplayArea = 0; // Whether to emit systrace output and debug logs. diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index f136e9f9df..7951c33d79 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -853,6 +853,8 @@ auto RefreshRateSelector::getFrameRateOverrides(const std::vector eventT const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++}; ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id); - auto connection = createConnectionInternal(eventThread.get()); + auto connection = eventThread->createEventConnection([&] { resync(); }); std::lock_guard lock(mConnectionsLock); mConnections.emplace(handle, Connection{connection, std::move(eventThread)}); return handle; } -sp Scheduler::createConnectionInternal( - EventThread* eventThread, EventRegistrationFlags eventRegistration, - const sp& layerHandle) { - int32_t layerId = static_cast(LayerHandle::getLayerId(layerHandle)); - auto connection = eventThread->createEventConnection([&] { resync(); }, eventRegistration); - mLayerHistory.attachChoreographer(layerId, connection); - return connection; -} - sp Scheduler::createDisplayEventConnection( ConnectionHandle handle, EventRegistrationFlags eventRegistration, const sp& layerHandle) { - std::lock_guard lock(mConnectionsLock); - RETURN_IF_INVALID_HANDLE(handle, nullptr); - return createConnectionInternal(mConnections[handle].thread.get(), eventRegistration, - layerHandle); + const auto connection = [&]() -> sp { + std::scoped_lock lock(mConnectionsLock); + RETURN_IF_INVALID_HANDLE(handle, nullptr); + + return mConnections[handle].thread->createEventConnection([&] { resync(); }, + eventRegistration); + }(); + const auto layerId = static_cast(LayerHandle::getLayerId(layerHandle)); + + if (layerId != static_cast(UNASSIGNED_LAYER_ID)) { + // TODO(b/290409668): Moving the choreographer attachment to be a transaction that will be + // processed on the main thread. + mSchedulerCallback.onChoreographerAttached(); + + std::scoped_lock lock(mChoreographerLock); + const auto [iter, emplaced] = + mAttachedChoreographers.emplace(layerId, + AttachedChoreographers{Fps(), {connection}}); + if (!emplaced) { + iter->second.connections.emplace(connection); + connection->frameRate = iter->second.frameRate; + } + } + return connection; } sp Scheduler::getEventConnection(ConnectionHandle handle) { @@ -555,6 +566,11 @@ void Scheduler::deregisterLayer(Layer* layer) { mLayerHistory.deregisterLayer(layer); } +void Scheduler::onLayerDestroyed(Layer* layer) { + std::scoped_lock lock(mChoreographerLock); + mAttachedChoreographers.erase(layer->getSequence()); +} + void Scheduler::recordLayerHistory(int32_t id, const LayerProps& layerProps, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType) { if (pacesetterSelectorPtr()->canSwitch()) { @@ -571,7 +587,9 @@ void Scheduler::setDefaultFrameRateCompatibility(Layer* layer) { mFeatures.test(Feature::kContentDetection)); } -void Scheduler::chooseRefreshRateForContent() { +void Scheduler::chooseRefreshRateForContent( + const surfaceflinger::frontend::LayerHierarchy* hierarchy, + bool updateAttachedChoreographer) { const auto selectorPtr = pacesetterSelectorPtr(); if (!selectorPtr->canSwitch()) return; @@ -579,6 +597,20 @@ void Scheduler::chooseRefreshRateForContent() { LayerHistory::Summary summary = mLayerHistory.summarize(*selectorPtr, systemTime()); applyPolicy(&Policy::contentRequirements, std::move(summary)); + + if (updateAttachedChoreographer) { + LOG_ALWAYS_FATAL_IF(!hierarchy); + + // update the attached choreographers after we selected the render rate. + const ftl::Optional modeOpt = [&] { + std::scoped_lock lock(mPolicyLock); + return mPolicy.modeOpt; + }(); + + if (modeOpt) { + updateAttachedChoreographers(*hierarchy, modeOpt->fps); + } + } } void Scheduler::resetIdleTimer() { @@ -822,6 +854,105 @@ void Scheduler::demotePacesetterDisplay() { mPolicy = {}; } +void Scheduler::updateAttachedChoreographersFrameRate( + const surfaceflinger::frontend::RequestedLayerState& layer, Fps fps) { + std::scoped_lock lock(mChoreographerLock); + + const auto layerId = static_cast(layer.id); + const auto choreographers = mAttachedChoreographers.find(layerId); + if (choreographers == mAttachedChoreographers.end()) { + return; + } + + auto& layerChoreographers = choreographers->second; + + layerChoreographers.frameRate = fps; + ATRACE_FORMAT_INSTANT("%s: %s for %s", __func__, to_string(fps).c_str(), layer.name.c_str()); + ALOGV("%s: %s for %s", __func__, to_string(fps).c_str(), layer.name.c_str()); + + auto it = layerChoreographers.connections.begin(); + while (it != layerChoreographers.connections.end()) { + sp choreographerConnection = it->promote(); + if (choreographerConnection) { + choreographerConnection->frameRate = fps; + it++; + } else { + it = choreographers->second.connections.erase(it); + } + } + + if (layerChoreographers.connections.empty()) { + mAttachedChoreographers.erase(choreographers); + } +} + +int Scheduler::updateAttachedChoreographersInternal( + const surfaceflinger::frontend::LayerHierarchy& layerHierarchy, Fps displayRefreshRate, + int parentDivisor) { + const char* name = layerHierarchy.getLayer() ? layerHierarchy.getLayer()->name.c_str() : "Root"; + + int divisor = 0; + if (layerHierarchy.getLayer()) { + const auto frameRateCompatibility = layerHierarchy.getLayer()->frameRateCompatibility; + const auto frameRate = Fps::fromValue(layerHierarchy.getLayer()->frameRate); + ALOGV("%s: %s frameRate %s parentDivisor=%d", __func__, name, to_string(frameRate).c_str(), + parentDivisor); + + if (frameRate.isValid()) { + if (frameRateCompatibility == ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE || + frameRateCompatibility == ANATIVEWINDOW_FRAME_RATE_EXACT) { + // Since this layer wants an exact match, we would only set a frame rate if the + // desired rate is a divisor of the display refresh rate. + divisor = RefreshRateSelector::getFrameRateDivisor(displayRefreshRate, frameRate); + } else if (frameRateCompatibility == ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) { + // find the closest frame rate divisor for the desired frame rate. + divisor = static_cast( + std::round(displayRefreshRate.getValue() / frameRate.getValue())); + } + } + } + + // We start by traversing the children, updating their choreographers, and getting back the + // aggregated frame rate. + int childrenDivisor = 0; + for (const auto& [child, _] : layerHierarchy.mChildren) { + LOG_ALWAYS_FATAL_IF(child == nullptr || child->getLayer() == nullptr); + + ALOGV("%s: %s traversing child %s", __func__, name, child->getLayer()->name.c_str()); + + const int childDivisor = + updateAttachedChoreographersInternal(*child, displayRefreshRate, divisor); + childrenDivisor = childrenDivisor > 0 ? childrenDivisor : childDivisor; + if (childDivisor > 0) { + childrenDivisor = std::gcd(childrenDivisor, childDivisor); + } + ALOGV("%s: %s childrenDivisor=%d", __func__, name, childrenDivisor); + } + + ALOGV("%s: %s divisor=%d", __func__, name, divisor); + + // If there is no explicit vote for this layer. Use the children's vote if exists + divisor = (divisor == 0) ? childrenDivisor : divisor; + ALOGV("%s: %s divisor=%d with children", __func__, name, divisor); + + // If there is no explicit vote for this layer or its children, Use the parent vote if exists + divisor = (divisor == 0) ? parentDivisor : divisor; + ALOGV("%s: %s divisor=%d with parent", __func__, name, divisor); + + if (layerHierarchy.getLayer()) { + Fps fps = divisor > 1 ? displayRefreshRate / (unsigned int)divisor : Fps(); + updateAttachedChoreographersFrameRate(*layerHierarchy.getLayer(), fps); + } + + return divisor; +} + +void Scheduler::updateAttachedChoreographers( + const surfaceflinger::frontend::LayerHierarchy& layerHierarchy, Fps displayRefreshRate) { + ATRACE_CALL(); + updateAttachedChoreographersInternal(layerHierarchy, displayRefreshRate, 0); +} + template auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals { ATRACE_CALL(); diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 17e9ceaf66..c44c447d90 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -52,6 +52,8 @@ #include "Utils/Dumper.h" #include "VsyncModulator.h" +#include + namespace android::scheduler { // Opaque handle to scheduler connection. @@ -153,7 +155,7 @@ public: sp createDisplayEventConnection( ConnectionHandle, EventRegistrationFlags eventRegistration = {}, - const sp& layerHandle = nullptr); + const sp& layerHandle = nullptr) EXCLUDES(mChoreographerLock); sp getEventConnection(ConnectionHandle); @@ -230,9 +232,11 @@ public: void setModeChangePending(bool pending); void setDefaultFrameRateCompatibility(Layer*); void deregisterLayer(Layer*); + void onLayerDestroyed(Layer*) EXCLUDES(mChoreographerLock); // Detects content using layer history, and selects a matching refresh rate. - void chooseRefreshRateForContent() EXCLUDES(mDisplayLock); + void chooseRefreshRateForContent(const surfaceflinger::frontend::LayerHierarchy*, + bool updateAttachedChoreographer) EXCLUDES(mDisplayLock); void resetIdleTimer(); @@ -310,9 +314,6 @@ private: // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr); - sp createConnectionInternal( - EventThread*, EventRegistrationFlags eventRegistration = {}, - const sp& layerHandle = nullptr); // Update feature state machine to given state when corresponding timer resets or expires. void kernelIdleTimerCallback(TimerState) EXCLUDES(mDisplayLock); @@ -386,6 +387,12 @@ private: GlobalSignals makeGlobalSignals() const REQUIRES(mPolicyLock); bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock); + void updateAttachedChoreographers(const surfaceflinger::frontend::LayerHierarchy&, + Fps displayRefreshRate); + int updateAttachedChoreographersInternal(const surfaceflinger::frontend::LayerHierarchy&, + Fps displayRefreshRate, int parentDivisor); + void updateAttachedChoreographersFrameRate(const surfaceflinger::frontend::RequestedLayerState&, + Fps fps) EXCLUDES(mChoreographerLock); void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mDisplayLock); @@ -506,6 +513,16 @@ private: std::optional cachedModeChangedParams; } mPolicy GUARDED_BY(mPolicyLock); + std::mutex mChoreographerLock; + + struct AttachedChoreographers { + Fps frameRate; + std::unordered_set, WpHash> connections; + }; + // Map keyed by layer ID (sequence) to choreographer connections. + std::unordered_map mAttachedChoreographers + GUARDED_BY(mChoreographerLock); + std::mutex mVsyncTimelineLock; std::optional mLastVsyncPeriodChangeTimeline GUARDED_BY(mVsyncTimelineLock); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c46da11a03..2782ce4ce4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2325,6 +2325,11 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, Changes::Visibility)) { mVisibleRegionsDirty = true; } + if (mLayerLifecycleManager.getGlobalChanges().any(Changes::Hierarchy | Changes::FrameRate)) { + // The frame rate of attached choreographers can only change as a result of a + // FrameRate change (including when Hierarchy changes). + mUpdateAttachedChoreographer = true; + } outTransactionsAreEmpty = mLayerLifecycleManager.getGlobalChanges().get() == 0; mustComposite |= mLayerLifecycleManager.getGlobalChanges().get() != 0; @@ -2501,8 +2506,14 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) // Hold mStateLock as chooseRefreshRateForContent promotes wp to sp // and may eventually call to ~Layer() if it holds the last reference { + bool updateAttachedChoreographer = mUpdateAttachedChoreographer; + mUpdateAttachedChoreographer = false; + Mutex::Autolock lock(mStateLock); - mScheduler->chooseRefreshRateForContent(); + mScheduler->chooseRefreshRateForContent(mLayerLifecycleManagerEnabled + ? &mLayerHierarchyBuilder.getHierarchy() + : nullptr, + updateAttachedChoreographer); setActiveModeInHwcIfNeeded(); } @@ -3924,6 +3935,14 @@ void SurfaceFlinger::notifyCpuLoadUp() { mPowerAdvisor->notifyCpuLoadUp(); } +void SurfaceFlinger::onChoreographerAttached() { + ATRACE_CALL(); + if (mLayerLifecycleManagerEnabled) { + mUpdateAttachedChoreographer = true; + scheduleCommit(FrameHint::kNone); + } +} + void SurfaceFlinger::initScheduler(const sp& display) { using namespace scheduler; @@ -7938,6 +7957,7 @@ void SurfaceFlinger::onLayerDestroyed(Layer* layer) { if (mTransactionTracing) { mTransactionTracing->onLayerRemoved(layer->getSequence()); } + mScheduler->onLayerDestroyed(layer); } void SurfaceFlinger::onLayerUpdate() { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index d97a7478dd..19470723b1 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -646,6 +646,7 @@ private: void requestDisplayModes(std::vector) override; void kernelTimerChanged(bool expired) override; void triggerOnFrameRateOverridesChanged() override; + void onChoreographerAttached() override; // ICEPowerCallback overrides: void notifyCpuLoadUp() override; @@ -1181,6 +1182,7 @@ private: bool mUpdateInputInfo = false; bool mSomeChildrenChanged; bool mForceTransactionDisplayChange = false; + bool mUpdateAttachedChoreographer = false; // Set if LayerMetadata has changed since the last LayerMetadata snapshot. bool mLayerMetadataSnapshotNeeded = false; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 0c9a16bee3..00e92a18ff 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -792,6 +792,7 @@ private: void requestDisplayModes(std::vector) override {} void kernelTimerChanged(bool) override {} void triggerOnFrameRateOverridesChanged() override {} + void onChoreographerAttached() override {} surfaceflinger::test::Factory mFactory; sp mFlinger = diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index fab3c0e887..405f79d290 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -30,6 +30,10 @@ #include "mock/MockLayer.h" #include "mock/MockSchedulerCallback.h" +#include + +#include "FpsOps.h" + namespace android::scheduler { using android::mock::createDisplayMode; @@ -42,6 +46,10 @@ namespace { using MockEventThread = android::mock::EventThread; using MockLayer = android::mock::MockLayer; +using LayerHierarchy = surfaceflinger::frontend::LayerHierarchy; +using LayerHierarchyBuilder = surfaceflinger::frontend::LayerHierarchyBuilder; +using RequestedLayerState = surfaceflinger::frontend::RequestedLayerState; + class SchedulerTest : public testing::Test { protected: class MockEventThreadConnection : public android::EventThreadConnection { @@ -83,6 +91,7 @@ protected: mock::SchedulerCallback mSchedulerCallback; TestableScheduler* mScheduler = new TestableScheduler{mSelector, mSchedulerCallback}; + surfaceflinger::frontend::LayerHierarchyBuilder mLayerHierarchyBuilder{{}}; ConnectionHandle mConnectionHandle; MockEventThread* mEventThread; @@ -199,7 +208,8 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSup mScheduler->onActiveDisplayAreaChanged(kDisplayArea); EXPECT_CALL(mSchedulerCallback, requestDisplayModes(_)).Times(0); - mScheduler->chooseRefreshRateForContent(); + mScheduler->chooseRefreshRateForContent(/*LayerHierarchy*/ nullptr, + /*updateAttachedChoreographer*/ false); } TEST_F(SchedulerTest, updateDisplayModes) { @@ -278,11 +288,13 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { mScheduler->onActiveDisplayAreaChanged(kDisplayArea); EXPECT_CALL(mSchedulerCallback, requestDisplayModes(Is120Hz())).Times(1); - mScheduler->chooseRefreshRateForContent(); + mScheduler->chooseRefreshRateForContent(/*LayerHierarchy*/ nullptr, + /*updateAttachedChoreographer*/ false); // No-op if layer requirements have not changed. EXPECT_CALL(mSchedulerCallback, requestDisplayModes(_)).Times(0); - mScheduler->chooseRefreshRateForContent(); + mScheduler->chooseRefreshRateForContent(/*LayerHierarchy*/ nullptr, + /*updateAttachedChoreographer*/ false); } TEST_F(SchedulerTest, chooseDisplayModesSingleDisplay) { @@ -437,4 +449,344 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { } } +class AttachedChoreographerTest : public SchedulerTest { +protected: + void frameRateTestScenario(Fps layerFps, int8_t frameRateCompatibility, Fps displayFps, + Fps expectedChoreographerFps); +}; + +TEST_F(AttachedChoreographerTest, registerSingle) { + EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty()); + + const sp layer = sp::make(mFlinger.flinger()); + + EXPECT_CALL(mSchedulerCallback, onChoreographerAttached); + const sp connection = + mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle()); + + EXPECT_EQ(1u, mScheduler->mutableAttachedChoreographers().size()); + ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence())); + EXPECT_EQ(1u, + mScheduler->mutableAttachedChoreographers()[layer->getSequence()].connections.size()); + EXPECT_FALSE( + mScheduler->mutableAttachedChoreographers()[layer->getSequence()].frameRate.isValid()); +} + +TEST_F(AttachedChoreographerTest, registerMultipleOnSameLayer) { + EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty()); + + const sp layer = sp::make(mFlinger.flinger()); + const auto handle = layer->getHandle(); + + EXPECT_CALL(mSchedulerCallback, onChoreographerAttached).Times(2); + + EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)) + .WillOnce(Return(0)) + .WillOnce(Return(0)); + + const auto mockConnection1 = sp::make(mEventThread); + const auto mockConnection2 = sp::make(mEventThread); + EXPECT_CALL(*mEventThread, createEventConnection(_, _)) + .WillOnce(Return(mockConnection1)) + .WillOnce(Return(mockConnection2)); + + const sp connection1 = + mScheduler->createDisplayEventConnection(mConnectionHandle, {}, handle); + const sp connection2 = + mScheduler->createDisplayEventConnection(mConnectionHandle, {}, handle); + + EXPECT_EQ(1u, mScheduler->mutableAttachedChoreographers().size()); + ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence())); + EXPECT_EQ(2u, + mScheduler->mutableAttachedChoreographers()[layer->getSequence()].connections.size()); + EXPECT_FALSE( + mScheduler->mutableAttachedChoreographers()[layer->getSequence()].frameRate.isValid()); +} + +TEST_F(AttachedChoreographerTest, registerMultipleOnDifferentLayers) { + EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty()); + + const sp layer1 = sp::make(mFlinger.flinger()); + const sp layer2 = sp::make(mFlinger.flinger()); + + EXPECT_CALL(mSchedulerCallback, onChoreographerAttached).Times(2); + const sp connection1 = + mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer1->getHandle()); + const sp connection2 = + mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer2->getHandle()); + + EXPECT_EQ(2u, mScheduler->mutableAttachedChoreographers().size()); + + ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer1->getSequence())); + EXPECT_EQ(1u, + mScheduler->mutableAttachedChoreographers()[layer1->getSequence()] + .connections.size()); + EXPECT_FALSE( + mScheduler->mutableAttachedChoreographers()[layer1->getSequence()].frameRate.isValid()); + + ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer2->getSequence())); + EXPECT_EQ(1u, + mScheduler->mutableAttachedChoreographers()[layer2->getSequence()] + .connections.size()); + EXPECT_FALSE( + mScheduler->mutableAttachedChoreographers()[layer2->getSequence()].frameRate.isValid()); +} + +TEST_F(AttachedChoreographerTest, removedWhenConnectionIsGone) { + EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty()); + + const sp layer = sp::make(mFlinger.flinger()); + + EXPECT_CALL(mSchedulerCallback, onChoreographerAttached); + + sp connection = + mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle()); + + ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence())); + EXPECT_EQ(1u, + mScheduler->mutableAttachedChoreographers()[layer->getSequence()].connections.size()); + + // The connection is used all over this test, so it is quite hard to release it from here. + // Instead, we just do a small shortcut. + { + EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0)); + sp mockConnection = + sp::make(mEventThread); + mScheduler->mutableAttachedChoreographers()[layer->getSequence()].connections.clear(); + mScheduler->mutableAttachedChoreographers()[layer->getSequence()].connections.emplace( + mockConnection); + } + + RequestedLayerState layerState(LayerCreationArgs(layer->getSequence())); + LayerHierarchy hierarchy(&layerState); + mScheduler->updateAttachedChoreographers(hierarchy, 60_Hz); + EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty()); +} + +TEST_F(AttachedChoreographerTest, removedWhenLayerIsGone) { + EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty()); + + sp layer = sp::make(mFlinger.flinger()); + + EXPECT_CALL(mSchedulerCallback, onChoreographerAttached); + const sp connection = + mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle()); + + layer.clear(); + mFlinger.mutableLayersPendingRemoval().clear(); + EXPECT_TRUE(mScheduler->mutableAttachedChoreographers().empty()); +} + +void AttachedChoreographerTest::frameRateTestScenario(Fps layerFps, int8_t frameRateCompatibility, + Fps displayFps, + Fps expectedChoreographerFps) { + const sp layer = sp::make(mFlinger.flinger()); + + EXPECT_CALL(mSchedulerCallback, onChoreographerAttached); + sp connection = + mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle()); + + RequestedLayerState layerState(LayerCreationArgs(layer->getSequence())); + LayerHierarchy hierarchy(&layerState); + + layerState.frameRate = layerFps.getValue(); + layerState.frameRateCompatibility = frameRateCompatibility; + + mScheduler->updateAttachedChoreographers(hierarchy, displayFps); + + ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence())); + EXPECT_EQ(expectedChoreographerFps, + mScheduler->mutableAttachedChoreographers()[layer->getSequence()].frameRate); + EXPECT_EQ(expectedChoreographerFps, mEventThreadConnection->frameRate); +} + +TEST_F(AttachedChoreographerTest, setsFrameRateDefault) { + Fps layerFps = 30_Hz; + int8_t frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT; + Fps displayFps = 60_Hz; + Fps expectedChoreographerFps = 30_Hz; + + frameRateTestScenario(layerFps, frameRateCompatibility, displayFps, expectedChoreographerFps); + + layerFps = Fps::fromValue(32.7f); + frameRateTestScenario(layerFps, frameRateCompatibility, displayFps, expectedChoreographerFps); +} + +TEST_F(AttachedChoreographerTest, setsFrameRateExact) { + Fps layerFps = 30_Hz; + int8_t frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_EXACT; + Fps displayFps = 60_Hz; + Fps expectedChoreographerFps = 30_Hz; + + frameRateTestScenario(layerFps, frameRateCompatibility, displayFps, expectedChoreographerFps); + + layerFps = Fps::fromValue(32.7f); + expectedChoreographerFps = {}; + frameRateTestScenario(layerFps, frameRateCompatibility, displayFps, expectedChoreographerFps); +} + +TEST_F(AttachedChoreographerTest, setsFrameRateExactOrMultiple) { + Fps layerFps = 30_Hz; + int8_t frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; + Fps displayFps = 60_Hz; + Fps expectedChoreographerFps = 30_Hz; + + frameRateTestScenario(layerFps, frameRateCompatibility, displayFps, expectedChoreographerFps); + + layerFps = Fps::fromValue(32.7f); + expectedChoreographerFps = {}; + frameRateTestScenario(layerFps, frameRateCompatibility, displayFps, expectedChoreographerFps); +} + +TEST_F(AttachedChoreographerTest, setsFrameRateParent) { + const sp layer = sp::make(mFlinger.flinger()); + const sp parent = sp::make(mFlinger.flinger()); + + EXPECT_CALL(mSchedulerCallback, onChoreographerAttached); + sp connection = + mScheduler->createDisplayEventConnection(mConnectionHandle, {}, parent->getHandle()); + + RequestedLayerState parentState(LayerCreationArgs(parent->getSequence())); + LayerHierarchy parentHierarchy(&parentState); + + RequestedLayerState layerState(LayerCreationArgs(layer->getSequence())); + LayerHierarchy hierarchy(&layerState); + parentHierarchy.mChildren.push_back( + std::make_pair(&hierarchy, LayerHierarchy::Variant::Attached)); + + layerState.frameRate = (30_Hz).getValue(); + layerState.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT; + + mScheduler->updateAttachedChoreographers(parentHierarchy, 120_Hz); + + ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(parent->getSequence())); + + EXPECT_EQ(30_Hz, mScheduler->mutableAttachedChoreographers()[parent->getSequence()].frameRate); +} + +TEST_F(AttachedChoreographerTest, setsFrameRateParent2Children) { + const sp layer1 = sp::make(mFlinger.flinger()); + const sp layer2 = sp::make(mFlinger.flinger()); + const sp parent = sp::make(mFlinger.flinger()); + + EXPECT_CALL(mSchedulerCallback, onChoreographerAttached); + sp connection = + mScheduler->createDisplayEventConnection(mConnectionHandle, {}, parent->getHandle()); + + RequestedLayerState parentState(LayerCreationArgs(parent->getSequence())); + LayerHierarchy parentHierarchy(&parentState); + + RequestedLayerState layer1State(LayerCreationArgs(layer1->getSequence())); + LayerHierarchy layer1Hierarchy(&layer1State); + parentHierarchy.mChildren.push_back( + std::make_pair(&layer1Hierarchy, LayerHierarchy::Variant::Attached)); + + RequestedLayerState layer2State(LayerCreationArgs(layer1->getSequence())); + LayerHierarchy layer2Hierarchy(&layer2State); + parentHierarchy.mChildren.push_back( + std::make_pair(&layer2Hierarchy, LayerHierarchy::Variant::Attached)); + + layer1State.frameRate = (30_Hz).getValue(); + layer1State.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT; + + layer2State.frameRate = (20_Hz).getValue(); + layer2State.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT; + + mScheduler->updateAttachedChoreographers(parentHierarchy, 120_Hz); + + ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(parent->getSequence())); + + EXPECT_EQ(60_Hz, mScheduler->mutableAttachedChoreographers()[parent->getSequence()].frameRate); +} + +TEST_F(AttachedChoreographerTest, setsFrameRateParentConflictingChildren) { + const sp layer1 = sp::make(mFlinger.flinger()); + const sp layer2 = sp::make(mFlinger.flinger()); + const sp parent = sp::make(mFlinger.flinger()); + + EXPECT_CALL(mSchedulerCallback, onChoreographerAttached); + sp connection = + mScheduler->createDisplayEventConnection(mConnectionHandle, {}, parent->getHandle()); + + RequestedLayerState parentState(LayerCreationArgs(parent->getSequence())); + LayerHierarchy parentHierarchy(&parentState); + + RequestedLayerState layer1State(LayerCreationArgs(layer1->getSequence())); + LayerHierarchy layer1Hierarchy(&layer1State); + parentHierarchy.mChildren.push_back( + std::make_pair(&layer1Hierarchy, LayerHierarchy::Variant::Attached)); + + RequestedLayerState layer2State(LayerCreationArgs(layer1->getSequence())); + LayerHierarchy layer2Hierarchy(&layer2State); + parentHierarchy.mChildren.push_back( + std::make_pair(&layer2Hierarchy, LayerHierarchy::Variant::Attached)); + + layer1State.frameRate = (30_Hz).getValue(); + layer1State.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT; + + layer2State.frameRate = (25_Hz).getValue(); + layer2State.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT; + + mScheduler->updateAttachedChoreographers(parentHierarchy, 120_Hz); + + ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(parent->getSequence())); + + EXPECT_EQ(Fps(), mScheduler->mutableAttachedChoreographers()[parent->getSequence()].frameRate); +} + +TEST_F(AttachedChoreographerTest, setsFrameRateChild) { + const sp layer = sp::make(mFlinger.flinger()); + const sp parent = sp::make(mFlinger.flinger()); + + EXPECT_CALL(mSchedulerCallback, onChoreographerAttached); + sp connection = + mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle()); + + RequestedLayerState parentState(LayerCreationArgs(parent->getSequence())); + LayerHierarchy parentHierarchy(&parentState); + + RequestedLayerState layerState(LayerCreationArgs(layer->getSequence())); + LayerHierarchy hierarchy(&layerState); + parentHierarchy.mChildren.push_back( + std::make_pair(&hierarchy, LayerHierarchy::Variant::Attached)); + + parentState.frameRate = (30_Hz).getValue(); + parentState.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT; + + mScheduler->updateAttachedChoreographers(parentHierarchy, 120_Hz); + + ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence())); + + EXPECT_EQ(30_Hz, mScheduler->mutableAttachedChoreographers()[layer->getSequence()].frameRate); +} + +TEST_F(AttachedChoreographerTest, setsFrameRateChildNotOverriddenByParent) { + const sp layer = sp::make(mFlinger.flinger()); + const sp parent = sp::make(mFlinger.flinger()); + + EXPECT_CALL(mSchedulerCallback, onChoreographerAttached); + sp connection = + mScheduler->createDisplayEventConnection(mConnectionHandle, {}, layer->getHandle()); + + RequestedLayerState parentState(LayerCreationArgs(parent->getSequence())); + LayerHierarchy parentHierarchy(&parentState); + + RequestedLayerState layerState(LayerCreationArgs(layer->getSequence())); + LayerHierarchy hierarchy(&layerState); + parentHierarchy.mChildren.push_back( + std::make_pair(&hierarchy, LayerHierarchy::Variant::Attached)); + + parentState.frameRate = (30_Hz).getValue(); + parentState.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT; + + layerState.frameRate = (60_Hz).getValue(); + layerState.frameRateCompatibility = ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT; + + mScheduler->updateAttachedChoreographers(parentHierarchy, 120_Hz); + + ASSERT_EQ(1u, mScheduler->mutableAttachedChoreographers().count(layer->getSequence())); + + EXPECT_EQ(60_Hz, mScheduler->mutableAttachedChoreographers()[layer->getSequence()].frameRate); +} + } // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index aac11c01b8..fa7a94735f 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -39,7 +39,7 @@ public: TestableScheduler(RefreshRateSelectorPtr selectorPtr, ISchedulerCallback& callback) : TestableScheduler(std::make_unique(), std::make_shared(), std::move(selectorPtr), - /* modulatorPtr */ nullptr, callback) {} + sp::make(VsyncConfigSet{}), callback) {} TestableScheduler(std::unique_ptr controller, std::shared_ptr tracker, RefreshRateSelectorPtr selectorPtr, @@ -104,6 +104,7 @@ public: auto& mutableAppConnectionHandle() { return mAppConnectionHandle; } auto& mutableLayerHistory() { return mLayerHistory; } + auto& mutableAttachedChoreographers() { return mAttachedChoreographers; } size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mActiveLayerInfos.size() + mLayerHistory.mInactiveLayerInfos.size(); @@ -168,6 +169,12 @@ public: : VsyncSchedule::HwVsyncState::Disabled; } + void updateAttachedChoreographers( + const surfaceflinger::frontend::LayerHierarchy& layerHierarchy, + Fps displayRefreshRate) { + Scheduler::updateAttachedChoreographers(layerHierarchy, displayRefreshRate); + } + using Scheduler::onHardwareVsyncRequest; private: diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 156c40a721..5be45489c2 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -624,6 +624,8 @@ public: auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; } + auto& mutableLayersPendingRemoval() { return mFlinger->mLayersPendingRemoval; } + auto fromHandle(const sp& handle) { return LayerHandle::getLayer(handle); } ~TestableSurfaceFlinger() { @@ -634,6 +636,7 @@ public: mutableDisplays().clear(); mutableCurrentState().displays.clear(); mutableDrawingState().displays.clear(); + mFlinger->mLayersPendingRemoval.clear(); mFlinger->mScheduler.reset(); mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr()); mFlinger->mRenderEngine = std::unique_ptr(); diff --git a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h index 306eb4d845..22b2cccf03 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h +++ b/services/surfaceflinger/tests/unittests/mock/MockSchedulerCallback.h @@ -27,6 +27,7 @@ struct SchedulerCallback final : ISchedulerCallback { MOCK_METHOD(void, requestDisplayModes, (std::vector), (override)); MOCK_METHOD(void, kernelTimerChanged, (bool), (override)); MOCK_METHOD(void, triggerOnFrameRateOverridesChanged, (), (override)); + MOCK_METHOD(void, onChoreographerAttached, (), (override)); }; struct NoOpSchedulerCallback final : ISchedulerCallback { @@ -34,6 +35,7 @@ struct NoOpSchedulerCallback final : ISchedulerCallback { void requestDisplayModes(std::vector) override {} void kernelTimerChanged(bool) override {} void triggerOnFrameRateOverridesChanged() override {} + void onChoreographerAttached() override {} }; } // namespace android::scheduler::mock -- GitLab From ccb75e899cb3a5384c92d6c2713c5bf1cac93d70 Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Fri, 23 Jun 2023 14:08:06 +0000 Subject: [PATCH 0269/1187] inputflinger: Add touchpad stack fuzzer Heavily inspired by MultiTouchInputFuzzer, this one works similarly but has additional code to fuzz touchpad setting values and device-specific configuration. The evdev axis info is also fuzzed, since unspecified resolution values have caused bugs in the Gestures library before. (Other fuzzers only fuzz the status_t return value from getAbsoluteAxisInfo, not the axis info struct itself.) Bug: 264582512 Test: build with SANITIZE_TARGET=hwaddress, run for a while on a device Change-Id: Ic22ac0f29d433fdf3c17331df620a39937ebd7eb --- services/inputflinger/Android.bp | 1 + .../inputflinger/tests/fuzzers/Android.bp | 16 ++ .../tests/fuzzers/FuzzContainer.h | 4 + .../tests/fuzzers/MapperHelpers.h | 14 ++ .../tests/fuzzers/TouchpadInputFuzzer.cpp | 176 ++++++++++++++++++ 5 files changed, 211 insertions(+) create mode 100644 services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index ee03d947db..f749b0e5b5 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -243,6 +243,7 @@ phony { "inputflinger_keyboard_input_fuzzer", "inputflinger_multitouch_input_fuzzer", "inputflinger_switch_input_fuzzer", + "inputflinger_touchpad_input_fuzzer", "inputflinger_input_reader_fuzzer", "inputflinger_blocking_queue_fuzzer", "inputflinger_input_classifier_fuzzer", diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp index 47b0824fd0..d7980f564e 100644 --- a/services/inputflinger/tests/fuzzers/Android.bp +++ b/services/inputflinger/tests/fuzzers/Android.bp @@ -99,6 +99,22 @@ cc_fuzz { ], } +cc_fuzz { + name: "inputflinger_touchpad_input_fuzzer", + defaults: [ + "inputflinger_fuzz_defaults", + ], + srcs: [ + "TouchpadInputFuzzer.cpp", + ], + static_libs: [ + "libchrome-gestures", + ], + header_libs: [ + "libchrome-gestures_headers", + ], +} + cc_fuzz { name: "inputflinger_input_reader_fuzzer", defaults: [ diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h index fd14e024c6..0869b9fee7 100644 --- a/services/inputflinger/tests/fuzzers/FuzzContainer.h +++ b/services/inputflinger/tests/fuzzers/FuzzContainer.h @@ -73,6 +73,10 @@ public: InputReaderConfiguration& getPolicyConfig() { return mPolicyConfig; } + void setAbsoluteAxisInfo(int axis, const RawAbsoluteAxisInfo& axisInfo) { + mFuzzEventHub->setAbsoluteAxisInfo(mFuzzDevice->getId(), axis, axisInfo); + } + template T& getMapper(Args... args) { int32_t eventhubId = mFdp->ConsumeIntegral(); diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index 4a2c98ccae..5039d1a5f1 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -15,6 +15,9 @@ */ #pragma once +#include + +#include #include #include #include @@ -92,6 +95,7 @@ class FuzzEventHub : public EventHubInterface { InputDeviceIdentifier mIdentifier; std::vector mVideoFrames; PropertyMap mFuzzConfig; + std::map> mAxes; std::shared_ptr mFdp; public: @@ -111,8 +115,18 @@ public: std::optional getConfiguration(int32_t deviceId) const override { return mFuzzConfig; } + void setAbsoluteAxisInfo(int32_t deviceId, int axis, const RawAbsoluteAxisInfo& axisInfo) { + mAxes[deviceId][axis] = axisInfo; + } status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const override { + if (auto deviceAxesIt = mAxes.find(deviceId); deviceAxesIt != mAxes.end()) { + const std::map& deviceAxes = deviceAxesIt->second; + if (auto axisInfoIt = deviceAxes.find(axis); axisInfoIt != deviceAxes.end()) { + *outAxisInfo = axisInfoIt->second; + return OK; + } + } return mFdp->ConsumeIntegral(); } bool hasRelativeAxis(int32_t deviceId, int axis) const override { return mFdp->ConsumeBool(); } diff --git a/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp new file mode 100644 index 0000000000..ef9663a8d6 --- /dev/null +++ b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp @@ -0,0 +1,176 @@ +/* + * Copyright 2023 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 +#include +#include + +#include + +#include +#include +#include + +namespace android { + +namespace { + +void setAxisInfo(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer, int axis) { + if (fdp.ConsumeBool()) { + fuzzer.setAbsoluteAxisInfo(axis, + RawAbsoluteAxisInfo{ + .valid = fdp.ConsumeBool(), + .minValue = fdp.ConsumeIntegral(), + .maxValue = fdp.ConsumeIntegral(), + .flat = fdp.ConsumeIntegral(), + .fuzz = fdp.ConsumeIntegral(), + .resolution = fdp.ConsumeIntegral(), + }); + } +} + +void setAxisInfos(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) { + setAxisInfo(fdp, fuzzer, ABS_MT_SLOT); + setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_X); + setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_Y); + setAxisInfo(fdp, fuzzer, ABS_MT_PRESSURE); + setAxisInfo(fdp, fuzzer, ABS_MT_ORIENTATION); + setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MAJOR); + setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MINOR); + setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MAJOR); + setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MINOR); +} + +const std::vector boolPropertiesToFuzz = { + "gestureProp.Compute_Surface_Area_from_Pressure", + "gestureProp.Drumroll_Suppression_Enable", + "gestureProp.Fling_Buffer_Suppress_Zero_Length_Scrolls", + "gestureProp.Stationary_Wiggle_Filter_Enabled", +}; +const std::vector doublePropertiesToFuzz = { + "gestureProp.Fake_Timestamp_Delta", + "gestureProp.Finger_Moving_Energy", + "gestureProp.Finger_Moving_Hysteresis", + "gestureProp.IIR_a1", + "gestureProp.IIR_a2", + "gestureProp.IIR_b0", + "gestureProp.IIR_b1", + "gestureProp.IIR_b2", + "gestureProp.IIR_b3", + "gestureProp.Max_Allowed_Pressure_Change_Per_Sec", + "gestureProp.Max_Hysteresis_Pressure_Per_Sec", + "gestureProp.Max_Stationary_Move_Speed", + "gestureProp.Max_Stationary_Move_Speed_Hysteresis", + "gestureProp.Max_Stationary_Move_Suppress_Distance", + "gestureProp.Multiple_Palm_Width", + "gestureProp.Palm_Edge_Zone_Width", + "gestureProp.Palm_Eval_Timeout", + "gestureProp.Palm_Pressure", + "gestureProp.Palm_Width", + "gestureProp.Pressure_Calibration_Offset", + "gestureProp.Pressure_Calibration_Slope", + "gestureProp.Tap_Exclusion_Border_Width", + "gestureProp.Touchpad_Device_Output_Bias_on_X-Axis", + "gestureProp.Touchpad_Device_Output_Bias_on_Y-Axis", + "gestureProp.Two_Finger_Vertical_Close_Distance_Thresh", +}; + +void setDeviceSpecificConfig(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) { + // There are a great many gesture properties offered by the Gestures library, all of which could + // potentially be set in Input Device Configuration files. Maintaining a complete list is + // impractical, so instead we only fuzz properties which are used in at least one IDC file, or + // which are likely to be used in future (e.g. ones for controlling palm rejection). + + if (fdp.ConsumeBool()) { + fuzzer.addProperty("gestureProp.Touchpad_Stack_Version", + std::to_string(fdp.ConsumeIntegral())); + } + + for (auto& propertyName : boolPropertiesToFuzz) { + if (fdp.ConsumeBool()) { + fuzzer.addProperty(propertyName, fdp.ConsumeBool() ? "1" : "0"); + } + } + + for (auto& propertyName : doublePropertiesToFuzz) { + if (fdp.ConsumeBool()) { + fuzzer.addProperty(propertyName, std::to_string(fdp.ConsumeFloatingPoint())); + } + } + + if (fdp.ConsumeBool()) { + fuzzer.addProperty("gestureProp." + fdp.ConsumeRandomLengthString(), + std::to_string(fdp.ConsumeIntegral())); + } +} + +void setTouchpadSettings(ThreadSafeFuzzedDataProvider& fdp, InputReaderConfiguration& config) { + config.touchpadPointerSpeed = fdp.ConsumeIntegralInRange(-7, 7); + config.touchpadNaturalScrollingEnabled = fdp.ConsumeBool(); + config.touchpadTapToClickEnabled = fdp.ConsumeBool(); + config.touchpadRightClickZoneEnabled = fdp.ConsumeBool(); +} + +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { + std::shared_ptr fdp = + std::make_shared(data, size); + FuzzContainer fuzzer(fdp); + setAxisInfos(*fdp, fuzzer); + setDeviceSpecificConfig(*fdp, fuzzer); + + auto policyConfig = fuzzer.getPolicyConfig(); + // Some settings are fuzzed here, as well as in the main loop, to provide randomized data to the + // TouchpadInputMapper constructor. + setTouchpadSettings(*fdp, policyConfig); + policyConfig.pointerCaptureRequest.enable = fdp->ConsumeBool(); + TouchpadInputMapper& mapper = fuzzer.getMapper(policyConfig); + + // Loop through mapper operations until randomness is exhausted. + while (fdp->remaining_bytes() > 0) { + fdp->PickValueInArray>({ + [&]() -> void { + std::string dump; + mapper.dump(dump); + }, + [&]() -> void { + InputDeviceInfo info; + mapper.populateDeviceInfo(info); + }, + [&]() -> void { mapper.getSources(); }, + [&]() -> void { + setTouchpadSettings(*fdp, policyConfig); + policyConfig.pointerCaptureRequest.enable = fdp->ConsumeBool(); + std::list unused = + mapper.reconfigure(fdp->ConsumeIntegral(), policyConfig, + InputReaderConfiguration::Change( + fdp->ConsumeIntegral())); + }, + [&]() -> void { + std::list unused = mapper.reset(fdp->ConsumeIntegral()); + }, + [&]() -> void { + RawEvent event = getFuzzedRawEvent(*fdp); + std::list unused = mapper.process(&event); + }, + })(); + } + + return 0; +} + +} // namespace android -- GitLab From e36d8359265b098fb6ffedf46716db6b374f4c64 Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Mon, 10 Jul 2023 13:28:45 +0000 Subject: [PATCH 0270/1187] inputflinger fuzzers: remove FuzzContainer.getPolicyConfig Because FuzzInputReaderPolicy::getReaderConfiguration does nothing, any calls to getPolicyConfig can be replaced with default InputReaderConfiguration structs. This makes it clearer where where a fuzzer is getting its configuration from, and therefore makes it easier to understand the fuzzer without having to dig into FuzzContainer and FuzzInputReaderPolicy. InputReaderPolicyInterface::getReaderConfiguration is not called by any of the code being fuzzed, so it's unlikely that FuzzInputReaderPolicy::getReaderConfiguration will need to be modified to return a non-default InputReaderConfiguration in future. Bug: 245989146 Test: build and briefly run all modified fuzzers $ SANITIZE_TARGET=hwaddress make ${FUZZER_NAME} $ cd $ANDROID_PRODUCT_OUT $ adb root $ adb sync data $ adb shell /data/fuzz/$(get_build_var TARGET_ARCH)/${FUZZER_NAME}/${FUZZER_NAME} Change-Id: If933e1ce81439831b24c61dde1c2d24ed1a00942 --- .../inputflinger/tests/fuzzers/CursorInputFuzzer.cpp | 3 ++- services/inputflinger/tests/fuzzers/FuzzContainer.h | 11 +++-------- .../tests/fuzzers/KeyboardInputFuzzer.cpp | 7 ++++--- .../tests/fuzzers/MultiTouchInputFuzzer.cpp | 3 ++- .../inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp | 4 ++-- .../tests/fuzzers/TouchpadInputFuzzer.cpp | 3 ++- 6 files changed, 15 insertions(+), 16 deletions(-) diff --git a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp index 993f6a8e5c..e93b5929c7 100644 --- a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp @@ -16,6 +16,7 @@ #include #include +#include #include namespace android { @@ -39,7 +40,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::make_shared(data, size); FuzzContainer fuzzer(fdp); - auto policyConfig = fuzzer.getPolicyConfig(); + InputReaderConfiguration policyConfig; CursorInputMapper& mapper = fuzzer.getMapper(policyConfig); // Loop through mapper operations until randomness is exhausted. diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h index 0869b9fee7..ade53281a6 100644 --- a/services/inputflinger/tests/fuzzers/FuzzContainer.h +++ b/services/inputflinger/tests/fuzzers/FuzzContainer.h @@ -25,11 +25,9 @@ namespace android { class FuzzContainer { std::shared_ptr mFuzzEventHub; - sp mFuzzPolicy; FuzzInputListener mFuzzListener; std::unique_ptr mFuzzContext; std::unique_ptr mFuzzDevice; - InputReaderConfiguration mPolicyConfig; std::shared_ptr mFdp; public: @@ -42,8 +40,8 @@ public: // Create mocked objects. mFuzzEventHub = std::make_shared(mFdp); - mFuzzPolicy = sp::make(mFdp); - mFuzzContext = std::make_unique(mFuzzEventHub, mFuzzPolicy, + sp policy = sp::make(mFdp); + mFuzzContext = std::make_unique(mFuzzEventHub, policy, mFuzzListener, mFdp); InputDeviceIdentifier identifier; @@ -51,7 +49,6 @@ public: identifier.location = deviceLocation; mFuzzDevice = std::make_unique(mFuzzContext.get(), deviceID, deviceGeneration, identifier); - mFuzzPolicy->getReaderConfiguration(&mPolicyConfig); } ~FuzzContainer() {} @@ -59,7 +56,7 @@ public: void configureDevice() { nsecs_t arbitraryTime = mFdp->ConsumeIntegral(); std::list out; - out += mFuzzDevice->configure(arbitraryTime, mPolicyConfig, /*changes=*/{}); + out += mFuzzDevice->configure(arbitraryTime, /*readerConfig=*/{}, /*changes=*/{}); out += mFuzzDevice->reset(arbitraryTime); for (const NotifyArgs& args : out) { mFuzzListener.notify(args); @@ -71,8 +68,6 @@ public: configureDevice(); } - InputReaderConfiguration& getPolicyConfig() { return mPolicyConfig; } - void setAbsoluteAxisInfo(int axis, const RawAbsoluteAxisInfo& axisInfo) { mFuzzEventHub->setAbsoluteAxisInfo(mFuzzDevice->getId(), axis, axisInfo); } diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp index d11e8ae24a..54977df2ed 100644 --- a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -45,9 +46,9 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::make_shared(data, size); FuzzContainer fuzzer(fdp); - auto policyConfig = fuzzer.getPolicyConfig(); KeyboardInputMapper& mapper = - fuzzer.getMapper(policyConfig, fdp->ConsumeIntegral(), + fuzzer.getMapper(InputReaderConfiguration{}, + fdp->ConsumeIntegral(), fdp->ConsumeIntegral()); // Loop through mapper operations until randomness is exhausted. @@ -65,7 +66,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { [&]() -> void { mapper.getSources(); }, [&]() -> void { std::list unused = - mapper.reconfigure(fdp->ConsumeIntegral(), policyConfig, + mapper.reconfigure(fdp->ConsumeIntegral(), /*readerConfig=*/{}, InputReaderConfiguration::Change( fdp->ConsumeIntegral())); }, diff --git a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp index 494b0efe79..569767f8c0 100644 --- a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -62,7 +63,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::make_shared(data, size); FuzzContainer fuzzer(fdp); - auto policyConfig = fuzzer.getPolicyConfig(); + InputReaderConfiguration policyConfig; MultiTouchInputMapper& mapper = fuzzer.getMapper(policyConfig); // Loop through mapper operations until randomness is exhausted. diff --git a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp index 381e7b5f8f..80eebd58e3 100644 --- a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include @@ -25,8 +26,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::make_shared(data, size); FuzzContainer fuzzer(fdp); - auto policyConfig = fuzzer.getPolicyConfig(); - SwitchInputMapper& mapper = fuzzer.getMapper(policyConfig); + SwitchInputMapper& mapper = fuzzer.getMapper(InputReaderConfiguration{}); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { diff --git a/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp index ef9663a8d6..796178addd 100644 --- a/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -133,7 +134,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { setAxisInfos(*fdp, fuzzer); setDeviceSpecificConfig(*fdp, fuzzer); - auto policyConfig = fuzzer.getPolicyConfig(); + InputReaderConfiguration policyConfig; // Some settings are fuzzed here, as well as in the main loop, to provide randomized data to the // TouchpadInputMapper constructor. setTouchpadSettings(*fdp, policyConfig); -- GitLab From 2af5b035a31bed75646e1f3ea18bfb98fbde3c22 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 10 Jul 2023 18:52:17 -0700 Subject: [PATCH 0271/1187] Use EventEntry fields as defaults for DispatchEntry When DispatchEntry is getting constructed, set some of its fields to the equivalents from EventEntry. Otherwise, currently, these are set to invalid values (0), which causes confusion during development. Bug: 211379801 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: Iddde9e7683caa94c2c1d7a1d8dfef1487ed67ba4 --- services/inputflinger/dispatcher/Entry.cpp | 23 ++++++++++++++++++- .../dispatcher/InputDispatcher.cpp | 6 ----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index a0f0dcb221..cb369a836e 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -321,7 +321,28 @@ DispatchEntry::DispatchEntry(std::shared_ptr eventEntry, globalScaleFactor(globalScaleFactor), deliveryTime(0), resolvedAction(0), - resolvedFlags(0) {} + resolvedFlags(0) { + switch (this->eventEntry->type) { + case EventEntry::Type::KEY: { + const KeyEntry& keyEntry = static_cast(*this->eventEntry); + resolvedEventId = keyEntry.id; + resolvedAction = keyEntry.action; + resolvedFlags = keyEntry.flags; + + break; + } + case EventEntry::Type::MOTION: { + const MotionEntry& motionEntry = static_cast(*this->eventEntry); + resolvedEventId = motionEntry.id; + resolvedAction = motionEntry.action; + resolvedFlags = motionEntry.flags; + break; + } + default: { + break; + } + } +} uint32_t DispatchEntry::nextSeq() { // Sequence number 0 is reserved and will never be returned. diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 1d9c5b4228..1a228d3c22 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3302,10 +3302,6 @@ void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr(newEntry); - dispatchEntry->resolvedEventId = keyEntry.id; - dispatchEntry->resolvedAction = keyEntry.action; - dispatchEntry->resolvedFlags = keyEntry.flags; - if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { LOG(WARNING) << "channel " << connection->getInputChannelName() @@ -3333,7 +3329,6 @@ void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptrresolvedAction = AMOTION_EVENT_ACTION_DOWN; } else { - dispatchEntry->resolvedAction = motionEntry.action; dispatchEntry->resolvedEventId = motionEntry.id; } if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE && @@ -3349,7 +3344,6 @@ void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptrresolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; } - dispatchEntry->resolvedFlags = motionEntry.flags; if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_CANCEL) { dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_CANCELED; } -- GitLab From 0fa7cbb9f2f131de58e76222f044670adc18456c Mon Sep 17 00:00:00 2001 From: Prashanth Swaminathan Date: Tue, 11 Jul 2023 10:53:21 -0700 Subject: [PATCH 0272/1187] Fix lint error for IFTTT rule Change-Id: Ieb1718b41b238a9b62f142d2d2dad0ed4cb0d8ed --- include/android/sensor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/android/sensor.h b/include/android/sensor.h index 16c5dde60f..a729dbcecc 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -658,7 +658,7 @@ typedef struct ASensorEvent { uint32_t flags; int32_t reserved1[3]; } ASensorEvent; -// LINT.ThenChange (hardware/libhardware/include/hardware/sensors.h) +// LINT.ThenChange(hardware/libhardware/include/hardware/sensors.h) struct ASensorManager; /** -- GitLab From 8b75d50c245c097b3a2dc27359ace8c0fe2b4261 Mon Sep 17 00:00:00 2001 From: Prashanth Swaminathan Date: Tue, 11 Jul 2023 10:48:18 -0700 Subject: [PATCH 0273/1187] Add sys/cdefs and __REMOVED_IN define to looper.h The looper.h header introduced __REMOVED_IN, which requires the sys/cdefs.h header to provide definitions for the macro. Add them here and update files that include looper.h to not provide their own definitions of __REMOVED_IN. Further, update comments to clarify that the additional defines are in place to satisfy builds that use glibc or Windows/MacOS libcs. Bug: 14257980 Change-Id: Ia524b7e180c5137e84c205a77dc219b9e9e41608 --- include/android/input.h | 8 ++------ include/android/looper.h | 8 ++++++++ include/android/sensor.h | 9 ++++----- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/include/android/input.h b/include/android/input.h index 9a0eb4d838..16d86af44c 100644 --- a/include/android/input.h +++ b/include/android/input.h @@ -54,16 +54,12 @@ #include #include #include - -// This file is included by modules that have host support but android/looper.h is not supported -// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled. -#ifndef __BIONIC__ -#define __REMOVED_IN(x) __attribute__((deprecated)) -#endif #include #include +// This file may also be built on glibc or on Windows/MacOS libc's, so no-op +// definitions are provided. #if !defined(__INTRODUCED_IN) #define __INTRODUCED_IN(__api_level) /* nothing */ #endif diff --git a/include/android/looper.h b/include/android/looper.h index 4fe142a8e2..e50730d5c1 100644 --- a/include/android/looper.h +++ b/include/android/looper.h @@ -26,10 +26,18 @@ #ifndef ANDROID_LOOPER_H #define ANDROID_LOOPER_H +#include + #ifdef __cplusplus extern "C" { #endif +// This file may also be built on glibc or on Windows/MacOS libc's, so +// deprecated definitions are provided. +#if !defined(__REMOVED_IN) +#define __REMOVED_IN(__api_level) __attribute__((__deprecated__)) +#endif + struct ALooper; /** * ALooper diff --git a/include/android/sensor.h b/include/android/sensor.h index a729dbcecc..a618393e66 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -29,6 +29,8 @@ #ifndef ANDROID_SENSOR_H #define ANDROID_SENSOR_H +#include + /****************************************************************** * * IMPORTANT NOTICE: @@ -45,11 +47,6 @@ * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES */ -// This file is included by modules that have host support but android/looper.h is not supported -// on host. __REMOVED_IN needs to be defined in order for android/looper.h to be compiled. -#ifndef __BIONIC__ -#define __REMOVED_IN(x) __attribute__((deprecated)) -#endif #include #include @@ -57,6 +54,8 @@ #include #include +// This file may also be built on glibc or on Windows/MacOS libc's, so no-op +// and deprecated definitions are provided. #if !defined(__INTRODUCED_IN) #define __INTRODUCED_IN(__api_level) /* nothing */ #endif -- GitLab From 4dee617664a40ddbe05500b5efe57effcf314569 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 11 Jul 2023 11:45:32 -0700 Subject: [PATCH 0274/1187] Remove empty if statement This statement has no body. Bug: 211379801 Test: none Change-Id: Ib65905d3c621eac620e63180b3d75274aeae32e0 --- services/inputflinger/dispatcher/InputDispatcher.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 1a228d3c22..a6aa8a112c 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2690,9 +2690,6 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( "Conflicting pointer actions: Hover received while pointer was down."); *outConflictingPointerActions = true; } - if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || - maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { - } } else if (maskedAction == AMOTION_EVENT_ACTION_UP) { // Pointer went up. tempTouchState.removeTouchingPointer(entry.deviceId, entry.pointerProperties[0].id); -- GitLab From 7e2f8f1835c261dd50f007bb194b33597050e28d Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 11 Jul 2023 10:51:20 -0700 Subject: [PATCH 0275/1187] Add type alias for DeviceId To facilitate the future transition to a strong type, add a "weak" type for DeviceId in this CL. This will allow us to fix some of the existing code before having to refactor all of it in a single topic. Also, in this CL, simplify the names of some variables in TouchState because we no longer have a conflict with the 'deviceId' member. Bug: 211379801 Test: none Change-Id: I1f287ad62fa26ba4bbbbbf353bebfbf8ad38ff67 --- include/input/Input.h | 15 +++--- .../inputflinger/dispatcher/InputState.cpp | 2 +- services/inputflinger/dispatcher/InputState.h | 6 +-- .../inputflinger/dispatcher/TouchState.cpp | 53 +++++++++---------- services/inputflinger/dispatcher/TouchState.h | 16 +++--- 5 files changed, 47 insertions(+), 45 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index 1fc9cb1207..a271f0c1f9 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -501,6 +501,9 @@ struct PointerProperties { PointerProperties& operator=(const PointerProperties&) = default; }; +// TODO(b/211379801) : Use a strong type from ftl/mixins.h instead +using DeviceId = int32_t; + /* * Input events. */ @@ -512,7 +515,7 @@ public: inline int32_t getId() const { return mId; } - inline int32_t getDeviceId() const { return mDeviceId; } + inline DeviceId getDeviceId() const { return mDeviceId; } inline uint32_t getSource() const { return mSource; } @@ -527,13 +530,13 @@ public: static int32_t nextId(); protected: - void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, + void initialize(int32_t id, DeviceId deviceId, uint32_t source, int32_t displayId, std::array hmac); void initialize(const InputEvent& from); int32_t mId; - int32_t mDeviceId; + DeviceId mDeviceId; uint32_t mSource; int32_t mDisplayId; std::array mHmac; @@ -571,7 +574,7 @@ public: static const char* getLabel(int32_t keyCode); static std::optional getKeyCodeFromLabel(const char* label); - void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, + void initialize(int32_t id, DeviceId deviceId, uint32_t source, int32_t displayId, std::array hmac, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime); @@ -835,7 +838,7 @@ public: ssize_t findPointerIndex(int32_t pointerId) const; - void initialize(int32_t id, int32_t deviceId, uint32_t source, int32_t displayId, + void initialize(int32_t id, DeviceId deviceId, uint32_t source, int32_t displayId, std::array hmac, int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, MotionClassification classification, const ui::Transform& transform, @@ -1013,7 +1016,7 @@ struct __attribute__((__packed__)) VerifiedInputEvent { }; Type type; - int32_t deviceId; + DeviceId deviceId; nsecs_t eventTimeNanos; uint32_t source; int32_t displayId; diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index fe0b89c025..e6941ef027 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -28,7 +28,7 @@ InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerato InputState::~InputState() {} -bool InputState::isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const { +bool InputState::isHovering(DeviceId deviceId, uint32_t source, int32_t displayId) const { for (const MotionMemento& memento : mMotionMementos) { if (memento.deviceId == deviceId && memento.source == source && memento.displayId == displayId && memento.hovering) { diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h index af2a3cbc93..e741137103 100644 --- a/services/inputflinger/dispatcher/InputState.h +++ b/services/inputflinger/dispatcher/InputState.h @@ -36,7 +36,7 @@ public: // Returns true if the specified source is known to have received a hover enter // motion event. - bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const; + bool isHovering(DeviceId deviceId, uint32_t source, int32_t displayId) const; // Records tracking information for a key event that has just been published. // Returns true if the event should be delivered, false if it is inconsistent @@ -76,7 +76,7 @@ public: private: struct KeyMemento { - int32_t deviceId; + DeviceId deviceId; uint32_t source; int32_t displayId; int32_t keyCode; @@ -88,7 +88,7 @@ private: }; struct MotionMemento { - int32_t deviceId; + DeviceId deviceId; uint32_t source; int32_t displayId; int32_t flags; diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index dadfdc122a..4221e42ae5 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -40,25 +40,25 @@ std::set TouchState::getActiveDeviceIds() const { return out; } -bool TouchState::hasTouchingPointers(int32_t deviceId) const { +bool TouchState::hasTouchingPointers(DeviceId deviceId) const { return std::any_of(windows.begin(), windows.end(), [&](const TouchedWindow& window) { return window.hasTouchingPointers(deviceId); }); } -void TouchState::removeTouchingPointer(int32_t removedDeviceId, int32_t pointerId) { +void TouchState::removeTouchingPointer(DeviceId deviceId, int32_t pointerId) { for (TouchedWindow& touchedWindow : windows) { - touchedWindow.removeTouchingPointer(removedDeviceId, pointerId); + touchedWindow.removeTouchingPointer(deviceId, pointerId); } clearWindowsWithoutPointers(); } void TouchState::removeTouchingPointerFromWindow( - int32_t removedDeviceId, int32_t pointerId, + DeviceId deviceId, int32_t pointerId, const sp& windowHandle) { for (TouchedWindow& touchedWindow : windows) { if (touchedWindow.windowHandle == windowHandle) { - touchedWindow.removeTouchingPointer(removedDeviceId, pointerId); + touchedWindow.removeTouchingPointer(deviceId, pointerId); clearWindowsWithoutPointers(); return; } @@ -79,8 +79,7 @@ void TouchState::clearWindowsWithoutPointers() { } void TouchState::addOrUpdateWindow(const sp& windowHandle, - ftl::Flags targetFlags, - int32_t addedDeviceId, + ftl::Flags targetFlags, DeviceId deviceId, std::bitset touchingPointerIds, std::optional firstDownTimeInTarget) { for (TouchedWindow& touchedWindow : windows) { @@ -94,9 +93,9 @@ void TouchState::addOrUpdateWindow(const sp& windowHandle, // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have // downTime set initially. Need to update existing window when a pointer is down for the // window. - touchedWindow.addTouchingPointers(addedDeviceId, touchingPointerIds); + touchedWindow.addTouchingPointers(deviceId, touchingPointerIds); if (firstDownTimeInTarget) { - touchedWindow.trySetDownTimeInTarget(addedDeviceId, *firstDownTimeInTarget); + touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget); } return; } @@ -104,25 +103,25 @@ void TouchState::addOrUpdateWindow(const sp& windowHandle, TouchedWindow touchedWindow; touchedWindow.windowHandle = windowHandle; touchedWindow.targetFlags = targetFlags; - touchedWindow.addTouchingPointers(addedDeviceId, touchingPointerIds); + touchedWindow.addTouchingPointers(deviceId, touchingPointerIds); if (firstDownTimeInTarget) { - touchedWindow.trySetDownTimeInTarget(addedDeviceId, *firstDownTimeInTarget); + touchedWindow.trySetDownTimeInTarget(deviceId, *firstDownTimeInTarget); } windows.push_back(touchedWindow); } void TouchState::addHoveringPointerToWindow(const sp& windowHandle, - int32_t hoveringDeviceId, int32_t hoveringPointerId) { + DeviceId deviceId, int32_t hoveringPointerId) { for (TouchedWindow& touchedWindow : windows) { if (touchedWindow.windowHandle == windowHandle) { - touchedWindow.addHoveringPointer(hoveringDeviceId, hoveringPointerId); + touchedWindow.addHoveringPointer(deviceId, hoveringPointerId); return; } } TouchedWindow touchedWindow; touchedWindow.windowHandle = windowHandle; - touchedWindow.addHoveringPointer(hoveringDeviceId, hoveringPointerId); + touchedWindow.addHoveringPointer(deviceId, hoveringPointerId); windows.push_back(touchedWindow); } @@ -149,12 +148,12 @@ void TouchState::filterNonAsIsTouchWindows() { } } -void TouchState::cancelPointersForWindowsExcept(int32_t touchedDeviceId, +void TouchState::cancelPointersForWindowsExcept(DeviceId deviceId, std::bitset pointerIds, const sp& token) { std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) { if (w.windowHandle->getToken() != token) { - w.removeTouchingPointers(touchedDeviceId, pointerIds); + w.removeTouchingPointers(deviceId, pointerIds); } }); clearWindowsWithoutPointers(); @@ -168,10 +167,10 @@ void TouchState::cancelPointersForWindowsExcept(int32_t touchedDeviceId, */ void TouchState::cancelPointersForNonPilferingWindows() { // First, find all pointers that are being pilfered, across all windows - std::map> allPilferedPointerIdsByDevice; + std::map> allPilferedPointerIdsByDevice; for (const TouchedWindow& w : windows) { - for (const auto& [iterDeviceId, pilferedPointerIds] : w.getPilferingPointers()) { - allPilferedPointerIdsByDevice[iterDeviceId] |= pilferedPointerIds; + for (const auto& [deviceId, pilferedPointerIds] : w.getPilferingPointers()) { + allPilferedPointerIdsByDevice[deviceId] |= pilferedPointerIds; } }; @@ -183,12 +182,12 @@ void TouchState::cancelPointersForNonPilferingWindows() { // (only), the remove pointer 2 from window A and pointer 1 from window B. Usually, the set of // pilfered pointers will be disjoint across all windows, but there's no reason to cause that // limitation here. - for (const auto& [iterDeviceId, allPilferedPointerIds] : allPilferedPointerIdsByDevice) { + for (const auto& [deviceId, allPilferedPointerIds] : allPilferedPointerIdsByDevice) { std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) { std::bitset pilferedByOtherWindows = - w.getPilferingPointers(iterDeviceId) ^ allPilferedPointerIds; + w.getPilferingPointers(deviceId) ^ allPilferedPointerIds; // Remove all pointers pilfered by other windows - w.removeTouchingPointers(iterDeviceId, pilferedByOtherWindows); + w.removeTouchingPointers(deviceId, pilferedByOtherWindows); }); } clearWindowsWithoutPointers(); @@ -248,11 +247,11 @@ bool TouchState::hasHoveringPointers() const { [](const TouchedWindow& window) { return window.hasHoveringPointers(); }); } -std::set> TouchState::getWindowsWithHoveringPointer(int32_t hoveringDeviceId, +std::set> TouchState::getWindowsWithHoveringPointer(DeviceId deviceId, int32_t pointerId) const { std::set> out; for (const TouchedWindow& window : windows) { - if (window.hasHoveringPointer(hoveringDeviceId, pointerId)) { + if (window.hasHoveringPointer(deviceId, pointerId)) { out.insert(window.windowHandle); } } @@ -266,10 +265,10 @@ void TouchState::removeHoveringPointer(int32_t hoveringDeviceId, int32_t hoverin clearWindowsWithoutPointers(); } -void TouchState::removeAllPointersForDevice(int32_t removedDeviceId) { +void TouchState::removeAllPointersForDevice(DeviceId deviceId) { for (TouchedWindow& window : windows) { - window.removeAllHoveringPointersForDevice(removedDeviceId); - window.removeAllTouchingPointersForDevice(removedDeviceId); + window.removeAllHoveringPointersForDevice(deviceId); + window.removeAllTouchingPointersForDevice(deviceId); } clearWindowsWithoutPointers(); diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 9f29a4aa71..25b9643528 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -41,24 +41,24 @@ struct TouchState { std::set getActiveDeviceIds() const; bool hasTouchingPointers(int32_t device) const; - void removeTouchingPointer(int32_t deviceId, int32_t pointerId); - void removeTouchingPointerFromWindow(int32_t deviceId, int32_t pointerId, + void removeTouchingPointer(DeviceId deviceId, int32_t pointerId); + void removeTouchingPointerFromWindow(DeviceId deviceId, int32_t pointerId, const sp& windowHandle); void addOrUpdateWindow(const sp& windowHandle, - ftl::Flags targetFlags, int32_t deviceId, + ftl::Flags targetFlags, DeviceId deviceId, std::bitset touchingPointerIds, std::optional firstDownTimeInTarget = std::nullopt); void addHoveringPointerToWindow(const sp& windowHandle, - int32_t deviceId, int32_t hoveringPointerId); - void removeHoveringPointer(int32_t deviceId, int32_t hoveringPointerId); + DeviceId deviceId, int32_t hoveringPointerId); + void removeHoveringPointer(DeviceId deviceId, int32_t hoveringPointerId); void clearHoveringPointers(); - void removeAllPointersForDevice(int32_t deviceId); + void removeAllPointersForDevice(DeviceId deviceId); void removeWindowByToken(const sp& token); void filterNonAsIsTouchWindows(); // Cancel pointers for current set of windows except the window with particular binder token. - void cancelPointersForWindowsExcept(int32_t deviceId, + void cancelPointersForWindowsExcept(DeviceId deviceId, std::bitset pointerIds, const sp& token); // Cancel pointers for current set of non-pilfering windows i.e. windows with isPilferingWindow @@ -75,7 +75,7 @@ struct TouchState { bool hasHoveringPointers() const; std::set> getWindowsWithHoveringPointer( - int32_t deviceId, int32_t pointerId) const; + DeviceId deviceId, int32_t pointerId) const; std::string dump() const; }; -- GitLab From a7dfda102226b7fd7499300a1c92c44512bc9d7f Mon Sep 17 00:00:00 2001 From: Josep del Rio Date: Wed, 12 Jul 2023 10:52:52 +0000 Subject: [PATCH 0276/1187] Add component to the input tests presubmit module As part of the trunkstable migration, we need to add a component to the OWNERS file of the input tests modules. Bug: 288143062 Bug: 288142414 Test: not needed Change-Id: I06f6d395e83ef0ddc95f81088eef8d0181c84eea --- services/inputflinger/OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/services/inputflinger/OWNERS b/services/inputflinger/OWNERS index c88bfe97ca..21d208f577 100644 --- a/services/inputflinger/OWNERS +++ b/services/inputflinger/OWNERS @@ -1 +1,2 @@ +# Bug component: 136048 include platform/frameworks/base:/INPUT_OWNERS -- GitLab From a1667e50a8b53f341f45de71dfae2e98dbc006a8 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Wed, 12 Jul 2023 20:42:35 +0000 Subject: [PATCH 0277/1187] Use service fuzzer defaults in fuzzers Using service fuzzer defaults in fuzzers which are using fuzzService API to monitor code coverage and bugs filed by fuzzers. Bug: 232439428 Test: m libgui_surfaceComposer_fuzzer libgui_surfaceComposerClient_fuzzer Change-Id: I576b56ec64912e349fd72e8d31cef0f3332cfe45 --- libs/gui/fuzzer/Android.bp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp index 75bae7650f..073cc08bff 100644 --- a/libs/gui/fuzzer/Android.bp +++ b/libs/gui/fuzzer/Android.bp @@ -90,6 +90,7 @@ cc_fuzz { ], defaults: [ "libgui_fuzzer_defaults", + "service_fuzzer_defaults", ], } @@ -100,6 +101,7 @@ cc_fuzz { ], defaults: [ "libgui_fuzzer_defaults", + "service_fuzzer_defaults", ], } -- GitLab From 9ea031229b7874584ac7fb00a5fc58ad5b073648 Mon Sep 17 00:00:00 2001 From: Brian Johnson Date: Fri, 30 Jun 2023 14:46:34 -0700 Subject: [PATCH 0278/1187] SF: Update unit test to pass non-default mocks. Update tests to pass non-default mocks so that surfaceflinger internals can be more accurately tested, allowing for testing for division by vsync Test: on main: lunch cf_x86_64_phone-userdebug && atest DisplayModeSwitchingTest#changeRefreshRate_OnActiveDisplay_WithoutRefreshRequired Bug: 278035063 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:f626c2f99cdc39266921642eb10d823472c2d74f) Merged-In: Ica4009c30940dad7a8b1dced712223e8eaabc99a Change-Id: Ica4009c30940dad7a8b1dced712223e8eaabc99a --- .../SurfaceFlinger_DisplayModeSwitching.cpp | 10 +++++++++- .../tests/unittests/TestableSurfaceFlinger.h | 17 ++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index e17654602b..703bdda694 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -49,9 +49,17 @@ public: mFlinger.onComposerHalHotplug(PrimaryDisplayVariant::HWC_DISPLAY_ID, Connection::CONNECTED); mFlinger.configureAndCommit(); + auto vsyncController = std::make_unique(); + auto vsyncTracker = std::make_shared(); + + EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0)); + EXPECT_CALL(*vsyncTracker, currentPeriod()) + .WillRepeatedly(Return( + TestableSurfaceFlinger::FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); + mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this) .setRefreshRateSelector(std::move(selectorPtr)) - .inject(); + .inject(std::move(vsyncController), std::move(vsyncTracker)); // isVsyncPeriodSwitchSupported should return true, otherwise the SF's HWC proxy // will call setActiveConfig instead of setActiveConfigWithConstraints. diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 5be45489c2..909b8b8964 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -55,6 +55,12 @@ #include "mock/MockSchedulerCallback.h" #include "mock/system/window/MockNativeWindow.h" +#include "Scheduler/VSyncTracker.h" +#include "Scheduler/VsyncController.h" +#include "mock/MockVSyncDispatch.h" +#include "mock/MockVSyncTracker.h" +#include "mock/MockVsyncController.h" + namespace android { struct DisplayStatInfo; @@ -911,6 +917,13 @@ public: } sp inject() NO_THREAD_SAFETY_ANALYSIS { + return inject(std::make_unique(), + std::make_shared()); + } + + sp inject(std::unique_ptr controller, + std::shared_ptr tracker) + NO_THREAD_SAFETY_ANALYSIS { const auto displayId = mCreationArgs.compositionDisplay->getDisplayId(); auto& modes = mDisplayModes; @@ -975,7 +988,9 @@ public: if (mFlinger.scheduler() && mRegisterDisplay) { mFlinger.scheduler()->registerDisplay(physicalId, - display->holdRefreshRateSelector()); + display->holdRefreshRateSelector(), + std::move(controller), + std::move(tracker)); } display->setActiveMode(activeModeId, fps, fps); -- GitLab From 6cc025ba652f25db0411cfbfe890284c1d4b43a3 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Thu, 13 Jul 2023 00:48:19 +0000 Subject: [PATCH 0279/1187] Remove event thread connection metric. It's not an actionable metric and is causing performance problems due to lock contention. So, remove the code. Bug: 170661858 Test: builds Change-Id: I70fc2772d2cfa1c8364775427b1e8f08ce4ca0ff --- .../surfaceflinger/Scheduler/EventThread.cpp | 5 ---- .../surfaceflinger/Scheduler/EventThread.h | 5 ---- .../surfaceflinger/Scheduler/Scheduler.cpp | 6 ----- services/surfaceflinger/Scheduler/Scheduler.h | 2 -- services/surfaceflinger/SurfaceFlinger.cpp | 4 --- .../surfaceflinger/TimeStats/TimeStats.cpp | 14 ++--------- services/surfaceflinger/TimeStats/TimeStats.h | 4 --- .../include/timestatsproto/TimeStatsHelper.h | 1 - .../tests/unittests/EventThreadTest.cpp | 25 ------------------- .../tests/unittests/SchedulerTest.cpp | 4 --- .../tests/unittests/TimeStatsTest.cpp | 3 --- .../tests/unittests/mock/MockEventThread.h | 1 - .../tests/unittests/mock/MockTimeStats.h | 1 - 13 files changed, 2 insertions(+), 73 deletions(-) diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 281b0ae559..c70ed2c544 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -427,11 +427,6 @@ void EventThread::onFrameRateOverridesChanged(PhysicalDisplayId displayId, mCondition.notify_all(); } -size_t EventThread::getEventThreadConnectionCount() { - std::lock_guard lock(mMutex); - return mDisplayEventConnections.size(); -} - void EventThread::threadMain(std::unique_lock& lock) { DisplayEventConsumers consumers; diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 684745b71b..7023445581 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -131,9 +131,6 @@ public: virtual VsyncEventData getLatestVsyncEventData( const sp& connection) const = 0; - // Retrieves the number of event connections tracked by this EventThread. - virtual size_t getEventThreadConnectionCount() = 0; - virtual void onNewVsyncSchedule(std::shared_ptr) = 0; }; @@ -172,8 +169,6 @@ public: void setDuration(std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) override; - size_t getEventThreadConnectionCount() override; - void onNewVsyncSchedule(std::shared_ptr) override EXCLUDES(mMutex); private: diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 0a1bd4c519..08667bfdec 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -393,12 +393,6 @@ void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, const Fr thread->onModeChanged(mode); } -size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) { - std::lock_guard lock(mConnectionsLock); - RETURN_IF_INVALID_HANDLE(handle, 0); - return mConnections[handle].thread->getEventThreadConnectionCount(); -} - void Scheduler::dump(ConnectionHandle handle, std::string& result) const { android::EventThread* thread; { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index c44c447d90..0ffa2d2022 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -278,8 +278,6 @@ public: // Notifies the scheduler when the display size has changed. Called from SF's main thread void onActiveDisplayAreaChanged(uint32_t displayArea); - size_t getEventThreadConnectionCount(ConnectionHandle handle); - // Stores the preferred refresh rate that an app should run at. // FrameRateOverride.refreshRateHz == 0 means no preference. void setPreferredRefreshRateForUid(FrameRateOverride); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2782ce4ce4..8c53c42974 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3002,10 +3002,6 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa } } - const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle); - const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle); - mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections); - if (isDisplayConnected && !defaultDisplay->isPoweredOn()) { getRenderEngine().cleanupPostRender(); return; diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index 630cef1fd4..368cb41779 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -106,7 +106,8 @@ bool TimeStats::populateGlobalAtom(std::vector* pulledData) { atom->set_client_composition_frames(mTimeStats.clientCompositionFramesLegacy); atom->set_display_on_millis(mTimeStats.displayOnTimeLegacy); atom->set_animation_millis(mTimeStats.presentToPresentLegacy.totalTime()); - atom->set_event_connection_count(mTimeStats.displayEventConnectionsCountLegacy); + // Deprecated + atom->set_event_connection_count(0); *atom->mutable_frame_duration() = histogramToProto(mTimeStats.frameDurationLegacy.hist, mMaxPulledHistogramBuckets); *atom->mutable_render_engine_timing() = @@ -356,16 +357,6 @@ void TimeStats::incrementRefreshRateSwitches() { mTimeStats.refreshRateSwitchesLegacy++; } -void TimeStats::recordDisplayEventConnectionCount(int32_t count) { - if (!mEnabled.load()) return; - - ATRACE_CALL(); - - std::lock_guard lock(mMutex); - mTimeStats.displayEventConnectionsCountLegacy = - std::max(mTimeStats.displayEventConnectionsCountLegacy, count); -} - static int32_t toMs(nsecs_t nanos) { int64_t millis = std::chrono::duration_cast(std::chrono::nanoseconds(nanos)) @@ -1072,7 +1063,6 @@ void TimeStats::clearGlobalLocked() { mTimeStats.compositionStrategyPredictedLegacy = 0; mTimeStats.compositionStrategyPredictionSucceededLegacy = 0; mTimeStats.refreshRateSwitchesLegacy = 0; - mTimeStats.displayEventConnectionsCountLegacy = 0; mTimeStats.displayOnTimeLegacy = 0; mTimeStats.presentToPresentLegacy.hist.clear(); mTimeStats.frameDurationLegacy.hist.clear(); diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 5f586577ac..0c227d4168 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -57,9 +57,6 @@ public: virtual void incrementMissedFrames() = 0; // Increments the number of times the display refresh rate changed. virtual void incrementRefreshRateSwitches() = 0; - // Records the most up-to-date count of display event connections. - // The stored count will be the maximum ever recoded. - virtual void recordDisplayEventConnectionCount(int32_t count) = 0; // Records the start and end times for a frame. // The start time is the same as the beginning of a SurfaceFlinger @@ -253,7 +250,6 @@ public: void incrementTotalFrames() override; void incrementMissedFrames() override; void incrementRefreshRateSwitches() override; - void recordDisplayEventConnectionCount(int32_t count) override; void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override; void recordRenderEngineDuration(nsecs_t startTime, nsecs_t endTime) override; diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h index 60aa810e8b..9e97f0db71 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h +++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h @@ -175,7 +175,6 @@ public: int32_t clientCompositionReusedFramesLegacy = 0; int32_t refreshRateSwitchesLegacy = 0; int32_t compositionStrategyChangesLegacy = 0; - int32_t displayEventConnectionsCountLegacy = 0; int64_t displayOnTimeLegacy = 0; Histogram presentToPresentLegacy; Histogram frameDurationLegacy; diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 5fed9b45a6..91c6239c87 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -634,31 +634,6 @@ TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) { expectVSyncCallbackScheduleReceived(false); } -TEST_F(EventThreadTest, tracksEventConnections) { - setupEventThread(VSYNC_PERIOD); - - EXPECT_EQ(2, mThread->getEventThreadConnectionCount()); - ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY}; - sp errorConnection = createConnection(errorConnectionEventRecorder); - mThread->setVsyncRate(1, errorConnection); - EXPECT_EQ(3, mThread->getEventThreadConnectionCount()); - ConnectionEventRecorder secondConnectionEventRecorder{0}; - sp secondConnection = - createConnection(secondConnectionEventRecorder); - mThread->setVsyncRate(1, secondConnection); - EXPECT_EQ(4, mThread->getEventThreadConnectionCount()); - - // EventThread should enable vsync callbacks. - expectVSyncCallbackScheduleReceived(true); - - // The first event will be seen by the connection, which then returns an error. - onVSyncEvent(123, 456, 789); - expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u); - expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123, - 1u); - EXPECT_EQ(3, mThread->getEventThreadConnectionCount()); -} - TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) { setupEventThread(VSYNC_PERIOD); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 405f79d290..3200003eda 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -158,10 +158,6 @@ TEST_F(SchedulerTest, validConnectionHandle) { EXPECT_CALL(*mEventThread, setDuration(10ns, 20ns)).Times(1); mScheduler->setDuration(mConnectionHandle, 10ns, 20ns); - - static constexpr size_t kEventConnections = 5; - EXPECT_CALL(*mEventThread, getEventThreadConnectionCount()).WillOnce(Return(kEventConnections)); - EXPECT_EQ(kEventConnections, mScheduler->getEventThreadConnectionCount(mConnectionHandle)); } TEST_F(SchedulerTest, registerDisplay) FTL_FAKE_GUARD(kMainThreadContext) { diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index a9ae1d3da3..86ed233a0a 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -1079,7 +1079,6 @@ TEST_F(TimeStatsTest, globalStatsCallback) { constexpr size_t TOTAL_FRAMES = 5; constexpr size_t MISSED_FRAMES = 4; constexpr size_t CLIENT_COMPOSITION_FRAMES = 3; - constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14; constexpr nsecs_t DISPLAY_DEADLINE_DELTA = 1'000'000; constexpr nsecs_t DISPLAY_PRESENT_JITTER = 2'000'000; constexpr nsecs_t APP_DEADLINE_DELTA = 3'000'000; @@ -1100,7 +1099,6 @@ TEST_F(TimeStatsTest, globalStatsCallback) { insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); - mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS); mTimeStats->setPowerMode(PowerMode::ON); mTimeStats->recordFrameDuration(1000000, 3000000); mTimeStats->recordRenderEngineDuration(2000000, 4000000); @@ -1157,7 +1155,6 @@ TEST_F(TimeStatsTest, globalStatsCallback) { EXPECT_EQ(atom.client_composition_frames(), CLIENT_COMPOSITION_FRAMES); // Display on millis is not checked. EXPECT_EQ(atom.animation_millis(), 2); - EXPECT_EQ(atom.event_connection_count(), DISPLAY_EVENT_CONNECTIONS); EXPECT_THAT(atom.frame_duration(), HistogramEq(buildExpectedHistogram({2}, {1}))); EXPECT_THAT(atom.render_engine_timing(), HistogramEq(buildExpectedHistogram({1, 2}, {1, 1}))); EXPECT_EQ(atom.total_timeline_frames(), 9); diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 8d57049219..9a1a16dd82 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -49,7 +49,6 @@ public: (const sp&), (const, override)); MOCK_METHOD(void, requestLatestConfig, (const sp&)); MOCK_METHOD(void, pauseVsyncCallback, (bool)); - MOCK_METHOD(size_t, getEventThreadConnectionCount, (), (override)); MOCK_METHOD(void, onNewVsyncSchedule, (std::shared_ptr), (override)); }; diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h index 86fbadc0f2..c82e45b5e8 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h @@ -34,7 +34,6 @@ public: MOCK_METHOD0(incrementTotalFrames, void()); MOCK_METHOD0(incrementMissedFrames, void()); MOCK_METHOD0(incrementRefreshRateSwitches, void()); - MOCK_METHOD1(recordDisplayEventConnectionCount, void(int32_t)); MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t)); MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t)); MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr&)); -- GitLab From 43d9afccaa932fd0d00623e63d13bcc874796b4e Mon Sep 17 00:00:00 2001 From: Carlos Martinez Romero Date: Fri, 7 Jul 2023 22:58:51 +0000 Subject: [PATCH 0280/1187] Add the basic files needed for an empty library. Test: None Bug: 290409936 Pair: jshargo Change-Id: I7a31fcbd3f1facc519e6020d17a9de3f1b2e3d91 --- libs/bufferstreams/README.md | 13 ++ libs/bufferstreams/include/bufferstreams.h | 13 ++ libs/bufferstreams/rust/Android.bp | 23 ++++ libs/bufferstreams/rust/Cargo.lock | 7 + libs/bufferstreams/rust/Cargo.toml | 6 + libs/bufferstreams/rust/cbindgen.toml | 149 +++++++++++++++++++++ libs/bufferstreams/rust/src/lib.rs | 22 +++ libs/bufferstreams/update_include.sh | 2 + 8 files changed, 235 insertions(+) create mode 100644 libs/bufferstreams/README.md create mode 100644 libs/bufferstreams/include/bufferstreams.h create mode 100644 libs/bufferstreams/rust/Android.bp create mode 100644 libs/bufferstreams/rust/Cargo.lock create mode 100644 libs/bufferstreams/rust/Cargo.toml create mode 100644 libs/bufferstreams/rust/cbindgen.toml create mode 100644 libs/bufferstreams/rust/src/lib.rs create mode 100755 libs/bufferstreams/update_include.sh diff --git a/libs/bufferstreams/README.md b/libs/bufferstreams/README.md new file mode 100644 index 0000000000..860adef281 --- /dev/null +++ b/libs/bufferstreams/README.md @@ -0,0 +1,13 @@ +# libbufferstreams: Reactive Streams for Graphics Buffers + +This library is currently **experimental** and **under active development**. +It is not production ready yet. + +For more information on reactive streams, please see + +## Contributing + +This library is natively written in Rust and exposes a C API. If you make changes to the Rust API, +you **must** update the C API in turn. To do so, with cbindgen installed, run: + +```$ ./update_include.sh``` diff --git a/libs/bufferstreams/include/bufferstreams.h b/libs/bufferstreams/include/bufferstreams.h new file mode 100644 index 0000000000..5308de24c0 --- /dev/null +++ b/libs/bufferstreams/include/bufferstreams.h @@ -0,0 +1,13 @@ +/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */ + +#include +#include +#include +#include +#include + + +/** + * This function will print Hello World. + */ +bool hello(void); diff --git a/libs/bufferstreams/rust/Android.bp b/libs/bufferstreams/rust/Android.bp new file mode 100644 index 0000000000..95a85b550f --- /dev/null +++ b/libs/bufferstreams/rust/Android.bp @@ -0,0 +1,23 @@ +// Copyright (C) 2023 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. + +rust_library { + name: "libbufferstreams", + crate_name: "bufferstreams", + srcs: ["src/lib.rs"], + edition: "2021", + vendor_available: true, + host_supported: true, + min_sdk_version: "30", +} diff --git a/libs/bufferstreams/rust/Cargo.lock b/libs/bufferstreams/rust/Cargo.lock new file mode 100644 index 0000000000..4482dba6cd --- /dev/null +++ b/libs/bufferstreams/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bufferstreams" +version = "0.1.0" diff --git a/libs/bufferstreams/rust/Cargo.toml b/libs/bufferstreams/rust/Cargo.toml new file mode 100644 index 0000000000..d30c55c551 --- /dev/null +++ b/libs/bufferstreams/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "bufferstreams" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/libs/bufferstreams/rust/cbindgen.toml b/libs/bufferstreams/rust/cbindgen.toml new file mode 100644 index 0000000000..eda837f360 --- /dev/null +++ b/libs/bufferstreams/rust/cbindgen.toml @@ -0,0 +1,149 @@ +# See https://github.com/eqrion/cbindgen/blob/master/docs.md#cbindgentoml +# for detailed documentation of every option here. + + + +language = "C" + + + +############## Options for Wrapping the Contents of the Header ################# + +# header = "/* Text to put at the beginning of the generated file. Probably a license. */" +# trailer = "/* Text to put at the end of the generated file */" +# include_guard = "my_bindings_h" +# pragma_once = true +autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" +include_version = false +# namespace = "my_namespace" +namespaces = [] +using_namespaces = [] +sys_includes = [] +includes = [] +no_includes = false +after_includes = "" + + + + +############################ Code Style Options ################################ + +braces = "SameLine" +line_length = 100 +tab_width = 2 +documentation = true +documentation_style = "auto" +documentation_length = "full" +line_endings = "LF" # also "CR", "CRLF", "Native" + + + + +############################# Codegen Options ################################## + +style = "both" +sort_by = "Name" # default for `fn.sort_by` and `const.sort_by` +usize_is_size_t = true + + + +[defines] +# "target_os = freebsd" = "DEFINE_FREEBSD" +# "feature = serde" = "DEFINE_SERDE" + + + +[export] +include = [] +exclude = [] +# prefix = "CAPI_" +item_types = [] +renaming_overrides_prefixing = false + + + +[export.rename] + + + +[export.body] + + +[export.mangle] + + +[fn] +rename_args = "None" +# must_use = "MUST_USE_FUNC" +# no_return = "NO_RETURN" +# prefix = "START_FUNC" +# postfix = "END_FUNC" +args = "auto" +sort_by = "Name" + + + + +[struct] +rename_fields = "None" +# must_use = "MUST_USE_STRUCT" +derive_constructor = false +derive_eq = false +derive_neq = false +derive_lt = false +derive_lte = false +derive_gt = false +derive_gte = false + + + + +[enum] +rename_variants = "None" +# must_use = "MUST_USE_ENUM" +add_sentinel = false +prefix_with_name = false +derive_helper_methods = false +derive_const_casts = false +derive_mut_casts = false +# cast_assert_name = "ASSERT" +derive_tagged_enum_destructor = false +derive_tagged_enum_copy_constructor = false +enum_class = true +private_default_tagged_enum_constructor = false + + + + +[const] +allow_static_const = true +allow_constexpr = false +sort_by = "Name" + + + + +[macro_expansion] +bitflags = false + + + + + + +############## Options for How Your Rust library Should Be Parsed ############## + +[parse] +parse_deps = false +# include = [] +exclude = [] +clean = false +extra_bindings = [] + + + +[parse.expand] +crates = [] +all_features = false +default_features = true +features = [] \ No newline at end of file diff --git a/libs/bufferstreams/rust/src/lib.rs b/libs/bufferstreams/rust/src/lib.rs new file mode 100644 index 0000000000..51f1c73c49 --- /dev/null +++ b/libs/bufferstreams/rust/src/lib.rs @@ -0,0 +1,22 @@ +// Copyright (C) 2023 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. + +//! libbufferstreams: Reactive Streams for Graphics Buffers + +/// This function will print Hello World. +#[no_mangle] +pub extern "C" fn hello() -> bool { + println!("Hello world."); + true +} diff --git a/libs/bufferstreams/update_include.sh b/libs/bufferstreams/update_include.sh new file mode 100755 index 0000000000..e986e9fb08 --- /dev/null +++ b/libs/bufferstreams/update_include.sh @@ -0,0 +1,2 @@ +cd rust +cbindgen --config cbindgen.toml --crate bufferstreams --output ../include/bufferstreams.h -- GitLab From aac785e6d9a917faa38dbce4e23d7014093b6b09 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 13 Jul 2023 18:25:08 +0000 Subject: [PATCH 0281/1187] Set AID_SYSTEM, AID_ROOT in fuzzService Updating fuzzService to pick the UIDs from AID_ROOT, AID_SYSTEM and other ranges. Services check for particular UIDs and this can help bypassing the UID checks. Bug: 291099142 Test: atest fuzz_service_test Change-Id: I4f83369fb36f9f6246ebbbaa74e16fadb34e627e --- .../tests/parcel_fuzzer/libbinder_driver.cpp | 9 ++++++++- .../test_fuzzer/TestServiceFuzzer.cpp | 20 +++++++++++++++++++ .../test_fuzzer/run_fuzz_service_test.sh | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index 45c3a90044..b268c5dcd4 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -21,6 +21,8 @@ #include #include +#include + namespace android { void fuzzService(const sp& binder, FuzzedDataProvider&& provider) { @@ -40,7 +42,12 @@ void fuzzService(const std::vector>& binders, FuzzedDataProvider&& p // Always take so that a perturbation of just the one ConsumeBool byte will always // take the same path, but with a different UID. Without this, the fuzzer needs to // guess both the change in value and the shift at the same time. - int64_t maybeSetUid = provider.ConsumeIntegral(); + int64_t maybeSetUid = provider.PickValueInArray( + {static_cast(AID_ROOT) << 32, static_cast(AID_SYSTEM) << 32, + provider.ConsumeIntegralInRange(static_cast(AID_ROOT) << 32, + static_cast(AID_USER) << 32), + provider.ConsumeIntegral()}); + if (provider.ConsumeBool()) { // set calling uid IPCThreadState::self()->restoreCallingIdentity(maybeSetUid); diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp index 7fbf2d0670..46205d7689 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp @@ -20,6 +20,8 @@ #include #include +#include + using android::binder::Status; namespace android { @@ -29,6 +31,8 @@ enum class CrashType { ON_PLAIN, ON_BINDER, ON_KNOWN_UID, + ON_SYSTEM_AID, + ON_ROOT_AID, }; // This service is to verify that fuzzService is functioning properly @@ -48,6 +52,18 @@ public: } break; } + case CrashType::ON_SYSTEM_AID: { + if (IPCThreadState::self()->getCallingUid() == AID_SYSTEM) { + LOG_ALWAYS_FATAL("Expected crash, AID_SYSTEM."); + } + break; + } + case CrashType::ON_ROOT_AID: { + if (IPCThreadState::self()->getCallingUid() == AID_ROOT) { + LOG_ALWAYS_FATAL("Expected crash, AID_ROOT."); + } + break; + } default: break; } @@ -99,6 +115,10 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { gCrashType = CrashType::ON_PLAIN; } else if (arg == "KNOWN_UID") { gCrashType = CrashType::ON_KNOWN_UID; + } else if (arg == "AID_SYSTEM") { + gCrashType = CrashType::ON_SYSTEM_AID; + } else if (arg == "AID_ROOT") { + gCrashType = CrashType::ON_ROOT_AID; } else if (arg == "BINDER") { gCrashType = CrashType::ON_BINDER; } else { diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh index e568035af1..25906d8aeb 100755 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh @@ -27,7 +27,7 @@ then exit 1 fi -for CRASH_TYPE in PLAIN KNOWN_UID BINDER; do +for CRASH_TYPE in PLAIN KNOWN_UID AID_SYSTEM AID_ROOT BINDER; do echo "INFO: Running fuzzer : test_service_fuzzer_should_crash $CRASH_TYPE" ./test_service_fuzzer_should_crash "$CRASH_TYPE" -max_total_time=30 &>"$FUZZER_OUT" -- GitLab From 147581b17b562f0bd44a5cc903906784b45b20a9 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Tue, 27 Jun 2023 11:55:34 -0700 Subject: [PATCH 0282/1187] Add new SF backdoor option: hdr/sdr ratio overlay - follow how RefreshRateOverlay did in general. - 1043 as new opcode to enable hdr/sdr ratio overlay. - decouple SevenSegmentDrawer and SurfaceControlHandle helper classes from RefreshRateOverlay. - add corresponding SF backdoor test for validation. - for non-HDR-supported device, we don't reject them to use SF backdoor but 1.00 will be always shown on the screen if enabling. Test: adb shell call service call SurfaceFlinger 1043 1; atest SurfaceFlinger_test Bug: 277957056 Change-Id: Ifce2d435f127b53ab9d01aba4e24ffd4fdb010a7 --- services/surfaceflinger/Android.bp | 1 + services/surfaceflinger/DisplayDevice.cpp | 44 ++++- services/surfaceflinger/DisplayDevice.h | 13 +- .../surfaceflinger/HdrSdrRatioOverlay.cpp | 178 ++++++++++++++++++ services/surfaceflinger/HdrSdrRatioOverlay.h | 45 +++++ .../surfaceflinger/RefreshRateOverlay.cpp | 133 +++---------- services/surfaceflinger/RefreshRateOverlay.h | 33 +--- services/surfaceflinger/SurfaceFlinger.cpp | 41 +++- services/surfaceflinger/SurfaceFlinger.h | 9 +- services/surfaceflinger/Utils/OverlayUtils.h | 146 ++++++++++++++ services/surfaceflinger/tests/Android.bp | 3 +- .../tests/HdrSdrRatioOverlay_test.cpp | 89 +++++++++ 12 files changed, 588 insertions(+), 147 deletions(-) create mode 100644 services/surfaceflinger/HdrSdrRatioOverlay.cpp create mode 100644 services/surfaceflinger/HdrSdrRatioOverlay.h create mode 100644 services/surfaceflinger/Utils/OverlayUtils.h create mode 100644 services/surfaceflinger/tests/HdrSdrRatioOverlay_test.cpp diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 89c80bc83a..326645e596 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -168,6 +168,7 @@ filegroup { "FrameTracer/FrameTracer.cpp", "FrameTracker.cpp", "HdrLayerInfoReporter.cpp", + "HdrSdrRatioOverlay.cpp", "WindowInfosListenerInvoker.cpp", "Layer.cpp", "LayerFE.cpp", diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index f6ca9e2856..32bd890aee 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -37,11 +37,11 @@ #include #include #include -#include #include "Display/DisplaySnapshot.h" #include "DisplayDevice.h" #include "FrontEnd/DisplayInfo.h" +#include "HdrSdrRatioOverlay.h" #include "Layer.h" #include "RefreshRateOverlay.h" #include "SurfaceFlinger.h" @@ -261,6 +261,9 @@ void DisplayDevice::setLayerFilter(ui::LayerFilter filter) { if (mRefreshRateOverlay) { mRefreshRateOverlay->setLayerStack(filter.layerStack); } + if (mHdrSdrRatioOverlay) { + mHdrSdrRatioOverlay->setLayerStack(filter.layerStack); + } } void DisplayDevice::setFlags(uint32_t flags) { @@ -274,10 +277,14 @@ void DisplayDevice::setDisplaySize(int width, int height) { if (mRefreshRateOverlay) { mRefreshRateOverlay->setViewport(size); } + if (mHdrSdrRatioOverlay) { + mHdrSdrRatioOverlay->setViewport(size); + } } void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpaceRect, Rect orientedDisplaySpaceRect) { + mIsOrientationChanged = mOrientation != orientation; mOrientation = orientation; // We need to take care of display rotation for globalTransform for case if the panel is not @@ -411,6 +418,26 @@ HdrCapabilities DisplayDevice::getHdrCapabilities() const { capabilities.getDesiredMinLuminance()); } +void DisplayDevice::enableHdrSdrRatioOverlay(bool enable) { + if (!enable) { + mHdrSdrRatioOverlay.reset(); + return; + } + + mHdrSdrRatioOverlay = std::make_unique(); + mHdrSdrRatioOverlay->setLayerStack(getLayerStack()); + mHdrSdrRatioOverlay->setViewport(getSize()); + updateHdrSdrRatioOverlayRatio(mHdrSdrRatio); +} + +void DisplayDevice::updateHdrSdrRatioOverlayRatio(float currentHdrSdrRatio) { + ATRACE_CALL(); + mHdrSdrRatio = currentHdrSdrRatio; + if (mHdrSdrRatioOverlay) { + mHdrSdrRatioOverlay->changeHdrSdrRatio(currentHdrSdrRatio); + } +} + void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner, bool showRenderRate, bool showInMiddle) { if (!enable) { @@ -463,10 +490,23 @@ bool DisplayDevice::onKernelTimerChanged(std::optional desiredMod return false; } -void DisplayDevice::animateRefreshRateOverlay() { +void DisplayDevice::animateOverlay() { if (mRefreshRateOverlay) { mRefreshRateOverlay->animate(); } + if (mHdrSdrRatioOverlay) { + // hdr sdr ratio is designed to be on the top right of the screen, + // therefore, we need to re-calculate the display's width and height + if (mIsOrientationChanged) { + auto width = getWidth(); + auto height = getHeight(); + if (mOrientation == ui::ROTATION_90 || mOrientation == ui::ROTATION_270) { + std::swap(width, height); + } + mHdrSdrRatioOverlay->setViewport({width, height}); + } + mHdrSdrRatioOverlay->animate(); + } } auto DisplayDevice::setDesiredActiveMode(const ActiveModeInfo& info, bool force) diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index dc5f8a85af..e92125a45d 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -55,6 +55,7 @@ namespace android { class Fence; class HWComposer; +class HdrSdrRatioOverlay; class IGraphicBufferProducer; class Layer; class RefreshRateOverlay; @@ -235,13 +236,19 @@ public: return mRefreshRateSelector; } + void animateOverlay(); + // Enables an overlay to be displayed with the current refresh rate void enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner, bool showRenderRate, bool showInMiddle) REQUIRES(kMainThreadContext); void updateRefreshRateOverlayRate(Fps displayFps, Fps renderFps, bool setByHwc = false); bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; } bool onKernelTimerChanged(std::optional, bool timerExpired); - void animateRefreshRateOverlay(); + + // Enables an overlay to be display with the hdr/sdr ratio + void enableHdrSdrRatioOverlay(bool enable) REQUIRES(kMainThreadContext); + void updateHdrSdrRatioOverlayRatio(float currentHdrSdrRatio); + bool isHdrSdrRatioOverlayEnabled() const { return mHdrSdrRatioOverlay != nullptr; } nsecs_t getVsyncPeriodFromHWC() const; @@ -271,6 +278,7 @@ private: const ui::Rotation mPhysicalOrientation; ui::Rotation mOrientation = ui::ROTATION_0; + bool mIsOrientationChanged = false; // Allow nullopt as initial power mode. using TracedPowerMode = TracedOrdinal; @@ -297,6 +305,9 @@ private: std::shared_ptr mRefreshRateSelector; std::unique_ptr mRefreshRateOverlay; + std::unique_ptr mHdrSdrRatioOverlay; + // This parameter is only used for hdr/sdr ratio overlay + float mHdrSdrRatio = 1.0f; mutable std::mutex mActiveModeLock; ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock); diff --git a/services/surfaceflinger/HdrSdrRatioOverlay.cpp b/services/surfaceflinger/HdrSdrRatioOverlay.cpp new file mode 100644 index 0000000000..2c0f5180cc --- /dev/null +++ b/services/surfaceflinger/HdrSdrRatioOverlay.cpp @@ -0,0 +1,178 @@ +/** + * Copyright (C) 2023 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_NDEBUG 0 +#include + +#include "HdrSdrRatioOverlay.h" + +#include + +#undef LOG_TAG +#define LOG_TAG "HdrSdrRatioOverlay" + +namespace android { + +void HdrSdrRatioOverlay::drawNumber(float number, int left, SkColor color, SkCanvas& canvas) { + if (!isfinite(number) || number >= 10.f) return; + // We assume that the number range is [1.f, 10.f) + // and the decimal places are 2. + int value = static_cast(number * 100); + SegmentDrawer::drawDigit(value / 100, left, color, canvas); + + left += kDigitWidth + kDigitSpace; + SegmentDrawer::drawSegment(SegmentDrawer::Segment::DecimalPoint, left, color, canvas); + left += kDigitWidth + kDigitSpace; + + SegmentDrawer::drawDigit((value / 10) % 10, left, color, canvas); + left += kDigitWidth + kDigitSpace; + SegmentDrawer::drawDigit(value % 10, left, color, canvas); +} + +sp HdrSdrRatioOverlay::draw(float currentHdrSdrRatio, SkColor color, + ui::Transform::RotationFlags rotation) { + SkMatrix canvasTransform = SkMatrix(); + const auto [bufferWidth, bufferHeight] = [&]() -> std::pair { + switch (rotation) { + case ui::Transform::ROT_90: + canvasTransform.setTranslate(kBufferHeight, 0); + canvasTransform.preRotate(90.f); + return {kBufferHeight, kBufferWidth}; + case ui::Transform::ROT_270: + canvasTransform.setRotate(270.f, kBufferWidth / 2.f, kBufferWidth / 2.f); + return {kBufferHeight, kBufferWidth}; + default: + return {kBufferWidth, kBufferHeight}; + } + }(); + + const auto kUsageFlags = static_cast( + GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE); + sp buffer = + sp::make(static_cast(bufferWidth), + static_cast(bufferHeight), HAL_PIXEL_FORMAT_RGBA_8888, + 1u, kUsageFlags, "HdrSdrRatioOverlay"); + + const status_t bufferStatus = buffer->initCheck(); + LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "HdrSdrRatioOverlay: Buffer failed to allocate: %d", + bufferStatus); + + sk_sp surface = + SkSurfaces::Raster(SkImageInfo::MakeN32Premul(bufferWidth, bufferHeight)); + SkCanvas* canvas = surface->getCanvas(); + canvas->setMatrix(canvasTransform); + + drawNumber(currentHdrSdrRatio, 0, color, *canvas); + + void* pixels = nullptr; + buffer->lock(GRALLOC_USAGE_SW_WRITE_RARELY, reinterpret_cast(&pixels)); + + const SkImageInfo& imageInfo = surface->imageInfo(); + const size_t dstRowBytes = buffer->getStride() * static_cast(imageInfo.bytesPerPixel()); + + canvas->readPixels(imageInfo, pixels, dstRowBytes, 0, 0); + buffer->unlock(); + return buffer; +} + +HdrSdrRatioOverlay::HdrSdrRatioOverlay() + : mSurfaceControl( + SurfaceControlHolder::createSurfaceControlHolder(String8("HdrSdrRatioOverlay"))) { + if (!mSurfaceControl) { + ALOGE("%s: Failed to create buffer state layer", __func__); + return; + } + SurfaceComposerClient::Transaction() + .setLayer(mSurfaceControl->get(), INT32_MAX - 2) + .setTrustedOverlay(mSurfaceControl->get(), true) + .apply(); +} + +void HdrSdrRatioOverlay::changeHdrSdrRatio(float currentHdrSdrRatio) { + mCurrentHdrSdrRatio = currentHdrSdrRatio; + animate(); +} + +void HdrSdrRatioOverlay::setLayerStack(ui::LayerStack stack) { + SurfaceComposerClient::Transaction().setLayerStack(mSurfaceControl->get(), stack).apply(); +} + +void HdrSdrRatioOverlay::setViewport(ui::Size viewport) { + constexpr int32_t kMaxWidth = 1000; + const auto width = std::min({kMaxWidth, viewport.width, viewport.height}); + const auto height = 2 * width; + Rect frame((5 * width) >> 4, height >> 5); + // set the ratio frame to the top right of the screen + frame.offsetBy(viewport.width - frame.width(), height >> 4); + + SurfaceComposerClient::Transaction() + .setMatrix(mSurfaceControl->get(), frame.getWidth() / static_cast(kBufferWidth), + 0, 0, frame.getHeight() / static_cast(kBufferHeight)) + .setPosition(mSurfaceControl->get(), frame.left, frame.top) + .apply(); +} + +auto HdrSdrRatioOverlay::getOrCreateBuffers(float currentHdrSdrRatio) -> const sp { + static const sp kNoBuffer; + if (!mSurfaceControl) return kNoBuffer; + + const auto transformHint = + static_cast(mSurfaceControl->get()->getTransformHint()); + + // Tell SurfaceFlinger about the pre-rotation on the buffer. + const auto transform = [&] { + switch (transformHint) { + case ui::Transform::ROT_90: + return ui::Transform::ROT_270; + case ui::Transform::ROT_270: + return ui::Transform::ROT_90; + default: + return ui::Transform::ROT_0; + } + }(); + + SurfaceComposerClient::Transaction().setTransform(mSurfaceControl->get(), transform).apply(); + + constexpr SkColor kMinRatioColor = SK_ColorBLUE; + constexpr SkColor kMaxRatioColor = SK_ColorGREEN; + constexpr float kAlpha = 0.8f; + + // 9.f is picked here as ratio range, given that we assume that + // hdr/sdr ratio is [1.f, 10.f) + const float scale = currentHdrSdrRatio / 9.f; + + SkColor4f colorBase = SkColor4f::FromColor(kMaxRatioColor) * scale; + const SkColor4f minRatioColor = SkColor4f::FromColor(kMinRatioColor) * (1 - scale); + + colorBase.fR = colorBase.fR + minRatioColor.fR; + colorBase.fG = colorBase.fG + minRatioColor.fG; + colorBase.fB = colorBase.fB + minRatioColor.fB; + colorBase.fA = kAlpha; + + const SkColor color = colorBase.toSkColor(); + + auto buffer = draw(currentHdrSdrRatio, color, transformHint); + return buffer; +} + +void HdrSdrRatioOverlay::animate() { + if (!std::isfinite(mCurrentHdrSdrRatio) || mCurrentHdrSdrRatio < 1.0f) return; + + SurfaceComposerClient::Transaction() + .setBuffer(mSurfaceControl->get(), getOrCreateBuffers(mCurrentHdrSdrRatio)) + .apply(); +} + +} // namespace android \ No newline at end of file diff --git a/services/surfaceflinger/HdrSdrRatioOverlay.h b/services/surfaceflinger/HdrSdrRatioOverlay.h new file mode 100644 index 0000000000..8a2586e9f8 --- /dev/null +++ b/services/surfaceflinger/HdrSdrRatioOverlay.h @@ -0,0 +1,45 @@ +/** + * Copyright (C) 2023 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 "Utils/OverlayUtils.h" + +#include +#include + +class SkCanvas; + +namespace android { +class HdrSdrRatioOverlay { +public: + HdrSdrRatioOverlay(); + void setLayerStack(ui::LayerStack); + void setViewport(ui::Size); + void animate(); + void changeHdrSdrRatio(float currentRatio); + +private: + float mCurrentHdrSdrRatio = 1.f; + + static sp draw(float currentHdrSdrRatio, SkColor, ui::Transform::RotationFlags); + static void drawNumber(float number, int left, SkColor, SkCanvas&); + + const sp getOrCreateBuffers(float currentHdrSdrRatio); + + const std::unique_ptr mSurfaceControl; +}; +} // namespace android diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index 607bec2e3f..577211f461 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -16,104 +16,20 @@ #include -#include "BackgroundExecutor.h" #include "Client.h" #include "Layer.h" #include "RefreshRateOverlay.h" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#include -#include -#pragma clang diagnostic pop -#include -#include #include -#include #undef LOG_TAG #define LOG_TAG "RefreshRateOverlay" namespace android { -namespace { -constexpr int kDigitWidth = 64; -constexpr int kDigitHeight = 100; -constexpr int kDigitSpace = 16; - -constexpr int kMaxDigits = /*displayFps*/ 3 + /*renderFps*/ 3 + /*spinner*/ 1; -constexpr int kBufferWidth = kMaxDigits * kDigitWidth + (kMaxDigits - 1) * kDigitSpace; -constexpr int kBufferHeight = kDigitHeight; - -} // namespace - -SurfaceControlHolder::~SurfaceControlHolder() { - // Hand the sp to the helper thread to release the last - // reference. This makes sure that the SurfaceControl is destructed without - // SurfaceFlinger::mStateLock held. - BackgroundExecutor::getInstance().sendCallbacks( - {[sc = std::move(mSurfaceControl)]() mutable { sc.clear(); }}); -} - -void RefreshRateOverlay::SevenSegmentDrawer::drawSegment(Segment segment, int left, SkColor color, - SkCanvas& canvas) { - const SkRect rect = [&]() { - switch (segment) { - case Segment::Upper: - return SkRect::MakeLTRB(left, 0, left + kDigitWidth, kDigitSpace); - case Segment::UpperLeft: - return SkRect::MakeLTRB(left, 0, left + kDigitSpace, kDigitHeight / 2); - case Segment::UpperRight: - return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, 0, left + kDigitWidth, - kDigitHeight / 2); - case Segment::Middle: - return SkRect::MakeLTRB(left, kDigitHeight / 2 - kDigitSpace / 2, - left + kDigitWidth, kDigitHeight / 2 + kDigitSpace / 2); - case Segment::LowerLeft: - return SkRect::MakeLTRB(left, kDigitHeight / 2, left + kDigitSpace, kDigitHeight); - case Segment::LowerRight: - return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, kDigitHeight / 2, - left + kDigitWidth, kDigitHeight); - case Segment::Bottom: - return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitWidth, - kDigitHeight); - } - }(); - - SkPaint paint; - paint.setColor(color); - paint.setBlendMode(SkBlendMode::kSrc); - canvas.drawRect(rect, paint); -} - -void RefreshRateOverlay::SevenSegmentDrawer::drawDigit(int digit, int left, SkColor color, - SkCanvas& canvas) { - if (digit < 0 || digit > 9) return; - - if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 || - digit == 8 || digit == 9) - drawSegment(Segment::Upper, left, color, canvas); - if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9) - drawSegment(Segment::UpperLeft, left, color, canvas); - if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 || - digit == 8 || digit == 9) - drawSegment(Segment::UpperRight, left, color, canvas); - if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || - digit == 9) - drawSegment(Segment::Middle, left, color, canvas); - if (digit == 0 || digit == 2 || digit == 6 || digit == 8) - drawSegment(Segment::LowerLeft, left, color, canvas); - if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || - digit == 7 || digit == 8 || digit == 9) - drawSegment(Segment::LowerRight, left, color, canvas); - if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 || - digit == 9) - drawSegment(Segment::Bottom, left, color, canvas); -} - -auto RefreshRateOverlay::SevenSegmentDrawer::draw(int displayFps, int renderFps, SkColor color, - ui::Transform::RotationFlags rotation, - ftl::Flags features) -> Buffers { +auto RefreshRateOverlay::draw(int displayFps, int renderFps, SkColor color, + ui::Transform::RotationFlags rotation, ftl::Flags features) + -> Buffers { const size_t loopCount = features.test(Features::Spinner) ? 6 : 1; Buffers buffers; @@ -159,22 +75,27 @@ auto RefreshRateOverlay::SevenSegmentDrawer::draw(int displayFps, int renderFps, if (features.test(Features::Spinner)) { switch (i) { case 0: - drawSegment(Segment::Upper, left, color, *canvas); + SegmentDrawer::drawSegment(SegmentDrawer::Segment::Upper, left, color, *canvas); break; case 1: - drawSegment(Segment::UpperRight, left, color, *canvas); + SegmentDrawer::drawSegment(SegmentDrawer::Segment::UpperRight, left, color, + *canvas); break; case 2: - drawSegment(Segment::LowerRight, left, color, *canvas); + SegmentDrawer::drawSegment(SegmentDrawer::Segment::LowerRight, left, color, + *canvas); break; case 3: - drawSegment(Segment::Bottom, left, color, *canvas); + SegmentDrawer::drawSegment(SegmentDrawer::Segment::Bottom, left, color, + *canvas); break; case 4: - drawSegment(Segment::LowerLeft, left, color, *canvas); + SegmentDrawer::drawSegment(SegmentDrawer::Segment::LowerLeft, left, color, + *canvas); break; case 5: - drawSegment(Segment::UpperLeft, left, color, *canvas); + SegmentDrawer::drawSegment(SegmentDrawer::Segment::UpperLeft, left, color, + *canvas); break; } } @@ -200,34 +121,27 @@ auto RefreshRateOverlay::SevenSegmentDrawer::draw(int displayFps, int renderFps, return buffers; } -void RefreshRateOverlay::SevenSegmentDrawer::drawNumber(int number, int left, SkColor color, - SkCanvas& canvas) { +void RefreshRateOverlay::drawNumber(int number, int left, SkColor color, SkCanvas& canvas) { if (number < 0 || number >= 1000) return; if (number >= 100) { - drawDigit(number / 100, left, color, canvas); + SegmentDrawer::drawDigit(number / 100, left, color, canvas); } left += kDigitWidth + kDigitSpace; if (number >= 10) { - drawDigit((number / 10) % 10, left, color, canvas); + SegmentDrawer::drawDigit((number / 10) % 10, left, color, canvas); } left += kDigitWidth + kDigitSpace; - drawDigit(number % 10, left, color, canvas); -} - -std::unique_ptr createSurfaceControlHolder() { - sp surfaceControl = - SurfaceComposerClient::getDefault() - ->createSurface(String8("RefreshRateOverlay"), kBufferWidth, kBufferHeight, - PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceBufferState); - return std::make_unique(std::move(surfaceControl)); + SegmentDrawer::drawDigit(number % 10, left, color, canvas); } RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, ftl::Flags features) - : mFpsRange(fpsRange), mFeatures(features), mSurfaceControl(createSurfaceControlHolder()) { + : mFpsRange(fpsRange), + mFeatures(features), + mSurfaceControl( + SurfaceControlHolder::createSurfaceControlHolder(String8("RefreshRateOverlay"))) { if (!mSurfaceControl) { ALOGE("%s: Failed to create buffer state layer", __func__); return; @@ -296,8 +210,7 @@ auto RefreshRateOverlay::getOrCreateBuffers(Fps displayFps, Fps renderFps) -> co const SkColor color = colorBase.toSkColor(); - auto buffers = SevenSegmentDrawer::draw(displayIntFps, renderIntFps, color, transformHint, - mFeatures); + auto buffers = draw(displayIntFps, renderIntFps, color, transformHint, mFeatures); it = mBufferCache .try_emplace({displayIntFps, renderIntFps, transformHint}, std::move(buffers)) .first; diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index 0b89b8e3a1..65c61cb4ca 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -16,12 +16,12 @@ #pragma once -#include +#include "Utils/OverlayUtils.h" + #include #include #include -#include #include #include #include @@ -34,22 +34,8 @@ class SkCanvas; namespace android { class GraphicBuffer; -class SurfaceControl; class SurfaceFlinger; -// Helper class to delete the SurfaceControl on a helper thread as -// SurfaceControl assumes its destruction happens without SurfaceFlinger::mStateLock held. -class SurfaceControlHolder { -public: - explicit SurfaceControlHolder(sp sc) : mSurfaceControl(std::move(sc)){}; - ~SurfaceControlHolder(); - - const sp& get() const { return mSurfaceControl; } - -private: - sp mSurfaceControl; -}; - class RefreshRateOverlay { public: enum class Features { @@ -70,18 +56,9 @@ public: private: using Buffers = std::vector>; - class SevenSegmentDrawer { - public: - static Buffers draw(int displayFps, int renderFps, SkColor, ui::Transform::RotationFlags, - ftl::Flags); - - private: - enum class Segment { Upper, UpperLeft, UpperRight, Middle, LowerLeft, LowerRight, Bottom }; - - static void drawSegment(Segment, int left, SkColor, SkCanvas&); - static void drawDigit(int digit, int left, SkColor, SkCanvas&); - static void drawNumber(int number, int left, SkColor, SkCanvas&); - }; + static Buffers draw(int displayFps, int renderFps, SkColor, ui::Transform::RotationFlags, + ftl::Flags); + static void drawNumber(int number, int left, SkColor, SkCanvas&); const Buffers& getOrCreateBuffers(Fps, Fps); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c46da11a03..8646c0cd02 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1963,6 +1963,11 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp& displayToken, FTL_FAKE_GUARD(kMainThreadContext, display->stageBrightness(brightness.displayBrightness)); + float currentHdrSdrRatio = + compositionDisplay->editState().displayBrightnessNits / + compositionDisplay->editState().sdrWhitePointNits; + FTL_FAKE_GUARD(kMainThreadContext, + display->updateHdrSdrRatioOverlayRatio(currentHdrSdrRatio)); if (brightness.sdrWhitePointNits / brightness.displayBrightnessNits != currentDimmingRatio) { @@ -2454,10 +2459,10 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) mPowerAdvisor->updateTargetWorkDuration(idealVsyncPeriod); } - if (mRefreshRateOverlaySpinner) { + if (mRefreshRateOverlaySpinner || mHdrSdrRatioOverlay) { Mutex::Autolock lock(mStateLock); if (const auto display = getDefaultDisplayDeviceLocked()) { - display->animateRefreshRateOverlay(); + display->animateOverlay(); } } @@ -6462,9 +6467,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { code == IBinder::SYSPROPS_TRANSACTION) { return OK; } - // Numbers from 1000 to 1042 are currently used for backdoors. The code + // Numbers from 1000 to 1043 are currently used for backdoors. The code // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1042) { + if (code >= 1000 && code <= 1043) { ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); return OK; } @@ -6925,6 +6930,24 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r reply->writeInt32(NO_ERROR); return NO_ERROR; } + // hdr sdr ratio overlay + case 1043: { + auto future = mScheduler->schedule( + [&]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(kMainThreadContext) { + n = data.readInt32(); + mHdrSdrRatioOverlay = n != 0; + switch (n) { + case 0: + case 1: + enableHdrSdrRatioOverlay(mHdrSdrRatioOverlay); + break; + default: + reply->writeBool(isHdrSdrRatioOverlayEnabled()); + } + }); + future.wait(); + return NO_ERROR; + } } } return err; @@ -8023,6 +8046,16 @@ void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { } } +void SurfaceFlinger::enableHdrSdrRatioOverlay(bool enable) { + for (const auto& [id, display] : mPhysicalDisplays) { + if (display.snapshot().connectionType() == ui::DisplayConnectionType::Internal) { + if (const auto device = getDisplayDeviceLocked(id)) { + device->enableHdrSdrRatioOverlay(enable); + } + } + } +} + int SurfaceFlinger::getGpuContextPriority() { return getRenderEngine().getContextPriority(); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index d97a7478dd..49aff143e6 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -672,6 +672,8 @@ private: bool mRefreshRateOverlayRenderRate = false; // Show render rate overlay offseted to the middle of the screen (e.g. for circular displays) bool mRefreshRateOverlayShowInMiddle = false; + // Show hdr sdr ratio overlay + bool mHdrSdrRatioOverlay = false; void setDesiredActiveMode(display::DisplayModeRequest&&, bool force = false) REQUIRES(mStateLock); @@ -1288,7 +1290,6 @@ private: ui::Dataspace mDefaultCompositionDataspace; ui::Dataspace mWideColorGamutCompositionDataspace; ui::Dataspace mColorSpaceAgnosticDataspace; - float mDimmingRatio = -1.f; std::unique_ptr mRenderEngine; std::atomic mNumTrustedPresentationListeners = 0; @@ -1336,6 +1337,8 @@ private: void enableRefreshRateOverlay(bool enable) REQUIRES(mStateLock, kMainThreadContext); + void enableHdrSdrRatioOverlay(bool enable) REQUIRES(mStateLock, kMainThreadContext); + // Flag used to set override desired display mode from backdoor bool mDebugDisplayModeSetByBackdoor = false; @@ -1381,6 +1384,10 @@ private: return hasDisplay( [](const auto& display) { return display.isRefreshRateOverlayEnabled(); }); } + bool isHdrSdrRatioOverlayEnabled() const REQUIRES(mStateLock) { + return hasDisplay( + [](const auto& display) { return display.isHdrSdrRatioOverlayEnabled(); }); + } std::function>>()> getLayerSnapshotsForScreenshots( std::optional layerStack, uint32_t uid, std::function diff --git a/services/surfaceflinger/Utils/OverlayUtils.h b/services/surfaceflinger/Utils/OverlayUtils.h new file mode 100644 index 0000000000..0ef0be1101 --- /dev/null +++ b/services/surfaceflinger/Utils/OverlayUtils.h @@ -0,0 +1,146 @@ +/** + * Copyright (C) 2023 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_NDEBUG 0 +#pragma once + +#include "BackgroundExecutor.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#include +#include +#pragma clang diagnostic pop + +#include +#include + +namespace android { + +inline constexpr int kDigitWidth = 64; +inline constexpr int kDigitHeight = 100; +inline constexpr int kDigitSpace = 16; + +// HdrSdrRatioOverlay re-uses this value though it doesn't really need such amount buffer. +// for output good-looking and code conciseness. +inline constexpr int kMaxDigits = /*displayFps*/ 3 + /*renderFps*/ 3 + /*spinner*/ 1; +inline constexpr int kBufferWidth = kMaxDigits * kDigitWidth + (kMaxDigits - 1) * kDigitSpace; +inline constexpr int kBufferHeight = kDigitHeight; + +class SurfaceControl; + +// Helper class to delete the SurfaceControl on a helper thread as +// SurfaceControl assumes its destruction happens without SurfaceFlinger::mStateLock held. +class SurfaceControlHolder { +public: + explicit SurfaceControlHolder(sp sc) : mSurfaceControl(std::move(sc)){}; + + ~SurfaceControlHolder() { + // Hand the sp to the helper thread to release the last + // reference. This makes sure that the SurfaceControl is destructed without + // SurfaceFlinger::mStateLock held. + BackgroundExecutor::getInstance().sendCallbacks( + {[sc = std::move(mSurfaceControl)]() mutable { sc.clear(); }}); + } + + static std::unique_ptr createSurfaceControlHolder(const String8& name) { + sp surfaceControl = + SurfaceComposerClient::getDefault() + ->createSurface(name, kBufferWidth, kBufferHeight, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState); + return std::make_unique(std::move(surfaceControl)); + } + + const sp& get() const { return mSurfaceControl; } + +private: + sp mSurfaceControl; +}; + +// Helper class to draw digit and decimal point. +class SegmentDrawer { +public: + enum class Segment { + Upper, + UpperLeft, + UpperRight, + Middle, + LowerLeft, + LowerRight, + Bottom, + DecimalPoint + }; + static void drawSegment(Segment segment, int left, SkColor color, SkCanvas& canvas) { + const SkRect rect = [&]() { + switch (segment) { + case Segment::Upper: + return SkRect::MakeLTRB(left, 0, left + kDigitWidth, kDigitSpace); + case Segment::UpperLeft: + return SkRect::MakeLTRB(left, 0, left + kDigitSpace, kDigitHeight / 2.); + case Segment::UpperRight: + return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, 0, left + kDigitWidth, + kDigitHeight / 2.); + case Segment::Middle: + return SkRect::MakeLTRB(left, kDigitHeight / 2. - kDigitSpace / 2., + left + kDigitWidth, + kDigitHeight / 2. + kDigitSpace / 2.); + case Segment::LowerLeft: + return SkRect::MakeLTRB(left, kDigitHeight / 2., left + kDigitSpace, + kDigitHeight); + case Segment::LowerRight: + return SkRect::MakeLTRB(left + kDigitWidth - kDigitSpace, kDigitHeight / 2., + left + kDigitWidth, kDigitHeight); + case Segment::Bottom: + return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitWidth, + kDigitHeight); + case Segment::DecimalPoint: + return SkRect::MakeLTRB(left, kDigitHeight - kDigitSpace, left + kDigitSpace, + kDigitHeight); + } + }(); + + SkPaint paint; + paint.setColor(color); + paint.setBlendMode(SkBlendMode::kSrc); + canvas.drawRect(rect, paint); + } + + static void drawDigit(int digit, int left, SkColor color, SkCanvas& canvas) { + if (digit < 0 || digit > 9) return; + + if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 7 || + digit == 8 || digit == 9) + drawSegment(Segment::Upper, left, color, canvas); + if (digit == 0 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || digit == 9) + drawSegment(Segment::UpperLeft, left, color, canvas); + if (digit == 0 || digit == 1 || digit == 2 || digit == 3 || digit == 4 || digit == 7 || + digit == 8 || digit == 9) + drawSegment(Segment::UpperRight, left, color, canvas); + if (digit == 2 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || digit == 8 || + digit == 9) + drawSegment(Segment::Middle, left, color, canvas); + if (digit == 0 || digit == 2 || digit == 6 || digit == 8) + drawSegment(Segment::LowerLeft, left, color, canvas); + if (digit == 0 || digit == 1 || digit == 3 || digit == 4 || digit == 5 || digit == 6 || + digit == 7 || digit == 8 || digit == 9) + drawSegment(Segment::LowerRight, left, color, canvas); + if (digit == 0 || digit == 2 || digit == 3 || digit == 5 || digit == 6 || digit == 8 || + digit == 9) + drawSegment(Segment::Bottom, left, color, canvas); + } +}; + +} // namespace android diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 62b539a888..b5168b0f01 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -37,8 +37,9 @@ cc_test { "DisplayConfigs_test.cpp", "DisplayEventReceiver_test.cpp", "EffectLayer_test.cpp", - "LayerBorder_test.cpp", + "HdrSdrRatioOverlay_test.cpp", "InvalidHandles_test.cpp", + "LayerBorder_test.cpp", "LayerCallback_test.cpp", "LayerRenderTypeTransaction_test.cpp", "LayerState_test.cpp", diff --git a/services/surfaceflinger/tests/HdrSdrRatioOverlay_test.cpp b/services/surfaceflinger/tests/HdrSdrRatioOverlay_test.cpp new file mode 100644 index 0000000000..77a8f9c79b --- /dev/null +++ b/services/surfaceflinger/tests/HdrSdrRatioOverlay_test.cpp @@ -0,0 +1,89 @@ +/** + * Copyright (C) 2023 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 + +#include + +#include +#include +#include + +using ::std::literals::chrono_literals::operator""s; + +static constexpr int kHdrSdrRatioOverlayCode = 1043; +static constexpr int kHdrSdrRatioOverlayEnable = 1; +static constexpr int kHdrSdrRatioOverlayDisable = 0; +static constexpr int kHdrSdrRatioOverlayQuery = 2; + +// These values must match the ones we used for developer options in +// com.android.settings.development.ShowHdrSdrRatioPreferenceController +static_assert(kHdrSdrRatioOverlayCode == 1043); +static_assert(kHdrSdrRatioOverlayEnable == 1); +static_assert(kHdrSdrRatioOverlayDisable == 0); +static_assert(kHdrSdrRatioOverlayQuery == 2); + +namespace android { + +namespace { +void sendCommandToSf(int command, Parcel& reply) { + sp sf(ComposerService::getComposerService()); + Parcel request; + request.writeInterfaceToken(String16("android.ui.ISurfaceComposer")); + request.writeInt32(command); + ASSERT_EQ(NO_ERROR, + IInterface::asBinder(sf)->transact(kHdrSdrRatioOverlayCode, request, &reply)); +} + +bool isOverlayEnabled() { + Parcel reply; + sendCommandToSf(kHdrSdrRatioOverlayQuery, reply); + return reply.readBool(); +} + +void waitForOverlay(bool enabled) { + static constexpr auto kTimeout = std::chrono::nanoseconds(1s); + static constexpr auto kIterations = 10; + for (int i = 0; i < kIterations; i++) { + if (enabled == isOverlayEnabled()) { + return; + } + std::this_thread::sleep_for(kTimeout / kIterations); + } +} + +void toggleOverlay(bool enabled) { + if (enabled == isOverlayEnabled()) { + return; + } + + Parcel reply; + const auto command = enabled ? kHdrSdrRatioOverlayEnable : kHdrSdrRatioOverlayDisable; + sendCommandToSf(command, reply); + waitForOverlay(enabled); + ASSERT_EQ(enabled, isOverlayEnabled()); +} + +} // namespace + +TEST(HdrSdrRatioOverlayTest, enableAndDisableOverlay) { + toggleOverlay(true); + toggleOverlay(false); + + toggleOverlay(true); + toggleOverlay(false); +} + +} // namespace android -- GitLab From fac97ad291aacb0236f5c817f55d07e79441f822 Mon Sep 17 00:00:00 2001 From: Brian Johnson Date: Fri, 14 Jul 2023 17:59:06 +0000 Subject: [PATCH 0283/1187] SF: Add domlaskowski@ to SurfaceFlinger OWNERS Bug: NA Change-Id: I244a599001b8de1536443f263885bf67cc31a9ab Test: NA --- services/surfaceflinger/OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS index 4e7da829f2..473409715f 100644 --- a/services/surfaceflinger/OWNERS +++ b/services/surfaceflinger/OWNERS @@ -1,6 +1,7 @@ adyabr@google.com alecmouri@google.com chaviw@google.com +domlaskowski@google.com lpy@google.com pdwilliams@google.com racarr@google.com -- GitLab From 484cbc7e435510f4708edc72ba2c22581fa17e80 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Thu, 6 Jul 2023 17:05:32 -0500 Subject: [PATCH 0284/1187] Add OWNERS file for libgui_test module Bug: 288142547 Test: none, only changes OWNERS file Change-Id: I418a4722a506556516b151fc1b150e911f8dd2da --- libs/gui/tests/OWNERS | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 libs/gui/tests/OWNERS diff --git a/libs/gui/tests/OWNERS b/libs/gui/tests/OWNERS new file mode 100644 index 0000000000..156efdb883 --- /dev/null +++ b/libs/gui/tests/OWNERS @@ -0,0 +1,3 @@ +# Android > Android OS & Apps > Framework (Java + Native) > Window Manager > Surfaces +# Bug component: 316245 = per-file BLASTBufferQueue_test.cpp, DisplayInfo_test.cpp, EndToEndNativeInputTest.cpp, WindowInfos_test.cpp +# Buganizer template url: https://b.corp.google.com/issues/new?component=316245&template=1018194 = per-file BLASTBufferQueue_test.cpp, DisplayInfo_test.cpp, EndToEndNativeInputTest.cpp, WindowInfos_test.cpp -- GitLab From 3422d41f53de10bce462e542ba200e6da2548340 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Fri, 14 Jul 2023 16:38:45 -0500 Subject: [PATCH 0285/1187] Update OWNERS file to use COGS component Bug: 288142547 Test: none, only changes OWNERS file Change-Id: Ia16adcac6ccd710d2547cfccff3072443eba9d06 --- libs/gui/tests/OWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/gui/tests/OWNERS b/libs/gui/tests/OWNERS index 156efdb883..48cd30d39d 100644 --- a/libs/gui/tests/OWNERS +++ b/libs/gui/tests/OWNERS @@ -1,3 +1,6 @@ # Android > Android OS & Apps > Framework (Java + Native) > Window Manager > Surfaces # Bug component: 316245 = per-file BLASTBufferQueue_test.cpp, DisplayInfo_test.cpp, EndToEndNativeInputTest.cpp, WindowInfos_test.cpp # Buganizer template url: https://b.corp.google.com/issues/new?component=316245&template=1018194 = per-file BLASTBufferQueue_test.cpp, DisplayInfo_test.cpp, EndToEndNativeInputTest.cpp, WindowInfos_test.cpp + +# Android > Android OS & Apps > graphics > Core Graphics Stack (CoGS) +# Bug component: 1075130 -- GitLab From c08e061e4bbdd2149ccc3a795276e145be1cdfd9 Mon Sep 17 00:00:00 2001 From: Trevor David Black Date: Mon, 17 Jul 2023 14:14:32 +0000 Subject: [PATCH 0286/1187] Add r16, rg1616, rgba10101010 to DebugUtils.cpp Bug: 291578126 Test: Build Change-Id: I2d343fe5c519cf24a4699011626553779049f2c7 --- libs/ui/DebugUtils.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp index 073da89758..8675f14d43 100644 --- a/libs/ui/DebugUtils.cpp +++ b/libs/ui/DebugUtils.cpp @@ -304,6 +304,12 @@ std::string decodePixelFormat(android::PixelFormat format) { return std::string("BGRA_8888"); case android::PIXEL_FORMAT_R_8: return std::string("R_8"); + case android::PIXEL_FORMAT_R_16_UINT: + return std::string("R_16_UINT"); + case android::PIXEL_FORMAT_RG_1616_UINT: + return std::string("RG_1616_UINT"); + case android::PIXEL_FORMAT_RGBA_10101010: + return std::string("RGBA_10101010"); default: return StringPrintf("Unknown %#08x", format); } -- GitLab From 7a1e742d154f7c4fdc8c3fbdb799c9ec4db1eb4d Mon Sep 17 00:00:00 2001 From: Ray Chin Date: Mon, 17 Jul 2023 16:39:22 +0800 Subject: [PATCH 0287/1187] Make mMutex the last attribute to be released The original attribute declaration order was mTimeKeeper -> mMutex. This will cause the mMutex be released prior than mTimeKeepr. When mMutex has been released and mTimeKeeper is still running dispatch(), the callback can be invoked and try to lock the released mMutex. Please check the error in https://b.corp.google.com/issues/284388255#comment37. This CL change the declaration order as mMutex -> mTimekeeper so that the release order become mTimeKeeper -> mMutex. When releasing mTimeKeeper, the ~Timer() will join the dispatch thread and thus ensure the callback won't be invoked after mMutex get released. Bug: 284388255 Test: Build, flash and run suspend<->resume test for over 96 hours. Change-Id: I75a3946e641cbe19a0caaeb91433010edcd9c0c7 --- services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h index 6499d69969..e0fb8f9f86 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h @@ -146,13 +146,14 @@ private: void cancelTimer() REQUIRES(mMutex); ScheduleResult scheduleLocked(CallbackToken, ScheduleTiming) REQUIRES(mMutex); + std::mutex mutable mMutex; + static constexpr nsecs_t kInvalidTime = std::numeric_limits::max(); std::unique_ptr const mTimeKeeper; VsyncSchedule::TrackerPtr mTracker; nsecs_t const mTimerSlack; nsecs_t const mMinVsyncDistance; - std::mutex mutable mMutex; size_t mCallbackToken GUARDED_BY(mMutex) = 0; CallbackMap mCallbacks GUARDED_BY(mMutex); -- GitLab From f499b5a6d57478ad842b55df85a63da0529e72f6 Mon Sep 17 00:00:00 2001 From: Trevor David Black Date: Fri, 14 Jul 2023 17:30:41 +0000 Subject: [PATCH 0288/1187] Move vulkan swapchain from pixelformat to aidl Bug: 291142745 Test: Build Change-Id: I3abe992f7d7cd2a79704a3189958e51b3c2f0bdb --- vulkan/libvulkan/swapchain.cpp | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index c46036a5e2..64393be3fe 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -16,6 +16,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include #include #include #include @@ -25,8 +26,6 @@ #include #include #include -#include -#include #include #include #include @@ -37,6 +36,7 @@ #include "driver.h" +using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat; using android::hardware::graphics::common::V1_0::BufferUsage; namespace vulkan { @@ -489,27 +489,27 @@ void copy_ready_timings(Swapchain& swapchain, *count = num_copied; } -android::PixelFormat GetNativePixelFormat(VkFormat format) { - android::PixelFormat native_format = android::PIXEL_FORMAT_RGBA_8888; +PixelFormat GetNativePixelFormat(VkFormat format) { + PixelFormat native_format = PixelFormat::RGBA_8888; switch (format) { case VK_FORMAT_R8G8B8A8_UNORM: case VK_FORMAT_R8G8B8A8_SRGB: - native_format = android::PIXEL_FORMAT_RGBA_8888; + native_format = PixelFormat::RGBA_8888; break; case VK_FORMAT_R5G6B5_UNORM_PACK16: - native_format = android::PIXEL_FORMAT_RGB_565; + native_format = PixelFormat::RGB_565; break; case VK_FORMAT_R16G16B16A16_SFLOAT: - native_format = android::PIXEL_FORMAT_RGBA_FP16; + native_format = PixelFormat::RGBA_FP16; break; case VK_FORMAT_A2B10G10R10_UNORM_PACK32: - native_format = android::PIXEL_FORMAT_RGBA_1010102; + native_format = PixelFormat::RGBA_1010102; break; case VK_FORMAT_R8_UNORM: - native_format = android::PIXEL_FORMAT_R_8; + native_format = PixelFormat::R_8; break; case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: - native_format = android::PIXEL_FORMAT_RGBA_10101010; + native_format = PixelFormat::RGBA_10101010; break; default: ALOGV("unsupported swapchain format %d", format); @@ -1256,7 +1256,7 @@ VkResult CreateSwapchainKHR(VkDevice device, if (!allocator) allocator = &GetData(device).allocator; - android::PixelFormat native_pixel_format = + PixelFormat native_pixel_format = GetNativePixelFormat(create_info->imageFormat); android_dataspace native_dataspace = GetNativeDataspace(create_info->imageColorSpace); @@ -1351,10 +1351,11 @@ VkResult CreateSwapchainKHR(VkDevice device, const auto& dispatch = GetData(device).driver; - err = native_window_set_buffers_format(window, native_pixel_format); + err = native_window_set_buffers_format( + window, static_cast(native_pixel_format)); if (err != android::OK) { ALOGE("native_window_set_buffers_format(%s) failed: %s (%d)", - decodePixelFormat(native_pixel_format).c_str(), strerror(-err), err); + toString(native_pixel_format).c_str(), strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } -- GitLab From 9762ac9c1b813850379f55dfc2bd6698b8c96c64 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 13 Jul 2023 21:45:12 +0000 Subject: [PATCH 0289/1187] EventHub: Track the global key and switch states for enabled devices Querying the global state of pressed keys using the EVIOCGKEY ioctl seems to affect the stream of events produced by evdev. For instance, if we query the global state just as the key state happens to have changed but before the corresponding event notification is sent to the device's fd, it's possible that the updated state of the key is reflected in the ioctl without a corresponding input_event being written to the fd. This means our current model of letting any InputMapper query the global state of keys is incompatible with the system's behavior, because a query from one mapper could affect the information available to others. We resolve this querying the global state of keys and switches exactly once, immediately after opening the device fd, and tracking the global state using the events from the fd for the rest of the fd lifecycle. This way, when a mapper requests the current state of a key, there is no syscall needed that could potentially affect the input stream. Bug: 290938220 Bug: 261025260 Test: atest inputflinger_tests --rerun-until-failure -- --test-arg com.android.tradefed.testtype.GTest:native-test-flag:"--gtest_filter=*StylusButtonIntegration*" Change-Id: I08376f69fccdc60441eb982d6fee1866bd512de6 --- services/inputflinger/reader/EventHub.cpp | 124 ++++++++++++------ .../inputflinger/reader/include/EventHub.h | 16 ++- 2 files changed, 102 insertions(+), 38 deletions(-) diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 4d0e13ed2f..4e72c4c84f 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -538,7 +538,8 @@ EventHub::Device::Device(int fd, int32_t id, std::string path, InputDeviceIdenti associatedDevice(std::move(assocDev)), controllerNumber(0), enabled(true), - isVirtual(fd < 0) {} + isVirtual(fd < 0), + currentFrameDropped(false) {} EventHub::Device::~Device() { close(); @@ -612,6 +613,18 @@ void EventHub::Device::configureFd() { } bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId); ALOGI("usingClockIoctl=%s", toString(usingClockIoctl)); + + // Query the initial state of keys and switches, which is tracked by EventHub. + readDeviceState(); +} + +void EventHub::Device::readDeviceState() { + if (readDeviceBitMask(EVIOCGKEY(0), keyState) < 0) { + ALOGD("Unable to query the global key state for %s: %s", path.c_str(), strerror(errno)); + } + if (readDeviceBitMask(EVIOCGSW(0), swState) < 0) { + ALOGD("Unable to query the global switch state for %s: %s", path.c_str(), strerror(errno)); + } } bool EventHub::Device::hasKeycodeLocked(int keycode) const { @@ -729,6 +742,48 @@ status_t EventHub::Device::mapLed(int32_t led, int32_t* outScanCode) const { return NAME_NOT_FOUND; } +void EventHub::Device::trackInputEvent(const struct input_event& event) { + switch (event.type) { + case EV_KEY: { + LOG_ALWAYS_FATAL_IF(!currentFrameDropped && + !keyState.set(static_cast(event.code), + event.value != 0), + "%s: received invalid EV_KEY event code: %s", __func__, + InputEventLookup::getLinuxEvdevLabel(EV_KEY, event.code, 1) + .code.c_str()); + break; + } + case EV_SW: { + LOG_ALWAYS_FATAL_IF(!currentFrameDropped && + !swState.set(static_cast(event.code), + event.value != 0), + "%s: received invalid EV_SW event code: %s", __func__, + InputEventLookup::getLinuxEvdevLabel(EV_SW, event.code, 1) + .code.c_str()); + break; + } + case EV_SYN: { + switch (event.code) { + case SYN_REPORT: + currentFrameDropped = false; + break; + case SYN_DROPPED: + // When we receive SYN_DROPPED, all events in the current frame should be + // dropped. We query the state of the device to synchronize our device state + // with the kernel's to account for the dropped events. + currentFrameDropped = true; + readDeviceState(); + break; + default: + break; + } + break; + } + default: + break; + } +} + /** * Get the capabilities for the current process. * Crashes the system if unable to create / check / destroy the capabilities object. @@ -962,38 +1017,34 @@ bool EventHub::hasMscEvent(int32_t deviceId, int mscEvent) const { } int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { - if (scanCode >= 0 && scanCode <= KEY_MAX) { - std::scoped_lock _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device != nullptr && device->hasValidFd() && device->keyBitmask.test(scanCode)) { - if (device->readDeviceBitMask(EVIOCGKEY(0), device->keyState) >= 0) { - return device->keyState.test(scanCode) ? AKEY_STATE_DOWN : AKEY_STATE_UP; - } - } + if (scanCode < 0 || scanCode > KEY_MAX) { + return AKEY_STATE_UNKNOWN; + } + std::scoped_lock _l(mLock); + const Device* device = getDeviceLocked(deviceId); + if (device == nullptr || !device->hasValidFd() || !device->keyBitmask.test(scanCode)) { + return AKEY_STATE_UNKNOWN; } - return AKEY_STATE_UNKNOWN; + return device->keyState.test(scanCode) ? AKEY_STATE_DOWN : AKEY_STATE_UP; } int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { std::scoped_lock _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device != nullptr && device->hasValidFd() && device->keyMap.haveKeyLayout()) { - std::vector scanCodes = device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode); - if (scanCodes.size() != 0) { - if (device->readDeviceBitMask(EVIOCGKEY(0), device->keyState) >= 0) { - for (size_t i = 0; i < scanCodes.size(); i++) { - int32_t sc = scanCodes[i]; - if (sc >= 0 && sc <= KEY_MAX && device->keyState.test(sc)) { - return AKEY_STATE_DOWN; - } - } - return AKEY_STATE_UP; - } - } + const Device* device = getDeviceLocked(deviceId); + if (device == nullptr || !device->hasValidFd() || !device->keyMap.haveKeyLayout()) { + return AKEY_STATE_UNKNOWN; + } + const std::vector scanCodes = + device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode); + if (scanCodes.empty()) { + return AKEY_STATE_UNKNOWN; } - return AKEY_STATE_UNKNOWN; + return std::any_of(scanCodes.begin(), scanCodes.end(), + [&device](const int32_t sc) { + return sc >= 0 && sc <= KEY_MAX && device->keyState.test(sc); + }) + ? AKEY_STATE_DOWN + : AKEY_STATE_UP; } int32_t EventHub::getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const { @@ -1037,17 +1088,15 @@ int32_t EventHub::getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKey } int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { - if (sw >= 0 && sw <= SW_MAX) { - std::scoped_lock _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device != nullptr && device->hasValidFd() && device->swBitmask.test(sw)) { - if (device->readDeviceBitMask(EVIOCGSW(0), device->swState) >= 0) { - return device->swState.test(sw) ? AKEY_STATE_DOWN : AKEY_STATE_UP; - } - } + if (sw < 0 || sw > SW_MAX) { + return AKEY_STATE_UNKNOWN; + } + std::scoped_lock _l(mLock); + const Device* device = getDeviceLocked(deviceId); + if (device == nullptr || !device->hasValidFd() || !device->swBitmask.test(sw)) { + return AKEY_STATE_UNKNOWN; } - return AKEY_STATE_UNKNOWN; + return device->swState.test(sw) ? AKEY_STATE_DOWN : AKEY_STATE_UP; } status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const { @@ -1922,6 +1971,7 @@ std::vector EventHub::getEvents(int timeoutMillis) { const size_t count = size_t(readSize) / sizeof(struct input_event); for (size_t i = 0; i < count; i++) { struct input_event& iev = readBuffer[i]; + device->trackInputEvent(iev); events.push_back({ .when = processEventTimestamp(iev), .readTime = systemTime(SYSTEM_TIME_MONOTONIC), diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 024187f5b5..6e647db18e 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -411,7 +411,17 @@ public: * Note the parameter "bit" is an index to the bit, 0 <= bit < BITS. */ inline bool test(size_t bit) const { - return (bit < BITS) ? mData[bit / WIDTH].test(bit % WIDTH) : false; + return (bit < BITS) && mData[bit / WIDTH].test(bit % WIDTH); + } + /* Sets the given bit in the bit array to given value. + * Returns true if the given bit is a valid index and thus was set successfully. + */ + inline bool set(size_t bit, bool value) { + if (bit >= BITS) { + return false; + } + mData[bit / WIDTH].set(bit % WIDTH, value); + return true; } /* Returns total number of bytes needed for the array */ inline size_t bytes() { return (BITS + CHAR_BIT - 1) / CHAR_BIT; } @@ -653,6 +663,10 @@ private: void setLedForControllerLocked(); status_t mapLed(int32_t led, int32_t* outScanCode) const; void setLedStateLocked(int32_t led, bool on); + + bool currentFrameDropped; + void trackInputEvent(const struct input_event& event); + void readDeviceState(); }; /** -- GitLab From 39d60aaca44d476b2bb18d6f2484c9ba1dc18d37 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 13 Jul 2023 22:01:04 +0000 Subject: [PATCH 0290/1187] Revert "Disable stylus integration tests temporarily" This reverts commit 5abecc3a9e11dcc5f40cc612b814afb82d79e03e. Bug: 261025260 Test: Presubmit Change-Id: I2a4359de93a865eddbe94a55d5d967305b7a1577 --- services/inputflinger/tests/InputReader_test.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index f4e471dcbb..4fd30c0d6c 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1886,7 +1886,7 @@ using StylusButtonIntegrationTestTypes = ::testing::Types; TYPED_TEST_SUITE(StylusButtonIntegrationTest, StylusButtonIntegrationTestTypes); -TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsGenerateKeyEvents) { +TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsGenerateKeyEvents) { const auto stylusId = TestFixture::mStylusInfo.getId(); TestFixture::mStylus->pressKey(BTN_STYLUS); @@ -1900,7 +1900,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsGenerateKeyEvents) WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); } -TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingTouchGesture) { +TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsSurroundingTouchGesture) { const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint(); const auto touchscreenId = TestFixture::mTouchscreenInfo.getId(); const auto stylusId = TestFixture::mStylusInfo.getId(); @@ -1946,7 +1946,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingTouchGe WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); } -TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingHoveringTouchGesture) { +TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsSurroundingHoveringTouchGesture) { const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint(); const auto touchscreenId = TestFixture::mTouchscreenInfo.getId(); const auto stylusId = TestFixture::mStylusInfo.getId(); @@ -2022,7 +2022,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingHoverin WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId)))); } -TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsWithinTouchGesture) { +TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsWithinTouchGesture) { const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint(); const auto touchscreenId = TestFixture::mTouchscreenInfo.getId(); const auto stylusId = TestFixture::mStylusInfo.getId(); @@ -2076,7 +2076,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsWithinTouchGesture WithDeviceId(touchscreenId)))); } -TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonMotionEventsDisabled) { +TYPED_TEST(StylusButtonIntegrationTest, StylusButtonMotionEventsDisabled) { TestFixture::mFakePolicy->setStylusButtonMotionEventsEnabled(false); TestFixture::mReader->requestRefreshConfiguration( InputReaderConfiguration::Change::STYLUS_BUTTON_REPORTING); @@ -2133,7 +2133,7 @@ TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonMotionEventsDisable // ongoing stylus gesture that is being emitted by the touchscreen. using ExternalStylusIntegrationTest = TouchIntegrationTest; -TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureReported) { +TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureReported) { const Point centerPoint = mDevice->getCenterPoint(); // Create an external stylus capable of reporting pressure data that @@ -2179,7 +2179,7 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureReport ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasNotCalled()); } -TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureNotReported) { +TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureNotReported) { const Point centerPoint = mDevice->getCenterPoint(); // Create an external stylus capable of reporting pressure data that @@ -2247,7 +2247,7 @@ TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureNotRep ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasNotCalled()); } -TEST_F(ExternalStylusIntegrationTest, DISABLED_UnfusedExternalStylus) { +TEST_F(ExternalStylusIntegrationTest, UnfusedExternalStylus) { const Point centerPoint = mDevice->getCenterPoint(); // Create an external stylus device that does not support pressure. It should not affect any -- GitLab From 341d0787299b5b9d3f8368c0d7315fa191849cff Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 14 Jul 2023 19:04:10 +0000 Subject: [PATCH 0291/1187] EventHub: Track the global abs axis states for enabled devices Similar to what we have done for the global switch and key states, we track the state and value of all ABS axes for each fd so that we no longer have to use ioctls to query the value when upper layers request it. This will help ensure that the device state remains synchronized between the kernel and userspace, as the axis info will only need to be queried once for each axis when the fd is opened. Bug: 290938220 Bug: 261025260 Test: Presubmit Change-Id: I622a20f27341b694140bb454bb1c744272d73183 --- services/inputflinger/reader/EventHub.cpp | 113 ++++++++++-------- .../inputflinger/reader/include/EventHub.h | 16 ++- 2 files changed, 69 insertions(+), 60 deletions(-) diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 4e72c4c84f..9a1273301b 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -625,6 +625,36 @@ void EventHub::Device::readDeviceState() { if (readDeviceBitMask(EVIOCGSW(0), swState) < 0) { ALOGD("Unable to query the global switch state for %s: %s", path.c_str(), strerror(errno)); } + + // Read absolute axis info and values for all available axes for the device. + populateAbsoluteAxisStates(); +} + +void EventHub::Device::populateAbsoluteAxisStates() { + absState.clear(); + + for (int axis = 0; axis <= ABS_MAX; axis++) { + if (!absBitmask.test(axis)) { + continue; + } + struct input_absinfo info {}; + if (ioctl(fd, EVIOCGABS(axis), &info)) { + ALOGE("Error reading absolute controller %d for device %s fd %d: %s", axis, + identifier.name.c_str(), fd, strerror(errno)); + continue; + } + if (info.minimum == info.maximum) { + continue; + } + auto& [axisInfo, value] = absState[axis]; + axisInfo.valid = true; + axisInfo.minValue = info.minimum; + axisInfo.maxValue = info.maximum; + axisInfo.flat = info.flat; + axisInfo.fuzz = info.fuzz; + axisInfo.resolution = info.resolution; + value = info.value; + } } bool EventHub::Device::hasKeycodeLocked(int keycode) const { @@ -762,6 +792,15 @@ void EventHub::Device::trackInputEvent(const struct input_event& event) { .code.c_str()); break; } + case EV_ABS: { + auto it = absState.find(event.code); + LOG_ALWAYS_FATAL_IF(!currentFrameDropped && it == absState.end(), + "%s: received invalid EV_ABS event code: %s", __func__, + InputEventLookup::getLinuxEvdevLabel(EV_ABS, event.code, 0) + .code.c_str()); + it->second.value = event.value; + break; + } case EV_SYN: { switch (event.code) { case SYN_REPORT: @@ -919,30 +958,6 @@ void EventHub::addDeviceInotify() { strerror(errno)); } -void EventHub::populateDeviceAbsoluteAxisInfo(Device& device) { - for (int axis = 0; axis <= ABS_MAX; axis++) { - if (!device.absBitmask.test(axis)) { - continue; - } - struct input_absinfo info {}; - if (ioctl(device.fd, EVIOCGABS(axis), &info)) { - ALOGE("Error reading absolute controller %d for device %s fd %d, errno=%d", axis, - device.identifier.name.c_str(), device.fd, errno); - continue; - } - if (info.minimum == info.maximum) { - continue; - } - RawAbsoluteAxisInfo& outAxisInfo = device.rawAbsoluteAxisInfoCache[axis]; - outAxisInfo.valid = true; - outAxisInfo.minValue = info.minimum; - outAxisInfo.maxValue = info.maximum; - outAxisInfo.flat = info.flat; - outAxisInfo.fuzz = info.fuzz; - outAxisInfo.resolution = info.resolution; - } -} - InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); @@ -974,18 +989,21 @@ status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const { outAxisInfo->clear(); if (axis < 0 || axis > ABS_MAX) { - return -1; + return NAME_NOT_FOUND; } std::scoped_lock _l(mLock); - Device* device = getDeviceLocked(deviceId); + const Device* device = getDeviceLocked(deviceId); if (device == nullptr) { - return -1; + return NAME_NOT_FOUND; } - auto it = device->rawAbsoluteAxisInfoCache.find(axis); - if (it == device->rawAbsoluteAxisInfoCache.end()) { - return -1; + // We can read the RawAbsoluteAxisInfo even if the device is disabled and doesn't have a valid + // fd, because the info is populated once when the device is first opened, and it doesn't change + // throughout the device lifecycle. + auto it = device->absState.find(axis); + if (it == device->absState.end()) { + return NAME_NOT_FOUND; } - *outAxisInfo = it->second; + *outAxisInfo = it->second.info; return OK; } @@ -1101,24 +1119,20 @@ int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const { *outValue = 0; - - if (axis >= 0 && axis <= ABS_MAX) { - std::scoped_lock _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device != nullptr && device->hasValidFd() && device->absBitmask.test(axis)) { - struct input_absinfo info; - if (ioctl(device->fd, EVIOCGABS(axis), &info)) { - ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", axis, - device->identifier.name.c_str(), device->fd, errno); - return -errno; - } - - *outValue = info.value; - return OK; - } + if (axis < 0 || axis > ABS_MAX) { + return NAME_NOT_FOUND; + } + std::scoped_lock _l(mLock); + const Device* device = getDeviceLocked(deviceId); + if (device == nullptr || !device->hasValidFd()) { + return NAME_NOT_FOUND; + } + const auto it = device->absState.find(axis); + if (it == device->absState.end()) { + return NAME_NOT_FOUND; } - return -1; + *outValue = it->second.value; + return OK; } bool EventHub::markSupportedKeyCodes(int32_t deviceId, const std::vector& keyCodes, @@ -2498,9 +2512,6 @@ void EventHub::openDeviceLocked(const std::string& devicePath) { device->configureFd(); - // read absolute axis info for all available axes for the device - populateDeviceAbsoluteAxisInfo(*device); - ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=%s, " "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ", deviceId, fd, devicePath.c_str(), device->identifier.name.c_str(), diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 6e647db18e..09c5e947d8 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -612,7 +612,6 @@ private: BitArray keyBitmask; BitArray keyState; - BitArray absBitmask; BitArray relBitmask; BitArray swBitmask; BitArray swState; @@ -620,12 +619,17 @@ private: BitArray ffBitmask; BitArray propBitmask; BitArray mscBitmask; + BitArray absBitmask; + struct AxisState { + RawAbsoluteAxisInfo info; + int value; + }; + std::unordered_map absState; std::string configurationFile; std::unique_ptr configuration; std::unique_ptr virtualKeyMap; KeyMap keyMap; - std::unordered_map rawAbsoluteAxisInfoCache; bool ffEffectPlaying; int16_t ffEffectId; // initially -1 @@ -654,6 +658,7 @@ private: status_t readDeviceBitMask(unsigned long ioctlCode, BitArray& bitArray); void configureFd(); + void populateAbsoluteAxisStates(); bool hasKeycodeLocked(int keycode) const; void loadConfigurationLocked(); bool loadVirtualKeyMapLocked(); @@ -732,13 +737,6 @@ private: void addDeviceInputInotify(); void addDeviceInotify(); - /** - * AbsoluteAxisInfo remains unchanged for the lifetime of the device, hence - * we can read and store it with device - * @param device target device - */ - static void populateDeviceAbsoluteAxisInfo(Device& device); - // Protect all internal state. mutable std::mutex mLock; -- GitLab From 0cd1d8db19914fdef74d90cbbeb6c86e36401d6f Mon Sep 17 00:00:00 2001 From: ramindani Date: Tue, 13 Jun 2023 13:43:23 -0700 Subject: [PATCH 0292/1187] [SF] Implements composer3 version 3 interface Utilizes the getDisplayConfigurations to construct DisplayModes for the display. Test: build, go/wm-smoke, atest libsurfaceflinger_unittest BUG: 284866749 BUG: 287517652 Change-Id: I2480e4ac56ec681cd126491d26f0fb1741072f26 --- .../DisplayHardware/AidlComposerHal.cpp | 25 ++- .../DisplayHardware/AidlComposerHal.h | 6 +- .../DisplayHardware/ComposerHal.h | 6 + .../DisplayHardware/DisplayMode.h | 12 +- .../DisplayHardware/HWComposer.cpp | 58 ++++++- .../DisplayHardware/HWComposer.h | 7 +- services/surfaceflinger/DisplayHardware/Hal.h | 3 + .../DisplayHardware/HidlComposerHal.cpp | 10 ++ .../DisplayHardware/HidlComposerHal.h | 2 + .../tests/unittests/HWComposerTest.cpp | 150 ++++++++++++++++++ .../mock/DisplayHardware/MockComposer.h | 2 + 11 files changed, 261 insertions(+), 20 deletions(-) diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index c0eb36dc02..311820c3ed 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -244,14 +244,13 @@ AidlComposer::AidlComposer(const std::string& serviceName) { addReader(translate(kSingleReaderKey)); // If unable to read interface version, then become backwards compatible. - int32_t version = 1; - const auto status = mAidlComposerClient->getInterfaceVersion(&version); + const auto status = mAidlComposerClient->getInterfaceVersion(&mComposerInterfaceVersion); if (!status.isOk()) { ALOGE("getInterfaceVersion for AidlComposer constructor failed %s", status.getDescription().c_str()); } - mSupportsBufferSlotsToClear = version > 1; - if (!mSupportsBufferSlotsToClear) { + + if (mComposerInterfaceVersion <= 1) { if (sysprop::clear_slots_with_set_layer_buffer(false)) { mClearSlotBuffer = sp::make(1, 1, PIXEL_FORMAT_RGBX_8888, GraphicBuffer::USAGE_HW_COMPOSER | @@ -281,6 +280,10 @@ bool AidlComposer::isSupported(OptionalFeature feature) const { } } +bool AidlComposer::getDisplayConfigurationsSupported() const { + return mComposerInterfaceVersion >= 3; +} + std::vector AidlComposer::getCapabilities() { std::vector capabilities; const auto status = mAidlComposer->getCapabilities(&capabilities); @@ -489,6 +492,18 @@ Error AidlComposer::getDisplayConfigs(Display display, std::vector* outC return Error::NONE; } +Error AidlComposer::getDisplayConfigurations(Display display, + std::vector* outConfigs) { + const auto status = + mAidlComposerClient->getDisplayConfigurations(translate(display), outConfigs); + if (!status.isOk()) { + ALOGE("getDisplayConfigurations failed %s", status.getDescription().c_str()); + return static_cast(status.getServiceSpecificError()); + } + + return Error::NONE; +} + Error AidlComposer::getDisplayName(Display display, std::string* outName) { const auto status = mAidlComposerClient->getDisplayName(translate(display), outName); if (!status.isOk()) { @@ -848,7 +863,7 @@ Error AidlComposer::setLayerBufferSlotsToClear(Display display, Layer layer, Error error = Error::NONE; mMutex.lock_shared(); if (auto writer = getWriter(display)) { - if (mSupportsBufferSlotsToClear) { + if (mComposerInterfaceVersion > 1) { writer->get().setLayerBufferSlotsToClear(translate(display), translate(layer), slotsToClear); // Backwards compatible way of clearing buffer slots is to set the layer buffer with a diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index 8d21b491c3..e31ff812e3 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -66,6 +66,7 @@ public: ~AidlComposer() override; bool isSupported(OptionalFeature) const; + bool getDisplayConfigurationsSupported() const; std::vector getCapabilities() override; @@ -95,6 +96,7 @@ public: Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) override; Error getDisplayConfigs(Display display, std::vector* outConfigs); + Error getDisplayConfigurations(Display, std::vector*); Error getDisplayName(Display display, std::string* outName) override; Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask, @@ -285,8 +287,8 @@ private: // threading annotations. ftl::SharedMutex mMutex; - // Whether or not explicitly clearing buffer slots is supported. - bool mSupportsBufferSlotsToClear; + int32_t mComposerInterfaceVersion = 1; + // Buffer slots for layers are cleared by setting the slot buffer to this buffer. sp mClearSlotBuffer; diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index cf677955bf..cc60fd0ec0 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -85,6 +86,7 @@ using PerFrameMetadata = IComposerClient::PerFrameMetadata; using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey; using PerFrameMetadataBlob = IComposerClient::PerFrameMetadataBlob; using AidlTransform = ::aidl::android::hardware::graphics::common::Transform; +using DisplayConfiguration = V3_0::DisplayConfiguration; using aidl::android::hardware::graphics::common::Hdr; class Composer { @@ -103,6 +105,7 @@ public: }; virtual bool isSupported(OptionalFeature) const = 0; + virtual bool getDisplayConfigurationsSupported() const = 0; virtual std::vector getCapabilities() = 0; @@ -130,6 +133,9 @@ public: virtual Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) = 0; virtual Error getDisplayConfigs(Display display, std::vector* outConfigs) = 0; + + virtual Error getDisplayConfigurations(Display, std::vector*) = 0; + virtual Error getDisplayName(Display display, std::string* outName) = 0; virtual Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask, diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h index 61a9a08a5c..1810925c8e 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayMode.h +++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h @@ -80,20 +80,20 @@ public: return *this; } - Builder& setDpiX(int32_t dpiX) { - if (dpiX == -1) { + Builder& setDpiX(float dpiX) { + if (dpiX == -1.f) { mDisplayMode->mDpi.x = getDefaultDensity(); } else { - mDisplayMode->mDpi.x = dpiX / 1000.f; + mDisplayMode->mDpi.x = dpiX; } return *this; } - Builder& setDpiY(int32_t dpiY) { - if (dpiY == -1) { + Builder& setDpiY(float dpiY) { + if (dpiY == -1.f) { mDisplayMode->mDpi.y = getDefaultDensity(); } else { - mDisplayMode->mDpi.y = dpiY / 1000.f; + mDisplayMode->mDpi.y = dpiY; } return *this; } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index f350eba7ca..aefa7c3551 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -265,6 +265,46 @@ std::vector HWComposer::getModes(PhysicalDisplayId d RETURN_IF_INVALID_DISPLAY(displayId, {}); const auto hwcDisplayId = mDisplayData.at(displayId).hwcDisplay->getId(); + + if (mComposer->getDisplayConfigurationsSupported()) { + return getModesFromDisplayConfigurations(hwcDisplayId); + } + + return getModesFromLegacyDisplayConfigs(hwcDisplayId); +} + +std::vector HWComposer::getModesFromDisplayConfigurations( + uint64_t hwcDisplayId) const { + std::vector configs; + auto error = + static_cast(mComposer->getDisplayConfigurations(hwcDisplayId, &configs)); + RETURN_IF_HWC_ERROR_FOR("getDisplayConfigurations", error, *toPhysicalDisplayId(hwcDisplayId), + {}); + + std::vector modes; + modes.reserve(configs.size()); + for (auto config : configs) { + auto hwcMode = HWCDisplayMode{ + .hwcId = static_cast(config.configId), + .width = config.width, + .height = config.height, + .vsyncPeriod = config.vsyncPeriod, + .configGroup = config.configGroup, + }; + + if (config.dpi) { + hwcMode.dpiX = config.dpi->x; + hwcMode.dpiY = config.dpi->y; + } + + modes.push_back(hwcMode); + } + + return modes; +} + +std::vector HWComposer::getModesFromLegacyDisplayConfigs( + uint64_t hwcDisplayId) const { std::vector configIds; auto error = static_cast(mComposer->getDisplayConfigs(hwcDisplayId, &configIds)); RETURN_IF_HWC_ERROR_FOR("getDisplayConfigs", error, *toPhysicalDisplayId(hwcDisplayId), {}); @@ -272,17 +312,25 @@ std::vector HWComposer::getModes(PhysicalDisplayId d std::vector modes; modes.reserve(configIds.size()); for (auto configId : configIds) { - modes.push_back(HWCDisplayMode{ + auto hwcMode = HWCDisplayMode{ .hwcId = configId, .width = getAttribute(hwcDisplayId, configId, hal::Attribute::WIDTH), .height = getAttribute(hwcDisplayId, configId, hal::Attribute::HEIGHT), .vsyncPeriod = getAttribute(hwcDisplayId, configId, hal::Attribute::VSYNC_PERIOD), - .dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X), - .dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y), .configGroup = getAttribute(hwcDisplayId, configId, hal::Attribute::CONFIG_GROUP), - }); - } + }; + const int32_t dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X); + const int32_t dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y); + if (dpiX != -1) { + hwcMode.dpiX = static_cast(dpiX) / 1000.f; + } + if (dpiY != -1) { + hwcMode.dpiY = static_cast(dpiY) / 1000.f; + } + + modes.push_back(hwcMode); + } return modes; } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 3702c62b65..8247d97005 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -99,8 +99,8 @@ public: int32_t width = -1; int32_t height = -1; nsecs_t vsyncPeriod = -1; - int32_t dpiX = -1; - int32_t dpiY = -1; + float dpiX = -1.f; + float dpiY = -1.f; int32_t configGroup = -1; friend std::ostream& operator<<(std::ostream& os, const HWCDisplayMode& mode) { @@ -501,6 +501,9 @@ private: std::optional onHotplugDisconnect(hal::HWDisplayId); bool shouldIgnoreHotplugConnect(hal::HWDisplayId, bool hasDisplayIdentificationData) const; + std::vector getModesFromDisplayConfigurations(uint64_t hwcDisplayId) const; + std::vector getModesFromLegacyDisplayConfigs(uint64_t hwcDisplayId) const; + int32_t getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId configId, hal::Attribute attribute) const; diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h index bf3089f040..e95ae8934d 100644 --- a/services/surfaceflinger/DisplayHardware/Hal.h +++ b/services/surfaceflinger/DisplayHardware/Hal.h @@ -23,6 +23,7 @@ #include #include #include +#include #define ERROR_HAS_CHANGES 5 @@ -34,6 +35,7 @@ namespace V2_1 = android::hardware::graphics::composer::V2_1; namespace V2_2 = android::hardware::graphics::composer::V2_2; namespace V2_3 = android::hardware::graphics::composer::V2_3; namespace V2_4 = android::hardware::graphics::composer::V2_4; +namespace V3_0 = ::aidl::android::hardware::graphics::composer3; using types::V1_0::ColorTransform; using types::V1_0::Transform; @@ -70,6 +72,7 @@ using PowerMode = IComposerClient::PowerMode; using Vsync = IComposerClient::Vsync; using VsyncPeriodChangeConstraints = IComposerClient::VsyncPeriodChangeConstraints; using Hdr = aidl::android::hardware::graphics::common::Hdr; +using DisplayConfiguration = V3_0::DisplayConfiguration; } // namespace hardware::graphics::composer::hal diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index 9b41da5754..0655abc1c6 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -269,6 +269,11 @@ bool HidlComposer::isSupported(OptionalFeature feature) const { } } +bool HidlComposer::getDisplayConfigurationsSupported() const { + // getDisplayConfigurations is not supported on the HIDL composer. + return false; +}; + std::vector HidlComposer::getCapabilities() { std::vector capabilities; mComposer->getCapabilities([&](const auto& tmpCapabilities) { @@ -477,6 +482,11 @@ Error HidlComposer::getDisplayConfigs(Display display, std::vector* outC return error; } +Error HidlComposer::getDisplayConfigurations(Display, std::vector*) { + LOG_ALWAYS_FATAL("getDisplayConfigurations should not have been called on this, as " + "it's a HWC3 interface version 3 feature"); +} + Error HidlComposer::getDisplayName(Display display, std::string* outName) { Error error = kDefaultError; mClient->getDisplayName(display, [&](const auto& tmpError, const auto& tmpName) { diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index 0521acf9c4..ac96d9a81d 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -167,6 +167,7 @@ public: ~HidlComposer() override; bool isSupported(OptionalFeature) const; + bool getDisplayConfigurationsSupported() const; std::vector getCapabilities() override; @@ -196,6 +197,7 @@ public: Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) override; Error getDisplayConfigs(Display display, std::vector* outConfigs); + Error getDisplayConfigurations(Display, std::vector*); Error getDisplayName(Display display, std::string* outName) override; Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask, diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index da00377cae..ec8069d299 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -53,6 +53,7 @@ namespace aidl = aidl::android::hardware::graphics::composer3; using Hwc2::Config; using ::aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData; +using hal::IComposerClient; using ::testing::_; using ::testing::DoAll; using ::testing::ElementsAreArray; @@ -119,6 +120,155 @@ TEST_F(HWComposerTest, getActiveMode) { } } +TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { + constexpr hal::HWDisplayId kHwcDisplayId = 2; + constexpr hal::HWConfigId kConfigId = 42; + + expectHotplugConnect(kHwcDisplayId); + const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); + ASSERT_TRUE(info); + + EXPECT_CALL(*mHal, getDisplayConfigurationsSupported()).WillRepeatedly(Return(false)); + + { + EXPECT_CALL(*mHal, getDisplayConfigs(kHwcDisplayId, _)) + .WillOnce(Return(HalError::BAD_DISPLAY)); + EXPECT_TRUE(mHwc.getModes(info->id).empty()); + } + { + constexpr int32_t kWidth = 480; + constexpr int32_t kHeight = 720; + constexpr int32_t kConfigGroup = 1; + constexpr int32_t kVsyncPeriod = 16666667; + + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::WIDTH, + _)) + .WillRepeatedly(DoAll(SetArgPointee<3>(kWidth), Return(HalError::NONE))); + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, + IComposerClient::Attribute::HEIGHT, _)) + .WillRepeatedly(DoAll(SetArgPointee<3>(kHeight), Return(HalError::NONE))); + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, + IComposerClient::Attribute::CONFIG_GROUP, _)) + .WillRepeatedly(DoAll(SetArgPointee<3>(kConfigGroup), Return(HalError::NONE))); + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, + IComposerClient::Attribute::VSYNC_PERIOD, _)) + .WillRepeatedly(DoAll(SetArgPointee<3>(kVsyncPeriod), Return(HalError::NONE))); + + // Optional Parameters UNSUPPORTED + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::DPI_X, + _)) + .WillOnce(Return(HalError::UNSUPPORTED)); + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::DPI_Y, + _)) + .WillOnce(Return(HalError::UNSUPPORTED)); + + EXPECT_CALL(*mHal, getDisplayConfigs(kHwcDisplayId, _)) + .WillRepeatedly(DoAll(SetArgPointee<1>(std::vector{kConfigId}), + Return(HalError::NONE))); + + auto modes = mHwc.getModes(info->id); + EXPECT_EQ(modes.size(), size_t{1}); + EXPECT_EQ(modes.front().hwcId, kConfigId); + EXPECT_EQ(modes.front().width, kWidth); + EXPECT_EQ(modes.front().height, kHeight); + EXPECT_EQ(modes.front().configGroup, kConfigGroup); + EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); + EXPECT_EQ(modes.front().dpiX, -1); + EXPECT_EQ(modes.front().dpiY, -1); + + // Optional parameters are supported + constexpr int32_t kDpi = 320; + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::DPI_X, + _)) + .WillOnce(DoAll(SetArgPointee<3>(kDpi), Return(HalError::NONE))); + EXPECT_CALL(*mHal, + getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::DPI_Y, + _)) + .WillOnce(DoAll(SetArgPointee<3>(kDpi), Return(HalError::NONE))); + + modes = mHwc.getModes(info->id); + EXPECT_EQ(modes.size(), size_t{1}); + EXPECT_EQ(modes.front().hwcId, kConfigId); + EXPECT_EQ(modes.front().width, kWidth); + EXPECT_EQ(modes.front().height, kHeight); + EXPECT_EQ(modes.front().configGroup, kConfigGroup); + EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); + // DPI values are scaled by 1000 in the legacy implementation. + EXPECT_EQ(modes.front().dpiX, kDpi / 1000.f); + EXPECT_EQ(modes.front().dpiY, kDpi / 1000.f); + } +} + +TEST_F(HWComposerTest, getModesWithDisplayConfigurations) { + constexpr hal::HWDisplayId kHwcDisplayId = 2; + constexpr hal::HWConfigId kConfigId = 42; + expectHotplugConnect(kHwcDisplayId); + const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); + ASSERT_TRUE(info); + + EXPECT_CALL(*mHal, getDisplayConfigurationsSupported()).WillRepeatedly(Return(true)); + + { + EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _)) + .WillOnce(Return(HalError::BAD_DISPLAY)); + EXPECT_TRUE(mHwc.getModes(info->id).empty()); + } + { + constexpr int32_t kWidth = 480; + constexpr int32_t kHeight = 720; + constexpr int32_t kConfigGroup = 1; + constexpr int32_t kVsyncPeriod = 16666667; + hal::DisplayConfiguration displayConfiguration; + displayConfiguration.configId = kConfigId; + displayConfiguration.configGroup = kConfigGroup; + displayConfiguration.height = kHeight; + displayConfiguration.width = kWidth; + displayConfiguration.vsyncPeriod = kVsyncPeriod; + + EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _)) + .WillOnce(DoAll(SetArgPointee<1>(std::vector{ + displayConfiguration}), + Return(HalError::NONE))); + + // Optional dpi not supported + auto modes = mHwc.getModes(info->id); + EXPECT_EQ(modes.size(), size_t{1}); + EXPECT_EQ(modes.front().hwcId, kConfigId); + EXPECT_EQ(modes.front().width, kWidth); + EXPECT_EQ(modes.front().height, kHeight); + EXPECT_EQ(modes.front().configGroup, kConfigGroup); + EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); + EXPECT_EQ(modes.front().dpiX, -1); + EXPECT_EQ(modes.front().dpiY, -1); + + // Supports optional dpi parameter + constexpr int32_t kDpi = 320; + displayConfiguration.dpi = {kDpi, kDpi}; + + EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _)) + .WillOnce(DoAll(SetArgPointee<1>(std::vector{ + displayConfiguration}), + Return(HalError::NONE))); + + modes = mHwc.getModes(info->id); + EXPECT_EQ(modes.size(), size_t{1}); + EXPECT_EQ(modes.front().hwcId, kConfigId); + EXPECT_EQ(modes.front().width, kWidth); + EXPECT_EQ(modes.front().height, kHeight); + EXPECT_EQ(modes.front().configGroup, kConfigGroup); + EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); + EXPECT_EQ(modes.front().dpiX, kDpi); + EXPECT_EQ(modes.front().dpiY, kDpi); + } +} + TEST_F(HWComposerTest, onVsync) { constexpr hal::HWDisplayId kHwcDisplayId = 1; expectHotplugConnect(kHwcDisplayId); diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index d3fb9fc3f8..8d48940aa9 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -51,6 +51,7 @@ public: ~Composer() override; MOCK_METHOD(bool, isSupported, (OptionalFeature), (const, override)); + MOCK_METHOD(bool, getDisplayConfigurationsSupported, (), (const, override)); MOCK_METHOD0(getCapabilities, std::vector()); MOCK_METHOD0(dumpDebugInfo, std::string()); @@ -70,6 +71,7 @@ public: MOCK_METHOD4(getDisplayAttribute, Error(Display, Config config, IComposerClient::Attribute, int32_t*)); MOCK_METHOD2(getDisplayConfigs, Error(Display, std::vector*)); + MOCK_METHOD2(getDisplayConfigurations, Error(Display, std::vector*)); MOCK_METHOD2(getDisplayName, Error(Display, std::string*)); MOCK_METHOD4(getDisplayRequests, Error(Display, uint32_t*, std::vector*, std::vector*)); -- GitLab From d2bfbb3276003e6a5d8eb4dddab633eff4d4e346 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 18 Jul 2023 00:45:45 +0000 Subject: [PATCH 0293/1187] [sf] Trigger input updates in post composition Move input updates off the hotpath. This doesn't affect input latency. We are updating the data input uses for hit testing after the composition hotpath. The data is pushed via an async call. If the caller wants to ensure the data is observable in inputflinger, they can add a window info reported listener. Bug: 256882630 Test: presubmit Test: perfetto traces Change-Id: If35b02d5754dd71c73a4ae23e318e3e8b0ada83b --- services/surfaceflinger/SurfaceFlinger.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 648409c40c..a9a1d80830 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2523,7 +2523,9 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) } updateCursorAsync(); - updateInputFlinger(vsyncId, pacesetterFrameTarget.frameBeginTime()); + if (!mustComposite) { + updateInputFlinger(vsyncId, pacesetterFrameTarget.frameBeginTime()); + } if (mLayerTracingEnabled && !mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { // This will block and tracing should only be enabled for debugging. @@ -2718,6 +2720,8 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr addToLayerTracing(mVisibleRegionsDirty, pacesetterFrameTarget.frameBeginTime(), vsyncId); } + updateInputFlinger(vsyncId, pacesetterFrameTarget.frameBeginTime()); + if (mVisibleRegionsDirty) mHdrLayerInfoChanged = true; mVisibleRegionsDirty = false; -- GitLab From 1007f60dbbeb49f2ddff34685d1b54bb75fc0133 Mon Sep 17 00:00:00 2001 From: mrulhania Date: Mon, 5 Jun 2023 16:10:15 -0700 Subject: [PATCH 0294/1187] Add device support in native APIs Update native permission APIs and attribution source to support iris. Ignore-AOSP-First: iris changes Bug: 283978089 Test: presubmit && atest CtsAppOpsTestCases Change-Id: Iacc591bd76c003c081fc31de2976d9c8e9fb5b0a --- .../aidl/android/content/AttributionSourceState.aidl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/permission/aidl/android/content/AttributionSourceState.aidl b/libs/permission/aidl/android/content/AttributionSourceState.aidl index ed1b37dc0b..b3fb7a7719 100644 --- a/libs/permission/aidl/android/content/AttributionSourceState.aidl +++ b/libs/permission/aidl/android/content/AttributionSourceState.aidl @@ -27,6 +27,10 @@ parcelable AttributionSourceState { int pid = -1; /** The UID that is accessing the permission protected data. */ int uid = -1; + /** The default device ID from where the permission protected data is read. + * @see Context#DEVICE_ID_DEFAULT + */ + int deviceId = 0; /** The package that is accessing the permission protected data. */ @nullable @utf8InCpp String packageName; /** The attribution tag of the app accessing the permission protected data. */ -- GitLab From ec0eac2dedfae2fe416469b4e4e1d6bb1004b00d Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Sat, 28 Jan 2023 16:16:19 -0500 Subject: [PATCH 0295/1187] SF: Report missed frames per display Create a FrameTargeter per display, each with its own present fences and metrics about missed frames. Label the traces for missed frames with the DisplayId. Track CompositionCoverage per display. Fixes: 262269033 Bug: 241285475 Test: Perfetto Test: dumpsys SurfaceFlinger --scheduler Change-Id: I0e599c602b9fd9ae4446dd076dea4b8a75652bd4 --- .../surfaceflinger/Scheduler/Scheduler.cpp | 79 ++++++-- services/surfaceflinger/Scheduler/Scheduler.h | 31 ++- .../include/scheduler/FrameTargeter.h | 15 +- .../scheduler/interface/CompositeResult.h | 5 + .../scheduler/interface/CompositionCoverage.h | 12 ++ .../include/scheduler/interface/ICompositor.h | 8 +- .../Scheduler/src/FrameTargeter.cpp | 10 +- .../Scheduler/tests/FrameTargeterTest.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 176 +++++++++++------- services/surfaceflinger/SurfaceFlinger.h | 23 ++- .../fuzzer/surfaceflinger_fuzzers_utils.h | 32 ++-- .../surfaceflinger_scheduler_fuzzer.cpp | 11 +- .../tests/unittests/MessageQueueTest.cpp | 5 +- .../tests/unittests/TestableScheduler.h | 5 +- .../tests/unittests/TestableSurfaceFlinger.h | 15 +- 15 files changed, 295 insertions(+), 134 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 08667bfdec..eeae93211e 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -130,8 +131,8 @@ void Scheduler::registerDisplayInternal(PhysicalDisplayId displayId, auto [pacesetterVsyncSchedule, isNew] = [&]() FTL_FAKE_GUARD(kMainThreadContext) { std::scoped_lock lock(mDisplayLock); const bool isNew = mDisplays - .emplace_or_replace(displayId, std::move(selectorPtr), - std::move(schedulePtr)) + .emplace_or_replace(displayId, displayId, std::move(selectorPtr), + std::move(schedulePtr), mFeatures) .second; return std::make_pair(promotePacesetterDisplayLocked(), isNew); @@ -171,21 +172,43 @@ void Scheduler::run() { void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, TimePoint expectedVsyncTime) { - mPacesetterFrameTargeter.beginFrame({.frameBeginTime = SchedulerClock::now(), - .vsyncId = vsyncId, - .expectedVsyncTime = expectedVsyncTime, - .sfWorkDuration = - mVsyncModulator->getVsyncConfig().sfWorkDuration}, - *getVsyncSchedule()); - - if (!compositor.commit(mPacesetterFrameTargeter.target())) { - return; + const FrameTargeter::BeginFrameArgs beginFrameArgs = + {.frameBeginTime = SchedulerClock::now(), + .vsyncId = vsyncId, + // TODO(b/255601557): Calculate per display. + .expectedVsyncTime = expectedVsyncTime, + .sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration}; + + LOG_ALWAYS_FATAL_IF(!mPacesetterDisplayId); + const auto pacesetterId = *mPacesetterDisplayId; + const auto pacesetterOpt = mDisplays.get(pacesetterId); + + FrameTargeter& pacesetterTargeter = *pacesetterOpt->get().targeterPtr; + pacesetterTargeter.beginFrame(beginFrameArgs, *pacesetterOpt->get().schedulePtr); + + if (!compositor.commit(pacesetterTargeter.target())) return; + + // TODO(b/256196556): Choose the frontrunner display. + FrameTargeters targeters; + targeters.try_emplace(pacesetterId, &pacesetterTargeter); + + for (auto& [id, display] : mDisplays) { + if (id == pacesetterId) continue; + + FrameTargeter& targeter = *display.targeterPtr; + targeter.beginFrame(beginFrameArgs, *display.schedulePtr); + + targeters.try_emplace(id, &targeter); } - const auto compositeResult = compositor.composite(mPacesetterFrameTargeter); + const auto resultsPerDisplay = compositor.composite(pacesetterId, targeters); compositor.sample(); - mPacesetterFrameTargeter.endFrame(compositeResult); + for (const auto& [id, targeter] : targeters) { + const auto resultOpt = resultsPerDisplay.get(id); + LOG_ALWAYS_FATAL_IF(!resultOpt); + targeter->endFrame(*resultOpt); + } } std::optional Scheduler::getFrameRateOverride(uid_t uid) const { @@ -539,8 +562,16 @@ bool Scheduler::addResyncSample(PhysicalDisplayId id, nsecs_t timestamp, } void Scheduler::addPresentFence(PhysicalDisplayId id, std::shared_ptr fence) { - auto schedule = getVsyncSchedule(id); - LOG_ALWAYS_FATAL_IF(!schedule); + const auto scheduleOpt = + (ftl::FakeGuard(mDisplayLock), mDisplays.get(id)).and_then([](const Display& display) { + return display.powerMode == hal::PowerMode::OFF + ? std::nullopt + : std::make_optional(display.schedulePtr); + }); + + if (!scheduleOpt) return; + const auto& schedule = scheduleOpt->get(); + if (const bool needMoreSignals = schedule->getController().addPresentFence(std::move(fence))) { schedule->enableHardwareVsync(); } else { @@ -750,7 +781,23 @@ void Scheduler::dump(utils::Dumper& dumper) const { mFrameRateOverrideMappings.dump(dumper); dumper.eol(); - mPacesetterFrameTargeter.dump(dumper); + { + utils::Dumper::Section section(dumper, "Frame Targeting"sv); + + std::scoped_lock lock(mDisplayLock); + ftl::FakeGuard guard(kMainThreadContext); + + for (const auto& [id, display] : mDisplays) { + utils::Dumper::Section + section(dumper, + id == mPacesetterDisplayId + ? ftl::Concat("Pacesetter Display ", id.value).c_str() + : ftl::Concat("Follower Display ", id.value).c_str()); + + display.targeterPtr->dump(dumper); + dumper.eol(); + } + } } void Scheduler::dumpVsync(std::string& out) const { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 0ffa2d2022..8f51e5d7ee 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -222,7 +222,7 @@ public: // otherwise. bool addResyncSample(PhysicalDisplayId, nsecs_t timestamp, std::optional hwcVsyncPeriod); - void addPresentFence(PhysicalDisplayId, std::shared_ptr) EXCLUDES(mDisplayLock) + void addPresentFence(PhysicalDisplayId, std::shared_ptr) REQUIRES(kMainThreadContext); // Layers are registered on creation, and unregistered when the weak reference expires. @@ -254,7 +254,14 @@ public: return std::const_pointer_cast(std::as_const(*this).getVsyncSchedule(idOpt)); } - const FrameTarget& pacesetterFrameTarget() { return mPacesetterFrameTargeter.target(); } + TimePoint expectedPresentTimeForPacesetter() const EXCLUDES(mDisplayLock) { + std::scoped_lock lock(mDisplayLock); + return pacesetterDisplayLocked() + .transform([](const Display& display) { + return display.targeterPtr->target().expectedPresentTime(); + }) + .value_or(TimePoint()); + } // Returns true if a given vsync timestamp is considered valid vsync // for a given uid @@ -308,7 +315,8 @@ private: enum class TouchState { Inactive, Active }; // impl::MessageQueue overrides: - void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override; + void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override + REQUIRES(kMainThreadContext, mDisplayLock); // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr); @@ -434,13 +442,24 @@ private: // must lock for writes but not reads. See also mPolicyLock for locking order. mutable std::mutex mDisplayLock; + using FrameTargeterPtr = std::unique_ptr; + struct Display { - Display(RefreshRateSelectorPtr selectorPtr, VsyncSchedulePtr schedulePtr) - : selectorPtr(std::move(selectorPtr)), schedulePtr(std::move(schedulePtr)) {} + Display(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr, + VsyncSchedulePtr schedulePtr, FeatureFlags features) + : displayId(displayId), + selectorPtr(std::move(selectorPtr)), + schedulePtr(std::move(schedulePtr)), + targeterPtr(std::make_unique< + FrameTargeter>(displayId, + features.test(Feature::kBackpressureGpuComposition))) {} + + const PhysicalDisplayId displayId; // Effectively const except in move constructor. RefreshRateSelectorPtr selectorPtr; VsyncSchedulePtr schedulePtr; + FrameTargeterPtr targeterPtr; hal::PowerMode powerMode = hal::PowerMode::OFF; }; @@ -454,8 +473,6 @@ private: ftl::Optional mPacesetterDisplayId GUARDED_BY(mDisplayLock) GUARDED_BY(kMainThreadContext); - FrameTargeter mPacesetterFrameTargeter{mFeatures.test(Feature::kBackpressureGpuComposition)}; - ftl::Optional pacesetterDisplayLocked() REQUIRES(mDisplayLock) { return static_cast(this)->pacesetterDisplayLocked().transform( [](const Display& display) { return std::ref(const_cast(display)); }); diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h index 85f2e64faa..ae74205720 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -75,16 +76,17 @@ public: bool didMissHwcFrame() const { return mHwcFrameMissed && !mGpuFrameMissed; } protected: + explicit FrameTarget(const std::string& displayLabel); ~FrameTarget() = default; VsyncId mVsyncId; TimePoint mFrameBeginTime; TimePoint mExpectedPresentTime; - TracedOrdinal mFramePending{"PrevFramePending", false}; - TracedOrdinal mFrameMissed{"PrevFrameMissed", false}; - TracedOrdinal mHwcFrameMissed{"PrevHwcFrameMissed", false}; - TracedOrdinal mGpuFrameMissed{"PrevGpuFrameMissed", false}; + TracedOrdinal mFramePending; + TracedOrdinal mFrameMissed; + TracedOrdinal mHwcFrameMissed; + TracedOrdinal mGpuFrameMissed; struct FenceWithFenceTime { sp fence = Fence::NO_FENCE; @@ -103,8 +105,9 @@ private: // Computes a display's per-frame metrics about past/upcoming targeting of present deadlines. class FrameTargeter final : private FrameTarget { public: - explicit FrameTargeter(bool backpressureGpuComposition) - : mBackpressureGpuComposition(backpressureGpuComposition) {} + FrameTargeter(PhysicalDisplayId displayId, bool backpressureGpuComposition) + : FrameTarget(to_string(displayId)), + mBackpressureGpuComposition(backpressureGpuComposition) {} const FrameTarget& target() const { return *this; } diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h index f795f1f09d..87c704ece3 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h @@ -16,6 +16,9 @@ #pragma once +#include +#include + #include namespace android { @@ -24,4 +27,6 @@ struct CompositeResult { CompositionCoverageFlags compositionCoverage; }; +using CompositeResultsPerDisplay = ui::PhysicalDisplayMap; + } // namespace android diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h index 3d0f1a9d33..767462dfce 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h @@ -19,6 +19,8 @@ #include #include +#include +#include namespace android { @@ -34,4 +36,14 @@ enum class CompositionCoverage : std::uint8_t { using CompositionCoverageFlags = ftl::Flags; +using CompositionCoveragePerDisplay = ui::DisplayMap; + +inline CompositionCoverageFlags multiDisplayUnion(const CompositionCoveragePerDisplay& displays) { + CompositionCoverageFlags coverage; + for (const auto& [id, flags] : displays) { + coverage |= flags; + } + return coverage; +} + } // namespace android diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h index 26960766e5..6fe813a181 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h @@ -16,6 +16,9 @@ #pragma once +#include +#include + #include #include #include @@ -26,6 +29,8 @@ namespace scheduler { class FrameTarget; class FrameTargeter; +using FrameTargeters = ui::PhysicalDisplayMap; + } // namespace scheduler struct ICompositor { @@ -38,7 +43,8 @@ struct ICompositor { // Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition // via RenderEngine and the Composer HAL, respectively. - virtual CompositeResult composite(scheduler::FrameTargeter&) = 0; + virtual CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId, + const scheduler::FrameTargeters&) = 0; // Samples the composited frame via RegionSamplingThread. virtual void sample() = 0; diff --git a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp index 7138afdf8b..7a18654346 100644 --- a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp +++ b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp @@ -21,6 +21,12 @@ namespace android::scheduler { +FrameTarget::FrameTarget(const std::string& displayLabel) + : mFramePending("PrevFramePending " + displayLabel, false), + mFrameMissed("PrevFrameMissed " + displayLabel, false), + mHwcFrameMissed("PrevHwcFrameMissed " + displayLabel, false), + mGpuFrameMissed("PrevGpuFrameMissed " + displayLabel, false) {} + TimePoint FrameTarget::pastVsyncTime(Period vsyncPeriod) const { // TODO(b/267315508): Generalize to N VSYNCs. const int shift = static_cast(targetsVsyncsAhead<2>(vsyncPeriod)); @@ -130,10 +136,6 @@ FenceTimePtr FrameTargeter::setPresentFence(sp presentFence, FenceTimePtr } void FrameTargeter::dump(utils::Dumper& dumper) const { - using namespace std::string_view_literals; - - utils::Dumper::Section section(dumper, "Frame Targeting"sv); - // There are scripts and tests that expect this (rather than "name=value") format. dumper.dump({}, "Total missed frame count: " + std::to_string(mFrameMissedCount)); dumper.dump({}, "HWC missed frame count: " + std::to_string(mHwcFrameMissedCount)); diff --git a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp index 908f214e85..1e038d1753 100644 --- a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp +++ b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp @@ -96,7 +96,7 @@ private: FenceToFenceTimeMap mFenceMap; static constexpr bool kBackpressureGpuComposition = true; - FrameTargeter mTargeter{kBackpressureGpuComposition}; + FrameTargeter mTargeter{PhysicalDisplayId::fromPort(13), kBackpressureGpuComposition}; }; TEST_F(FrameTargeterTest, targetsFrames) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a9a1d80830..711bea56bf 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2181,7 +2181,7 @@ void SurfaceFlinger::onRefreshRateChangedDebug(const RefreshRateChangedDebugData } } -void SurfaceFlinger::configure() FTL_FAKE_GUARD(kMainThreadContext) { +void SurfaceFlinger::configure() { Mutex::Autolock lock(mStateLock); if (configureLocked()) { setTransactionFlags(eDisplayTransactionNeeded); @@ -2401,8 +2401,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, return mustComposite; } -bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) - FTL_FAKE_GUARD(kMainThreadContext) { +bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) { const VsyncId vsyncId = pacesetterFrameTarget.vsyncId(); ATRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str()); @@ -2538,31 +2537,42 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER); } -CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFrameTargeter) - FTL_FAKE_GUARD(kMainThreadContext) { - const scheduler::FrameTarget& pacesetterFrameTarget = pacesetterFrameTargeter.target(); +CompositeResultsPerDisplay SurfaceFlinger::composite( + PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters& frameTargeters) { + const scheduler::FrameTarget& pacesetterTarget = + frameTargeters.get(pacesetterId)->get()->target(); - const VsyncId vsyncId = pacesetterFrameTarget.vsyncId(); + const VsyncId vsyncId = pacesetterTarget.vsyncId(); ATRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str()); compositionengine::CompositionRefreshArgs refreshArgs; refreshArgs.powerCallback = this; const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays); refreshArgs.outputs.reserve(displays.size()); + + // Add outputs for physical displays. + for (const auto& [id, targeter] : frameTargeters) { + ftl::FakeGuard guard(mStateLock); + + if (const auto display = getCompositionDisplayLocked(id)) { + refreshArgs.outputs.push_back(display); + } + } + std::vector displayIds; for (const auto& [_, display] : displays) { displayIds.push_back(display->getId()); display->tracePowerMode(); + // Add outputs for virtual displays. if (display->isVirtual()) { const Fps refreshRate = display->getAdjustedRefreshRate(); - if (refreshRate.isValid() && - !mScheduler->isVsyncInPhase(pacesetterFrameTarget.frameBeginTime(), refreshRate)) { - continue; + + if (!refreshRate.isValid() || + mScheduler->isVsyncInPhase(pacesetterTarget.frameBeginTime(), refreshRate)) { + refreshArgs.outputs.push_back(display->getCompositionDisplay()); } } - - refreshArgs.outputs.push_back(display->getCompositionDisplay()); } mPowerAdvisor->setDisplays(displayIds); @@ -2622,15 +2632,16 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr if (!getHwComposer().getComposer()->isSupported( Hwc2::Composer::OptionalFeature::ExpectedPresentTime) && - pacesetterFrameTarget.wouldPresentEarly(vsyncPeriod)) { + pacesetterTarget.wouldPresentEarly(vsyncPeriod)) { const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration; + // TODO(b/255601557): Calculate and pass per-display values for each FrameTarget. refreshArgs.earliestPresentTime = - pacesetterFrameTarget.previousFrameVsyncTime(vsyncPeriod) - hwcMinWorkDuration; + pacesetterTarget.previousFrameVsyncTime(vsyncPeriod) - hwcMinWorkDuration; } refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime(); - refreshArgs.expectedPresentTime = pacesetterFrameTarget.expectedPresentTime().ns(); + refreshArgs.expectedPresentTime = pacesetterTarget.expectedPresentTime().ns(); refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0; // Store the present time just before calling to the composition engine so we could notify @@ -2656,14 +2667,14 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr } } - mTimeStats->recordFrameDuration(pacesetterFrameTarget.frameBeginTime().ns(), systemTime()); + mTimeStats->recordFrameDuration(pacesetterTarget.frameBeginTime().ns(), systemTime()); // Send a power hint after presentation is finished. if (mPowerHintSessionEnabled) { // Now that the current frame has been presented above, PowerAdvisor needs the present time // of the previous frame (whose fence is signaled by now) to determine how long the HWC had // waited on that fence to retire before presenting. - const auto& previousPresentFence = pacesetterFrameTarget.presentFenceForPreviousFrame(); + const auto& previousPresentFence = pacesetterTarget.presentFenceForPreviousFrame(); mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(previousPresentFence->getSignalTime()), TimePoint::now()); @@ -2674,23 +2685,27 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr scheduleComposite(FrameHint::kNone); } - postComposition(pacesetterFrameTargeter, presentTime); + postComposition(pacesetterId, frameTargeters, presentTime); - const bool hadGpuComposited = mCompositionCoverage.test(CompositionCoverage::Gpu); + const bool hadGpuComposited = + multiDisplayUnion(mCompositionCoverage).test(CompositionCoverage::Gpu); mCompositionCoverage.clear(); TimeStats::ClientCompositionRecord clientCompositionRecord; + for (const auto& [_, display] : displays) { const auto& state = display->getCompositionDisplay()->getState(); + CompositionCoverageFlags& flags = + mCompositionCoverage.try_emplace(display->getId()).first->second; if (state.usesDeviceComposition) { - mCompositionCoverage |= CompositionCoverage::Hwc; + flags |= CompositionCoverage::Hwc; } if (state.reusedClientComposition) { - mCompositionCoverage |= CompositionCoverage::GpuReuse; + flags |= CompositionCoverage::GpuReuse; } else if (state.usesClientComposition) { - mCompositionCoverage |= CompositionCoverage::Gpu; + flags |= CompositionCoverage::Gpu; } clientCompositionRecord.predicted |= @@ -2699,10 +2714,11 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr (state.strategyPrediction == CompositionStrategyPredictionState::SUCCESS); } - const bool hasGpuComposited = mCompositionCoverage.test(CompositionCoverage::Gpu); + const auto coverage = multiDisplayUnion(mCompositionCoverage); + const bool hasGpuComposited = coverage.test(CompositionCoverage::Gpu); clientCompositionRecord.hadClientComposition = hasGpuComposited; - clientCompositionRecord.reused = mCompositionCoverage.test(CompositionCoverage::GpuReuse); + clientCompositionRecord.reused = coverage.test(CompositionCoverage::GpuReuse); clientCompositionRecord.changed = hadGpuComposited != hasGpuComposited; mTimeStats->pushCompositionStrategyState(clientCompositionRecord); @@ -2711,16 +2727,16 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr // TODO(b/160583065): Enable skip validation when SF caches all client composition layers. const bool hasGpuUseOrReuse = - mCompositionCoverage.any(CompositionCoverage::Gpu | CompositionCoverage::GpuReuse); + coverage.any(CompositionCoverage::Gpu | CompositionCoverage::GpuReuse); mScheduler->modulateVsync({}, &VsyncModulator::onDisplayRefresh, hasGpuUseOrReuse); mLayersWithQueuedFrames.clear(); if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { // This will block and should only be used for debugging. - addToLayerTracing(mVisibleRegionsDirty, pacesetterFrameTarget.frameBeginTime(), vsyncId); + addToLayerTracing(mVisibleRegionsDirty, pacesetterTarget.frameBeginTime(), vsyncId); } - updateInputFlinger(vsyncId, pacesetterFrameTarget.frameBeginTime()); + updateInputFlinger(vsyncId, pacesetterTarget.frameBeginTime()); if (mVisibleRegionsDirty) mHdrLayerInfoChanged = true; mVisibleRegionsDirty = false; @@ -2733,7 +2749,16 @@ CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFr mPowerAdvisor->setCompositeEnd(TimePoint::now()); } - return {mCompositionCoverage}; + CompositeResultsPerDisplay resultsPerDisplay; + + // Filter out virtual displays. + for (const auto& [id, coverage] : mCompositionCoverage) { + if (const auto idOpt = PhysicalDisplayId::tryCast(id)) { + resultsPerDisplay.try_emplace(*idOpt, CompositeResult{coverage}); + } + } + + return resultsPerDisplay; } void SurfaceFlinger::updateLayerGeometry() { @@ -2817,35 +2842,56 @@ ui::Rotation SurfaceFlinger::getPhysicalDisplayOrientation(DisplayId displayId, return ui::ROTATION_0; } -void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTargeter, +void SurfaceFlinger::postComposition(PhysicalDisplayId pacesetterId, + const scheduler::FrameTargeters& frameTargeters, nsecs_t presentStartTime) { ATRACE_CALL(); ALOGV(__func__); - const auto* defaultDisplay = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get(); + ui::PhysicalDisplayMap> presentFences; + ui::PhysicalDisplayMap> gpuCompositionDoneFences; - std::shared_ptr glCompositionDoneFenceTime; - if (defaultDisplay && - defaultDisplay->getCompositionDisplay()->getState().usesClientComposition) { - glCompositionDoneFenceTime = - std::make_shared(defaultDisplay->getCompositionDisplay() - ->getRenderSurface() - ->getClientTargetAcquireFence()); - } else { - glCompositionDoneFenceTime = FenceTime::NO_FENCE; + for (const auto& [id, targeter] : frameTargeters) { + auto presentFence = getHwComposer().getPresentFence(id); + + if (id == pacesetterId) { + mTransactionCallbackInvoker.addPresentFence(presentFence); + } + + if (auto fenceTime = targeter->setPresentFence(std::move(presentFence)); + fenceTime->isValid()) { + presentFences.try_emplace(id, std::move(fenceTime)); + } + + ftl::FakeGuard guard(mStateLock); + if (const auto display = getCompositionDisplayLocked(id); + display && display->getState().usesClientComposition) { + gpuCompositionDoneFences + .try_emplace(id, display->getRenderSurface()->getClientTargetAcquireFence()); + } } - auto presentFence = defaultDisplay - ? getHwComposer().getPresentFence(defaultDisplay->getPhysicalId()) - : Fence::NO_FENCE; + const auto pacesetterDisplay = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(pacesetterId)); + + std::shared_ptr pacesetterPresentFenceTime = + presentFences.get(pacesetterId) + .transform([](const FenceTimePtr& ptr) { return ptr; }) + .value_or(FenceTime::NO_FENCE); + + std::shared_ptr pacesetterGpuCompositionDoneFenceTime = + gpuCompositionDoneFences.get(pacesetterId) + .transform([](sp fence) { + return std::make_shared(std::move(fence)); + }) + .value_or(FenceTime::NO_FENCE); - auto presentFenceTime = pacesetterFrameTargeter.setPresentFence(presentFence); const TimePoint presentTime = TimePoint::now(); // Set presentation information before calling Layer::releasePendingBuffer, such that jank // information from previous' frame classification is already available when sending jank info // to clients, so they get jank classification as early as possible. - mFrameTimeline->setSfPresent(presentTime.ns(), presentFenceTime, glCompositionDoneFenceTime); + mFrameTimeline->setSfPresent(presentTime.ns(), pacesetterPresentFenceTime, + pacesetterGpuCompositionDoneFenceTime); // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might // be sampled a little later than when we started doing work for this frame, @@ -2853,9 +2899,9 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa const TimePoint compositeTime = TimePoint::fromNs(mCompositionEngine->getLastFrameRefreshTimestamp()); const Duration presentLatency = - !getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE) - ? mPresentLatencyTracker.trackPendingFrame(compositeTime, presentFenceTime) - : Duration::zero(); + getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE) + ? Duration::zero() + : mPresentLatencyTracker.trackPendingFrame(compositeTime, pacesetterPresentFenceTime); const auto schedule = mScheduler->getVsyncSchedule(); const TimePoint vsyncDeadline = schedule->vsyncDeadlineAfter(presentTime); @@ -2892,8 +2938,8 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa mLayersWithBuffersRemoved.clear(); for (const auto& layer: mLayersWithQueuedFrames) { - layer->onPostComposition(defaultDisplay, glCompositionDoneFenceTime, presentFenceTime, - compositorTiming); + layer->onPostComposition(pacesetterDisplay.get(), pacesetterGpuCompositionDoneFenceTime, + pacesetterPresentFenceTime, compositorTiming); layer->releasePendingBuffer(presentTime.ns()); } @@ -2980,38 +3026,32 @@ void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTa mHdrLayerInfoChanged = false; - mTransactionCallbackInvoker.addPresentFence(std::move(presentFence)); mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */); mTransactionCallbackInvoker.clearCompletedTransactions(); mTimeStats->incrementTotalFrames(); - mTimeStats->setPresentFenceGlobal(presentFenceTime); + mTimeStats->setPresentFenceGlobal(pacesetterPresentFenceTime); - { + for (auto&& [id, presentFence] : presentFences) { ftl::FakeGuard guard(mStateLock); - for (const auto& [id, physicalDisplay] : mPhysicalDisplays) { - if (auto displayDevice = getDisplayDeviceLocked(id); - displayDevice && displayDevice->isPoweredOn() && physicalDisplay.isInternal()) { - auto presentFenceTimeI = defaultDisplay && defaultDisplay->getPhysicalId() == id - ? std::move(presentFenceTime) - : std::make_shared(getHwComposer().getPresentFence(id)); - if (presentFenceTimeI->isValid()) { - mScheduler->addPresentFence(id, std::move(presentFenceTimeI)); - } - } + const bool isInternalDisplay = + mPhysicalDisplays.get(id).transform(&PhysicalDisplay::isInternal).value_or(false); + + if (isInternalDisplay) { + mScheduler->addPresentFence(id, std::move(presentFence)); } } - const bool isDisplayConnected = - defaultDisplay && getHwComposer().isConnected(defaultDisplay->getPhysicalId()); + const bool hasPacesetterDisplay = + pacesetterDisplay && getHwComposer().isConnected(pacesetterId); if (!hasSyncFramework) { - if (isDisplayConnected && defaultDisplay->isPoweredOn()) { - mScheduler->enableHardwareVsync(defaultDisplay->getPhysicalId()); + if (hasPacesetterDisplay && pacesetterDisplay->isPoweredOn()) { + mScheduler->enableHardwareVsync(pacesetterId); } } - if (isDisplayConnected && !defaultDisplay->isPoweredOn()) { + if (hasPacesetterDisplay && !pacesetterDisplay->isPoweredOn()) { getRenderEngine().cleanupPostRender(); return; } @@ -4298,7 +4338,7 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyTimelin const auto& transaction = *flushState.transaction; const TimePoint desiredPresentTime = TimePoint::fromNs(transaction.desiredPresentTime); - const TimePoint expectedPresentTime = mScheduler->pacesetterFrameTarget().expectedPresentTime(); + const TimePoint expectedPresentTime = mScheduler->expectedPresentTimeForPacesetter(); using TransactionReadiness = TransactionHandler::TransactionReadiness; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index aeaeb47210..3d46239759 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -636,9 +636,12 @@ private: void onRefreshRateChangedDebug(const RefreshRateChangedDebugData&) override; // ICompositor overrides: - void configure() override; - bool commit(const scheduler::FrameTarget&) override; - CompositeResult composite(scheduler::FrameTargeter&) override; + void configure() override REQUIRES(kMainThreadContext); + bool commit(const scheduler::FrameTarget&) override REQUIRES(kMainThreadContext); + CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId, + const scheduler::FrameTargeters&) override + REQUIRES(kMainThreadContext); + void sample() override; // ISchedulerCallback overrides: @@ -891,6 +894,14 @@ private: return findDisplay([id](const auto& display) { return display.getId() == id; }); } + std::shared_ptr getCompositionDisplayLocked(DisplayId id) const + REQUIRES(mStateLock) { + if (const auto display = getDisplayDeviceLocked(id)) { + return display->getCompositionDisplay(); + } + return nullptr; + } + // Returns the primary display or (for foldables) the active display, assuming that the inner // and outer displays have mutually exclusive power states. sp getDefaultDisplayDeviceLocked() const REQUIRES(mStateLock) { @@ -964,8 +975,8 @@ private: /* * Compositing */ - void postComposition(scheduler::FrameTargeter&, nsecs_t presentStartTime) - REQUIRES(kMainThreadContext); + void postComposition(PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters&, + nsecs_t presentStartTime) REQUIRES(kMainThreadContext); /* * Display management @@ -1298,7 +1309,7 @@ private: std::unique_ptr mCompositionEngine; - CompositionCoverageFlags mCompositionCoverage; + CompositionCoveragePerDisplay mCompositionCoverage; // mMaxRenderTargetSize is only set once in init() so it doesn't need to be protected by // any mutex. diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 00e92a18ff..28ac664ba3 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -287,7 +287,10 @@ private: // ICompositor overrides: void configure() override {} bool commit(const scheduler::FrameTarget&) override { return false; } - CompositeResult composite(scheduler::FrameTargeter&) override { return {}; } + CompositeResultsPerDisplay composite(PhysicalDisplayId, + const scheduler::FrameTargeters&) override { + return {}; + } void sample() override {} // MessageQueue overrides: @@ -474,25 +477,25 @@ public: &outWideColorGamutPixelFormat); } - void overrideHdrTypes(sp &display, FuzzedDataProvider *fdp) { + void overrideHdrTypes(const sp& display, FuzzedDataProvider* fdp) { std::vector hdrTypes; hdrTypes.push_back(fdp->PickValueInArray(kHdrTypes)); mFlinger->overrideHdrTypes(display, hdrTypes); } - void getDisplayedContentSample(sp &display, FuzzedDataProvider *fdp) { + void getDisplayedContentSample(const sp& display, FuzzedDataProvider* fdp) { DisplayedFrameStats outDisplayedFrameStats; mFlinger->getDisplayedContentSample(display, fdp->ConsumeIntegral(), fdp->ConsumeIntegral(), &outDisplayedFrameStats); } - void getDisplayStats(sp &display) { + void getDisplayStats(const sp& display) { android::DisplayStatInfo stats; mFlinger->getDisplayStats(display, &stats); } - void getDisplayState(sp &display) { + void getDisplayState(const sp& display) { ui::DisplayState displayState; mFlinger->getDisplayState(display, &displayState); } @@ -506,12 +509,12 @@ public: android::ui::DynamicDisplayInfo dynamicDisplayInfo; mFlinger->getDynamicDisplayInfoFromId(displayId, &dynamicDisplayInfo); } - void getDisplayNativePrimaries(sp &display) { + void getDisplayNativePrimaries(const sp& display) { android::ui::DisplayPrimaries displayPrimaries; mFlinger->getDisplayNativePrimaries(display, displayPrimaries); } - void getDesiredDisplayModeSpecs(sp &display) { + void getDesiredDisplayModeSpecs(const sp& display) { gui::DisplayModeSpecs _; mFlinger->getDesiredDisplayModeSpecs(display, &_); } @@ -523,7 +526,7 @@ public: return ids.front(); } - std::pair, int64_t> fuzzBoot(FuzzedDataProvider *fdp) { + std::pair, PhysicalDisplayId> fuzzBoot(FuzzedDataProvider* fdp) { mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(fdp->ConsumeBool()); const sp client = sp::make(mFlinger); @@ -550,13 +553,13 @@ public: mFlinger->bootFinished(); - return {display, physicalDisplayId.value}; + return {display, physicalDisplayId}; } void fuzzSurfaceFlinger(const uint8_t *data, size_t size) { FuzzedDataProvider mFdp(data, size); - auto [display, displayId] = fuzzBoot(&mFdp); + const auto [display, displayId] = fuzzBoot(&mFdp); sp bufferProducer = sp::make(); @@ -564,8 +567,8 @@ public: getDisplayStats(display); getDisplayState(display); - getStaticDisplayInfo(displayId); - getDynamicDisplayInfo(displayId); + getStaticDisplayInfo(displayId.value); + getDynamicDisplayInfo(displayId.value); getDisplayNativePrimaries(display); mFlinger->setAutoLowLatencyMode(display, mFdp.ConsumeBool()); @@ -605,8 +608,9 @@ public: mFlinger->commitTransactions(); mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp)); - scheduler::FrameTargeter frameTargeter(mFdp.ConsumeBool()); - mFlinger->postComposition(frameTargeter, mFdp.ConsumeIntegral()); + scheduler::FrameTargeter frameTargeter(displayId, mFdp.ConsumeBool()); + mFlinger->postComposition(displayId, ftl::init::map(displayId, &frameTargeter), + mFdp.ConsumeIntegral()); } mFlinger->setTransactionFlags(mFdp.ConsumeIntegral()); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp index b1fd06f998..4d1a5ffa67 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp @@ -50,7 +50,7 @@ constexpr PowerMode kPowerModes[] = {PowerMode::ON, PowerMode::DOZE, PowerMode:: constexpr uint16_t kRandomStringLength = 256; constexpr std::chrono::duration kSyncPeriod(16ms); -constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u); +constexpr PhysicalDisplayId kDisplayId = PhysicalDisplayId::fromPort(42u); template void dump(T* component, FuzzedDataProvider* fdp) { @@ -177,9 +177,8 @@ void SchedulerFuzzer::fuzzVSyncPredictor() { uint16_t now = mFdp.ConsumeIntegral(); uint16_t historySize = mFdp.ConsumeIntegralInRange(1, UINT16_MAX); uint16_t minimumSamplesForPrediction = mFdp.ConsumeIntegralInRange(1, UINT16_MAX); - scheduler::VSyncPredictor tracker{DEFAULT_DISPLAY_ID, - mFdp.ConsumeIntegral() /*period*/, historySize, - minimumSamplesForPrediction, + scheduler::VSyncPredictor tracker{kDisplayId, mFdp.ConsumeIntegral() /*period*/, + historySize, minimumSamplesForPrediction, mFdp.ConsumeIntegral() /*outlierTolerancePercent*/}; uint16_t period = mFdp.ConsumeIntegral(); tracker.setPeriod(period); @@ -251,7 +250,7 @@ void SchedulerFuzzer::fuzzLayerHistory() { void SchedulerFuzzer::fuzzVSyncReactor() { std::shared_ptr vSyncTracker = std::make_shared(); - scheduler::VSyncReactor reactor(DEFAULT_DISPLAY_ID, + scheduler::VSyncReactor reactor(kDisplayId, std::make_unique( std::make_shared()), *vSyncTracker, mFdp.ConsumeIntegral() /*pendingLimit*/, @@ -408,7 +407,7 @@ void SchedulerFuzzer::fuzzPresentLatencyTracker() { } void SchedulerFuzzer::fuzzFrameTargeter() { - scheduler::FrameTargeter frameTargeter(mFdp.ConsumeBool()); + scheduler::FrameTargeter frameTargeter(kDisplayId, mFdp.ConsumeBool()); const struct VsyncSource final : scheduler::IVsyncSource { explicit VsyncSource(FuzzedDataProvider& fuzzer) : fuzzer(fuzzer) {} diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp index 359e2ab7fb..1dcf222834 100644 --- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp @@ -36,7 +36,10 @@ using CallbackToken = scheduler::VSyncDispatch::CallbackToken; struct NoOpCompositor final : ICompositor { void configure() override {} bool commit(const scheduler::FrameTarget&) override { return false; } - CompositeResult composite(scheduler::FrameTargeter&) override { return {}; } + CompositeResultsPerDisplay composite(PhysicalDisplayId, + const scheduler::FrameTargeters&) override { + return {}; + } void sample() override {} } gNoOpCompositor; diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index fa7a94735f..f3c9d0dd44 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -181,7 +181,10 @@ private: // ICompositor overrides: void configure() override {} bool commit(const scheduler::FrameTarget&) override { return false; } - CompositeResult composite(scheduler::FrameTargeter&) override { return {}; } + CompositeResultsPerDisplay composite(PhysicalDisplayId, + const scheduler::FrameTargeters&) override { + return {}; + } void sample() override {} }; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 909b8b8964..9b3a893409 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -359,7 +359,10 @@ public: * Forwarding for functions being tested */ - void configure() { mFlinger->configure(); } + void configure() { + ftl::FakeGuard guard(kMainThreadContext); + mFlinger->configure(); + } void configureAndCommit() { configure(); @@ -368,8 +371,14 @@ public: void commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime, bool composite = false) { + ftl::FakeGuard guard(kMainThreadContext); + + const auto displayIdOpt = mScheduler->pacesetterDisplayId(); + LOG_ALWAYS_FATAL_IF(!displayIdOpt); + const auto displayId = *displayIdOpt; + constexpr bool kBackpressureGpuComposition = true; - scheduler::FrameTargeter frameTargeter(kBackpressureGpuComposition); + scheduler::FrameTargeter frameTargeter(displayId, kBackpressureGpuComposition); frameTargeter.beginFrame({.frameBeginTime = frameTime, .vsyncId = vsyncId, @@ -380,7 +389,7 @@ public: mFlinger->commit(frameTargeter.target()); if (composite) { - mFlinger->composite(frameTargeter); + mFlinger->composite(displayId, ftl::init::map(displayId, &frameTargeter)); } } -- GitLab From 42b918ef9d67d655d3f1c04f72354fc5eec34d95 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 18 Jul 2023 20:05:29 +0000 Subject: [PATCH 0296/1187] [sf] Update framerate correctly with new frontend In order to optimize snapshot updates, we only update the snapshot if the requested state has changed. If the hierarchy changes, we force update the children's snapshot but this is not sufficient because a parent's framerate might be affect by the child's framerate. To fix this explicitly update the framerate when the hierarchy changes. Test: presubmit Test: atest android.graphics.cts.FrameRateOverrideTest Bug: 238781169 Change-Id: Ia633e7800cf3169c944313b4220b889bec0c3c5f --- .../surfaceflinger/FrontEnd/LayerSnapshot.h | 5 -- .../FrontEnd/LayerSnapshotBuilder.cpp | 66 ++++++++++--------- .../FrontEnd/LayerSnapshotBuilder.h | 4 +- 3 files changed, 38 insertions(+), 37 deletions(-) diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 1416872f95..1afcef9e44 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -41,10 +41,6 @@ struct RoundedCornerState { } }; -struct ChildState { - bool hasValidFrameRate = false; -}; - // LayerSnapshot stores Layer state used by CompositionEngine and RenderEngine. Composition // Engine uses a pointer to LayerSnapshot (as LayerFECompositionState*) and the LayerSettings // passed to Render Engine are created using properties stored on this struct. @@ -99,7 +95,6 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { uint32_t touchCropId; gui::Uid uid = gui::Uid::INVALID; gui::Pid pid = gui::Pid::INVALID; - ChildState childState; enum class Reachablilty : uint32_t { // Can traverse the hierarchy from a root node and reach this snapshot Reachable, diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 3a19d0b389..7e678b98fa 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -558,7 +558,7 @@ const LayerSnapshot& LayerSnapshotBuilder::updateSnapshotsInHierarchy( const LayerSnapshot& childSnapshot = updateSnapshotsInHierarchy(args, *childHierarchy, traversalPath, *snapshot, depth + 1); - updateChildState(*snapshot, childSnapshot, args); + updateFrameRateFromChildSnapshot(*snapshot, childSnapshot, args); } if (oldFrameRate == snapshot->frameRate) { @@ -666,36 +666,40 @@ void LayerSnapshotBuilder::updateRelativeState(LayerSnapshot& snapshot, } } -void LayerSnapshotBuilder::updateChildState(LayerSnapshot& snapshot, - const LayerSnapshot& childSnapshot, const Args& args) { - if (snapshot.childState.hasValidFrameRate) { +void LayerSnapshotBuilder::updateFrameRateFromChildSnapshot(LayerSnapshot& snapshot, + const LayerSnapshot& childSnapshot, + const Args& args) { + if (args.forceUpdate == ForceUpdateFlags::NONE && + !childSnapshot.changes.any(RequestedLayerState::Changes::FrameRate | + RequestedLayerState::Changes::Hierarchy)) { return; } - if (args.forceUpdate == ForceUpdateFlags::ALL || - childSnapshot.changes.test(RequestedLayerState::Changes::FrameRate)) { - // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes - // for the same reason we are allowing touch boost for those layers. See - // RefreshRateSelector::rankFrameRates for details. - using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; - const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.rate.isValid() && - childSnapshot.frameRate.type == FrameRateCompatibility::Default; - const auto layerVotedWithNoVote = - childSnapshot.frameRate.type == FrameRateCompatibility::NoVote; - const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.rate.isValid() && - childSnapshot.frameRate.type == FrameRateCompatibility::Exact; - - snapshot.childState.hasValidFrameRate |= layerVotedWithDefaultCompatibility || - layerVotedWithNoVote || layerVotedWithExactCompatibility; - - // If we don't have a valid frame rate, but the children do, we set this - // layer as NoVote to allow the children to control the refresh rate - if (!snapshot.frameRate.rate.isValid() && - snapshot.frameRate.type != FrameRateCompatibility::NoVote && - snapshot.childState.hasValidFrameRate) { - snapshot.frameRate = - scheduler::LayerInfo::FrameRate(Fps(), FrameRateCompatibility::NoVote); - snapshot.changes |= childSnapshot.changes & RequestedLayerState::Changes::FrameRate; - } + + using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; + if (snapshot.frameRate.rate.isValid() || + snapshot.frameRate.type == FrameRateCompatibility::NoVote) { + // we already have a valid framerate. + return; + } + + // We return whether this layer or its children has a vote. We ignore ExactOrMultiple votes + // for the same reason we are allowing touch boost for those layers. See + // RefreshRateSelector::rankFrameRates for details. + const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.rate.isValid() && + childSnapshot.frameRate.type == FrameRateCompatibility::Default; + const auto layerVotedWithNoVote = + childSnapshot.frameRate.type == FrameRateCompatibility::NoVote; + const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.rate.isValid() && + childSnapshot.frameRate.type == FrameRateCompatibility::Exact; + + bool childHasValidFrameRate = layerVotedWithDefaultCompatibility || layerVotedWithNoVote || + layerVotedWithExactCompatibility; + + // If we don't have a valid frame rate, but the children do, we set this + // layer as NoVote to allow the children to control the refresh rate + if (childHasValidFrameRate) { + snapshot.frameRate = scheduler::LayerInfo::FrameRate(Fps(), FrameRateCompatibility::NoVote); + snapshot.changes |= RequestedLayerState::Changes::FrameRate; } } @@ -812,7 +816,9 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a } } - if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::FrameRate)) { + if (forceUpdate || + snapshot.changes.any(RequestedLayerState::Changes::FrameRate | + RequestedLayerState::Changes::Hierarchy)) { snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() || (requested.requestedFrameRate.type == scheduler::LayerInfo::FrameRateCompatibility::NoVote)) diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h index c81a5d2b9e..d361605875 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h @@ -116,8 +116,8 @@ private: LayerSnapshot* createSnapshot(const LayerHierarchy::TraversalPath& id, const RequestedLayerState& layer, const LayerSnapshot& parentSnapshot); - void updateChildState(LayerSnapshot& snapshot, const LayerSnapshot& childSnapshot, - const Args& args); + void updateFrameRateFromChildSnapshot(LayerSnapshot& snapshot, + const LayerSnapshot& childSnapshot, const Args& args); void updateTouchableRegionCrop(const Args& args); std::unordered_map Date: Tue, 11 Jul 2023 15:02:03 +0000 Subject: [PATCH 0297/1187] Pass layout info in native callback for quicker layout setup. Passing language tag and layout type to getKeyboardLayoutOverlay() callback allows us to setup keyboard layout before device creation is complete. Hence when we get onInputDeviceAdded() is callback, the layout is already set up. Test: atest VirtualKeyboardLayoutTest Bug: 271905768 Change-Id: I46a6e4b0f512beb4a560374feda4104ff32d27cc --- .../inputflinger/include/InputReaderBase.h | 3 +- services/inputflinger/reader/InputDevice.cpp | 17 -------- .../reader/mapper/KeyboardInputMapper.cpp | 40 +++++++++++++++---- .../reader/mapper/KeyboardInputMapper.h | 2 + .../tests/FakeInputReaderPolicy.cpp | 2 +- .../tests/FakeInputReaderPolicy.h | 2 +- .../tests/fuzzers/MapperHelpers.h | 3 +- 7 files changed, 40 insertions(+), 29 deletions(-) diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index a93a2ea615..ed493dea03 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -437,7 +437,8 @@ public: /* Gets the keyboard layout for a particular input device. */ virtual std::shared_ptr getKeyboardLayoutOverlay( - const InputDeviceIdentifier& identifier) = 0; + const InputDeviceIdentifier& identifier, + const std::optional keyboardLayoutInfo) = 0; /* Gets a user-supplied alias for a particular input device, or an empty string if none. */ virtual std::string getDeviceAlias(const InputDeviceIdentifier& identifier) = 0; diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 2aaddf59bb..bacc7203b6 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -225,23 +225,6 @@ std::list InputDevice::configure(nsecs_t when, mIsWaking = mConfiguration.getBool("device.wake").value_or(false); } - if (!changes.any() || changes.test(Change::KEYBOARD_LAYOUTS)) { - if (!mClasses.test(InputDeviceClass::VIRTUAL)) { - std::shared_ptr keyboardLayout = - mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier); - bool shouldBumpGeneration = false; - for_each_subdevice( - [&keyboardLayout, &shouldBumpGeneration](InputDeviceContext& context) { - if (context.setKeyboardLayoutOverlay(keyboardLayout)) { - shouldBumpGeneration = true; - } - }); - if (shouldBumpGeneration) { - bumpGeneration(); - } - } - } - if (!changes.any() || changes.test(Change::DEVICE_ALIAS)) { if (!(mClasses.test(InputDeviceClass::VIRTUAL))) { std::string alias = mContext->getPolicy()->getDeviceAlias(mIdentifier); diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp index e03a7730ae..6932a2e2d4 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp @@ -86,20 +86,26 @@ int32_t KeyboardInputMapper::getDisplayId() { return ADISPLAY_ID_NONE; } +std::optional KeyboardInputMapper::getKeyboardLayoutInfo() const { + if (mKeyboardLayoutInfo) { + return mKeyboardLayoutInfo; + } + std::optional layoutInfo = getDeviceContext().getRawLayoutInfo(); + if (!layoutInfo) { + return std::nullopt; + } + return KeyboardLayoutInfo(layoutInfo->languageTag, layoutInfo->layoutType); +} + void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo& info) { InputMapper::populateDeviceInfo(info); info.setKeyboardType(mKeyboardType); info.setKeyCharacterMap(getDeviceContext().getKeyCharacterMap()); - if (mKeyboardLayoutInfo) { - info.setKeyboardLayoutInfo(*mKeyboardLayoutInfo); - } else { - std::optional layoutInfo = getDeviceContext().getRawLayoutInfo(); - if (layoutInfo) { - info.setKeyboardLayoutInfo( - KeyboardLayoutInfo(layoutInfo->languageTag, layoutInfo->layoutType)); - } + std::optional keyboardLayoutInfo = getKeyboardLayoutInfo(); + if (keyboardLayoutInfo) { + info.setKeyboardLayoutInfo(*keyboardLayoutInfo); } } @@ -152,13 +158,31 @@ std::list KeyboardInputMapper::reconfigure(nsecs_t when, getValueByKey(config.keyboardLayoutAssociations, getDeviceContext().getLocation()); if (mKeyboardLayoutInfo != newKeyboardLayoutInfo) { mKeyboardLayoutInfo = newKeyboardLayoutInfo; + // Also update keyboard layout overlay as soon as we find the new layout info + updateKeyboardLayoutOverlay(); bumpGeneration(); } } + if (!changes.any() || changes.test(InputReaderConfiguration::Change::KEYBOARD_LAYOUTS)) { + if (!getDeviceContext().getDeviceClasses().test(InputDeviceClass::VIRTUAL) && + updateKeyboardLayoutOverlay()) { + bumpGeneration(); + } + } return out; } +bool KeyboardInputMapper::updateKeyboardLayoutOverlay() { + std::shared_ptr keyboardLayout = + getDeviceContext() + .getContext() + ->getPolicy() + ->getKeyboardLayoutOverlay(getDeviceContext().getDeviceIdentifier(), + getKeyboardLayoutInfo()); + return getDeviceContext().setKeyboardLayoutOverlay(keyboardLayout); +} + void KeyboardInputMapper::configureParameters() { const PropertyMap& config = getDeviceContext().getConfiguration(); mParameters.orientationAware = config.getBool("keyboard.orientationAware").value_or(false); diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h index 45fd68b8bb..14343c448a 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h @@ -99,6 +99,8 @@ private: bool updateMetaStateIfNeeded(int32_t keyCode, bool down); std::optional findKeyDownIndex(int32_t scanCode); + std::optional getKeyboardLayoutInfo() const; + bool updateKeyboardLayoutOverlay(); void resetLedState(); void initializeLedState(LedState& ledState, int32_t led); diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp index 3486d0f2a4..6c6a522f01 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp +++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp @@ -227,7 +227,7 @@ void FakeInputReaderPolicy::notifyInputDevicesChanged( } std::shared_ptr FakeInputReaderPolicy::getKeyboardLayoutOverlay( - const InputDeviceIdentifier&) { + const InputDeviceIdentifier&, const std::optional) { return nullptr; } diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h index 85ff01a071..ad3260b9a7 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.h +++ b/services/inputflinger/tests/FakeInputReaderPolicy.h @@ -84,7 +84,7 @@ private: int32_t /*deviceId*/) override; void notifyInputDevicesChanged(const std::vector& inputDevices) override; std::shared_ptr getKeyboardLayoutOverlay( - const InputDeviceIdentifier&) override; + const InputDeviceIdentifier&, const std::optional) override; std::string getDeviceAlias(const InputDeviceIdentifier&) override; void waitForInputDevices(std::function processDevicesChanged); void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) override; diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index 5039d1a5f1..58ffd072ad 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -294,7 +294,8 @@ public: } void notifyInputDevicesChanged(const std::vector& inputDevices) override {} std::shared_ptr getKeyboardLayoutOverlay( - const InputDeviceIdentifier& identifier) override { + const InputDeviceIdentifier& identifier, + const std::optional layoutInfo) override { return nullptr; } std::string getDeviceAlias(const InputDeviceIdentifier& identifier) { -- GitLab From 33a386bac9b1b00bb56ed2b156c917af5064ed14 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 18 Jul 2023 15:37:11 -0700 Subject: [PATCH 0298/1187] SF: update frameRateOverride list when policy changes Otherwise we might use a stale list which results in an incorrect refresh rate reporting to apps Bug: 290807889 Test: atest android.graphics.cts.FrameRateOverrideTest Change-Id: I328d360bf4b63dc29f0c93fe5281ea826b9ac8c9 --- services/surfaceflinger/Scheduler/Scheduler.cpp | 8 +++++++- services/surfaceflinger/Scheduler/Scheduler.h | 5 ++++- services/surfaceflinger/SurfaceFlinger.cpp | 8 +++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 0a1bd4c519..c8c210ee19 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -777,6 +777,12 @@ void Scheduler::dumpVsync(std::string& out) const { } bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) { + std::scoped_lock lock(mPolicyLock); + return updateFrameRateOverridesLocked(consideredSignals, displayRefreshRate); +} + +bool Scheduler::updateFrameRateOverridesLocked(GlobalSignals consideredSignals, + Fps displayRefreshRate) { if (consideredSignals.idle) return false; const auto frameRateOverrides = @@ -995,7 +1001,7 @@ auto Scheduler::applyPolicy(S Policy::*statePtr, T&& newState) -> GlobalSignals .emitEvent = !choice.consideredSignals.idle}); } - frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, modeOpt->fps); + frameRateOverridesChanged = updateFrameRateOverridesLocked(consideredSignals, modeOpt->fps); if (mPolicy.modeOpt != modeOpt) { mPolicy.modeOpt = modeOpt; diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index c44c447d90..a33edf8892 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -302,6 +302,8 @@ public: return mLayerHistory.getLayerFramerate(now, id); } + bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) EXCLUDES(mPolicyLock); + private: friend class TestableScheduler; @@ -386,7 +388,8 @@ private: GlobalSignals makeGlobalSignals() const REQUIRES(mPolicyLock); - bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock); + bool updateFrameRateOverridesLocked(GlobalSignals, Fps displayRefreshRate) + REQUIRES(mPolicyLock); void updateAttachedChoreographers(const surfaceflinger::frontend::LayerHierarchy&, Fps displayRefreshRate); int updateAttachedChoreographersInternal(const surfaceflinger::frontend::LayerHierarchy&, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2782ce4ce4..c709f0d48e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -7856,7 +7856,13 @@ status_t SurfaceFlinger::applyRefreshRateSelectorPolicy( return INVALID_OPERATION; } - setDesiredActiveMode({std::move(preferredMode), .emitEvent = true}, force); + setDesiredActiveMode({preferredMode, .emitEvent = true}, force); + + // Update the frameRateOverride list as the display render rate might have changed + if (mScheduler->updateFrameRateOverrides(/*consideredSignals*/ {}, preferredMode.fps)) { + triggerOnFrameRateOverridesChanged(); + } + return NO_ERROR; } -- GitLab From 4a1a896c3e5477c9a03e856217b02950842c5b34 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Wed, 19 Jul 2023 16:26:31 +0800 Subject: [PATCH 0299/1187] Fix ADATASPACE_BT601_625 and ADATASPACE_BT601_525 doc. Bug: 266124653 Test: builds Change-Id: I3a77febcc4fa36f7b00abd77326cfb33eaf7dfbc --- libs/nativewindow/include/android/data_space.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h index ad4cc4a229..9fa5569e32 100644 --- a/libs/nativewindow/include/android/data_space.h +++ b/libs/nativewindow/include/android/data_space.h @@ -450,7 +450,7 @@ enum ADataSpace { * * Use limited range, SMPTE 2084 (PQ) transfer and BT2020 standard */ - ADATASPACE_BT2020_ITU_PQ = 298188800, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED + ADATASPACE_BT2020_ITU_PQ = 298188800, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED /** * Adobe RGB @@ -471,20 +471,20 @@ enum ADataSpace { ADATASPACE_JFIF = 146931712, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL /** - * ITU-R Recommendation 601 (BT.601) - 525-line + * ITU-R Recommendation 601 (BT.601) - 625-line * - * Standard-definition television, 525 Lines (NTSC) + * Standard-definition television, 625 Lines (PAL) * - * Use limited range, SMPTE 170M transfer and BT.601_525 standard. + * Use limited range, SMPTE 170M transfer and BT.601_625 standard. */ ADATASPACE_BT601_625 = 281149440, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED /** - * ITU-R Recommendation 709 (BT.709) + * ITU-R Recommendation 601 (BT.601) - 525-line * - * High-definition television + * Standard-definition television, 525 Lines (NTSC) * - * Use limited range, SMPTE 170M transfer and BT.709 standard. + * Use limited range, SMPTE 170M transfer and BT.601_525 standard. */ ADATASPACE_BT601_525 = 281280512, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED -- GitLab From f61c0471dedc68b367931cad9e04edf9a24ee05a Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Mon, 10 Jul 2023 14:45:15 +0000 Subject: [PATCH 0300/1187] inputflinger fuzzers: Remove FuzzContainer As discussed on the touchpad fuzzer CL [0], FuzzContainer was hiding quite a bit of internal state and making fuzzers harder to understand. Its constructor appeared to be deduplicating code, but looking more closely, it wasn't really helping that much, especially for the most common cases. Replace it with a few static methods, making it clearer how state is being changed in the fuzzers. [0] Change ID Ic22ac0f29d433fdf3c17331df620a39937ebd7eb Bug: 245989146 Test: build and briefly run all modified fuzzers $ SANITIZE_TARGET=hwaddress make ${FUZZER_NAME} $ cd $ANDROID_PRODUCT_OUT $ adb root $ adb sync data $ adb shell /data/fuzz/$(get_build_var TARGET_ARCH)/${FUZZER_NAME}/${FUZZER_NAME} Change-Id: I6e28b1f5ec62dc2d084173c1eb461c4bb699678b --- .../tests/fuzzers/CursorInputFuzzer.cpp | 29 ++++--- .../tests/fuzzers/FuzzContainer.h | 86 ------------------- .../tests/fuzzers/KeyboardInputFuzzer.cpp | 35 ++++---- .../tests/fuzzers/MapperHelpers.h | 35 +++++++- .../tests/fuzzers/MultiTouchInputFuzzer.cpp | 48 +++++++---- .../tests/fuzzers/SwitchInputFuzzer.cpp | 12 ++- .../tests/fuzzers/TouchpadInputFuzzer.cpp | 72 +++++++++------- 7 files changed, 148 insertions(+), 169 deletions(-) delete mode 100644 services/inputflinger/tests/fuzzers/FuzzContainer.h diff --git a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp index e93b5929c7..af20a271b8 100644 --- a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp @@ -15,38 +15,47 @@ */ #include -#include +#include #include #include namespace android { -static void addProperty(FuzzContainer& fuzzer, std::shared_ptr fdp) { +static void addProperty(FuzzEventHub& eventHub, std::shared_ptr fdp) { // Pick a random property to set for the mapper to have set. fdp->PickValueInArray>( - {[&]() -> void { fuzzer.addProperty("cursor.mode", "pointer"); }, - [&]() -> void { fuzzer.addProperty("cursor.mode", "navigation"); }, + {[&]() -> void { eventHub.addProperty("cursor.mode", "pointer"); }, + [&]() -> void { eventHub.addProperty("cursor.mode", "navigation"); }, [&]() -> void { - fuzzer.addProperty("cursor.mode", fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("cursor.mode", fdp->ConsumeRandomLengthString(100).data()); }, [&]() -> void { - fuzzer.addProperty("cursor.orientationAware", - fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("cursor.orientationAware", + fdp->ConsumeRandomLengthString(100).data()); }})(); } extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr fdp = std::make_shared(data, size); - FuzzContainer fuzzer(fdp); + + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr eventHub = std::make_shared(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); InputReaderConfiguration policyConfig; - CursorInputMapper& mapper = fuzzer.getMapper(policyConfig); + CursorInputMapper& mapper = + getMapperForDevice(*fdp.get(), device, + policyConfig); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { fdp->PickValueInArray>({ - [&]() -> void { addProperty(fuzzer, fdp); }, + [&]() -> void { + addProperty(*eventHub.get(), fdp); + configureAndResetDevice(*fdp, device); + }, [&]() -> void { std::string dump; mapper.dump(dump); diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h deleted file mode 100644 index ade53281a6..0000000000 --- a/services/inputflinger/tests/fuzzers/FuzzContainer.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2022 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 -#include -#include -#include - -namespace android { - -class FuzzContainer { - std::shared_ptr mFuzzEventHub; - FuzzInputListener mFuzzListener; - std::unique_ptr mFuzzContext; - std::unique_ptr mFuzzDevice; - std::shared_ptr mFdp; - -public: - FuzzContainer(std::shared_ptr fdp) : mFdp(fdp) { - // Setup parameters. - std::string deviceName = mFdp->ConsumeRandomLengthString(16); - std::string deviceLocation = mFdp->ConsumeRandomLengthString(12); - int32_t deviceID = mFdp->ConsumeIntegralInRange(0, 5); - int32_t deviceGeneration = mFdp->ConsumeIntegralInRange(/*from=*/0, /*to=*/5); - - // Create mocked objects. - mFuzzEventHub = std::make_shared(mFdp); - sp policy = sp::make(mFdp); - mFuzzContext = std::make_unique(mFuzzEventHub, policy, - mFuzzListener, mFdp); - - InputDeviceIdentifier identifier; - identifier.name = deviceName; - identifier.location = deviceLocation; - mFuzzDevice = std::make_unique(mFuzzContext.get(), deviceID, deviceGeneration, - identifier); - } - - ~FuzzContainer() {} - - void configureDevice() { - nsecs_t arbitraryTime = mFdp->ConsumeIntegral(); - std::list out; - out += mFuzzDevice->configure(arbitraryTime, /*readerConfig=*/{}, /*changes=*/{}); - out += mFuzzDevice->reset(arbitraryTime); - for (const NotifyArgs& args : out) { - mFuzzListener.notify(args); - } - } - - void addProperty(std::string key, std::string value) { - mFuzzEventHub->addProperty(key, value); - configureDevice(); - } - - void setAbsoluteAxisInfo(int axis, const RawAbsoluteAxisInfo& axisInfo) { - mFuzzEventHub->setAbsoluteAxisInfo(mFuzzDevice->getId(), axis, axisInfo); - } - - template - T& getMapper(Args... args) { - int32_t eventhubId = mFdp->ConsumeIntegral(); - // ensure a device entry exists for this eventHubId - mFuzzDevice->addEmptyEventHubDevice(eventhubId); - configureDevice(); - - return mFuzzDevice->template constructAndAddMapper(eventhubId, args...); - } -}; - -} // namespace android diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp index 54977df2ed..922cbdfb87 100644 --- a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include #include #include @@ -23,38 +23,43 @@ namespace android { const int32_t kMaxKeycodes = 100; -static void addProperty(FuzzContainer& fuzzer, std::shared_ptr fdp) { +static void addProperty(FuzzEventHub& eventHub, std::shared_ptr fdp) { // Pick a random property to set for the mapper to have set. fdp->PickValueInArray>( - {[&]() -> void { fuzzer.addProperty("keyboard.orientationAware", "1"); }, + {[&]() -> void { eventHub.addProperty("keyboard.orientationAware", "1"); }, [&]() -> void { - fuzzer.addProperty("keyboard.orientationAware", - fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("keyboard.orientationAware", + fdp->ConsumeRandomLengthString(100).data()); }, [&]() -> void { - fuzzer.addProperty("keyboard.doNotWakeByDefault", - fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("keyboard.doNotWakeByDefault", + fdp->ConsumeRandomLengthString(100).data()); }, [&]() -> void { - fuzzer.addProperty("keyboard.handlesKeyRepeat", - fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("keyboard.handlesKeyRepeat", + fdp->ConsumeRandomLengthString(100).data()); }})(); } extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr fdp = std::make_shared(data, size); - FuzzContainer fuzzer(fdp); - KeyboardInputMapper& mapper = - fuzzer.getMapper(InputReaderConfiguration{}, - fdp->ConsumeIntegral(), - fdp->ConsumeIntegral()); + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr eventHub = std::make_shared(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); + + KeyboardInputMapper& mapper = getMapperForDevice< + ThreadSafeFuzzedDataProvider, + KeyboardInputMapper>(*fdp.get(), device, InputReaderConfiguration{}, + /*source=*/fdp->ConsumeIntegral(), + /*keyboardType=*/fdp->ConsumeIntegral()); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { fdp->PickValueInArray>({ - [&]() -> void { addProperty(fuzzer, fdp); }, + [&]() -> void { addProperty(*eventHub.get(), fdp); }, [&]() -> void { std::string dump; mapper.dump(dump); diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index 5039d1a5f1..e88731aafd 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -16,6 +16,7 @@ #pragma once #include +#include #include #include @@ -328,10 +329,8 @@ class FuzzInputReaderContext : public InputReaderContext { public: FuzzInputReaderContext(std::shared_ptr eventHub, - const sp& policy, - InputListenerInterface& listener, - std::shared_ptr mFdp) - : mEventHub(eventHub), mPolicy(policy), mFdp(mFdp) {} + std::shared_ptr fdp) + : mEventHub(eventHub), mPolicy(sp::make(fdp)), mFdp(fdp) {} ~FuzzInputReaderContext() {} void updateGlobalMetaState() override {} int32_t getGlobalMetaState() { return mFdp->ConsumeIntegral(); } @@ -358,4 +357,32 @@ public: void notifyStylusGestureStarted(int32_t, nsecs_t) {} }; +template +InputDevice getFuzzedInputDevice(Fdp& fdp, FuzzInputReaderContext* context) { + InputDeviceIdentifier identifier; + identifier.name = fdp.ConsumeRandomLengthString(16); + identifier.location = fdp.ConsumeRandomLengthString(12); + int32_t deviceID = fdp.ConsumeIntegralInRange(0, 5); + int32_t deviceGeneration = fdp.ConsumeIntegralInRange(0, 5); + return InputDevice(context, deviceID, deviceGeneration, identifier); +} + +template +void configureAndResetDevice(Fdp& fdp, InputDevice& device) { + nsecs_t arbitraryTime = fdp.template ConsumeIntegral(); + std::list out; + out += device.configure(arbitraryTime, /*readerConfig=*/{}, /*changes=*/{}); + out += device.reset(arbitraryTime); +} + +template +T& getMapperForDevice(Fdp& fdp, InputDevice& device, Args... args) { + int32_t eventhubId = fdp.template ConsumeIntegral(); + // ensure a device entry exists for this eventHubId + device.addEmptyEventHubDevice(eventhubId); + configureAndResetDevice(fdp, device); + + return device.template constructAndAddMapper(eventhubId, args...); +} + } // namespace android diff --git a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp index 569767f8c0..d3f66900da 100644 --- a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include #include #include @@ -23,53 +23,63 @@ namespace android { const int32_t kMaxKeycodes = 100; -static void addProperty(FuzzContainer& fuzzer, std::shared_ptr fdp) { +static void addProperty(FuzzEventHub& eventHub, std::shared_ptr fdp) { // Pick a random property to set for the mapper to have set. fdp->PickValueInArray>( - {[&]() -> void { fuzzer.addProperty("touch.deviceType", "touchScreen"); }, + {[&]() -> void { eventHub.addProperty("touch.deviceType", "touchScreen"); }, [&]() -> void { - fuzzer.addProperty("touch.deviceType", fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.deviceType", fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.scale", fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.size.scale", fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.bias", fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.size.bias", fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.isSummed", - fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.size.isSummed", + fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.calibration", - fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.size.calibration", + fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.pressure.scale", - fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.pressure.scale", + fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.calibration", - fdp->ConsumeBool() ? "diameter" : "area"); + eventHub.addProperty("touch.size.calibration", + fdp->ConsumeBool() ? "diameter" : "area"); }, [&]() -> void { - fuzzer.addProperty("touch.pressure.calibration", - fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.pressure.calibration", + fdp->ConsumeRandomLengthString(8).data()); }})(); } extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr fdp = std::make_shared(data, size); - FuzzContainer fuzzer(fdp); + + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr eventHub = std::make_shared(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); InputReaderConfiguration policyConfig; - MultiTouchInputMapper& mapper = fuzzer.getMapper(policyConfig); + MultiTouchInputMapper& mapper = + getMapperForDevice(*fdp.get(), + device, + policyConfig); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { fdp->PickValueInArray>({ - [&]() -> void { addProperty(fuzzer, fdp); }, + [&]() -> void { + addProperty(*eventHub.get(), fdp); + configureAndResetDevice(*fdp, device); + }, [&]() -> void { std::string dump; mapper.dump(dump); diff --git a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp index 80eebd58e3..ac2030afd3 100644 --- a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include #include #include @@ -24,9 +24,15 @@ namespace android { extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr fdp = std::make_shared(data, size); - FuzzContainer fuzzer(fdp); - SwitchInputMapper& mapper = fuzzer.getMapper(InputReaderConfiguration{}); + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr eventHub = std::make_shared(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); + + SwitchInputMapper& mapper = + getMapperForDevice(*fdp.get(), device, InputReaderConfiguration{}); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { diff --git a/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp index 796178addd..be765cc364 100644 --- a/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp @@ -15,12 +15,13 @@ */ #include +#include #include #include #include -#include +#include #include #include #include @@ -29,30 +30,30 @@ namespace android { namespace { -void setAxisInfo(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer, int axis) { +void setAxisInfo(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub, int32_t id, int axis) { if (fdp.ConsumeBool()) { - fuzzer.setAbsoluteAxisInfo(axis, - RawAbsoluteAxisInfo{ - .valid = fdp.ConsumeBool(), - .minValue = fdp.ConsumeIntegral(), - .maxValue = fdp.ConsumeIntegral(), - .flat = fdp.ConsumeIntegral(), - .fuzz = fdp.ConsumeIntegral(), - .resolution = fdp.ConsumeIntegral(), - }); + eventHub.setAbsoluteAxisInfo(id, axis, + RawAbsoluteAxisInfo{ + .valid = fdp.ConsumeBool(), + .minValue = fdp.ConsumeIntegral(), + .maxValue = fdp.ConsumeIntegral(), + .flat = fdp.ConsumeIntegral(), + .fuzz = fdp.ConsumeIntegral(), + .resolution = fdp.ConsumeIntegral(), + }); } } -void setAxisInfos(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) { - setAxisInfo(fdp, fuzzer, ABS_MT_SLOT); - setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_X); - setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_Y); - setAxisInfo(fdp, fuzzer, ABS_MT_PRESSURE); - setAxisInfo(fdp, fuzzer, ABS_MT_ORIENTATION); - setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MAJOR); - setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MINOR); - setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MAJOR); - setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MINOR); +void setAxisInfos(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub, int32_t id) { + setAxisInfo(fdp, eventHub, id, ABS_MT_SLOT); + setAxisInfo(fdp, eventHub, id, ABS_MT_POSITION_X); + setAxisInfo(fdp, eventHub, id, ABS_MT_POSITION_Y); + setAxisInfo(fdp, eventHub, id, ABS_MT_PRESSURE); + setAxisInfo(fdp, eventHub, id, ABS_MT_ORIENTATION); + setAxisInfo(fdp, eventHub, id, ABS_MT_TOUCH_MAJOR); + setAxisInfo(fdp, eventHub, id, ABS_MT_TOUCH_MINOR); + setAxisInfo(fdp, eventHub, id, ABS_MT_WIDTH_MAJOR); + setAxisInfo(fdp, eventHub, id, ABS_MT_WIDTH_MINOR); } const std::vector boolPropertiesToFuzz = { @@ -89,32 +90,32 @@ const std::vector doublePropertiesToFuzz = { "gestureProp.Two_Finger_Vertical_Close_Distance_Thresh", }; -void setDeviceSpecificConfig(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) { +void setDeviceSpecificConfig(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub) { // There are a great many gesture properties offered by the Gestures library, all of which could // potentially be set in Input Device Configuration files. Maintaining a complete list is // impractical, so instead we only fuzz properties which are used in at least one IDC file, or // which are likely to be used in future (e.g. ones for controlling palm rejection). if (fdp.ConsumeBool()) { - fuzzer.addProperty("gestureProp.Touchpad_Stack_Version", - std::to_string(fdp.ConsumeIntegral())); + eventHub.addProperty("gestureProp.Touchpad_Stack_Version", + std::to_string(fdp.ConsumeIntegral())); } for (auto& propertyName : boolPropertiesToFuzz) { if (fdp.ConsumeBool()) { - fuzzer.addProperty(propertyName, fdp.ConsumeBool() ? "1" : "0"); + eventHub.addProperty(propertyName, fdp.ConsumeBool() ? "1" : "0"); } } for (auto& propertyName : doublePropertiesToFuzz) { if (fdp.ConsumeBool()) { - fuzzer.addProperty(propertyName, std::to_string(fdp.ConsumeFloatingPoint())); + eventHub.addProperty(propertyName, std::to_string(fdp.ConsumeFloatingPoint())); } } if (fdp.ConsumeBool()) { - fuzzer.addProperty("gestureProp." + fdp.ConsumeRandomLengthString(), - std::to_string(fdp.ConsumeIntegral())); + eventHub.addProperty("gestureProp." + fdp.ConsumeRandomLengthString(), + std::to_string(fdp.ConsumeIntegral())); } } @@ -130,16 +131,23 @@ void setTouchpadSettings(ThreadSafeFuzzedDataProvider& fdp, InputReaderConfigura extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr fdp = std::make_shared(data, size); - FuzzContainer fuzzer(fdp); - setAxisInfos(*fdp, fuzzer); - setDeviceSpecificConfig(*fdp, fuzzer); + + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr eventHub = std::make_shared(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); + + setAxisInfos(*fdp, *eventHub.get(), device.getId()); + setDeviceSpecificConfig(*fdp, *eventHub.get()); InputReaderConfiguration policyConfig; // Some settings are fuzzed here, as well as in the main loop, to provide randomized data to the // TouchpadInputMapper constructor. setTouchpadSettings(*fdp, policyConfig); policyConfig.pointerCaptureRequest.enable = fdp->ConsumeBool(); - TouchpadInputMapper& mapper = fuzzer.getMapper(policyConfig); + TouchpadInputMapper& mapper = + getMapperForDevice(*fdp, device, + policyConfig); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { -- GitLab From 25537f8503565a35062ffe01a83914abb96a2db2 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 18 Jul 2023 14:35:47 -0700 Subject: [PATCH 0301/1187] Add test for non-splittable windows We currently have some code to block incomplete gestures from being sent to the windows that don't set FLAG_SPLIT (setPreventSplitting to true). However, this code in untested today. Add some logs to detect this condition at runtime, and a test to ensure that the corresponding code isn't deleted. Bug: 291809671 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: Idc3e9d5b94f67a5700652df35e8983a2a23de0a2 --- .../dispatcher/InputDispatcher.cpp | 2 + .../tests/InputDispatcher_test.cpp | 49 +++++++++++++++---- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 7611d681a6..fd97309664 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2338,6 +2338,8 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( } else if (isSplit) { // New window does not support splitting but we have already split events. // Ignore the new window. + LOG(INFO) << "Skipping " << newTouchedWindowHandle->getName() + << " because it doesn't support split touch"; newTouchedWindowHandle = nullptr; } } else { diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index d367cd71f0..609e4dd5b4 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2386,7 +2386,6 @@ TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { const int32_t touchDeviceId = 4; const int32_t mouseDeviceId = 6; - NotifyMotionArgs args; // Start hovering over the left window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) @@ -2462,7 +2461,6 @@ TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { const int32_t touchDeviceId = 4; const int32_t mouseDeviceId = 6; - NotifyMotionArgs args; // First touch pointer down mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) @@ -2528,7 +2526,6 @@ TEST_F(InputDispatcherTest, UnfinishedInjectedEvent) { mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); const int32_t touchDeviceId = 4; - NotifyMotionArgs args; // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after // completion. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -2696,9 +2693,7 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) - .pointer(PointerBuilder(0, ToolType::STYLUS) - .x(50) - .y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60)) .build())); // No event should be sent. This event should be ignored because a pointer from another device // is already down. @@ -2721,9 +2716,7 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) - .pointer(PointerBuilder(0, ToolType::STYLUS) - .x(50) - .y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // No more events @@ -3808,6 +3801,44 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { EXPECT_EQ(-10, event->getY(1)); // -50 + 40 } +/** + * Two windows: a splittable and a non-splittable. + * The non-splittable window shouldn't receive any "incomplete" gestures. + * Send the first pointer to the splittable window, and then touch the non-splittable window. + * The second pointer should be dropped because the initial window is splittable, so it won't get + * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any + * "incomplete" gestures. + */ +TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) { + std::shared_ptr application = std::make_shared(); + sp leftWindow = + sp::make(application, mDispatcher, "Left splittable Window", + ADISPLAY_ID_DEFAULT); + leftWindow->setPreventSplitting(false); + leftWindow->setFrame(Rect(0, 0, 100, 100)); + sp rightWindow = + sp::make(application, mDispatcher, "Right non-splittable Window", + ADISPLAY_ID_DEFAULT); + rightWindow->setPreventSplitting(true); + rightWindow->setFrame(Rect(100, 100, 200, 200)); + mDispatcher->onWindowInfosChanged( + {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); + + // Touch down on left, splittable window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .build()); + leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + + mDispatcher->notifyMotion( + MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) + .build()); + leftWindow->assertNoEvents(); + rightWindow->assertNoEvents(); +} + TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) { std::shared_ptr application = std::make_shared(); sp window = -- GitLab From 227a7f8fd9cbc8e4105bfb8d0688aa5f37c0d9a7 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 18 Jul 2023 18:30:32 -0700 Subject: [PATCH 0302/1187] Add flags to input_verifier These flags are currently not known by the verifier. As a result, this causes a panic when such events are trying to get converted to the rust object. Add the missing flags in this CL. Bug: 271455682 Test: manually enable event verification Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: I351b87c339c7efe8e6f3b14ad05e89d8a9e8c9e2 --- libs/input/Android.bp | 4 ++++ libs/input/InputVerifier.cpp | 2 +- libs/input/rust/input.rs | 14 ++++++++++++-- libs/input/rust/lib.rs | 4 ++-- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 769677c6ff..757cde2074 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -65,6 +65,10 @@ rust_bindgen { bindgen_flags: [ "--verbose", "--allowlist-var=AMOTION_EVENT_FLAG_CANCELED", + "--allowlist-var=AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED", + "--allowlist-var=AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED", + "--allowlist-var=AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT", + "--allowlist-var=AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE", "--allowlist-var=AMOTION_EVENT_ACTION_CANCEL", "--allowlist-var=AMOTION_EVENT_ACTION_UP", "--allowlist-var=AMOTION_EVENT_ACTION_POINTER_DOWN", diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp index 851babfb54..341eb6f920 100644 --- a/libs/input/InputVerifier.cpp +++ b/libs/input/InputVerifier.cpp @@ -44,7 +44,7 @@ Result InputVerifier::processMovement(DeviceId deviceId, int32_t action, rust::Slice properties{rpp.data(), rpp.size()}; rust::String errorMessage = android::input::verifier::process_movement(*mVerifier, deviceId, action, properties, - flags); + static_cast(flags)); if (errorMessage.empty()) { return {}; } else { diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs index a308c26b2e..9d3b38693a 100644 --- a/libs/input/rust/input.rs +++ b/libs/input/rust/input.rs @@ -119,8 +119,18 @@ impl MotionAction { bitflags! { /// MotionEvent flags. - pub struct MotionFlags: i32 { + pub struct MotionFlags: u32 { /// FLAG_CANCELED - const CANCELED = input_bindgen::AMOTION_EVENT_FLAG_CANCELED; + const CANCELED = input_bindgen::AMOTION_EVENT_FLAG_CANCELED as u32; + /// FLAG_WINDOW_IS_OBSCURED + const WINDOW_IS_OBSCURED = input_bindgen::AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; + /// FLAG_WINDOW_IS_PARTIALLY_OBSCURED + const WINDOW_IS_PARTIALLY_OBSCURED = + input_bindgen::AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; + /// FLAG_IS_ACCESSIBILITY_EVENT + const IS_ACCESSIBILITY_EVENT = + input_bindgen::AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT; + /// FLAG_NO_FOCUS_CHANGE + const NO_FOCUS_CHANGE = input_bindgen::AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE; } } diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs index 892f558da6..688d941bf6 100644 --- a/libs/input/rust/lib.rs +++ b/libs/input/rust/lib.rs @@ -52,7 +52,7 @@ mod ffi { device_id: i32, action: u32, pointer_properties: &[RustPointerProperties], - flags: i32, + flags: u32, ) -> String; fn reset_device(verifier: &mut InputVerifier, device_id: i32); } @@ -74,7 +74,7 @@ fn process_movement( device_id: i32, action: u32, pointer_properties: &[RustPointerProperties], - flags: i32, + flags: u32, ) -> String { let result = verifier.process_movement( DeviceId(device_id), -- GitLab From aa238976f9378543e8512e0e6e87e38e65c2103c Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Mon, 17 Jul 2023 12:52:05 +0800 Subject: [PATCH 0303/1187] Fix bt2020 linear ext mapping issue in EGL and Vulkan. - EGL_EXT_BT2020_LINEAR should be mapped to extend bt2020 linear if output format is FP16. Bug: 261485283 Test: builds Change-Id: Ifd68cc10afc0b5b38b15af2a938d02bb3bcd3764 --- opengl/libs/EGL/egl_platform_entries.cpp | 15 ++++++++++----- vulkan/libvulkan/swapchain.cpp | 18 ++++++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index 88001b2b95..440eb17873 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -49,6 +49,7 @@ #include "egl_trace.h" using namespace android; +using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat; // ---------------------------------------------------------------------------- @@ -406,7 +407,7 @@ EGLBoolean eglGetConfigAttribImpl(EGLDisplay dpy, EGLConfig config, EGLint attri // ---------------------------------------------------------------------------- // Translates EGL color spaces to Android data spaces. -static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) { +static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace, PixelFormat pixelFormat) { if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) { return HAL_DATASPACE_UNKNOWN; } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) { @@ -424,7 +425,13 @@ static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) { } else if (colorspace == EGL_GL_COLORSPACE_BT2020_HLG_EXT) { return static_cast(HAL_DATASPACE_BT2020_HLG); } else if (colorspace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT) { - return HAL_DATASPACE_BT2020_LINEAR; + if (pixelFormat == PixelFormat::RGBA_FP16) { + return static_cast(HAL_DATASPACE_STANDARD_BT2020 | + HAL_DATASPACE_TRANSFER_LINEAR | + HAL_DATASPACE_RANGE_EXTENDED); + } else { + return HAL_DATASPACE_BT2020_LINEAR; + } } else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) { return HAL_DATASPACE_BT2020_PQ; } @@ -573,8 +580,6 @@ void convertAttribs(const EGLAttrib* attribList, std::vector& newList) { newList.push_back(EGL_NONE); } -using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat; - // Gets the native pixel format corrsponding to the passed EGLConfig. void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, PixelFormat* format) { @@ -714,7 +719,7 @@ EGLSurface eglCreateWindowSurfaceTmpl(egl_display_t* dp, egl_connection_t* cnx, return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); } - android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace); + android_dataspace dataSpace = dataSpaceFromEGLColorSpace(colorSpace, format); // Set dataSpace even if it could be HAL_DATASPACE_UNKNOWN. // HAL_DATASPACE_UNKNOWN is the default value, but it may have changed // at this point. diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index 114f863fa8..07b95694d5 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -532,7 +532,8 @@ PixelFormat GetNativePixelFormat(VkFormat format) { return native_format; } -android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) { +android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace, + PixelFormat pixelFormat) { switch (colorspace) { case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR: return HAL_DATASPACE_V0_SRGB; @@ -551,7 +552,14 @@ android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) { case VK_COLOR_SPACE_BT709_NONLINEAR_EXT: return HAL_DATASPACE_V0_SRGB; case VK_COLOR_SPACE_BT2020_LINEAR_EXT: - return HAL_DATASPACE_BT2020_LINEAR; + if (pixelFormat == PixelFormat::RGBA_FP16) { + return static_cast( + HAL_DATASPACE_STANDARD_BT2020 | + HAL_DATASPACE_TRANSFER_LINEAR | + HAL_DATASPACE_RANGE_EXTENDED); + } else { + return HAL_DATASPACE_BT2020_LINEAR; + } case VK_COLOR_SPACE_HDR10_ST2084_EXT: return static_cast( HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 | @@ -561,9 +569,7 @@ android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) { HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 | HAL_DATASPACE_RANGE_FULL); case VK_COLOR_SPACE_HDR10_HLG_EXT: - return static_cast( - HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_HLG | - HAL_DATASPACE_RANGE_FULL); + return static_cast(HAL_DATASPACE_BT2020_HLG); case VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT: return static_cast( HAL_DATASPACE_STANDARD_ADOBE_RGB | @@ -1364,7 +1370,7 @@ VkResult CreateSwapchainKHR(VkDevice device, PixelFormat native_pixel_format = GetNativePixelFormat(create_info->imageFormat); android_dataspace native_dataspace = - GetNativeDataspace(create_info->imageColorSpace); + GetNativeDataspace(create_info->imageColorSpace, native_pixel_format); if (native_dataspace == HAL_DATASPACE_UNKNOWN) { ALOGE( "CreateSwapchainKHR(VkSwapchainCreateInfoKHR.imageColorSpace = %d) " -- GitLab From d38a1e000e11f5307055bab44223444fc4ebbb07 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 18 Jul 2023 11:55:17 -0700 Subject: [PATCH 0304/1187] Add dump for InputState and InputTarget These are useful when you want to print these variables for debugging. Currently, InputState isn't even shown in the dispatcher dump. Include it there. Also, update some types to use DeviceId. Bug: 211379801 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: Ifc983a653d9f1f546b71b8404f67caa1c89d3b01 --- .../dispatcher/InputDispatcher.cpp | 10 ++++ .../inputflinger/dispatcher/InputDispatcher.h | 1 - .../inputflinger/dispatcher/InputState.cpp | 10 ++++ services/inputflinger/dispatcher/InputState.h | 3 ++ .../inputflinger/dispatcher/InputTarget.cpp | 20 ++++++++ .../inputflinger/dispatcher/InputTarget.h | 2 +- .../inputflinger/dispatcher/TouchedWindow.cpp | 50 +++++++++---------- .../inputflinger/dispatcher/TouchedWindow.h | 46 ++++++++--------- 8 files changed, 92 insertions(+), 50 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index fd97309664..da7a2a412d 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -119,6 +119,10 @@ inline nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); } +bool isEmpty(const std::stringstream& ss) { + return ss.rdbuf()->in_avail() == 0; +} + inline const std::string binderToString(const sp& binder) { if (binder == nullptr) { return ""; @@ -5779,6 +5783,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) const { } else { dump += INDENT3 "WaitQueue: \n"; } + std::stringstream inputStateDump; + inputStateDump << connection->inputState; + if (!isEmpty(inputStateDump)) { + dump += INDENT3 "InputState: "; + dump += inputStateDump.str() + "\n"; + } } } else { dump += INDENT "Connections: \n"; diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index cb87067ec2..909c683d1b 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -25,7 +25,6 @@ #include "InputDispatcherConfiguration.h" #include "InputDispatcherInterface.h" #include "InputDispatcherPolicyInterface.h" -#include "InputState.h" #include "InputTarget.h" #include "InputThread.h" #include "LatencyAggregator.h" diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index e6941ef027..ccffe26d57 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -525,4 +525,14 @@ bool InputState::shouldCancelMotion(const MotionMemento& memento, } } +std::ostream& operator<<(std::ostream& out, const InputState& state) { + if (!state.mMotionMementos.empty()) { + out << "mMotionMementos: "; + for (const InputState::MotionMemento& memento : state.mMotionMementos) { + out << "{deviceId= " << memento.deviceId << ", hovering=" << memento.hovering << "}, "; + } + } + return out; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h index e741137103..32df034f67 100644 --- a/services/inputflinger/dispatcher/InputState.h +++ b/services/inputflinger/dispatcher/InputState.h @@ -128,7 +128,10 @@ private: std::vector> synthesizeCancelationEventsForPointers( const MotionMemento& memento, std::bitset pointerIds, nsecs_t currentTime); + friend std::ostream& operator<<(std::ostream& out, const InputState& state); }; +std::ostream& operator<<(std::ostream& out, const InputState& state); + } // namespace inputdispatcher } // namespace android diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp index fc8b785aa5..11f3413df8 100644 --- a/services/inputflinger/dispatcher/InputTarget.cpp +++ b/services/inputflinger/dispatcher/InputTarget.cpp @@ -76,4 +76,24 @@ std::string InputTarget::getPointerInfoString() const { } return out; } + +std::ostream& operator<<(std::ostream& out, const InputTarget& target) { + out << "{inputChannel="; + if (target.inputChannel != nullptr) { + out << target.inputChannel->getName(); + } else { + out << ""; + } + out << ", windowHandle="; + if (target.windowHandle != nullptr) { + out << target.windowHandle->getName(); + } else { + out << ""; + } + out << ", targetFlags=" << target.flags.string(); + out << ", pointers=" << target.getPointerInfoString(); + out << "}"; + return out; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h index 3bf8b68f0e..8b8a35aea8 100644 --- a/services/inputflinger/dispatcher/InputTarget.h +++ b/services/inputflinger/dispatcher/InputTarget.h @@ -139,6 +139,6 @@ struct InputTarget { std::string getPointerInfoString() const; }; -std::string dispatchModeToString(int32_t dispatchMode); +std::ostream& operator<<(std::ostream& out, const InputTarget& target); } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp index ae165209bd..a1fee6add3 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.cpp +++ b/services/inputflinger/dispatcher/TouchedWindow.cpp @@ -35,7 +35,7 @@ bool TouchedWindow::hasHoveringPointers() const { return false; } -bool TouchedWindow::hasHoveringPointers(int32_t deviceId) const { +bool TouchedWindow::hasHoveringPointers(DeviceId deviceId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return false; @@ -53,7 +53,7 @@ void TouchedWindow::clearHoveringPointers() { std::erase_if(mDeviceStates, [](const auto& pair) { return !pair.second.hasPointers(); }); } -bool TouchedWindow::hasHoveringPointer(int32_t deviceId, int32_t pointerId) const { +bool TouchedWindow::hasHoveringPointer(DeviceId deviceId, int32_t pointerId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return false; @@ -63,15 +63,15 @@ bool TouchedWindow::hasHoveringPointer(int32_t deviceId, int32_t pointerId) cons return state.hoveringPointerIds.test(pointerId); } -void TouchedWindow::addHoveringPointer(int32_t deviceId, int32_t pointerId) { +void TouchedWindow::addHoveringPointer(DeviceId deviceId, int32_t pointerId) { mDeviceStates[deviceId].hoveringPointerIds.set(pointerId); } -void TouchedWindow::addTouchingPointer(int32_t deviceId, int32_t pointerId) { +void TouchedWindow::addTouchingPointer(DeviceId deviceId, int32_t pointerId) { mDeviceStates[deviceId].touchingPointerIds.set(pointerId); } -void TouchedWindow::addTouchingPointers(int32_t deviceId, +void TouchedWindow::addTouchingPointers(DeviceId deviceId, std::bitset pointers) { mDeviceStates[deviceId].touchingPointerIds |= pointers; } @@ -85,15 +85,15 @@ bool TouchedWindow::hasTouchingPointers() const { return false; } -bool TouchedWindow::hasTouchingPointers(int32_t deviceId) const { +bool TouchedWindow::hasTouchingPointers(DeviceId deviceId) const { return getTouchingPointers(deviceId).any(); } -bool TouchedWindow::hasTouchingPointer(int32_t deviceId, int32_t pointerId) const { +bool TouchedWindow::hasTouchingPointer(DeviceId deviceId, int32_t pointerId) const { return getTouchingPointers(deviceId).test(pointerId); } -std::bitset TouchedWindow::getTouchingPointers(int32_t deviceId) const { +std::bitset TouchedWindow::getTouchingPointers(DeviceId deviceId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return {}; @@ -103,14 +103,14 @@ std::bitset TouchedWindow::getTouchingPointers(int32_t devic return state.touchingPointerIds; } -void TouchedWindow::removeTouchingPointer(int32_t deviceId, int32_t pointerId) { +void TouchedWindow::removeTouchingPointer(DeviceId deviceId, int32_t pointerId) { std::bitset pointerIds; pointerIds.set(pointerId, true); removeTouchingPointers(deviceId, pointerIds); } -void TouchedWindow::removeTouchingPointers(int32_t deviceId, +void TouchedWindow::removeTouchingPointers(DeviceId deviceId, std::bitset pointers) { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { @@ -126,23 +126,23 @@ void TouchedWindow::removeTouchingPointers(int32_t deviceId, } } -std::set TouchedWindow::getTouchingDeviceIds() const { - std::set deviceIds; +std::set TouchedWindow::getTouchingDeviceIds() const { + std::set deviceIds; for (const auto& [deviceId, _] : mDeviceStates) { deviceIds.insert(deviceId); } return deviceIds; } -std::set TouchedWindow::getActiveDeviceIds() const { - std::set out; +std::set TouchedWindow::getActiveDeviceIds() const { + std::set out; for (const auto& [deviceId, _] : mDeviceStates) { out.emplace(deviceId); } return out; } -bool TouchedWindow::hasPilferingPointers(int32_t deviceId) const { +bool TouchedWindow::hasPilferingPointers(DeviceId deviceId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return false; @@ -152,16 +152,16 @@ bool TouchedWindow::hasPilferingPointers(int32_t deviceId) const { return state.pilferingPointerIds.any(); } -void TouchedWindow::addPilferingPointers(int32_t deviceId, +void TouchedWindow::addPilferingPointers(DeviceId deviceId, std::bitset pointerIds) { mDeviceStates[deviceId].pilferingPointerIds |= pointerIds; } -void TouchedWindow::addPilferingPointer(int32_t deviceId, int32_t pointerId) { +void TouchedWindow::addPilferingPointer(DeviceId deviceId, int32_t pointerId) { mDeviceStates[deviceId].pilferingPointerIds.set(pointerId); } -std::bitset TouchedWindow::getPilferingPointers(int32_t deviceId) const { +std::bitset TouchedWindow::getPilferingPointers(DeviceId deviceId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return {}; @@ -171,15 +171,15 @@ std::bitset TouchedWindow::getPilferingPointers(int32_t devi return state.pilferingPointerIds; } -std::map> TouchedWindow::getPilferingPointers() const { - std::map> out; +std::map> TouchedWindow::getPilferingPointers() const { + std::map> out; for (const auto& [deviceId, state] : mDeviceStates) { out.emplace(deviceId, state.pilferingPointerIds); } return out; } -std::optional TouchedWindow::getDownTimeInTarget(int32_t deviceId) const { +std::optional TouchedWindow::getDownTimeInTarget(DeviceId deviceId) const { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return {}; @@ -188,7 +188,7 @@ std::optional TouchedWindow::getDownTimeInTarget(int32_t deviceId) cons return state.downTimeInTarget; } -void TouchedWindow::trySetDownTimeInTarget(int32_t deviceId, nsecs_t downTime) { +void TouchedWindow::trySetDownTimeInTarget(DeviceId deviceId, nsecs_t downTime) { auto [stateIt, _] = mDeviceStates.try_emplace(deviceId); DeviceState& state = stateIt->second; @@ -197,7 +197,7 @@ void TouchedWindow::trySetDownTimeInTarget(int32_t deviceId, nsecs_t downTime) { } } -void TouchedWindow::removeAllTouchingPointersForDevice(int32_t deviceId) { +void TouchedWindow::removeAllTouchingPointersForDevice(DeviceId deviceId) { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return; @@ -213,7 +213,7 @@ void TouchedWindow::removeAllTouchingPointersForDevice(int32_t deviceId) { } } -void TouchedWindow::removeHoveringPointer(int32_t deviceId, int32_t pointerId) { +void TouchedWindow::removeHoveringPointer(DeviceId deviceId, int32_t pointerId) { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return; @@ -227,7 +227,7 @@ void TouchedWindow::removeHoveringPointer(int32_t deviceId, int32_t pointerId) { } } -void TouchedWindow::removeAllHoveringPointersForDevice(int32_t deviceId) { +void TouchedWindow::removeAllHoveringPointersForDevice(DeviceId deviceId) { const auto stateIt = mDeviceStates.find(deviceId); if (stateIt == mDeviceStates.end()) { return; diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h index 81393fc2fc..1efefad334 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ b/services/inputflinger/dispatcher/TouchedWindow.h @@ -34,43 +34,43 @@ struct TouchedWindow { // Hovering bool hasHoveringPointers() const; - bool hasHoveringPointers(int32_t deviceId) const; - bool hasHoveringPointer(int32_t deviceId, int32_t pointerId) const; - void addHoveringPointer(int32_t deviceId, int32_t pointerId); - void removeHoveringPointer(int32_t deviceId, int32_t pointerId); + bool hasHoveringPointers(DeviceId deviceId) const; + bool hasHoveringPointer(DeviceId deviceId, int32_t pointerId) const; + void addHoveringPointer(DeviceId deviceId, int32_t pointerId); + void removeHoveringPointer(DeviceId deviceId, int32_t pointerId); // Touching - bool hasTouchingPointer(int32_t deviceId, int32_t pointerId) const; + bool hasTouchingPointer(DeviceId deviceId, int32_t pointerId) const; bool hasTouchingPointers() const; - bool hasTouchingPointers(int32_t deviceId) const; - std::bitset getTouchingPointers(int32_t deviceId) const; - void addTouchingPointer(int32_t deviceId, int32_t pointerId); - void addTouchingPointers(int32_t deviceId, std::bitset pointers); - void removeTouchingPointer(int32_t deviceId, int32_t pointerId); - void removeTouchingPointers(int32_t deviceId, std::bitset pointers); + bool hasTouchingPointers(DeviceId deviceId) const; + std::bitset getTouchingPointers(DeviceId deviceId) const; + void addTouchingPointer(DeviceId deviceId, int32_t pointerId); + void addTouchingPointers(DeviceId deviceId, std::bitset pointers); + void removeTouchingPointer(DeviceId deviceId, int32_t pointerId); + void removeTouchingPointers(DeviceId deviceId, std::bitset pointers); /** * Get the currently active touching device id. If there isn't exactly 1 touching device, return * nullopt. */ - std::set getTouchingDeviceIds() const; + std::set getTouchingDeviceIds() const; /** * The ids of devices that are currently touching or hovering. */ - std::set getActiveDeviceIds() const; + std::set getActiveDeviceIds() const; // Pilfering pointers - bool hasPilferingPointers(int32_t deviceId) const; - void addPilferingPointers(int32_t deviceId, std::bitset pointerIds); - void addPilferingPointer(int32_t deviceId, int32_t pointerId); - std::bitset getPilferingPointers(int32_t deviceId) const; - std::map> getPilferingPointers() const; + bool hasPilferingPointers(DeviceId deviceId) const; + void addPilferingPointers(DeviceId deviceId, std::bitset pointerIds); + void addPilferingPointer(DeviceId deviceId, int32_t pointerId); + std::bitset getPilferingPointers(DeviceId deviceId) const; + std::map> getPilferingPointers() const; // Down time - std::optional getDownTimeInTarget(int32_t deviceId) const; - void trySetDownTimeInTarget(int32_t deviceId, nsecs_t downTime); + std::optional getDownTimeInTarget(DeviceId deviceId) const; + void trySetDownTimeInTarget(DeviceId deviceId, nsecs_t downTime); - void removeAllTouchingPointersForDevice(int32_t deviceId); - void removeAllHoveringPointersForDevice(int32_t deviceId); + void removeAllTouchingPointersForDevice(DeviceId deviceId); + void removeAllHoveringPointersForDevice(DeviceId deviceId); void clearHoveringPointers(); std::string dump() const; @@ -88,7 +88,7 @@ private: bool hasPointers() const { return touchingPointerIds.any() || hoveringPointerIds.any(); }; }; - std::map mDeviceStates; + std::map mDeviceStates; static std::string deviceStateToString(const TouchedWindow::DeviceState& state); }; -- GitLab From 5b9766d989553bc0a04848501324c1bb77ecadb3 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 18 Jul 2023 14:06:29 -0700 Subject: [PATCH 0305/1187] Simplify pointer handling code in InputDispatcher Some of the code in dispatcher can be simplified. Some fixes here: 1. Use 'removeTouchingPointer' instead of implementing the same logic from scratch. 2. Remove `addTouchingPointer` API since there's a similar API called 'addTouchingPointers'. 3. Use MotionEvent::getActionIndex instead of a custom function that does the same thing. Bug: 211379801 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: I1fec64be6e9da11199c55a96cac17ee5e6c14b82 --- .../dispatcher/InputDispatcher.cpp | 35 ++++++------------- services/inputflinger/dispatcher/TouchState.h | 4 +-- .../inputflinger/dispatcher/TouchedWindow.cpp | 4 --- .../inputflinger/dispatcher/TouchedWindow.h | 1 - 4 files changed, 13 insertions(+), 31 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index da7a2a412d..619ecdc773 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -134,11 +134,6 @@ static std::string uidString(const gui::Uid& uid) { return uid.toString(); } -inline int32_t getMotionEventActionPointerIndex(int32_t action) { - return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> - AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; -} - Result checkKeyAction(int32_t action) { switch (action) { case AKEY_EVENT_ACTION_DOWN: @@ -606,7 +601,7 @@ std::pair resolveTouchedPosition(const MotionEntry& entry) { return {entry.xCursorPosition, entry.yCursorPosition}; } - const int32_t pointerIndex = getMotionEventActionPointerIndex(entry.action); + const int32_t pointerIndex = MotionEvent::getActionIndex(entry.action); return {entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X), entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)}; } @@ -2309,7 +2304,7 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) { /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ const auto [x, y] = resolveTouchedPosition(entry); - const int32_t pointerIndex = getMotionEventActionPointerIndex(action); + const int32_t pointerIndex = MotionEvent::getActionIndex(action); // Outside targets should be added upon first dispatched DOWN event. That means, this should // be a pointer that would generate ACTION_DOWN, *and* touch should not already be down. const bool isStylus = isPointerFromStylus(entry, pointerIndex); @@ -2558,15 +2553,16 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( // Update the pointerIds for non-splittable when it received pointer down. if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) { // If no split, we suppose all touched windows should receive pointer down. - const int32_t pointerIndex = getMotionEventActionPointerIndex(action); + const int32_t pointerIndex = MotionEvent::getActionIndex(action); for (size_t i = 0; i < tempTouchState.windows.size(); i++) { TouchedWindow& touchedWindow = tempTouchState.windows[i]; // Ignore drag window for it should just track one pointer. if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) { continue; } - touchedWindow.addTouchingPointer(entry.deviceId, - entry.pointerProperties[pointerIndex].id); + std::bitset touchingPointers; + touchingPointers.set(entry.pointerProperties[pointerIndex].id); + touchedWindow.addTouchingPointers(entry.deviceId, touchingPointers); } } } @@ -2710,18 +2706,9 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( } } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { // One pointer went up. - int32_t pointerIndex = getMotionEventActionPointerIndex(action); - uint32_t pointerId = entry.pointerProperties[pointerIndex].id; - - for (size_t i = 0; i < tempTouchState.windows.size();) { - TouchedWindow& touchedWindow = tempTouchState.windows[i]; - touchedWindow.removeTouchingPointer(entry.deviceId, pointerId); - if (!touchedWindow.hasTouchingPointers(entry.deviceId)) { - tempTouchState.windows.erase(tempTouchState.windows.begin() + i); - continue; - } - i += 1; - } + const int32_t pointerIndex = MotionEvent::getActionIndex(action); + const uint32_t pointerId = entry.pointerProperties[pointerIndex].id; + tempTouchState.removeTouchingPointer(entry.deviceId, pointerId); } // Save changes unless the action was scroll in which case the temporary touch @@ -2820,7 +2807,7 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { } case AMOTION_EVENT_ACTION_POINTER_UP: - if (getMotionEventActionPointerIndex(entry.action) != pointerIndex) { + if (MotionEvent::getActionIndex(entry.action) != pointerIndex) { break; } // The drag pointer is up. @@ -4114,7 +4101,7 @@ std::unique_ptr InputDispatcher::splitMotionEvent( int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN || maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { - int32_t originalPointerIndex = getMotionEventActionPointerIndex(action); + int32_t originalPointerIndex = MotionEvent::getActionIndex(action); const PointerProperties& pointerProperties = originalMotionEntry.pointerProperties[originalPointerIndex]; uint32_t pointerId = uint32_t(pointerProperties.id); diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 25b9643528..39e63e5894 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -38,9 +38,9 @@ struct TouchState { void reset(); void clearWindowsWithoutPointers(); - std::set getActiveDeviceIds() const; + std::set getActiveDeviceIds() const; - bool hasTouchingPointers(int32_t device) const; + bool hasTouchingPointers(DeviceId deviceId) const; void removeTouchingPointer(DeviceId deviceId, int32_t pointerId); void removeTouchingPointerFromWindow(DeviceId deviceId, int32_t pointerId, const sp& windowHandle); diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp index a1fee6add3..9807a6da9b 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.cpp +++ b/services/inputflinger/dispatcher/TouchedWindow.cpp @@ -67,10 +67,6 @@ void TouchedWindow::addHoveringPointer(DeviceId deviceId, int32_t pointerId) { mDeviceStates[deviceId].hoveringPointerIds.set(pointerId); } -void TouchedWindow::addTouchingPointer(DeviceId deviceId, int32_t pointerId) { - mDeviceStates[deviceId].touchingPointerIds.set(pointerId); -} - void TouchedWindow::addTouchingPointers(DeviceId deviceId, std::bitset pointers) { mDeviceStates[deviceId].touchingPointerIds |= pointers; diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h index 1efefad334..0a38f9f5cd 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ b/services/inputflinger/dispatcher/TouchedWindow.h @@ -44,7 +44,6 @@ struct TouchedWindow { bool hasTouchingPointers() const; bool hasTouchingPointers(DeviceId deviceId) const; std::bitset getTouchingPointers(DeviceId deviceId) const; - void addTouchingPointer(DeviceId deviceId, int32_t pointerId); void addTouchingPointers(DeviceId deviceId, std::bitset pointers); void removeTouchingPointer(DeviceId deviceId, int32_t pointerId); void removeTouchingPointers(DeviceId deviceId, std::bitset pointers); -- GitLab From cb0afc44e1cdbca96b6badd7f650a8d2804ca18a Mon Sep 17 00:00:00 2001 From: Lais Andrade Date: Wed, 19 Jul 2023 16:27:32 +0000 Subject: [PATCH 0306/1187] Add bug component to services/vibratorservice Change-Id: I4add2fe2bada0be788a436f5431129a03faef58c Fix: 290748221 Test: N/A --- services/vibratorservice/OWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/vibratorservice/OWNERS b/services/vibratorservice/OWNERS index d073e2bd46..031b333fab 100644 --- a/services/vibratorservice/OWNERS +++ b/services/vibratorservice/OWNERS @@ -1 +1,3 @@ +# Bug component: 345036 + include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS -- GitLab From 21f77bd50eb77b1ae440890777fb6fb4a065d55f Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 18 Jul 2023 17:51:35 -0700 Subject: [PATCH 0307/1187] Make UntrustedSpy_AbortsDispatcher threadsafe A similar fix worked for the other dispatcher death test. The test UntrustedSpy_AbortsDispatcher is a lot less flakier, with a fail rate of about 1 in 1502. Still, we want to achieve a near-zero flake rate, so apply the same fix here. Bug: 291797922 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: Ic4a759862f110a24f7b239b9e20fa0222fd6668d --- services/inputflinger/tests/InputDispatcher_test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 609e4dd5b4..70516808f4 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -9015,6 +9015,7 @@ using InputDispatcherSpyWindowDeathTest = InputDispatcherSpyWindowTest; * Adding a spy window that is not a trusted overlay causes Dispatcher to abort. */ TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) { + testing::GTEST_FLAG(death_test_style) = "threadsafe"; ScopedSilentDeath _silentDeath; auto spy = createSpy(); -- GitLab From 1aabf5b012db3928481b0076acd57fea581d8c19 Mon Sep 17 00:00:00 2001 From: Arthur Ishiguro Date: Wed, 19 Jul 2023 15:39:34 +0000 Subject: [PATCH 0308/1187] Fix return value of AidlSensorHalWrapper::configureDirectChannel Bug: 287721163 Test: Test on device Change-Id: I9585d8c1a285e27ed8c1f506dd9ac24a47631f93 --- services/sensorservice/AidlSensorHalWrapper.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/sensorservice/AidlSensorHalWrapper.cpp b/services/sensorservice/AidlSensorHalWrapper.cpp index f5b360f3b6..e60db93431 100644 --- a/services/sensorservice/AidlSensorHalWrapper.cpp +++ b/services/sensorservice/AidlSensorHalWrapper.cpp @@ -308,8 +308,12 @@ status_t AidlSensorHalWrapper::configureDirectChannel(int32_t sensorHandle, int3 } int32_t token; - mSensors->configDirectReport(sensorHandle, channelHandle, rate, &token); - return token; + status_t status = convertToStatus( + mSensors->configDirectReport(sensorHandle, channelHandle, rate, &token)); + if (status == OK && rate != ISensors::RateLevel::STOP) { + status = static_cast(token); + } + return status; } void AidlSensorHalWrapper::writeWakeLockHandled(uint32_t count) { -- GitLab From fe787b7b66fe3b8390739d5fe992f5ea45f947f3 Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 19 Jul 2023 15:35:19 -0400 Subject: [PATCH 0309/1187] Remove AHardwareBuffer_bytesPerPixel Bug: 291932479 Test: atest CtsNativeHardwareTestCases Change-Id: I71da959f5ea9d95ad4edb90171abd452059a6e85 --- libs/nativewindow/AHardwareBuffer.cpp | 37 ++++--------------- .../private/android/AHardwareBufferHelpers.h | 3 -- 2 files changed, 7 insertions(+), 33 deletions(-) diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 80607055ed..6a5ce029cc 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -227,11 +227,14 @@ int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage, } return result; } else { - const uint32_t pixelStride = AHardwareBuffer_bytesPerPixel(format); + int32_t bytesPerPixel; + int32_t bytesPerStride; + int result = gBuffer->lockAsync(usage, usage, bounds, &outPlanes->planes[0].data, fence, + &bytesPerPixel, &bytesPerStride); outPlanes->planeCount = 1; - outPlanes->planes[0].pixelStride = pixelStride; - outPlanes->planes[0].rowStride = gBuffer->getStride() * pixelStride; - return gBuffer->lockAsync(usage, usage, bounds, &outPlanes->planes[0].data, fence); + outPlanes->planes[0].pixelStride = bytesPerPixel; + outPlanes->planes[0].rowStride = bytesPerStride; + return result; } } @@ -681,32 +684,6 @@ bool AHardwareBuffer_formatIsYuv(uint32_t format) { } } -uint32_t AHardwareBuffer_bytesPerPixel(uint32_t format) { - switch (format) { - case AHARDWAREBUFFER_FORMAT_R8_UNORM: - return 1; - case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: - case AHARDWAREBUFFER_FORMAT_D16_UNORM: - case AHARDWAREBUFFER_FORMAT_R16_UINT: - return 2; - case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: - case AHARDWAREBUFFER_FORMAT_D24_UNORM: - return 3; - case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: - case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: - case AHARDWAREBUFFER_FORMAT_D32_FLOAT: - case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: - case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT: - case AHARDWAREBUFFER_FORMAT_R16G16_UINT: - return 4; - case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: - case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM: - return 8; - default: - return 0; - } -} - uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t hal_format) { return hal_format; } diff --git a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h index 6d3d295a0c..15e7aca694 100644 --- a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h +++ b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h @@ -43,9 +43,6 @@ bool AHardwareBuffer_isValidPixelFormat(uint32_t ahardwarebuffer_format); // whether this is a YUV type format bool AHardwareBuffer_formatIsYuv(uint32_t format); -// number of bytes per pixel or 0 if unknown or multi-planar -uint32_t AHardwareBuffer_bytesPerPixel(uint32_t format); - // convert AHardwareBuffer format to HAL format (note: this is a no-op) uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format); -- GitLab From acd2258a5492a9e289fd7f4b8ea90543d6843a23 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Wed, 12 Jul 2023 13:47:28 -0500 Subject: [PATCH 0310/1187] Improve updateInputFlinger performance This change improves the performance of the WindowInfosListenerInvoker work done on SurfaceFlinger's background executor thread. The primary optimization made is not sending a WindowInfosReportedListener with every call to WindowInfosListener.onWindowInfosChanged. Instead, we send a new interface, WindowInfosPublisher, and a unique listener id to listeners when they're added. Listeners call WindowInfosPublisher.ackWindowInfosReceived with their id after processing each update. From traces taken during development, the new code is a major improvement, taking about 15% of the time spent previously on SurfaceFlinger's background thread for sending window infos. Performance with this change seems roughly in line with the performance in T. Bug: 290377931 Test: atest WindowInfosListenerTest Test: atest WindowInfosListenerInvokerTest Test: manually killing system server and checking valid state on restart Change-Id: Ib39ba935727df0bc1ab4030bcfe8301de7e64805 --- libs/gui/Android.bp | 3 + libs/gui/WindowInfosListenerReporter.cpp | 20 +- .../aidl/android/gui/ISurfaceComposer.aidl | 4 +- .../android/gui/WindowInfosListenerInfo.aidl | 25 ++ .../gui/android/gui/IWindowInfosListener.aidl | 4 +- .../android/gui/IWindowInfosPublisher.aidl | 23 ++ libs/gui/fuzzer/libgui_fuzzer_utils.h | 4 +- libs/gui/include/gui/ISurfaceComposer.h | 1 + .../include/gui/WindowInfosListenerReporter.h | 8 +- libs/gui/tests/Surface_test.cpp | 3 +- .../surfaceflinger/BackgroundExecutor.cpp | 14 + services/surfaceflinger/BackgroundExecutor.h | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 14 +- services/surfaceflinger/SurfaceFlinger.h | 7 +- .../WindowInfosListenerInvoker.cpp | 253 +++++++++--------- .../WindowInfosListenerInvoker.h | 35 +-- .../WindowInfosListenerInvokerTest.cpp | 156 +++++------ 17 files changed, 333 insertions(+), 242 deletions(-) create mode 100644 libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl create mode 100644 libs/gui/android/gui/IWindowInfosPublisher.aidl diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 342f132f0c..d7e7eb8ea1 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -73,6 +73,7 @@ filegroup { "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", "android/gui/IWindowInfosListener.aidl", + "android/gui/IWindowInfosPublisher.aidl", "android/gui/IWindowInfosReportedListener.aidl", "android/gui/WindowInfo.aidl", "android/gui/WindowInfosUpdate.aidl", @@ -90,6 +91,7 @@ cc_library_static { "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", "android/gui/IWindowInfosListener.aidl", + "android/gui/IWindowInfosPublisher.aidl", "android/gui/IWindowInfosReportedListener.aidl", "android/gui/WindowInfosUpdate.aidl", "android/gui/WindowInfo.aidl", @@ -136,6 +138,7 @@ aidl_library { "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", "android/gui/IWindowInfosListener.aidl", + "android/gui/IWindowInfosPublisher.aidl", "android/gui/IWindowInfosReportedListener.aidl", "android/gui/WindowInfo.aidl", "android/gui/WindowInfosUpdate.aidl", diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp index 76e7b6e162..0929b8e120 100644 --- a/libs/gui/WindowInfosListenerReporter.cpp +++ b/libs/gui/WindowInfosListenerReporter.cpp @@ -22,7 +22,6 @@ namespace android { using gui::DisplayInfo; -using gui::IWindowInfosReportedListener; using gui::WindowInfo; using gui::WindowInfosListener; using gui::aidl_utils::statusTFromBinderStatus; @@ -40,8 +39,13 @@ status_t WindowInfosListenerReporter::addWindowInfosListener( { std::scoped_lock lock(mListenersMutex); if (mWindowInfosListeners.empty()) { - binder::Status s = surfaceComposer->addWindowInfosListener(this); + gui::WindowInfosListenerInfo listenerInfo; + binder::Status s = surfaceComposer->addWindowInfosListener(this, &listenerInfo); status = statusTFromBinderStatus(s); + if (status == OK) { + mWindowInfosPublisher = std::move(listenerInfo.windowInfosPublisher); + mListenerId = listenerInfo.listenerId; + } } if (status == OK) { @@ -85,8 +89,7 @@ status_t WindowInfosListenerReporter::removeWindowInfosListener( } binder::Status WindowInfosListenerReporter::onWindowInfosChanged( - const gui::WindowInfosUpdate& update, - const sp& windowInfosReportedListener) { + const gui::WindowInfosUpdate& update) { std::unordered_set, gui::SpHash> windowInfosListeners; @@ -104,9 +107,7 @@ binder::Status WindowInfosListenerReporter::onWindowInfosChanged( listener->onWindowInfosChanged(update); } - if (windowInfosReportedListener) { - windowInfosReportedListener->onWindowInfosReported(); - } + mWindowInfosPublisher->ackWindowInfosReceived(update.vsyncId, mListenerId); return binder::Status::ok(); } @@ -114,7 +115,10 @@ binder::Status WindowInfosListenerReporter::onWindowInfosChanged( void WindowInfosListenerReporter::reconnect(const sp& composerService) { std::scoped_lock lock(mListenersMutex); if (!mWindowInfosListeners.empty()) { - composerService->addWindowInfosListener(this); + gui::WindowInfosListenerInfo listenerInfo; + composerService->addWindowInfosListener(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 ec3266ca83..539a1c140e 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -40,12 +40,14 @@ import android.gui.IScreenCaptureListener; import android.gui.ISurfaceComposerClient; import android.gui.ITunnelModeEnabledListener; import android.gui.IWindowInfosListener; +import android.gui.IWindowInfosPublisher; import android.gui.LayerCaptureArgs; import android.gui.LayerDebugInfo; import android.gui.OverlayProperties; import android.gui.PullAtomData; import android.gui.ARect; import android.gui.StaticDisplayInfo; +import android.gui.WindowInfosListenerInfo; /** @hide */ interface ISurfaceComposer { @@ -500,7 +502,7 @@ interface ISurfaceComposer { */ int getMaxAcquiredBufferCount(); - void addWindowInfosListener(IWindowInfosListener windowInfosListener); + WindowInfosListenerInfo addWindowInfosListener(IWindowInfosListener windowInfosListener); void removeWindowInfosListener(IWindowInfosListener windowInfosListener); diff --git a/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl b/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl new file mode 100644 index 0000000000..0ca13b768a --- /dev/null +++ b/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2023, 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. + */ + +package android.gui; + +import android.gui.IWindowInfosPublisher; + +/** @hide */ +parcelable WindowInfosListenerInfo { + long listenerId; + IWindowInfosPublisher windowInfosPublisher; +} \ No newline at end of file diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl index 400229d99f..07cb5ed0e6 100644 --- a/libs/gui/android/gui/IWindowInfosListener.aidl +++ b/libs/gui/android/gui/IWindowInfosListener.aidl @@ -16,11 +16,9 @@ package android.gui; -import android.gui.IWindowInfosReportedListener; import android.gui.WindowInfosUpdate; /** @hide */ oneway interface IWindowInfosListener { - void onWindowInfosChanged( - in WindowInfosUpdate update, in @nullable IWindowInfosReportedListener windowInfosReportedListener); + void onWindowInfosChanged(in WindowInfosUpdate update); } diff --git a/libs/gui/android/gui/IWindowInfosPublisher.aidl b/libs/gui/android/gui/IWindowInfosPublisher.aidl new file mode 100644 index 0000000000..5a9c32845e --- /dev/null +++ b/libs/gui/android/gui/IWindowInfosPublisher.aidl @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2023, 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. + */ + +package android.gui; + +/** @hide */ +oneway interface IWindowInfosPublisher +{ + void ackWindowInfosReceived(long vsyncId, long listenerId); +} diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index 8c003d8ad4..4c7d0562af 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -153,8 +153,8 @@ public: MOCK_METHOD(binder::Status, setOverrideFrameRate, (int32_t, float), (override)); MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override)); MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override)); - MOCK_METHOD(binder::Status, addWindowInfosListener, (const sp&), - (override)); + MOCK_METHOD(binder::Status, addWindowInfosListener, + (const sp&, gui::WindowInfosListenerInfo*), (override)); MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp&), (override)); MOCK_METHOD(binder::Status, getOverlaySupport, (gui::OverlayProperties*), (override)); diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 7c150d53d9..3ff6735926 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h index 38cb108912..684e21ad96 100644 --- a/libs/gui/include/gui/WindowInfosListenerReporter.h +++ b/libs/gui/include/gui/WindowInfosListenerReporter.h @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -30,8 +30,7 @@ namespace android { class WindowInfosListenerReporter : public gui::BnWindowInfosListener { public: static sp getInstance(); - binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update, - const sp&) override; + binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update) override; status_t addWindowInfosListener( const sp& windowInfosListener, const sp&, @@ -47,5 +46,8 @@ private: std::vector mLastWindowInfos GUARDED_BY(mListenersMutex); std::vector mLastDisplayInfos GUARDED_BY(mListenersMutex); + + sp mWindowInfosPublisher; + int64_t mListenerId; }; } // namespace android diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 90c0a63286..567604dbec 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1002,7 +1002,8 @@ public: } binder::Status addWindowInfosListener( - const sp& /*windowInfosListener*/) override { + const sp& /*windowInfosListener*/, + gui::WindowInfosListenerInfo* /*outInfo*/) override { return binder::Status::ok(); } diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp index 6ddf790d47..5a1ec6f501 100644 --- a/services/surfaceflinger/BackgroundExecutor.cpp +++ b/services/surfaceflinger/BackgroundExecutor.cpp @@ -20,6 +20,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include +#include #include "BackgroundExecutor.h" @@ -60,4 +61,17 @@ void BackgroundExecutor::sendCallbacks(Callbacks&& tasks) { LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed"); } +void BackgroundExecutor::flushQueue() { + std::mutex mutex; + std::condition_variable cv; + bool flushComplete = false; + sendCallbacks({[&]() { + std::scoped_lock lock{mutex}; + flushComplete = true; + cv.notify_one(); + }}); + std::unique_lock lock{mutex}; + cv.wait(lock, [&]() { return flushComplete; }); +} + } // namespace android diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h index 0fae5a5c93..66b7d7a1fc 100644 --- a/services/surfaceflinger/BackgroundExecutor.h +++ b/services/surfaceflinger/BackgroundExecutor.h @@ -34,6 +34,7 @@ public: // Queues callbacks onto a work queue to be executed by a background thread. // This is safe to call from multiple threads. void sendCallbacks(Callbacks&& tasks); + void flushQueue(); private: sem_t mSemaphore; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a9a1d80830..f8d39cbc2c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -6347,8 +6347,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp ftl::to_underlying(windowInfosDebug.maxSendDelayVsyncId)); StringAppendF(&result, " max send delay (ns): %" PRId64 " ns\n", windowInfosDebug.maxSendDelayDuration); - StringAppendF(&result, " unsent messages: %" PRIu32 "\n", - windowInfosDebug.pendingMessageCount); + StringAppendF(&result, " unsent messages: %zu\n", windowInfosDebug.pendingMessageCount); result.append("\n"); } @@ -8214,9 +8213,9 @@ void SurfaceFlinger::onActiveDisplayChangedLocked(const DisplayDevice* inactiveD forceApplyPolicy); } -status_t SurfaceFlinger::addWindowInfosListener( - const sp& windowInfosListener) { - mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener); +status_t SurfaceFlinger::addWindowInfosListener(const sp& windowInfosListener, + gui::WindowInfosListenerInfo* outInfo) { + mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener, outInfo); setTransactionFlags(eInputInfoUpdateNeeded); return NO_ERROR; } @@ -9300,7 +9299,8 @@ binder::Status SurfaceComposerAIDL::getMaxAcquiredBufferCount(int32_t* buffers) } binder::Status SurfaceComposerAIDL::addWindowInfosListener( - const sp& windowInfosListener) { + const sp& windowInfosListener, + gui::WindowInfosListenerInfo* outInfo) { status_t status; const int pid = IPCThreadState::self()->getCallingPid(); const int uid = IPCThreadState::self()->getCallingUid(); @@ -9308,7 +9308,7 @@ binder::Status SurfaceComposerAIDL::addWindowInfosListener( // WindowInfosListeners if (uid == AID_SYSTEM || uid == AID_GRAPHICS || checkPermission(sAccessSurfaceFlinger, pid, uid)) { - status = mFlinger->addWindowInfosListener(windowInfosListener); + status = mFlinger->addWindowInfosListener(windowInfosListener, outInfo); } else { status = PERMISSION_DENIED; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index aeaeb47210..296bcb9a56 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -617,7 +617,8 @@ private: status_t getMaxAcquiredBufferCount(int* buffers) const; - status_t addWindowInfosListener(const sp& windowInfosListener); + status_t addWindowInfosListener(const sp& windowInfosListener, + gui::WindowInfosListenerInfo* outResult); status_t removeWindowInfosListener( const sp& windowInfosListener) const; @@ -1541,8 +1542,8 @@ public: binder::Status setOverrideFrameRate(int32_t uid, float frameRate) override; binder::Status getGpuContextPriority(int32_t* outPriority) override; binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override; - binder::Status addWindowInfosListener( - const sp& windowInfosListener) override; + binder::Status addWindowInfosListener(const sp& windowInfosListener, + gui::WindowInfosListenerInfo* outInfo) override; binder::Status removeWindowInfosListener( const sp& windowInfosListener) override; diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index 20699ef123..7062a4e3a7 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -14,7 +14,9 @@ * limitations under the License. */ -#include +#include +#include +#include #include #include #include @@ -23,162 +25,130 @@ #include "BackgroundExecutor.h" #include "WindowInfosListenerInvoker.h" +#undef ATRACE_TAG +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + namespace android { using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; -using WindowInfosListenerVector = ftl::SmallVector, 3>; - -struct WindowInfosReportedListenerInvoker : gui::BnWindowInfosReportedListener, - IBinder::DeathRecipient { - WindowInfosReportedListenerInvoker(WindowInfosListenerVector windowInfosListeners, - WindowInfosReportedListenerSet windowInfosReportedListeners) - : mCallbacksPending(windowInfosListeners.size()), - mWindowInfosListeners(std::move(windowInfosListeners)), - mWindowInfosReportedListeners(std::move(windowInfosReportedListeners)) {} +void WindowInfosListenerInvoker::addWindowInfosListener(sp listener, + gui::WindowInfosListenerInfo* outInfo) { + int64_t listenerId = mNextListenerId++; + outInfo->listenerId = listenerId; + outInfo->windowInfosPublisher = sp::fromExisting(this); - binder::Status onWindowInfosReported() override { - if (--mCallbacksPending == 0) { - for (const auto& listener : mWindowInfosReportedListeners) { + BackgroundExecutor::getInstance().sendCallbacks( + {[this, listener = std::move(listener), listenerId]() { + ATRACE_NAME("WindowInfosListenerInvoker::addWindowInfosListener"); sp asBinder = IInterface::asBinder(listener); - if (asBinder->isBinderAlive()) { - listener->onWindowInfosReported(); - } - } - - auto wpThis = wp::fromExisting(this); - for (const auto& listener : mWindowInfosListeners) { - sp binder = IInterface::asBinder(listener); - binder->unlinkToDeath(wpThis); - } - } - return binder::Status::ok(); - } - - void binderDied(const wp&) { onWindowInfosReported(); } - -private: - std::atomic mCallbacksPending; - static constexpr size_t kStaticCapacity = 3; - const WindowInfosListenerVector mWindowInfosListeners; - WindowInfosReportedListenerSet mWindowInfosReportedListeners; -}; - -void WindowInfosListenerInvoker::addWindowInfosListener(sp listener) { - sp asBinder = IInterface::asBinder(listener); - asBinder->linkToDeath(sp::fromExisting(this)); - - std::scoped_lock lock(mListenersMutex); - mWindowInfosListeners.try_emplace(asBinder, std::move(listener)); + asBinder->linkToDeath(sp::fromExisting(this)); + mWindowInfosListeners.try_emplace(asBinder, + std::make_pair(listenerId, std::move(listener))); + }}); } void WindowInfosListenerInvoker::removeWindowInfosListener( const sp& listener) { - sp asBinder = IInterface::asBinder(listener); - - std::scoped_lock lock(mListenersMutex); - asBinder->unlinkToDeath(sp::fromExisting(this)); - mWindowInfosListeners.erase(asBinder); + BackgroundExecutor::getInstance().sendCallbacks({[this, listener]() { + ATRACE_NAME("WindowInfosListenerInvoker::removeWindowInfosListener"); + sp asBinder = IInterface::asBinder(listener); + asBinder->unlinkToDeath(sp::fromExisting(this)); + mWindowInfosListeners.erase(asBinder); + }}); } void WindowInfosListenerInvoker::binderDied(const wp& who) { - std::scoped_lock lock(mListenersMutex); - mWindowInfosListeners.erase(who); + BackgroundExecutor::getInstance().sendCallbacks({[this, who]() { + ATRACE_NAME("WindowInfosListenerInvoker::binderDied"); + auto it = mWindowInfosListeners.find(who); + int64_t listenerId = it->second.first; + mWindowInfosListeners.erase(who); + + std::vector vsyncIds; + for (auto& [vsyncId, state] : mUnackedState) { + if (std::find(state.unackedListenerIds.begin(), state.unackedListenerIds.end(), + listenerId) != state.unackedListenerIds.end()) { + vsyncIds.push_back(vsyncId); + } + } + + for (int64_t vsyncId : vsyncIds) { + ackWindowInfosReceived(vsyncId, listenerId); + } + }}); } void WindowInfosListenerInvoker::windowInfosChanged( gui::WindowInfosUpdate update, WindowInfosReportedListenerSet reportedListeners, bool forceImmediateCall) { - WindowInfosListenerVector listeners; - { - std::scoped_lock lock{mMessagesMutex}; - - if (!mDelayInfo) { - mDelayInfo = DelayInfo{ - .vsyncId = update.vsyncId, - .frameTime = update.timestamp, - }; - } - - // If there are unacked messages and this isn't a forced call, then return immediately. - // If a forced window infos change doesn't happen first, the update will be sent after - // the WindowInfosReportedListeners are called. If a forced window infos change happens or - // if there are subsequent delayed messages before this update is sent, then this message - // will be dropped and the listeners will only be called with the latest info. This is done - // to reduce the amount of binder memory used. - if (mActiveMessageCount > 0 && !forceImmediateCall) { - mDelayedUpdate = std::move(update); - mReportedListeners.merge(reportedListeners); - return; - } - - if (mDelayedUpdate) { - mDelayedUpdate.reset(); - } + if (!mDelayInfo) { + mDelayInfo = DelayInfo{ + .vsyncId = update.vsyncId, + .frameTime = update.timestamp, + }; + } - { - std::scoped_lock lock{mListenersMutex}; - for (const auto& [_, listener] : mWindowInfosListeners) { - listeners.push_back(listener); - } - } - if (CC_UNLIKELY(listeners.empty())) { - mReportedListeners.merge(reportedListeners); - mDelayInfo.reset(); - return; - } + // If there are unacked messages and this isn't a forced call, then return immediately. + // If a forced window infos change doesn't happen first, the update will be sent after + // the WindowInfosReportedListeners are called. If a forced window infos change happens or + // if there are subsequent delayed messages before this update is sent, then this message + // will be dropped and the listeners will only be called with the latest info. This is done + // to reduce the amount of binder memory used. + if (!mUnackedState.empty() && !forceImmediateCall) { + mDelayedUpdate = std::move(update); + mReportedListeners.merge(reportedListeners); + return; + } - reportedListeners.insert(sp::fromExisting(this)); - reportedListeners.merge(mReportedListeners); - mReportedListeners.clear(); + if (mDelayedUpdate) { + mDelayedUpdate.reset(); + } - mActiveMessageCount++; - updateMaxSendDelay(); + if (CC_UNLIKELY(mWindowInfosListeners.empty())) { + mReportedListeners.merge(reportedListeners); mDelayInfo.reset(); + return; } - auto reportedInvoker = - sp::make(listeners, std::move(reportedListeners)); - - for (const auto& listener : listeners) { - sp asBinder = IInterface::asBinder(listener); + reportedListeners.merge(mReportedListeners); + mReportedListeners.clear(); + + // Update mUnackedState to include the message we're about to send + auto [it, _] = mUnackedState.try_emplace(update.vsyncId, + UnackedState{.reportedListeners = + std::move(reportedListeners)}); + auto& unackedState = it->second; + for (auto& pair : mWindowInfosListeners) { + int64_t listenerId = pair.second.first; + unackedState.unackedListenerIds.push_back(listenerId); + } - // linkToDeath is used here to ensure that the windowInfosReportedListeners - // are called even if one of the windowInfosListeners dies before - // calling onWindowInfosReported. - asBinder->linkToDeath(reportedInvoker); + mDelayInfo.reset(); + updateMaxSendDelay(); - auto status = listener->onWindowInfosChanged(update, reportedInvoker); + // Call the listeners + for (auto& pair : mWindowInfosListeners) { + auto& [listenerId, listener] = pair.second; + auto status = listener->onWindowInfosChanged(update); if (!status.isOk()) { - reportedInvoker->onWindowInfosReported(); + ackWindowInfosReceived(update.vsyncId, listenerId); } } } -binder::Status WindowInfosListenerInvoker::onWindowInfosReported() { - BackgroundExecutor::getInstance().sendCallbacks({[this]() { - gui::WindowInfosUpdate update; - { - std::scoped_lock lock{mMessagesMutex}; - mActiveMessageCount--; - if (!mDelayedUpdate || mActiveMessageCount > 0) { - return; - } - update = std::move(*mDelayedUpdate); - mDelayedUpdate.reset(); - } - windowInfosChanged(std::move(update), {}, false); - }}); - return binder::Status::ok(); -} - WindowInfosListenerInvoker::DebugInfo WindowInfosListenerInvoker::getDebugInfo() { - std::scoped_lock lock{mMessagesMutex}; - updateMaxSendDelay(); - mDebugInfo.pendingMessageCount = mActiveMessageCount; - return mDebugInfo; + DebugInfo result; + BackgroundExecutor::getInstance().sendCallbacks({[&, this]() { + ATRACE_NAME("WindowInfosListenerInvoker::getDebugInfo"); + updateMaxSendDelay(); + result = mDebugInfo; + result.pendingMessageCount = mUnackedState.size(); + }}); + BackgroundExecutor::getInstance().flushQueue(); + return result; } void WindowInfosListenerInvoker::updateMaxSendDelay() { @@ -192,4 +162,41 @@ void WindowInfosListenerInvoker::updateMaxSendDelay() { } } +binder::Status WindowInfosListenerInvoker::ackWindowInfosReceived(int64_t vsyncId, + int64_t listenerId) { + BackgroundExecutor::getInstance().sendCallbacks({[this, vsyncId, listenerId]() { + ATRACE_NAME("WindowInfosListenerInvoker::ackWindowInfosReceived"); + auto it = mUnackedState.find(vsyncId); + if (it == mUnackedState.end()) { + return; + } + + auto& state = it->second; + state.unackedListenerIds.unstable_erase(std::find(state.unackedListenerIds.begin(), + state.unackedListenerIds.end(), + listenerId)); + if (!state.unackedListenerIds.empty()) { + return; + } + + WindowInfosReportedListenerSet reportedListeners{std::move(state.reportedListeners)}; + mUnackedState.erase(vsyncId); + + for (const auto& reportedListener : reportedListeners) { + sp asBinder = IInterface::asBinder(reportedListener); + if (asBinder->isBinderAlive()) { + reportedListener->onWindowInfosReported(); + } + } + + if (!mDelayedUpdate || !mUnackedState.empty()) { + return; + } + gui::WindowInfosUpdate update{std::move(*mDelayedUpdate)}; + mDelayedUpdate.reset(); + windowInfosChanged(std::move(update), {}, false); + }}); + return binder::Status::ok(); +} + } // namespace android diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index bc465a3a2b..f36b0edd7d 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -19,11 +19,12 @@ #include #include -#include +#include #include #include #include #include +#include #include #include @@ -35,22 +36,22 @@ using WindowInfosReportedListenerSet = std::unordered_set, gui::SpHash>; -class WindowInfosListenerInvoker : public gui::BnWindowInfosReportedListener, +class WindowInfosListenerInvoker : public gui::BnWindowInfosPublisher, public IBinder::DeathRecipient { public: - void addWindowInfosListener(sp); + void addWindowInfosListener(sp, gui::WindowInfosListenerInfo*); void removeWindowInfosListener(const sp& windowInfosListener); void windowInfosChanged(gui::WindowInfosUpdate update, WindowInfosReportedListenerSet windowInfosReportedListeners, bool forceImmediateCall); - binder::Status onWindowInfosReported() override; + binder::Status ackWindowInfosReceived(int64_t, int64_t) override; struct DebugInfo { VsyncId maxSendDelayVsyncId; nsecs_t maxSendDelayDuration; - uint32_t pendingMessageCount; + size_t pendingMessageCount; }; DebugInfo getDebugInfo(); @@ -58,24 +59,28 @@ protected: void binderDied(const wp& who) override; private: - std::mutex mListenersMutex; - static constexpr size_t kStaticCapacity = 3; - ftl::SmallMap, const sp, kStaticCapacity> - mWindowInfosListeners GUARDED_BY(mListenersMutex); + std::atomic mNextListenerId{0}; + ftl::SmallMap, const std::pair>, + kStaticCapacity> + mWindowInfosListeners; - std::mutex mMessagesMutex; - uint32_t mActiveMessageCount GUARDED_BY(mMessagesMutex) = 0; - std::optional mDelayedUpdate GUARDED_BY(mMessagesMutex); + std::optional mDelayedUpdate; WindowInfosReportedListenerSet mReportedListeners; - DebugInfo mDebugInfo GUARDED_BY(mMessagesMutex); + struct UnackedState { + ftl::SmallVector unackedListenerIds; + WindowInfosReportedListenerSet reportedListeners; + }; + ftl::SmallMap mUnackedState; + + DebugInfo mDebugInfo; struct DelayInfo { int64_t vsyncId; nsecs_t frameTime; }; - std::optional mDelayInfo GUARDED_BY(mMessagesMutex); - void updateMaxSendDelay() REQUIRES(mMessagesMutex); + std::optional mDelayInfo; + void updateMaxSendDelay(); }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp index af4971b063..c7b845e668 100644 --- a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp +++ b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp @@ -15,35 +15,23 @@ protected: WindowInfosListenerInvokerTest() : mInvoker(sp::make()) {} ~WindowInfosListenerInvokerTest() { - std::mutex mutex; - std::condition_variable cv; - bool flushComplete = false; // Flush the BackgroundExecutor thread to ensure any scheduled tasks are complete. // Otherwise, references those tasks hold may go out of scope before they are done // executing. - BackgroundExecutor::getInstance().sendCallbacks({[&]() { - std::scoped_lock lock{mutex}; - flushComplete = true; - cv.notify_one(); - }}); - std::unique_lock lock{mutex}; - cv.wait(lock, [&]() { return flushComplete; }); + BackgroundExecutor::getInstance().flushQueue(); } sp mInvoker; }; -using WindowInfosUpdateConsumer = std::function&)>; +using WindowInfosUpdateConsumer = std::function; class Listener : public gui::BnWindowInfosListener { public: Listener(WindowInfosUpdateConsumer consumer) : mConsumer(std::move(consumer)) {} - binder::Status onWindowInfosChanged( - const gui::WindowInfosUpdate& update, - const sp& reportedListener) override { - mConsumer(update, reportedListener); + binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update) override { + mConsumer(update); return binder::Status::ok(); } @@ -58,15 +46,17 @@ TEST_F(WindowInfosListenerInvokerTest, callsSingleListener) { int callCount = 0; - mInvoker->addWindowInfosListener( - sp::make([&](const gui::WindowInfosUpdate&, - const sp& reportedListener) { - std::scoped_lock lock{mutex}; - callCount++; - cv.notify_one(); + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp::make([&](const gui::WindowInfosUpdate& update) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); - reportedListener->onWindowInfosReported(); - })); + listenerInfo.windowInfosPublisher + ->ackWindowInfosReceived(update.vsyncId, + listenerInfo.listenerId); + }), + &listenerInfo); BackgroundExecutor::getInstance().sendCallbacks( {[this]() { mInvoker->windowInfosChanged({}, {}, false); }}); @@ -81,21 +71,27 @@ TEST_F(WindowInfosListenerInvokerTest, callsMultipleListeners) { std::mutex mutex; std::condition_variable cv; - int callCount = 0; - const int expectedCallCount = 3; - - for (int i = 0; i < expectedCallCount; i++) { - mInvoker->addWindowInfosListener(sp::make( - [&](const gui::WindowInfosUpdate&, - const sp& reportedListener) { - std::scoped_lock lock{mutex}; - callCount++; - if (callCount == expectedCallCount) { - cv.notify_one(); - } - - reportedListener->onWindowInfosReported(); - })); + size_t callCount = 0; + const size_t expectedCallCount = 3; + std::vector listenerInfos{expectedCallCount, + gui::WindowInfosListenerInfo{}}; + + for (size_t i = 0; i < expectedCallCount; i++) { + mInvoker->addWindowInfosListener(sp::make([&, &listenerInfo = listenerInfos[i]]( + const gui::WindowInfosUpdate& + update) { + std::scoped_lock lock{mutex}; + callCount++; + if (callCount == expectedCallCount) { + cv.notify_one(); + } + + listenerInfo.windowInfosPublisher + ->ackWindowInfosReceived(update.vsyncId, + listenerInfo + .listenerId); + }), + &listenerInfos[i]); } BackgroundExecutor::getInstance().sendCallbacks( @@ -114,17 +110,20 @@ TEST_F(WindowInfosListenerInvokerTest, delaysUnackedCall) { int callCount = 0; - // Simulate a slow ack by not calling the WindowInfosReportedListener. - mInvoker->addWindowInfosListener(sp::make( - [&](const gui::WindowInfosUpdate&, const sp&) { - std::scoped_lock lock{mutex}; - callCount++; - cv.notify_one(); - })); + // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp::make([&](const gui::WindowInfosUpdate&) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); + }), + &listenerInfo); BackgroundExecutor::getInstance().sendCallbacks({[&]() { - mInvoker->windowInfosChanged({}, {}, false); - mInvoker->windowInfosChanged({}, {}, false); + mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 0, 0}, {}, + false); + mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 1, 0}, {}, + false); }}); { @@ -134,7 +133,7 @@ TEST_F(WindowInfosListenerInvokerTest, delaysUnackedCall) { EXPECT_EQ(callCount, 1); // Ack the first message. - mInvoker->onWindowInfosReported(); + listenerInfo.windowInfosPublisher->ackWindowInfosReceived(0, listenerInfo.listenerId); { std::unique_lock lock{mutex}; @@ -152,19 +151,21 @@ TEST_F(WindowInfosListenerInvokerTest, sendsForcedMessage) { int callCount = 0; const int expectedCallCount = 2; - // Simulate a slow ack by not calling the WindowInfosReportedListener. - mInvoker->addWindowInfosListener(sp::make( - [&](const gui::WindowInfosUpdate&, const sp&) { - std::scoped_lock lock{mutex}; - callCount++; - if (callCount == expectedCallCount) { - cv.notify_one(); - } - })); + // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp::make([&](const gui::WindowInfosUpdate&) { + std::scoped_lock lock{mutex}; + callCount++; + if (callCount == expectedCallCount) { + cv.notify_one(); + } + }), + &listenerInfo); BackgroundExecutor::getInstance().sendCallbacks({[&]() { - mInvoker->windowInfosChanged({}, {}, false); - mInvoker->windowInfosChanged({}, {}, true); + mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 0, 0}, {}, + false); + mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 1, 0}, {}, true); }}); { @@ -182,14 +183,14 @@ TEST_F(WindowInfosListenerInvokerTest, skipsDelayedMessage) { int64_t lastUpdateId = -1; - // Simulate a slow ack by not calling the WindowInfosReportedListener. - mInvoker->addWindowInfosListener( - sp::make([&](const gui::WindowInfosUpdate& update, - const sp&) { - std::scoped_lock lock{mutex}; - lastUpdateId = update.vsyncId; - cv.notify_one(); - })); + // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp::make([&](const gui::WindowInfosUpdate& update) { + std::scoped_lock lock{mutex}; + lastUpdateId = update.vsyncId; + cv.notify_one(); + }), + &listenerInfo); BackgroundExecutor::getInstance().sendCallbacks({[&]() { mInvoker->windowInfosChanged({{}, {}, /* vsyncId= */ 1, 0}, {}, false); @@ -204,7 +205,7 @@ TEST_F(WindowInfosListenerInvokerTest, skipsDelayedMessage) { EXPECT_EQ(lastUpdateId, 1); // Ack the first message. The third update should be sent. - mInvoker->onWindowInfosReported(); + listenerInfo.windowInfosPublisher->ackWindowInfosReceived(1, listenerInfo.listenerId); { std::unique_lock lock{mutex}; @@ -225,14 +226,17 @@ TEST_F(WindowInfosListenerInvokerTest, noListeners) { // delayed. BackgroundExecutor::getInstance().sendCallbacks({[&]() { mInvoker->windowInfosChanged({}, {}, false); - mInvoker->addWindowInfosListener(sp::make( - [&](const gui::WindowInfosUpdate&, const sp&) { - std::scoped_lock lock{mutex}; - callCount++; - cv.notify_one(); - })); - mInvoker->windowInfosChanged({}, {}, false); + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp::make([&](const gui::WindowInfosUpdate&) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); + }), + &listenerInfo); }}); + BackgroundExecutor::getInstance().flushQueue(); + BackgroundExecutor::getInstance().sendCallbacks( + {[&]() { mInvoker->windowInfosChanged({}, {}, false); }}); { std::unique_lock lock{mutex}; -- GitLab From 3daa2725652978af091176e891f7627bca8f7a2d Mon Sep 17 00:00:00 2001 From: John Reck Date: Wed, 19 Jul 2023 17:25:42 -0400 Subject: [PATCH 0311/1187] Remove AHardwareBuffer_isValidPixelFormat Test: make && atest CtsNativeHardwareTestCases Bug: 291932479 Change-Id: I90f05d23ca9acdebade1854ed38c4aedbce158bf --- libs/nativewindow/AHardwareBuffer.cpp | 188 +++++++----------- .../private/android/AHardwareBufferHelpers.h | 3 - libs/nativewindow/libnativewindow.map.txt | 1 - 3 files changed, 74 insertions(+), 118 deletions(-) diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 80607055ed..b7da35d4d3 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -39,6 +39,80 @@ static constexpr int kFdBufferSize = 128 * sizeof(int); // 128 ints using namespace android; +// ---------------------------------------------------------------------------- +// Validate hardware_buffer.h and PixelFormat.aidl agree +// ---------------------------------------------------------------------------- + +static_assert(HAL_PIXEL_FORMAT_RGBA_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RGBX_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RGB_565 == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RGB_888 == AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RGBA_FP16 == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RGBA_1010102 == AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_BLOB == AHARDWAREBUFFER_FORMAT_BLOB, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_DEPTH_16 == AHARDWAREBUFFER_FORMAT_D16_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_DEPTH_24 == AHARDWAREBUFFER_FORMAT_D24_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_DEPTH_32F == AHARDWAREBUFFER_FORMAT_D32_FLOAT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_STENCIL_8 == AHARDWAREBUFFER_FORMAT_S8_UINT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_BGRA_8888 == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_YV12 == AHARDWAREBUFFER_FORMAT_YV12, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_Y8 == AHARDWAREBUFFER_FORMAT_Y8, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_Y16 == AHARDWAREBUFFER_FORMAT_Y16, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RAW16 == AHARDWAREBUFFER_FORMAT_RAW16, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RAW10 == AHARDWAREBUFFER_FORMAT_RAW10, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RAW12 == AHARDWAREBUFFER_FORMAT_RAW12, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_RAW_OPAQUE == AHARDWAREBUFFER_FORMAT_RAW_OPAQUE, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED == + AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_YCBCR_420_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_YCBCR_422_SP == AHARDWAREBUFFER_FORMAT_YCbCr_422_SP, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_YCRCB_420_SP == AHARDWAREBUFFER_FORMAT_YCrCb_420_SP, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_YCBCR_422_I == AHARDWAREBUFFER_FORMAT_YCbCr_422_I, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(HAL_PIXEL_FORMAT_YCBCR_P010 == AHARDWAREBUFFER_FORMAT_YCbCr_P010, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(static_cast(aidl::android::hardware::graphics::common::PixelFormat::R_8) == + AHARDWAREBUFFER_FORMAT_R8_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert(static_cast(aidl::android::hardware::graphics::common::PixelFormat::R_16_UINT) == + AHARDWAREBUFFER_FORMAT_R16_UINT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert( + static_cast(aidl::android::hardware::graphics::common::PixelFormat::RG_1616_UINT) == + AHARDWAREBUFFER_FORMAT_R16G16_UINT, + "HAL and AHardwareBuffer pixel format don't match"); +static_assert( + static_cast(aidl::android::hardware::graphics::common::PixelFormat::RGBA_10101010) == + AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM, + "HAL and AHardwareBuffer pixel format don't match"); + // ---------------------------------------------------------------------------- // Public functions // ---------------------------------------------------------------------------- @@ -487,12 +561,6 @@ bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool l return false; } - if (!AHardwareBuffer_isValidPixelFormat(desc->format)) { - ALOGE_IF(log, "Invalid AHardwareBuffer pixel format %u (%#x))", - desc->format, desc->format); - return false; - } - if (desc->rfu0 != 0 || desc->rfu1 != 0) { ALOGE_IF(log, "AHardwareBuffer_Desc::rfu fields must be 0"); return false; @@ -557,114 +625,6 @@ bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool l return true; } -bool AHardwareBuffer_isValidPixelFormat(uint32_t format) { - static_assert(HAL_PIXEL_FORMAT_RGBA_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RGBX_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RGB_565 == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RGB_888 == AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RGBA_FP16 == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RGBA_1010102 == AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_BLOB == AHARDWAREBUFFER_FORMAT_BLOB, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_DEPTH_16 == AHARDWAREBUFFER_FORMAT_D16_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_DEPTH_24 == AHARDWAREBUFFER_FORMAT_D24_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_DEPTH_32F == AHARDWAREBUFFER_FORMAT_D32_FLOAT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_STENCIL_8 == AHARDWAREBUFFER_FORMAT_S8_UINT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_BGRA_8888 == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YV12 == AHARDWAREBUFFER_FORMAT_YV12, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_Y8 == AHARDWAREBUFFER_FORMAT_Y8, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_Y16 == AHARDWAREBUFFER_FORMAT_Y16, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RAW16 == AHARDWAREBUFFER_FORMAT_RAW16, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RAW10 == AHARDWAREBUFFER_FORMAT_RAW10, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RAW12 == AHARDWAREBUFFER_FORMAT_RAW12, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_RAW_OPAQUE == AHARDWAREBUFFER_FORMAT_RAW_OPAQUE, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED == AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YCBCR_420_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YCBCR_422_SP == AHARDWAREBUFFER_FORMAT_YCbCr_422_SP, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YCRCB_420_SP == AHARDWAREBUFFER_FORMAT_YCrCb_420_SP, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YCBCR_422_I == AHARDWAREBUFFER_FORMAT_YCbCr_422_I, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(HAL_PIXEL_FORMAT_YCBCR_P010 == AHARDWAREBUFFER_FORMAT_YCbCr_P010, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(static_cast(aidl::android::hardware::graphics::common::PixelFormat::R_8) == - AHARDWAREBUFFER_FORMAT_R8_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(static_cast(aidl::android::hardware::graphics::common::PixelFormat::R_16_UINT) == - AHARDWAREBUFFER_FORMAT_R16_UINT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(static_cast(aidl::android::hardware::graphics::common::PixelFormat::RG_1616_UINT) == - AHARDWAREBUFFER_FORMAT_R16G16_UINT, - "HAL and AHardwareBuffer pixel format don't match"); - static_assert(static_cast(aidl::android::hardware::graphics::common::PixelFormat::RGBA_10101010) == - AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM, - "HAL and AHardwareBuffer pixel format don't match"); - - switch (format) { - case AHARDWAREBUFFER_FORMAT_R8_UNORM: - case AHARDWAREBUFFER_FORMAT_R16_UINT: - case AHARDWAREBUFFER_FORMAT_R16G16_UINT: - case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: - case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: - case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: - case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: - case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: - case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: - case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM: - case AHARDWAREBUFFER_FORMAT_BLOB: - case AHARDWAREBUFFER_FORMAT_D16_UNORM: - case AHARDWAREBUFFER_FORMAT_D24_UNORM: - case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT: - case AHARDWAREBUFFER_FORMAT_D32_FLOAT: - case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT: - case AHARDWAREBUFFER_FORMAT_S8_UINT: - case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420: - // VNDK formats only -- unfortunately we can't differentiate from where we're called - case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM: - case AHARDWAREBUFFER_FORMAT_YV12: - case AHARDWAREBUFFER_FORMAT_Y8: - case AHARDWAREBUFFER_FORMAT_Y16: - case AHARDWAREBUFFER_FORMAT_RAW16: - case AHARDWAREBUFFER_FORMAT_RAW10: - case AHARDWAREBUFFER_FORMAT_RAW12: - case AHARDWAREBUFFER_FORMAT_RAW_OPAQUE: - case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED: - case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP: - case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP: - case AHARDWAREBUFFER_FORMAT_YCbCr_422_I: - case AHARDWAREBUFFER_FORMAT_YCbCr_P010: - return true; - - default: - return false; - } -} - bool AHardwareBuffer_formatIsYuv(uint32_t format) { switch (format) { case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420: diff --git a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h index 6d3d295a0c..6df4ea3050 100644 --- a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h +++ b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h @@ -37,9 +37,6 @@ namespace android { // parameters. Note: this does not verify any platform-specific contraints. bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool log); -// whether this AHardwareBuffer format is valid -bool AHardwareBuffer_isValidPixelFormat(uint32_t ahardwarebuffer_format); - // whether this is a YUV type format bool AHardwareBuffer_formatIsYuv(uint32_t format); diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index c2fd6efcdb..dcb506815c 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -65,7 +65,6 @@ LIBNATIVEWINDOW { LIBNATIVEWINDOW_PLATFORM { global: extern "C++" { - android::AHardwareBuffer_isValidPixelFormat*; android::AHardwareBuffer_convertFromPixelFormat*; android::AHardwareBuffer_convertToPixelFormat*; android::AHardwareBuffer_convertFromGrallocUsageBits*; -- GitLab From c6976c8e0cc4c022a07345638127cbd3df1a778e Mon Sep 17 00:00:00 2001 From: Jim Shargo Date: Tue, 18 Jul 2023 20:33:45 +0000 Subject: [PATCH 0312/1187] libnativewindow: Add rust library and set up bindgen For now we only expose AHardwareBuffer, but the exposed bindings will make it easy to also expose ANativeWindow, ADataspace, and others in the future. Bug: 291954749 Test: Added new unit tests for both bindings and the rust library. Change-Id: I8ef24fc9111bb3fb72a4cdd941742d42d72fa776 --- libs/nativewindow/TEST_MAPPING | 6 + libs/nativewindow/rust/Android.bp | 87 ++++++ libs/nativewindow/rust/src/lib.rs | 260 ++++++++++++++++++ .../rust/sys/nativewindow_bindings.h | 20 ++ 4 files changed, 373 insertions(+) create mode 100644 libs/nativewindow/rust/Android.bp create mode 100644 libs/nativewindow/rust/src/lib.rs create mode 100644 libs/nativewindow/rust/sys/nativewindow_bindings.h diff --git a/libs/nativewindow/TEST_MAPPING b/libs/nativewindow/TEST_MAPPING index 3d7f3c28f4..9d6425bfe0 100644 --- a/libs/nativewindow/TEST_MAPPING +++ b/libs/nativewindow/TEST_MAPPING @@ -1,7 +1,13 @@ { "presubmit": [ + { + "name": "libnativewindow_bindgen_test" + }, { "name": "libnativewindow_test" + }, + { + "name": "libnativewindow_rs-internal_test" } ] } diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp new file mode 100644 index 0000000000..dc1575ca33 --- /dev/null +++ b/libs/nativewindow/rust/Android.bp @@ -0,0 +1,87 @@ +// Copyright (C) 2023 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. + +package { + default_applicable_licenses: [ + "frameworks_native_libs_nativewindow_license", + ], +} + +rust_bindgen { + name: "libnativewindow_bindgen", + crate_name: "nativewindow_bindgen", + wrapper_src: "sys/nativewindow_bindings.h", + source_stem: "bindings", + bindgen_flags: [ + "--constified-enum-module=AHardwareBuffer_Format", + "--bitfield-enum=AHardwareBuffer_UsageFlags", + + "--allowlist-file=.*/nativewindow/include/.*\\.h", + + "--with-derive-eq", + "--with-derive-partialeq", + ], + shared_libs: [ + "libnativewindow", + ], + + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", +} + +rust_test { + name: "libnativewindow_bindgen_test", + srcs: [":libnativewindow_bindgen"], + crate_name: "nativewindow_bindgen_test", + test_suites: ["general-tests"], + auto_gen_config: true, + clippy_lints: "none", + lints: "none", +} + +rust_defaults { + name: "libnativewindow_defaults", + srcs: ["src/lib.rs"], + rustlibs: [ + "libnativewindow_bindgen", + ], +} + +rust_library { + name: "libnativewindow_rs", + crate_name: "nativewindow", + defaults: ["libnativewindow_defaults"], + + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", +} + +rust_test { + name: "libnativewindow_rs-internal_test", + crate_name: "nativewindow", + defaults: ["libnativewindow_defaults"], + test_suites: ["general-tests"], +} diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs new file mode 100644 index 0000000000..a5bcc6293a --- /dev/null +++ b/libs/nativewindow/rust/src/lib.rs @@ -0,0 +1,260 @@ +// Copyright (C) 2023 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. + +//! Pleasant Rust bindings for libnativewindow, including AHardwareBuffer + +extern crate nativewindow_bindgen as ffi; + +pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; + +use std::os::raw::c_void; +use std::ptr; + +/// Wrapper around an opaque C AHardwareBuffer. +pub struct AHardwareBuffer(*mut ffi::AHardwareBuffer); + +impl AHardwareBuffer { + /// Test whether the given format and usage flag combination is allocatable. If this function + /// returns true, it means that a buffer with the given description can be allocated on this + /// implementation, unless resource exhaustion occurs. If this function returns false, it means + /// that the allocation of the given description will never succeed. + /// + /// Available since API 29 + pub fn is_supported( + width: u32, + height: u32, + layers: u32, + format: AHardwareBuffer_Format::Type, + usage: AHardwareBuffer_UsageFlags, + stride: u32, + ) -> bool { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width, + height, + layers, + format, + usage: usage.0, + stride, + rfu0: 0, + rfu1: 0, + }; + // SAFETY: *buffer_desc will never be null. + let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) }; + + status == 1 + } + + /// Allocates a buffer that matches the passed AHardwareBuffer_Desc. If allocation succeeds, the + /// buffer can be used according to the usage flags specified in its description. If a buffer is + /// used in ways not compatible with its usage flags, the results are undefined and may include + /// program termination. + /// + /// Available since API level 26. + pub fn new( + width: u32, + height: u32, + layers: u32, + format: AHardwareBuffer_Format::Type, + usage: AHardwareBuffer_UsageFlags, + ) -> Option { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width, + height, + layers, + format, + usage: usage.0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + let mut buffer = ptr::null_mut(); + // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail + // and return a status, but we check it later. + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut buffer) }; + + if status == 0 { + Some(Self(buffer)) + } else { + None + } + } + + /// Adopts the raw pointer and wraps it in a Rust AHardwareBuffer. + /// + /// # Errors + /// + /// Will panic if buffer_ptr is null. + /// + /// # Safety + /// + /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the + /// caller uses the pointer after the created object is dropped it will cause a memory leak. + pub unsafe fn take_from_raw(buffer_ptr: *mut c_void) -> Self { + assert!(!buffer_ptr.is_null()); + Self(buffer_ptr as *mut ffi::AHardwareBuffer) + } + + /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme + /// and undocumented circumstances. + /// + /// Available since API level 31. + pub fn id(&self) -> u64 { + let mut out_id = 0; + // SAFETY: Neither pointers can be null. + let status = unsafe { ffi::AHardwareBuffer_getId(self.0, &mut out_id) }; + assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}"); + + out_id + } + + /// Get the width of this buffer + pub fn width(&self) -> u32 { + self.description().width + } + + /// Get the height of this buffer + pub fn height(&self) -> u32 { + self.description().height + } + + /// Get the number of layers of this buffer + pub fn layers(&self) -> u32 { + self.description().layers + } + + /// Get the format of this buffer + pub fn format(&self) -> AHardwareBuffer_Format::Type { + self.description().format + } + + /// Get the usage bitvector of this buffer + pub fn usage(&self) -> AHardwareBuffer_UsageFlags { + AHardwareBuffer_UsageFlags(self.description().usage) + } + + /// Get the stride of this buffer + pub fn stride(&self) -> u32 { + self.description().stride + } + + fn description(&self) -> ffi::AHardwareBuffer_Desc { + let mut buffer_desc = ffi::AHardwareBuffer_Desc { + width: 0, + height: 0, + layers: 0, + format: 0, + usage: 0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null. + unsafe { ffi::AHardwareBuffer_describe(self.0, &mut buffer_desc) }; + buffer_desc + } +} + +impl Drop for AHardwareBuffer { + fn drop(&mut self) { + // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have + // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw + // pointer requiring callers to ensure the refcount is managed appropriately. + unsafe { ffi::AHardwareBuffer_release(self.0) } + } +} + +#[cfg(test)] +mod ahardwarebuffer_tests { + use super::*; + + #[test] + fn create_valid_buffer_returns_ok() { + let buffer = AHardwareBuffer::new( + 512, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ); + assert!(buffer.is_some()); + } + + #[test] + fn create_invalid_buffer_returns_err() { + let buffer = AHardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0)); + assert!(buffer.is_none()); + } + + #[test] + #[should_panic] + fn take_from_raw_panics_on_null() { + unsafe { AHardwareBuffer::take_from_raw(ptr::null_mut()) }; + } + + #[test] + fn take_from_raw_allows_getters() { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width: 1024, + height: 512, + layers: 1, + format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + let mut raw_buffer_ptr = ptr::null_mut(); + + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) }; + assert_eq!(status, 0); + + let buffer = unsafe { AHardwareBuffer::take_from_raw(raw_buffer_ptr as *mut c_void) }; + assert_eq!(buffer.width(), 1024); + } + + #[test] + fn basic_getters() { + let buffer = AHardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + + assert_eq!(buffer.width(), 1024); + assert_eq!(buffer.height(), 512); + assert_eq!(buffer.layers(), 1); + assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM); + assert_eq!( + buffer.usage(), + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN + ); + } + + #[test] + fn id_getter() { + let buffer = AHardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + + assert_ne!(0, buffer.id()); + } +} diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h new file mode 100644 index 0000000000..e652aee711 --- /dev/null +++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h @@ -0,0 +1,20 @@ +/* + * Copyright 2023 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 +#include +#include +#include -- GitLab From 700424cd0b73782ac4f4e821038e11d5af8d55f0 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 18 Jul 2023 17:18:42 -0700 Subject: [PATCH 0313/1187] Replace duplicate with onWindowInfosChanged The call to onWindowInfosChanged already creates new objects, so we don't need to be extra careful when sending the window handles to the dispatcher. In this CL, use onWindowInfosChanged instead of having to explicitly duplicate the handles. Bug: 211379801 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: Ic25c7662592b3c0b7160f4e5c4f434358711e1f4 --- .../tests/InputDispatcher_test.cpp | 32 +++---------------- 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 70516808f4..de6bd149c7 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1167,23 +1167,6 @@ public: return handle; } - /** - * This is different from clone, because clone will make a "mirror" window - a window with the - * same token, but a different ID. The original window and the clone window are allowed to be - * sent to the dispatcher at the same time - they can coexist inside the dispatcher. - * This function will create a different object of WindowInfoHandle, but with the same - * properties as the original object - including the ID. - * You can use either the old or the new object to consume the events. - * IMPORTANT: The duplicated object is supposed to replace the original object, and not appear - * at the same time inside dispatcher. - */ - sp duplicate() { - sp handle = sp::make(mName); - handle->mInfo = mInfo; - handle->mInputReceiver = mInputReceiver; - return handle; - } - void setTouchable(bool touchable) { mInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, !touchable); } @@ -3969,7 +3952,7 @@ TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) { sp window = sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 400, 400)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC); mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) @@ -3980,17 +3963,10 @@ TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) { window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); - // We need a new window object for the same window, because dispatcher will store objects by - // reference. That means that the testing code and the dispatcher will refer to the same shared - // object. Calling window->setTransform here would affect dispatcher's comparison - // of the old window to the new window, since both the old window and the new window would be - // updated to the same value. - sp windowDup = window->duplicate(); - // Change the transform so that the orientation is now different from original. - windowDup->setWindowTransform(0, -1, 1, 0); + window->setWindowTransform(0, -1, 1, 0); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowDup}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .downTime(baseTime + 10) @@ -4025,7 +4001,7 @@ TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) { .pointer(PointerBuilder(0, ToolType::FINGER).x(40).y(40)) .build()); - windowDup->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); } /** -- GitLab From e8a7ab25b2f2f17571279a2c2bf2ea0dff66c8e6 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Wed, 12 Jul 2023 13:47:28 -0500 Subject: [PATCH 0314/1187] Improve updateInputFlinger performance This change improves the performance of the WindowInfosListenerInvoker work done on SurfaceFlinger's background executor thread. The primary optimization made is not sending a WindowInfosReportedListener with every call to WindowInfosListener.onWindowInfosChanged. Instead, we send a new interface, WindowInfosPublisher, and a unique listener id to listeners when they're added. Listeners call WindowInfosPublisher.ackWindowInfosReceived with their id after processing each update. From traces taken during development, the new code is a major improvement, taking about 15% of the time spent previously on SurfaceFlinger's background thread for sending window infos. Performance with this change seems roughly in line with the performance in T. Bug: 290377931 Test: atest WindowInfosListenerTest Test: atest WindowInfosListenerInvokerTest Test: manually killing system server and checking valid state on restart Change-Id: Ib39ba935727df0bc1ab4030bcfe8301de7e64805 (cherry picked from commit acd2258a5492a9e289fd7f4b8ea90543d6843a23) --- libs/gui/Android.bp | 3 + libs/gui/WindowInfosListenerReporter.cpp | 20 +- .../aidl/android/gui/ISurfaceComposer.aidl | 4 +- .../android/gui/WindowInfosListenerInfo.aidl | 25 ++ .../gui/android/gui/IWindowInfosListener.aidl | 4 +- .../android/gui/IWindowInfosPublisher.aidl | 23 ++ libs/gui/fuzzer/libgui_fuzzer_utils.h | 4 +- libs/gui/include/gui/ISurfaceComposer.h | 1 + .../include/gui/WindowInfosListenerReporter.h | 8 +- libs/gui/tests/Surface_test.cpp | 3 +- .../surfaceflinger/BackgroundExecutor.cpp | 14 + services/surfaceflinger/BackgroundExecutor.h | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 14 +- services/surfaceflinger/SurfaceFlinger.h | 7 +- .../WindowInfosListenerInvoker.cpp | 253 +++++++++--------- .../WindowInfosListenerInvoker.h | 35 +-- .../WindowInfosListenerInvokerTest.cpp | 156 +++++------ 17 files changed, 333 insertions(+), 242 deletions(-) create mode 100644 libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl create mode 100644 libs/gui/android/gui/IWindowInfosPublisher.aidl diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 342f132f0c..d7e7eb8ea1 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -73,6 +73,7 @@ filegroup { "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", "android/gui/IWindowInfosListener.aidl", + "android/gui/IWindowInfosPublisher.aidl", "android/gui/IWindowInfosReportedListener.aidl", "android/gui/WindowInfo.aidl", "android/gui/WindowInfosUpdate.aidl", @@ -90,6 +91,7 @@ cc_library_static { "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", "android/gui/IWindowInfosListener.aidl", + "android/gui/IWindowInfosPublisher.aidl", "android/gui/IWindowInfosReportedListener.aidl", "android/gui/WindowInfosUpdate.aidl", "android/gui/WindowInfo.aidl", @@ -136,6 +138,7 @@ aidl_library { "android/gui/FocusRequest.aidl", "android/gui/InputApplicationInfo.aidl", "android/gui/IWindowInfosListener.aidl", + "android/gui/IWindowInfosPublisher.aidl", "android/gui/IWindowInfosReportedListener.aidl", "android/gui/WindowInfo.aidl", "android/gui/WindowInfosUpdate.aidl", diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp index 76e7b6e162..0929b8e120 100644 --- a/libs/gui/WindowInfosListenerReporter.cpp +++ b/libs/gui/WindowInfosListenerReporter.cpp @@ -22,7 +22,6 @@ namespace android { using gui::DisplayInfo; -using gui::IWindowInfosReportedListener; using gui::WindowInfo; using gui::WindowInfosListener; using gui::aidl_utils::statusTFromBinderStatus; @@ -40,8 +39,13 @@ status_t WindowInfosListenerReporter::addWindowInfosListener( { std::scoped_lock lock(mListenersMutex); if (mWindowInfosListeners.empty()) { - binder::Status s = surfaceComposer->addWindowInfosListener(this); + gui::WindowInfosListenerInfo listenerInfo; + binder::Status s = surfaceComposer->addWindowInfosListener(this, &listenerInfo); status = statusTFromBinderStatus(s); + if (status == OK) { + mWindowInfosPublisher = std::move(listenerInfo.windowInfosPublisher); + mListenerId = listenerInfo.listenerId; + } } if (status == OK) { @@ -85,8 +89,7 @@ status_t WindowInfosListenerReporter::removeWindowInfosListener( } binder::Status WindowInfosListenerReporter::onWindowInfosChanged( - const gui::WindowInfosUpdate& update, - const sp& windowInfosReportedListener) { + const gui::WindowInfosUpdate& update) { std::unordered_set, gui::SpHash> windowInfosListeners; @@ -104,9 +107,7 @@ binder::Status WindowInfosListenerReporter::onWindowInfosChanged( listener->onWindowInfosChanged(update); } - if (windowInfosReportedListener) { - windowInfosReportedListener->onWindowInfosReported(); - } + mWindowInfosPublisher->ackWindowInfosReceived(update.vsyncId, mListenerId); return binder::Status::ok(); } @@ -114,7 +115,10 @@ binder::Status WindowInfosListenerReporter::onWindowInfosChanged( void WindowInfosListenerReporter::reconnect(const sp& composerService) { std::scoped_lock lock(mListenersMutex); if (!mWindowInfosListeners.empty()) { - composerService->addWindowInfosListener(this); + gui::WindowInfosListenerInfo listenerInfo; + composerService->addWindowInfosListener(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 ec3266ca83..539a1c140e 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -40,12 +40,14 @@ import android.gui.IScreenCaptureListener; import android.gui.ISurfaceComposerClient; import android.gui.ITunnelModeEnabledListener; import android.gui.IWindowInfosListener; +import android.gui.IWindowInfosPublisher; import android.gui.LayerCaptureArgs; import android.gui.LayerDebugInfo; import android.gui.OverlayProperties; import android.gui.PullAtomData; import android.gui.ARect; import android.gui.StaticDisplayInfo; +import android.gui.WindowInfosListenerInfo; /** @hide */ interface ISurfaceComposer { @@ -500,7 +502,7 @@ interface ISurfaceComposer { */ int getMaxAcquiredBufferCount(); - void addWindowInfosListener(IWindowInfosListener windowInfosListener); + WindowInfosListenerInfo addWindowInfosListener(IWindowInfosListener windowInfosListener); void removeWindowInfosListener(IWindowInfosListener windowInfosListener); diff --git a/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl b/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl new file mode 100644 index 0000000000..0ca13b768a --- /dev/null +++ b/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2023, 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. + */ + +package android.gui; + +import android.gui.IWindowInfosPublisher; + +/** @hide */ +parcelable WindowInfosListenerInfo { + long listenerId; + IWindowInfosPublisher windowInfosPublisher; +} \ No newline at end of file diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl index 400229d99f..07cb5ed0e6 100644 --- a/libs/gui/android/gui/IWindowInfosListener.aidl +++ b/libs/gui/android/gui/IWindowInfosListener.aidl @@ -16,11 +16,9 @@ package android.gui; -import android.gui.IWindowInfosReportedListener; import android.gui.WindowInfosUpdate; /** @hide */ oneway interface IWindowInfosListener { - void onWindowInfosChanged( - in WindowInfosUpdate update, in @nullable IWindowInfosReportedListener windowInfosReportedListener); + void onWindowInfosChanged(in WindowInfosUpdate update); } diff --git a/libs/gui/android/gui/IWindowInfosPublisher.aidl b/libs/gui/android/gui/IWindowInfosPublisher.aidl new file mode 100644 index 0000000000..5a9c32845e --- /dev/null +++ b/libs/gui/android/gui/IWindowInfosPublisher.aidl @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2023, 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. + */ + +package android.gui; + +/** @hide */ +oneway interface IWindowInfosPublisher +{ + void ackWindowInfosReceived(long vsyncId, long listenerId); +} diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index 8c003d8ad4..4c7d0562af 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -153,8 +153,8 @@ public: MOCK_METHOD(binder::Status, setOverrideFrameRate, (int32_t, float), (override)); MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override)); MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override)); - MOCK_METHOD(binder::Status, addWindowInfosListener, (const sp&), - (override)); + MOCK_METHOD(binder::Status, addWindowInfosListener, + (const sp&, gui::WindowInfosListenerInfo*), (override)); MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp&), (override)); MOCK_METHOD(binder::Status, getOverlaySupport, (gui::OverlayProperties*), (override)); diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 7c150d53d9..3ff6735926 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h index 38cb108912..684e21ad96 100644 --- a/libs/gui/include/gui/WindowInfosListenerReporter.h +++ b/libs/gui/include/gui/WindowInfosListenerReporter.h @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -30,8 +30,7 @@ namespace android { class WindowInfosListenerReporter : public gui::BnWindowInfosListener { public: static sp getInstance(); - binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update, - const sp&) override; + binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update) override; status_t addWindowInfosListener( const sp& windowInfosListener, const sp&, @@ -47,5 +46,8 @@ private: std::vector mLastWindowInfos GUARDED_BY(mListenersMutex); std::vector mLastDisplayInfos GUARDED_BY(mListenersMutex); + + sp mWindowInfosPublisher; + int64_t mListenerId; }; } // namespace android diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 90c0a63286..567604dbec 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1002,7 +1002,8 @@ public: } binder::Status addWindowInfosListener( - const sp& /*windowInfosListener*/) override { + const sp& /*windowInfosListener*/, + gui::WindowInfosListenerInfo* /*outInfo*/) override { return binder::Status::ok(); } diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp index 6ddf790d47..5a1ec6f501 100644 --- a/services/surfaceflinger/BackgroundExecutor.cpp +++ b/services/surfaceflinger/BackgroundExecutor.cpp @@ -20,6 +20,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include +#include #include "BackgroundExecutor.h" @@ -60,4 +61,17 @@ void BackgroundExecutor::sendCallbacks(Callbacks&& tasks) { LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed"); } +void BackgroundExecutor::flushQueue() { + std::mutex mutex; + std::condition_variable cv; + bool flushComplete = false; + sendCallbacks({[&]() { + std::scoped_lock lock{mutex}; + flushComplete = true; + cv.notify_one(); + }}); + std::unique_lock lock{mutex}; + cv.wait(lock, [&]() { return flushComplete; }); +} + } // namespace android diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h index 0fae5a5c93..66b7d7a1fc 100644 --- a/services/surfaceflinger/BackgroundExecutor.h +++ b/services/surfaceflinger/BackgroundExecutor.h @@ -34,6 +34,7 @@ public: // Queues callbacks onto a work queue to be executed by a background thread. // This is safe to call from multiple threads. void sendCallbacks(Callbacks&& tasks); + void flushQueue(); private: sem_t mSemaphore; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0710d875a9..de0034b8ac 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -6128,8 +6128,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp ftl::to_underlying(windowInfosDebug.maxSendDelayVsyncId)); StringAppendF(&result, " max send delay (ns): %" PRId64 " ns\n", windowInfosDebug.maxSendDelayDuration); - StringAppendF(&result, " unsent messages: %" PRIu32 "\n", - windowInfosDebug.pendingMessageCount); + StringAppendF(&result, " unsent messages: %zu\n", windowInfosDebug.pendingMessageCount); result.append("\n"); } @@ -7969,9 +7968,9 @@ void SurfaceFlinger::onActiveDisplayChangedLocked(const DisplayDevice* inactiveD forceApplyPolicy); } -status_t SurfaceFlinger::addWindowInfosListener( - const sp& windowInfosListener) { - mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener); +status_t SurfaceFlinger::addWindowInfosListener(const sp& windowInfosListener, + gui::WindowInfosListenerInfo* outInfo) { + mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener, outInfo); setTransactionFlags(eInputInfoUpdateNeeded); return NO_ERROR; } @@ -9054,7 +9053,8 @@ binder::Status SurfaceComposerAIDL::getMaxAcquiredBufferCount(int32_t* buffers) } binder::Status SurfaceComposerAIDL::addWindowInfosListener( - const sp& windowInfosListener) { + const sp& windowInfosListener, + gui::WindowInfosListenerInfo* outInfo) { status_t status; const int pid = IPCThreadState::self()->getCallingPid(); const int uid = IPCThreadState::self()->getCallingUid(); @@ -9062,7 +9062,7 @@ binder::Status SurfaceComposerAIDL::addWindowInfosListener( // WindowInfosListeners if (uid == AID_SYSTEM || uid == AID_GRAPHICS || checkPermission(sAccessSurfaceFlinger, pid, uid)) { - status = mFlinger->addWindowInfosListener(windowInfosListener); + status = mFlinger->addWindowInfosListener(windowInfosListener, outInfo); } else { status = PERMISSION_DENIED; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 19a1feb38d..f1759a5e52 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -613,7 +613,8 @@ private: status_t getMaxAcquiredBufferCount(int* buffers) const; - status_t addWindowInfosListener(const sp& windowInfosListener); + status_t addWindowInfosListener(const sp& windowInfosListener, + gui::WindowInfosListenerInfo* outResult); status_t removeWindowInfosListener( const sp& windowInfosListener) const; @@ -1537,8 +1538,8 @@ public: binder::Status setOverrideFrameRate(int32_t uid, float frameRate) override; binder::Status getGpuContextPriority(int32_t* outPriority) override; binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override; - binder::Status addWindowInfosListener( - const sp& windowInfosListener) override; + binder::Status addWindowInfosListener(const sp& windowInfosListener, + gui::WindowInfosListenerInfo* outInfo) override; binder::Status removeWindowInfosListener( const sp& windowInfosListener) override; diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index 20699ef123..7062a4e3a7 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -14,7 +14,9 @@ * limitations under the License. */ -#include +#include +#include +#include #include #include #include @@ -23,162 +25,130 @@ #include "BackgroundExecutor.h" #include "WindowInfosListenerInvoker.h" +#undef ATRACE_TAG +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + namespace android { using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; -using WindowInfosListenerVector = ftl::SmallVector, 3>; - -struct WindowInfosReportedListenerInvoker : gui::BnWindowInfosReportedListener, - IBinder::DeathRecipient { - WindowInfosReportedListenerInvoker(WindowInfosListenerVector windowInfosListeners, - WindowInfosReportedListenerSet windowInfosReportedListeners) - : mCallbacksPending(windowInfosListeners.size()), - mWindowInfosListeners(std::move(windowInfosListeners)), - mWindowInfosReportedListeners(std::move(windowInfosReportedListeners)) {} +void WindowInfosListenerInvoker::addWindowInfosListener(sp listener, + gui::WindowInfosListenerInfo* outInfo) { + int64_t listenerId = mNextListenerId++; + outInfo->listenerId = listenerId; + outInfo->windowInfosPublisher = sp::fromExisting(this); - binder::Status onWindowInfosReported() override { - if (--mCallbacksPending == 0) { - for (const auto& listener : mWindowInfosReportedListeners) { + BackgroundExecutor::getInstance().sendCallbacks( + {[this, listener = std::move(listener), listenerId]() { + ATRACE_NAME("WindowInfosListenerInvoker::addWindowInfosListener"); sp asBinder = IInterface::asBinder(listener); - if (asBinder->isBinderAlive()) { - listener->onWindowInfosReported(); - } - } - - auto wpThis = wp::fromExisting(this); - for (const auto& listener : mWindowInfosListeners) { - sp binder = IInterface::asBinder(listener); - binder->unlinkToDeath(wpThis); - } - } - return binder::Status::ok(); - } - - void binderDied(const wp&) { onWindowInfosReported(); } - -private: - std::atomic mCallbacksPending; - static constexpr size_t kStaticCapacity = 3; - const WindowInfosListenerVector mWindowInfosListeners; - WindowInfosReportedListenerSet mWindowInfosReportedListeners; -}; - -void WindowInfosListenerInvoker::addWindowInfosListener(sp listener) { - sp asBinder = IInterface::asBinder(listener); - asBinder->linkToDeath(sp::fromExisting(this)); - - std::scoped_lock lock(mListenersMutex); - mWindowInfosListeners.try_emplace(asBinder, std::move(listener)); + asBinder->linkToDeath(sp::fromExisting(this)); + mWindowInfosListeners.try_emplace(asBinder, + std::make_pair(listenerId, std::move(listener))); + }}); } void WindowInfosListenerInvoker::removeWindowInfosListener( const sp& listener) { - sp asBinder = IInterface::asBinder(listener); - - std::scoped_lock lock(mListenersMutex); - asBinder->unlinkToDeath(sp::fromExisting(this)); - mWindowInfosListeners.erase(asBinder); + BackgroundExecutor::getInstance().sendCallbacks({[this, listener]() { + ATRACE_NAME("WindowInfosListenerInvoker::removeWindowInfosListener"); + sp asBinder = IInterface::asBinder(listener); + asBinder->unlinkToDeath(sp::fromExisting(this)); + mWindowInfosListeners.erase(asBinder); + }}); } void WindowInfosListenerInvoker::binderDied(const wp& who) { - std::scoped_lock lock(mListenersMutex); - mWindowInfosListeners.erase(who); + BackgroundExecutor::getInstance().sendCallbacks({[this, who]() { + ATRACE_NAME("WindowInfosListenerInvoker::binderDied"); + auto it = mWindowInfosListeners.find(who); + int64_t listenerId = it->second.first; + mWindowInfosListeners.erase(who); + + std::vector vsyncIds; + for (auto& [vsyncId, state] : mUnackedState) { + if (std::find(state.unackedListenerIds.begin(), state.unackedListenerIds.end(), + listenerId) != state.unackedListenerIds.end()) { + vsyncIds.push_back(vsyncId); + } + } + + for (int64_t vsyncId : vsyncIds) { + ackWindowInfosReceived(vsyncId, listenerId); + } + }}); } void WindowInfosListenerInvoker::windowInfosChanged( gui::WindowInfosUpdate update, WindowInfosReportedListenerSet reportedListeners, bool forceImmediateCall) { - WindowInfosListenerVector listeners; - { - std::scoped_lock lock{mMessagesMutex}; - - if (!mDelayInfo) { - mDelayInfo = DelayInfo{ - .vsyncId = update.vsyncId, - .frameTime = update.timestamp, - }; - } - - // If there are unacked messages and this isn't a forced call, then return immediately. - // If a forced window infos change doesn't happen first, the update will be sent after - // the WindowInfosReportedListeners are called. If a forced window infos change happens or - // if there are subsequent delayed messages before this update is sent, then this message - // will be dropped and the listeners will only be called with the latest info. This is done - // to reduce the amount of binder memory used. - if (mActiveMessageCount > 0 && !forceImmediateCall) { - mDelayedUpdate = std::move(update); - mReportedListeners.merge(reportedListeners); - return; - } - - if (mDelayedUpdate) { - mDelayedUpdate.reset(); - } + if (!mDelayInfo) { + mDelayInfo = DelayInfo{ + .vsyncId = update.vsyncId, + .frameTime = update.timestamp, + }; + } - { - std::scoped_lock lock{mListenersMutex}; - for (const auto& [_, listener] : mWindowInfosListeners) { - listeners.push_back(listener); - } - } - if (CC_UNLIKELY(listeners.empty())) { - mReportedListeners.merge(reportedListeners); - mDelayInfo.reset(); - return; - } + // If there are unacked messages and this isn't a forced call, then return immediately. + // If a forced window infos change doesn't happen first, the update will be sent after + // the WindowInfosReportedListeners are called. If a forced window infos change happens or + // if there are subsequent delayed messages before this update is sent, then this message + // will be dropped and the listeners will only be called with the latest info. This is done + // to reduce the amount of binder memory used. + if (!mUnackedState.empty() && !forceImmediateCall) { + mDelayedUpdate = std::move(update); + mReportedListeners.merge(reportedListeners); + return; + } - reportedListeners.insert(sp::fromExisting(this)); - reportedListeners.merge(mReportedListeners); - mReportedListeners.clear(); + if (mDelayedUpdate) { + mDelayedUpdate.reset(); + } - mActiveMessageCount++; - updateMaxSendDelay(); + if (CC_UNLIKELY(mWindowInfosListeners.empty())) { + mReportedListeners.merge(reportedListeners); mDelayInfo.reset(); + return; } - auto reportedInvoker = - sp::make(listeners, std::move(reportedListeners)); - - for (const auto& listener : listeners) { - sp asBinder = IInterface::asBinder(listener); + reportedListeners.merge(mReportedListeners); + mReportedListeners.clear(); + + // Update mUnackedState to include the message we're about to send + auto [it, _] = mUnackedState.try_emplace(update.vsyncId, + UnackedState{.reportedListeners = + std::move(reportedListeners)}); + auto& unackedState = it->second; + for (auto& pair : mWindowInfosListeners) { + int64_t listenerId = pair.second.first; + unackedState.unackedListenerIds.push_back(listenerId); + } - // linkToDeath is used here to ensure that the windowInfosReportedListeners - // are called even if one of the windowInfosListeners dies before - // calling onWindowInfosReported. - asBinder->linkToDeath(reportedInvoker); + mDelayInfo.reset(); + updateMaxSendDelay(); - auto status = listener->onWindowInfosChanged(update, reportedInvoker); + // Call the listeners + for (auto& pair : mWindowInfosListeners) { + auto& [listenerId, listener] = pair.second; + auto status = listener->onWindowInfosChanged(update); if (!status.isOk()) { - reportedInvoker->onWindowInfosReported(); + ackWindowInfosReceived(update.vsyncId, listenerId); } } } -binder::Status WindowInfosListenerInvoker::onWindowInfosReported() { - BackgroundExecutor::getInstance().sendCallbacks({[this]() { - gui::WindowInfosUpdate update; - { - std::scoped_lock lock{mMessagesMutex}; - mActiveMessageCount--; - if (!mDelayedUpdate || mActiveMessageCount > 0) { - return; - } - update = std::move(*mDelayedUpdate); - mDelayedUpdate.reset(); - } - windowInfosChanged(std::move(update), {}, false); - }}); - return binder::Status::ok(); -} - WindowInfosListenerInvoker::DebugInfo WindowInfosListenerInvoker::getDebugInfo() { - std::scoped_lock lock{mMessagesMutex}; - updateMaxSendDelay(); - mDebugInfo.pendingMessageCount = mActiveMessageCount; - return mDebugInfo; + DebugInfo result; + BackgroundExecutor::getInstance().sendCallbacks({[&, this]() { + ATRACE_NAME("WindowInfosListenerInvoker::getDebugInfo"); + updateMaxSendDelay(); + result = mDebugInfo; + result.pendingMessageCount = mUnackedState.size(); + }}); + BackgroundExecutor::getInstance().flushQueue(); + return result; } void WindowInfosListenerInvoker::updateMaxSendDelay() { @@ -192,4 +162,41 @@ void WindowInfosListenerInvoker::updateMaxSendDelay() { } } +binder::Status WindowInfosListenerInvoker::ackWindowInfosReceived(int64_t vsyncId, + int64_t listenerId) { + BackgroundExecutor::getInstance().sendCallbacks({[this, vsyncId, listenerId]() { + ATRACE_NAME("WindowInfosListenerInvoker::ackWindowInfosReceived"); + auto it = mUnackedState.find(vsyncId); + if (it == mUnackedState.end()) { + return; + } + + auto& state = it->second; + state.unackedListenerIds.unstable_erase(std::find(state.unackedListenerIds.begin(), + state.unackedListenerIds.end(), + listenerId)); + if (!state.unackedListenerIds.empty()) { + return; + } + + WindowInfosReportedListenerSet reportedListeners{std::move(state.reportedListeners)}; + mUnackedState.erase(vsyncId); + + for (const auto& reportedListener : reportedListeners) { + sp asBinder = IInterface::asBinder(reportedListener); + if (asBinder->isBinderAlive()) { + reportedListener->onWindowInfosReported(); + } + } + + if (!mDelayedUpdate || !mUnackedState.empty()) { + return; + } + gui::WindowInfosUpdate update{std::move(*mDelayedUpdate)}; + mDelayedUpdate.reset(); + windowInfosChanged(std::move(update), {}, false); + }}); + return binder::Status::ok(); +} + } // namespace android diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index bc465a3a2b..f36b0edd7d 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -19,11 +19,12 @@ #include #include -#include +#include #include #include #include #include +#include #include #include @@ -35,22 +36,22 @@ using WindowInfosReportedListenerSet = std::unordered_set, gui::SpHash>; -class WindowInfosListenerInvoker : public gui::BnWindowInfosReportedListener, +class WindowInfosListenerInvoker : public gui::BnWindowInfosPublisher, public IBinder::DeathRecipient { public: - void addWindowInfosListener(sp); + void addWindowInfosListener(sp, gui::WindowInfosListenerInfo*); void removeWindowInfosListener(const sp& windowInfosListener); void windowInfosChanged(gui::WindowInfosUpdate update, WindowInfosReportedListenerSet windowInfosReportedListeners, bool forceImmediateCall); - binder::Status onWindowInfosReported() override; + binder::Status ackWindowInfosReceived(int64_t, int64_t) override; struct DebugInfo { VsyncId maxSendDelayVsyncId; nsecs_t maxSendDelayDuration; - uint32_t pendingMessageCount; + size_t pendingMessageCount; }; DebugInfo getDebugInfo(); @@ -58,24 +59,28 @@ protected: void binderDied(const wp& who) override; private: - std::mutex mListenersMutex; - static constexpr size_t kStaticCapacity = 3; - ftl::SmallMap, const sp, kStaticCapacity> - mWindowInfosListeners GUARDED_BY(mListenersMutex); + std::atomic mNextListenerId{0}; + ftl::SmallMap, const std::pair>, + kStaticCapacity> + mWindowInfosListeners; - std::mutex mMessagesMutex; - uint32_t mActiveMessageCount GUARDED_BY(mMessagesMutex) = 0; - std::optional mDelayedUpdate GUARDED_BY(mMessagesMutex); + std::optional mDelayedUpdate; WindowInfosReportedListenerSet mReportedListeners; - DebugInfo mDebugInfo GUARDED_BY(mMessagesMutex); + struct UnackedState { + ftl::SmallVector unackedListenerIds; + WindowInfosReportedListenerSet reportedListeners; + }; + ftl::SmallMap mUnackedState; + + DebugInfo mDebugInfo; struct DelayInfo { int64_t vsyncId; nsecs_t frameTime; }; - std::optional mDelayInfo GUARDED_BY(mMessagesMutex); - void updateMaxSendDelay() REQUIRES(mMessagesMutex); + std::optional mDelayInfo; + void updateMaxSendDelay(); }; } // namespace android diff --git a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp index af4971b063..c7b845e668 100644 --- a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp +++ b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp @@ -15,35 +15,23 @@ protected: WindowInfosListenerInvokerTest() : mInvoker(sp::make()) {} ~WindowInfosListenerInvokerTest() { - std::mutex mutex; - std::condition_variable cv; - bool flushComplete = false; // Flush the BackgroundExecutor thread to ensure any scheduled tasks are complete. // Otherwise, references those tasks hold may go out of scope before they are done // executing. - BackgroundExecutor::getInstance().sendCallbacks({[&]() { - std::scoped_lock lock{mutex}; - flushComplete = true; - cv.notify_one(); - }}); - std::unique_lock lock{mutex}; - cv.wait(lock, [&]() { return flushComplete; }); + BackgroundExecutor::getInstance().flushQueue(); } sp mInvoker; }; -using WindowInfosUpdateConsumer = std::function&)>; +using WindowInfosUpdateConsumer = std::function; class Listener : public gui::BnWindowInfosListener { public: Listener(WindowInfosUpdateConsumer consumer) : mConsumer(std::move(consumer)) {} - binder::Status onWindowInfosChanged( - const gui::WindowInfosUpdate& update, - const sp& reportedListener) override { - mConsumer(update, reportedListener); + binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update) override { + mConsumer(update); return binder::Status::ok(); } @@ -58,15 +46,17 @@ TEST_F(WindowInfosListenerInvokerTest, callsSingleListener) { int callCount = 0; - mInvoker->addWindowInfosListener( - sp::make([&](const gui::WindowInfosUpdate&, - const sp& reportedListener) { - std::scoped_lock lock{mutex}; - callCount++; - cv.notify_one(); + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp::make([&](const gui::WindowInfosUpdate& update) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); - reportedListener->onWindowInfosReported(); - })); + listenerInfo.windowInfosPublisher + ->ackWindowInfosReceived(update.vsyncId, + listenerInfo.listenerId); + }), + &listenerInfo); BackgroundExecutor::getInstance().sendCallbacks( {[this]() { mInvoker->windowInfosChanged({}, {}, false); }}); @@ -81,21 +71,27 @@ TEST_F(WindowInfosListenerInvokerTest, callsMultipleListeners) { std::mutex mutex; std::condition_variable cv; - int callCount = 0; - const int expectedCallCount = 3; - - for (int i = 0; i < expectedCallCount; i++) { - mInvoker->addWindowInfosListener(sp::make( - [&](const gui::WindowInfosUpdate&, - const sp& reportedListener) { - std::scoped_lock lock{mutex}; - callCount++; - if (callCount == expectedCallCount) { - cv.notify_one(); - } - - reportedListener->onWindowInfosReported(); - })); + size_t callCount = 0; + const size_t expectedCallCount = 3; + std::vector listenerInfos{expectedCallCount, + gui::WindowInfosListenerInfo{}}; + + for (size_t i = 0; i < expectedCallCount; i++) { + mInvoker->addWindowInfosListener(sp::make([&, &listenerInfo = listenerInfos[i]]( + const gui::WindowInfosUpdate& + update) { + std::scoped_lock lock{mutex}; + callCount++; + if (callCount == expectedCallCount) { + cv.notify_one(); + } + + listenerInfo.windowInfosPublisher + ->ackWindowInfosReceived(update.vsyncId, + listenerInfo + .listenerId); + }), + &listenerInfos[i]); } BackgroundExecutor::getInstance().sendCallbacks( @@ -114,17 +110,20 @@ TEST_F(WindowInfosListenerInvokerTest, delaysUnackedCall) { int callCount = 0; - // Simulate a slow ack by not calling the WindowInfosReportedListener. - mInvoker->addWindowInfosListener(sp::make( - [&](const gui::WindowInfosUpdate&, const sp&) { - std::scoped_lock lock{mutex}; - callCount++; - cv.notify_one(); - })); + // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp::make([&](const gui::WindowInfosUpdate&) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); + }), + &listenerInfo); BackgroundExecutor::getInstance().sendCallbacks({[&]() { - mInvoker->windowInfosChanged({}, {}, false); - mInvoker->windowInfosChanged({}, {}, false); + mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 0, 0}, {}, + false); + mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 1, 0}, {}, + false); }}); { @@ -134,7 +133,7 @@ TEST_F(WindowInfosListenerInvokerTest, delaysUnackedCall) { EXPECT_EQ(callCount, 1); // Ack the first message. - mInvoker->onWindowInfosReported(); + listenerInfo.windowInfosPublisher->ackWindowInfosReceived(0, listenerInfo.listenerId); { std::unique_lock lock{mutex}; @@ -152,19 +151,21 @@ TEST_F(WindowInfosListenerInvokerTest, sendsForcedMessage) { int callCount = 0; const int expectedCallCount = 2; - // Simulate a slow ack by not calling the WindowInfosReportedListener. - mInvoker->addWindowInfosListener(sp::make( - [&](const gui::WindowInfosUpdate&, const sp&) { - std::scoped_lock lock{mutex}; - callCount++; - if (callCount == expectedCallCount) { - cv.notify_one(); - } - })); + // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp::make([&](const gui::WindowInfosUpdate&) { + std::scoped_lock lock{mutex}; + callCount++; + if (callCount == expectedCallCount) { + cv.notify_one(); + } + }), + &listenerInfo); BackgroundExecutor::getInstance().sendCallbacks({[&]() { - mInvoker->windowInfosChanged({}, {}, false); - mInvoker->windowInfosChanged({}, {}, true); + mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 0, 0}, {}, + false); + mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 1, 0}, {}, true); }}); { @@ -182,14 +183,14 @@ TEST_F(WindowInfosListenerInvokerTest, skipsDelayedMessage) { int64_t lastUpdateId = -1; - // Simulate a slow ack by not calling the WindowInfosReportedListener. - mInvoker->addWindowInfosListener( - sp::make([&](const gui::WindowInfosUpdate& update, - const sp&) { - std::scoped_lock lock{mutex}; - lastUpdateId = update.vsyncId; - cv.notify_one(); - })); + // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp::make([&](const gui::WindowInfosUpdate& update) { + std::scoped_lock lock{mutex}; + lastUpdateId = update.vsyncId; + cv.notify_one(); + }), + &listenerInfo); BackgroundExecutor::getInstance().sendCallbacks({[&]() { mInvoker->windowInfosChanged({{}, {}, /* vsyncId= */ 1, 0}, {}, false); @@ -204,7 +205,7 @@ TEST_F(WindowInfosListenerInvokerTest, skipsDelayedMessage) { EXPECT_EQ(lastUpdateId, 1); // Ack the first message. The third update should be sent. - mInvoker->onWindowInfosReported(); + listenerInfo.windowInfosPublisher->ackWindowInfosReceived(1, listenerInfo.listenerId); { std::unique_lock lock{mutex}; @@ -225,14 +226,17 @@ TEST_F(WindowInfosListenerInvokerTest, noListeners) { // delayed. BackgroundExecutor::getInstance().sendCallbacks({[&]() { mInvoker->windowInfosChanged({}, {}, false); - mInvoker->addWindowInfosListener(sp::make( - [&](const gui::WindowInfosUpdate&, const sp&) { - std::scoped_lock lock{mutex}; - callCount++; - cv.notify_one(); - })); - mInvoker->windowInfosChanged({}, {}, false); + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp::make([&](const gui::WindowInfosUpdate&) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); + }), + &listenerInfo); }}); + BackgroundExecutor::getInstance().flushQueue(); + BackgroundExecutor::getInstance().sendCallbacks( + {[&]() { mInvoker->windowInfosChanged({}, {}, false); }}); { std::unique_lock lock{mutex}; -- GitLab From 0a321db33ed5b3831d39ff36a3b14c48434a849e Mon Sep 17 00:00:00 2001 From: John Reck Date: Thu, 20 Jul 2023 11:47:13 -0400 Subject: [PATCH 0315/1187] Remove logspam This log seems to fire regularly when drawing to things like a SurfaceTexture. Certainly doesn't seem like an error, and it doesn't seem useful, either. So remove it. Test: make && adb logcat Change-Id: I92c8b9f298775db9a6d0fc8eea0b0e3d06975ad2 --- libs/gui/FrameTimestamps.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp index f3eb4e83aa..afb09de94b 100644 --- a/libs/gui/FrameTimestamps.cpp +++ b/libs/gui/FrameTimestamps.cpp @@ -255,7 +255,6 @@ void ProducerFrameEventHistory::updateAcquireFence( uint64_t frameNumber, std::shared_ptr&& acquire) { FrameEvents* frame = getFrame(frameNumber, &mAcquireOffset); if (frame == nullptr) { - ALOGE("updateAcquireFence: Did not find frame."); return; } -- GitLab From 52d56fd14ec7e8aa5b0532dbb1330b5ef5cc5248 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 20 Jul 2023 17:02:43 +0000 Subject: [PATCH 0316/1187] [sf] additional fixes for framerate propagation in new fe We have to update the parents when their child is reparented. The parent doesn't have a change flag since a child in most cases does not affect its parent. To ensure framerate gets updated correctly, always update framerates if there are any hierarchy changes. Also add more tests to exercise this path. Test: presubmit Test: atest android.graphics.cts.FrameRateOverrideTest Bug: 238781169 Change-Id: I3eefdeefae4e18b5f2f65a6f341481e328f5d1c7 --- .../FrontEnd/LayerSnapshotBuilder.cpp | 14 ++-- .../tests/unittests/LayerHierarchyTest.h | 14 ++++ .../tests/unittests/LayerSnapshotTest.cpp | 84 +++++++++++++++++++ 3 files changed, 106 insertions(+), 6 deletions(-) diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 7e678b98fa..23cfe928f5 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -540,7 +540,7 @@ const LayerSnapshot& LayerSnapshotBuilder::updateSnapshotsInHierarchy( primaryDisplayRotationFlags); snapshot->changes |= RequestedLayerState::Changes::Created; } - scheduler::LayerInfo::FrameRate oldFrameRate = snapshot->frameRate; + if (traversalPath.isRelative()) { bool parentIsRelative = traversalPath.variant == LayerHierarchy::Variant::Relative; updateRelativeState(*snapshot, parentSnapshot, parentIsRelative, args); @@ -561,9 +561,6 @@ const LayerSnapshot& LayerSnapshotBuilder::updateSnapshotsInHierarchy( updateFrameRateFromChildSnapshot(*snapshot, childSnapshot, args); } - if (oldFrameRate == snapshot->frameRate) { - snapshot->changes.clear(RequestedLayerState::Changes::FrameRate); - } return *snapshot; } @@ -670,8 +667,10 @@ void LayerSnapshotBuilder::updateFrameRateFromChildSnapshot(LayerSnapshot& snaps const LayerSnapshot& childSnapshot, const Args& args) { if (args.forceUpdate == ForceUpdateFlags::NONE && - !childSnapshot.changes.any(RequestedLayerState::Changes::FrameRate | - RequestedLayerState::Changes::Hierarchy)) { + !args.layerLifecycleManager.getGlobalChanges().any( + RequestedLayerState::Changes::Hierarchy) && + !childSnapshot.changes.any(RequestedLayerState::Changes::FrameRate) && + !snapshot.changes.any(RequestedLayerState::Changes::FrameRate)) { return; } @@ -817,6 +816,8 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a } if (forceUpdate || + args.layerLifecycleManager.getGlobalChanges().any( + RequestedLayerState::Changes::Hierarchy) || snapshot.changes.any(RequestedLayerState::Changes::FrameRate | RequestedLayerState::Changes::Hierarchy)) { snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() || @@ -824,6 +825,7 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a scheduler::LayerInfo::FrameRateCompatibility::NoVote)) ? requested.requestedFrameRate : parentSnapshot.frameRate; + snapshot.changes |= RequestedLayerState::Changes::FrameRate; } if (forceUpdate || snapshot.clientChanges & layer_state_t::eFrameRateSelectionPriority) { diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index 3234483f14..e475b843c9 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -319,6 +319,20 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setFrameRate(uint32_t id, float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) { + std::vector transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = layer_state_t::eFrameRateChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.frameRate = frameRate; + transactions.back().states.front().state.frameRateCompatibility = compatibility; + transactions.back().states.front().state.changeFrameRateStrategy = changeFrameRateStrategy; + mLifecycleManager.applyTransactions(transactions); + } + LayerLifecycleManager mLifecycleManager; }; diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index d6c4b7229e..a581d5b6ff 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -512,4 +512,88 @@ TEST_F(LayerSnapshotTest, frameRateSelectionPriorityPassedToChildLayers) { EXPECT_EQ(getSnapshot({.id = 1221})->frameRateSelectionPriority, 1); } +TEST_F(LayerSnapshotTest, framerate) { + setFrameRate(11, 244.f, 0, 0); + + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + // verify parent is gets no vote + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type, + scheduler::LayerInfo::FrameRateCompatibility::NoVote); + EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // verify layer and children get the requested votes + EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_TRUE(getSnapshot({.id = 11})->changes.test(RequestedLayerState::Changes::FrameRate)); + + EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_TRUE(getSnapshot({.id = 111})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // reparent and verify the child gets the new parent's framerate + reparentLayer(122, 11); + + std::vector expected = {1, 11, 111, 122, 1221, 12, 121, 13, 2}; + UPDATE_AND_VERIFY(mSnapshotBuilder, expected); + // verify parent is gets no vote + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type, + scheduler::LayerInfo::FrameRateCompatibility::NoVote); + + // verify layer and children get the requested votes + EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + + EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + + EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // reparent and verify the new parent gets no vote + reparentLayer(11, 2); + expected = {1, 12, 121, 13, 2, 11, 111, 122, 1221}; + UPDATE_AND_VERIFY(mSnapshotBuilder, expected); + + // verify old parent has invalid framerate (default) + EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // verify new parent get no vote + EXPECT_FALSE(getSnapshot({.id = 2})->frameRate.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 2})->frameRate.type, + scheduler::LayerInfo::FrameRateCompatibility::NoVote); + EXPECT_TRUE(getSnapshot({.id = 2})->changes.test(RequestedLayerState::Changes::FrameRate)); + + // verify layer and children get the requested votes (unchanged) + EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + + EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); + + EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.rate.isValid()); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.rate.getValue(), 244.f); + EXPECT_EQ(getSnapshot({.id = 122})->frameRate.type, + scheduler::LayerInfo::FrameRateCompatibility::Default); +} + } // namespace android::surfaceflinger::frontend -- GitLab From 41bf7c63078d8fce42ff2484359e859c89b56d6d Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 20 Jul 2023 10:33:06 -0700 Subject: [PATCH 0317/1187] SF: fix a bug when render frame rate range is lower then supported Ideally DisplayManager should know what is the min supported frame rate that SF allows, and send the policy accordingly. This is a more elaborate fix that will be coming as part of b/292105422. For now we fix it in SF by just ignoring the render frame rate when we can't find any frame rate that is allowed by the policy. Bug: 292047939 Bug: 291172084 Test: atest android.graphics.cts.FrameRateOverrideTest Change-Id: Id053a07eec2525ecbe1156ad46f649956a06a03b --- .../Scheduler/RefreshRateSelector.cpp | 15 ++++++++++++--- .../tests/unittests/RefreshRateSelectorTest.cpp | 15 +++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index 7951c33d79..2529095f99 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -1223,10 +1223,19 @@ void RefreshRateSelector::constructAvailableRefreshRates() { (supportsFrameRateOverride() || ranges.render.includes(mode.getFps())); }; - const auto frameRateModes = createFrameRateModes(filterModes, ranges.render); + auto frameRateModes = createFrameRateModes(filterModes, ranges.render); + if (frameRateModes.empty()) { + ALOGW("No matching frame rate modes for %s range. policy: %s", rangeName, + policy->toString().c_str()); + // TODO(b/292105422): Ideally DisplayManager should not send render ranges smaller than + // the min supported. See b/292047939. + // For not we just ignore the render ranges. + frameRateModes = createFrameRateModes(filterModes, {}); + } LOG_ALWAYS_FATAL_IF(frameRateModes.empty(), - "No matching frame rate modes for %s range. policy: %s", rangeName, - policy->toString().c_str()); + "No matching frame rate modes for %s range even after ignoring the " + "render range. policy: %s", + rangeName, policy->toString().c_str()); const auto stringifyModes = [&] { std::string str; diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index d63e187ac4..646d9cc0a0 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -3042,5 +3042,20 @@ TEST_P(RefreshRateSelectorTest, frameRateNotInRange) { EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode); } +TEST_P(RefreshRateSelectorTest, frameRateIsLowerThanMinSupported) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + auto selector = createSelector(kModes_60_90, kModeId60); + + constexpr Fps kMin = RefreshRateSelector::kMinSupportedFrameRate; + constexpr FpsRanges kLowerThanMin = {{60_Hz, 90_Hz}, {kMin / 2, kMin / 2}}; + + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy( + {DisplayModeId(kModeId60), kLowerThanMin, kLowerThanMin})); +} + } // namespace } // namespace android::scheduler -- GitLab From 24f862dd5c645e203bc64531d5ec31db8b4acc1b Mon Sep 17 00:00:00 2001 From: Pontus Lidman Date: Fri, 7 May 2021 21:21:31 -0700 Subject: [PATCH 0318/1187] SensorFusion: don't use wake sensors for fusion - Avoid using wake sensors for fusion as the fused sensor isn't wake up and it causes a lot of load on the system to keep wake locks. Bug: 270230642 Bug: 290816762 Test: local build and using maps app Change-Id: I17159f55f0d32bda3c15b56412b6d93808e1c436 (cherry picked from commit 8af03c922eb53fc3d8711cb304bb0b128f6d48ae) (cherry picked from commit fc6db32061be72c9dc95c293ac1e07c96ea62e18) --- services/sensorservice/SensorFusion.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp index e27b52b23e..c3f38d9838 100644 --- a/services/sensorservice/SensorFusion.cpp +++ b/services/sensorservice/SensorFusion.cpp @@ -41,17 +41,20 @@ SensorFusion::SensorFusion() if (count > 0) { for (size_t i=0 ; i Date: Tue, 18 Jul 2023 21:37:41 +0000 Subject: [PATCH 0319/1187] [sf] enable new sf frontend Change-Id: Ia2b8d200cd9b8acbab6899e6f282ca6aa876e2d5 Test: presubmit Test: atest android.graphics.cts.FrameRateOverrideTest Bug: 238781169 --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a9a1d80830..6df7bc0722 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -487,7 +487,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false); mLayerLifecycleManagerEnabled = - base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false); + base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, true); mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled || base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); } -- GitLab From 955b6137114012c7b70c88f07de08410c539a7fa Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 14 Jul 2023 19:44:34 +0000 Subject: [PATCH 0320/1187] EventHub: Dump tracked EV_KEY, EV_SW, and EV_ABS states Dump the pressed keys and switches, and the current value of all axes to ensure EventHub is tracking the input device state correctly. Bug: 290938220 Bug: 261025260 Test: manual, adb shell dumpsys input Change-Id: I443692cfddcd3a2f19576076cde3b8a35a4c4a40 --- services/inputflinger/reader/EventHub.cpp | 25 +++++++++++++++++++ .../inputflinger/reader/include/EventHub.h | 18 ++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 9a1273301b..bc4cdd1192 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -2863,6 +2863,31 @@ void EventHub::dump(std::string& dump) const { device->associatedDevice ? device->associatedDevice->sysfsRootPath.c_str() : ""); + if (device->keyBitmask.any(0, KEY_MAX + 1)) { + const auto pressedKeys = device->keyState.dumpSetIndices(", ", [](int i) { + return InputEventLookup::getLinuxEvdevLabel(EV_KEY, i, 1).code; + }); + dump += StringPrintf(INDENT3 "KeyState (pressed): %s\n", pressedKeys.c_str()); + } + if (device->swBitmask.any(0, SW_MAX + 1)) { + const auto pressedSwitches = device->swState.dumpSetIndices(", ", [](int i) { + return InputEventLookup::getLinuxEvdevLabel(EV_SW, i, 1).code; + }); + dump += StringPrintf(INDENT3 "SwState (pressed): %s\n", pressedSwitches.c_str()); + } + if (!device->absState.empty()) { + std::string axisValues; + for (const auto& [axis, state] : device->absState) { + if (!axisValues.empty()) { + axisValues += ", "; + } + axisValues += StringPrintf("%s=%d", + InputEventLookup::getLinuxEvdevLabel(EV_ABS, axis, 0) + .code.c_str(), + state.value); + } + dump += INDENT3 "AbsState: " + axisValues + "\n"; + } } dump += INDENT "Unattached video devices:\n"; diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 09c5e947d8..8347df8bdc 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -469,6 +471,20 @@ public: mData[i] = std::bitset(buffer[i]); } } + /* Dump the indices in the bit array that are set. */ + inline std::string dumpSetIndices(std::string separator, + std::function format) { + std::string dmp; + for (size_t i = 0; i < BITS; i++) { + if (test(i)) { + if (!dmp.empty()) { + dmp += separator; + } + dmp += format(i); + } + } + return dmp.empty() ? "" : dmp; + } private: std::array, COUNT> mData; @@ -624,7 +640,7 @@ private: RawAbsoluteAxisInfo info; int value; }; - std::unordered_map absState; + std::map absState; std::string configurationFile; std::unique_ptr configuration; -- GitLab From f44ab48b78109f876671532ca390bfa34a12e78d Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 20 Jul 2023 20:46:09 +0000 Subject: [PATCH 0321/1187] EventHub: Ensure bit arrays are large enough to store all event codes We were previously initializing bit arrays with a min size equaling to the MAX value for the event type (i.e. initialize array of min size KEY_MAX for EV_KEY). This is incorrect, because the max value could be a possible valid value, in which case it could not be stored in the array. The bit arrays should be initialzed with the min size equaling the count of the values (CNT == MAX + 1; e.g. KEY_CNT). Bug: 290938220 Test: None Change-Id: I1fa748f521a8539da444a4ae6e31cc4fb49be138 --- .../inputflinger/reader/include/EventHub.h | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 8347df8bdc..0bcab42417 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -626,16 +626,16 @@ private: ftl::Flags classes; - BitArray keyBitmask; - BitArray keyState; - BitArray relBitmask; - BitArray swBitmask; - BitArray swState; - BitArray ledBitmask; - BitArray ffBitmask; - BitArray propBitmask; - BitArray mscBitmask; - BitArray absBitmask; + BitArray keyBitmask; + BitArray keyState; + BitArray relBitmask; + BitArray swBitmask; + BitArray swState; + BitArray ledBitmask; + BitArray ffBitmask; + BitArray propBitmask; + BitArray mscBitmask; + BitArray absBitmask; struct AxisState { RawAbsoluteAxisInfo info; int value; -- GitLab From c41de37b6bda6c8f2e3951af0a1a3266774d0cc6 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 20 Jul 2023 13:14:26 -0700 Subject: [PATCH 0322/1187] Remove setInputWindows API This API has been replaced by onWindowInfosChanged. Fixes: 198444055 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Test: m checkinput Change-Id: Id1b311b122b94b843ad17e683b70b665fcd341ce --- .../benchmarks/InputDispatcher_benchmarks.cpp | 4 +- .../dispatcher/InputDispatcher.cpp | 13 - .../inputflinger/dispatcher/InputDispatcher.h | 3 - .../include/InputDispatcherInterface.h | 8 - .../tests/InputDispatcher_test.cpp | 555 +++++++++++------- 5 files changed, 330 insertions(+), 253 deletions(-) diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index 7a410831f6..6dd785ae56 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -268,7 +268,7 @@ static void benchmarkNotifyMotion(benchmark::State& state) { sp window = sp::make(application, dispatcher, "Fake Window"); - dispatcher.setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + dispatcher.onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); NotifyMotionArgs motionArgs = generateMotionArgs(); @@ -303,7 +303,7 @@ static void benchmarkInjectMotion(benchmark::State& state) { sp window = sp::make(application, dispatcher, "Fake Window"); - dispatcher.setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + dispatcher.onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); for (auto _ : state) { MotionEvent event = generateMotionEvent(); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 619ecdc773..c80cf4c4ae 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -5057,19 +5057,6 @@ void InputDispatcher::updateWindowHandlesForDisplayLocked( mWindowHandlesByDisplay[displayId] = newHandles; } -void InputDispatcher::setInputWindows( - const std::unordered_map>>& handlesPerDisplay) { - // TODO(b/198444055): Remove setInputWindows from InputDispatcher. - { // acquire lock - std::scoped_lock _l(mLock); - for (const auto& [displayId, handles] : handlesPerDisplay) { - setInputWindowsLocked(handles, displayId); - } - } - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); -} - /** * Called from InputManagerService, update window handle list by displayId that can receive input. * A window handle contains information about InputChannel, Touch Region, Types, Focused,... diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 909c683d1b..fef726fc30 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -109,9 +109,6 @@ public: std::unique_ptr verifyInputEvent(const InputEvent& event) override; - void setInputWindows( - const std::unordered_map>>& - handlesPerDisplay) override; void setFocusedApplication( int32_t displayId, const std::shared_ptr& inputApplicationHandle) override; diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index 4ddfee039c..d099b44d91 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -87,14 +87,6 @@ public: */ virtual std::unique_ptr verifyInputEvent(const InputEvent& event) = 0; - /* Sets the list of input windows per display. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setInputWindows( - const std::unordered_map>>& - handlesPerDisplay) = 0; - /* Sets the focused application on the given display. * * This method may be called on any thread (usually by the input manager). diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index de6bd149c7..bc87c8e7df 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -861,7 +861,6 @@ TEST_F(InputDispatcherTest, NotifySwitch_CallsPolicy) { namespace { -// --- InputDispatcherTest SetInputWindowTest --- static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 500ms; // Default input dispatching timeout if there is no focused application or paused window // from which to determine an appropriate dispatching timeout. @@ -1621,7 +1620,7 @@ TEST_F(InputDispatcherTest, WhenInputChannelBreaks_PolicyIsNotified) { sp::make(application, mDispatcher, "Window that breaks its input channel", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // Window closes its channel, but the window remains. window->destroyReceiver(); @@ -1633,7 +1632,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) { sp window = sp::make(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1647,7 +1646,7 @@ TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay sp window = sp::make(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // Inject a MotionEvent to an unknown display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_NONE)) @@ -1658,8 +1657,8 @@ TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay } /** - * Calling setInputWindows once should not cause any issues. - * This test serves as a sanity check for the next test, where setInputWindows is + * Calling onWindowInfosChanged once should not cause any issues. + * This test serves as a sanity check for the next test, where onWindowInfosChanged is * called twice. */ TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) { @@ -1668,7 +1667,7 @@ TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) { "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) @@ -1679,7 +1678,7 @@ TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) { } /** - * Calling setInputWindows twice, with the same info, should not cause any issues. + * Calling onWindowInfosChanged twice, with the same info, should not cause any issues. */ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { std::shared_ptr application = std::make_shared(); @@ -1687,8 +1686,8 @@ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { "Fake Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) @@ -1706,7 +1705,8 @@ TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) { sp windowSecond = sp::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}}); + mDispatcher->onWindowInfosChanged( + {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1732,7 +1732,8 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance sp::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) @@ -1751,7 +1752,7 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance wallpaperWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); // Now the foreground window goes away, but the wallpaper stays - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wallpaperWindow}}}); + mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0}); foregroundWindow->consumeMotionCancel(); // Since the "parent" window of the wallpaper is gone, wallpaper should receive cancel, too. wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); @@ -1767,7 +1768,7 @@ TEST_F(InputDispatcherTest, CancelAfterPointer0Up) { sp window = sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // First touch pointer down on right window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) @@ -1787,7 +1788,7 @@ TEST_F(InputDispatcherTest, CancelAfterPointer0Up) { window->consumeMotionEvent(WithMotionAction(POINTER_0_UP)); // Remove the window. The gesture should be canceled - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {}}}); + mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); const std::map expectedPointers{{1, PointF{110, 100}}}; window->consumeMotionEvent( AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedPointers))); @@ -1810,7 +1811,8 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { sp::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) @@ -1834,7 +1836,7 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { // Now the foreground window goes away, but the wallpaper stays, even though its channel // is no longer valid. - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wallpaperWindow}}}); + mDispatcher->onWindowInfosChanged({{*wallpaperWindow->getInfo()}, {}, 0, 0}); foregroundWindow->consumeMotionCancel(); } @@ -1858,7 +1860,8 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { sp::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); // Touch down on top window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1941,8 +1944,11 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { wallpaperWindow->setFrame(Rect(0, 0, 400, 200)); wallpaperWindow->setIsWallpaper(true); - mDispatcher->setInputWindows( - {{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow, wallpaperWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()}, + {}, + 0, + 0}); // Touch down on left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -1973,7 +1979,8 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { expectedWallpaperFlags); // Now, leftWindow, which received the first finger, disappears. - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {rightWindow, wallpaperWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*rightWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); leftWindow->consumeMotionCancel(); // Since a "parent" window of the wallpaper is gone, wallpaper should receive cancel, too. wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); @@ -2017,8 +2024,11 @@ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) { sp::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); - mDispatcher->setInputWindows( - {{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow, wallpaperWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*leftWindow->getInfo(), *rightWindow->getInfo(), *wallpaperWindow->getInfo()}, + {}, + 0, + 0}); // Touch down on left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -2069,7 +2079,7 @@ TEST_F(InputDispatcherTest, TwoPointerCancelInconsistentPolicy) { sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 200, 200)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, window}}}); + mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); const int32_t touchDeviceId = 4; // Two pointers down @@ -2142,7 +2152,8 @@ TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) { sp::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); rightWindow->setFrame(Rect(200, 0, 400, 200)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); // All times need to start at the current time, otherwise the dispatcher will drop the events as // stale. const nsecs_t baseTime = systemTime(SYSTEM_TIME_MONOTONIC); @@ -2254,7 +2265,7 @@ TEST_F(InputDispatcherTest, HoverWhileWindowAppears) { window->setFrame(Rect(0, 0, 200, 200)); // Only a single window is present at first - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // Start hovering in the window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) @@ -2273,7 +2284,8 @@ TEST_F(InputDispatcherTest, HoverWhileWindowAppears) { obscuringWindow->setNoInputChannel(true); obscuringWindow->setFocusable(false); obscuringWindow->setAlpha(1.0); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); + mDispatcher->onWindowInfosChanged( + {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); // While this new obscuring window is present, the hovering is stopped mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_EXIT, AINPUT_SOURCE_STYLUS) @@ -2282,7 +2294,7 @@ TEST_F(InputDispatcherTest, HoverWhileWindowAppears) { window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); // Now the obscuring window goes away. - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // And a new hover gesture starts. mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) @@ -2302,7 +2314,7 @@ TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) { window->setFrame(Rect(0, 0, 200, 200)); // Only a single window is present at first - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // Start hovering in the window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) @@ -2321,7 +2333,8 @@ TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) { obscuringWindow->setNoInputChannel(true); obscuringWindow->setFocusable(false); obscuringWindow->setAlpha(1.0); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); + mDispatcher->onWindowInfosChanged( + {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); // While this new obscuring window is present, the hovering continues. The event can't go to the // bottom window due to obstructed touches, so it should generate HOVER_EXIT for that window. @@ -2332,7 +2345,7 @@ TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) { window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_EXIT)); // Now the obscuring window goes away. - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // Hovering continues in the same position. The hovering pointer re-enters the bottom window, // so it should generate a HOVER_ENTER @@ -2365,7 +2378,8 @@ TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { sp::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); rightWindow->setFrame(Rect(200, 0, 400, 200)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); const int32_t touchDeviceId = 4; const int32_t mouseDeviceId = 6; @@ -2440,7 +2454,7 @@ TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 400, 400)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); const int32_t touchDeviceId = 4; const int32_t mouseDeviceId = 6; @@ -2506,7 +2520,7 @@ TEST_F(InputDispatcherTest, UnfinishedInjectedEvent) { sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 400, 400)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); const int32_t touchDeviceId = 4; // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after @@ -2558,7 +2572,8 @@ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { sp::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); rightWindow->setFrame(Rect(200, 0, 400, 200)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); const int32_t mouseDeviceId = 6; const int32_t touchDeviceId = 4; @@ -2641,7 +2656,7 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 200, 200)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); const int32_t stylusDeviceId = 5; const int32_t touchDeviceId = 4; @@ -2723,7 +2738,7 @@ TEST_F(InputDispatcherTest, StylusHoverAndDownNoInputChannel) { window->setNoInputChannel(true); window->setFrame(Rect(0, 0, 200, 200)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, window}}}); + mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); // Start hovering with stylus mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) @@ -2781,7 +2796,7 @@ TEST_F(InputDispatcherTest, TouchPilferAndMouseMove) { sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 200, 200)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, window}}}); + mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); const int32_t mouseDeviceId = 7; const int32_t touchDeviceId = 4; @@ -2876,7 +2891,7 @@ TEST_F(InputDispatcherTest, SplitWorksWhenEmptyAreaIsTouched) { sp window = sp::make(application, mDispatcher, "Window", DISPLAY_ID); - mDispatcher->setInputWindows({{DISPLAY_ID, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // Touch down on the empty space mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{-1, -1}})); @@ -2904,7 +2919,7 @@ TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) { sp::make(application, mDispatcher, "Window2", DISPLAY_ID); window2->setTouchableRegion(Region{{100, 0, 200, 100}}); - mDispatcher->setInputWindows({{DISPLAY_ID, {window1, window2}}}); + mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0}); // Touch down on the non-touchable window mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}})); @@ -2932,7 +2947,7 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) { sp::make(application, mDispatcher, "Window2", DISPLAY_ID); window2->setTouchableRegion(Region{{100, 0, 200, 100}}); - mDispatcher->setInputWindows({{DISPLAY_ID, {window1, window2}}}); + mDispatcher->onWindowInfosChanged({{*window1->getInfo(), *window2->getInfo()}, {}, 0, 0}); // Touch down on the first window mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}})); @@ -2992,7 +3007,8 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowLeft, windowRight}}}); + mDispatcher->onWindowInfosChanged( + {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0}); // Start cursor position in right window so that we can move the cursor to left window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -3076,7 +3092,7 @@ TEST_F(InputDispatcherTest, TwoPointersDownMouseClick) { sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 600, 800)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); const int32_t touchDeviceId = 4; const int32_t mouseDeviceId = 6; @@ -3137,7 +3153,7 @@ TEST_F(InputDispatcherTest, HoverWithSpyWindows) { window->setFrame(Rect(0, 0, 600, 800)); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, window}}}); + mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); // Send mouse cursor to the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -3171,7 +3187,7 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { window->setFrame(Rect(0, 0, 600, 800)); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, window}}}); + mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); // Send mouse cursor to the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -3286,7 +3302,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, @@ -3356,7 +3372,7 @@ TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) { mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, @@ -3369,7 +3385,7 @@ TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) { window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // Remove the window, but keep the channel. - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {}}}); + mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); } @@ -3382,7 +3398,7 @@ TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) { sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); const int32_t mouseDeviceId = 7; const int32_t touchDeviceId = 4; @@ -3417,7 +3433,7 @@ TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) { sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 100, 100)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // Inject a hover_move from mouse. NotifyMotionArgs motionArgs = @@ -3460,8 +3476,8 @@ TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) { SECOND_DISPLAY_ID); windowSecondDisplay->setFrame(Rect(0, 0, 600, 800)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowDefaultDisplay}}, - {SECOND_DISPLAY_ID, {windowSecondDisplay}}}); + mDispatcher->onWindowInfosChanged( + {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0}); // Set cursor position in window in default display and check that hover enter and move // events are generated. @@ -3478,14 +3494,14 @@ TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) { // Remove all windows in secondary display and check that no event happens on window in // primary display. - mDispatcher->setInputWindows( - {{ADISPLAY_ID_DEFAULT, {windowDefaultDisplay}}, {SECOND_DISPLAY_ID, {}}}); + mDispatcher->onWindowInfosChanged({{*windowDefaultDisplay->getInfo()}, {}, 0, 0}); + windowDefaultDisplay->assertNoEvents(); // Move cursor position in window in default display and check that only hover move // event is generated and not hover enter event. - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowDefaultDisplay}}, - {SECOND_DISPLAY_ID, {windowSecondDisplay}}}); + mDispatcher->onWindowInfosChanged( + {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, @@ -3513,7 +3529,8 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowLeft, windowRight}}}); + mDispatcher->onWindowInfosChanged( + {{*windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0}); // Inject an event with coordinate in the area of right window, with mouse cursor in the area of // left window. This event should be dispatched to the left window. @@ -3530,7 +3547,7 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsKeyStream) { "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(true); @@ -3552,7 +3569,7 @@ TEST_F(InputDispatcherTest, NotifyDeviceReset_CancelsMotionStream) { sp window = sp::make(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); @@ -3572,7 +3589,7 @@ TEST_F(InputDispatcherTest, NotifyDeviceResetCancelsHoveringStream) { sp window = sp::make(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(10)) @@ -3597,7 +3614,7 @@ TEST_F(InputDispatcherTest, InterceptKeyByPolicy) { "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(true); @@ -3622,7 +3639,7 @@ TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) { "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(true); @@ -3657,7 +3674,7 @@ TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinates) { outsideWindow->setFrame(Rect{100, 100, 200, 200}); outsideWindow->setWatchOutsideTouch(true); // outsideWindow must be above 'window' to receive ACTION_OUTSIDE events when 'window' is tapped - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {outsideWindow, window}}}); + mDispatcher->onWindowInfosChanged({{*outsideWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); // Tap on first window. mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, @@ -3690,7 +3707,8 @@ TEST_F(InputDispatcherTest, ActionOutsideSentOnlyWhenAWindowIsTouched) { sp::make(application, mDispatcher, "Third Window", ADISPLAY_ID_DEFAULT); thirdWindow->setFrame(Rect{200, 200, 300, 300}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, secondWindow, thirdWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*window->getInfo(), *secondWindow->getInfo(), *thirdWindow->getInfo()}, {}, 0, 0}); // First pointer lands outside all windows. `window` does not get ACTION_OUTSIDE. mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, @@ -3833,7 +3851,7 @@ TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) { trustedOverlay->setSpy(true); trustedOverlay->setTrustedOverlay(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {trustedOverlay, window}}}); + mDispatcher->onWindowInfosChanged({{*trustedOverlay->getInfo(), *window->getInfo()}, {}, 0, 0}); // Start a three-finger touchpad swipe mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) @@ -3895,7 +3913,7 @@ TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) { sp window = sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect(0, 0, 400, 400)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // Start a three-finger touchpad swipe mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) @@ -4242,7 +4260,8 @@ TEST_P(TransferTouchFixture, TransferTouch_OnePointer) { sp::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaper->setIsWallpaper(true); // Add the windows to the dispatcher - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow, wallpaper}}}); + mDispatcher->onWindowInfosChanged( + {{*firstWindow->getInfo(), *secondWindow->getInfo(), *wallpaper->getInfo()}, {}, 0, 0}); // Send down to the first window mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, @@ -4297,7 +4316,8 @@ TEST_P(TransferTouchFixture, TransferTouch_MultipleWindowsWithSpy) { sp::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); // Add the windows to the dispatcher - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyWindow, firstWindow, secondWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*spyWindow->getInfo(), *firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0}); // Send down to the first window mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, @@ -4340,7 +4360,8 @@ TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) { secondWindow->setPreventSplitting(true); // Add the windows to the dispatcher - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0}); // Send down to the first window mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, @@ -4402,8 +4423,11 @@ TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) { sp::make(application, mDispatcher, "Wallpaper2", ADISPLAY_ID_DEFAULT); wallpaper2->setIsWallpaper(true); // Add the windows to the dispatcher - mDispatcher->setInputWindows( - {{ADISPLAY_ID_DEFAULT, {firstWindow, wallpaper1, secondWindow, wallpaper2}}}); + mDispatcher->onWindowInfosChanged({{*firstWindow->getInfo(), *wallpaper1->getInfo(), + *secondWindow->getInfo(), *wallpaper2->getInfo()}, + {}, + 0, + 0}); // Send down to the first window mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, @@ -4466,7 +4490,8 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) { secondWindow->setFrame(Rect(0, 400, 600, 800)); // Add the windows to the dispatcher - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0}); PointF pointInFirst = {300, 200}; PointF pointInSecond = {300, 600}; @@ -4527,7 +4552,8 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) { secondWindow->setFrame(Rect(0, 400, 600, 800)); // Add the windows to the dispatcher - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0}); PointF pointInFirst = {300, 200}; PointF pointInSecond = {300, 600}; @@ -4595,10 +4621,13 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); // Update window info, let it find window handle of second display first. - mDispatcher->setInputWindows( - {{SECOND_DISPLAY_ID, {firstWindowInSecondary, secondWindowInSecondary}}, - {ADISPLAY_ID_DEFAULT, - {mirrorWindowInPrimary, firstWindowInPrimary, secondWindowInPrimary}}}); + mDispatcher->onWindowInfosChanged( + {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(), + *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(), + *secondWindowInPrimary->getInfo()}, + {}, + 0, + 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, @@ -4651,10 +4680,13 @@ TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { secondWindowInPrimary->setFrame(Rect(100, 0, 200, 100)); // Update window info, let it find window handle of second display first. - mDispatcher->setInputWindows( - {{SECOND_DISPLAY_ID, {firstWindowInSecondary, secondWindowInSecondary}}, - {ADISPLAY_ID_DEFAULT, - {mirrorWindowInPrimary, firstWindowInPrimary, secondWindowInPrimary}}}); + mDispatcher->onWindowInfosChanged( + {{*firstWindowInSecondary->getInfo(), *secondWindowInSecondary->getInfo(), + *mirrorWindowInPrimary->getInfo(), *firstWindowInPrimary->getInfo(), + *secondWindowInPrimary->getInfo()}, + {}, + 0, + 0}); // Touch on second display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -4691,7 +4723,7 @@ TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) { "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(true); @@ -4713,7 +4745,7 @@ TEST_F(InputDispatcherTest, FocusedWindow_DisableUserActivity) { window->setDisableUserActivity(true); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(true); @@ -4734,7 +4766,7 @@ TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveSystemShortcut) { "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(true); @@ -4755,7 +4787,7 @@ TEST_F(InputDispatcherTest, FocusedWindow_DoesNotReceiveAssistantKey) { "Fake Window", ADISPLAY_ID_DEFAULT); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(true); @@ -4777,7 +4809,7 @@ TEST_F(InputDispatcherTest, FocusedWindow_SystemKeyIgnoresDisableUserActivity) { window->setDisableUserActivity(true); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(true); @@ -4797,7 +4829,7 @@ TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) { sp window = sp::make(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, @@ -4817,7 +4849,7 @@ TEST_F(InputDispatcherTest, UnfocusedWindow_DoesNotReceiveFocusEventOrKeyEvent) sp window = sp::make(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); mDispatcher->waitForIdle(); @@ -4831,7 +4863,7 @@ TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) { sp window = sp::make(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // Send key mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT)); @@ -4858,7 +4890,8 @@ TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) { secondWindow->setFrame(Rect(0, 400, 600, 800)); // Add the windows to the dispatcher - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*firstWindow->getInfo(), *secondWindow->getInfo()}, {}, 0, 0}); PointF pointInFirst = {300, 200}; PointF pointInSecond = {300, 600}; @@ -4902,7 +4935,7 @@ TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) { sp window = sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); std::array graphicsTimeline; graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2; graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3; @@ -4997,7 +5030,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDis FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) @@ -5016,7 +5049,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDis monitor.consumeMotionMove(ADISPLAY_ID_DEFAULT); // Now the foreground window goes away - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {}}}); + mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); window->consumeMotionCancel(); monitor.assertNoEvents(); // Global monitor does not get a cancel yet @@ -5035,7 +5068,7 @@ TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) { std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); @@ -5052,7 +5085,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) { std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) @@ -5077,7 +5110,7 @@ TEST_F(InputDispatcherMonitorTest, NoWindowTransform) { std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); window->setWindowOffset(20, 40); window->setWindowTransform(0, 1, -1, 0); @@ -5107,7 +5140,7 @@ TEST_F(InputDispatcherTest, TestMoveEvent) { sp window = sp::make(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); NotifyMotionArgs motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, @@ -5144,13 +5177,13 @@ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) { window->setFocusable(true); SCOPED_TRACE("Check default value of touch mode"); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); SCOPED_TRACE("Remove the window to trigger focus loss"); window->setFocusable(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/true); SCOPED_TRACE("Disable touch mode"); @@ -5158,13 +5191,13 @@ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) { /*hasPermission=*/true, ADISPLAY_ID_DEFAULT); window->consumeTouchModeEvent(false); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/false); SCOPED_TRACE("Remove the window to trigger focus loss"); window->setFocusable(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); window->consumeFocusEvent(/*hasFocus=*/false, /*inTouchMode=*/false); SCOPED_TRACE("Enable touch mode again"); @@ -5172,7 +5205,7 @@ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) { /*hasPermission=*/true, ADISPLAY_ID_DEFAULT); window->consumeTouchModeEvent(true); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); @@ -5187,7 +5220,7 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); @@ -5333,7 +5366,8 @@ TEST_F(InputDispatcherTest, SetFocusedWindow) { // Top window is also focusable but is not granted focus. windowTop->setFocusable(true); windowSecond->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}}); + mDispatcher->onWindowInfosChanged( + {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0}); setFocusedWindow(windowSecond); windowSecond->consumeFocusEvent(true); @@ -5354,7 +5388,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) { window->setFocusable(true); // Release channel for window is no longer valid. window->releaseChannel(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); // Test inject a key down, should timeout. @@ -5372,7 +5406,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) { window->setFocusable(false); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); // Test inject a key down, should timeout. @@ -5393,12 +5427,14 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) { windowTop->setFocusable(true); windowSecond->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}}); + mDispatcher->onWindowInfosChanged( + {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0}); setFocusedWindow(windowTop); windowTop->consumeFocusEvent(true); windowTop->editInfo()->focusTransferTarget = windowSecond->getToken(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}}); + mDispatcher->onWindowInfosChanged( + {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0}); windowSecond->consumeFocusEvent(true); windowTop->consumeFocusEvent(false); @@ -5420,7 +5456,8 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) { windowTop->setFocusable(true); windowSecond->setFocusable(false); windowTop->editInfo()->focusTransferTarget = windowSecond->getToken(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}}); + mDispatcher->onWindowInfosChanged( + {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0}); setFocusedWindow(windowTop); windowTop->consumeFocusEvent(true); @@ -5444,7 +5481,8 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) { window->setFocusable(true); previousFocusedWindow->setFocusable(true); window->setVisible(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, previousFocusedWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*window->getInfo(), *previousFocusedWindow->getInfo()}, {}, 0, 0}); setFocusedWindow(previousFocusedWindow); previousFocusedWindow->consumeFocusEvent(true); @@ -5462,7 +5500,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) { // Window becomes visible. window->setVisible(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // Window receives focus event. window->consumeFocusEvent(true); @@ -5478,7 +5516,7 @@ TEST_F(InputDispatcherTest, DisplayRemoved) { // window is granted focus. window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(true); @@ -5530,8 +5568,8 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { sp::make(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT); slipperyExitWindow->setFrame(Rect(0, 0, 100, 100)); - mDispatcher->setInputWindows( - {{ADISPLAY_ID_DEFAULT, {slipperyExitWindow, slipperyEnterWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0}); // Use notifyMotion instead of injecting to avoid dealing with injection permissions mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, @@ -5539,8 +5577,8 @@ TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) { {{50, 50}})); slipperyExitWindow->consumeMotionDown(); slipperyExitWindow->setFrame(Rect(70, 70, 100, 100)); - mDispatcher->setInputWindows( - {{ADISPLAY_ID_DEFAULT, {slipperyExitWindow, slipperyEnterWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*slipperyExitWindow->getInfo(), *slipperyEnterWindow->getInfo()}, {}, 0, 0}); mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, @@ -5572,8 +5610,8 @@ TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) { rightDropTouchesWindow->setFrame(Rect(100, 0, 200, 100)); rightDropTouchesWindow->setDropInput(true); - mDispatcher->setInputWindows( - {{ADISPLAY_ID_DEFAULT, {leftSlipperyWindow, rightDropTouchesWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*leftSlipperyWindow->getInfo(), *rightDropTouchesWindow->getInfo()}, {}, 0, 0}); // Start touch in the left window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) @@ -5613,7 +5651,8 @@ TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) { rightWindow->setFrame(Rect(100, 0, 200, 100)); rightWindow->setOwnerInfo(gui::Pid{3}, Uid{103}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {rightSpy, rightWindow, leftWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*rightSpy->getInfo(), *rightWindow->getInfo(), *leftWindow->getInfo()}, {}, 0, 0}); // Touch in the left window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) @@ -5678,7 +5717,7 @@ TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithKeys) { window->setFrame(Rect(0, 0, 100, 100)); window->setOwnerInfo(gui::Pid{1}, gui::Uid{101}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); ASSERT_NO_FATAL_FAILURE(window->consumeFocusEvent(true)); @@ -5718,7 +5757,7 @@ protected: mWindow = sp::make(mApp, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); mWindow->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); setFocusedWindow(mWindow); mWindow->consumeFocusEvent(true); } @@ -5857,7 +5896,8 @@ public: // Set focus window for primary display, but focused display would be second one. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1); windowInPrimary->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowInPrimary}}}); + mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0}); + setFocusedWindow(windowInPrimary); windowInPrimary->consumeFocusEvent(true); @@ -5870,7 +5910,8 @@ public: // Set focus window for second display. mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2); windowInSecondary->setFocusable(true); - mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}}); + mDispatcher->onWindowInfosChanged( + {{*windowInPrimary->getInfo(), *windowInSecondary->getInfo()}, {}, 0, 0}); setFocusedWindow(windowInSecondary); windowInSecondary->consumeFocusEvent(true); } @@ -5922,7 +5963,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE); // Remove all windows in secondary display. - mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {}}}); + mDispatcher->onWindowInfosChanged({{*windowInPrimary->getInfo()}, {}, 0, 0}); // Old focus should receive a cancel event. windowInSecondary->consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_UP, ADISPLAY_ID_NONE, @@ -6001,7 +6042,12 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) sp secondWindowInPrimary = sp::make(application1, mDispatcher, "D_1_W2", ADISPLAY_ID_DEFAULT); secondWindowInPrimary->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowInPrimary, secondWindowInPrimary}}}); + mDispatcher->onWindowInfosChanged( + {{*windowInPrimary->getInfo(), *secondWindowInPrimary->getInfo(), + *windowInSecondary->getInfo()}, + {}, + 0, + 0}); setFocusedWindow(secondWindowInPrimary); windowInPrimary->consumeFocusEvent(false); secondWindowInPrimary->consumeFocusEvent(true); @@ -6173,7 +6219,7 @@ protected: mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); mWindow->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); setFocusedWindow(mWindow); mWindow->consumeFocusEvent(true); } @@ -6285,7 +6331,8 @@ class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest { mFocusedWindow->setFocusable(true); // Expect one focus window exist in display. - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0}); setFocusedWindow(mFocusedWindow); mFocusedWindow->consumeFocusEvent(true); } @@ -6391,7 +6438,7 @@ class InputDispatcherMultiWindowSameTokenTests : public InputDispatcherTest { ADISPLAY_ID_DEFAULT, mWindow1->getToken()); mWindow2->setFrame(Rect(100, 100, 200, 200)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}}); + mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); } protected: @@ -6460,6 +6507,7 @@ TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchSameScale) { TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentTransform) { // Set scale value for window2 mWindow2->setWindowScale(0.5f, 0.5f); + mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); // Touch Window 1 PointF touchedPoint = {10, 10}; @@ -6476,12 +6524,14 @@ TEST_F(InputDispatcherMultiWindowSameTokenTests, SingleTouchDifferentTransform) // Update the transform so rotation is set mWindow2->setWindowTransform(0, -1, 1, 0); + mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); expectedPoint = getPointInWindow(mWindow2->getInfo(), touchedPoint); touchAndAssertPositions(AMOTION_EVENT_ACTION_DOWN, {touchedPoint}, {expectedPoint}); } TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentTransform) { mWindow2->setWindowScale(0.5f, 0.5f); + mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); // Touch Window 1 std::vector touchedPoints = {PointF{10, 10}}; @@ -6499,12 +6549,14 @@ TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentTransform // Update the transform so rotation is set for Window 2 mWindow2->setWindowTransform(0, -1, 1, 0); + mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1])); touchAndAssertPositions(POINTER_1_DOWN, touchedPoints, expectedPoints); } TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTransform) { mWindow2->setWindowScale(0.5f, 0.5f); + mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); // Touch Window 1 std::vector touchedPoints = {PointF{10, 10}}; @@ -6530,6 +6582,7 @@ TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTrans // Touch Window 2 mWindow2->setWindowTransform(0, -1, 1, 0); + mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); expectedPoints.push_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1])); touchAndAssertPositions(POINTER_1_DOWN, touchedPoints, expectedPoints); @@ -6543,6 +6596,7 @@ TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentTrans TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithScale) { mWindow1->setWindowScale(0.5f, 0.5f); + mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); // Touch Window 1 std::vector touchedPoints = {PointF{10, 10}}; @@ -6569,7 +6623,7 @@ TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithSc */ TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) { mWindow1->setSlippery(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}}); + mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); // Touch down in window 1 mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, @@ -6591,7 +6645,7 @@ TEST_F(InputDispatcherMultiWindowSameTokenTests, TouchDoesNotSlipEvenIfSlippery) * that the pointer is hovering over may have a different transform. */ TEST_F(InputDispatcherMultiWindowSameTokenTests, HoverIntoClone) { - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow1, mWindow2}}}); + mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); // Start hover in window 1 mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN, @@ -6623,7 +6677,7 @@ class InputDispatcherSingleWindowAnr : public InputDispatcherTest { // Set focused application. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); setFocusedWindow(mWindow); mWindow->consumeFocusEvent(true); } @@ -6654,7 +6708,7 @@ protected: spy->setFocusable(false); spy->setSpy(true); spy->setDispatchingTimeout(30ms); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, mWindow}}}); + mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0}); return spy; } }; @@ -6678,7 +6732,7 @@ TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) { TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) { mWindow->setFocusable(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); mWindow->consumeFocusEvent(false); InputEventInjectionResult result = @@ -6731,7 +6785,7 @@ TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) { // We have a focused application, but no focused window TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) { mWindow->setFocusable(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); mWindow->consumeFocusEvent(false); // taps on the window work as normal @@ -6760,7 +6814,7 @@ TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) { */ TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) { mWindow->setFocusable(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); mWindow->consumeFocusEvent(false); KeyEvent event; @@ -6790,7 +6844,7 @@ TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) { // Make sure that we don't notify policy twice about the same ANR. TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) { mWindow->setFocusable(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); mWindow->consumeFocusEvent(false); // Once a focused event arrives, we get an ANR for this application @@ -6816,7 +6870,7 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) // We have a focused application, but no focused window TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) { mWindow->setFocusable(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); mWindow->consumeFocusEvent(false); // Once a focused event arrives, we get an ANR for this application @@ -7024,7 +7078,7 @@ TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) { */ TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) { mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); tapOnWindow(); std::optional downSequenceNum = mWindow->receiveEvent(); @@ -7062,7 +7116,7 @@ TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) { TEST_F(InputDispatcherSingleWindowAnr, PendingKey_IsDroppedWhileMotionIsProcessedAndNewTouchComesIn) { mWindow->setDispatchingTimeout(2s); // Set a long ANR timeout to prevent it from triggering - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); tapOnWindow(); std::optional downSequenceNum = mWindow->receiveEvent(); @@ -7160,7 +7214,8 @@ class InputDispatcherMultiWindowAnr : public InputDispatcherTest { mFocusedWindow->setFocusable(true); // Expect one focus window exist in display. - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0}); setFocusedWindow(mFocusedWindow); mFocusedWindow->consumeFocusEvent(true); } @@ -7240,7 +7295,8 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsiveWithSameTimeout // Set the timeout for unfocused window to match the focused window mUnfocusedWindow->setDispatchingTimeout( mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0}); tapOnFocusedWindow(); // we should have ACTION_DOWN/ACTION_UP on focused window and ACTION_OUTSIDE on unfocused window @@ -7323,7 +7379,8 @@ TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) { // Since the focused window is paused, tapping on it should not produce any events TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) { mFocusedWindow->setPaused(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mUnfocusedWindow, mFocusedWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::FAILED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, @@ -7354,7 +7411,8 @@ TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) { TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) { // Set a long ANR timeout to prevent it from triggering mFocusedWindow->setDispatchingTimeout(2s); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0}); tapOnUnfocusedWindow(); std::optional downSequenceNum = mUnfocusedWindow->receiveEvent(); @@ -7377,7 +7435,8 @@ TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) { // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there mFocusedWindow->setFocusable(false); mUnfocusedWindow->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0}); setFocusedWindow(mUnfocusedWindow); // Focus events should precede the key events @@ -7460,7 +7519,8 @@ TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_ // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused. mFocusedWindow->setFocusable(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0}); mFocusedWindow->consumeFocusEvent(false); // Send a key. The ANR timer should start because there is no focused window. @@ -7490,7 +7550,8 @@ TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_ // process (== drop) the key event, and by that time, ANR will be raised. // Set the focused window first. mFocusedWindow->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mFocusedWindow->getInfo(), *mUnfocusedWindow->getInfo()}, {}, 0, 0}); setFocusedWindow(mFocusedWindow); mFocusedWindow->consumeFocusEvent(true); // We do not call "setFocusedApplication" here, even though the newly focused window belongs @@ -7527,7 +7588,8 @@ class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest { ADISPLAY_ID_DEFAULT); mBottomWindow->setFrame(Rect(0, 0, 100, 100)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mNoInputWindow, mBottomWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0}); } protected: @@ -7562,7 +7624,8 @@ TEST_F(InputDispatcherMultiWindowOcclusionTests, mNoInputWindow->setNoInputChannel(true); mNoInputWindow->setFrame(Rect(0, 0, 100, 100)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mNoInputWindow, mBottomWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mNoInputWindow->getInfo(), *mBottomWindow->getInfo()}, {}, 0, 0}); PointF touchedPoint = {10, 10}; @@ -7589,7 +7652,7 @@ protected: mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); mWindow->setFocusable(true); mMirror->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mMirror}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); } }; @@ -7619,7 +7682,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) { mWindow->consumeKeyUp(ADISPLAY_ID_NONE); mMirror->setFocusable(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mMirror}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); // window loses focus since one of the windows associated with the token in not focusable mWindow->consumeFocusEvent(false); @@ -7644,7 +7707,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) { mWindow->consumeKeyUp(ADISPLAY_ID_NONE); mMirror->setVisible(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mMirror}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; @@ -7654,7 +7717,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) { mWindow->consumeKeyUp(ADISPLAY_ID_NONE); mWindow->setVisible(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mMirror}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); // window loses focus only after all windows associated with the token become invisible. mWindow->consumeFocusEvent(false); @@ -7678,7 +7741,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) { mWindow->consumeKeyUp(ADISPLAY_ID_NONE); // single window is removed but the window token remains focused - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mMirror}}}); + mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; @@ -7688,7 +7751,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) { mWindow->consumeKeyUp(ADISPLAY_ID_NONE); // Both windows are removed - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {}}}); + mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); mWindow->consumeFocusEvent(false); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) @@ -7701,7 +7764,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) { // Request focus on an invisible mirror. mWindow->setVisible(false); mMirror->setVisible(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mMirror}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); setFocusedWindow(mMirror); // Injected key goes to pending queue. @@ -7710,7 +7773,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) { InputEventInjectionSync::NONE)); mMirror->setVisible(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mMirror}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); // window gets focused mWindow->consumeFocusEvent(true); @@ -7734,7 +7797,8 @@ protected: mSecondWindow->setFocusable(true); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0}); setFocusedWindow(mWindow); mWindow->consumeFocusEvent(true); @@ -7926,7 +7990,7 @@ protected: TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_BlocksTouch) { const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -7937,7 +8001,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionModeWithOpacityBelowThreshold_BlocksTouch) { const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.7f); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -7948,7 +8012,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithBlockUntrustedOcclusionMode_DoesNotReceiveTouch) { const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -7957,7 +8021,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithAllowOcclusionMode_AllowsTouch) { const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::ALLOW); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -7968,7 +8032,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTo const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED); w->setFrame(Rect(0, 0, 50, 50)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch({PointF{100, 100}}); @@ -7978,7 +8042,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, TouchOutsideOccludingWindow_AllowsTo TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) { const sp& w = getOccludingWindow(TOUCHED_APP_UID, "A", TouchOcclusionMode::BLOCK_UNTRUSTED); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -7988,7 +8052,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowFromSameUid_AllowsTouch) { TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) { const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -7998,7 +8062,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_AllowsTouch) { TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithZeroOpacity_DoesNotReceiveTouch) { const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8015,7 +8079,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); w->setWatchOutsideTouch(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8026,7 +8090,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, OutsideEvent_HasZeroCoordinates) { const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED, 0.0f); w->setWatchOutsideTouch(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8037,7 +8101,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityBelowThreshold_Allo const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, OPACITY_BELOW_THRESHOLD); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8048,7 +8112,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAtThreshold_AllowsT const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, MAXIMUM_OBSCURING_OPACITY); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8059,7 +8123,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowWithOpacityAboveThreshold_Bloc const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, OPACITY_ABOVE_THRESHOLD); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8074,7 +8138,8 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityAboveThres const sp& w2 = getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY, OPACITY_BELOW_THRESHOLD); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w1, w2, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8089,7 +8154,8 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowsWithCombinedOpacityBelowThres const sp& w2 = getOccludingWindow(APP_B_UID, "B2", TouchOcclusionMode::USE_OPACITY, OPACITY_FAR_BELOW_THRESHOLD); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w1, w2, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8104,7 +8170,8 @@ TEST_F(InputDispatcherUntrustedTouchesTest, const sp& wC = getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, OPACITY_BELOW_THRESHOLD); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wB, wC, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8118,7 +8185,8 @@ TEST_F(InputDispatcherUntrustedTouchesTest, WindowsFromDifferentAppsOneAboveThre const sp& wC = getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, OPACITY_ABOVE_THRESHOLD); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wB, wC, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8133,7 +8201,8 @@ TEST_F(InputDispatcherUntrustedTouchesTest, const sp& wB = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, OPACITY_ABOVE_THRESHOLD); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wA, wB, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8148,7 +8217,8 @@ TEST_F(InputDispatcherUntrustedTouchesTest, const sp& wB = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, OPACITY_BELOW_THRESHOLD); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wA, wB, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*wA->getInfo(), *wB->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8159,7 +8229,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_ const sp& w = getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::USE_OPACITY, OPACITY_ABOVE_THRESHOLD); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8169,7 +8239,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithOpacityAboveThreshold_ TEST_F(InputDispatcherUntrustedTouchesTest, SelfWindowWithBlockUntrustedMode_AllowsTouch) { const sp& w = getOccludingWindow(TOUCHED_APP_UID, "T", TouchOcclusionMode::BLOCK_UNTRUSTED); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8181,7 +8251,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, mDispatcher->setMaximumObscuringOpacityForTouch(0.0f); const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.1f); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8192,7 +8262,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, OpacityThresholdIs0AndWindowAtThresh mDispatcher->setMaximumObscuringOpacityForTouch(0.0f); const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, 0.0f); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8205,7 +8275,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, OPACITY_ABOVE_THRESHOLD); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8220,7 +8290,8 @@ TEST_F(InputDispatcherUntrustedTouchesTest, const sp& w2 = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::USE_OPACITY, OPACITY_BELOW_THRESHOLD); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w1, w2, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*w1->getInfo(), *w2->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8240,7 +8311,8 @@ TEST_F(InputDispatcherUntrustedTouchesTest, const sp& wC = getOccludingWindow(APP_C_UID, "C", TouchOcclusionMode::USE_OPACITY, OPACITY_BELOW_THRESHOLD); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {wB, wC, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*wB->getInfo(), *wC->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8256,7 +8328,7 @@ TEST_F(InputDispatcherUntrustedTouchesTest, const sp& w = getOccludingWindow(APP_B_UID, "B", TouchOcclusionMode::BLOCK_UNTRUSTED); w->setApplicationToken(mTouchWindow->getApplicationToken()); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {w, mTouchWindow}}}); + mDispatcher->onWindowInfosChanged({{*w->getInfo(), *mTouchWindow->getInfo()}, {}, 0, 0}); touch(); @@ -8290,7 +8362,11 @@ protected: mSpyWindow->setFrame(Rect(0, 0, 200, 100)); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mSpyWindow, mWindow, mSecondWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mSpyWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, + {}, + 0, + 0}); } void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) { @@ -8347,8 +8423,11 @@ protected: mDragWindow = sp::make(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT); mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}}); - mDispatcher->setInputWindows( - {{ADISPLAY_ID_DEFAULT, {mDragWindow, mSpyWindow, mWindow, mSecondWindow}}}); + mDispatcher->onWindowInfosChanged({{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), + *mWindow->getInfo(), *mSecondWindow->getInfo()}, + {}, + 0, + 0}); // Transfer touch focus to the drag window bool transferred = @@ -8502,7 +8581,8 @@ TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) { // Set second window invisible. mSecondWindow->setVisible(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mDragWindow->getInfo(), *mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0}); // Move on window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -8622,7 +8702,12 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { // Update window of second display. sp windowInSecondary = sp::make(mApp, mDispatcher, "D_2", SECOND_DISPLAY_ID); - mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}}); + mDispatcher->onWindowInfosChanged( + {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(), + *mSecondWindow->getInfo(), *windowInSecondary->getInfo()}, + {}, + 0, + 0}); // Let second display has a touch state. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -8635,7 +8720,12 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { windowInSecondary->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN, SECOND_DISPLAY_ID, /*expectedFlag=*/0); // Update window again. - mDispatcher->setInputWindows({{SECOND_DISPLAY_ID, {windowInSecondary}}}); + mDispatcher->onWindowInfosChanged( + {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(), + *mSecondWindow->getInfo(), *windowInSecondary->getInfo()}, + {}, + 0, + 0}); // Move on window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -8724,7 +8814,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { window->setDropInput(true); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); @@ -8740,7 +8830,7 @@ TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { // With the flag cleared, the window should get input window->setDropInput(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT)); window->consumeKeyUp(ADISPLAY_ID_DEFAULT); @@ -8767,7 +8857,8 @@ TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { window->setOwnerInfo(gui::Pid{222}, gui::Uid{222}); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); + mDispatcher->onWindowInfosChanged( + {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); @@ -8783,7 +8874,8 @@ TEST_F(InputDispatcherDropInputFeatureTest, ObscuredWindowDropsInput) { // With the flag cleared, the window should get input window->setDropInputIfObscured(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); + mDispatcher->onWindowInfosChanged( + {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT)); window->consumeKeyUp(ADISPLAY_ID_DEFAULT); @@ -8810,7 +8902,8 @@ TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) { window->setOwnerInfo(gui::Pid{222}, gui::Uid{222}); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); window->setFocusable(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}}); + mDispatcher->onWindowInfosChanged( + {{*obscuringWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); @@ -8825,7 +8918,8 @@ TEST_F(InputDispatcherDropInputFeatureTest, UnobscuredWindowGetsInput) { window->assertNoEvents(); // When the window is no longer obscured because it went on top, it should get input - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, obscuringWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*window->getInfo(), *obscuringWindow->getInfo()}, {}, 0, 0}); mDispatcher->notifyKey(generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT)); window->consumeKeyUp(ADISPLAY_ID_DEFAULT); @@ -8861,8 +8955,11 @@ protected: mThirdWindow->setFocusable(true); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}, - {SECOND_DISPLAY_ID, {mThirdWindow}}}); + mDispatcher->onWindowInfosChanged( + {{*mWindow->getInfo(), *mSecondWindow->getInfo(), *mThirdWindow->getInfo()}, + {}, + 0, + 0}); mThirdWindow->setOwnerInfo(SECONDARY_WINDOW_PID, SECONDARY_WINDOW_UID); mWindow->consumeFocusEvent(true); @@ -8949,7 +9046,7 @@ TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInt // Then remove focus. mWindow->setFocusable(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow}}}); + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); // Assert that caller can switch touch mode by owning one of the last interacted window. const WindowInfo& windowInfo = *mWindow->getInfo(); @@ -8996,7 +9093,7 @@ TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) { auto spy = createSpy(); spy->setTrustedOverlay(false); - ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}), + ASSERT_DEATH(mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}), ".* not a trusted overlay"); } @@ -9005,7 +9102,7 @@ TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) { */ TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) { auto spy = createSpy(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy}}}); + mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) @@ -9030,7 +9127,8 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) { auto spy1 = createSpy(); auto spy2 = createSpy(); auto spy3 = createSpy(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window, spy3}}}); + mDispatcher->onWindowInfosChanged( + {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo(), *spy3->getInfo()}, {}, 0, 0}); const std::vector> channels{spy1, spy2, window, spy3}; const size_t numChannels = channels.size(); @@ -9082,7 +9180,7 @@ TEST_F(InputDispatcherSpyWindowTest, NotTouchable) { auto window = createForeground(); auto spy = createSpy(); spy->setTouchable(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) @@ -9100,7 +9198,7 @@ TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) { auto window = createForeground(); auto spy = createSpy(); spy->setTouchableRegion(Region{{0, 0, 20, 20}}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); // Inject an event outside the spy window's touchable region. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -9134,7 +9232,7 @@ TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { spy->setWatchOutsideTouch(true); spy->setOwnerInfo(gui::Pid{56}, gui::Uid{78}); spy->setFrame(Rect{0, 0, 20, 20}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); // Inject an event outside the spy window's frame and touchable region. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -9156,7 +9254,8 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { windowRight->setFrame({100, 0, 200, 200}); auto spy = createSpy(); spy->setFrame({0, 0, 200, 200}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, windowLeft, windowRight}}}); + mDispatcher->onWindowInfosChanged( + {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, @@ -9188,7 +9287,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { window->setFrame({0, 0, 200, 200}); auto spyRight = createSpy(); spyRight->setFrame({100, 0, 200, 200}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyRight, window}}}); + mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, @@ -9224,7 +9323,7 @@ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { auto window = createForeground(); window->setFrame(Rect(0, 0, 100, 100)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); // First finger down, no window touched. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -9260,7 +9359,7 @@ TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) { spy->setFocusable(false); auto window = createForeground(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(true); @@ -9285,7 +9384,8 @@ TEST_F(InputDispatcherPilferPointersTest, PilferPointers) { auto window = createForeground(); auto spy1 = createSpy(); auto spy2 = createSpy(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy1, spy2, window}}}); + mDispatcher->onWindowInfosChanged( + {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) @@ -9317,7 +9417,7 @@ TEST_F(InputDispatcherPilferPointersTest, PilferPointers) { TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) { auto window = createForeground(); auto spy = createSpy(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) @@ -9343,7 +9443,7 @@ TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) auto spy = createSpy(); auto window = createForeground(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); // First finger down on the window and the spy. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -9399,7 +9499,7 @@ TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) { auto window = createForeground(); window->setFrame(Rect(0, 0, 200, 200)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); // First finger down on the window only ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -9459,7 +9559,7 @@ TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) { auto window = createForeground(); window->setFrame(Rect(0, 0, 200, 200)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); // First finger down on both spy and window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -9502,7 +9602,7 @@ TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) { auto window = createForeground(); window->setFrame(Rect(0, 0, 200, 200)); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); // First finger down on both window and spy ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -9559,7 +9659,7 @@ public: window->setOwnerInfo(gui::Pid{222}, gui::Uid{222}); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); + mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); setFocusedWindow(window); window->consumeFocusEvent(/*hasFocus=*/true, /*inTouchMode=*/true); return {std::move(overlay), std::move(window)}; @@ -9589,13 +9689,14 @@ TEST_F(InputDispatcherStylusInterceptorDeathTest, UntrustedOverlay_AbortsDispatc auto [overlay, window] = setupStylusOverlayScenario(); overlay->setTrustedOverlay(false); // Configuring an untrusted overlay as a stylus interceptor should cause Dispatcher to abort. - ASSERT_DEATH(mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}), + ASSERT_DEATH(mDispatcher->onWindowInfosChanged( + {{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}), ".* not a trusted overlay"); } TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) { auto [overlay, window] = setupStylusOverlayScenario(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); + mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); sendStylusEvent(AMOTION_EVENT_ACTION_DOWN); overlay->consumeMotionDown(); @@ -9614,7 +9715,7 @@ TEST_F(InputDispatcherStylusInterceptorTest, ConsmesOnlyStylusEvents) { TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) { auto [overlay, window] = setupStylusOverlayScenario(); overlay->setSpy(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); + mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); sendStylusEvent(AMOTION_EVENT_ACTION_DOWN); overlay->consumeMotionDown(); @@ -9643,7 +9744,7 @@ TEST_F(InputDispatcherStylusInterceptorTest, SpyWindowStylusInterceptor) { TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) { auto [overlay, window] = setupStylusOverlayScenario(); overlay->setSpy(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); + mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); sendStylusEvent(AMOTION_EVENT_ACTION_DOWN); overlay->consumeMotionDown(); @@ -9655,7 +9756,7 @@ TEST_F(InputDispatcherStylusInterceptorTest, StylusHandwritingScenario) { // The interceptor configures itself so that it is no longer a spy. overlay->setSpy(false); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}}); + mDispatcher->onWindowInfosChanged({{*overlay->getInfo(), *window->getInfo()}, {}, 0, 0}); // It continues to receive the rest of the stylus gesture. sendStylusEvent(AMOTION_EVENT_ACTION_MOVE); @@ -9707,7 +9808,7 @@ using InputDispatcherTargetedInjectionTest = InputDispatcherTest; TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) { auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); auto window = owner.createWindow(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN)); @@ -9724,7 +9825,7 @@ TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) { TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) { auto owner = User(mDispatcher, gui::Pid{10}, gui::Uid{11}); auto window = owner.createWindow(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); auto rando = User(mDispatcher, gui::Pid{20}, gui::Uid{21}); EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH, @@ -9744,7 +9845,7 @@ TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) { auto spy = owner.createWindow(); spy->setSpy(true); spy->setTrustedOverlay(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, owner.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN)); @@ -9760,7 +9861,7 @@ TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) { auto randosSpy = rando.createWindow(); randosSpy->setSpy(true); randosSpy->setTrustedOverlay(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}}); + mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0}); // The event is targeted at owner's window, so injection should succeed, but the spy should // not receive the event. @@ -9778,7 +9879,7 @@ TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTarget auto randosSpy = rando.createWindow(); randosSpy->setSpy(true); randosSpy->setTrustedOverlay(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosSpy, window}}}); + mDispatcher->onWindowInfosChanged({{*randosSpy->getInfo(), *window->getInfo()}, {}, 0, 0}); // A user that has injection permission can inject into any window. EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -9803,7 +9904,7 @@ TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherU auto randosWindow = rando.createWindow(); randosWindow->setFrame(Rect{-10, -10, -5, -5}); randosWindow->setWatchOutsideTouch(true); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {randosWindow, window}}}); + mDispatcher->onWindowInfosChanged({{*randosWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); // Do not allow generation of ACTION_OUTSIDE events into windows owned by different uids. EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, -- GitLab From 3652ba0fac04d5646a2fe39c74de22269b2a8d7c Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 21 Jul 2023 00:37:18 +0000 Subject: [PATCH 0323/1187] binderAllocationLimits: check remote binder null Possible null de-ref hit one time? This is not actually expected to fix this bug, but if it reproduces again, it should give us slightly more information. Change-Id: Ie3de2b50088179d1c7fcb8d492dfc092a2e45b91 Fixes: 291870594 Test: N/A --- libs/binder/tests/binderAllocationLimits.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp index bc40864020..6712c9cece 100644 --- a/libs/binder/tests/binderAllocationLimits.cpp +++ b/libs/binder/tests/binderAllocationLimits.cpp @@ -216,16 +216,16 @@ TEST(RpcBinderAllocation, SetupRpcServer) { auto server = RpcServer::make(); server->setRootObject(sp::make()); - CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str())); + ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str())); std::thread([server]() { server->join(); }).detach(); - status_t status; auto session = RpcSession::make(); - status = session->setupUnixDomainClient(addr.c_str()); - CHECK_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str(); + status_t status = session->setupUnixDomainClient(addr.c_str()); + ASSERT_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str(); auto remoteBinder = session->getRootObject(); + ASSERT_NE(remoteBinder, nullptr); size_t mallocs = 0, totalBytes = 0; { @@ -233,7 +233,7 @@ TEST(RpcBinderAllocation, SetupRpcServer) { mallocs++; totalBytes += bytes; }); - CHECK_EQ(OK, remoteBinder->pingBinder()); + ASSERT_EQ(OK, remoteBinder->pingBinder()); } EXPECT_EQ(mallocs, 1); EXPECT_EQ(totalBytes, 40); -- GitLab From d0e68d20a6ae8aa91e2aef40cec57e148eb896c1 Mon Sep 17 00:00:00 2001 From: Pontus Lidman Date: Thu, 20 Jul 2023 18:31:53 +0000 Subject: [PATCH 0324/1187] Make maximum sensor fusion rate tunable. Instead of the hard-coded 200Hz maximum rate limit for sensor fusion, make it a tunable parameter using a property: sensors.aosp_low_power_sensor_fusion.maximum_rate If the property is not specified, the default remains 200Hz. Wearable devices are recommended to change it to 100 (Hz) to save power. Bug: b/270230642 Test: dumpsys sensorservice and verify gyro-rate Change-Id: Iff07899b80366d6a9913529d5758f386848c9697 --- services/sensorservice/SensorFusion.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp index e27b52b23e..5c00260008 100644 --- a/services/sensorservice/SensorFusion.cpp +++ b/services/sensorservice/SensorFusion.cpp @@ -19,6 +19,7 @@ #include "SensorService.h" #include +#include #include namespace android { @@ -60,10 +61,12 @@ SensorFusion::SensorFusion() mGyro = uncalibratedGyro; } - // 200 Hz for gyro events is a good compromise between precision - // and power/cpu usage. - mEstimatedGyroRate = 200; - mTargetDelayNs = 1000000000LL/mEstimatedGyroRate; + // Wearable devices will want to tune this parameter + // to 100 (Hz) in device.mk to save some power. + int32_t value = property_get_int32( + "sensors.aosp_low_power_sensor_fusion.maximum_rate", 200); + mEstimatedGyroRate = static_cast(value); + mTargetDelayNs = 1000000000LL / mEstimatedGyroRate; for (int i = 0; i Date: Fri, 21 Jul 2023 14:20:27 +0000 Subject: [PATCH 0325/1187] [sf] Only trace rebuildLayerStacks if there are changes Clean up perfetto traces to only show tags when they are interesting. Bug: 292225846 Test: open trace in perfetto Change-Id: I1e3744abb08c7a3b34244db8ce8be5299cf86b19 --- services/surfaceflinger/CompositionEngine/src/Output.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 1205a2ce71..b1b5708473 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -469,15 +469,14 @@ void Output::uncacheBuffers(std::vector const& bufferIdsToUncache) { void Output::rebuildLayerStacks(const compositionengine::CompositionRefreshArgs& refreshArgs, LayerFESet& layerFESet) { - ATRACE_CALL(); - ALOGV(__FUNCTION__); - auto& outputState = editState(); // Do nothing if this output is not enabled or there is no need to perform this update if (!outputState.isEnabled || CC_LIKELY(!refreshArgs.updatingOutputGeometryThisFrame)) { return; } + ATRACE_CALL(); + ALOGV(__FUNCTION__); // Process the layers to determine visibility and coverage compositionengine::Output::CoverageState coverage{layerFESet}; -- GitLab From 2aef0f420b0b3c1ea564a9c1291bbedd9f833ac8 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 21 Jul 2023 17:03:32 +0000 Subject: [PATCH 0326/1187] Revert "[sf] enable new sf frontend" This reverts commit bdf565b2b74ef70f167e4855699ce947ff9fa6d7. Reason for revert: suspect for b/292166769 Change-Id: I9945cd6f979c2abbdceb02743e1f1f68e8da2bcd --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6df7bc0722..a9a1d80830 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -487,7 +487,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false); mLayerLifecycleManagerEnabled = - base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, true); + base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false); mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled || base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); } -- GitLab From 4ed9d77720784debaa328c48353b284ff21248df Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Fri, 21 Jul 2023 18:21:05 +0100 Subject: [PATCH 0327/1187] Add safety comments to binder tests. These will soon be required by a lint. Bug: 290018030 Test: m rust Change-Id: I807496ec5262145342ad9a40943094bfbe3cccc5 --- libs/binder/rust/src/parcel.rs | 40 +++++++++++ libs/binder/rust/src/parcel/parcelable.rs | 66 +++++++++++++++++++ libs/binder/rust/tests/integration.rs | 5 ++ libs/binder/rust/tests/ndk_rust_interop.rs | 10 +-- .../rust/tests/parcel_fuzzer/parcel_fuzzer.rs | 4 +- libs/binder/rust/tests/serialization.rs | 21 ++++++ 6 files changed, 140 insertions(+), 6 deletions(-) diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs index 0b0f9f9b61..3c615edbc0 100644 --- a/libs/binder/rust/src/parcel.rs +++ b/libs/binder/rust/src/parcel.rs @@ -723,6 +723,8 @@ fn test_read_write() { parcel.write(&1i32).unwrap(); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { parcel.set_data_position(start).unwrap(); } @@ -739,6 +741,8 @@ fn test_read_data() { parcel.write(&b"Hello, Binder!\0"[..]).unwrap(); // Skip over string length + // SAFETY: str_start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(str_start).is_ok()); } @@ -747,42 +751,56 @@ fn test_read_data() { assert!(parcel.read::().unwrap()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::().unwrap(), 72i8); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::().unwrap(), 25928); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::().unwrap(), 1819043144); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::().unwrap(), 1819043144); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::().unwrap(), 4764857262830019912); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::().unwrap(), 4764857262830019912); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -790,6 +808,8 @@ fn test_read_data() { assert_eq!(parcel.read::().unwrap(), 1143139100000000000000000000.0); assert_eq!(parcel.read::().unwrap(), 40.043392); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -797,6 +817,8 @@ fn test_read_data() { assert_eq!(parcel.read::().unwrap(), 34732488246.197815); // Skip back to before the string length + // SAFETY: str_start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(str_start).is_ok()); } @@ -810,15 +832,21 @@ fn test_utf8_utf16_conversions() { let start = parcel.get_data_position(); assert!(parcel.write("Hello, Binder!").is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::>().unwrap().unwrap(), "Hello, Binder!",); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(parcel.write("Embedded null \0 inside a string").is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -826,6 +854,8 @@ fn test_utf8_utf16_conversions() { parcel.read::>().unwrap().unwrap(), "Embedded null \0 inside a string", ); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -840,6 +870,8 @@ fn test_utf8_utf16_conversions() { let s3 = "Some more text here."; assert!(parcel.write(&[s1, s2, s3][..]).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -865,6 +897,8 @@ fn test_sized_write() { assert_eq!(parcel.get_data_position(), start + expected_len); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { parcel.set_data_position(start).unwrap(); } @@ -884,6 +918,8 @@ fn test_append_from() { assert_eq!(4, parcel2.get_data_size()); assert_eq!(Ok(()), parcel2.append_all_from(&parcel1)); assert_eq!(8, parcel2.get_data_size()); + // SAFETY: 0 is less than the current size of the parcel data buffer, because the parcel is not + // empty. unsafe { parcel2.set_data_position(0).unwrap(); } @@ -894,6 +930,8 @@ fn test_append_from() { assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2)); assert_eq!(Ok(()), parcel2.append_from(&parcel1, 2, 2)); assert_eq!(4, parcel2.get_data_size()); + // SAFETY: 0 is less than the current size of the parcel data buffer, because the parcel is not + // empty. unsafe { parcel2.set_data_position(0).unwrap(); } @@ -902,6 +940,8 @@ fn test_append_from() { let mut parcel2 = Parcel::new(); assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2)); assert_eq!(2, parcel2.get_data_size()); + // SAFETY: 0 is less than the current size of the parcel data buffer, because the parcel is not + // empty. unsafe { parcel2.set_data_position(0).unwrap(); } diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs index 038f198fce..9008a3cc0e 100644 --- a/libs/binder/rust/src/parcel/parcelable.rs +++ b/libs/binder/rust/src/parcel/parcelable.rs @@ -1087,6 +1087,8 @@ mod tests { assert!(custom.serialize(&mut parcel.borrowed()).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1109,6 +1111,8 @@ mod tests { assert!(bools.serialize(&mut parcel.borrowed()).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1118,6 +1122,8 @@ mod tests { assert_eq!(parcel.read::().unwrap(), 0); assert_eq!(parcel.read::().unwrap(), 0); assert_eq!(parcel.read::().unwrap(), 1); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1133,12 +1139,17 @@ mod tests { assert!(parcel.write(&u8s[..]).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::().unwrap(), 4); // 4 items assert_eq!(parcel.read::().unwrap(), 0x752aff65); // bytes + + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1148,18 +1159,25 @@ mod tests { let i8s = [-128i8, 127, 42, -117]; + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(parcel.write(&i8s[..]).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert_eq!(parcel.read::().unwrap(), 4); // 4 items assert_eq!(parcel.read::().unwrap(), 0x8b2a7f80); // bytes + + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1169,10 +1187,14 @@ mod tests { let u16s = [u16::max_value(), 12_345, 42, 117]; + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(u16s.serialize(&mut parcel.borrowed()).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1182,6 +1204,9 @@ mod tests { assert_eq!(parcel.read::().unwrap(), 12345); // 12,345 assert_eq!(parcel.read::().unwrap(), 42); // 42 assert_eq!(parcel.read::().unwrap(), 117); // 117 + + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1192,10 +1217,14 @@ mod tests { let i16s = [i16::max_value(), i16::min_value(), 42, -117]; + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(i16s.serialize(&mut parcel.borrowed()).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1205,6 +1234,9 @@ mod tests { assert_eq!(parcel.read::().unwrap(), 0x8000); // i16::min_value() assert_eq!(parcel.read::().unwrap(), 42); // 42 assert_eq!(parcel.read::().unwrap(), 0xff8b); // -117 + + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1215,10 +1247,14 @@ mod tests { let u32s = [u32::max_value(), 12_345, 42, 117]; + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(u32s.serialize(&mut parcel.borrowed()).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1228,6 +1264,9 @@ mod tests { assert_eq!(parcel.read::().unwrap(), 12345); // 12,345 assert_eq!(parcel.read::().unwrap(), 42); // 42 assert_eq!(parcel.read::().unwrap(), 117); // 117 + + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1238,10 +1277,14 @@ mod tests { let i32s = [i32::max_value(), i32::min_value(), 42, -117]; + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(i32s.serialize(&mut parcel.borrowed()).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1251,6 +1294,9 @@ mod tests { assert_eq!(parcel.read::().unwrap(), 0x80000000); // i32::min_value() assert_eq!(parcel.read::().unwrap(), 42); // 42 assert_eq!(parcel.read::().unwrap(), 0xffffff8b); // -117 + + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1261,10 +1307,14 @@ mod tests { let u64s = [u64::max_value(), 12_345, 42, 117]; + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(u64s.serialize(&mut parcel.borrowed()).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1275,10 +1325,14 @@ mod tests { let i64s = [i64::max_value(), i64::min_value(), 42, -117]; + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(i64s.serialize(&mut parcel.borrowed()).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1289,10 +1343,14 @@ mod tests { let f32s = [std::f32::NAN, std::f32::INFINITY, 1.23456789, std::f32::EPSILON]; + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(f32s.serialize(&mut parcel.borrowed()).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1305,10 +1363,14 @@ mod tests { let f64s = [std::f64::NAN, std::f64::INFINITY, 1.234567890123456789, std::f64::EPSILON]; + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(f64s.serialize(&mut parcel.borrowed()).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } @@ -1326,10 +1388,14 @@ mod tests { let strs = [s1, s2, s3, s4]; + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } assert!(strs.serialize(&mut parcel.borrowed()).is_ok()); + // SAFETY: start is less than the current size of the parcel data buffer, because we haven't + // made it any shorter since we got the position. unsafe { assert!(parcel.set_data_position(start).is_ok()); } diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs index ca2cedc19d..c049b807df 100644 --- a/libs/binder/rust/tests/integration.rs +++ b/libs/binder/rust/tests/integration.rs @@ -545,6 +545,11 @@ mod tests { } fn get_expected_selinux_context() -> &'static str { + // SAFETY: The pointer we pass to `getcon` is valid because it comes from a reference, and + // `getcon` doesn't retain it after it returns. If `getcon` succeeds then `out_ptr` will + // point to a valid C string, otherwise it will remain null. We check for null, so the + // pointer we pass to `CStr::from_ptr` must be a valid pointer to a C string. There is a + // memory leak as we don't call `freecon`, but that's fine because this is just a test. unsafe { let mut out_ptr = ptr::null_mut(); assert_eq!(selinux_sys::getcon(&mut out_ptr), 0); diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs index 415ede1a7b..37f182eb08 100644 --- a/libs/binder/rust/tests/ndk_rust_interop.rs +++ b/libs/binder/rust/tests/ndk_rust_interop.rs @@ -28,10 +28,11 @@ use std::os::raw::{c_char, c_int}; /// /// # Safety /// -/// service_name must be a valid, non-null C-style string (null-terminated). +/// service_name must be a valid, non-null C-style string (nul-terminated). #[no_mangle] pub unsafe extern "C" fn rust_call_ndk(service_name: *const c_char) -> c_int { - let service_name = CStr::from_ptr(service_name).to_str().unwrap(); + // SAFETY: Our caller promises that service_name is a valid C string. + let service_name = unsafe { CStr::from_ptr(service_name) }.to_str().unwrap(); // The Rust class descriptor pointer will not match the NDK one, but the // descriptor strings match so this needs to still associate. @@ -85,10 +86,11 @@ impl IBinderRustNdkInteropTest for Service { /// /// # Safety /// -/// service_name must be a valid, non-null C-style string (null-terminated). +/// service_name must be a valid, non-null C-style string (nul-terminated). #[no_mangle] pub unsafe extern "C" fn rust_start_service(service_name: *const c_char) -> c_int { - let service_name = CStr::from_ptr(service_name).to_str().unwrap(); + // SAFETY: Our caller promises that service_name is a valid C string. + let service_name = unsafe { CStr::from_ptr(service_name) }.to_str().unwrap(); let service = BnBinderRustNdkInteropTest::new_binder(Service, BinderFeatures::default()); match binder::add_service(service_name, service.as_binder()) { Ok(_) => StatusCode::OK as c_int, diff --git a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs index 29bf92cb97..ce0f742934 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs +++ b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs @@ -105,9 +105,9 @@ fn do_read_fuzz(read_operations: Vec, data: &[u8]) { for operation in read_operations { match operation { ReadOperation::SetDataPosition { pos } => { + // Safety: Safe if pos is less than current size of the parcel. + // It relies on C++ code for bound checks unsafe { - // Safety: Safe if pos is less than current size of the parcel. - // It relies on C++ code for bound checks match parcel.set_data_position(pos) { Ok(result) => result, Err(e) => println!("error occurred while setting data position: {:?}", e), diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs index 6220db4b28..8b04c76b33 100644 --- a/libs/binder/rust/tests/serialization.rs +++ b/libs/binder/rust/tests/serialization.rs @@ -113,11 +113,13 @@ fn on_transact( bindings::Transaction_TEST_BOOL => { assert!(parcel.read::()?); assert!(!parcel.read::()?); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::>()?, unsafe { bindings::TESTDATA_BOOL }); assert_eq!(parcel.read::>>()?, None); reply.write(&true)?; reply.write(&false)?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_BOOL }[..])?; reply.write(&(None as Option>))?; } @@ -125,14 +127,18 @@ fn on_transact( assert_eq!(parcel.read::()?, 0); assert_eq!(parcel.read::()?, 1); assert_eq!(parcel.read::()?, i8::max_value()); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::>()?, unsafe { bindings::TESTDATA_I8 }); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::>()?, unsafe { bindings::TESTDATA_U8 }); assert_eq!(parcel.read::>>()?, None); reply.write(&0i8)?; reply.write(&1i8)?; reply.write(&i8::max_value())?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_I8 }[..])?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_U8 }[..])?; reply.write(&(None as Option>))?; } @@ -140,12 +146,14 @@ fn on_transact( assert_eq!(parcel.read::()?, 0); assert_eq!(parcel.read::()?, 1); assert_eq!(parcel.read::()?, u16::max_value()); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::>()?, unsafe { bindings::TESTDATA_CHARS }); assert_eq!(parcel.read::>>()?, None); reply.write(&0u16)?; reply.write(&1u16)?; reply.write(&u16::max_value())?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_CHARS }[..])?; reply.write(&(None as Option>))?; } @@ -153,12 +161,14 @@ fn on_transact( assert_eq!(parcel.read::()?, 0); assert_eq!(parcel.read::()?, 1); assert_eq!(parcel.read::()?, i32::max_value()); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::>()?, unsafe { bindings::TESTDATA_I32 }); assert_eq!(parcel.read::>>()?, None); reply.write(&0i32)?; reply.write(&1i32)?; reply.write(&i32::max_value())?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_I32 }[..])?; reply.write(&(None as Option>))?; } @@ -166,12 +176,14 @@ fn on_transact( assert_eq!(parcel.read::()?, 0); assert_eq!(parcel.read::()?, 1); assert_eq!(parcel.read::()?, i64::max_value()); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::>()?, unsafe { bindings::TESTDATA_I64 }); assert_eq!(parcel.read::>>()?, None); reply.write(&0i64)?; reply.write(&1i64)?; reply.write(&i64::max_value())?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_I64 }[..])?; reply.write(&(None as Option>))?; } @@ -179,12 +191,14 @@ fn on_transact( assert_eq!(parcel.read::()?, 0); assert_eq!(parcel.read::()?, 1); assert_eq!(parcel.read::()?, u64::max_value()); + // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::>()?, unsafe { bindings::TESTDATA_U64 }); assert_eq!(parcel.read::>>()?, None); reply.write(&0u64)?; reply.write(&1u64)?; reply.write(&u64::max_value())?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_U64 }[..])?; reply.write(&(None as Option>))?; } @@ -192,10 +206,12 @@ fn on_transact( assert_eq!(parcel.read::()?, 0f32); let floats = parcel.read::>()?; assert!(floats[0].is_nan()); + // SAFETY: Just reading an extern constant. assert_eq!(floats[1..], unsafe { bindings::TESTDATA_FLOAT }[1..]); assert_eq!(parcel.read::>>()?, None); reply.write(&0f32)?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_FLOAT }[..])?; reply.write(&(None as Option>))?; } @@ -203,10 +219,12 @@ fn on_transact( assert_eq!(parcel.read::()?, 0f64); let doubles = parcel.read::>()?; assert!(doubles[0].is_nan()); + // SAFETY: Just reading an extern constant. assert_eq!(doubles[1..], unsafe { bindings::TESTDATA_DOUBLE }[1..]); assert_eq!(parcel.read::>>()?, None); reply.write(&0f64)?; + // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_DOUBLE }[..])?; reply.write(&(None as Option>))?; } @@ -216,14 +234,17 @@ fn on_transact( let s: Option = parcel.read()?; assert_eq!(s, None); let s: Option>> = parcel.read()?; + // SAFETY: Just reading an extern constant. for (s, expected) in s.unwrap().iter().zip(unsafe { bindings::TESTDATA_STRS }.iter()) { let expected = + // SAFETY: Just reading an extern constant. unsafe { expected.as_ref().and_then(|e| CStr::from_ptr(e).to_str().ok()) }; assert_eq!(s.as_deref(), expected); } let s: Option>> = parcel.read()?; assert_eq!(s, None); + // SAFETY: Just reading an extern constant. let strings: Vec> = unsafe { bindings::TESTDATA_STRS .iter() -- GitLab From 91082644ee78c97fc0b5a5be6a9cb2a7a41a863f Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Fri, 21 Jul 2023 18:21:58 +0100 Subject: [PATCH 0328/1187] Use OnceLock rather than Once. This avoids the need for a mutable static, and most of the unsafety. Bug: 290018030 Test: m rust Change-Id: Ib9a1af0c74f1620db340ee4abdbfb5e6ad9752a7 --- libs/binder/rust/tests/serialization.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs index 8b04c76b33..2b6c282530 100644 --- a/libs/binder/rust/tests/serialization.rs +++ b/libs/binder/rust/tests/serialization.rs @@ -26,7 +26,7 @@ use binder::{ use binder::binder_impl::{Binder, BorrowedParcel, TransactionCode}; use std::ffi::{c_void, CStr, CString}; -use std::sync::Once; +use std::sync::OnceLock; #[allow( non_camel_case_types, @@ -70,20 +70,18 @@ macro_rules! assert { }; } -static SERVICE_ONCE: Once = Once::new(); -static mut SERVICE: Option = None; +static SERVICE: OnceLock = OnceLock::new(); /// Start binder service and return a raw AIBinder pointer to it. /// /// Safe to call multiple times, only creates the service once. #[no_mangle] pub extern "C" fn rust_service() -> *mut c_void { - unsafe { - SERVICE_ONCE.call_once(|| { - SERVICE = Some(BnReadParcelTest::new_binder((), BinderFeatures::default()).as_binder()); - }); - SERVICE.as_ref().unwrap().as_raw().cast() - } + let service = SERVICE + .get_or_init(|| BnReadParcelTest::new_binder((), BinderFeatures::default()).as_binder()); + // SAFETY: The SpIBinder will remain alive as long as the program is running because it is in + // the static SERVICE, so the pointer is valid forever. + unsafe { service.as_raw().cast() } } /// Empty interface just to use the declare_binder_interface macro @@ -279,8 +277,7 @@ fn on_transact( assert!(ibinders[1].is_none()); assert!(parcel.read::>>>()?.is_none()); - let service = - unsafe { SERVICE.as_ref().expect("Global binder service not initialized").clone() }; + let service = SERVICE.get().expect("Global binder service not initialized").clone(); reply.write(&service)?; reply.write(&(None as Option<&SpIBinder>))?; reply.write(&[Some(&service), None][..])?; -- GitLab From 263a3f1f1b7a316eb78a9034c976c0c3b26171f1 Mon Sep 17 00:00:00 2001 From: ramindani Date: Tue, 18 Jul 2023 20:44:49 -0700 Subject: [PATCH 0329/1187] [SF] Updates to incorporate vrr aidl interface changes Test: builds, atest libsurfaceflinger_unittest BUG: 284881912 BUG: 287517352 Change-Id: Icf7b23686c26108b0681ccbeea8d3591211a2611 --- .../CompositionEngine/tests/MockHWComposer.h | 3 ++- .../DisplayHardware/AidlComposerHal.cpp | 5 ++-- .../DisplayHardware/AidlComposerHal.h | 3 ++- .../DisplayHardware/ComposerHal.h | 3 ++- .../DisplayHardware/HWComposer.cpp | 11 +++++---- .../DisplayHardware/HWComposer.h | 9 ++++--- .../DisplayHardware/HidlComposerHal.cpp | 3 ++- .../DisplayHardware/HidlComposerHal.h | 3 ++- services/surfaceflinger/SurfaceFlinger.cpp | 4 +++- .../surfaceflinger_displayhardware_fuzzer.cpp | 2 +- .../tests/unittests/HWComposerTest.cpp | 24 ++++++++++--------- .../mock/DisplayHardware/MockComposer.h | 3 ++- 12 files changed, 44 insertions(+), 29 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index 67b94ee749..892bb8f726 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -94,7 +94,8 @@ public: MOCK_METHOD(std::optional, onVsync, (hal::HWDisplayId, int64_t)); MOCK_METHOD2(setVsyncEnabled, void(PhysicalDisplayId, hal::Vsync)); MOCK_CONST_METHOD1(isConnected, bool(PhysicalDisplayId)); - MOCK_CONST_METHOD1(getModes, std::vector(PhysicalDisplayId)); + MOCK_CONST_METHOD2(getModes, + std::vector(PhysicalDisplayId, int32_t)); MOCK_CONST_METHOD1(getActiveMode, std::optional(PhysicalDisplayId)); MOCK_CONST_METHOD1(getColorModes, std::vector(PhysicalDisplayId)); MOCK_METHOD3(setActiveColorMode, status_t(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent)); diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index 311820c3ed..1f409c6ee7 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -492,10 +492,11 @@ Error AidlComposer::getDisplayConfigs(Display display, std::vector* outC return Error::NONE; } -Error AidlComposer::getDisplayConfigurations(Display display, +Error AidlComposer::getDisplayConfigurations(Display display, int32_t maxFrameIntervalNs, std::vector* outConfigs) { const auto status = - mAidlComposerClient->getDisplayConfigurations(translate(display), outConfigs); + mAidlComposerClient->getDisplayConfigurations(translate(display), + maxFrameIntervalNs, outConfigs); if (!status.isOk()) { ALOGE("getDisplayConfigurations failed %s", status.getDescription().c_str()); return static_cast(status.getServiceSpecificError()); diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index e31ff812e3..b1b57a4528 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -96,7 +96,8 @@ public: Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) override; Error getDisplayConfigs(Display display, std::vector* outConfigs); - Error getDisplayConfigurations(Display, std::vector*); + Error getDisplayConfigurations(Display, int32_t maxFrameIntervalNs, + std::vector*); Error getDisplayName(Display display, std::string* outName) override; Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask, diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index cc60fd0ec0..e94258707b 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -134,7 +134,8 @@ public: IComposerClient::Attribute attribute, int32_t* outValue) = 0; virtual Error getDisplayConfigs(Display display, std::vector* outConfigs) = 0; - virtual Error getDisplayConfigurations(Display, std::vector*) = 0; + virtual Error getDisplayConfigurations(Display, int32_t maxFrameIntervalNs, + std::vector*) = 0; virtual Error getDisplayName(Display display, std::string* outName) = 0; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index aefa7c3551..3177b33538 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -261,23 +261,24 @@ bool HWComposer::isConnected(PhysicalDisplayId displayId) const { return mDisplayData.count(displayId) && mDisplayData.at(displayId).hwcDisplay->isConnected(); } -std::vector HWComposer::getModes(PhysicalDisplayId displayId) const { +std::vector HWComposer::getModes(PhysicalDisplayId displayId, + int32_t maxFrameIntervalNs) const { RETURN_IF_INVALID_DISPLAY(displayId, {}); const auto hwcDisplayId = mDisplayData.at(displayId).hwcDisplay->getId(); if (mComposer->getDisplayConfigurationsSupported()) { - return getModesFromDisplayConfigurations(hwcDisplayId); + return getModesFromDisplayConfigurations(hwcDisplayId, maxFrameIntervalNs); } return getModesFromLegacyDisplayConfigs(hwcDisplayId); } std::vector HWComposer::getModesFromDisplayConfigurations( - uint64_t hwcDisplayId) const { + uint64_t hwcDisplayId, int32_t maxFrameIntervalNs) const { std::vector configs; - auto error = - static_cast(mComposer->getDisplayConfigurations(hwcDisplayId, &configs)); + auto error = static_cast( + mComposer->getDisplayConfigurations(hwcDisplayId, maxFrameIntervalNs, &configs)); RETURN_IF_HWC_ERROR_FOR("getDisplayConfigurations", error, *toPhysicalDisplayId(hwcDisplayId), {}); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 8247d97005..86f382596a 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -229,7 +229,8 @@ public: virtual bool isConnected(PhysicalDisplayId) const = 0; - virtual std::vector getModes(PhysicalDisplayId) const = 0; + virtual std::vector getModes(PhysicalDisplayId, + int32_t maxFrameIntervalNs) const = 0; virtual std::optional getActiveMode(PhysicalDisplayId) const = 0; @@ -412,7 +413,8 @@ public: bool isConnected(PhysicalDisplayId) const override; - std::vector getModes(PhysicalDisplayId) const override; + std::vector getModes(PhysicalDisplayId, + int32_t maxFrameIntervalNs) const override; std::optional getActiveMode(PhysicalDisplayId) const override; @@ -501,7 +503,8 @@ private: std::optional onHotplugDisconnect(hal::HWDisplayId); bool shouldIgnoreHotplugConnect(hal::HWDisplayId, bool hasDisplayIdentificationData) const; - std::vector getModesFromDisplayConfigurations(uint64_t hwcDisplayId) const; + std::vector getModesFromDisplayConfigurations(uint64_t hwcDisplayId, + int32_t maxFrameIntervalNs) const; std::vector getModesFromLegacyDisplayConfigs(uint64_t hwcDisplayId) const; int32_t getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId configId, diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index 0655abc1c6..70d48de75a 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -482,7 +482,8 @@ Error HidlComposer::getDisplayConfigs(Display display, std::vector* outC return error; } -Error HidlComposer::getDisplayConfigurations(Display, std::vector*) { +Error HidlComposer::getDisplayConfigurations(Display, int32_t /*maxFrameIntervalNs*/, + std::vector*) { LOG_ALWAYS_FATAL("getDisplayConfigurations should not have been called on this, as " "it's a HWC3 interface version 3 feature"); } diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index ac96d9a81d..26d22227ce 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -197,7 +197,8 @@ public: Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, int32_t* outValue) override; Error getDisplayConfigs(Display display, std::vector* outConfigs); - Error getDisplayConfigurations(Display, std::vector*); + Error getDisplayConfigurations(Display, int32_t maxFrameIntervalNs, + std::vector*); Error getDisplayName(Display display, std::string* outName) override; Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 198e92abaf..1da51bd5f2 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3166,7 +3166,9 @@ std::pair SurfaceFlinger::loadDisplayModes( int attempt = 0; constexpr int kMaxAttempts = 3; do { - hwcModes = getHwComposer().getModes(displayId); + hwcModes = getHwComposer().getModes(displayId, + scheduler::RefreshRateSelector::kMinSupportedFrameRate + .getPeriodNsecs()); activeModeHwcId = getHwComposer().getActiveMode(displayId); const auto isActiveMode = [activeModeHwcId](const HWComposer::HWCDisplayMode& mode) { diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp index 9fac14ed4c..f22315ab1e 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp @@ -597,7 +597,7 @@ void DisplayHardwareFuzzer::invokeComposer() { mFdp.ConsumeBool() ? hal::Vsync::ENABLE : hal::Vsync::DISABLE); mHwc.isConnected(mPhysicalDisplayId); - mHwc.getModes(mPhysicalDisplayId); + mHwc.getModes(mPhysicalDisplayId, mFdp.ConsumeIntegral()); mHwc.getActiveMode(mPhysicalDisplayId); mHwc.getColorModes(mPhysicalDisplayId); mHwc.hasCapability(mFdp.PickValueInArray(kCapability)); diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index ec8069d299..8a45f17e2f 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -123,6 +123,7 @@ TEST_F(HWComposerTest, getActiveMode) { TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { constexpr hal::HWDisplayId kHwcDisplayId = 2; constexpr hal::HWConfigId kConfigId = 42; + constexpr int32_t kMaxFrameIntervalNs = 50000000; // 20Fps expectHotplugConnect(kHwcDisplayId); const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); @@ -133,7 +134,7 @@ TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { { EXPECT_CALL(*mHal, getDisplayConfigs(kHwcDisplayId, _)) .WillOnce(Return(HalError::BAD_DISPLAY)); - EXPECT_TRUE(mHwc.getModes(info->id).empty()); + EXPECT_TRUE(mHwc.getModes(info->id, kMaxFrameIntervalNs).empty()); } { constexpr int32_t kWidth = 480; @@ -172,7 +173,7 @@ TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { .WillRepeatedly(DoAll(SetArgPointee<1>(std::vector{kConfigId}), Return(HalError::NONE))); - auto modes = mHwc.getModes(info->id); + auto modes = mHwc.getModes(info->id, kMaxFrameIntervalNs); EXPECT_EQ(modes.size(), size_t{1}); EXPECT_EQ(modes.front().hwcId, kConfigId); EXPECT_EQ(modes.front().width, kWidth); @@ -193,7 +194,7 @@ TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { _)) .WillOnce(DoAll(SetArgPointee<3>(kDpi), Return(HalError::NONE))); - modes = mHwc.getModes(info->id); + modes = mHwc.getModes(info->id, kMaxFrameIntervalNs); EXPECT_EQ(modes.size(), size_t{1}); EXPECT_EQ(modes.front().hwcId, kConfigId); EXPECT_EQ(modes.front().width, kWidth); @@ -209,6 +210,7 @@ TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) { TEST_F(HWComposerTest, getModesWithDisplayConfigurations) { constexpr hal::HWDisplayId kHwcDisplayId = 2; constexpr hal::HWConfigId kConfigId = 42; + constexpr int32_t kMaxFrameIntervalNs = 50000000; // 20Fps expectHotplugConnect(kHwcDisplayId); const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); ASSERT_TRUE(info); @@ -216,9 +218,9 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations) { EXPECT_CALL(*mHal, getDisplayConfigurationsSupported()).WillRepeatedly(Return(true)); { - EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _)) + EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _, _)) .WillOnce(Return(HalError::BAD_DISPLAY)); - EXPECT_TRUE(mHwc.getModes(info->id).empty()); + EXPECT_TRUE(mHwc.getModes(info->id, kMaxFrameIntervalNs).empty()); } { constexpr int32_t kWidth = 480; @@ -232,13 +234,13 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations) { displayConfiguration.width = kWidth; displayConfiguration.vsyncPeriod = kVsyncPeriod; - EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _)) - .WillOnce(DoAll(SetArgPointee<1>(std::vector{ + EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _, _)) + .WillOnce(DoAll(SetArgPointee<2>(std::vector{ displayConfiguration}), Return(HalError::NONE))); // Optional dpi not supported - auto modes = mHwc.getModes(info->id); + auto modes = mHwc.getModes(info->id, kMaxFrameIntervalNs); EXPECT_EQ(modes.size(), size_t{1}); EXPECT_EQ(modes.front().hwcId, kConfigId); EXPECT_EQ(modes.front().width, kWidth); @@ -252,12 +254,12 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations) { constexpr int32_t kDpi = 320; displayConfiguration.dpi = {kDpi, kDpi}; - EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _)) - .WillOnce(DoAll(SetArgPointee<1>(std::vector{ + EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _, _)) + .WillOnce(DoAll(SetArgPointee<2>(std::vector{ displayConfiguration}), Return(HalError::NONE))); - modes = mHwc.getModes(info->id); + modes = mHwc.getModes(info->id, kMaxFrameIntervalNs); EXPECT_EQ(modes.size(), size_t{1}); EXPECT_EQ(modes.front().hwcId, kConfigId); EXPECT_EQ(modes.front().width, kWidth); diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index 8d48940aa9..95004a485b 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -71,7 +71,8 @@ public: MOCK_METHOD4(getDisplayAttribute, Error(Display, Config config, IComposerClient::Attribute, int32_t*)); MOCK_METHOD2(getDisplayConfigs, Error(Display, std::vector*)); - MOCK_METHOD2(getDisplayConfigurations, Error(Display, std::vector*)); + MOCK_METHOD3(getDisplayConfigurations, + Error(Display, int32_t, std::vector*)); MOCK_METHOD2(getDisplayName, Error(Display, std::string*)); MOCK_METHOD4(getDisplayRequests, Error(Display, uint32_t*, std::vector*, std::vector*)); -- GitLab From bf78e0c875dab3586300d2ac73403dcc214e49d5 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 21 Jul 2023 18:43:36 +0000 Subject: [PATCH 0330/1187] [sf] add CtsSurfaceControlTests and FrameRateOverrideTest to SF presubmit Bug: 292166769 Fixes: 292293573 Test: confirm new tests are running in presubmit Change-Id: I637f76dadfc0282a1077764e86c6fc5ae36ca80e --- services/surfaceflinger/TEST_MAPPING | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/services/surfaceflinger/TEST_MAPPING b/services/surfaceflinger/TEST_MAPPING index fc6c4f3b1f..b7115207ac 100644 --- a/services/surfaceflinger/TEST_MAPPING +++ b/services/surfaceflinger/TEST_MAPPING @@ -13,6 +13,20 @@ }, { "name": "libscheduler_test" + }, + { + "name": "CtsGraphicsTestCases", + "options": [ + { + "include-filter": "android.graphics.cts.VulkanPreTransformTest" + }, + { + "include-filter": "android.graphics.cts.FrameRateOverrideTest" + } + ] + }, + { + "name": "CtsSurfaceControlTests" } ], "hwasan-presubmit": [ -- GitLab From 827d1acbe3249c2dce1ee667c5eafcdc0ffc57d2 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 21 Jul 2023 16:37:51 -0700 Subject: [PATCH 0331/1187] Change debug logs to info These debug logs currently don't show up in the logcat. Change them to INFO level so that they are useful. This can be observed by enabling some of the input logs and checking logcat. Bug: 282236272 Test: logcatcolor -b all | grep -i input Change-Id: Ied3af6edc3fb5e4c3cb773131eabd1851bc6f83e --- .../dispatcher/InputDispatcher.cpp | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index c80cf4c4ae..2923a3cfa7 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3581,8 +3581,8 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const KeyEntry& keyEntry = static_cast(eventEntry); std::array hmac = getSignature(keyEntry, *dispatchEntry); if (DEBUG_OUTBOUND_EVENT_DETAILS) { - LOG(DEBUG) << "Publishing " << *dispatchEntry << " to " - << connection->getInputChannelName(); + LOG(INFO) << "Publishing " << *dispatchEntry << " to " + << connection->getInputChannelName(); } // Publish the key event. @@ -3600,8 +3600,8 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, case EventEntry::Type::MOTION: { if (DEBUG_OUTBOUND_EVENT_DETAILS) { - LOG(DEBUG) << "Publishing " << *dispatchEntry << " to " - << connection->getInputChannelName(); + LOG(INFO) << "Publishing " << *dispatchEntry << " to " + << connection->getInputChannelName(); } status = publishMotionEvent(*connection, *dispatchEntry); break; @@ -3760,8 +3760,8 @@ void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, const std::shared_ptr& connection, bool notify) { if (DEBUG_DISPATCH_CYCLE) { - LOG(DEBUG) << "channel '" << connection->getInputChannelName() << "'~ " << __func__ - << " - notify=" << toString(notify); + LOG(INFO) << "channel '" << connection->getInputChannelName() << "'~ " << __func__ + << " - notify=" << toString(notify); } // Clear the dispatch queues. @@ -4538,10 +4538,10 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev } if (debugInboundEventDetails()) { - LOG(DEBUG) << __func__ << ": targetUid=" << toString(targetUid, &uidString) - << ", syncMode=" << ftl::enum_string(syncMode) << ", timeout=" << timeout.count() - << "ms, policyFlags=0x" << std::hex << policyFlags << std::dec - << ", event=" << *event; + LOG(INFO) << __func__ << ": targetUid=" << toString(targetUid, &uidString) + << ", syncMode=" << ftl::enum_string(syncMode) << ", timeout=" << timeout.count() + << "ms, policyFlags=0x" << std::hex << policyFlags << std::dec + << ", event=" << *event; } nsecs_t endTime = now() + std::chrono::duration_cast(timeout).count(); @@ -4692,7 +4692,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev bool needWake = false; while (!injectedEntries.empty()) { if (DEBUG_INJECTION) { - LOG(DEBUG) << "Injecting " << injectedEntries.front()->getDescription(); + LOG(INFO) << "Injecting " << injectedEntries.front()->getDescription(); } needWake |= enqueueInboundEventLocked(std::move(injectedEntries.front())); injectedEntries.pop(); @@ -4756,8 +4756,8 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev } // release lock if (DEBUG_INJECTION) { - LOG(DEBUG) << "injectInputEvent - Finished with result " - << ftl::enum_string(injectionResult); + LOG(INFO) << "injectInputEvent - Finished with result " + << ftl::enum_string(injectionResult); } return injectionResult; @@ -4801,8 +4801,8 @@ void InputDispatcher::setInjectionResult(EventEntry& entry, InjectionState* injectionState = entry.injectionState; if (injectionState) { if (DEBUG_INJECTION) { - LOG(DEBUG) << "Setting input event injection result to " - << ftl::enum_string(injectionResult); + LOG(INFO) << "Setting input event injection result to " + << ftl::enum_string(injectionResult); } if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) { @@ -5409,8 +5409,8 @@ bool InputDispatcher::transferTouchFocus(const sp& fromToken, const sp< } std::set deviceIds = touchedWindow->getTouchingDeviceIds(); if (deviceIds.size() != 1) { - LOG(DEBUG) << "Can't transfer touch. Currently touching devices: " << dumpSet(deviceIds) - << " for window: " << touchedWindow->dump(); + LOG(INFO) << "Can't transfer touch. Currently touching devices: " << dumpSet(deviceIds) + << " for window: " << touchedWindow->dump(); return false; } const int32_t deviceId = *deviceIds.begin(); -- GitLab From d9c4008a731999a141faa518b42fc3385c5540f6 Mon Sep 17 00:00:00 2001 From: Yeabkal Wubshit Date: Fri, 21 Jul 2023 19:11:52 -0700 Subject: [PATCH 0332/1187] Improve VelocityTracker bad pointer ID crash log This helps developers better understand the crash cause when crashes are caused by bad pointer IDs given to VelocityTracker Bug: 292300437 Test: atest libinput_tests Change-Id: I3108f5b378ed2d9e92102cc7b38045058e02ec1f --- libs/input/VelocityTracker.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index 87c7768f25..8704eee73d 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -16,10 +16,11 @@ #define LOG_TAG "VelocityTracker" -#include +#include #include #include #include +#include #include #include @@ -243,6 +244,11 @@ void VelocityTracker::clearPointer(int32_t pointerId) { void VelocityTracker::addMovement(nsecs_t eventTime, int32_t pointerId, int32_t axis, float position) { + if (pointerId < 0 || pointerId > MAX_POINTER_ID) { + LOG(FATAL) << "Invalid pointer ID " << pointerId << " for axis " + << MotionEvent::getLabel(axis); + } + if (mCurrentPointerIdBits.hasBit(pointerId) && std::chrono::nanoseconds(eventTime - mLastEventTime) > ASSUME_POINTER_STOPPED_TIME) { ALOGD_IF(DEBUG_VELOCITY, "VelocityTracker: stopped for %s, clearing state.", -- GitLab From 0d3e763b76e4023ccf85aef48043dd759d91e3a0 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 24 Jul 2023 17:09:16 +0000 Subject: [PATCH 0333/1187] libgui: add SF presubmit tests to libgui Bug: 292293573 Change-Id: I26e6d5571b025f46610d0e51587256d0bc92b6ce Test: presubmit --- libs/gui/TEST_MAPPING | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/gui/TEST_MAPPING b/libs/gui/TEST_MAPPING index a4d9e77351..a590c86ceb 100644 --- a/libs/gui/TEST_MAPPING +++ b/libs/gui/TEST_MAPPING @@ -2,6 +2,9 @@ "imports": [ { "path": "frameworks/native/libs/nativewindow" + }, + { + "path": "frameworks/native/services/surfaceflinger" } ], "presubmit": [ -- GitLab From bfcc610254119b6a61548357598aa383b06966b1 Mon Sep 17 00:00:00 2001 From: Huihong Luo Date: Thu, 23 Mar 2023 17:29:52 +0000 Subject: [PATCH 0334/1187] Generate texture pool asynchronously This improves performance by moving allocateHelper to a different thread, which is launched early so that the allocation is ready when it is needed. In addition, each display will only need at most one additional texture per frame, so replace the idea of a minimum pool with making sure there is either at least one texture in the pool or a future which will generate one. Bug: 256184546 Test: atest libcompositionengine_test Change-Id: Icb92a85c07b9f2911d1365aa9bbc8d0750a8c116 --- .../impl/planner/TexturePool.h | 17 +++-- .../src/planner/TexturePool.cpp | 64 +++++++++++++++---- .../tests/planner/TexturePoolTest.cpp | 33 ++++------ 3 files changed, 71 insertions(+), 43 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h index d607c75325..9f6141a1b1 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/TexturePool.h @@ -66,7 +66,7 @@ public: TexturePool(renderengine::RenderEngine& renderEngine) : mRenderEngine(renderEngine), mEnabled(false) {} - virtual ~TexturePool() = default; + virtual ~TexturePool(); // Sets the display size for the texture pool. // This will trigger a reallocation for all remaining textures in the pool. @@ -83,11 +83,10 @@ public: // be held by the pool. This is useful when the active display changes. void setEnabled(bool enable); - void dump(std::string& out) const; + void dump(std::string& out) const EXCLUDES(mMutex); protected: // Proteted visibility so that they can be used for testing - const static constexpr size_t kMinPoolSize = 3; const static constexpr size_t kMaxPoolSize = 4; struct Entry { @@ -96,16 +95,20 @@ protected: }; std::deque mPool; + std::future> mGenTextureFuture; private: - std::shared_ptr genTexture(); + std::shared_ptr genTexture(ui::Size size); // Returns a previously borrowed texture to the pool. void returnTexture(std::shared_ptr&& texture, const sp& fence); - void allocatePool(); - renderengine::RenderEngine& mRenderEngine; - ui::Size mSize; + void genTextureAsyncIfNeeded() REQUIRES(mMutex); + void resetPool() REQUIRES(mMutex); + renderengine::RenderEngine& mRenderEngine GUARDED_BY(mRenderEngineMutex); + ui::Size mSize GUARDED_BY(mMutex); bool mEnabled; + mutable std::mutex mMutex; + mutable std::mutex mRenderEngineMutex; }; } // namespace android::compositionengine::impl::planner diff --git a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp index 54ecb5691d..10f58cea5d 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/TexturePool.cpp @@ -25,31 +25,61 @@ namespace android::compositionengine::impl::planner { -void TexturePool::allocatePool() { +TexturePool::~TexturePool() { + if (mGenTextureFuture.valid()) { + mGenTextureFuture.get(); + } +} + +void TexturePool::resetPool() { + if (mGenTextureFuture.valid()) { + mGenTextureFuture.get(); + } mPool.clear(); - if (mEnabled && mSize.isValid()) { - mPool.resize(kMinPoolSize); - std::generate_n(mPool.begin(), kMinPoolSize, [&]() { - return Entry{genTexture(), nullptr}; - }); + genTextureAsyncIfNeeded(); +} + +// Generate a new texture asynchronously so it will not require allocation on the main +// thread. +void TexturePool::genTextureAsyncIfNeeded() { + if (mEnabled && mSize.isValid() && !mGenTextureFuture.valid()) { + mGenTextureFuture = std::async( + std::launch::async, [&](ui::Size size) { return genTexture(size); }, mSize); } } void TexturePool::setDisplaySize(ui::Size size) { + std::lock_guard lock(mMutex); if (mSize == size) { return; } mSize = size; - allocatePool(); + resetPool(); } std::shared_ptr TexturePool::borrowTexture() { if (mPool.empty()) { - return std::make_shared(*this, genTexture(), nullptr); + std::lock_guard lock(mMutex); + std::shared_ptr tex; + if (mGenTextureFuture.valid()) { + tex = std::make_shared(*this, mGenTextureFuture.get(), nullptr); + } else { + tex = std::make_shared(*this, genTexture(mSize), nullptr); + } + // Speculatively generate a new texture, so that the next call does not need + // to wait for allocation. + genTextureAsyncIfNeeded(); + return tex; } const auto entry = mPool.front(); mPool.pop_front(); + if (mPool.empty()) { + std::lock_guard lock(mMutex); + // Similiarly generate a new texture when lending out the last entry, so that + // the next call does not need to wait for allocation. + genTextureAsyncIfNeeded(); + } return std::make_shared(*this, entry.texture, entry.fence); } @@ -60,6 +90,8 @@ void TexturePool::returnTexture(std::shared_ptr&& return; } + std::lock_guard lock(mMutex); + // Or the texture on the floor if the pool is no longer tracking textures of the same size. if (static_cast(texture->getBuffer()->getWidth()) != mSize.getWidth() || static_cast(texture->getBuffer()->getHeight()) != mSize.getHeight()) { @@ -80,13 +112,14 @@ void TexturePool::returnTexture(std::shared_ptr&& mPool.push_back({std::move(texture), fence}); } -std::shared_ptr TexturePool::genTexture() { - LOG_ALWAYS_FATAL_IF(!mSize.isValid(), "Attempted to generate texture with invalid size"); +std::shared_ptr TexturePool::genTexture(ui::Size size) { + std::lock_guard lock(mRenderEngineMutex); + LOG_ALWAYS_FATAL_IF(!size.isValid(), "Attempted to generate texture with invalid size"); return std::make_shared< renderengine::impl:: ExternalTexture>(sp:: - make(static_cast(mSize.getWidth()), - static_cast(mSize.getHeight()), + make(static_cast(size.getWidth()), + static_cast(size.getHeight()), HAL_PIXEL_FORMAT_RGBA_8888, 1U, static_cast( GraphicBuffer::USAGE_HW_RENDER | @@ -100,13 +133,16 @@ std::shared_ptr TexturePool::genTexture() { void TexturePool::setEnabled(bool enabled) { mEnabled = enabled; - allocatePool(); + + std::lock_guard lock(mMutex); + resetPool(); } void TexturePool::dump(std::string& out) const { + std::lock_guard lock(mMutex); base::StringAppendF(&out, "TexturePool (%s) has %zu buffers of size [%" PRId32 ", %" PRId32 "]\n", mEnabled ? "enabled" : "disabled", mPool.size(), mSize.width, mSize.height); } -} // namespace android::compositionengine::impl::planner \ No newline at end of file +} // namespace android::compositionengine::impl::planner diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp index 6fc90fe5e5..494a9f4df0 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/TexturePoolTest.cpp @@ -32,9 +32,9 @@ class TestableTexturePool : public TexturePool { public: TestableTexturePool(renderengine::RenderEngine& renderEngine) : TexturePool(renderEngine) {} - size_t getMinPoolSize() const { return kMinPoolSize; } size_t getMaxPoolSize() const { return kMaxPoolSize; } size_t getPoolSize() const { return mPool.size(); } + size_t isGenTextureFutureValid() const { return mGenTextureFuture.valid(); } }; struct TexturePoolTest : public testing::Test { @@ -56,16 +56,8 @@ struct TexturePoolTest : public testing::Test { TestableTexturePool mTexturePool = TestableTexturePool(mRenderEngine); }; -TEST_F(TexturePoolTest, preallocatesMinPool) { - EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); -} - -TEST_F(TexturePoolTest, doesNotAllocateBeyondMinPool) { - for (size_t i = 0; i < mTexturePool.getMinPoolSize() + 1; i++) { - auto texture = mTexturePool.borrowTexture(); - } - - EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); +TEST_F(TexturePoolTest, preallocatesZeroSizePool) { + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); } TEST_F(TexturePoolTest, cyclesUpToMaxPoolSize) { @@ -119,10 +111,10 @@ TEST_F(TexturePoolTest, reallocatesWhenDisplaySizeChanges) { static_cast(texture->get()->getBuffer()->getHeight())); mTexturePool.setDisplaySize(kDisplaySizeTwo); - EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); texture.reset(); // When the texture is returned to the pool, the pool now destroys it. - EXPECT_EQ(mTexturePool.getMinPoolSize(), mTexturePool.getPoolSize()); + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); texture = mTexturePool.borrowTexture(); EXPECT_EQ(kDisplaySizeTwo.getWidth(), @@ -132,14 +124,11 @@ TEST_F(TexturePoolTest, reallocatesWhenDisplaySizeChanges) { } TEST_F(TexturePoolTest, freesBuffersWhenDisabled) { - EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); - std::deque> textures; - for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) { + for (size_t i = 0; i < 2; i++) { textures.emplace_back(mTexturePool.borrowTexture()); } - EXPECT_EQ(mTexturePool.getPoolSize(), 1u); mTexturePool.setEnabled(false); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); @@ -148,12 +137,11 @@ TEST_F(TexturePoolTest, freesBuffersWhenDisabled) { } TEST_F(TexturePoolTest, doesNotHoldBuffersWhenDisabled) { - EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); mTexturePool.setEnabled(false); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); std::deque> textures; - for (size_t i = 0; i < mTexturePool.getMinPoolSize() - 1; i++) { + for (size_t i = 0; i < 2; i++) { textures.emplace_back(mTexturePool.borrowTexture()); } @@ -162,12 +150,13 @@ TEST_F(TexturePoolTest, doesNotHoldBuffersWhenDisabled) { EXPECT_EQ(mTexturePool.getPoolSize(), 0u); } -TEST_F(TexturePoolTest, reallocatesWhenReEnabled) { - EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); +TEST_F(TexturePoolTest, genFutureWhenReEnabled) { mTexturePool.setEnabled(false); EXPECT_EQ(mTexturePool.getPoolSize(), 0u); + EXPECT_FALSE(mTexturePool.isGenTextureFutureValid()); mTexturePool.setEnabled(true); - EXPECT_EQ(mTexturePool.getPoolSize(), mTexturePool.getMinPoolSize()); + EXPECT_EQ(mTexturePool.getPoolSize(), 0u); + EXPECT_TRUE(mTexturePool.isGenTextureFutureValid()); } } // namespace -- GitLab From fd0c1b4b42a0b0d946718dc7819281b290320e81 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Mon, 24 Jul 2023 14:19:46 -0500 Subject: [PATCH 0335/1187] Log fatal if transaction callbacks are called more than once Bug: 288781573 Test: presubmits Change-Id: I424bf89cc3fd52df2460a6028f71b2a988b783b4 --- libs/gui/SurfaceComposerClient.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 5bc05ef0d8..dcadf07d06 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1901,8 +1901,29 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTrans CallbackId::Type callbackType) { auto listener = TransactionCompletedListener::getInstance(); - auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1, - std::placeholders::_2, std::placeholders::_3); + TransactionCompletedCallback callbackWithContext = + [called = false, callback, + callbackContext](nsecs_t latchTime, const sp& presentFence, + const std::vector& stats) mutable { + if (called) { + std::stringstream stream; + auto it = stats.begin(); + if (it != stats.end()) { + stream << it->surfaceControl->getName(); + it++; + } + while (it != stats.end()) { + stream << ", " << it->surfaceControl->getName(); + it++; + } + LOG_ALWAYS_FATAL("Transaction callback called more than once. SurfaceControls: " + "%s", + stream.str().c_str()); + } + callback(callbackContext, latchTime, presentFence, stats); + called = true; + }; + const auto& surfaceControls = mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls; -- GitLab From 239f45348de7368078b525efbf6fac1085a433ab Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Thu, 20 Jul 2023 20:04:42 -0700 Subject: [PATCH 0336/1187] Add InlineStdAllocator::rebind struct member Newer versions of libc++ (as well as libstdc++) require this of allocators. This member is needed for std::allocator_traits>::rebind_alloc, which contains a typedef for InlineStdAllocator. I believe this requirement was always present, but libc++ is checking for it now. AFAICT, the STL wouldn't be able to construct an InlineStdAllocator, because there is no default constructor, and the copy constructor wouldn't accept a reference to InlineStdAllocator. Perhaps that's OK because this allocator is only used with std::vector, not (say) std::list or std::map, which actually need to allocate internal node types. std::allocator_traits::rebind_alloc can automatically handle custom allocators with type parameters, but not with non-type parameters (i.e. It can't handle "size_t SIZE = 4"). See https://stackoverflow.com/a/34863387. Bug: b/175635923 Test: treehugger Change-Id: I0cceb47ab780414202cef1ed54fa7deb3773d01a --- libs/ui/include/ui/FatVector.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h index cb61e6a320..494272b1a8 100644 --- a/libs/ui/include/ui/FatVector.h +++ b/libs/ui/include/ui/FatVector.h @@ -65,6 +65,17 @@ public: free(p); } } + + // The STL checks that this member type is present so that + // std::allocator_traits>::rebind_alloc + // works. std::vector won't be able to construct an + // InlineStdAllocator, because InlineStdAllocator has no + // default constructor, but vector presumably doesn't rebind the allocator + // because it doesn't allocate internal node types. + template + struct rebind { + typedef InlineStdAllocator other; + }; Allocation& mAllocation; }; -- GitLab From 62e35d62263b7f24fa524522c483770a5d4c7b70 Mon Sep 17 00:00:00 2001 From: Ahmad Khalil Date: Mon, 24 Jul 2023 19:56:20 +0000 Subject: [PATCH 0337/1187] Extract vibrator cts tests from CtsOsTestCases Trigger the vibrator cts tests from vibratorservice TEST_MAPPING file. Fix: 290746931 Test: atest CtsVibratorTestCases Change-Id: Ie161c9a2a6591118beb6b7f9e80d42151104d91a --- services/vibratorservice/TEST_MAPPING | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/vibratorservice/TEST_MAPPING b/services/vibratorservice/TEST_MAPPING index b033adbd05..1eb3a581b7 100644 --- a/services/vibratorservice/TEST_MAPPING +++ b/services/vibratorservice/TEST_MAPPING @@ -3,5 +3,10 @@ { "name": "libvibratorservice_test" } + ], + "imports": [ + { + "path": "cts/tests/vibrator" + } ] } -- GitLab From c30dbbba87eed80e4013ce2fda8cc4e670b54191 Mon Sep 17 00:00:00 2001 From: Nataniel Borges Date: Tue, 25 Jul 2023 11:52:26 +0000 Subject: [PATCH 0338/1187] Use only subset of WM CTS tests on inputflinger Bug: 290634145 Test: atest CtsWindowManagerDeviceWindow Change-Id: I9ff656bd28ae40ca323604371748cb79c53e3e4c --- services/inputflinger/TEST_MAPPING | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING index ca00e7dac2..c2da5bafaf 100644 --- a/services/inputflinger/TEST_MAPPING +++ b/services/inputflinger/TEST_MAPPING @@ -1,10 +1,10 @@ { "presubmit": [ { - "name": "CtsWindowManagerDeviceTestCases", + "name": "CtsWindowManagerDeviceWindow", "options": [ { - "include-filter": "android.server.wm.WindowInputTests" + "include-filter": "android.server.wm.window.WindowInputTests" } ] }, @@ -150,10 +150,10 @@ ], "hwasan-postsubmit": [ { - "name": "CtsWindowManagerDeviceTestCases", + "name": "CtsWindowManagerDeviceWindow", "options": [ { - "include-filter": "android.server.wm.WindowInputTests" + "include-filter": "android.server.wm.window.WindowInputTests" } ] }, -- GitLab From eed9ac11734ddb2798ebf44ee8691449a961ac09 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 25 Jul 2023 13:45:47 +0000 Subject: [PATCH 0339/1187] Fix unimplemented codepath in conversion to async binder interface Bug: 291764260 Test: atest aidl_integration_test Change-Id: I348ab109fd541c51ec51c9edec10100949dcaac7 --- libs/binder/rust/binder_tokio/lib.rs | 7 ++++++- libs/binder/rust/src/binder.rs | 12 +----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs index 2d2bf7c582..1dc0b2471d 100644 --- a/libs/binder/rust/binder_tokio/lib.rs +++ b/libs/binder/rust/binder_tokio/lib.rs @@ -103,7 +103,12 @@ impl BinderAsyncPool for Tokio { // // This shouldn't cause issues with blocking the thread as only one task will run in a // call to `block_on`, so there aren't other tasks to block. - let result = spawn_me(); + // + // If the `block_in_place` call fails, then you are driving a current-thread runtime on + // the binder threadpool. Instead, it is recommended to use `TokioRuntime` when + // the runtime is a current-thread runtime, as the current-thread runtime can be driven + // only by `Runtime::block_on` calls and not by `Handle::block_on`. + let result = tokio::task::block_in_place(spawn_me); Box::pin(after_spawn(result)) } else { let handle = tokio::task::spawn_blocking(spawn_me); diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 0bd0781cf4..463c210316 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -1023,17 +1023,7 @@ macro_rules! declare_binder_interface { } if ibinder.associate_class(<$native as $crate::binder_impl::Remotable>::get_class()) { - let service: std::result::Result<$crate::binder_impl::Binder<$native>, $crate::StatusCode> = - std::convert::TryFrom::try_from(ibinder.clone()); - if let Ok(service) = service { - // We were able to associate with our expected class and - // the service is local. - todo!() - //return Ok($crate::Strong::new(Box::new(service))); - } else { - // Service is remote - return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?))); - } + return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?))); } Err($crate::StatusCode::BAD_TYPE.into()) -- GitLab From 45f243ddbc99c052b7061841a61b78b97969acc3 Mon Sep 17 00:00:00 2001 From: Nataniel Borges Date: Tue, 25 Jul 2023 14:50:20 +0000 Subject: [PATCH 0340/1187] Use only subset of WM CTS tests on inputflinger Bug: 290634145 Test: atest CtsWindowManagerDeviceWindow Change-Id: Ie8c7174edd433bd101eb7e02416f30bf4a555159 --- services/inputflinger/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index f749b0e5b5..18f6dbc1e1 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -249,7 +249,7 @@ phony { "inputflinger_input_classifier_fuzzer", // Java/Kotlin targets - "CtsWindowManagerDeviceTestCases", + "CtsWindowManagerDeviceWindow", "InputTests", "CtsHardwareTestCases", "CtsInputTestCases", -- GitLab From 5089908c7886f554beb1004f0ff976ddf922e8b4 Mon Sep 17 00:00:00 2001 From: Parth Sane Date: Tue, 4 Jul 2023 16:20:03 +0000 Subject: [PATCH 0341/1187] Clean up atrace.rc Moving boot trace related things to perfetto.rc Ensure that tracing is turned off by default only if boot tracing isn't enabled. Bug: 271576143 Test: Manually checked that tracing works Change-Id: I89e2bc0abe111bed4a230619afa544c214c10e6e --- cmds/atrace/atrace.rc | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index f1d8c72d85..fc0801cce8 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -228,10 +228,6 @@ on late-init chmod 0666 /sys/kernel/debug/tracing/events/thermal/cdev_update/enable chmod 0666 /sys/kernel/tracing/events/thermal/cdev_update/enable -# Tracing disabled by default - write /sys/kernel/debug/tracing/tracing_on 0 - write /sys/kernel/tracing/tracing_on 0 - # Read and truncate the kernel trace. chmod 0666 /sys/kernel/debug/tracing/trace chmod 0666 /sys/kernel/tracing/trace @@ -310,18 +306,9 @@ on late-init chmod 0666 /sys/kernel/tracing/events/synthetic/suspend_resume_minimal/enable chmod 0666 /sys/kernel/debug/tracing/events/synthetic/suspend_resume_minimal/enable -on late-init && property:ro.boot.fastboot.boottrace=enabled - setprop debug.atrace.tags.enableflags 802922 - setprop persist.traced.enable 0 - write /sys/kernel/tracing/events/binder/binder_transaction/enable 1 - write /sys/kernel/tracing/events/binder/binder_transaction_received/enable 1 - write /sys/kernel/tracing/events/binder/binder_transaction_alloc_buf/enable 1 - write /sys/kernel/tracing/events/binder/binder_set_priority/enable 1 - write /sys/kernel/tracing/events/binder/binder_lock/enable 1 - write /sys/kernel/tracing/events/binder/binder_locked/enable 1 - write /sys/kernel/tracing/events/binder/binder_unlock/enable 1 - write /sys/kernel/debug/tracing/tracing_on 1 - write /sys/kernel/tracing/tracing_on 1 +on late-init && property:ro.boot.fastboot.boottrace= + write /sys/kernel/debug/tracing/tracing_on 0 + write /sys/kernel/tracing/tracing_on 0 # Only create the tracing instance if persist.mm_events.enabled # Attempting to remove the tracing instance after it has been created @@ -534,7 +521,6 @@ on late-init && property:ro.boot.hypervisor.vm.supported=1 chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_mem_abort/id chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_mem_abort/id - on property:persist.debug.atrace.boottrace=1 start boottrace @@ -543,17 +529,3 @@ service boottrace /system/bin/atrace --async_start -f /data/misc/boottrace/categ user root disabled oneshot - -on property:sys.boot_completed=1 && property:ro.boot.fastboot.boottrace=enabled - setprop debug.atrace.tags.enableflags 0 - setprop persist.traced.enable 1 - write /sys/kernel/tracing/events/binder/binder_transaction/enable 0 - write /sys/kernel/tracing/events/binder/binder_transaction_received/enable 0 - write /sys/kernel/tracing/events/binder/binder_transaction_alloc_buf/enable 0 - write /sys/kernel/tracing/events/binder/binder_set_priority/enable 0 - write /sys/kernel/tracing/events/binder/binder_lock/enable 0 - write /sys/kernel/tracing/events/binder/binder_locked/enable 0 - write /sys/kernel/tracing/events/binder/binder_unlock/enable 0 - write /sys/kernel/debug/tracing/tracing_on 0 - write /sys/kernel/tracing/tracing_on 0 - -- GitLab From 82b5ba49461487ba52872ad94e24b2d895a96aa5 Mon Sep 17 00:00:00 2001 From: Parth Sane Date: Tue, 4 Jul 2023 16:20:03 +0000 Subject: [PATCH 0342/1187] Clean up atrace.rc Moving boot trace related things to perfetto.rc Ensure that tracing is turned off by default only if boot tracing isn't enabled. Bug: 271576143 Test: Manually checked that tracing works Change-Id: I89e2bc0abe111bed4a230619afa544c214c10e6e Merged-In: I89e2bc0abe111bed4a230619afa544c214c10e6e --- cmds/atrace/atrace.rc | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index c3cf2c2a60..fc0801cce8 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -228,10 +228,6 @@ on late-init chmod 0666 /sys/kernel/debug/tracing/events/thermal/cdev_update/enable chmod 0666 /sys/kernel/tracing/events/thermal/cdev_update/enable -# Tracing disabled by default - write /sys/kernel/debug/tracing/tracing_on 0 - write /sys/kernel/tracing/tracing_on 0 - # Read and truncate the kernel trace. chmod 0666 /sys/kernel/debug/tracing/trace chmod 0666 /sys/kernel/tracing/trace @@ -310,11 +306,9 @@ on late-init chmod 0666 /sys/kernel/tracing/events/synthetic/suspend_resume_minimal/enable chmod 0666 /sys/kernel/debug/tracing/events/synthetic/suspend_resume_minimal/enable -on late-init && property:ro.boot.fastboot.boottrace=enabled - setprop debug.atrace.tags.enableflags 802922 - setprop persist.traced.enable 0 - write /sys/kernel/debug/tracing/tracing_on 1 - write /sys/kernel/tracing/tracing_on 1 +on late-init && property:ro.boot.fastboot.boottrace= + write /sys/kernel/debug/tracing/tracing_on 0 + write /sys/kernel/tracing/tracing_on 0 # Only create the tracing instance if persist.mm_events.enabled # Attempting to remove the tracing instance after it has been created @@ -527,7 +521,6 @@ on late-init && property:ro.boot.hypervisor.vm.supported=1 chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_mem_abort/id chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_mem_abort/id - on property:persist.debug.atrace.boottrace=1 start boottrace @@ -536,10 +529,3 @@ service boottrace /system/bin/atrace --async_start -f /data/misc/boottrace/categ user root disabled oneshot - -on property:sys.boot_completed=1 && property:ro.boot.fastboot.boottrace=enabled - setprop debug.atrace.tags.enableflags 0 - setprop persist.traced.enable 1 - write /sys/kernel/debug/tracing/tracing_on 0 - write /sys/kernel/tracing/tracing_on 0 - -- GitLab From 5da65608206cddeafae2ecf51d0d708c66d740ee Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Thu, 29 Jun 2023 10:12:50 -0700 Subject: [PATCH 0343/1187] Fix init list order. Bug: 145210666 Test: build with aosp/2644915 Test: binder_rpc_test Change-Id: I169fe7526c58d2473f39340022e721d3ade4c209 --- libs/binder/tests/binderRpcTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index d352ce5bca..38c7f7cb6f 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -674,7 +674,7 @@ TEST_P(BinderRpc, SessionWithIncomingThreadpoolDoesntLeak) { // session 0 - will check for leaks in destrutor of proc // session 1 - we want to make sure it gets deleted when we drop all references to it auto proc = createRpcTestSocketServerProcess( - {.numThreads = 1, .numIncomingConnectionsBySession = {0, 1}, .numSessions = 2}); + {.numThreads = 1, .numSessions = 2, .numIncomingConnectionsBySession = {0, 1}}); wp session = proc.proc->sessions.at(1).session; -- GitLab From 88790f34d48e84b349014fc10b275385d5037d8e Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 21 Jul 2023 01:25:14 +0000 Subject: [PATCH 0344/1187] Remove the concept of target dataspace This is only needed for configuring colorspace agnostic dataspaces, but no device does that. For colorspace agnostic layers, it's sufficient to just use the colormode dataspace, with the possible exception of HDR where we can preserve some bespoke logic, so we can just get rid of target dataspaces and any associated plumbing. Bug: 292162273 Test: builds Test: libsurfaceflinger_unittest Test: libcompositionengine_test Change-Id: I319bb354e80e3ad1eaaacd896b897e6696f96588 --- .../CompositionRefreshArgs.h | 3 - .../compositionengine/DisplayColorProfile.h | 4 - .../include/compositionengine/Output.h | 1 - .../impl/DisplayColorProfile.h | 1 - .../impl/OutputCompositionState.h | 3 - .../mock/DisplayColorProfile.h | 2 - .../CompositionEngine/src/Display.cpp | 7 +- .../src/DisplayColorProfile.cpp | 11 --- .../CompositionEngine/src/Output.cpp | 14 +-- .../src/OutputCompositionState.cpp | 1 - .../CompositionEngine/src/OutputLayer.cpp | 7 +- .../tests/DisplayColorProfileTest.cpp | 24 ----- .../CompositionEngine/tests/DisplayTest.cpp | 23 ++--- .../tests/OutputLayerTest.cpp | 11 ++- .../CompositionEngine/tests/OutputTest.cpp | 90 ++----------------- services/surfaceflinger/SurfaceFlinger.cpp | 9 +- services/surfaceflinger/SurfaceFlinger.h | 1 - .../SurfaceFlingerProperties.cpp | 8 -- .../surfaceflinger/SurfaceFlingerProperties.h | 3 - .../sysprop/SurfaceFlingerProperties.sysprop | 5 +- 20 files changed, 36 insertions(+), 192 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index 09bc46747a..1a8644e9fe 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -67,9 +67,6 @@ struct CompositionRefreshArgs { // Controls how the color mode is chosen for an output OutputColorSetting outputColorSetting{OutputColorSetting::kEnhanced}; - // If not Dataspace::UNKNOWN, overrides the dataspace on each output - ui::Dataspace colorSpaceAgnosticDataspace{ui::Dataspace::UNKNOWN}; - // Forces a color mode on the outputs being refreshed ui::ColorMode forceOutputColorMode{ui::ColorMode::NATIVE}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h index df44e75625..9c80cacf6f 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h @@ -87,10 +87,6 @@ public: // Returns true if HWC for this profile supports the dataspace virtual bool isDataspaceSupported(ui::Dataspace) const = 0; - // Returns the target dataspace for picked color mode and dataspace - virtual ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace, - ui::Dataspace colorSpaceAgnosticDataspace) const = 0; - // Debugging virtual void dump(std::string&) const = 0; }; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h index a3d86398cf..370c7cf223 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h @@ -136,7 +136,6 @@ public: ui::ColorMode mode{ui::ColorMode::NATIVE}; ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC}; - ui::Dataspace colorSpaceAgnosticDataspace{ui::Dataspace::UNKNOWN}; }; // Use internally to incrementally compute visibility/coverage diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h index 9bc0e681c7..3aad04c1a3 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h @@ -55,7 +55,6 @@ public: const HdrCapabilities& getHdrCapabilities() const override; bool isDataspaceSupported(ui::Dataspace) const override; - ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace) const override; void dump(std::string&) const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 28c6e92b06..6cb1e7e4c2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -116,9 +116,6 @@ struct OutputCompositionState { // Current active dataspace ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; - // Current target dataspace - ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN}; - std::optional previousDeviceRequestedChanges{}; bool previousDeviceRequestedSuccess = false; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h index 1aaebea295..a9045211af 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h @@ -43,8 +43,6 @@ public: MOCK_CONST_METHOD0(getHdrCapabilities, const HdrCapabilities&()); MOCK_CONST_METHOD1(isDataspaceSupported, bool(ui::Dataspace)); - MOCK_CONST_METHOD3(getTargetDataspace, - ui::Dataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace)); MOCK_CONST_METHOD1(dump, void(std::string&)); }; diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 85fc09549b..f2acfc9e6e 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -107,14 +107,9 @@ void Display::setColorTransform(const compositionengine::CompositionRefreshArgs& } void Display::setColorProfile(const ColorProfile& colorProfile) { - const ui::Dataspace targetDataspace = - getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace, - colorProfile.colorSpaceAgnosticDataspace); - if (colorProfile.mode == getState().colorMode && colorProfile.dataspace == getState().dataspace && - colorProfile.renderIntent == getState().renderIntent && - targetDataspace == getState().targetDataspace) { + colorProfile.renderIntent == getState().renderIntent) { return; } diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp index a7c45129b1..8f67f3683a 100644 --- a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp @@ -391,17 +391,6 @@ bool DisplayColorProfile::isDataspaceSupported(Dataspace dataspace) const { } } -ui::Dataspace DisplayColorProfile::getTargetDataspace(ColorMode mode, Dataspace dataspace, - Dataspace colorSpaceAgnosticDataspace) const { - if (isHdrColorMode(mode)) { - return Dataspace::UNKNOWN; - } - if (colorSpaceAgnosticDataspace != ui::Dataspace::UNKNOWN) { - return colorSpaceAgnosticDataspace; - } - return dataspace; -} - void DisplayColorProfile::dump(std::string& out) const { out.append(" Composition Display Color State:"); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 1205a2ce71..e42e27dfbb 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -261,22 +261,16 @@ void Output::setColorTransform(const compositionengine::CompositionRefreshArgs& } void Output::setColorProfile(const ColorProfile& colorProfile) { - ui::Dataspace targetDataspace = - getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace, - colorProfile.colorSpaceAgnosticDataspace); - auto& outputState = editState(); if (outputState.colorMode == colorProfile.mode && outputState.dataspace == colorProfile.dataspace && - outputState.renderIntent == colorProfile.renderIntent && - outputState.targetDataspace == targetDataspace) { + outputState.renderIntent == colorProfile.renderIntent) { return; } outputState.colorMode = colorProfile.mode; outputState.dataspace = colorProfile.dataspace; outputState.renderIntent = colorProfile.renderIntent; - outputState.targetDataspace = targetDataspace; mRenderSurface->setBufferDataspace(colorProfile.dataspace); @@ -985,8 +979,7 @@ compositionengine::Output::ColorProfile Output::pickColorProfile( const compositionengine::CompositionRefreshArgs& refreshArgs) const { if (refreshArgs.outputColorSetting == OutputColorSetting::kUnmanaged) { return ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, - ui::RenderIntent::COLORIMETRIC, - refreshArgs.colorSpaceAgnosticDataspace}; + ui::RenderIntent::COLORIMETRIC}; } ui::Dataspace hdrDataSpace; @@ -1032,8 +1025,7 @@ compositionengine::Output::ColorProfile Output::pickColorProfile( mDisplayColorProfile->getBestColorMode(bestDataSpace, intent, &outDataSpace, &outMode, &outRenderIntent); - return ColorProfile{outMode, outDataSpace, outRenderIntent, - refreshArgs.colorSpaceAgnosticDataspace}; + return ColorProfile{outMode, outDataSpace, outRenderIntent}; } void Output::beginFrame() { diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index 9713e79fe3..39cf67165a 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -52,7 +52,6 @@ void OutputCompositionState::dump(std::string& out) const { dumpVal(out, "colorMode", toString(colorMode), colorMode); dumpVal(out, "renderIntent", toString(renderIntent), renderIntent); dumpVal(out, "dataspace", toString(dataspace), dataspace); - dumpVal(out, "targetDataspace", toString(targetDataspace), targetDataspace); out.append("\n "); dumpVal(out, "colorTransformMatrix", colorTransformMatrix); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 0ac0ecb727..b492b6a79e 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -315,9 +315,10 @@ void OutputLayer::updateCompositionState( // Determine the output dependent dataspace for this layer. If it is // colorspace agnostic, it just uses the dataspace chosen for the output to // avoid the need for color conversion. - state.dataspace = layerFEState->isColorspaceAgnostic && - outputState.targetDataspace != ui::Dataspace::UNKNOWN - ? outputState.targetDataspace + // For now, also respect the colorspace agnostic flag if we're drawing to HDR, to avoid drastic + // luminance shift. TODO(b/292162273): we should check if that's true though. + state.dataspace = layerFEState->isColorspaceAgnostic && !isHdrDataspace(outputState.dataspace) + ? outputState.dataspace : layerFEState->dataspace; // Override the dataspace transfer from 170M to sRGB if the device configuration requests this. diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp index 21b9aa93ea..b3ff2ec6a0 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp @@ -646,29 +646,5 @@ TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithHlgSuppor EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG)); } -/* - * RenderSurface::getTargetDataspace() - */ - -TEST_F(DisplayColorProfileTest, getTargetDataspaceWorks) { - auto profile = ProfileFactory::createProfileWithNoColorModeSupport(); - - // For a non-HDR colorspace with no colorSpaceAgnosticDataspace override, - // the input dataspace should be returned. - EXPECT_EQ(Dataspace::DISPLAY_P3, - profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3, - Dataspace::UNKNOWN)); - - // If colorSpaceAgnosticDataspace is set, its value should be returned - EXPECT_EQ(Dataspace::V0_SRGB, - profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3, - Dataspace::V0_SRGB)); - - // For an HDR colorspace, Dataspace::UNKNOWN should be returned. - EXPECT_EQ(Dataspace::UNKNOWN, - profile.getTargetDataspace(ColorMode::BT2100_PQ, Dataspace::BT2020_PQ, - Dataspace::UNKNOWN)); -} - } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 9be6bc2075..027004acf6 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -403,23 +403,18 @@ TEST_F(DisplaySetColorModeTest, setsModeUnlessNoChange) { mock::DisplayColorProfile* colorProfile = new StrictMock(); mDisplay->setDisplayColorProfileForTest(std::unique_ptr(colorProfile)); - EXPECT_CALL(*colorProfile, getTargetDataspace(_, _, _)) - .WillRepeatedly(Return(ui::Dataspace::UNKNOWN)); - // These values are expected to be the initial state. ASSERT_EQ(ui::ColorMode::NATIVE, mDisplay->getState().colorMode); ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().dataspace); ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay->getState().renderIntent); - ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace); // Otherwise if the values are unchanged, nothing happens mDisplay->setColorProfile(ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, - ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN}); + ui::RenderIntent::COLORIMETRIC}); EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay->getState().colorMode); EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().dataspace); EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay->getState().renderIntent); - EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace); // Otherwise if the values are different, updates happen EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1); @@ -429,13 +424,11 @@ TEST_F(DisplaySetColorModeTest, setsModeUnlessNoChange) { .Times(1); mDisplay->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, - ui::Dataspace::UNKNOWN}); + ui::RenderIntent::TONE_MAP_COLORIMETRIC}); EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mDisplay->getState().colorMode); EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mDisplay->getState().dataspace); EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mDisplay->getState().renderIntent); - EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace); } TEST_F(DisplaySetColorModeTest, doesNothingForVirtualDisplay) { @@ -448,19 +441,13 @@ TEST_F(DisplaySetColorModeTest, doesNothingForVirtualDisplay) { virtualDisplay->setDisplayColorProfileForTest( std::unique_ptr(colorProfile)); - EXPECT_CALL(*colorProfile, - getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::Dataspace::UNKNOWN)) - .WillOnce(Return(ui::Dataspace::UNKNOWN)); - - virtualDisplay->setColorProfile( - ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN}); + virtualDisplay->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, + ui::Dataspace::DISPLAY_P3, + ui::RenderIntent::TONE_MAP_COLORIMETRIC}); EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay->getState().colorMode); EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay->getState().dataspace); EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay->getState().renderIntent); - EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay->getState().targetDataspace); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index aa83883e95..9039d16aeb 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -642,7 +642,7 @@ TEST_F(OutputLayerUpdateCompositionStateTest, TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceCorrectly) { mLayerFEState.dataspace = ui::Dataspace::DISPLAY_P3; - mOutputState.targetDataspace = ui::Dataspace::V0_SCRGB; + mOutputState.dataspace = ui::Dataspace::V0_SCRGB; // If the layer is not colorspace agnostic, the output layer dataspace // should use the layers requested colorspace. @@ -659,11 +659,18 @@ TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceCorrectly mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0); EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace); + + // If the output is HDR, then don't blind the user with a colorspace agnostic dataspace + // drawing all white + mOutputState.dataspace = ui::Dataspace::BT2020_PQ; + + mOutputLayer.updateCompositionState(false, false, ui::Transform::RotationFlags::ROT_0); + + EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutputLayer.getState().dataspace); } TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceWith170mReplacement) { mLayerFEState.dataspace = ui::Dataspace::TRANSFER_SMPTE_170M; - mOutputState.targetDataspace = ui::Dataspace::V0_SCRGB; mOutputState.treat170mAsSrgb = false; mLayerFEState.isColorspaceAgnostic = false; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 9e0e7b5a53..ebf9a2b2e2 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -175,12 +175,10 @@ const Rect OutputTest::kDefaultDisplaySize{100, 200}; using ColorProfile = compositionengine::Output::ColorProfile; void dumpColorProfile(ColorProfile profile, std::string& result, const char* name) { - android::base::StringAppendF(&result, "%s (%s[%d] %s[%d] %s[%d] %s[%d]) ", name, + android::base::StringAppendF(&result, "%s (%s[%d] %s[%d] %s[%d]) ", name, toString(profile.mode).c_str(), profile.mode, toString(profile.dataspace).c_str(), profile.dataspace, - toString(profile.renderIntent).c_str(), profile.renderIntent, - toString(profile.colorSpaceAgnosticDataspace).c_str(), - profile.colorSpaceAgnosticDataspace); + toString(profile.renderIntent).c_str(), profile.renderIntent); } // Checks for a ColorProfile match @@ -192,8 +190,7 @@ MATCHER_P(ColorProfileEq, expected, "") { *result_listener << buf; return (expected.mode == arg.mode) && (expected.dataspace == arg.dataspace) && - (expected.renderIntent == arg.renderIntent) && - (expected.colorSpaceAgnosticDataspace == arg.colorSpaceAgnosticDataspace); + (expected.renderIntent == arg.renderIntent); } /* @@ -540,20 +537,14 @@ using OutputSetColorProfileTest = OutputTest; TEST_F(OutputSetColorProfileTest, setsStateAndDirtiesOutputIfChanged) { using ColorProfile = Output::ColorProfile; - EXPECT_CALL(*mDisplayColorProfile, - getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::Dataspace::UNKNOWN)) - .WillOnce(Return(ui::Dataspace::UNKNOWN)); EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1); mOutput->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, - ui::Dataspace::UNKNOWN}); + ui::RenderIntent::TONE_MAP_COLORIMETRIC}); EXPECT_EQ(ui::ColorMode::DISPLAY_P3, mOutput->getState().colorMode); EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutput->getState().dataspace); EXPECT_EQ(ui::RenderIntent::TONE_MAP_COLORIMETRIC, mOutput->getState().renderIntent); - EXPECT_EQ(ui::Dataspace::UNKNOWN, mOutput->getState().targetDataspace); EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize))); } @@ -561,19 +552,12 @@ TEST_F(OutputSetColorProfileTest, setsStateAndDirtiesOutputIfChanged) { TEST_F(OutputSetColorProfileTest, doesNothingIfNoChange) { using ColorProfile = Output::ColorProfile; - EXPECT_CALL(*mDisplayColorProfile, - getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::Dataspace::UNKNOWN)) - .WillOnce(Return(ui::Dataspace::UNKNOWN)); - mOutput->editState().colorMode = ui::ColorMode::DISPLAY_P3; mOutput->editState().dataspace = ui::Dataspace::DISPLAY_P3; mOutput->editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC; - mOutput->editState().targetDataspace = ui::Dataspace::UNKNOWN; mOutput->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3, - ui::RenderIntent::TONE_MAP_COLORIMETRIC, - ui::Dataspace::UNKNOWN}); + ui::RenderIntent::TONE_MAP_COLORIMETRIC}); EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region())); } @@ -2133,12 +2117,11 @@ TEST_F(OutputUpdateColorProfileTest, setsAColorProfileWhenUnmanaged) { EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3u)); EXPECT_CALL(mOutput, - setColorProfile(ColorProfileEq( - ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, - ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN}))); + setColorProfile( + ColorProfileEq(ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, + ui::RenderIntent::COLORIMETRIC}))); mRefreshArgs.outputColorSetting = OutputColorSetting::kUnmanaged; - mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; mOutput.updateColorProfile(mRefreshArgs); } @@ -2148,7 +2131,6 @@ struct OutputUpdateColorProfileTest_GetBestColorModeResultBecomesSetProfile OutputUpdateColorProfileTest_GetBestColorModeResultBecomesSetProfile() { EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced; - mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; } struct ExpectBestColorModeCallResultUsedToSetColorProfileState @@ -2163,8 +2145,7 @@ struct OutputUpdateColorProfileTest_GetBestColorModeResultBecomesSetProfile SetArgPointee<4>(renderIntent))); EXPECT_CALL(getInstance()->mOutput, setColorProfile( - ColorProfileEq(ColorProfile{colorMode, dataspace, renderIntent, - ui::Dataspace::UNKNOWN}))); + ColorProfileEq(ColorProfile{colorMode, dataspace, renderIntent}))); return nextState(); } }; @@ -2191,55 +2172,6 @@ TEST_F(OutputUpdateColorProfileTest_GetBestColorModeResultBecomesSetProfile, .execute(); } -struct OutputUpdateColorProfileTest_ColorSpaceAgnosticeDataspaceAffectsSetColorProfile - : public OutputUpdateColorProfileTest { - OutputUpdateColorProfileTest_ColorSpaceAgnosticeDataspaceAffectsSetColorProfile() { - EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u)); - EXPECT_CALL(*mDisplayColorProfile, - getBestColorMode(ui::Dataspace::V0_SRGB, ui::RenderIntent::ENHANCE, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<2>(ui::Dataspace::UNKNOWN), - SetArgPointee<3>(ui::ColorMode::NATIVE), - SetArgPointee<4>(ui::RenderIntent::COLORIMETRIC))); - mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced; - } - - struct IfColorSpaceAgnosticDataspaceSetToState - : public CallOrderStateMachineHelper { - [[nodiscard]] auto ifColorSpaceAgnosticDataspaceSetTo(ui::Dataspace dataspace) { - getInstance()->mRefreshArgs.colorSpaceAgnosticDataspace = dataspace; - return nextState(); - } - }; - - struct ThenExpectSetColorProfileCallUsesColorSpaceAgnosticDataspaceState - : public CallOrderStateMachineHelper< - TestType, ThenExpectSetColorProfileCallUsesColorSpaceAgnosticDataspaceState> { - [[nodiscard]] auto thenExpectSetColorProfileCallUsesColorSpaceAgnosticDataspace( - ui::Dataspace dataspace) { - EXPECT_CALL(getInstance()->mOutput, - setColorProfile(ColorProfileEq( - ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN, - ui::RenderIntent::COLORIMETRIC, dataspace}))); - return nextState(); - } - }; - - // Call this member function to start using the mini-DSL defined above. - [[nodiscard]] auto verify() { return IfColorSpaceAgnosticDataspaceSetToState::make(this); } -}; - -TEST_F(OutputUpdateColorProfileTest_ColorSpaceAgnosticeDataspaceAffectsSetColorProfile, DisplayP3) { - verify().ifColorSpaceAgnosticDataspaceSetTo(ui::Dataspace::DISPLAY_P3) - .thenExpectSetColorProfileCallUsesColorSpaceAgnosticDataspace(ui::Dataspace::DISPLAY_P3) - .execute(); -} - -TEST_F(OutputUpdateColorProfileTest_ColorSpaceAgnosticeDataspaceAffectsSetColorProfile, V0_SRGB) { - verify().ifColorSpaceAgnosticDataspaceSetTo(ui::Dataspace::V0_SRGB) - .thenExpectSetColorProfileCallUsesColorSpaceAgnosticDataspace(ui::Dataspace::V0_SRGB) - .execute(); -} - struct OutputUpdateColorProfileTest_TopmostLayerPreferenceSetsOutputPreference : public OutputUpdateColorProfileTest { // Internally the implementation looks through the dataspaces of all the @@ -2248,7 +2180,6 @@ struct OutputUpdateColorProfileTest_TopmostLayerPreferenceSetsOutputPreference OutputUpdateColorProfileTest_TopmostLayerPreferenceSetsOutputPreference() { mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced; - mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(3u)); EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return()); @@ -2368,7 +2299,6 @@ struct OutputUpdateColorProfileTest_ForceOutputColorOverrides OutputUpdateColorProfileTest_ForceOutputColorOverrides() { mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced; - mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; mLayer1.mLayerFEState.dataspace = ui::Dataspace::DISPLAY_BT2020; @@ -2424,7 +2354,6 @@ TEST_F(OutputUpdateColorProfileTest_ForceOutputColorOverrides, DisplayP3_Overrid struct OutputUpdateColorProfileTest_Hdr : public OutputUpdateColorProfileTest { OutputUpdateColorProfileTest_Hdr() { mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced; - mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(2u)); EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return()); } @@ -2703,7 +2632,6 @@ struct OutputUpdateColorProfile_AffectsChosenRenderIntentTest OutputUpdateColorProfile_AffectsChosenRenderIntentTest() { mRefreshArgs.outputColorSetting = OutputColorSetting::kEnhanced; - mRefreshArgs.colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN; mLayer1.mLayerFEState.dataspace = ui::Dataspace::BT2020_PQ; EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u)); EXPECT_CALL(mOutput, setColorProfile(_)).WillRepeatedly(Return()); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 198e92abaf..b1c6ccc689 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -406,9 +406,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI wideColorGamutCompositionPixelFormat = static_cast(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888)); - mColorSpaceAgnosticDataspace = - static_cast(color_space_agnostic_dataspace(Dataspace::UNKNOWN)); - mLayerCachingEnabled = [] { const bool enable = android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false); @@ -1526,7 +1523,7 @@ status_t SurfaceFlinger::setActiveColorMode(const sp& displayToken, ui: } display->getCompositionDisplay()->setColorProfile( - {mode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC, Dataspace::UNKNOWN}); + {mode, Dataspace::UNKNOWN, RenderIntent::COLORIMETRIC}); return NO_ERROR; }); @@ -2609,7 +2606,6 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( refreshArgs.outputColorSetting = useColorManagement ? mDisplayColorSetting : compositionengine::OutputColorSetting::kUnmanaged; - refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace; refreshArgs.forceOutputColorMode = mForceColorMode; refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty; @@ -3419,8 +3415,7 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( } display->getCompositionDisplay()->setColorProfile( compositionengine::Output::ColorProfile{defaultColorMode, defaultDataSpace, - RenderIntent::COLORIMETRIC, - Dataspace::UNKNOWN}); + RenderIntent::COLORIMETRIC}); if (const auto& physical = state.physical) { mPhysicalDisplays.get(physical->id) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 3d46239759..85b1422faa 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1302,7 +1302,6 @@ private: ui::Dataspace mDefaultCompositionDataspace; ui::Dataspace mWideColorGamutCompositionDataspace; - ui::Dataspace mColorSpaceAgnosticDataspace; std::unique_ptr mRenderEngine; std::atomic mNumTrustedPresentationListeners = 0; diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 96c8b54005..66c8f33fe5 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -227,14 +227,6 @@ int32_t wcg_composition_pixel_format(PixelFormat defaultValue) { return static_cast(defaultValue); } -int64_t color_space_agnostic_dataspace(Dataspace defaultValue) { - auto temp = SurfaceFlingerProperties::color_space_agnostic_dataspace(); - if (temp.has_value()) { - return *temp; - } - return static_cast(defaultValue); -} - bool refresh_rate_switching(bool defaultValue) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index 951f8f8cb3..a08042009b 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -71,9 +71,6 @@ int64_t wcg_composition_dataspace( int32_t wcg_composition_pixel_format( android::hardware::graphics::common::V1_2::PixelFormat defaultValue); -int64_t color_space_agnostic_dataspace( - android::hardware::graphics::common::V1_2::Dataspace defaultValue); - bool refresh_rate_switching(bool defaultValue); int32_t set_idle_timer_ms(int32_t defaultValue); diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index 5cac086c21..be29be4ef4 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -199,6 +199,7 @@ prop { # useColorManagement indicates whether SurfaceFlinger should manage color # by switching to appropriate color mode automatically depending on the # Dataspace of the surfaces on screen. +# DEPRECATED: SurfaceFlinger is always color managed. prop { api_name: "use_color_management" type: Boolean @@ -207,7 +208,7 @@ prop { prop_name: "ro.surface_flinger.use_color_management" } -# The following four propertiess define: +# The following four properties define: # Returns the default data space and pixel format that SurfaceFlinger # expects to receive and output as well as the wide color gamut data space # and pixel format for wide color gamut surfaces. @@ -276,7 +277,7 @@ prop { # The variable works only when useColorManagement is specified. If # unspecified, the data space follows what SurfaceFlinger expects for # surfaces when useColorManagement is specified. - +# DEPRECATED: do not use prop { api_name: "color_space_agnostic_dataspace" type: Long -- GitLab From 571797962883359d42b27aba9b2c0bc0b6785f71 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 25 Jul 2023 18:43:17 +0000 Subject: [PATCH 0345/1187] InputEventLabels: Use EV_ABS when looking for tool type label Using EV_MSC for querying tool type label seems to be a typo. Bug: None Test: None Change-Id: Idf3da2d5a2e7c16e32dcc326f1d2bde89705b56b --- libs/input/InputEventLabels.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index bade68629d..50efac1314 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -556,7 +556,7 @@ const label* getValueLabelsForTypeAndCode(int32_t type, int32_t code) { if (type == EV_KEY) { return ev_key_value_labels; } - if (type == EV_MSC && code == ABS_MT_TOOL_TYPE) { + if (type == EV_ABS && code == ABS_MT_TOOL_TYPE) { return mt_tool_labels; } return nullptr; -- GitLab From b237f9e214a05f9018c0321b8090e186a24fa364 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 21 Jul 2023 16:42:23 -0700 Subject: [PATCH 0346/1187] Increase timeouts in InputDispatcher_tests These tests are flaky on some platforms because we aren't allowing enough time to consume the events. To work around this, create another path for checking when the events didn't occur. Now, if we expect to receive an event, we are waiting for a very long time. If we expect no event, we are waiting a short time. This will speed up tests while reducing the flake rate. In addition to the above, add some more infrastructure to be able to match against common fields of NotifyArgs and InputEvent. Bug: 292232423 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: I1d6f091376b59279f11a04d02a875991a6384e31 --- include/input/Input.h | 12 +- services/inputflinger/tests/Android.bp | 1 + .../tests/InputDispatcher_test.cpp | 881 ++++++++---------- .../tests/TestInputListenerMatchers.cpp | 37 + .../tests/TestInputListenerMatchers.h | 152 ++- 5 files changed, 574 insertions(+), 509 deletions(-) create mode 100644 services/inputflinger/tests/TestInputListenerMatchers.cpp diff --git a/include/input/Input.h b/include/input/Input.h index a271f0c1f9..64ee47342d 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -551,7 +551,7 @@ class KeyEvent : public InputEvent { public: virtual ~KeyEvent() { } - virtual InputEventType getType() const { return InputEventType::KEY; } + InputEventType getType() const override { return InputEventType::KEY; } inline int32_t getAction() const { return mAction; } @@ -602,7 +602,7 @@ class MotionEvent : public InputEvent { public: virtual ~MotionEvent() { } - virtual InputEventType getType() const { return InputEventType::MOTION; } + InputEventType getType() const override { return InputEventType::MOTION; } inline int32_t getAction() const { return mAction; } @@ -930,7 +930,7 @@ class FocusEvent : public InputEvent { public: virtual ~FocusEvent() {} - virtual InputEventType getType() const override { return InputEventType::FOCUS; } + InputEventType getType() const override { return InputEventType::FOCUS; } inline bool getHasFocus() const { return mHasFocus; } @@ -949,7 +949,7 @@ class CaptureEvent : public InputEvent { public: virtual ~CaptureEvent() {} - virtual InputEventType getType() const override { return InputEventType::CAPTURE; } + InputEventType getType() const override { return InputEventType::CAPTURE; } inline bool getPointerCaptureEnabled() const { return mPointerCaptureEnabled; } @@ -968,7 +968,7 @@ class DragEvent : public InputEvent { public: virtual ~DragEvent() {} - virtual InputEventType getType() const override { return InputEventType::DRAG; } + InputEventType getType() const override { return InputEventType::DRAG; } inline bool isExiting() const { return mIsExiting; } @@ -992,7 +992,7 @@ class TouchModeEvent : public InputEvent { public: virtual ~TouchModeEvent() {} - virtual InputEventType getType() const override { return InputEventType::TOUCH_MODE; } + InputEventType getType() const override { return InputEventType::TOUCH_MODE; } inline bool isInTouchMode() const { return mIsInTouchMode; } diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index 38640b3f02..b9b0a74fc9 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -62,6 +62,7 @@ cc_test { "SlopController_test.cpp", "SyncQueue_test.cpp", "TestInputListener.cpp", + "TestInputListenerMatchers.cpp", "TouchpadInputMapper_test.cpp", "UinputDevice.cpp", "UnwantedInteractionBlocker_test.cpp", diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index bc87c8e7df..6d9cd87c4f 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -16,6 +16,7 @@ #include "../dispatcher/InputDispatcher.h" #include "../BlockingQueue.h" +#include "TestInputListenerMatchers.h" #include #include @@ -107,6 +108,23 @@ static constexpr gui::Pid MONITOR_PID{2001}; static constexpr std::chrono::duration STALE_EVENT_TIMEOUT = 1000ms; +/** + * If we expect to receive the event, the timeout can be made very long. When the test are running + * correctly, we will actually never wait until the end of the timeout because the wait will end + * when the event comes in. Still, this value shouldn't be infinite. During development, a local + * change may cause the test to fail. This timeout should be short enough to not annoy so that the + * developer can see the failure quickly (on human scale). + */ +static constexpr std::chrono::duration CONSUME_TIMEOUT_EVENT_EXPECTED = 1000ms; +/** + * When no event is expected, we can have a very short timeout. A large value here would slow down + * the tests. In the unlikely event of system being too slow, the event may still be present but the + * timeout would complete before it is consumed. This would result in test flakiness. If this + * occurs, the flakiness rate would be high. Since the flakes are treated with high priority, this + * would get noticed and addressed quickly. + */ +static constexpr std::chrono::duration CONSUME_TIMEOUT_NO_EVENT_EXPECTED = 10ms; + static constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; @@ -136,41 +154,10 @@ static void assertMotionAction(int32_t expectedAction, int32_t receivedAction) { << MotionEvent::actionToString(receivedAction); } -MATCHER_P(WithMotionAction, action, "MotionEvent with specified action") { - bool matches = action == arg.getAction(); - if (!matches) { - *result_listener << "expected action " << MotionEvent::actionToString(action) - << ", but got " << MotionEvent::actionToString(arg.getAction()); - } - if (action == AMOTION_EVENT_ACTION_DOWN) { - if (!matches) { - *result_listener << "; "; - } - *result_listener << "downTime should match eventTime for ACTION_DOWN events"; - matches &= arg.getDownTime() == arg.getEventTime(); - } - if (action == AMOTION_EVENT_ACTION_CANCEL) { - if (!matches) { - *result_listener << "; "; - } - *result_listener << "expected FLAG_CANCELED to be set with ACTION_CANCEL, but was not set"; - matches &= (arg.getFlags() & AMOTION_EVENT_FLAG_CANCELED) != 0; - } - return matches; -} - MATCHER_P(WithDownTime, downTime, "InputEvent with specified downTime") { return arg.getDownTime() == downTime; } -MATCHER_P(WithDisplayId, displayId, "InputEvent with specified displayId") { - return arg.getDisplayId() == displayId; -} - -MATCHER_P(WithDeviceId, deviceId, "InputEvent with specified deviceId") { - return arg.getDeviceId() == deviceId; -} - MATCHER_P(WithSource, source, "InputEvent with specified source") { *result_listener << "expected source " << inputEventSourceToString(source) << ", but got " << inputEventSourceToString(arg.getSource()); @@ -892,9 +879,9 @@ public: mConsumer = std::make_unique(std::move(clientChannel)); } - InputEvent* consume() { + InputEvent* consume(std::chrono::milliseconds timeout) { InputEvent* event; - std::optional consumeSeq = receiveEvent(&event); + std::optional consumeSeq = receiveEvent(timeout, &event); if (!consumeSeq) { return nullptr; } @@ -906,7 +893,8 @@ public: * Receive an event without acknowledging it. * Return the sequence number that could later be used to send finished signal. */ - std::optional receiveEvent(InputEvent** outEvent = nullptr) { + std::optional receiveEvent(std::chrono::milliseconds timeout, + InputEvent** outEvent = nullptr) { uint32_t consumeSeq; InputEvent* event; @@ -916,7 +904,7 @@ public: status = mConsumer->consume(&mEventFactory, /*consumeBatches=*/true, -1, &consumeSeq, &event); std::chrono::duration elapsed = std::chrono::steady_clock::now() - start; - if (elapsed > 100ms) { + if (elapsed > timeout) { break; } } @@ -956,7 +944,7 @@ public: void consumeEvent(InputEventType expectedEventType, int32_t expectedAction, std::optional expectedDisplayId, std::optional expectedFlags) { - InputEvent* event = consume(); + InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event."; @@ -1002,7 +990,7 @@ public: } MotionEvent* consumeMotion() { - InputEvent* event = consume(); + InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); if (event == nullptr) { ADD_FAILURE() << mName << ": expected a MotionEvent, but didn't get one."; @@ -1023,7 +1011,7 @@ public: } void consumeFocusEvent(bool hasFocus, bool inTouchMode) { - InputEvent* event = consume(); + InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event."; ASSERT_EQ(InputEventType::FOCUS, event->getType()) @@ -1037,7 +1025,7 @@ public: } void consumeCaptureEvent(bool hasCapture) { - const InputEvent* event = consume(); + const InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event."; ASSERT_EQ(InputEventType::CAPTURE, event->getType()) @@ -1051,7 +1039,7 @@ public: } void consumeDragEvent(bool isExiting, float x, float y) { - const InputEvent* event = consume(); + const InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event."; ASSERT_EQ(InputEventType::DRAG, event->getType()) << "Instead of DragEvent, got " << *event; @@ -1066,7 +1054,7 @@ public: } void consumeTouchModeEvent(bool inTouchMode) { - const InputEvent* event = consume(); + const InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); ASSERT_NE(nullptr, event) << mName.c_str() << ": consumer should have returned non-NULL event."; ASSERT_EQ(InputEventType::TOUCH_MODE, event->getType()) @@ -1079,7 +1067,7 @@ public: } void assertNoEvents() { - InputEvent* event = consume(); + InputEvent* event = consume(CONSUME_TIMEOUT_NO_EVENT_EXPECTED); if (event == nullptr) { return; } @@ -1262,6 +1250,25 @@ public: void setWindowOffset(float offsetX, float offsetY) { mInfo.transform.set(offsetX, offsetY); } + KeyEvent* consumeKey() { + InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); + if (event == nullptr) { + ADD_FAILURE() << "Consume failed : no event"; + return nullptr; + } + if (event->getType() != InputEventType::KEY) { + ADD_FAILURE() << "Instead of key event, got " << *event; + return nullptr; + } + return static_cast(event); + } + + void consumeKeyEvent(const ::testing::Matcher& matcher) { + KeyEvent* keyEvent = consumeKey(); + ASSERT_NE(nullptr, keyEvent) << "Did not get a key event, but expected " << matcher; + ASSERT_THAT(*keyEvent, matcher); + } + void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) { consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId, expectedFlags); } @@ -1322,13 +1329,11 @@ public: void consumeMotionOutsideWithZeroedCoords(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { - InputEvent* event = consume(); - ASSERT_NE(nullptr, event); - ASSERT_EQ(InputEventType::MOTION, event->getType()); - const MotionEvent& motionEvent = static_cast(*event); - EXPECT_EQ(AMOTION_EVENT_ACTION_OUTSIDE, motionEvent.getActionMasked()); - EXPECT_EQ(0.f, motionEvent.getRawPointerCoords(0)->getX()); - EXPECT_EQ(0.f, motionEvent.getRawPointerCoords(0)->getY()); + MotionEvent* motionEvent = consumeMotion(); + ASSERT_NE(nullptr, motionEvent); + EXPECT_EQ(AMOTION_EVENT_ACTION_OUTSIDE, motionEvent->getActionMasked()); + EXPECT_EQ(0.f, motionEvent->getRawPointerCoords(0)->getX()); + EXPECT_EQ(0.f, motionEvent->getRawPointerCoords(0)->getY()); } void consumeFocusEvent(bool hasFocus, bool inTouchMode = true) { @@ -1372,7 +1377,7 @@ public: ADD_FAILURE() << "Invalid receive event on window with no receiver"; return std::nullopt; } - return mInputReceiver->receiveEvent(outEvent); + return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED, outEvent); } void finishEvent(uint32_t sequenceNum) { @@ -1385,15 +1390,15 @@ public: mInputReceiver->sendTimeline(inputEventId, timeline); } - InputEvent* consume() { + InputEvent* consume(std::chrono::milliseconds timeout) { if (mInputReceiver == nullptr) { return nullptr; } - return mInputReceiver->consume(); + return mInputReceiver->consume(timeout); } MotionEvent* consumeMotion() { - InputEvent* event = consume(); + InputEvent* event = consume(CONSUME_TIMEOUT_EVENT_EXPECTED); if (event == nullptr) { ADD_FAILURE() << "Consume failed : no event"; return nullptr; @@ -1441,7 +1446,7 @@ private: std::atomic FakeWindowHandle::sId{1}; static InputEventInjectionResult injectKey( - const std::unique_ptr& dispatcher, int32_t action, int32_t repeatCount, + InputDispatcher& dispatcher, int32_t action, int32_t repeatCount, int32_t displayId = ADISPLAY_ID_NONE, InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT, std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT, @@ -1459,10 +1464,19 @@ static InputEventInjectionResult injectKey( policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT; } // Inject event until dispatch out. - return dispatcher->injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags); + return dispatcher.injectInputEvent(&event, targetUid, syncMode, injectionTimeout, policyFlags); +} + +static void assertInjectedKeyTimesOut(InputDispatcher& dispatcher) { + InputEventInjectionResult result = + injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_NONE, + InputEventInjectionSync::WAIT_FOR_RESULT, CONSUME_TIMEOUT_NO_EVENT_EXPECTED); + if (result != InputEventInjectionResult::TIMED_OUT) { + FAIL() << "Injection should have timed out, but got " << ftl::enum_string(result); + } } -static InputEventInjectionResult injectKeyDown(const std::unique_ptr& dispatcher, +static InputEventInjectionResult injectKeyDown(InputDispatcher& dispatcher, int32_t displayId = ADISPLAY_ID_NONE) { return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId); } @@ -1470,30 +1484,30 @@ static InputEventInjectionResult injectKeyDown(const std::unique_ptr& dispatcher, int32_t displayId = ADISPLAY_ID_NONE) { +static InputEventInjectionResult injectKeyDownNoRepeat(InputDispatcher& dispatcher, + int32_t displayId = ADISPLAY_ID_NONE) { return injectKey(dispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, displayId, InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false); } -static InputEventInjectionResult injectKeyUp(const std::unique_ptr& dispatcher, +static InputEventInjectionResult injectKeyUp(InputDispatcher& dispatcher, int32_t displayId = ADISPLAY_ID_NONE) { return injectKey(dispatcher, AKEY_EVENT_ACTION_UP, /*repeatCount=*/0, displayId); } static InputEventInjectionResult injectMotionEvent( - const std::unique_ptr& dispatcher, const MotionEvent& event, + InputDispatcher& dispatcher, const MotionEvent& event, std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT, InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT, std::optional targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) { - return dispatcher->injectInputEvent(&event, targetUid, injectionMode, injectionTimeout, - policyFlags); + return dispatcher.injectInputEvent(&event, targetUid, injectionMode, injectionTimeout, + policyFlags); } static InputEventInjectionResult injectMotionEvent( - const std::unique_ptr& dispatcher, int32_t action, int32_t source, - int32_t displayId, const PointF& position = {100, 200}, + InputDispatcher& dispatcher, int32_t action, int32_t source, int32_t displayId, + const PointF& position = {100, 200}, const PointF& cursorPosition = {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION}, std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT, @@ -1517,14 +1531,14 @@ static InputEventInjectionResult injectMotionEvent( targetUid, policyFlags); } -static InputEventInjectionResult injectMotionDown( - const std::unique_ptr& dispatcher, int32_t source, int32_t displayId, - const PointF& location = {100, 200}) { +static InputEventInjectionResult injectMotionDown(InputDispatcher& dispatcher, int32_t source, + int32_t displayId, + const PointF& location = {100, 200}) { return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, location); } -static InputEventInjectionResult injectMotionUp(const std::unique_ptr& dispatcher, - int32_t source, int32_t displayId, +static InputEventInjectionResult injectMotionUp(InputDispatcher& dispatcher, int32_t source, + int32_t displayId, const PointF& location = {100, 200}) { return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_UP, source, displayId, location); } @@ -1634,7 +1648,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; // Window should receive motion event. @@ -1649,7 +1663,7 @@ TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); // Inject a MotionEvent to an unknown display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_NONE)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_NONE)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; // Window should receive motion event. @@ -1669,7 +1683,7 @@ TEST_F(InputDispatcherTest, SetInputWindowOnceWithSingleTouchWindow) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1689,7 +1703,7 @@ TEST_F(InputDispatcherTest, SetInputWindowTwice_SingleWindowTouch) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1708,7 +1722,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) { mDispatcher->onWindowInfosChanged( {{*windowTop->getInfo(), *windowSecond->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; // Top window should receive the touch down event. Second window should not receive anything. @@ -1735,7 +1749,7 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance mDispatcher->onWindowInfosChanged( {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1744,7 +1758,7 @@ TEST_F(InputDispatcherTest, WhenForegroundWindowDisappears_WallpaperTouchIsCance wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {110, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1814,7 +1828,7 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { mDispatcher->onWindowInfosChanged( {{*foregroundWindow->getInfo(), *wallpaperWindow->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1823,7 +1837,7 @@ TEST_F(InputDispatcherTest, WhenWallpaperDisappears_NoCrash) { wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {110, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1865,7 +1879,7 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { // Touch down on top window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1881,7 +1895,7 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1897,14 +1911,14 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; foregroundWindow->consumeMotionPointerUp(0); wallpaperWindow->consumeMotionPointerUp(0, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) @@ -1952,7 +1966,7 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { // Touch down on left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1968,7 +1982,7 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(300).y(100)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -1994,7 +2008,7 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(310).y(110)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)); rightWindow->consumeMotionMove(); @@ -2032,7 +2046,7 @@ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) { // Touch down on left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -2042,7 +2056,7 @@ TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) { // Move to right window, the left window should receive cancel. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {201, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -2161,86 +2175,74 @@ TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) { const int32_t touchDeviceId = 4; // Move the cursor from right ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) .downTime(baseTime + 10) .eventTime(baseTime + 20) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(300) - .y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(100)) .build())); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // .. to the left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) .downTime(baseTime + 10) .eventTime(baseTime + 30) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(110) - .y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(100)) .build())); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // Now tap the left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .downTime(baseTime + 40) .eventTime(baseTime + 40) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); // release tap ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .downTime(baseTime + 40) .eventTime(baseTime + 50) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); // Tap the window on the right ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .downTime(baseTime + 60) .eventTime(baseTime + 60) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(300) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .build())); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); // release tap ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .downTime(baseTime + 60) .eventTime(baseTime + 70) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(300) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .build())); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); @@ -2526,12 +2528,10 @@ TEST_F(InputDispatcherTest, UnfinishedInjectedEvent) { // Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after // completion. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE) .deviceId(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(50) - .y(50)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50)) .build())); window->consumeMotionEvent( AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(VIRTUAL_KEYBOARD_ID))); @@ -2579,35 +2579,29 @@ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { const int32_t touchDeviceId = 4; // Hover over the left window. Keep the cursor there. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(50) - .y(50)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // Tap on left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); @@ -2615,27 +2609,21 @@ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { // First finger down on right window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(300) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .build())); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); // Second finger down on the left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(300) - .y(100)) - .pointer(PointerBuilder(1, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); @@ -2662,32 +2650,28 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { const int32_t touchDeviceId = 4; // Start hovering with stylus ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) - .pointer(PointerBuilder(0, ToolType::STYLUS) - .x(50) - .y(50)) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // Finger down on the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); // Try to continue hovering with stylus. Since we are already down, injection should fail ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) @@ -2698,19 +2682,17 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { // Lift up the finger ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); // Now that the touch is gone, stylus hovering should start working again ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) @@ -2953,22 +2935,21 @@ TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) { mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}})); mDispatcher->waitForIdle(); - InputEvent* inputEvent1 = window1->consume(); - ASSERT_NE(inputEvent1, nullptr); + + MotionEvent* motionEvent1 = window1->consumeMotion(); + ASSERT_NE(motionEvent1, nullptr); window2->assertNoEvents(); - MotionEvent& motionEvent1 = static_cast(*inputEvent1); - nsecs_t downTimeForWindow1 = motionEvent1.getDownTime(); - ASSERT_EQ(motionEvent1.getDownTime(), motionEvent1.getEventTime()); + nsecs_t downTimeForWindow1 = motionEvent1->getDownTime(); + ASSERT_EQ(motionEvent1->getDownTime(), motionEvent1->getEventTime()); // Now touch down on the window with another pointer mDispatcher->notifyMotion(generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}})); mDispatcher->waitForIdle(); - InputEvent* inputEvent2 = window2->consume(); - ASSERT_NE(inputEvent2, nullptr); - MotionEvent& motionEvent2 = static_cast(*inputEvent2); - nsecs_t downTimeForWindow2 = motionEvent2.getDownTime(); + MotionEvent* motionEvent2 = window2->consumeMotion(); + ASSERT_NE(motionEvent2, nullptr); + nsecs_t downTimeForWindow2 = motionEvent2->getDownTime(); ASSERT_NE(downTimeForWindow1, downTimeForWindow2); - ASSERT_EQ(motionEvent2.getDownTime(), motionEvent2.getEventTime()); + ASSERT_EQ(motionEvent2->getDownTime(), motionEvent2->getEventTime()); // Now move the pointer on the second window mDispatcher->notifyMotion(generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}})); @@ -3012,7 +2993,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { // Start cursor position in right window so that we can move the cursor to left window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400)) @@ -3021,7 +3002,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { // Move cursor into left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3031,7 +3012,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { // Inject a series of mouse events for a mouse click ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3040,7 +3021,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { windowLeft->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) @@ -3050,7 +3031,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE, AINPUT_SOURCE_MOUSE) .buttonState(0) @@ -3060,7 +3041,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { windowLeft->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) .buttonState(0) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3069,7 +3050,7 @@ TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { // Move mouse cursor back to right window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::MOUSE).x(900).y(400)) @@ -3157,12 +3138,10 @@ TEST_F(InputDispatcherTest, HoverWithSpyWindows) { // Send mouse cursor to the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) .build())); window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), @@ -3191,22 +3170,18 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { // Send mouse cursor to the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(100) - .y(100)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(100)) .build())); // Move mouse cursor ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(110) - .y(110)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(110)) .build())); window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), @@ -3219,13 +3194,11 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { WithSource(AINPUT_SOURCE_MOUSE))); // Touch down on the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(SECOND_DEVICE_ID) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(200) - .y(200)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200)) .build())); window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT), WithSource(AINPUT_SOURCE_MOUSE))); @@ -3243,13 +3216,11 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { // Touch UP on the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(SECOND_DEVICE_ID) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(200) - .y(200)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(200)) .build())); spyWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); @@ -3260,13 +3231,11 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { // One more tap - DOWN ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(SECOND_DEVICE_ID) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(250) - .y(250)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250)) .build())); window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); @@ -3275,13 +3244,11 @@ TEST_F(InputDispatcherTest, MouseAndTouchWithSpyWindows) { // Touch UP on the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(SECOND_DEVICE_ID) - .pointer(PointerBuilder(0, ToolType::FINGER) - .x(250) - .y(250)) + .pointer(PointerBuilder(0, ToolType::FINGER).x(250).y(250)) .build())); window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN))); @@ -3305,7 +3272,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3313,7 +3280,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // Inject a series of mouse events for a mouse click ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3322,7 +3289,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) @@ -3332,7 +3299,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE, AINPUT_SOURCE_MOUSE) .buttonState(0) @@ -3342,7 +3309,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) .buttonState(0) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3352,7 +3319,7 @@ TEST_F(InputDispatcherTest, HoverEnterMouseClickAndHoverExit) { // We already canceled the hovering implicitly by injecting the "DOWN" event without lifting the // hover first. Therefore, injection of HOVER_EXIT is inconsistent, and should fail. ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT, AINPUT_SOURCE_MOUSE) .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) @@ -3375,12 +3342,10 @@ TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(300) - .y(400)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) .build())); window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); @@ -3482,13 +3447,11 @@ TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) { // Set cursor position in window in default display and check that hover enter and move // events are generated. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .displayId(ADISPLAY_ID_DEFAULT) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(300) - .y(600)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(600)) .build())); windowDefaultDisplay->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); @@ -3503,13 +3466,11 @@ TEST_F(InputDispatcherTest, HoverEnterMoveRemoveWindowsInSecondDisplay) { mDispatcher->onWindowInfosChanged( {{*windowDefaultDisplay->getInfo(), *windowSecondDisplay->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) .displayId(ADISPLAY_ID_DEFAULT) - .pointer(PointerBuilder(0, ToolType::MOUSE) - .x(400) - .y(700)) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(400).y(700)) .build())); windowDefaultDisplay->consumeMotionEvent( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), @@ -3535,7 +3496,7 @@ TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) { // Inject an event with coordinate in the area of right window, with mouse cursor in the area of // left window. This event should be dispatched to the left window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, {610, 400}, {599, 400})); windowLeft->consumeMotionDown(ADISPLAY_ID_DEFAULT); windowRight->assertNoEvents(); @@ -3777,7 +3738,7 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -3790,7 +3751,7 @@ TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(-30).y(-50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -4106,7 +4067,7 @@ TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) { // Send down to the first window. The point is represented in the logical display space. The // point is selected so that if the hit test was done in logical display space, then it would // end up in the incorrect window. - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, PointF{75 * 2, 55 * 4}); firstWindow->consumeMotionDown(); @@ -4133,7 +4094,7 @@ TEST_F(InputDispatcherDisplayProjectionTest, InjectionWithTransformInLogicalDisp .build(); event.transform(matrix); - injectMotionEvent(mDispatcher, event, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, event, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT); firstWindow->consumeMotionDown(); @@ -4630,7 +4591,7 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -4645,14 +4606,14 @@ TEST_F(InputDispatcherTest, TransferTouchFocus_CloneSurface) { secondWindowInPrimary->consumeMotionDown(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; firstWindowInPrimary->assertNoEvents(); secondWindowInPrimary->consumeMotionMove(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; firstWindowInPrimary->assertNoEvents(); @@ -4690,7 +4651,8 @@ TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { // Touch on second display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {50, 50})) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, + {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; // Window should receive motion event. @@ -4704,14 +4666,14 @@ TEST_F(InputDispatcherTest, TransferTouch_CloneSurface) { secondWindowInPrimary->consumeMotionDown(SECOND_DISPLAY_ID); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; firstWindowInPrimary->assertNoEvents(); secondWindowInPrimary->consumeMotionMove(SECOND_DISPLAY_ID); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50})) + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; firstWindowInPrimary->assertNoEvents(); secondWindowInPrimary->consumeMotionUp(SECOND_DISPLAY_ID); @@ -4832,7 +4794,7 @@ TEST_F(InputDispatcherTest, InjectedTouchesPokeUserActivity) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 100})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -4961,7 +4923,9 @@ public: expectedFlags); } - std::optional receiveEvent() { return mInputReceiver->receiveEvent(); } + std::optional receiveEvent() { + return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED); + } void finishEvent(uint32_t consumeSeq) { return mInputReceiver->finishEvent(consumeSeq); } @@ -4994,18 +4958,7 @@ public: /*expectedFlags=*/0); } - MotionEvent* consumeMotion() { - InputEvent* event = mInputReceiver->consume(); - if (!event) { - ADD_FAILURE() << "No event was produced"; - return nullptr; - } - if (event->getType() != InputEventType::MOTION) { - ADD_FAILURE() << "Expected MotionEvent, got " << *event; - return nullptr; - } - return static_cast(event); - } + MotionEvent* consumeMotion() { return mInputReceiver->consumeMotion(); } void assertNoEvents() { mInputReceiver->assertNoEvents(); } @@ -5032,7 +4985,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDis mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -5041,7 +4994,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDis monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {110, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -5056,7 +5009,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDis // If more events come in, there will be no more foreground window to send them to. This will // cause a cancel for the monitor, as well. ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {120, 200})) << "Injection should fail because the window was removed"; window->assertNoEvents(); @@ -5073,7 +5026,7 @@ TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) { FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -5088,7 +5041,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) { mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT); window->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -5098,7 +5051,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) { EXPECT_NE(OK, mDispatcher->pilferPointers(monitor.getToken())); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -5117,7 +5070,7 @@ TEST_F(InputDispatcherMonitorTest, NoWindowTransform) { FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); MotionEvent* event = monitor.consumeMotion(); @@ -5130,7 +5083,7 @@ TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) { FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Injection should fail if there is a monitor, but no touchable window"; monitor.assertNoEvents(); } @@ -5228,7 +5181,7 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_KeyEvent) { const NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN); mDispatcher->notifyKey(keyArgs); - InputEvent* event = window->consume(); + KeyEvent* event = window->consumeKey(); ASSERT_NE(event, nullptr); std::unique_ptr verified = mDispatcher->verifyInputEvent(*event); @@ -5272,7 +5225,7 @@ TEST_F(InputDispatcherTest, VerifyInputEvent_MotionEvent) { ADISPLAY_ID_DEFAULT); mDispatcher->notifyMotion(motionArgs); - InputEvent* event = window->consume(); + MotionEvent* event = window->consumeMotion(); ASSERT_NE(event, nullptr); std::unique_ptr verified = mDispatcher->verifyInputEvent(*event); @@ -5371,7 +5324,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow) { setFocusedWindow(windowSecond); windowSecond->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; // Focused window should receive event. @@ -5392,8 +5345,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestInvalidChannel) { setFocusedWindow(window); // Test inject a key down, should timeout. - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) - << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; + ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher)); // window channel is invalid, so it should not receive any input event. window->assertNoEvents(); @@ -5410,8 +5362,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DropRequestNoFocusableWindow) { setFocusedWindow(window); // Test inject a key down, should timeout. - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) - << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; + ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher)); // window is not focusable, so it should not receive any input event. window->assertNoEvents(); @@ -5438,7 +5389,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_CheckFocusedToken) { windowSecond->consumeFocusEvent(true); windowTop->consumeFocusEvent(false); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; // Focused window should receive event. @@ -5461,7 +5412,7 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_TransferFocusTokenNotFocusable) { setFocusedWindow(windowTop); windowTop->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; // Event should be dropped. @@ -5492,8 +5443,8 @@ TEST_F(InputDispatcherTest, SetFocusedWindow_DeferInvisibleWindow) { // Injected key goes to pending queue. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE)); + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, + ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE)); // Window does not get focus event or key down. window->assertNoEvents(); @@ -5774,15 +5725,8 @@ protected: void expectKeyRepeatOnce(int32_t repeatCount) { SCOPED_TRACE(StringPrintf("Checking event with repeat count %" PRId32, repeatCount)); - InputEvent* repeatEvent = mWindow->consume(); - ASSERT_NE(nullptr, repeatEvent); - - ASSERT_EQ(InputEventType::KEY, repeatEvent->getType()); - - KeyEvent* repeatKeyEvent = static_cast(repeatEvent); - uint32_t eventAction = repeatKeyEvent->getAction(); - EXPECT_EQ(AKEY_EVENT_ACTION_DOWN, eventAction); - EXPECT_EQ(repeatCount, repeatKeyEvent->getRepeatCount()); + mWindow->consumeKeyEvent( + AllOf(WithKeyAction(AKEY_EVENT_ACTION_DOWN), WithRepeatCount(repeatCount))); } void sendAndConsumeKeyUp(int32_t deviceId) { @@ -5862,7 +5806,7 @@ TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFrom GTEST_SKIP() << "Flaky test (b/270393106)"; sendAndConsumeKeyDown(/*deviceId=*/1); for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { - InputEvent* repeatEvent = mWindow->consume(); + KeyEvent* repeatEvent = mWindow->consumeKey(); ASSERT_NE(nullptr, repeatEvent) << "Didn't receive event with repeat count " << repeatCount; EXPECT_EQ(IdGenerator::Source::INPUT_DISPATCHER, IdGenerator::getSource(repeatEvent->getId())); @@ -5875,7 +5819,7 @@ TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEvent std::unordered_set idSet; for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) { - InputEvent* repeatEvent = mWindow->consume(); + KeyEvent* repeatEvent = mWindow->consumeKey(); ASSERT_NE(nullptr, repeatEvent) << "Didn't receive event with repeat count " << repeatCount; int32_t id = repeatEvent->getId(); EXPECT_EQ(idSet.end(), idSet.find(id)); @@ -5935,14 +5879,14 @@ protected: TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) { // Test touch down on primary display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT); windowInSecondary->assertNoEvents(); // Test touch down on second display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->assertNoEvents(); windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID); @@ -5951,13 +5895,13 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayTouch) TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) { // Test inject a key down with display id specified. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectKeyDownNoRepeat(mDispatcher, ADISPLAY_ID_DEFAULT)) + injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->consumeKeyDown(ADISPLAY_ID_DEFAULT); windowInSecondary->assertNoEvents(); // Test inject a key down without display id specified. - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->assertNoEvents(); windowInSecondary->consumeKeyDown(ADISPLAY_ID_NONE); @@ -5970,8 +5914,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) AKEY_EVENT_FLAG_CANCELED); // Test inject a key down, should timeout because of no target window. - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDownNoRepeat(mDispatcher)) - << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; + ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher)); windowInPrimary->assertNoEvents(); windowInSecondary->consumeFocusEvent(false); windowInSecondary->assertNoEvents(); @@ -5986,7 +5929,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { // Test touch down on primary display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT); monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -5995,7 +5938,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { // Test touch down on second display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->assertNoEvents(); monitorInPrimary.assertNoEvents(); @@ -6004,7 +5947,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { // Lift up the touch from the second display ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInSecondary->consumeMotionUp(SECOND_DISPLAY_ID); monitorInSecondary.consumeMotionUp(SECOND_DISPLAY_ID); @@ -6013,7 +5956,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { // If specific a display, it will dispatch to the focused window of particular display, // or it will dispatch to the focused window of focused display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_NONE)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->assertNoEvents(); monitorInPrimary.assertNoEvents(); @@ -6030,7 +5973,7 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) { FakeMonitorReceiver(mDispatcher, "M_2", SECOND_DISPLAY_ID); // Test inject a key down. - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->assertNoEvents(); monitorInPrimary.assertNoEvents(); @@ -6053,7 +5996,8 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) secondWindowInPrimary->consumeFocusEvent(true); // Test inject a key down. - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->assertNoEvents(); windowInSecondary->assertNoEvents(); @@ -6068,14 +6012,14 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) { // Test touch down on primary display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInPrimary->consumeMotionDown(ADISPLAY_ID_DEFAULT); monitorInPrimary.consumeMotionDown(ADISPLAY_ID_DEFAULT); // Test touch down on second display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowInSecondary->consumeMotionDown(SECOND_DISPLAY_ID); monitorInSecondary.consumeMotionDown(SECOND_DISPLAY_ID); @@ -6089,14 +6033,14 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) { // Test inject a move motion event, no window/monitor should receive the event. ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {110, 200})) << "Inject motion event should return InputEventInjectionResult::FAILED"; windowInPrimary->assertNoEvents(); monitorInPrimary.assertNoEvents(); ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, SECOND_DISPLAY_ID, {110, 200})) << "Inject motion event should return InputEventInjectionResult::FAILED"; windowInSecondary->assertNoEvents(); @@ -6239,12 +6183,7 @@ protected: InputEventInjectionSync::WAIT_FOR_RESULT, 100ms, policyFlags | additionalPolicyFlags)); - InputEvent* received = mWindow->consume(); - ASSERT_NE(nullptr, received); - ASSERT_EQ(resolvedDeviceId, received->getDeviceId()); - ASSERT_EQ(received->getType(), InputEventType::KEY); - KeyEvent& keyEvent = static_cast(*received); - ASSERT_EQ(flags, keyEvent.getFlags()); + mWindow->consumeKeyEvent(AllOf(WithDeviceId(resolvedDeviceId), WithFlags(flags))); } void testInjectedMotion(int32_t policyFlags, int32_t injectedDeviceId, int32_t resolvedDeviceId, @@ -6274,12 +6213,7 @@ protected: InputEventInjectionSync::WAIT_FOR_RESULT, 100ms, policyFlags | additionalPolicyFlags)); - InputEvent* received = mWindow->consume(); - ASSERT_NE(nullptr, received); - ASSERT_EQ(resolvedDeviceId, received->getDeviceId()); - ASSERT_EQ(received->getType(), InputEventType::MOTION); - MotionEvent& motionEvent = static_cast(*received); - ASSERT_EQ(flags, motionEvent.getFlags()); + mWindow->consumeMotionEvent(AllOf(WithFlags(flags), WithDeviceId(resolvedDeviceId))); } private: @@ -6355,7 +6289,7 @@ protected: // the onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {20, 20})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mUnfocusedWindow->consumeMotionDown(); @@ -6369,7 +6303,8 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Succe // onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, {20, 20})) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, + {20, 20})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mFocusedWindow->consumeMotionDown(); @@ -6381,7 +6316,7 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPo // have focus. Ensure no window received the onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectKeyDownNoRepeat(mDispatcher, ADISPLAY_ID_DEFAULT)) + injectKeyDownNoRepeat(*mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mFocusedWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); @@ -6394,7 +6329,7 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMo // onPointerDownOutsideFocus callback. TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, FOCUSED_WINDOW_TOUCH_POINT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mFocusedWindow->consumeMotionDown(); @@ -6412,7 +6347,7 @@ TEST_F(InputDispatcherOnPointerDownOutsideFocus, NoFocusChangeFlag) { .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(20).y(20)) .addFlag(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE) .build(); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, event)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, event)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mUnfocusedWindow->consumeAnyMotionDown(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE); @@ -6454,28 +6389,24 @@ protected: void consumeMotionEvent(const sp& window, int32_t expectedAction, const std::vector& points) { const std::string name = window->getName(); - InputEvent* event = window->consume(); - - ASSERT_NE(nullptr, event) << name.c_str() - << ": consumer should have returned non-NULL event."; + MotionEvent* motionEvent = window->consumeMotion(); - ASSERT_EQ(InputEventType::MOTION, event->getType()) - << name.c_str() << ": expected MotionEvent, got " << *event; + ASSERT_NE(nullptr, motionEvent) + << name.c_str() << ": consumer should have returned non-NULL event."; - const MotionEvent& motionEvent = static_cast(*event); - assertMotionAction(expectedAction, motionEvent.getAction()); - ASSERT_EQ(points.size(), motionEvent.getPointerCount()); + assertMotionAction(expectedAction, motionEvent->getAction()); + ASSERT_EQ(points.size(), motionEvent->getPointerCount()); for (size_t i = 0; i < points.size(); i++) { float expectedX = points[i].x; float expectedY = points[i].y; - EXPECT_EQ(expectedX, motionEvent.getX(i)) + EXPECT_EQ(expectedX, motionEvent->getX(i)) << "expected " << expectedX << " for x[" << i << "] coord of " << name.c_str() - << ", got " << motionEvent.getX(i); - EXPECT_EQ(expectedY, motionEvent.getY(i)) + << ", got " << motionEvent->getX(i); + EXPECT_EQ(expectedY, motionEvent->getY(i)) << "expected " << expectedY << " for y[" << i << "] coord of " << name.c_str() - << ", got " << motionEvent.getY(i); + << ", got " << motionEvent->getY(i); } } @@ -6688,16 +6619,17 @@ class InputDispatcherSingleWindowAnr : public InputDispatcherTest { } protected: + static constexpr std::chrono::duration SPY_TIMEOUT = 200ms; std::shared_ptr mApplication; sp mWindow; static constexpr PointF WINDOW_LOCATION = {20, 20}; void tapOnWindow() { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); } @@ -6707,7 +6639,7 @@ protected: spy->setTrustedOverlay(true); spy->setFocusable(false); spy->setSpy(true); - spy->setDispatchingTimeout(30ms); + spy->setDispatchingTimeout(SPY_TIMEOUT); mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *mWindow->getInfo()}, {}, 0, 0}); return spy; } @@ -6724,7 +6656,7 @@ TEST_F(InputDispatcherSingleWindowAnr, WhenTouchIsConsumed_NoAnr) { // Send a regular key and respond, which should not cause an ANR. TEST_F(InputDispatcherSingleWindowAnr, WhenKeyIsConsumed_NoAnr) { - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(mDispatcher)); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher)); mWindow->consumeKeyDown(ADISPLAY_ID_NONE); ASSERT_TRUE(mDispatcher->waitForIdle()); mFakePolicy->assertNotifyAnrWasNotCalled(); @@ -6736,8 +6668,8 @@ TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) { mWindow->consumeFocusEvent(false); InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE, /*injectionTimeout=*/50ms, + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, + InputEventInjectionSync::NONE, CONSUME_TIMEOUT_EVENT_EXPECTED, /*allowKeyRepeat=*/false); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); // Key will not go to window because we have no focused window. @@ -6756,7 +6688,7 @@ TEST_F(InputDispatcherSingleWindowAnr, WhenFocusedApplicationChanges_NoAnr) { // So InputDispatcher will enqueue ACTION_CANCEL event as well. TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); std::optional sequenceNum = mWindow->receiveEvent(); // ACTION_DOWN @@ -6774,7 +6706,7 @@ TEST_F(InputDispatcherSingleWindowAnr, OnPointerDown_BasicAnr) { // Send a key to the app and have the app not respond right away. TEST_F(InputDispatcherSingleWindowAnr, OnKeyDown_BasicAnr) { // Inject a key, and don't respond - expect that ANR is called. - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(mDispatcher)); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDownNoRepeat(*mDispatcher)); std::optional sequenceNum = mWindow->receiveEvent(); ASSERT_TRUE(sequenceNum); const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); @@ -6790,7 +6722,7 @@ TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) { // taps on the window work as normal ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown()); mDispatcher->waitForIdle(); @@ -6800,7 +6732,7 @@ TEST_F(InputDispatcherSingleWindowAnr, FocusedApplication_NoFocusedWindow) { // We specify the injection timeout to be smaller than the application timeout, to ensure that // injection times out (instead of failing). const InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); @@ -6851,8 +6783,8 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) // We specify the injection timeout to be smaller than the application timeout, to ensure that // injection times out (instead of failing). const InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::WAIT_FOR_RESULT, 50ms, /*allowKeyRepeat=*/false); + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, + InputEventInjectionSync::WAIT_FOR_RESULT, 100ms, /*allowKeyRepeat=*/false); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); const std::chrono::duration appTimeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); @@ -6874,16 +6806,13 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) { mWindow->consumeFocusEvent(false); // Once a focused event arrives, we get an ANR for this application - const InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::WAIT_FOR_RESULT, 50ms); - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); + ASSERT_NO_FATAL_FAILURE(assertInjectedKeyTimesOut(*mDispatcher)); const std::chrono::duration timeout = mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(timeout, mApplication); // Future focused events get dropped right away - ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(mDispatcher)); + ASSERT_EQ(InputEventInjectionResult::FAILED, injectKeyDown(*mDispatcher)); ASSERT_TRUE(mDispatcher->waitForIdle()); mWindow->assertNoEvents(); } @@ -6899,14 +6828,14 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DropsFocusedEvents) { */ TEST_F(InputDispatcherSingleWindowAnr, Anr_HandlesEventsWithIdenticalTimestamps) { nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION, {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION}, 500ms, InputEventInjectionSync::WAIT_FOR_RESULT, currentTime); // Now send ACTION_UP, with identical timestamp - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION, {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION}, @@ -6923,7 +6852,7 @@ TEST_F(InputDispatcherSingleWindowAnr, SpyWindowAnr) { sp spy = addSpyWindow(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); mWindow->consumeMotionDown(); @@ -6945,9 +6874,9 @@ TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnKey) sp spy = addSpyWindow(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)); + injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT)); mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher, ADISPLAY_ID_DEFAULT)); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher, ADISPLAY_ID_DEFAULT)); // Stuck on the ACTION_UP const std::chrono::duration timeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); @@ -6992,19 +6921,20 @@ TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMoti } TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) { - mDispatcher->setMonitorDispatchingTimeoutForTest(30ms); + mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT); FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); const std::optional consumeSeq = monitor.receiveEvent(); ASSERT_TRUE(consumeSeq); - mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(30ms, monitor.getToken(), MONITOR_PID); + mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(SPY_TIMEOUT, monitor.getToken(), + MONITOR_PID); monitor.finishEvent(*consumeSeq); monitor.consumeMotionCancel(ADISPLAY_ID_DEFAULT); @@ -7046,7 +6976,7 @@ TEST_F(InputDispatcherSingleWindowAnr, SameWindow_CanReceiveAnrTwice) { // it. TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, WINDOW_LOCATION)); const std::chrono::duration windowTimeout = mWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); @@ -7066,12 +6996,12 @@ TEST_F(InputDispatcherSingleWindowAnr, Policy_DoesNotGetDuplicateAnr) { /** * If a window is processing a motion event, and then a key event comes in, the key event should - * not to to the focused window until the motion is processed. + * not get delivered to the focused window until the motion is processed. * * Warning!!! * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT * and the injection timeout that we specify when injecting the key. - * We must have the injection timeout (10ms) be smaller than + * We must have the injection timeout (100ms) be smaller than * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms). * * If that value changes, this test should also change. @@ -7091,13 +7021,15 @@ TEST_F(InputDispatcherSingleWindowAnr, Key_StaysPendingWhileMotionIsProcessed) { // we will receive INJECTION_TIMED_OUT as the result. InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::WAIT_FOR_RESULT, 50ms); + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, + InputEventInjectionSync::WAIT_FOR_RESULT, 100ms); ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); // Key will not be sent to the window, yet, because the window is still processing events // and the key remains pending, waiting for the touch events to be processed - std::optional keySequenceNum = mWindow->receiveEvent(); - ASSERT_FALSE(keySequenceNum); + // Make sure that `assertNoEvents` doesn't wait too long, because it could cause an ANR. + // Rely here on the fact that it uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED under the hood. + static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms); + mWindow->assertNoEvents(); std::this_thread::sleep_for(500ms); // if we wait long enough though, dispatcher will give up, and still send the key @@ -7126,11 +7058,13 @@ TEST_F(InputDispatcherSingleWindowAnr, // Don't finish the events yet, and send a key // Injection is async, so it will succeed ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE)); + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, + ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE)); // At this point, key is still pending, and should not be sent to the application yet. - std::optional keySequenceNum = mWindow->receiveEvent(); - ASSERT_FALSE(keySequenceNum); + // Make sure the `assertNoEvents` check doesn't take too long. It uses + // CONSUME_TIMEOUT_NO_EVENT_EXPECTED under the hood. + static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms); + mWindow->assertNoEvents(); // Now tap down again. It should cause the pending key to go to the focused window right away. tapOnWindow(); @@ -7242,10 +7176,10 @@ protected: private: void tap(const PointF& location) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, location)); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, location)); } }; @@ -7254,7 +7188,7 @@ private: // should be ANR'd first. TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, FOCUSED_WINDOW_LOCATION)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mFocusedWindow->consumeMotionDown(); @@ -7265,7 +7199,7 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) { mFakePolicy->assertNotifyAnrWasNotCalled(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, FOCUSED_WINDOW_LOCATION)); std::optional unfocusedSequenceNum = mUnfocusedWindow->receiveEvent(); ASSERT_TRUE(unfocusedSequenceNum); @@ -7346,10 +7280,10 @@ TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) { // Tap once again // We cannot use "tapOnFocusedWindow" because it asserts the injection result to be success ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, FOCUSED_WINDOW_LOCATION)); ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, FOCUSED_WINDOW_LOCATION)); // Unfocused window does not receive ACTION_OUTSIDE because the tapped window is not a // valid touch target @@ -7370,7 +7304,7 @@ TEST_F(InputDispatcherMultiWindowAnr, DuringAnr_SecondTapIsIgnored) { // If you tap outside of all windows, there will not be ANR TEST_F(InputDispatcherMultiWindowAnr, TapOutsideAllWindows_DoesNotAnr) { ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, LOCATION_OUTSIDE_ALL_WINDOWS)); ASSERT_TRUE(mDispatcher->waitForIdle()); mFakePolicy->assertNotifyAnrWasNotCalled(); @@ -7383,7 +7317,7 @@ TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) { {{*mUnfocusedWindow->getInfo(), *mFocusedWindow->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, FOCUSED_WINDOW_LOCATION)); std::this_thread::sleep_for(mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT)); @@ -7397,13 +7331,13 @@ TEST_F(InputDispatcherMultiWindowAnr, Window_CanBePaused) { /** * If a window is processing a motion event, and then a key event comes in, the key event should - * not to to the focused window until the motion is processed. + * not get delivered to the focused window until the motion is processed. * If a different window becomes focused at this time, the key should go to that window instead. * * Warning!!! * This test depends on the value of android::inputdispatcher::KEY_WAITING_FOR_MOTION_TIMEOUT * and the injection timeout that we specify when injecting the key. - * We must have the injection timeout (10ms) be smaller than + * We must have the injection timeout (100ms) be smaller than * KEY_WAITING_FOR_MOTION_TIMEOUT (currently 500ms). * * If that value changes, this test should also change. @@ -7424,13 +7358,15 @@ TEST_F(InputDispatcherMultiWindowAnr, PendingKey_GoesToNewlyFocusedWindow) { // window even if motions are still being processed. InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE, /*injectionTimeout=*/50ms); + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, + InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); // Key will not be sent to the window, yet, because the window is still processing events - // and the key remains pending, waiting for the touch events to be processed - std::optional keySequenceNum = mFocusedWindow->receiveEvent(); - ASSERT_FALSE(keySequenceNum); + // and the key remains pending, waiting for the touch events to be processed. + // Make sure `assertNoEvents` doesn't take too long. It uses CONSUME_TIMEOUT_NO_EVENT_EXPECTED + // under the hood. + static_assert(CONSUME_TIMEOUT_NO_EVENT_EXPECTED < 100ms); + mFocusedWindow->assertNoEvents(); // Switch the focus to the "unfocused" window that we tapped. Expect the key to go there mFocusedWindow->setFocusable(false); @@ -7514,7 +7450,7 @@ TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) { TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) { std::shared_ptr focusedApplication = std::make_shared(); - focusedApplication->setDispatchingTimeout(100ms); + focusedApplication->setDispatchingTimeout(200ms); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication); // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused. mFocusedWindow->setFocusable(false); @@ -7527,8 +7463,8 @@ TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_ // 'focusedApplication' will get blamed if this timer completes. // Key will not be sent anywhere because we have no focused window. It will remain pending. InputEventInjectionResult result = - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE, /*injectionTimeout=*/50ms, + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, + InputEventInjectionSync::NONE, /*injectionTimeout=*/100ms, /*allowKeyRepeat=*/false); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, result); @@ -7539,7 +7475,7 @@ TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_ // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'. // For this test, it means that the key would get delivered to the window once it becomes // focused. - std::this_thread::sleep_for(50ms); + std::this_thread::sleep_for(100ms); // Touch unfocused window. This should force the pending key to get dropped. mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, @@ -7662,7 +7598,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, CanGetFocus) { // window gets focused mWindow->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_NONE); } @@ -7674,10 +7610,10 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) { // window gets focused mWindow->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_NONE); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyUp(ADISPLAY_ID_NONE); @@ -7687,7 +7623,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAllWindowsFocusable) { // window loses focus since one of the windows associated with the token in not focusable mWindow->consumeFocusEvent(false); - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; mWindow->assertNoEvents(); } @@ -7699,20 +7635,20 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) { // window gets focused mWindow->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_NONE); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyUp(ADISPLAY_ID_NONE); mMirror->setVisible(false); mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_NONE); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyUp(ADISPLAY_ID_NONE); @@ -7722,7 +7658,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedIfAnyWindowVisible) { // window loses focus only after all windows associated with the token become invisible. mWindow->consumeFocusEvent(false); - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; mWindow->assertNoEvents(); } @@ -7733,20 +7669,20 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) { // window gets focused mWindow->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_NONE); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyUp(ADISPLAY_ID_NONE); // single window is removed but the window token remains focused mDispatcher->onWindowInfosChanged({{*mMirror->getInfo()}, {}, 0, 0}); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_NONE); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyUp(ADISPLAY_ID_NONE); @@ -7754,7 +7690,7 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, FocusedWhileWindowsAlive) { mDispatcher->onWindowInfosChanged({{}, {}, 0, 0}); mWindow->consumeFocusEvent(false); - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::TIMED_OUT"; mWindow->assertNoEvents(); } @@ -7769,8 +7705,8 @@ TEST_F(InputDispatcherMirrorWindowFocusTests, DeferFocusWhenInvisible) { // Injected key goes to pending queue. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::NONE)); + injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, + ADISPLAY_ID_DEFAULT, InputEventInjectionSync::NONE)); mMirror->setVisible(true); mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mMirror->getInfo()}, {}, 0, 0}); @@ -8373,33 +8309,33 @@ protected: switch (fromSource) { case AINPUT_SOURCE_TOUCHSCREEN: ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; break; case AINPUT_SOURCE_STYLUS: ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent( - mDispatcher, - MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, - AINPUT_SOURCE_STYLUS) - .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) - .pointer(PointerBuilder(0, ToolType::STYLUS) - .x(50) - .y(50)) - .build())); + injectMotionEvent(*mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_STYLUS) + .buttonState( + AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) + .pointer(PointerBuilder(0, ToolType::STYLUS) + .x(50) + .y(50)) + .build())); break; case AINPUT_SOURCE_MOUSE: ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent( - mDispatcher, - MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) - .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(MOUSE_POINTER_ID, - ToolType::MOUSE) - .x(50) - .y(50)) - .build())); + injectMotionEvent(*mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_MOUSE) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(MOUSE_POINTER_ID, + ToolType::MOUSE) + .x(50) + .y(50)) + .build())); break; default: FAIL() << "Source " << fromSource << " doesn't support drag and drop"; @@ -8446,7 +8382,7 @@ TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) { // Move on window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8455,7 +8391,7 @@ TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) { // Move to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8464,7 +8400,7 @@ TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) { // Move back to original window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8472,7 +8408,8 @@ TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) { mSecondWindow->consumeDragEvent(true, -50, 50); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); mWindow->assertNoEvents(); @@ -8492,7 +8429,7 @@ TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(60).y(60)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -8508,7 +8445,7 @@ TEST_F(InputDispatcherDragTests, DragAndDrop) { // Move on window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8517,7 +8454,7 @@ TEST_F(InputDispatcherDragTests, DragAndDrop) { // Move to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8526,7 +8463,7 @@ TEST_F(InputDispatcherDragTests, DragAndDrop) { // drop to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); @@ -8540,7 +8477,7 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) { // Move on window and keep button pressed. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS) .buttonState(AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) @@ -8552,7 +8489,7 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) { // Move to another window and release button, expect to drop item. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS) .buttonState(0) .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50)) @@ -8565,7 +8502,7 @@ TEST_F(InputDispatcherDragTests, StylusDragAndDrop) { // nothing to the window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS) .buttonState(0) .pointer(PointerBuilder(0, ToolType::STYLUS).x(150).y(50)) @@ -8586,7 +8523,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) { // Move on window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8595,7 +8532,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) { // Move to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8604,7 +8541,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) { // drop to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); @@ -8618,7 +8555,7 @@ TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) { mWindow->setPreventSplitting(true); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -8631,7 +8568,7 @@ TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(75).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeMotionPointerDown(/*pointerIndex=*/1); @@ -8643,7 +8580,7 @@ TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) { TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) { // First down on second window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -8658,7 +8595,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -8674,7 +8611,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)); mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); mWindow->consumeDragEvent(false, 50, 50); @@ -8688,7 +8625,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)); mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken()); @@ -8711,7 +8648,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { // Let second display has a touch state. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(SECOND_DISPLAY_ID) @@ -8729,7 +8666,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { // Move on window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8738,7 +8675,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { // Move to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT); @@ -8747,7 +8684,7 @@ TEST_F(InputDispatcherDragTests, DragAndDropWhenMultiDisplays) { // drop to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT); @@ -8760,11 +8697,10 @@ TEST_F(InputDispatcherDragTests, MouseDragAndDrop) { startDrag(true, AINPUT_SOURCE_MOUSE); // Move on window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(MOUSE_POINTER_ID, - ToolType::MOUSE) + .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE) .x(50) .y(50)) .build())) @@ -8775,11 +8711,10 @@ TEST_F(InputDispatcherDragTests, MouseDragAndDrop) { // Move to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) - .pointer(PointerBuilder(MOUSE_POINTER_ID, - ToolType::MOUSE) + .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE) .x(150) .y(50)) .build())) @@ -8790,11 +8725,10 @@ TEST_F(InputDispatcherDragTests, MouseDragAndDrop) { // drop to another window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, + injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) .buttonState(0) - .pointer(PointerBuilder(MOUSE_POINTER_ID, - ToolType::MOUSE) + .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE) .x(150) .y(50)) .build())) @@ -9040,7 +8974,8 @@ TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchOnSecondaryDisplayOnly) TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInteractedWindow) { // Interact with the window first. - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectKeyDown(*mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT); @@ -9105,7 +9040,7 @@ TEST_F(InputDispatcherSpyWindowTest, NoForegroundWindow) { mDispatcher->onWindowInfosChanged({{*spy->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); } @@ -9145,7 +9080,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesInputInOrder) { } ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; std::vector eventOrder; @@ -9183,7 +9118,7 @@ TEST_F(InputDispatcherSpyWindowTest, NotTouchable) { mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); spy->assertNoEvents(); @@ -9202,19 +9137,19 @@ TEST_F(InputDispatcherSpyWindowTest, TouchableRegion) { // Inject an event outside the spy window's touchable region. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); spy->assertNoEvents(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionUp(); spy->assertNoEvents(); // Inject an event inside the spy window's touchable region. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {5, 10})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9236,7 +9171,7 @@ TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { // Inject an event outside the spy window's frame and touchable region. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9258,7 +9193,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { {{*spy->getInfo(), *windowLeft->getInfo(), *windowRight->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowLeft->consumeMotionDown(); @@ -9271,7 +9206,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; windowRight->consumeMotionDown(); @@ -9290,7 +9225,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { mDispatcher->onWindowInfosChanged({{*spyRight->getInfo(), *window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9303,7 +9238,7 @@ TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionPointerDown(/*pointerIndex=*/1); @@ -9327,7 +9262,7 @@ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { // First finger down, no window touched. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -9342,7 +9277,7 @@ TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -9363,11 +9298,11 @@ TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) { setFocusedWindow(window); window->consumeFocusEvent(true); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; window->consumeKeyDown(ADISPLAY_ID_NONE); - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(*mDispatcher)) << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; window->consumeKeyUp(ADISPLAY_ID_NONE); @@ -9388,7 +9323,7 @@ TEST_F(InputDispatcherPilferPointersTest, PilferPointers) { {{*spy1->getInfo(), *spy2->getInfo(), *window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); spy1->consumeMotionDown(); @@ -9402,7 +9337,7 @@ TEST_F(InputDispatcherPilferPointersTest, PilferPointers) { // The rest of the gesture should only be sent to the second spy window. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy2->consumeMotionMove(); @@ -9420,7 +9355,7 @@ TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream mDispatcher->onWindowInfosChanged({{*spy->getInfo(), *window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); @@ -9430,7 +9365,7 @@ TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionUp(ADISPLAY_ID_DEFAULT); } @@ -9447,7 +9382,7 @@ TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) // First finger down on the window and the spy. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionDown(); @@ -9466,7 +9401,7 @@ TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; @@ -9482,7 +9417,7 @@ TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(-5).y(-5)) .build(); ASSERT_EQ(InputEventInjectionResult::FAILED, - injectMotionEvent(mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::FAILED"; @@ -9503,7 +9438,7 @@ TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) { // First finger down on the window only ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {150, 150})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9517,7 +9452,7 @@ TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(10).y(10)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionDown(); @@ -9533,7 +9468,7 @@ TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) { .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionPointerDown(1); @@ -9563,7 +9498,7 @@ TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) { // First finger down on both spy and window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {10, 10})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9578,7 +9513,7 @@ TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; spy->consumeMotionPointerDown(1); @@ -9606,7 +9541,7 @@ TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) { // First finger down on both window and spy ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {10, 10})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9625,7 +9560,7 @@ TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) { .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); @@ -9777,7 +9712,7 @@ struct User { : mPid(pid), mUid(uid), mDispatcher(dispatcher) {} InputEventInjectionResult injectTargetedMotion(int32_t action) const { - return injectMotionEvent(mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN, + return injectMotionEvent(*mDispatcher, action, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {100, 200}, {AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION}, @@ -9786,7 +9721,7 @@ struct User { } InputEventInjectionResult injectTargetedKey(int32_t action) const { - return inputdispatcher::injectKey(mDispatcher, action, /*repeatCount=*/0, ADISPLAY_ID_NONE, + return inputdispatcher::injectKey(*mDispatcher, action, /*repeatCount=*/0, ADISPLAY_ID_NONE, InputEventInjectionSync::WAIT_FOR_RESULT, INJECT_EVENT_TIMEOUT, /*allowKeyRepeat=*/false, {mUid}, mPolicyFlags); @@ -9883,7 +9818,7 @@ TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTarget // A user that has injection permission can inject into any window. EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + injectMotionEvent(*mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)); randosSpy->consumeMotionDown(); window->consumeMotionDown(); @@ -9891,7 +9826,7 @@ TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTarget setFocusedWindow(randosSpy); randosSpy->consumeFocusEvent(true); - EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)); + EXPECT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)); randosSpy->consumeKeyDown(ADISPLAY_ID_NONE); window->assertNoEvents(); } diff --git a/services/inputflinger/tests/TestInputListenerMatchers.cpp b/services/inputflinger/tests/TestInputListenerMatchers.cpp new file mode 100644 index 0000000000..1464e6097e --- /dev/null +++ b/services/inputflinger/tests/TestInputListenerMatchers.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2023 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 "TestInputListenerMatchers.h" + +namespace android { + +WithKeyActionMatcher WithKeyAction(int32_t action) { + return WithKeyActionMatcher(action); +} + +WithMotionActionMatcher WithMotionAction(int32_t action) { + return WithMotionActionMatcher(action); +} + +WithDisplayIdMatcher WithDisplayId(int32_t displayId) { + return WithDisplayIdMatcher(displayId); +} + +WithDeviceIdMatcher WithDeviceId(int32_t deviceId) { + return WithDeviceIdMatcher(deviceId); +} + +} // namespace android diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h index 70bad7c66b..020ea86da2 100644 --- a/services/inputflinger/tests/TestInputListenerMatchers.h +++ b/services/inputflinger/tests/TestInputListenerMatchers.h @@ -23,53 +23,145 @@ #include #include +#include "NotifyArgs.h" #include "TestConstants.h" namespace android { -MATCHER_P(WithMotionAction, action, "MotionEvent with specified action") { - bool matches = action == arg.action; - if (!matches) { - *result_listener << "expected action " << MotionEvent::actionToString(action) - << ", but got " << MotionEvent::actionToString(arg.action); - } - if (action == AMOTION_EVENT_ACTION_CANCEL) { - if (!matches) { - *result_listener << "; "; - } - *result_listener << "expected FLAG_CANCELED to be set with ACTION_CANCEL, but was not set"; - matches &= (arg.flags & AMOTION_EVENT_FLAG_CANCELED) != 0; - } - return matches; -} - -MATCHER_P(WithKeyAction, action, "KeyEvent with specified action") { - *result_listener << "expected action " << KeyEvent::actionToString(action) << ", but got " - << KeyEvent::actionToString(arg.action); - return arg.action == action; -} - MATCHER_P(WithSource, source, "InputEvent with specified source") { *result_listener << "expected source " << inputEventSourceToString(source) << ", but got " << inputEventSourceToString(arg.source); return arg.source == source; } -MATCHER_P(WithDisplayId, displayId, "InputEvent with specified displayId") { - *result_listener << "expected displayId " << displayId << ", but got " << arg.displayId; - return arg.displayId == displayId; -} +/// Key action +class WithKeyActionMatcher { +public: + using is_gtest_matcher = void; + explicit WithKeyActionMatcher(int32_t action) : mAction(action) {} -MATCHER_P(WithDeviceId, deviceId, "InputEvent with specified deviceId") { - *result_listener << "expected deviceId " << deviceId << ", but got " << arg.deviceId; - return arg.deviceId == deviceId; -} + bool MatchAndExplain(const NotifyKeyArgs& args, std::ostream*) const { + return mAction == args.action; + } + + bool MatchAndExplain(const KeyEvent& event, std::ostream*) const { + return mAction == event.getAction(); + } + + void DescribeTo(std::ostream* os) const { + *os << "with key action " << KeyEvent::actionToString(mAction); + } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong action"; } + +private: + const int32_t mAction; +}; + +WithKeyActionMatcher WithKeyAction(int32_t action); + +/// Motion action +class WithMotionActionMatcher { +public: + using is_gtest_matcher = void; + explicit WithMotionActionMatcher(int32_t action) : mAction(action) {} + + bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const { + bool matches = mAction == args.action; + if (args.action == AMOTION_EVENT_ACTION_CANCEL) { + matches &= (args.flags & AMOTION_EVENT_FLAG_CANCELED) != 0; + } + return matches; + } + + bool MatchAndExplain(const MotionEvent& event, std::ostream*) const { + bool matches = mAction == event.getAction(); + if (event.getAction() == AMOTION_EVENT_ACTION_CANCEL) { + matches &= (event.getFlags() & AMOTION_EVENT_FLAG_CANCELED) != 0; + } + return matches; + } + + void DescribeTo(std::ostream* os) const { + *os << "with motion action " << MotionEvent::actionToString(mAction); + if (mAction == AMOTION_EVENT_ACTION_CANCEL) { + *os << " and FLAG_CANCELED"; + } + } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong action"; } + +private: + const int32_t mAction; +}; + +WithMotionActionMatcher WithMotionAction(int32_t action); + +/// Display Id +class WithDisplayIdMatcher { +public: + using is_gtest_matcher = void; + explicit WithDisplayIdMatcher(int32_t displayId) : mDisplayId(displayId) {} + + bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const { + return mDisplayId == args.displayId; + } + + bool MatchAndExplain(const NotifyKeyArgs& args, std::ostream*) const { + return mDisplayId == args.displayId; + } + + bool MatchAndExplain(const InputEvent& event, std::ostream*) const { + return mDisplayId == event.getDisplayId(); + } + + void DescribeTo(std::ostream* os) const { *os << "with display id " << mDisplayId; } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong display id"; } + +private: + const int32_t mDisplayId; +}; + +WithDisplayIdMatcher WithDisplayId(int32_t displayId); + +/// Device Id +class WithDeviceIdMatcher { +public: + using is_gtest_matcher = void; + explicit WithDeviceIdMatcher(int32_t deviceId) : mDeviceId(deviceId) {} + + bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const { + return mDeviceId == args.deviceId; + } + + bool MatchAndExplain(const NotifyKeyArgs& args, std::ostream*) const { + return mDeviceId == args.deviceId; + } + + bool MatchAndExplain(const InputEvent& event, std::ostream*) const { + return mDeviceId == event.getDeviceId(); + } + + void DescribeTo(std::ostream* os) const { *os << "with device id " << mDeviceId; } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong device id"; } + +private: + const int32_t mDeviceId; +}; + +WithDeviceIdMatcher WithDeviceId(int32_t deviceId); MATCHER_P(WithKeyCode, keyCode, "KeyEvent with specified key code") { *result_listener << "expected key code " << keyCode << ", but got " << arg.keyCode; return arg.keyCode == keyCode; } +MATCHER_P(WithRepeatCount, repeatCount, "KeyEvent with specified repeat count") { + return arg.getRepeatCount() == repeatCount; +} + MATCHER_P(WithPointerCount, count, "MotionEvent with specified number of pointers") { *result_listener << "expected " << count << " pointer(s), but got " << arg.getPointerCount(); return arg.getPointerCount() == count; -- GitLab From a09cddcb63bbb04f59deac653b3ddd1f16d38757 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Tue, 25 Jul 2023 09:34:11 -0400 Subject: [PATCH 0347/1187] RenderEngine: Limit the size of blur input to the display size Some layers are extraordinarily large. In the particular case we've found, the layer does not have any content, but even if it did, content outside the display would not impact the blur. So limit the size of the rectangle we use for blurring, which in turn limits the size of the buffers we allocate to compute the blur. Use the canvas' existing clip, which has already been adjusted to the size of the display. Bug: 283427479 Bug: 292539958 Test: manual (logcat) Change-Id: I17e646cce0dca02f4e6a18032ecd1e9120fcf880 --- libs/renderengine/skia/SkiaRenderEngine.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index 871d258ce7..01acf0e921 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -816,8 +816,20 @@ void SkiaRenderEngine::drawLayersInternal( if (!blurInput) { blurInput = activeSurface->makeImageSnapshot(); } + // rect to be blurred in the coordinate space of blurInput - const auto blurRect = canvas->getTotalMatrix().mapRect(bounds.rect()); + SkRect blurRect = canvas->getTotalMatrix().mapRect(bounds.rect()); + + // Some layers may be much bigger than the screen. If we used + // `blurRect` directly, this would allocate a large buffer with no + // benefit. Apply the clip, which already takes the display size + // into account. The clipped size will then be used to calculate the + // size of the buffer we will create for blurring. + if (!blurRect.intersect(SkRect::Make(canvas->getDeviceClipBounds()))) { + // This should not happen, but if it did, we would use the full + // sized layer, which should still be fine. + ALOGW("blur bounds does not intersect display clip!"); + } // if the clip needs to be applied then apply it now and make sure // it is restored before we attempt to draw any shadows. -- GitLab From 1293d58ad7884e302634bb8af5957d854520802d Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Tue, 25 Jul 2023 21:55:03 +0000 Subject: [PATCH 0348/1187] Revert "Log fatal if transaction callbacks are called more than once" This reverts commit fd0c1b4b42a0b0d946718dc7819281b290320e81. Reason for revert: reverting in favor of ag/24199759 which should fix the root cause Change-Id: I23dd23954edad3a95899b8d75f5b518c836b302b --- libs/gui/SurfaceComposerClient.cpp | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index dcadf07d06..5bc05ef0d8 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1901,29 +1901,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTrans CallbackId::Type callbackType) { auto listener = TransactionCompletedListener::getInstance(); - TransactionCompletedCallback callbackWithContext = - [called = false, callback, - callbackContext](nsecs_t latchTime, const sp& presentFence, - const std::vector& stats) mutable { - if (called) { - std::stringstream stream; - auto it = stats.begin(); - if (it != stats.end()) { - stream << it->surfaceControl->getName(); - it++; - } - while (it != stats.end()) { - stream << ", " << it->surfaceControl->getName(); - it++; - } - LOG_ALWAYS_FATAL("Transaction callback called more than once. SurfaceControls: " - "%s", - stream.str().c_str()); - } - callback(callbackContext, latchTime, presentFence, stats); - called = true; - }; - + auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3); const auto& surfaceControls = mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls; -- GitLab From 30da367c6c0781d9783459567ec57d9d10c77c92 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Tue, 25 Jul 2023 16:52:01 -0500 Subject: [PATCH 0349/1187] Ensure transaction commit callbacks are called at most once. Bug: 288781573 Bug: 292443283 Test: atest LayerTransactionTest Change-Id: Ide66601b8a892b4bf5a331d83d38b4bd50919751 --- libs/gui/SurfaceComposerClient.cpp | 6 +++- .../tests/LayerTransaction_test.cpp | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 5bc05ef0d8..db99726739 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -377,7 +377,6 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener } auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId]; if (!callbackFunction) { - ALOGE("cannot call null callback function, skipping"); continue; } std::vector surfaceControlStats; @@ -394,6 +393,11 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener callbackFunction(transactionStats.latchTime, transactionStats.presentFence, surfaceControlStats); + + // More than one transaction may contain the same callback id. Erase the callback from + // the map to ensure that it is only called once. This can happen if transactions are + // parcelled out of process and applied in both processes. + callbacksMap.erase(callbackId); } // handle on complete callbacks diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp index cbd54e7aa9..03de8d0b6d 100644 --- a/services/surfaceflinger/tests/LayerTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp @@ -184,6 +184,35 @@ TEST_F(LayerTransactionTest, BufferTakesPriorityOverColor) { } } +TEST_F(LayerTransactionTest, CommitCallbackCalledOnce) { + auto callCount = 0; + auto commitCallback = + [&callCount](void* /* context */, nsecs_t /* latchTime */, + const sp& /* presentFence */, + const std::vector& /* stats */) mutable { + callCount++; + }; + + // Create two transactions that both contain the same callback id. + Transaction t1; + t1.addTransactionCommittedCallback(commitCallback, nullptr); + Parcel parcel; + t1.writeToParcel(&parcel); + parcel.setDataPosition(0); + Transaction t2; + t2.readFromParcel(&parcel); + + // Apply the two transactions. There is a race here as we can't guarantee that the two + // transactions will be applied within the same SurfaceFlinger commit. If the transactions are + // applied within the same commit then we verify that callback ids are deduplicated within a + // single commit. Otherwise, we verify that commit callbacks are deduplicated across separate + // commits. + t1.apply(); + t2.apply(/*synchronous=*/true); + + ASSERT_EQ(callCount, 1); +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -- GitLab From f6d21b5582b76c70c49003f57595f38535f58f29 Mon Sep 17 00:00:00 2001 From: Xiang Wang Date: Tue, 25 Jul 2023 17:34:01 -0700 Subject: [PATCH 0350/1187] Update NDK doc for setThreads on permission error Bug: 291830812 Test: atest PerformanceHintTest Change-Id: If62fbaa2a3e50718e8a231779c56d33c1fab33ca --- include/android/performance_hint.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h index b494f897d5..cedd361f7e 100644 --- a/include/android/performance_hint.h +++ b/include/android/performance_hint.h @@ -171,6 +171,7 @@ void APerformanceHint_closeSession( * @return 0 on success. * EINVAL if the list of thread ids is empty or if any of the thread ids is not part of the thread group. * EPIPE if communication with the system service has failed. + * EPERM if any thread id doesn't belong to the application. */ int APerformanceHint_setThreads( APerformanceHintSession* session, -- GitLab From 8b6bca66d82e9a6aec334c28b2bc8046d685592d Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 24 Jul 2023 20:46:34 +0000 Subject: [PATCH 0351/1187] SF: add entire suite of CtsGraphicsTestCases to presubmit Bug: 292293573 Change-Id: I2b9632f89b3511e4ca1b6e7b749402a73b586c92 Test: presubmit --- services/surfaceflinger/TEST_MAPPING | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/services/surfaceflinger/TEST_MAPPING b/services/surfaceflinger/TEST_MAPPING index b7115207ac..bfa5997e30 100644 --- a/services/surfaceflinger/TEST_MAPPING +++ b/services/surfaceflinger/TEST_MAPPING @@ -15,15 +15,7 @@ "name": "libscheduler_test" }, { - "name": "CtsGraphicsTestCases", - "options": [ - { - "include-filter": "android.graphics.cts.VulkanPreTransformTest" - }, - { - "include-filter": "android.graphics.cts.FrameRateOverrideTest" - } - ] + "name": "CtsGraphicsTestCases" }, { "name": "CtsSurfaceControlTests" -- GitLab From 644a5b7d25e54a1a682ad25d873b95453c405c97 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Thu, 20 Jul 2023 21:39:48 -0700 Subject: [PATCH 0352/1187] installd: add missing for std::function. Bug: b/175635923 Test: treehugger Change-Id: I2541263d27b5bced25667baaf814bff0e65e4604 --- cmds/installd/CrateManager.cpp | 3 ++- cmds/installd/CrateManager.h | 1 + cmds/installd/utils.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cmds/installd/CrateManager.cpp b/cmds/installd/CrateManager.cpp index b17cba15d5..fd1df35aee 100644 --- a/cmds/installd/CrateManager.cpp +++ b/cmds/installd/CrateManager.cpp @@ -29,9 +29,10 @@ #include #include +#include #include +#include #include -#include #include "utils.h" diff --git a/cmds/installd/CrateManager.h b/cmds/installd/CrateManager.h index 1f30b5dc79..d9b590f784 100644 --- a/cmds/installd/CrateManager.h +++ b/cmds/installd/CrateManager.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index ecea1d2b1c..c43fdbd547 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -18,6 +18,7 @@ #ifndef UTILS_H_ #define UTILS_H_ +#include #include #include -- GitLab From c8512110f3c41e79ae6aaca496fe28ffb288f1e7 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Thu, 20 Jul 2023 20:52:45 -0700 Subject: [PATCH 0353/1187] RESTRICT AUTOMERGE: Explicitly ignore the result of std::async The newer libc++ marks std::async with [[nodiscard]] in C++20 mode. Bug: b/175635923 Test: treehugger Change-Id: Ia222778697ab4241f25e002073b3514c7e106007 --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8c46515bf1..64348a544c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -6755,7 +6755,7 @@ ftl::SharedFuture SurfaceFlinger::captureScreenCommon( if (captureListener) { // TODO: The future returned by std::async blocks the main thread. Return a chain of // futures to the Binder thread instead. - std::async([=]() mutable { + (void)std::async([=]() mutable { ATRACE_NAME("captureListener is nonnull!"); auto fenceResult = renderFuture.get(); // TODO(b/232535621): Change ScreenCaptureResults to store a FenceResult. -- GitLab From 9bb5291102c912b92577f81599576b75bc6923ad Mon Sep 17 00:00:00 2001 From: Parth Sane Date: Tue, 4 Jul 2023 16:20:03 +0000 Subject: [PATCH 0354/1187] Clean up atrace.rc Moving boot trace related things to perfetto.rc Ensure that tracing is turned off by default only if boot tracing isn't enabled. Bug: 271576143 Test: Manually checked that tracing works (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5089908c7886f554beb1004f0ff976ddf922e8b4) Merged-In: I89e2bc0abe111bed4a230619afa544c214c10e6e Change-Id: I89e2bc0abe111bed4a230619afa544c214c10e6e --- cmds/atrace/atrace.rc | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index f1d8c72d85..fc0801cce8 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -228,10 +228,6 @@ on late-init chmod 0666 /sys/kernel/debug/tracing/events/thermal/cdev_update/enable chmod 0666 /sys/kernel/tracing/events/thermal/cdev_update/enable -# Tracing disabled by default - write /sys/kernel/debug/tracing/tracing_on 0 - write /sys/kernel/tracing/tracing_on 0 - # Read and truncate the kernel trace. chmod 0666 /sys/kernel/debug/tracing/trace chmod 0666 /sys/kernel/tracing/trace @@ -310,18 +306,9 @@ on late-init chmod 0666 /sys/kernel/tracing/events/synthetic/suspend_resume_minimal/enable chmod 0666 /sys/kernel/debug/tracing/events/synthetic/suspend_resume_minimal/enable -on late-init && property:ro.boot.fastboot.boottrace=enabled - setprop debug.atrace.tags.enableflags 802922 - setprop persist.traced.enable 0 - write /sys/kernel/tracing/events/binder/binder_transaction/enable 1 - write /sys/kernel/tracing/events/binder/binder_transaction_received/enable 1 - write /sys/kernel/tracing/events/binder/binder_transaction_alloc_buf/enable 1 - write /sys/kernel/tracing/events/binder/binder_set_priority/enable 1 - write /sys/kernel/tracing/events/binder/binder_lock/enable 1 - write /sys/kernel/tracing/events/binder/binder_locked/enable 1 - write /sys/kernel/tracing/events/binder/binder_unlock/enable 1 - write /sys/kernel/debug/tracing/tracing_on 1 - write /sys/kernel/tracing/tracing_on 1 +on late-init && property:ro.boot.fastboot.boottrace= + write /sys/kernel/debug/tracing/tracing_on 0 + write /sys/kernel/tracing/tracing_on 0 # Only create the tracing instance if persist.mm_events.enabled # Attempting to remove the tracing instance after it has been created @@ -534,7 +521,6 @@ on late-init && property:ro.boot.hypervisor.vm.supported=1 chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_mem_abort/id chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_mem_abort/id - on property:persist.debug.atrace.boottrace=1 start boottrace @@ -543,17 +529,3 @@ service boottrace /system/bin/atrace --async_start -f /data/misc/boottrace/categ user root disabled oneshot - -on property:sys.boot_completed=1 && property:ro.boot.fastboot.boottrace=enabled - setprop debug.atrace.tags.enableflags 0 - setprop persist.traced.enable 1 - write /sys/kernel/tracing/events/binder/binder_transaction/enable 0 - write /sys/kernel/tracing/events/binder/binder_transaction_received/enable 0 - write /sys/kernel/tracing/events/binder/binder_transaction_alloc_buf/enable 0 - write /sys/kernel/tracing/events/binder/binder_set_priority/enable 0 - write /sys/kernel/tracing/events/binder/binder_lock/enable 0 - write /sys/kernel/tracing/events/binder/binder_locked/enable 0 - write /sys/kernel/tracing/events/binder/binder_unlock/enable 0 - write /sys/kernel/debug/tracing/tracing_on 0 - write /sys/kernel/tracing/tracing_on 0 - -- GitLab From 7ecae40568a745b4a331e04ea4532e78979044ef Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Wed, 26 Jul 2023 20:22:34 +0000 Subject: [PATCH 0355/1187] Revert "Revert "Enable crashing fuzzer on infra"" This reverts commit 6081795a4d8bced410364186124549a3fd2c51c0. Reason for revert: Testing bug filing for main branch Change-Id: I497d6c3204768c1cc37010d4de48a13ddccb1265 --- libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp index 690c39afc9..96092b10d3 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp @@ -36,8 +36,8 @@ cc_fuzz { triage_assignee: "waghpawan@google.com", // This fuzzer should be used only test fuzzService locally - fuzz_on_haiku_host: false, - fuzz_on_haiku_device: false, + fuzz_on_haiku_host: true, + fuzz_on_haiku_device: true, }, } -- GitLab From 9485bc7b96e515595c9e3796ac05e5ecf1a9b355 Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Mon, 24 Jul 2023 14:37:05 +0530 Subject: [PATCH 0356/1187] ultrahdr: rework jpegr unit tests - Allocations are modified to scope bound resource management - Add some more units for encode apis for better coverage - clang-formatted the code - Improved the modularity for extending the tests to cover for stride support for 420 input Bug: Test: ./libultrahdr_test Change-Id: Iecc6242bca132229f51793132f0bc31cb04654f9 --- libs/ultrahdr/tests/Android.bp | 6 +- .../data/raw_p010_image_with_stride.p010 | Bin 2782080 -> 0 bytes libs/ultrahdr/tests/jpegr_test.cpp | 2728 ++++++++++------- 3 files changed, 1587 insertions(+), 1147 deletions(-) delete mode 100644 libs/ultrahdr/tests/data/raw_p010_image_with_stride.p010 diff --git a/libs/ultrahdr/tests/Android.bp b/libs/ultrahdr/tests/Android.bp index 594413018c..004a582fd6 100644 --- a/libs/ultrahdr/tests/Android.bp +++ b/libs/ultrahdr/tests/Android.bp @@ -22,7 +22,7 @@ package { } cc_test { - name: "libultrahdr_test", + name: "ultrahdr_unit_test", test_suites: ["device-tests"], srcs: [ "gainmapmath_test.cpp", @@ -45,7 +45,7 @@ cc_test { } cc_test { - name: "libjpegencoderhelper_test", + name: "jpegencoderhelper_test", test_suites: ["device-tests"], srcs: [ "jpegencoderhelper_test.cpp", @@ -61,7 +61,7 @@ cc_test { } cc_test { - name: "libjpegdecoderhelper_test", + name: "jpegdecoderhelper_test", test_suites: ["device-tests"], srcs: [ "jpegdecoderhelper_test.cpp", diff --git a/libs/ultrahdr/tests/data/raw_p010_image_with_stride.p010 b/libs/ultrahdr/tests/data/raw_p010_image_with_stride.p010 deleted file mode 100644 index e7a5dc84dc7ab98f35303753e7e7191a8d158993..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2782080 zcmZShJqkxdU^E06K8-@UhQJMmQAp1aIL9ywM?+vZhrlC-kq0Sny)mEx%1sgq!#o5=UTg3X6~=MUnuAm@ap<=NMtv|E0`zSSjoLQa zMx$>C4Cj%dQNN9bz_}4PIyl-M9BsFZh5&6sV6=rs-w>d0YiQKA(H6sK2n_EK7#$xZ zr)C@-A0#K#M)eH$5TI{sXwO_8>W-HmYa1hrnnH zjlLm3-`3EmZKLgl(GVEkAu!q=B&UuZZ4Z(YYNL9FdkE0CH8g75XbX+LAuzn#0;9eg z4S~`2AUSpPXnT;HP#e`V+(Tfrg+|{Hpl@qv)V9&~!e|H#?+_Sm50XL&p5Yz>^lc4|+BVukqi+Zd@3z3G??yvlv^_{p9X;9} zBq!8H^$hnA7;T}^Hw5V08XC22w7oDI0>e85M%#nr)X}5uL2^QERL^h^0s6LvMr|8y zq0u)4hIdO_8>W-HmYa1hX8$BL!-8hw$SJs0>is4FzUO}5EyL_l2b>Iwg<@xwNX98Jp@Ku zX!H#M`nHBfZ5wSbjE2DQ4uR43AUSpPXnT;HP#e`V+(UrAt)WrdMq6m~4T0g^78v#2 zXb6n92g#|UN85wsgxaW{;T{5`Ej0Ru0DW6SqqdE<7e+&1c!$7fdyt$udbB-APNgdt- zAUUBns%N-|z-SANz9B&0*3hVJqwR&!5E$MeFxnm@r;Z+N50VpVqk4vW2++4RG-}&u z3yr=ZFudCWqrMvrfzkFLId$}Cdyt$^8`U%1LtwOpM&A&iZ)<4Ow$b*&Xb24N5EyL_ zl2b>Iwg<@xwNX98Jp}068XC22w1r0B5E$NVfl=R$hQMfhkeoVtv^_{psEz6w?jbPR zLZfd8(6==-YTIagVKfAWcLgdt-AUUBns%N-|0DW6SqqdE<(C8Zi!@Dgo>bubp7;O)dQ%8@s z2gwPwQ9Z*w1V&qE^bG;}wuVM+8*ML)hQRO+fzkFLId$}Cdyt$^8`U%1Lx8@mp;6mL zTWItRf#Ka281>y~2#mG|$*H49+k@nU+Nhr49s;8+H2Q`BeOp7LwvDzIMnhnDhrnoi zkeoVtv^_{psEz6w?jbd0YiQKA z(e}b<2n_EK7;O)dQ%8@s2gwPwQ9Z*w1nAou8ntb-g+|{H7~XAxQQwV*z-W7roH}~6 zJxETdjp`ZhAu!rPqi+b%w>30s+h}`XGz5ls2#mG|$*H49+k@nU+Nhr49s=}j4UO71 z+Crmm2n_GGz^Ly=LtwN$NKPF++8!h))JF9T_YfFuq0u)4=-V0^wQaP$Fd72GI|N4C zgXGlFqwPU*LTyyfa1R0cwuX>xJIyc>;b;quz9BHY+XA?Jr_3-CA+FFE-r}R}L2~No z(e@xYp*E^#xQ7683yr?)k=PnM%|PGQ(5P+0yDfmrcO$VisLX&XG={hMXnT;HI(oD{ zNKUAY>KX1KK;JeXvTdX7!O_+l?L%OAw*_$dZnQm!D`bYB_-K2OoH}~6JxETdjp`Zh zA%NUMqc3~3JxKf3(5MZ=ul^^-N2BdQVnS(ns2Ob!l2b>Iwg<@xwNX98Jp}0621K@P zv^_Z5TBCgk439dWR9}p?2T2XFp{sthJxER+J=z{5C)7su4EGQ~ZlTeaJ=z|meQRjc zhM`-}Q{wW`_8=vpH?;JQwg<_nqet6=L&p5Yz>^lbwo+cw%B9Br-9J_LqV-A*mn zj6_SJBoYD3mId$}Cdyt$^8`U%1LjbvjMql=5dyw|6p-~$Ke|=617ml_EX%VV} z)6CKKAUSpPXnT;HP#e`V+(UrAZ9rt(M%#mgN>u@!NCv<^l`&zdyt$udbB-APNq!ZKLhM z(bgL6Lx4VY@?f)Nv^_Z3VuW_?8Ep@eQ%8@s2gwPwQ9Z*w1dv;3^kt8>2Wj6L8nuCT z_3&Ued9*z^m}7^!ZX0b6l2b>Iwg<@xwNX98Jp}0621K@Pv^_Z5TBCgkP`BWR^k{pKoKPFpGu%S}xrIhw_Go*M_N}2&8z`@DhoT9i?ZKfKYvj3k zv^_{p9X;9}Bq!8H^$hnApl=%x*|yR4;Am@&_8~xC9Xr%@jkX7edJGcp{?YazId$}C zdyt$^8`U%1LjbvjMql=5dyw|6p-~%%uUChY%F*`VaEeX*ei>~Kl2b>Iwg<@xwNX98 zJp}0621K@Pv^_Z5TBCgk;IB)EtL$idaJa@SroTqpgXGlFqwPU*LTyyfa1R0G78-ro zqwPW3w}wV-z^p$r#DvoDP&3*dB&UuZZ4Z(Y zYNL9FdkE0C4Tx;pXnSz9wMP387#?*#slFI(50V;ULs$K1dyt$udbB-APN?LkUHZ)oWqZ4Z)DM~}7#$qBVlJ;OZ&=-UQFwr#XM zINDmHeFzM#x}93C9c>R%DO_8>W-HmYa1hX8U5jlS&B_8{$BL!&kf z{`#C2E*xzS(jrs`r)P})RZ`0EyqwPU@hW5bP zHQF8|r;Z+N50VpVqk4vW2++3;h-}+vdvLV1M*9#L*t&Y4Y#(h84phj~-`>&oAUSpP zXnT;HP#e`V+(Q7lg+^cYXnTWR^k{pKoKPFp zGu%UfzHLBc+eX`iqpdaChX8%*`r;Z+N50VpVqk4vW2q3r6 z=*u2$57NFhG-?Cw>fym`@@RW-Fvkvc-8R}DB&UuZZ4Z(YYNL9FdkE0C4Tx;pXnSz9 zwMP38pl;neR7@Lf4-S=>qTHRM?Ll(t=+X8dIiWVHXSjy|atn>V?9uih?OQ{mHc(#Q z4n-42+k-KX1KK;JeXvTdX7!O_+l?L&aPI(De*8f^~_ z^%x}H{iE$ca_Z>O_8>W-HmYa1hX8U5jlS&B_8{$BL!&kjU#|`)m80#!;S`(r{W97f zB&UuZZ4Z(YYNL9FdkE0C4Tx;pXnSz9wMP38z+aaRSJ~0_;BbvuOn;5G2g#|UN85ws zgxaW{;T{6WEj0SFN85w6Zw-ywfLVWz1d-A9;7EvNh#yDWgXGlFqwPU*LTyyfa1R0c zwgHiC8*LAcw$^AL0+2d$q>-cT!I2Z=qwPU*>gdt-AUUBns%N-|0CEeBzUgdt-AUUBns%N-|0Daql$hM8P2S;0Lv=4#d-4?** zyV3R_u8O_8>W-HmYa1hX8U5jlS&B_8{$BL!&kfzxtmTAC0yLi3z3Q zp=Pu_NKPF++8!h))JF9T_Yk0O8xYyH(e~hIYmN3HFg)sfQhhPn9waryhOYY2_8>WR z^k{pKoKPFpGu%S}xrIhw_Go*M_N}2&8-{K@Pl?M%+k=#Z-q6xJ+8!jQjvj3fk`rp9 zdWL%l(6PBTZ_gXGlFqwPU*LTyyfa1R0cwgHiC8*LAc zw$^AL0)w*-r?sm_+k>KX1KfZRf(FMG5-Nc+~%s11Xs z-lnHZM%#n*4DErnYqUK`P8~hk9waB!M)eH$5TI`x5ZSiT_TXr1jrJihuyyr7**@AH z9H@||zrCaFL2~No(e@xYp*E^#xQ7683yr?)(e@ziTSKEZ(7%2j3^tCo2M0qe(8mp< z?Ll(t=+X8dIiWVHXSjy|ecOP@wvDz2M_X&O4*~kr$%D<7(e~hAixJwnXS6*?P8~hk z9waB!M)eH$5I}CB(U(2i9;AJ1Xw(MU)x(3?M=;X`$yY@H#2g#|U zN85wsgxaW{;T{6?Z380PHrgH>ZLQHh1R!4o z5019hXdeQ@yDfmrccbk=Tp=_3#7EnMV?9uih?OQ{mHVoZ*o)VXjwg)K*y`iOd zv^_{p9X;9}Bq!8H^$hnApl=%x*|yR4;Am@&_8~B|>UL_mcC=k4UO6``0I08xNx*RNQ+P%oMw);2g#|UN85wsgxaW{ z;T{6?Z380PHrgH>ZLQHh1O{gvPHR_P%&+^JvdZiigI_3wg<_nqet6= zL&p5Yz>$SpMbvPav4v~LZK+CX`II}}YAZ4VB`SR>EPqwPU*>gdt-AUUBns%N-| z0Daql$hM8P2S;0Lv=0ID>e!*KYqUK$)MJo%_m8#*$*H49+k@nU+Nhr49s=k4UO7Be7!oHRF1X>hf{3g_seK|keoVtv^_{psEz6w?jb5=2JZ zgCil9A$}Zf50X~{i`m#scgS2lAjoL7B+6Bly9c>RHhsN+`kG2QNsiQ~RgXDzT zsGi{-0`zSIBHK3F9vp40(LMx*cUu6L??&5$xI$+5iI27i$*H49+k@nU+Nhr49s=k4UO6`{OW&Vd^Fk~Bqo%Ghnms$AUSpPXnT;HP#e`V+(UrAZ9rt(M%#m< ztu@+*!0@Q^N%h5Odyv!+8@lR8+k@oP(WC7_azbrX&u|X`KX1KK;JeXvTdX7!O_+l?L%N_)$P=B?PzIwg<@xwNX98Jp_@Ymgdt- zAUUBns%N-|0CEeBzU`&Id$}Cdyt$^8`U%1 zLx8?*KxErS+k>O6HQI;3z}D3RW&3D*aG*k-{`QWx2g#|UN85wsgxaW{;T{6WEj0SF zN85w6Zw-ywK>zxAFxWWS9vlp@Kp!`Zwg<_nqet6=L&p5Yz>^lbx<+BVukqi+b% zr%oQVWi$i^Dg;K`gXGlFqwPU*LTyyfa1Vje78-p+fWEDvQQHQpmL9ctGz91q0;BCg za_Z>O_8>W-HmYa1hX8$BL!-8hw$SJs0`#eqM{OAmfq@Ev(e@xYb@XU^kepB()ic~f zV6=rs-w>d0YiQKAfvTlP?HvsP`h>t}dyt$udbB-APNf}*dMnhnrLSVE#NKPF++8!h))JF9T_YfFuq0u)4=-V0^wQZnk=}~(}Lx4UZFxnm@ zr;Z+N50VpVqk4vW2++4RG-}&u3yr=ZK%Y8!)Rxf@7^n~!Z4Z)DM~}7#$qBVlJ;OZ& zMq6m~4FUSLhDL20s9Ji|-q8@CPY8^*2g#|UN85wsgxaW{;T{6?Z4HguHrhg?ZwSz* zP9C*oGz11J1V-C~gdt-AUUBns%N-|0DW6SqqdE<(C8Zi^r@3aZ5a)LfeL}q_8>WR^k{pKoKPFpGu%U9 zw1r0B5TI{sXw+Zr0RZJ=uDQF}*2fIcBG+8!jQ zjvj3fk`rp9dWL%l(6==-YTIZFjlLm3pE`NemeCLxs1O)!50X zTWItR0s6LvMr|9YT6)yp(GZ|d2#mG|$*H49+k@nU+Nhr49s=}j4UO71+Crmm2+*fa z9<^mO1O_SuM%#nr)X}5uL2^QERL^h^fzcKkeM5l0t)Wrd2C9}GwRbcG=o12??Ll(t z=+X8dIiWVHXSjy|eOp7LwvD#X=o30s+h_}oz9B%LI(gKV(GVD@5EyL_l2b>Iwg<@xwNX98Jp@Ku zX!H#M`nHBfZ5yasdeq+05TH*8jJ5~KsiQ~RgXDzTsGi{-0`zSSjoLQaLZfd8(5Frw zwPiE}1}X$b+k@oP(WC7_azbrX&u|Zc(H0tgLx8@mp;6lgs+JzLcQgd(69S{{L2~No z(e@xYp*E^#xQ76JTSKF^jkeI}8v^vHlSgeC4S|6QfzkFLId$}Cdyt$^8`U%1LtwOp zM&A&iZ)<4Owt=dpN9`RA0s4f%XnT;HI(oD{NKUAY>KX1KK;PETsBNPyH2Q`Bed^>< zTSh}*ph94@JxER+J=z{5C)7su4EGQiZK2UO1nAou8ntbpYUxpXM?-)m`()ZWn$pic;lwg<_nqet6=L&p5Yz>^lc4|+BVukqi+b%r%oQV zWi$i^Dg;K`gXGlFqwPU*LTyyfa1Vje78-p+fWEDvQQHQpmL9ctGz91q0;BCga_Z>O z_8>W-HmYa1hX8$BL!-8hw$SJs0`#eqM{OAmfq@Ev(e@xYb@XU^kepB()ic~fV6=rs z-w>d0YiQKAfvTlP?HvsP`h>t}dyt$udbB-APNf}*d zMnhnrLSVE#NKPF++8!h))JF9T_YfFuq0u)4=-V0^wQZnk=}~(}Lx4UZFxnm@r;Z+N z50VpVqk4vW2++4RG-}&u3yr=ZK%Y8!)Rxf@7^n~!Z4Z)DM~}7#$qBVlJ;OZ&Mq6m~ z4FUSLhDL20s9Ji|-q8@CPY8^*2g#|UN85wsgxaW{;T{6?Z4HguHrhg?ZwSz*P9C*o zGz11J1V-C~S%O8 zjv1qRMnhn@g#dk9L!-8hw$SJs0`#eqM{OAmfq@Ev(e@xYb@FI?kepB()ic~fV6=rs z-w>d0YiQKAfvTlP?HvsP`h>t}dyt$udbB-APNf}*d zMnhnrLSVE#NKPF++8!h))JF9T_YfFuq0u)4=-V0^wQZnk=}~(}Lx4UZFxnm@r;Z+N z50VpVqk4vW2++4RG-}&u3yr=ZK%Y8!u-USWVHA#(5EyL_l2b>Iwg<@xwNX98Jp@Ku zX!H#M`nHBfZ5wPYHTt+`q_l-b{ke@{v^_{p9X;9}Bq!8H^$hnApl@qv)V9$U8ht~6 zKJBl;X3JKX1KFxo<+ZwS!0H8g75U~8$-$2}vbH8kqe z(e@xYb@XU^kepB()ic~ffWEDvQQJmaX!H#M`n10Wn=PZQq>&Q>qwPU*>gdt-AUUBn zs%N-|z-SANz9B&0*3hVJgRP}TANP!$*3hU=N85ws)X}5uL2^QERL^h^0s6LvMr|8y zq0u)4=+pihY_^QHl15GljJ5~KsiQ~RgXDzTsGi{-0;4T7`i1~~TSKF^4YrmVecUs0 zT0^5g9c>SiQ%8@s2gwPwQ9Z*w1nAou8ntb-g+|{Hpild2u-P)&N*XyKFxnm@r;Z+N z50VpVqk4vW2#mJS=o7D{16}z-W7roH}~6JxETdjp`ZhAu!rPqi+b%w>30s+hA*{ z(Z@X_r!_R{)6w=IId$}Cdyt$^8`U%1Lx8@mp;6mLTWItR0s6GR2AeITt)!6?0;BCg za_Z>O_8>W-HmYa1hrnnHjlLm3-`3EmZG)|)Mj!W#oYv5&PeIwg<@xwNX98Jp}068XC22w1r0B5TH-{Yp~fe+DaNZ zAu!q=B&UuZZ4Z(YYNL9FdkBoS(C8Zi^lc4|+BVo)YV>i>$Y~9Y`gF8CNKPF++8!h) z)JF9T_Yk0OYiQKA(H0tgLx4W*ufb-^Xe(*tgurNfkeoVtv^_{psEz6w?jbPRLZfd8 z(6==-YTICIsnN$hBd0Yq>eJEoAUSpPXnT;HP#e`V+(UrAt)WrdMq6m~4FUSJzXqEv zqphTo69S{{L2~No(e@xYp*E^#xQD=K3yr=ZK;PETsBMF-rA8n3jGWfcs82`RgXGlF zqwPU*LTyyfa1R0cwuVM+8*QP{Hw5U@{u*qyjJA?SP6&*)2g#|UN85wsgxaW{;T{5` zEj0Ru0DW6SqqYsUmKuHBGjdu(qdpyN50Xcr z`)jb-GTKTSIUz9G9weuZ9&Hbj6KbP+hIWR^k{pKoKPFpGu%UfzOA8A+eTYx z^bG;}w7&+MEu*cZkrM)=?Ll(t=+X8dIiWVHXSj#JXbX+LAwb{O(5P*Lt))gE_l%s@ z(5O#G+k@oP(WC7_azbrX&u|X``nHBfZ5wT&(KiI>)BYN4wv4utMotKfwg<_nqet6= zL&p5Yz>qb)T0h5&tAL!-70ww4-w+%s}oL!&+&Z4Z)DM~}7#$qBVlJ;OZ&=-V0^ zwQaP8M&A&iPy1`I*)rNn8aW{_+8!jQjvj3fk`rp9dWL%ljJD9|8v^ug4UO71*jj4z zanHzU4UPJAv^_{p9X;9}Bq!8H^$hnApl@qv)V9$U8ht~6KJBl;X3JKX1KFxo<+ZwS!0H8g75U~8$-$2}vbH8kqe(e@xYb@XU^kepB()ic~f zfWEDvQQJmaX!H#M`n10Wn=PZQq>&Q>qwPU*>gdt-AUUBns%N-|z-SANz9B&0*3hVJ zgRP}TANP!$*3hU=N85ws)X}5uL2^QERL^h^0s6LvMr|8yq0u)4=+pihY_^QHl15Gl zjJ5~KsiQ~RgXDzTsGi{-0;4T7`i1~~TSKF^4YrmVecUs0T0^5g9c>SiQ%8@s2gwPw zQ9Z*w1nAou8ntb-g+|{Hpild2u-P)&N*XyKFxnm@r;Z+N50VpVqk4vW2#mJS=o7 zD{16}z-W7roH}~6JxETdjp`ZhAu!rPqi+b%w>30s+hA*{(Z@X_r!_R{)6w=IId$}C zdyt$^8`U%1Lx8@mp;6mLTWItR0s6GR2AeITt)!6?0;BCga_Z>O_8>W-HmYa1hrnnH zjlLm3-`3EmZG)|)Mj!W#oYv5&PeIwg<@xwNX98Jp}068XC22w1r0B5TH-{Yp~fe+DaNZAu!q=B&UuZZ4Z(YYNL9F zdkBoS(C8Zi^lc4|+BVo)YV>i>$Y~9Y`gF8CNKPF++8!h))JF9T_Yk0OYiQKA(H0tg zLx4W*ufb-^Xe(*tgurNfkeoVtv^_{psEz6w?jbPRLZfd8(6==-YTICIsnN$hBd0Yq z>eJEoAUSpPXnT;HP#e`V+(UrAt)WrdMq6m~4FUSJzXqEvqphTo69S{{L2~No(e@xY zp*E^#xQD=K3yr=ZK;PETsBMF-rA8n3jGWfcs82`RgXGlFqwPU*LTyyfa1R0cwuVM+ z8*QP{Hw5U@{u*qyjJA?SP6&*)2g#|UN85wsgxaW{;T{5`Ej0Ru0DW6SqqYsUmKuHB zGjdu(qdpyN50Xcr`)jb-GTKTSIUz9G9weuZ z9&Hbj6KbP+hIWR^k{pKoKPFpGu%UfzOA8A+eTYx^bG;}w7&+MEu*cZkrM)= z?Ll(t=+X8dIiWVHXSj#JXbX+LAwb{O(5P*Lt))gE_l%s@(5O#G+k@oP(WC7_azbrX z&u|X``nHBfZ5wT&(KiI>)BYN4wv4utMotKfwg<_nqet6=L&p5Yz>qb)T0h5&tA zL!-70ww4-w+%s}oL!&+&Z4Z)DM~}7#$qBVlJ;OZ&=-V0^wQaP8M&A&iPy1`I*)rNn z8aW{_+8!jQjvj3fk`rp9dWL%ljJD9|8v^ug4UO71*jj4zanHzU4UPJAv^_{p9X;9} zBq!8H^$hnApl@qv)V9$U8ht~6KJBl;X3JKX1KFxo<+ zZwS!0H8g75U~8$-$2}vbH8kqe(e@xYb@XU^kepB()ic~ffWEDvQQJmaX!H#M`n10W zn=PZQq>&Q>qwPU*>gdt-AUUBns%N-|z-SANz9B&0*3hVJgRP}TANP!$*3hU=N85ws z)X}5uL2^QERL^h^0s6LvMr|8yq0u)4=+pihY_^QHl15GljJ5~KsiQ~RgXDzTsGi{- z0;4T7`i1~~TSKF^4YrmVecUs0T0^5g9c>SiQ%8@s2gwPwQ9Z*w1nAou8ntb-g+|{H zpild2u-P)&N*XyKFxnm@r;Z+N50VpVqk4vW2#mJS=o7D{16}z-W7roH}~6JxETd zjp`ZhAu!rPqi+b%w>30s+hA*{(Z@X_r!_R{)6w=IId$}Cdyt$^8`U%1Lx8@mp;6mL zTWItR0s6GR2AeITt)!6?0;BCga_Z>O_8>W-HmYa1hrnnHjlLm3-`3EmZG)|)Mj!W# zoYv5&PeIwg<@xwNX98Jp}06 z8XC22w1r0B5TH-{Yp~fe+DaNZAu!q=B&UuZZ4Z(YYNL9FdkBoS(C8Zi^lc4|+BVo) zYV>i>$Y~9Y`gF8CNKPF++8!h))JF9T_Yk0OYiQKA(H0tgLx4W*ufb-^Xe(*tgurNf zkeoVtv^_{psEz6w?jbPRLZfd8(6==-YTICIsnN$hBd0Yq>eJEoAUSpPXnT;HP#e`V z+(UrAt)WrdMq6m~4FUSJzXqEvqphTo69S{{L2~No(e@xYp*E^#xQD=K3yr=ZK;PET zsBMF-rA8n3jGWfcs82`RgXGlFqwPU*LTyyfa1R0cwuVM+8*QP{Hw5U@{u*qyjJA?S zP6&*)2g#|UN85wsgxaW{;T{5`Ej0Ru0DW6SqqYsUmKuHBGjdu(qdpyN50Xcr`)jb-GTKTSIUz9G9weuZ9&Hbj6KbP+hIWR z^k{pKoKPFpGu%UfzOA8A+eTYx^bG;}w7*7e84ZDf3W3q~AUSpPXnT;HP#e`V+(Tfr zg+|{Hpl@qv)V6`DrAO@@4FURuz-W7roH}~6JxETdjp`ZhAwb{O(5P*rEj0Ru0DbD@ zQCmhsV4y-^v^_{p9X;9}Bq!8H^$hnA7;T}^Hw5V08XC22plaz+dq+cnJ|QsL9weuZ z9&Hbj6KbP+hI30s+h_}oz9B%LI(gKV(GVD@5EyL_l2b>Iwg<@xwNX98Jp@Ku zX!H#M`nHBfZ5yasdeq+05TH*8jJ5~KsiQ~RgXDzTsGi{-0`zSSjoLQaLZfd8(5Frw zwPiE}1}X$b+k@oP(WC7_azbrX&u|Zc(H0tgLx8@mp;6lgs+JzLcQgd(69S{{L2~No z(e@xYp*E^#xQ76JTSKF^jkeI}8v^vHlSgeC4S|6QfzkFLId$}Cdyt$^8`U%1LtwOp zM&A&iZ)<4Owt=dpN9`RA0s4f%XnT;HI(oD{NKUAY>KX1KK;PETsBNPyH2Q`Bed^>< zTSh}*ph94@JxER+J=z{5C)7su4EGQiZK2UO1nAou8ntbpYUxpXM?-)m`()ZWn$pic;lwg<_nqet6=L&p5Yz>^lc4|+BVukqi+b%r%oQV zWi$i^Dg;K`gXGlFqwPU*LTyyfa1Vje78-p+fWEDvQQHQpmL9ctGz91q0;BCga_Z>O z_8>W-HmYa1hX8$BL!-8hw$SJs0`#eqM{OAmfq@Ev(e@xYb@XU^kepB()ic~fV6=rs z-w>d0YiQKAfvTlP?HvsP`h>t}dyt$udbB-APNf}*d zMnhnrLSVE#NKPF++8!h))JF9T_YfFuq0u)4=-V0^wQZnk=}~(}Lx4UZFxnm@r;Z+N z50VpVqk4vW2++4RG-}&u3yr=ZK%Y8!)Rxf@7^n~!Z4Z)DM~}7#$qBVlJ;OZ&Mq6m~ z4FUSLhDL20s9Ji|-q8@CPY8^*2g#|UN85wsgxaW{;T{6?Z4HguHrhg?ZwSz*P9C*o zGz11J1V-C~gdt- zAUUBns%N-|0DW6SqqdE<(C8Zi^r@3aZ5a)LfeL}q_8>WR^k{pKoKPFpGu%U9w1r0B z5TI{sXw+Zr0RZJ=uDQF}*2fIcBG+8!jQjvj3f zk`rp9dWL%l(6==-YTIZFjlLm3pE`NemeCLxs1O)!50XTWItR z0s6LvMr|9YT6)yp(GZ|d2#mG|$*H49+k@nU+Nhr49s=}j4UO71+Crmm2+*fa9<^mO z1O_SuM%#nr)X}5uL2^QERL^h^fzcKkeM5l0t)Wrd2C9}GwRbcG=o12??Ll(t=+X8d zIiWVHXSjy|eOp7LwvD#X=o30s+h_}oz9B%LI(gKV(GVD@5EyL_l2b>Iwg<@xwNX98Jp@KuX!H#M z`nHBfZ5yasdeq+05TH*8jJ5~KsiQ~RgXDzTsGi{-0`zSSjoLQaLZfd8(5FrwwPiE} z1}X$b+k@oP(WC7_azbrX&u|Zc(H0tgLx8@mp;6lgs+JzLcQgd(69S{{L2~No(e@xY zp*E^#xQ76JTSKF^jkeI}8v^vHlSgeC4S|6QfzkFLId$}Cdyt$^8`U%1LtwOpM&A&i zZ)<4Owt=dpN9`RA0s4f%XnT;HI(oD{NKUAY>KX1KK;PETsBNPyH2Q`Bed^>m`()ZWn$pic;lwg<_nqet6=L&p5Yz>^lc4|+BVukqi+b%r%oPhwkR`< zL^#-Dfj;gTZ4Z)DM~}7#$qBVlJ;OZ&Mq6m~4FUSLhDL3pPn|s2Y#E8IL1l))77O%o z&uDv)oH}~6JxETdjp`ZhAwb{O(5P*rEj0Ru0DbD@!Dh>7dvLJD2<_Z6+8!jQjvj3f zk`rp9dWL%ljJD9|8v^ug4UO7HyLxyqn>^Yc9L%vpUAK+42g#|UN85wsgxaW{;T{6? zZ4HguHrhg?ZwOGg?j0(ojkX7eN=#Ai&e8TDId$}Cdyt$^8`U%1LtwOpM&A&iZ)<4O zHp=VUp=iQrdvGYm8hLIWZ4Z)DM~}7#$qBVlJ;OZ&=-V0^wQaP8M&A%1uZ|t+x<=cB zLp=tGcmHU6keoVtv^_{psEz6w?jbPRLZfd8(6==-Y8&zO>Tpsy+8!KEv5DU=qwPU* z>gdt-AUUBns%N-|0DW6SqqdE<(C8Zi`0LW)Dm&U99Ii2o>95iDAUSpPXnT;HP#e`V z+(Tfrg+|{Hpl@qv)Hcleb0mn2wg*Q-EJOS_+8!jQjvj3fk`rp9dWL%l(6==-YTIZF zjlLlOsWV3!Ioci^IWa!k9weuZ9&Hbj6KbP+hIRH zhsN+`kG2QNsiQ~RgXDzTsGi{-0`zSSjoLQaLZfd84DYr8F5iu|2XTeW@Dm?x50XTWItR0s6LvMr|8@^*=E_8f^~}6H3EF&1id&oH}~6JxETdjp`Zh zAwb{O(5P*rEj0Ru!0@Q^N%h5Odyv!+8@lR8+k@oP(WC7_azbrX&u|Zc(H0tgLx8@m zp;6n0Zaq(l%SYRTl!V^U(mUE7B&UuZZ4Z(YYNL9FdkE0CH8g75XbX+LAuzP+c51nH zv^_|zkR1HxjJ5~KsiQ~RgXDzTsGi{-0;4T7`i1~~TSKF^4gUI^7A_oZ57Hu32d9~% z?Ll(t=+X8dIiWVHXSjy|eOp7LwvD#X=oWR^k{pKoKPFpGu%U9w1r0B5TI{sXw)|P z*Uy8&#?kiRV2B0!xM8$CNKPF++8!h))JF9T_Yk0OYiQKA(H0tgLx4VY@?f)Nv^_Z3 zVuW_?8Ep@eQ%8@s2gwPwQ9Z*w1V&qE^bG;}wuVM+qg_2bm`xsS4-V$op|0CT+k@oP z(WC7_azbrX&u|X``nHBfZ5wT&(KiIBTlWqX(?;8aLnWptcjst(keoVtv^_{psEz6w z?jbPRLZfd8(6==-Y8&PC?NBsfv^_W!V~spFkG2QNsiQ~RgXDzTsGi{-0`zSSjoLQa zLZfd8kXOeJbzP(F!J!_5#JhjAJxER+J=z{5C)7su4EGQiZK2UO1nAou8nuo1dUZId z9BmH{r`W{rm(lhhId$}Cdyt$^8`U%1Lx8@mp;6mLTWItR0sM98aFrcx4-VIu#q`%` zdyt$udbB-APNupN_T%kwas6vq#&5L&p5Yz>qb)T0h5&tAL!-70zxtmTAC0yLi3z3Qp=Pu_ zNKPF++8!h))JF9T_Yk0OYiQKA(H0tgLtuE+`K0<{v^_{_hz(u!qwPU*>gdt-AUUBn zs%N-|z-SANz9B&0*3hVJL${u%#O0&yK}tezXz3ko50XKX1K zFxo<+ZwS!0H8g4){p;t!VB=_ea4^IIecUkG9weuZ9&Hbj6KbP+hI30s+h_}o zz9B%LI(e|!GTI&-Y%xMR_l&j&$*H49+k@nU+Nhr49s;8+H2Q`BeOp7Lw$ZL09?T|> zwg(4u>`>QjqwPU*>gdt-AUUBns%N-|0DW6SqqdE<(C8Zi)UA7mifNhf{3g_seK|keoVtv^_{psEz6w?jb30s+h_}oz9BF?>U>gtG1?v^HN=Ll z`qB0vId$}Cdyt$^8`U%1LtwOpM&A&iZ)<4OwxL_kQ{wW`_8=vpH?;JQwg<_nqet6= zL&p5Yz>^lc4|+BVukqi+Zdt-76Bt{rU;QY$0}zd57rL2~No(e@xYp*E^#xQD=K z3yr=ZK;PETsBMG4KBt8XN85w62-U%9=4gA6oH}~6JxETdjp`ZhAwb{O(5P*rEj0Ru zz~HRIY3-`f_8_f8c<`7%+8!jQjvj3fk`rp9dWL%ljJD9|8v^ug4UO71cx@5FH zNYBt7Si45sgXGlFqwPU*LTyyfa1R0cwuVM+8*QP{Hv|T@t{y1cN85t~74r1AceFi7 zP8~hk9waB!M)eH$5EyNt(KiI>+Zr0RjsErXV6bttJvbO*fj({+Z4Z)DM~}7#$qBVl zJ;OZ&=-V0^wQaP8M&A&iPn|s2Y#D724z?JfoqI;xgXGlFqwPU*LTyyfa1Vje78-p+ zfWEDvQQK%&4-aOON85vgId-V)w$b(=Id$}Cdyt$^8`U%1Lx8@mp;6mLTWItR0qWMh zL&dbw_TW&7DazeB+8!jQjvj3fk`rp9dWL%ljJD9|8v^ug4UO7Hd3`$+O&Dzt4#ij_ z&&{LlL2~No(e@xYp*E^#xQ76JTSKF^jkeI}8v^9ju|r+gXnSy|#~|_UA8ikkQ%8@s z2gwPwQ9Z*w1V&qE^bG;}wuVM+Bfef8PAW&+gTpB{@%v@8JxER+J=z{5C)7su4EGSA zZ)<4Ow$TK4N85wLHD)pWHQF8|r;Z+N50VpVqk4vW2#mJS=oWR^k{pK zoKPFpGu%UfzOA8A+eTYx^bLXG-4?**yV3R_u8O_8>W-HmYa1hrnnH zjlLm3-`3EmZNsnrC&ovk?LlHfX?Um^Z4Z)DM~}7#$qBVlJ;OZ&=-V0^wQaP8M&A$^ z9(6vcz8Gx}k{V(|SN&*vkeoVtv^_{psEz6w?jbPRLZfd8(6==-YTMAQ=P7adXnT;7 z&>LEMN85ws)X}5uL2^QERL^h^0s6LvMr|8yq0u)4hF0B9E!U2=2dNd3gWsId_8>WR z^k{pKoKPFpGu%U9w1r0B5TI{sXwH0G;_2)NKPF++8!h))JF9T z_Yk0OYiQKA(H0tgLtt>$;k0(uXnT;>Av}1@A8ikkQ%8@s2gwPwQ9Z*w1V&qE^bG;} zwuVM+8$9(kJzX-|9;9bz53F6I?Ll(t=+X8dIiWVHXSjy|eOp7LwvD#X=oG+8!JXu|OX; zjJ5~KsiQ~RgXDzTsGi{-0`zSSjoLQaLZfd8(5FrwY_^QH2M1e>(9S)h?Ll(t=+X8d zIiWVHXSj#JXbX+LAwb{O(5P*+tA_`($)oMT!5ll(b=zorkeoVtv^_{psEz6w?jb}>o_8>WR^k{pKoKPFpGu%UfzOA8A+eTYx^bG;>>e!*KYqUK$ z)MJo%_m8#*$*H49+k@nU+Nhr49s;8+H2Q`BeOp7Lwh>>i4kwkP?ZM#`oA~`Q+8!jQ zjvj3fk`rp9dWL%l(6==-YTIZFjlLm(zb+lFvZL+6;Tp4;{u*r$l2b>Iwg<@xwNX98 zJp@KuX!H#M`nHBfZNscTM}o*`dvGMgGQ^Lg?Ll(t=+X8dIiWVHXSjy|eOp7LwvD#X z=oKX1KK;PETsBNPyH2Q|X@NNr?`ffA?M%#nr)X}5uL2^QE zRL^h^fzcKkeM5l0t)WrdM%xRcAuzl{V6;6*P8~hk9waB!M)eH$5TI{sXwO_8>W-HmYa1hrnnHjlLm3-`3EmZKLgl(GVEkAu!q=B&UuZ zZ4Z(YYNL9FdkE0CH8g75XbX+LAuzn#0;9eg4S~`2AUSpPXnT;HP#e`V+(Tfrg+|{H zpl@qv)V9&~!e|H#?+_Sm50XL&p5Yz> z^lc4|+BVukqi+Zd@3z3G??yvlv^_{p9X;9}Bq!8H^$hnA7;T}^Hw5V08XC22w7oDI z0>e85M%#nr)X}5uL2^QERL^h^0s6LvMr|8yq0u)4hIdO_8>W-HmYa1hX8$BL!-8hw$SJs z0>is4FzUO}5EyL_l2b>Iwg<@xwNX98Jp@KuX!H#M`nHBfZ5wSbjE2DQ4uR43AUSpP zXnT;HP#e`V+(UrAt)WrdMq6m~4T0g^78v#2Xb6n92g#|UN85wsgxaW{;T{5`Ej0Ru z0DW6SqqdE<7e+&1c!$7fdyt$udbB-APNgdt-AUUBns%N-|z-SANz9B&0*3hVJqwR&! z5E$MeFxnm@r;Z+N50VpVqk4vW2++4RG-}&u3yr=ZFudCWqrMvrfzkFLId$}Cdyt$^ z8`U%1LtwOpM&A&iZ)<4Ow$b*&Xb24N5EyL_l2b>Iwg<@xwNX98Jp}068XC22w1r0B z5E$NVfl=R$hQMfhkeoVtv^_{psEz6w?jbPRLZfd8(6==-YTIagVKfAWcLgdt-AUUBns%N-| z0DW6SqqdE<(C8Zi!@Dgo>bubp7;O)dQ%8@s2gwPwQ9Z*w1V&qE^bG;}wuVM+8*ML) zhQRO+fzkFLId$}Cdyt$^8`U%1Lx8@mp;6mLTWItRf#Ka281>y~2#mG|$*H49+k@nU z+Nhr49s;8+H2Q`BeOp7LwvDzIMnhnDhrnoikeoVtv^_{psEz6w?jbd0YiQKA(e}b<2n_EK7;O)dQ%8@s2gwPwQ9Z*w z1nAou8ntb-g+|{H7~XAxQQwV*z-W7roH}~6JxETdjp`ZhAu!rPqi+b%w>30s+h}`X zGz5ls2#mG|$*H49+k@nU+Nhr49s=}j4UO71+Crmm2n_GGz^Ly=LtwN$NKPF++8!h) z)JF9T_YfFuq0u)4=-V0^wQaP$Fd72GI|N4CgXGlFqwPU*LTyyfa1R0cwuVM+8*QP{ zHw1=vTVT|8qaiTb9weuZ9&Hbj6KbP+hIyy(C8ZipfDdOJQCYv1LF#feV4r_Ta#U{iw~OAuzZ?VBlH_qb)T0hQPqZ z^k{pK-fhFdRmP0EW-y1qXnSxl$IhtRMniy}Auw>Q1p2myMr|9om>z8pjh3AuyanVBlH_qb)T0hQPqZ^k{o825SfmTq|L;g+|{H7`T`oZ4ZvN2M25UH|nm@_TXq57!85Z5P*ch zz_k+S+Zr0RZQx>hv^_Z59)y%OqvYTVfzkHh;ER({7mbF%z=XiSwGu{KX!H$%fs5(U z_TXrHa9~QeQCkUzz-W7ra2SoM7!84u5ds6(N}z9RXwz_k)aTWItRfq{$Z(e~hIdyp1o*QlA)2!YY|AT>g9)Qr&(7!DyY zaIFOTwuVM+8@QMrZ4ZvN2ZuvhIXwL^+8!L9@jB|O(GVa#1O~2^Fxo<+ZwL%rOpmq) zN85v>mrSEN=o12??Lqp4^QbMOAu#wuVBlH_^lc4|+BR@8J=z`|Z4VCql5nKDaI`%* zQe%G9-=iUb9s&c`N*HaS(KiGJE~ZD@gQM+1^m1pEKUhLwv^_XjVq(-CqaiTRAuw>Q z1p2myMr|9om>z8pjQgwYlneM4a2VtTYaINBZ@UZv)6^37;_a5%;0s9#1yfRYdxxK;vv zTSKF^4O~o*wg*SsgOrp}qk3r>0;BCgT88eZ*`pyaltN(OS_z{qH2Q|Xz{T`vdvLTp zIF!o7k>%FW_Tb2h?@`~5h5+sm7`RpfeOp7LwhdfNkG2O#+k?1Epi!BD4S~`2;J}9e zsO_U6FnB^>;93czEj0Ruz`(`yXnSz9Jvewuyiu2+hQMfh5H&nTd7~jPazkL?S_$-R z4UO71a4|jF9vp2Cj@%Mhv^_Z59vrUa=g{}pXnSzz$Kj|C zMnix)Auw>QgwYlneM4a2VtTYaINBbhPH8o23iU%^v^_}uFda2oe7;O)NLSYn- zhQMeD{AL)qR>EitjlLl;a4|jF9vp2Cj+V89H3UZ6gM&3@M%^_U0`v}nfomnuw>30s z+rY*2XnSz9JxK3zZPY$uLtwN$NNh-rsv8Y~;T{45*Gd>|q0u)41}>&Y+k>O+!Qozx z4qg9^wg-o9+>N??Gz6#{0t44dpl@qv)V6_(>CyJ!XnT;lrPiov)C+;p_8|4ba@3^J z5E$AaFmSDe(H0tgLtx-ydbB+_+8!L*rQ~pS{b+k|ILGd&-$p}#ln@xWRswxnL!-70 zTuhI)2S?k3q?AdcYUvpQqwPU@hW4mkqaiSuLtx-q38O7E`i8*3#q?-Weu(n7;O&@uJ{;r&1eV= zTnG$YD`B*SM&A$^xR@So501762d;!0wHbd1jJ5~yhtH_&Xb6m)5E!^t0)1OUqqYrP zOpmq)N85uVr$ilUJ{@fj4z(B?b?;~h&?*E5vXwAu_eco=dbfv0x_z`NEk?~9ejza0 z9vpsgI_jg*5FjrEMoNoh)Sm+x0wcYBMsNR8>ij9WANDP6I(jpo4=Rk(QNN=Cf+y5i6 zBpdZJc_A>`9waZ^Ms% z4S}H+0wbkGGV0HP41tl}KBKq)hgvB#>fV71fzkHhz=i#&&7&bOxI$ncTM46fkCYIg zcYA20+c&t%m{HdZ<`5Wd4-V$o8Fkxe2+%VGMoNoh)Sm+x0wcYBMsNSqvjiEnYiNhS zXnSyI$KR;yM?-*mAuy1wgi*UkN(j)qJv7qoqh9$iYSM5IfzkHhaF5|p|BZ$Ku^}*0 zS|p?X9LNwD>FqOm`=8j{KdNpt1V-C~qiJ9?1V%#u5&{F+N*J|!q=W#y+e0JWK1kjk zB}YSma0raH2MLGKsEW}L7#SfjQd%UV{v5~<80qaZdi#H5lwG5~q(%sgwg;&Zilb(X zhQM$Lfq`r#jM_a?LV(`wp^ z-aezZ{|A4$GwQ;@5(1;`!NC#}qwW|Dfq@Qzfovs=+C5T2fZpw)k#65Wmnx(751kMg zZ4VBexEgioXb8|Y1V&1WWYnJn83H4{eMWEp)3(eQHGMdRz-W7LIK}3uUq(ZKk`Nfk zR>G*=BP9gr-5wh0_EAzIjOra(Au!q=99i)_>f6x}z#Rf3rA0F8&w&hqk={O|xBqeH z_feVA5I_xq(e@x}c#QH!Ltx~Fz(BSVM(rLcAwci;&`7s$i$+~N5Fs$y9vp~JAGLEd1O{UWjFcA1s6PiX1V(!MjNbkqj3v#en+9hH zjJ5{{XS|HMYBU7s9|8l}N*J|!q=W#y+e0JWKKhp+t1wg+h)!lUMohQLq>fq`r#jM_a?LV(`wp^g%B8R4-SP`8g=7n2+$)0 z2C|hfYWGM90eZKGM!J3UC^<&$7#<-o+8!Jp@i^*>(GZ|K1V&1WWYnJn83H4{eMWEp zQ(i8NnlMsAV6;6rQet}4pQ9l_CSXb24D5Ev;fl2LySWC)D(_8GnXKa@+PQMc1K z1V-C~^bPM(+eSlR@P@!Zwh~6|9w{L}@AlA0w{P&4H=`~aY#}h(9vo~jGU}eu5E!Ts z7%451QGX6(2#oah8NK~KP^HPJy+bbqM%#l!FV03?JQ@PD34wuZC5+lVQbK^G*=BP9gr-5wh0_6@gEYScfp z3xU!0Ann3-)a20+7+N7PQd%UV{v5~<80qaZdi#H9l|iGf9mo(EZ4VA)=#Sbx8UlkU z1O~E|FlzTm2?2Vyheo=6gQ2p-?Xb8|N1V-C~ z^a|-wdqzWGGz11?2#mxw*+BYvFtpF;?S{da?nm7;8UpAcFxnnO50O#+Xb6mkz(@*# zfovO%M7!zT78?xqjimfE>erzg0;BE0p&NIjE*}kn(GZ|K1V&<;Y#{wS7}{s_b_3<9 zbku~=5TJbsjJ5}9AI76LjE2By2n^m37|6EKNVJ>YZLz^%-{4LCqb?f_0YnIlwg(Ym zG0GYZfzc2cc_AW08bY?BS7p9e$xjNWdbZi*c>Z8QXE69S{{LE41tsHvkNFd70wBLoJrZ8Q?? zrgvLxFxWRVa>A%9M|ud1wg*Rg3K;eOXb6n#5EzMVvVrvTU}&Gw+YKW-hmHDvsD!|1 zdvK`4)Tld0Ltr!nXb}Pf*)|%9cGJ5pHW=)qMY7!84;83H4*O*W8z9t`a>db?q0=8RESkF*dNZ4ZvL7$5cT zXb6mk0CETnWZP&Y+D-4a*kG^^IlYatM?+w+hQMfhaInVAsJli(U^E2i5dtHzO*W8z z9t`a>db@!h>3GzR(GZ|C1V-C~l!oA_{?QN^4S}H?0t4AL8i{t(yDc^t>>JAYW7O>< zCj>^@gCi%dM}0aP0;3^-83H4*O*W8z9t`a>dbQ*hjzAJZjTu2#_BFqwPWR!){dPXb6mkz|aqYk=Q01NIwsT z_8Gn1F!XcDs1HU$2#mG|M?x%*`f)S_MneEs2n=M~Xe8QA@3z=run$+-8xB$ww9n}6270IIQTs+ifSeE*Z4Z(YYNL8aLtr!n zhD!(xWZP&Y+D-4a*kG`4xa5^le+=&s7;O&@@Aw_{-Dn7mh5-H$7>RANf%NlWXrIyB z4fs>wsO)G642}>OZ4VBPco=oXXb6mkz`%sSK(>uWqTTdviwy?*1}0^X+BzBnq=mp} zdyus78dW_S0;3@?yh30kw#f$4&x4_TMsGI^uN*V#o8cM)qwT@r8ndJR8V!Nb5FjQ5 z2C{85678mUTWm1cM@%{#RWlj_104dR?ZJVLfl>QMLtr!n1~LRjVw-Fr{X7`jXY_W% zK&J0eyGKKS*bo?P4-y+vqv}ROU^E1VV+agn+h`=(P4BkYV6bmE=9^JJ4Zjc=Z4VB= zI34xTXb6mk0P!I(65C`0>F2@FKBKoAh)<29Dn~xLK9!HUU^D~>hrnoikZ>4{su&G{(GVEEAutl#WCQ8v!O%XVw;P6U z?iuyja0-FZ_TX@e%~8LMhQMeDkQxF5*)|%9cGJ5pHW=(9HBFAH9}R(l2!YY|;6Q}> zsGXxBFd71bB?Lxdn`|KcJQ&(%^mfBwN$aET7!3h@Au!q=#1}fFa-$(I8Un*T1O~Eg zG!pHmcUx>Q*f-qs(5U~0M+l6z2Zu*Ij{0IW1V%%Eybu_PZL)#%^I&M7(c2B=rOZ)X zqai@w5EyL_(l@+EZ5s`N(GVD1Auy0_qmgJgz1w1g!M?$j;zwOG8UoluV6;7mJzPdb zM?+vV1V%;(jKntCK>B$ww9n}6hLMqzMtwQdLtwN$IMics)cvC&Fd71sgupY?_Ltr!nMnhmU1V%$(Gz3ONU}S~BXnSyE#rLRhM?+vV1V%$(Gz3ON zU^E0qLjXMlM%#nvAu`Gz4S~@R7!85Z5Eu=C(GVC7fsqvgqwT?w72l)29Swoe5Eu=C z(GVC7fzc2c4FU8J7;O)thsY>@Gz3ONU^E0qLtr!nMnhmU1V&Z}jJ5|yR(y~8b~FS= zLtr!nMnhmU1V%$(Gz8E?V6;7m9wMXs(GVC7fzc2c4S~@R7!85Z5Exk@Fxnm*S@AvU z+tCmh4S~@R7!85Z5Eu=C(GWlnfzkFLdWekjM?+vV1V%$(Gz3ONU^E0qLttcuz-W7L zWX1QWZ%0F5Gz3ONU^E0qLtr!nMneES1V-C~=pi!79}R)g5Eu=C(GVC7fzc2c4S|sr z0;BE0krm&gz8wvL(GVC7fzc2c4S~@R7!3jR5EyL_qKC*Re>4O}Ltr!nMnhmU1V%$( zGz3Og2#mG|M^=1~`gSw~MnhmU1V%$(Gz3ONU^E2KLtwN$h#n%N{Lv5?4S~@R7!85Z z5Eu=C(GVC}Au!q=99i)_>f6x}7!85Z5Eu=C(GVC7fzc2^4}sD4AbN<5@<&5pGz3ON zU^E0qLtr!nMnhm^g}`WgaAd{zsBcF@U^E0qLtr!nMnhmU1V%#uJp@MEgXkeL${!7Z z(GVC7fzc2c4S~@R7!84u6#}E}!I2f;qrM#tfzc2c4S~@R7!85Z5Eu;s^bi z(GVC7fzc2c4S~@R7!85Z5I_%s(e@yEh>Y?_Ltr!nMnhmU1V%$(Gz3ONU}S~BXnSyE z#rLRhM?+vV1V%$(Gz3ONU^E0qLjXMlM%#nvAu`Gz4S~@R7!85Z5Eu=C(GVC7fsqvg zqwT?w72l)29Swoe5Eu=C(GVC7fzc2c4FU8J7;O)thsY>@Gz3ONU^E0qLtr!nMnhmU z1V&Z}jJ5|yR(y~8b~FS=Ltr!nMnhmU1V%$(Gz8E?V6;7m9wMXs(GVC7fzc2c4S~@R z7!85Z5Exk@Fxnm*S@AvU+tCmh4S~@R7!85Z5Eu=C(GWlnfzkFLdWekjM?+vV1V%$( zGz3ONU^E0qLttcuz-W7LWX1QWZ%0F5Gz3ONU^E0qLtr!nMneES1V-C~=pi!79}R)g z5Eu=C(GVC7fzc2c4S|sr0;BE0krm&gz8wvL(GVC7fzc2c4S~@R7!3jR5EyL_qKC*R ze>4O}Ltr!nMnhmU1V%$(Gz3Og2#mG|M^=1~`gSw~MnhmU1V%$(Gz3ONU^E2KLtwN$ zh#n%N{Lv5?4S~@R7!85Z5Eu=C(GVC}Au!q=99i)_>f6x}7!85Z5Eu=C(GVC7fzc2^ z4}sD4AbN<5@<&5pGz3ONU^E0qLtr!nMnhm^g}`WgaAd{zsBcF@U^E0qLtr!nMnhmU z1V%#uJp@MEgXkeL${!7Z(GVC7fzc2c4S~@R7!84u6#}E}!I2f;qrM#tfzc2c4S~@R z7!85Z5Eu;s^bi(GVC7fzc2c4S~@R7!85Z5I_%s(e@yEh>Y?_Ltr!nMnhmU z1V%$(Gz3ONU}S~BXnSyE#rLRhM?+vV1V%$(Gz3ONU^E0qLjXMlM%#nvAu`Gz4S~@R z7!85Z5Eu=C(GVC7fsqvgqwT?w72l)29Swoe5Eu=C(GVC7fzc2c4FU8J7;O)thsY>@ zGz3ONU^E0qLtr!nMnhmU1V&Z}jJ5|yR(y~8b~FS=Ltr!nMnhmU1V%$(Gz8E?V6;7m z9wMXs(GVC7fzc2c4S~@R7!85Z5Exk@Fxnm*S@AvU+tCmh4S~@R7!85Z5Eu=C(GWln zfzkFLdWekjM?+vV1V%$(Gz3ONU^E0qLttcuz-W7LWX1QWZ%0F5Gz3ONU^E0qLtr!n zMneES1V-C~=pi!79}R)g5Eu=C(GVC7fzc2c4S|sr0;BE0krm&gz8wvL(GVC7fzc2c z4S~@R7!3jR5EyL_qKC*Re>4O}Ltr!nMnhmU1V%$(Gz3Og2#mG|M^=1~`gSw~MnhmU z1V%$(Gz3ONU^E2KLtwN$h#n%N{Lv5?4S~@R7!85Z5Eu=C(GVC}Au!q=99i)_>f6x} z7!85Z5Eu=C(GVC7fzc2^4}sD4AbN<5@<&5pGz3ONU^E0qLtr!nMnhm^g}`WgaAd{z zsBcF@U^E0qLtr!nMnhmU1V%#uJp@MEgXkeL${!7Z(GVC7fzc2c4S~@R7!84u6#}E} z!I2f;qrM#tfzc2c4S~@R7!85Z5Eu;s^bi>#RI%>yg2n^j27;O&@-MAZd`Dh4?hQLq`fsxo6{4`*# z!AB!(?r$jPj8V4_ObCp&2L~qHM{OMqfzc2c=^-%M9;EL`;Yd$!qy8Ta0sJ8_+8)Fo zKBKauAut*Oqai?>5EyL_jKP4z(GVC70ZKz)v^_Z5 z9;7r4jp`o_0qTXoXnT-)VL58jXb6mkz-R~%9|EK8!O`|0@u_804O+4S~@R7&##@+8!Kj500GFKI+rK9|EK8!NDI#qb?i`fzc2c zjv+AG9vp2C4##vo>ZhR^0;BE0p&E0e?j8++(GVEgAu!q=9BmH{?G!xf`r#DUFxnm*Z4VBWv^wg}kq`o-?ZJ@{%cFiA4S~@R7*4!I2yHqdp%Efzc2c$PgH9501762QvMQ+C3Tqs39=g9z+d~QQl|>jE2By z2+$`4M%#mKWBJ8UoY~fzkFLwL^5&ywMOC4S~@R zASMJx+k>O+L1NO$sG89bpic;lwg>4G&ZD-BhQMeDjD`Se2#mG|N85v_DPoj28Uh0u z0;BE0feigoyGKJ{Gz3O&2#mG|N85uVH}#MDeDH<9XnSz*#mT6PMnhmU1V%y#jJ5|y z+k+z^osar)sD!|1dvK`4)Tld0Ltr!nhF1uTwg*SsgTpIDkNRe4hrnoiaA?QhsOv{V zU^E1VY6y(B2S?k3LpAM=x_dZ=z-W7LIL7LzpGHGqGz12J2#mG|N85vgKb4NUaO8x* zXnSzv#Pz68M?+vV1O`(GjJ5|y+k=BCJ&w9%q=&$0dvK(ufKmUChQMeD3`_`&wg*Ss zg9DTDMr|Dp0c;^K+8)FfDx+efAut*Oqai@+5EyL_j-EqaiTxAu!q=9QZgGb-`!|jE2BS41v-1;AnerB&PdO zKM&RrKyME=GmOH~5Eu=C7=|u}QB1!u$YGenFpB9H29*q+45N5742E+WNM^`q7-^W& zntQZ8NNEU;>K~3FFxnQRUt16q)}w7f`n3f?VLhDN0i%8!ZRdj0z({Kgg8WNqT|C+z zq%;Ia^$*7o0JTv@G5y+vpf<`VreB*7R9}wb(RR~tP6MF!(MZFT*2SakK}th#RR3@c zfzh@g{n~<{upVs-(yuKD3hUwA4jA>@Xge2_21Z(25aeG<>*CS&Af+KVs((0!0H}>J zis{!T1hr8{G5y+vp!#wYkG7kJa~c4(k474%v@RZP4^kR}qxy$q2#mG`>DLwnh4pA# zkbZ4JP*@M=cEG6LM%%fdG%(WIf*}7=S{IMD2PqA~QT@X)1VC++QB1!!A*hWqis{!T z1l5Ole&_+8(4d z1V{A`#}F883(~JG2ny@bwjll5f}pS-&h3Cvzm2wYL1|#5wFN=`rL-;{Z4Xi!f}{F} zV+erSD5IEuZ9-5RWfaq|O$e$lNAYO8X*j0=Q2S`4VM^=b(e@yvAvmgkIEKJzTabQj zK~Pwawgu_e76gU$aBc^T`faqG3rYhctt|-hFQs+yXnT;-5FFJ%976!qMj6HQYZHRn zD5IEuZ9-6eIf_TyO~W}2fZ9hR4O3bdkG2OX4Z%_U!!ZO#+k*6K3xdLWv@J-#wje01 zhjTk%)NiBhTu>SqX>CD}e<`htN85vxhTy3F;TQs-Hp(cbUz-rrMj6HQYZHR%%TYYq zZW_*M0MtGjX_(Twc(gr8X$X$$AC4g~+7_f=TM!i1qisR@wFN<8J)GMCqkbE0=YrC} zNNWp%{7Y$FJlY*3rE81>s|I~SA&Mp|1CjE!sEsm;>DML%wNXYf{n~_}`f?PHwws1?8UVGAMjEEHE*@9KEeP^2rFHRWdyvu)9MwM@ zLjcq+8z>BFAB{8&YNL!|`n3r`_2o#!p!U&7!y_@CL4F3ck474%v@RZP4^kR}qxy$q z2nJK7ecUt16q)}Z=wB;t|Q76kcsB*rty&m*lZ2=Xtbb@6C>kkSww z)ju3V0MsrUC=6;JjWi5uql{wuwFyD>ZGz@B^jAHt=2|@McNW`G_(MZE1F`hww2DOhy8m6=^9&Ha& z8iJ$xhhqo~R9g^a??`J4g8Vz$7NlQW5ERy+`f?=Vk=7Oj`FAA7Gsw>)tt|-hFQs+y zXnT;-5FFJ%976!qE*mHeY9Ea>3~Hl{V*0fSLG|TG#Gv-kNW&vBo9KEeP^2 zrFHRWdyvu)9MwM@Ljcq+8z>BFAB{8&YNL!|`n3r`_2o#!p!U&7!y_@CL4F3ck474% zv@RZP4^kR}qxy$q2nJK7ecUt16q)}Z=wB;t|Q76kcsB*rty&m*lZ z2=Xtbb@6C>kkSww)ju3V0MsrUC=6;JjWi5uql{wuwFyD>ZGz@B^jAHt=2|@McNW`G_(MZE1F`hww z2DOhy8m6=^9&Ha&8iJ$xhhqo~R9g^a??`J4g8Vz$7NlQW5ERy+`f?=Vk=7Oj`FAA7 zGsw>)tt|-hFQs+yXnT;-5FFJ%976!qE*mHeY9Ea>3~Hl{V*0fSLG|TG#Gv-kNW&vB zo9KEeP^2rFHRWdyvu)9MwM@Ljcq+8z>BFAB{8&YNL!|`n3r`_2o#!p!U&7 z!y_@CL4F3ck474%v@RZP4^kR}qxy$q2nJK7ecUt16q)}Z=wB;t|Q z76kcsB*rty&m*lZ2=Xtbb@6C>kkSww)ju3V0MsrUC=6;JjWi5uql{wuwFyD>ZGz@B^jAHt=2|@Mc zNW`G_(MZE1F`hww2DOhy8m6=^9&Ha&8iJ$xhhqo~R9g^a??`J4g8Vz$7NlQW5ERy+ z`f?=Vk=7Oj`FAA7Gsw>)tt|-hFQs+yXnT;-5FFJ%976!qE*mHeY9Ea>3~Hl{V*0fS zLG|TG#Gv-kNW&vBo9KEeP^2rFHRWdyvu)9MwM@Ljcq+8z>BFAB{8&YNL!| z`n3r`_2o#!p!U&7!y_@CL4F3ck474%v@RZP4^kR}qxy$q2nJK7ec zUt16q)}Z=wB;t|Q76kcsB*rty&m*lZ2=Xtbb@6C>kkSww)ju3V0MsrUC=6;JjWi5u zql{wuwFyD>Z zGz@B^jAHt=2|@McNW`G_(MZE1F`hww2DOhy8m6=^9&Ha&8iJ$xhhqo~R9g^a??`J4 zg8Vz$7NlQW5ERy+`f?=Vk=7Oj`FAA7Gsw>)tt|-hFQs+yXnT;-5FFJ%976!qE*mHe zY9Ea>3~Hl{V*0fSLG|TG#Gv-kNW&vBo9KEeP^2rFHRWdyvu)9MwM@Ljcq+ z8z>BFAB{8&YNL!|`n3r`_2o#!p!U&7!y_@CL4F3ck474%v@RZP4^kR}qxy$q2nJK7ecUt16q)}Z=wB;t|Q76kcsB*rty&m*lZ2=Xtbb@6C>kkSww)ju3V z0MsrUC=6;JjWi5uql{wuwFyD>ZGz@B^jAHt=2|@McNW`G_(MZE1F`hww2DOhy8m6=^9&Ha&8iJ$x zhhqo~R9g^a??`J4g8Vz$7NlQW5ERy+`f?=Vk=7Oj`FAA7Gsw>)tt|-hFQs+yXnT;- z5FFJ%976!qE*mHeY9Ea>3~Hl{V*0fSLG|TG#Gv-kNW&vBo9KEeP^2rFHRW zdyvu)9MwM@Ljcq+8z>BFAB{8&YNL!|`n3r`_2o#!p!U&7!y_@CL4F3ck474%v@RZP z4^kR}qxy$q2nJK7ecUt16q)}Z=wB;t|Q76kcsB*rty&m*lZ2=Xtb zb@6C>kkSww)ju3V0MsrUC=6;JjWi5uql{wuwFyD>sjm9k`Zbw>M5aeG<>*CS&Af+KVs((0!z-T)S z(oUmSIDpzHqnLhe!qGMZq|GoI4#PJbK<%TEhAFL!N85vxhTy3F;TQt+Y6p$l18H}T zwgu_e76gU$Xgg^5wu46F78183tt|-hFQs+yXnT;-5FFJ%97ABVod#*A(JLH4ZIn?= zzc%4$n*q{h7!8Nv8xElM(MZFT*2SakK}th#RR3@c0eZEAM(u&LJ4f4s^lJ-(!g{nF zG<@4Zqj3v~+mY551o@ZJx_GobNNEU;>K~3FFxpOowA1Jn4xl#5D5hVVaJ0<;X)}z5 z!|)9UQ2S`4VM^=b(e@yvAvmgkIEDbd+CiiCK-!(7Z9)3A1wmmw+724N?V!=Pg~aVh zYYT$>OKDv^+8(4d1V{A`#}F88r$O3j^a=-18)X#JuT41GW`MLAM#EwFh6AX5G}17o zb@6C>kkSww)ju3VfL`sOQF|cm&e66Y{n~<{upVs(4c~UqXxu{LcBHihLH?z*E*@ zjv+v=cF?Fjkap*2TabQjK~Pwawu6RmJ7_d+A#pp>+JYeeQd$>}wg)K zG#rL+IDpzmBMnnp7mv0FDGk9<{lhT?=+zDywFlDf9Bm8IuPq1)>(O@5@NEZ;#w{dn zM_OADjG~XgdwkPNP>ifZ8adn0{@-(KZ95%`h4c!#5m2?W2)~ zDXoh~+k=#b;HduL7y|Ta2aVbTX?Kpc1?kro1cmizJ81Z}gGS>P61O9*EeP^2rFHRW zdyvu)9MwM@LtwO>25G0!D;z*=lu=B-HsNTS0n%m|4Ts?y4xskYNW+xY#iQ*(N<(l| z|8NWedbNW_?SZsAN85t*YYT$HdZf04RxwOr7{wza3`Sa85aeG<>*CS&Af+KVs((0! zz-T)S(oUmSIDpzHqnLhe!qN8N$Y>Ld{-v}o9&Ha&8iJ$xhhqqgw$mW(GDMM4Z4ZvN2S?k3`3#^o)NsO-*2SakK}th#RR3@c0eZEAM(u&LJ4f4s^lJ-(!g{nl zINBZ@Z4ZvN2hr>9(e@yEh>Y?_L!g;qw4DZNr_n1MKy8#!OushaXnSz9JviDP9BmJx z*Y%_ALG%zA<&TEIXnT-e?Le44qisR@wFN<8J=z`|Z4ZvN2S?k3=ym;Qdk{TDM){*5 zFxno3wbSTDgW4#gn0{@-(e~hIdvLTpINBaWuj@zKgXkeL${!7Z(e@y{+JP{8M%#k) zYYT$HdbB+_+8!Kj50176(d+ur_8@wQjPgfAV6;65Yp2nR2DMQ}G5y+vqwT@b_TXrH zaI`&$Ue}Md2hl@hls_5*qwPU@wF6=HjJ5^o*A@hY^=Nx=v^_Z59vp2CqSy7K?LqVq z8Rd_Lz-W6A)=r}r4Qiu|V*0fSN85v=?ZMIZ;Andgy{;c^52A<2D1S5rM%#n*Y6rsX z8Ep&FuPq1)>(Tb$XnSz9JviDPM6c^d+k@yKGRhwffzkFLter+L8q`J^#q?_vjO+!O`|0dR;%-9z+k3QT}KMjJ5~q)eeN&GujrUUt16q)}!sg(e~hIdvLTph+fx^ zwg=HeWRyP|0;BCgSUZhgG^mX-is{!T9BmJdwg*SsgQM+1^tyhuJ%}D6qx{hj7;O*I zs~rflXS6LyzqTMKtVi2}qwT@b_TXrH5WTJ+Z4aV{$S8j_1V-C~uyz`~Xiytv6w|Lw zINBZ@Z4ZvN2S?k3=ym;Qdk{TDM){*5FxnoZS33}9&uCkaer-WeSdX>`N85v=?ZMIZ zAbMRt+8#s?kx~9=2#mG|VeK?}(V#ZUD5hVVaI`%*+8!Kj50176(d+ur_8@wQjPgfA zV6;6*uXZ5Jp3$}-{n~<{upVs>jO+LG-$Qv^|I(BBT7#5EyL_!rE!{qCstx zQB1!!;b?nsv^_Z59vp2CqSy7K?LqVq8Rd_Lz-W7rUhP1bJ)>L(e@yEh>Y?_LtwN$2y3U& ziw3n(Mlt=`grn`j(e~hIdvLTph+fx^wg=HeWRyP|0;BCgdbI;#_Kda#>DLwnh4pBA zaI`%*+8!Kj52DxgqwPWT5E=|tf(yuKD3hUAK;Anerv^_Z59z?I}N85wwAu`Gz4S~`2 zAgrB6FB;TF8O8K#6OOhAN85v=?ZMIZAbMRt+8#s?kx~9=2#mG|>D3N|*)!S}q+eSQ z6xO5d!O`~MXnSz9J&0b{kG2QVLu8ac8Umy3L0CJDUNoqUGK%TfCLC=KjO+ zLG-$Qv^|I(BBT7#5EyL_(yJW^vuCs|NWZoqD6B`@gQM-i(e~hIdl0>@A8ik!hsY>@ zGz3Q5gRpiQy=YJyWfaq|O*q;f9BmJdwg*SsgXnerXnPPnL`M0eAu!q=q*pr-X3uC_ zkbZ4JP*{()2S?k3qwT@b_8@v)KiVEd50O#+Xb6n92Vw0rdeNXZ$|$B^n{c!}INBZ@ zZ4ZvN2hr>L(e@yEh>Y?_LtwN$NUwGv%%0J@A8ik!hsY>@Gz3Q5gY;?#!t5Ds3(~JG2ny@b_TXrHaI`%* z+8#u&>qpyz=pi!79}R)g_8_dCMlTxFMj6HQYZH#P2S?k3qwT@b_8@v)KiVEd50O#+ zXb6n92kF%ggxNFN7NlQW5ERxUwLLiMZ%>Ai5(dc(!>_$Z$WN5k-J|V6N<(l||8NWe zSUY8u?qZ-v7=YR+qnLhe!jaM@81?7KY5$?eHKDfCaFnOCE*@ZyDLwng*B|s9HmFw zPs24049E5!AwN-C7mv0FDGk9<{lhT?M%!wLwi-Rc0@Ows#q?_v4%arosJ}+rx3Dxo zsO>ZyDLwng*B|s9HmFwPs24049E5!AwN-C7mv0FDGk9< z{lhT?M%!wLwi-Rc0@Ows#q?_v4%arosJ}+rx3DxosO>ZyDLwng*B|s9HmFwPs24049E5!AwN-C7mv0FDGk9<{lhT?M%!wLwi-Rc0@Ows#q?_v z4%arosJ}+rx3DxosO>ZyDLwng*B|s9HmFwPs24049E5! zAwN-C7mv0FDGk9<{lhT?M%!wLwi-Rc0@Ows#q?_v4%arosJ}+rx3DxosO>ZyDLwng*B|s9HmFwPs24049E5!AwN-C7mv0FDGk9<{lhT?M%!wL zwi-Rc0@Ows#q?_v4%apSA%B%IbTW)IOejo-t308$({Plhv@RZP4^kR}qxy$q2+*Sq zG-?N;%{kf@q+eSQ6xPGF4M50WBdsk6@-Lw<8LslfvAsvgPn6chqwPUTLvU38a14Rb zwi=?XMvt%nwNXYf{n~`XwGBYXU!eBUNW+A}WVp%`YC8=_c}nZz(e@yvAvmgkIEDZ{ z+CZarAljUxZ9)3A1wmmwT-yMI{58_rf*}7A3X|a~KOEb8g#1KlT|C+zq%;Ia^$*7o z7;UQ|+G_L&3s4(n6w|LwI9%HRg!~0+AB{9jC`^W{JfXJJaFnOCE*@QARQS+JwWk4M50Wp!U&7!-T?QxXKf1I}Jy9O6%g$_8_GpII4d* zh5$X_8HPYIGApa5yli?~q9NT+@{6uM8JlYV9&Ha&8iJ$x zhhqrPqYX4_2cpe6+7_f=TM!i1!?g`S$X_F^EeP^2p)eV)^24#cN61f<*2SakK}th# zRR3@cfzh@aqOC@cumH7DMlt=`gu}HBK*(R9_R&bggu-OF$`fik4M%xO>*CS&Af+KV zs((0!06p43qjn(LoTF_)`n3f?VLe>i0EGNC(%OO`{}Kw5;VM5I+k1rkL}^_-+8(4d z1V{A`#}F88t0CHI^au-38)X#JuT3~y+W>_81!^CSG)yQ=hO0cGw$pHwr?f5}Z4Xi! zf}{F}V+hcr4K!*8qRlzl7NlQW5ERzKwGBYXUn8w82=XtXFd44$!?C?b$WN5k#iQ*( zN<(l||8NX}(Y6|*twxWq0JTv@G5y+v!?g`S$X}rL(MZFD!eqG06KXpRM|n!?;?edX zr6D+~e>jE!J=#E{b|BiEqisR@wFN<8JzU!Wg#0zq+JYee5(<;yDnA_CdxZQ%XOejo-t308$({Plhv@RZP z4^kR}qxy$q2+*SqG-?N;%{kf@q+eSQ6xPGF4M50WBdsk6@-Lw<8LslfvAsvgPn6ch zqwPUTLvU38a14Rbwi=?XMvt%nwNXYf{n~`XwGBYXU!eBUNW+A}WVp%`YC8=_c}nZz z(e@yvAvmgkIEDZ{+CZarAljUxZ9)3A1wmmwT-yMI{58_rf*}7A3X|a~KOEb8g#1Kl zT|C+zq%;Ia^$*7o7;UQ|+G_L&3s4(n6w|LwI9%HRg!~0+AB{9jC`^W{JfXJJaFnOC zE*@QARQS+JwWk4M50Wp!U&7!-T?QxXKf1I}Jy9 zO6%g$_8_GpII4d*h5$X_8HPYIGApa5yli?~q9NT+@ z{6uM8JlYV9&Ha&8iJ$xhhqrPqYX4_2cpe6+7_f=TM!i1!?g`S$X_F^EeP^2p)eV)^24#c zN61f<*2SakK}th#RR3@cfzh@aqOC@cumH7DMlt=`gu}HBK*(R9_R&bggu-OF$`fik z4M%xO>*CS&Af+KVs((0!06p43qjn(LoTF_)`n3f?VLe>i0EGNC(%OO`{}Kw5;VM5I z+k1rkL}^_-+8(4d1V{A`#}F88t0CHI^au-38)X#JuT3~y+W>_81!^CSG)yQ=hO0cG zw$pHwr?f5}Z4Xi!f}{F}V+hcr4K!*8qRlzl7NlQW5ERzKwGBYXUn8w82=XtXFd44$ z!?C?b$WN5k#iQ*(N<(l||8NX}(Y6|*twxWq0JTv@G5y+v!?g`S$X}rL(MZFD!eqG0 z6KXpRM|n!?;?edXr6D+~e>jE!J=#E{b|BiEqisR@wFN<8JzU!Wg#0zq+JYee5(<;y zDnA_CdxZQ%XOejo- zt308$({Plhv@RZP4^kR}qxy$q2+*SqG-?N;%{kf@q+eSQ6xPGF4M50WBdsk6@-Lw< z8LslfvAsvgPn6chqwPUTLvU38a14Rbwi=?XMvt%nwNXYf{n~`XwGBYXU!eBUNW+A} zWVp%`YC8=_c}nZz(e@yvAvmgkIEDZ{+CZarAljUxZ9)3A1wmmwT-yMI{58_rf*}7A z3X|a~KOEb8g#1KlT|C+zq%;Ia^$*7o7;UQ|+G_L&3s4(n6w|LwI9%HRg!~0+AB{9j zC`^W{JfXJJaFnOCE*@QARQS+JwWk4M50Wp!U&7 z!-T?QxXKf1I}Jy9O6%g$_8_GpII4d*h5$X_8HPYIG zApa5yli?~q9NT+@{6uM8JlYV9&Ha&8iJ$xhhqrPqYX4_2cpe6+7_f=TM!i1!?g`S$X_F^ zEeP^2p)eV)^24#cN61f<*2SakK}th#RR3@cfzh@aqOC@cumH7DMlt=`gu}HBK*(R9 z_R&bggu-OF$`fik4M%xO>*CS&Af+KVs((0!06p43qjn(LoTF_)`n3f?VLe>i0EGNC z(%OO`{}Kw5;VM5I+k1rkL}^_-+8(4d1V{A`#}F88t0CHI^au-38)X#JuT3~y+W>_8 z1!^CSG)yQ=hO0cGw$pHwr?f5}Z4Xi!f}{F}V+hcr4K!*8qRlzl7NlQW5ERzKwGBYX zUn8w82=XtXFd44$!?C?b$WN5k#iQ*(N<(l||8NX}(Y6|*twxWq0JTv@G5y+v!?g`C z>Mu`*(J+970im|jaFnOCE*@Zy8|lu=B-HsNSHX!y2+M&lL|w}jeG!%?2nx_GobNNEU;>K~3F zK#w-is2zwl=V)7yer-WeSdX?DAZ>=xa2USfFdW-^g#1KlT|C+zq%;Ia^$*7o7;UQ| z+G_L&3s4(n6w|LwINA;xzU`pVxP`V9&Ha&8iJ$xhhqrPqYX4_2cpe6 z+7_f=TM!i1qiqIAn_)B@hHp3w$Mzl}KT%p2kG2OX4Z%_U!!ZO#+iHlm8a=`S)J7S_ z^lKB2wu6RmJ7_d+A#qEn?KB+aDXoh~+k=#b;HduL7y|TY1C82&XmgIX1?kro1cmiz zn*q{h7!8Nv8xF&QARQS+JvL+pyAsN z8jV{>+!AU#4M%xO>*CS&Af+KVs((0!06p43qjn(LoTF_)`n3f?VLjSrfV3G#!(sS_ z!*Fcx5%LqIb@6C>kkSww)ju3VV6?4DLwnh4pBg0n%m|4Ts?y4#Tm%N61f<*2SakK}th#RR3@cfzh@aqOC@c zumH7DMlt=`grn`C;oA-xjax|E5^6gQM|n!?;?edXr6D+~e>jE!J=#E{b|BiEqisR@ zwFN<8J=$h~v>8UjVfco_aBS}p@)M4T0ek0`zG6VY6ejEl9t%ASkS{#R0v< zhGRWEnEf<-N~cku&^iQ0+k>CGOFZLY!Wr@>RY zjJjm7hrnoiaInYFsQX4kfPNuB@3sNVK2RHF6w|Lw2n+Xtpa*l?X*jx#ex=8#O+!5d zM%#l!JqAbJKNxIl^G2I)DReL52A+0C~q_b zMsf&%>g$2PqisR@wFN<8JrHpWvvWAMxdyYJMsj&J>UYvYV6;6*T6m4B9u0xv90IU9 zo8C02jWUYq*CwQQ{36>onA=Xn(QU)Iyc+czbwgmZJxJZ~95rn;1cq`5AlKXUWRJE5 z>DLwng*83n7TvDl*yb9{ej3W<(Wu+$8v>*4LHdUGsBNPmFqlICz3!$LAJj$}#q?_v z(kouE*)y2iPQ%e{gSosJb=%+yfzkHh;EIn?*Nle1K!yOe`kNkNqisR@wFN<8O^-Om zWyf%Aa}8!c4P<#TYWL6zfzkHh(2B27*N%n&EkgiT9ZqX;P#a|w)2~fP>-fZH{$Or9 z4M(@pvb-2Idw7MwXnSyY#pkGRMniy-5WrWD(^77bk)c0;BE0!4w;#ZW#@Mfeit2 z>UV1B8Ep&FuPq1)Yih(9xn>NY=x z2Wq2?V*0fSDUB~m^bh8?({OYfZA*+%(}z%c}nz-wgu_e z76gSgC2>Wm-r?Bh8q9v8tV9^qJ(5CTv^_YIVtdrDqalDl1SqZR$<+^Pql{wuwF$|M zCu-;$%x$OP=r;U0epGfe1P~!G+8#uN#VBhu1V(xYP@}#l$BfaoApP2cps*$(e~iriHlK}jE2BKhrnnX274Q3 zG+d|`F2k|SHJJT0&}GV~{X-`NM%#l!C$2_aIvN7B4uR2j5B1tTqhX0XEC+MjX*jx# z)@8=1`NJm!M%#nKCoV^QG8zJuhQMeW274Q3G+d|`F2k|SHJJTGX_+vpf8>O~XnSzv z#Pz68M?-*62#mISsMqcp4NL4{Ihfl{!_jSo^8Bd$Xb8YUV6;653yD#BGz3ONV6+W` zy$v%OF4PN`;n?OH%zhdz)kZ^r*bo?P4-y+vqv}ROVEBi?XuF4c?Vi!F#2%J|x$QI@ z-8TG7tx+FRD+ET{gVYMiQFBH^VCaXyXd4E58)h_Is2487vCTD@{WSDTrBNTyD+ET{ zgY*jNQF}&1VDN{)XuF4c?Vi!F#2%J|x$QI@-8T43olzGKmJk?i4-S@?7J2n>7( zjJ9F0w_!%Zg?iyK9NS!j*-ryss*Ji|sD!|1dvK`4)Tld0LxA=nFxu{+Ub|;BEU|~> zU~W4NN4L?w)EKp4xP-uHdvLhKT!v$tYcTt1;7gTJ7YvmU7;O&@m6#fJ=V%DfJ_JVF zJ=AOWjD{ulupG>7r{U-}+Ls!mHVl^#7;O&@mzW&&$7l#p9s;9n80>AB(Qu(&xD3ZO z*I@P&<)y-?2_q#0M%#lUC8kIHIT`|lLtwPsL%nv-Xjozo%fZ}s8jfxwoa;wbjD`Rt z1V-C~kZ>3!M?+vV1V&~EjJDgbx7%nHF2k|SMaWMhGiQzZdZ>lKXnSy|#n`BOM?+vV z1gIGTv}*T^nv1=iNvQ2K9ObE*UPsLu4FOt(z-W7rRv|lT?q~>%hQLq=fzfsw_I4Ys z!euzN_XzoEDCC1tH;#tDXnSxp4UC4sXb6nt5TI4NXVhHm?My;#r{O3+lJnQ7--k{J zjJ5}dPF#(;bTkA;LxB1rFxqaz-fp8+xD3bk9w9$bKh=(!I2r=f4}sD4Aoas^)Wp#c z7!84;69Tkq_l%m0y`4#@?KB+ahfZ!7b?HbBfzkHhNRItczmJB%Xb6n9+pxFWXcaEQ zvAsvgPouePGz5l12#mG|he9lkx^XlFMniyBAwa8kZB+nI#gPQy{2R%v(C+|dxA zW(bV72dNpFqh^hUz-R~zwGbF>w_$I$(JEYqV|$N~pN3kV7kQD2XS zz-S0SLV#B7o>6nLw=)T~ora@4B&Cg#qaiT3LtwN$IJo0y)ODjFFd7214S~^i8}@b^ zt-@tEw)Y76iMAc7zt7!85Z5Eu=C(GVC7fzc4a z9|EK8LHyw}DmxkiqaiRF0;3@?8UmvsFd72GJp@MEgTpTtHZ2#kinXb6mkz-S1JhQMeD4EGQiZ4VCj7#{WCXb6mk zz-S1JhQMeDjE2By2;dKa(e@zz@EMgI4S~@R7!85Z5Eu=C(GVC7f#DtkqwT@r9>b&l z8x4Wc5Eu=C(GVC7fzc2c4FUWiFxno(A3me9qaiRF0;3@?8UmvsFd71*Au!xSV6;6r z++%puf1@EV8UmvsFd71*Aut*OqalDl1V-C~_`_#Zb~FS=Ltr!nMnhmU1V%$(Gz5lw z2#mG|hkFc<`foG@MnhmU1V%$(Gz3ONU^E2qhrnoi5P$fL%8rJ>Xb6mkz-S1JhQMeD zjE2B)4}sD4;Bb%OQU8sGz-S1JhQMeDjE2By2#kgR{ty^#58@A>QQ6TD7!85Z5Eu=C z(GVC7fzc2c?jbPR9vtp5JnFyE5Eu=C(GVC7fzc2c4S~@Rz#jsm?LqwEGb%e80;3@? z8UmvsFd71*Aut*O!#xB>+k?YBhDZH38UmvsFd71*Aut*OqaiRF0{BBSg@;F~8TG|z2+$@3M%#n53D;3mM?+vV1V%%EPza2) zwjjvA1JxD;*-I!sM&(CCU?hjYXnSxZ$Ns3_M?+vV1O_q$K<%TEhC%JJfx-hB*Q0ii zhQMGCfzkHhV2`0u_l<_YXb23~5EyA~L6Cn3sx1hzcetjbQGbnw05w8jv^_|TP#iU5 zGz3ONU^E0s4*^j7Xry6KyKJB^=`l2_V>ARtP6&*)2S-j^kNR{p1V%$(aD~7~YYT$> zJ5X&wkiCN|_D5Ya8UlkW1V-C~gDXBpT{9X2qaiSILIBi08fh5RE*mI3a#Gf)Pe((5 z^bi vz-W7Lc*NtVFGfRPGz5lT2#mD0AjrQ1)fNQVJM>b>sEbEKfPNu>)*b`^&T|I9 diff --git a/libs/ultrahdr/tests/jpegr_test.cpp b/libs/ultrahdr/tests/jpegr_test.cpp index 41d55ec497..7837bcfc31 100644 --- a/libs/ultrahdr/tests/jpegr_test.cpp +++ b/libs/ultrahdr/tests/jpegr_test.cpp @@ -14,810 +14,1232 @@ * limitations under the License. */ +#include +#include +#include + +#include #include #include -#include -#include -#include + #include -#include #include -#define RAW_P010_IMAGE "/sdcard/Documents/raw_p010_image.p010" -#define RAW_P010_IMAGE_WITH_STRIDE "/sdcard/Documents/raw_p010_image_with_stride.p010" -#define RAW_YUV420_IMAGE "/sdcard/Documents/raw_yuv420_image.yuv420" -#define JPEG_IMAGE "/sdcard/Documents/jpeg_image.jpg" -#define TEST_IMAGE_WIDTH 1280 -#define TEST_IMAGE_HEIGHT 720 -#define TEST_IMAGE_STRIDE 1288 -#define DEFAULT_JPEG_QUALITY 90 - -#define SAVE_ENCODING_RESULT true -#define SAVE_DECODING_RESULT true -#define SAVE_INPUT_RGBA true +//#define DUMP_OUTPUT namespace android::ultrahdr { -struct Timer { - struct timeval StartingTime; - struct timeval EndingTime; - struct timeval ElapsedMicroseconds; +// resources used by unit tests +const char* kYCbCrP010FileName = "raw_p010_image.p010"; +const char* kYCbCr420FileName = "raw_yuv420_image.yuv420"; +const char* kSdrJpgFileName = "jpeg_image.jpg"; +const int kImageWidth = 1280; +const int kImageHeight = 720; +const int kQuality = 90; + +// Wrapper to describe the input type +typedef enum { + YCbCr_p010 = 0, + YCbCr_420 = 1, +} UhdrInputFormat; + +/** + * Wrapper class for raw resource + * Sample usage: + * UhdrUnCompressedStructWrapper rawImg(width, height, YCbCr_p010); + * rawImg.setImageColorGamut(colorGamut)); + * rawImg.setImageStride(strideLuma, strideChroma); // optional + * rawImg.setChromaMode(false); // optional + * rawImg.allocateMemory(); + * rawImg.loadRawResource(kYCbCrP010FileName); + */ +class UhdrUnCompressedStructWrapper { +public: + UhdrUnCompressedStructWrapper(uint32_t width, uint32_t height, UhdrInputFormat format); + ~UhdrUnCompressedStructWrapper() = default; + + bool setChromaMode(bool isChromaContiguous); + bool setImageStride(int lumaStride, int chromaStride); + bool setImageColorGamut(ultrahdr_color_gamut colorGamut); + bool allocateMemory(); + bool loadRawResource(const char* fileName); + jr_uncompressed_ptr getImageHandle(); + +private: + std::unique_ptr mLumaData; + std::unique_ptr mChromaData; + jpegr_uncompressed_struct mImg; + UhdrInputFormat mFormat; + bool mIsChromaContiguous; }; -void timerStart(Timer *t) { - gettimeofday(&t->StartingTime, nullptr); -} +/** + * Wrapper class for compressed resource + * Sample usage: + * UhdrCompressedStructWrapper jpgImg(width, height); + * rawImg.allocateMemory(); + */ +class UhdrCompressedStructWrapper { +public: + UhdrCompressedStructWrapper(uint32_t width, uint32_t height); + ~UhdrCompressedStructWrapper() = default; -void timerStop(Timer *t) { - gettimeofday(&t->EndingTime, nullptr); -} + bool allocateMemory(); + jr_compressed_ptr getImageHandle(); -int64_t elapsedTime(Timer *t) { - t->ElapsedMicroseconds.tv_sec = t->EndingTime.tv_sec - t->StartingTime.tv_sec; - t->ElapsedMicroseconds.tv_usec = t->EndingTime.tv_usec - t->StartingTime.tv_usec; - return t->ElapsedMicroseconds.tv_sec * 1000000 + t->ElapsedMicroseconds.tv_usec; -} +private: + std::unique_ptr mData; + jpegr_compressed_struct mImg{}; + uint32_t mWidth; + uint32_t mHeight; +}; -static size_t getFileSize(int fd) { - struct stat st; - if (fstat(fd, &st) < 0) { - ALOGW("%s : fstat failed", __func__); - return 0; - } - return st.st_size; // bytes +UhdrUnCompressedStructWrapper::UhdrUnCompressedStructWrapper(uint32_t width, uint32_t height, + UhdrInputFormat format) { + mImg.data = nullptr; + mImg.width = width; + mImg.height = height; + mImg.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; + mImg.chroma_data = nullptr; + mImg.luma_stride = 0; + mImg.chroma_stride = 0; + mFormat = format; + mIsChromaContiguous = true; } -static bool loadFile(const char filename[], void*& result, int* fileLength) { - int fd = open(filename, O_CLOEXEC); - if (fd < 0) { +bool UhdrUnCompressedStructWrapper::setChromaMode(bool isChromaContiguous) { + if (mLumaData.get() != nullptr) { + std::cerr << "Object has sailed, no further modifications are allowed" << std::endl; return false; } - int length = getFileSize(fd); - if (length == 0) { - close(fd); + mIsChromaContiguous = isChromaContiguous; + return true; +} + +bool UhdrUnCompressedStructWrapper::setImageStride(int lumaStride, int chromaStride) { + if (mLumaData.get() != nullptr) { + std::cerr << "Object has sailed, no further modifications are allowed" << std::endl; return false; } - if (fileLength != nullptr) { - *fileLength = length; + if (lumaStride != 0) { + if (lumaStride < mImg.width) { + std::cerr << "Bad luma stride received" << std::endl; + return false; + } + mImg.luma_stride = lumaStride; } - result = malloc(length); - if (read(fd, result, length) != static_cast(length)) { - close(fd); - return false; + if (chromaStride != 0) { + if (mFormat == YCbCr_p010 && chromaStride < mImg.width) { + std::cerr << "Bad chroma stride received for format YCbCrP010" << std::endl; + return false; + } + if (mFormat == YCbCr_420 && chromaStride < (mImg.width >> 1)) { + std::cerr << "Bad chroma stride received for format YCbCr420" << std::endl; + return false; + } + mImg.chroma_stride = chromaStride; } - close(fd); return true; } -static bool loadP010Image(const char *filename, jr_uncompressed_ptr img, - bool isUVContiguous) { - int fd = open(filename, O_CLOEXEC); - if (fd < 0) { +bool UhdrUnCompressedStructWrapper::setImageColorGamut(ultrahdr_color_gamut colorGamut) { + if (mLumaData.get() != nullptr) { + std::cerr << "Object has sailed, no further modifications are allowed" << std::endl; return false; } - const int bpp = 2; - int lumaStride = img->luma_stride == 0 ? img->width : img->luma_stride; - int lumaSize = bpp * lumaStride * img->height; - int chromaSize = bpp * (img->height / 2) * - (isUVContiguous ? lumaStride : img->chroma_stride); - img->data = malloc(lumaSize + (isUVContiguous ? chromaSize : 0)); - if (img->data == nullptr) { - ALOGE("loadP010Image(): failed to allocate memory for luma data."); + mImg.colorGamut = colorGamut; + return true; +} + +bool UhdrUnCompressedStructWrapper::allocateMemory() { + if (mImg.width == 0 || (mImg.width % 2 != 0) || mImg.height == 0 || (mImg.height % 2 != 0) || + (mFormat != YCbCr_p010 && mFormat != YCbCr_420)) { + std::cerr << "Object in bad state, mem alloc failed" << std::endl; return false; } - uint8_t *mem = static_cast(img->data); - for (int i = 0; i < img->height; i++) { - if (read(fd, mem, img->width * bpp) != img->width * bpp) { - close(fd); + int lumaStride = mImg.luma_stride == 0 ? mImg.width : mImg.luma_stride; + int lumaSize = lumaStride * mImg.height * (mFormat == YCbCr_p010 ? 2 : 1); + int chromaSize = (mImg.height >> 1) * (mFormat == YCbCr_p010 ? 2 : 1); + if (mIsChromaContiguous) { + chromaSize *= lumaStride; + } else { + if (mImg.chroma_stride == 0) { + std::cerr << "Object in bad state, mem alloc failed" << std::endl; return false; } - mem += lumaStride * bpp; - } - int chromaStride = lumaStride; - if (!isUVContiguous) { - img->chroma_data = malloc(chromaSize); - if (img->chroma_data == nullptr) { - ALOGE("loadP010Image(): failed to allocate memory for chroma data."); - return false; + if (mFormat == YCbCr_p010) { + chromaSize *= mImg.chroma_stride; + } else { + chromaSize *= (mImg.chroma_stride * 2); } - mem = static_cast(img->chroma_data); - chromaStride = img->chroma_stride; } - for (int i = 0; i < img->height / 2; i++) { - if (read(fd, mem, img->width * bpp) != img->width * bpp) { - close(fd); - return false; - } - mem += chromaStride * bpp; + if (mIsChromaContiguous) { + mLumaData = std::make_unique(lumaSize + chromaSize); + mImg.data = mLumaData.get(); + mImg.chroma_data = nullptr; + } else { + mLumaData = std::make_unique(lumaSize); + mImg.data = mLumaData.get(); + mChromaData = std::make_unique(chromaSize); + mImg.chroma_data = mChromaData.get(); } - close(fd); return true; } -class JpegRTest : public testing::Test { -public: - JpegRTest(); - ~JpegRTest(); - -protected: - virtual void SetUp(); - virtual void TearDown(); - - struct jpegr_uncompressed_struct mRawP010Image{}; - struct jpegr_uncompressed_struct mRawP010ImageWithStride{}; - struct jpegr_uncompressed_struct mRawP010ImageWithChromaData{}; - struct jpegr_uncompressed_struct mRawYuv420Image{}; - struct jpegr_compressed_struct mJpegImage{}; -}; - -JpegRTest::JpegRTest() {} -JpegRTest::~JpegRTest() {} - -void JpegRTest::SetUp() {} -void JpegRTest::TearDown() { - free(mRawP010Image.data); - free(mRawP010Image.chroma_data); - free(mRawP010ImageWithStride.data); - free(mRawP010ImageWithStride.chroma_data); - free(mRawP010ImageWithChromaData.data); - free(mRawP010ImageWithChromaData.chroma_data); - free(mRawYuv420Image.data); - free(mJpegImage.data); +bool UhdrUnCompressedStructWrapper::loadRawResource(const char* fileName) { + if (!mImg.data) { + std::cerr << "memory is not allocated, read not possible" << std::endl; + return false; + } + std::ifstream ifd(fileName, std::ios::binary | std::ios::ate); + if (ifd.good()) { + int bpp = mFormat == YCbCr_p010 ? 2 : 1; + int size = ifd.tellg(); + int length = mImg.width * mImg.height * bpp * 3 / 2; // 2x2 subsampling + if (size < length) { + std::cerr << "requested to read " << length << " bytes from file : " << fileName + << ", file contains only " << length << " bytes" << std::endl; + return false; + } + ifd.seekg(0, std::ios::beg); + int lumaStride = mImg.luma_stride == 0 ? mImg.width : mImg.luma_stride; + char* mem = static_cast(mImg.data); + for (int i = 0; i < mImg.height; i++) { + ifd.read(mem, mImg.width * bpp); + mem += lumaStride * bpp; + } + if (!mIsChromaContiguous) { + mem = static_cast(mImg.chroma_data); + } + int chromaStride; + if (mIsChromaContiguous) { + chromaStride = mFormat == YCbCr_p010 ? lumaStride : lumaStride / 2; + } else { + if (mFormat == YCbCr_p010) { + chromaStride = mImg.chroma_stride == 0 ? lumaStride : mImg.chroma_stride; + } else { + chromaStride = mImg.chroma_stride == 0 ? (lumaStride / 2) : mImg.chroma_stride; + } + } + if (mFormat == YCbCr_p010) { + for (int i = 0; i < mImg.height / 2; i++) { + ifd.read(mem, mImg.width * 2); + mem += chromaStride * 2; + } + } else { + for (int i = 0; i < mImg.height / 2; i++) { + ifd.read(mem, (mImg.width / 2)); + mem += chromaStride; + } + for (int i = 0; i < mImg.height / 2; i++) { + ifd.read(mem, (mImg.width / 2)); + mem += chromaStride; + } + } + return true; + } + std::cerr << "unable to open file : " << fileName << std::endl; + return false; } -class JpegRBenchmark : public JpegR { -public: - void BenchmarkGenerateGainMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr p010Image, - ultrahdr_metadata_ptr metadata, jr_uncompressed_ptr map); - void BenchmarkApplyGainMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr map, - ultrahdr_metadata_ptr metadata, jr_uncompressed_ptr dest); -private: - const int kProfileCount = 10; -}; - -void JpegRBenchmark::BenchmarkGenerateGainMap(jr_uncompressed_ptr yuv420Image, - jr_uncompressed_ptr p010Image, - ultrahdr_metadata_ptr metadata, - jr_uncompressed_ptr map) { - ASSERT_EQ(yuv420Image->width, p010Image->width); - ASSERT_EQ(yuv420Image->height, p010Image->height); +jr_uncompressed_ptr UhdrUnCompressedStructWrapper::getImageHandle() { + return &mImg; +} - Timer genRecMapTime; +UhdrCompressedStructWrapper::UhdrCompressedStructWrapper(uint32_t width, uint32_t height) { + mWidth = width; + mHeight = height; +} - timerStart(&genRecMapTime); - for (auto i = 0; i < kProfileCount; i++) { - ASSERT_EQ(OK, generateGainMap( - yuv420Image, p010Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, metadata, map)); - if (i != kProfileCount - 1) delete[] static_cast(map->data); +bool UhdrCompressedStructWrapper::allocateMemory() { + if (mWidth == 0 || (mWidth % 2 != 0) || mHeight == 0 || (mHeight % 2 != 0)) { + std::cerr << "Object in bad state, mem alloc failed" << std::endl; + return false; } - timerStop(&genRecMapTime); - - ALOGE("Generate Gain Map:- Res = %i x %i, time = %f ms", - yuv420Image->width, yuv420Image->height, - elapsedTime(&genRecMapTime) / (kProfileCount * 1000.f)); - + int maxLength = std::max(8 * 1024 /* min size 8kb */, (int)(mWidth * mHeight * 3 * 2)); + mData = std::make_unique(maxLength); + mImg.data = mData.get(); + mImg.length = 0; + mImg.maxLength = maxLength; + return true; } -void JpegRBenchmark::BenchmarkApplyGainMap(jr_uncompressed_ptr yuv420Image, - jr_uncompressed_ptr map, - ultrahdr_metadata_ptr metadata, - jr_uncompressed_ptr dest) { - Timer applyRecMapTime; +jr_compressed_ptr UhdrCompressedStructWrapper::getImageHandle() { + return &mImg; +} - timerStart(&applyRecMapTime); - for (auto i = 0; i < kProfileCount; i++) { - ASSERT_EQ(OK, applyGainMap(yuv420Image, map, metadata, ULTRAHDR_OUTPUT_HDR_HLG, - metadata->maxContentBoost /* displayBoost */, dest)); +static bool writeFile(const char* filename, void*& result, int length) { + std::ofstream ofd(filename, std::ios::binary); + if (ofd.is_open()) { + ofd.write(static_cast(result), length); + return true; } - timerStop(&applyRecMapTime); - - ALOGE("Apply Gain Map:- Res = %i x %i, time = %f ms", - yuv420Image->width, yuv420Image->height, - elapsedTime(&applyRecMapTime) / (kProfileCount * 1000.f)); + std::cerr << "unable to write to file : " << filename << std::endl; + return false; } -TEST_F(JpegRTest, build) { - // Force all of the gain map lib to be linked by calling all public functions. - JpegR jpegRCodec; - jpegRCodec.encodeJPEGR(nullptr, static_cast(0), nullptr, 0, nullptr); - jpegRCodec.encodeJPEGR(nullptr, nullptr, static_cast(0), - nullptr, 0, nullptr); - jpegRCodec.encodeJPEGR(nullptr, nullptr, nullptr, static_cast(0), - nullptr); - jpegRCodec.encodeJPEGR(nullptr, nullptr, static_cast(0), nullptr); - jpegRCodec.decodeJPEGR(nullptr, nullptr); +static bool readFile(const char* fileName, void*& result, int maxLength, int& length) { + std::ifstream ifd(fileName, std::ios::binary | std::ios::ate); + if (ifd.good()) { + length = ifd.tellg(); + if (length > maxLength) { + std::cerr << "not enough space to read file" << std::endl; + return false; + } + ifd.seekg(0, std::ios::beg); + ifd.read(static_cast(result), length); + return true; + } + std::cerr << "unable to read file : " << fileName << std::endl; + return false; } -/* Test Encode API-0 invalid arguments */ -TEST_F(JpegRTest, encodeAPI0ForInvalidArgs) { - int ret; - - // we are not really compressing anything so lets keep allocs to a minimum - jpegr_compressed_struct jpegR; - jpegR.maxLength = 16 * sizeof(uint8_t); - jpegR.data = malloc(jpegR.maxLength); - - JpegR jpegRCodec; - - // we are not really compressing anything so lets keep allocs to a minimum - mRawP010ImageWithStride.data = malloc(16); - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_STRIDE; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - - // test quality factor - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - -1, nullptr)) << "fail, API allows bad jpeg quality factor"; - - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - 101, nullptr)) << "fail, API allows bad jpeg quality factor"; - - // test hdr transfer function - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad hdr transfer function"; - - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, - static_cast(ultrahdr_transfer_function::ULTRAHDR_TF_MAX + 1), - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad hdr transfer function"; +void decodeJpegRImg(jr_compressed_ptr img, [[maybe_unused]] const char* outFileName) { + std::vector iccData(0); + std::vector exifData(0); + jpegr_info_struct info{0, 0, &iccData, &exifData}; + JpegR jpegHdr; + ASSERT_EQ(OK, jpegHdr.getJPEGRInfo(img, &info)); + ASSERT_EQ(kImageWidth, info.width); + ASSERT_EQ(kImageHeight, info.height); + size_t outSize = info.width * info.height * 8; + std::unique_ptr data = std::make_unique(outSize); + jpegr_uncompressed_struct destImage{}; + destImage.data = data.get(); + ASSERT_EQ(OK, jpegHdr.decodeJPEGR(img, &destImage)); + ASSERT_EQ(kImageWidth, destImage.width); + ASSERT_EQ(kImageHeight, destImage.height); +#ifdef DUMP_OUTPUT + if (!writeFile(outFileName, destImage.data, outSize)) { + std::cerr << "unable to write output file" << std::endl; + } +#endif +} - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, - static_cast(-10), - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad hdr transfer function"; +// ============================================================================ +// Unit Tests +// ============================================================================ + +// Test Encode API-0 invalid arguments +TEST(JpegRTest, EncodeAPI0WithInvalidArgs) { + JpegR uHdrLib; + + UhdrCompressedStructWrapper jpgImg(16, 16); + ASSERT_TRUE(jpgImg.allocateMemory()); + + // test quality factor and transfer function + { + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), -1, nullptr), + OK) + << "fail, API allows bad jpeg quality factor"; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), 101, nullptr), + OK) + << "fail, API allows bad jpeg quality factor"; + + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad hdr transfer function"; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), + static_cast( + ultrahdr_transfer_function::ULTRAHDR_TF_MAX + 1), + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad hdr transfer function"; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), + static_cast(-10), + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad hdr transfer function"; + } // test dest - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, nullptr, - DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows nullptr dest"; + { + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, nullptr, kQuality, + nullptr), + OK) + << "fail, API allows nullptr dest"; + UhdrCompressedStructWrapper jpgImg2(16, 16); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows nullptr dest"; + } // test p010 input - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - nullptr, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows nullptr p010 image"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad p010 color gamut"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.colorGamut = static_cast( - ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1); - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad p010 color gamut"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH - 1; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad image width"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT - 1; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad image height"; - - mRawP010ImageWithStride.width = 0; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad image width"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = 0; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad image height"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_WIDTH - 2; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad luma stride"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_STRIDE; - mRawP010ImageWithStride.chroma_data = mRawP010ImageWithStride.data; - mRawP010ImageWithStride.chroma_stride = TEST_IMAGE_WIDTH - 2; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad chroma stride"; - - mRawP010ImageWithStride.chroma_data = nullptr; - - free(jpegR.data); + { + ASSERT_NE(uHdrLib.encodeJPEGR(nullptr, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows nullptr p010 image"; + + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows nullptr p010 image"; + } + + { + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED)); + ASSERT_TRUE(rawImg.allocateMemory()); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad p010 color gamut"; + + UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg2.setImageColorGamut( + static_cast(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1))); + ASSERT_TRUE(rawImg2.allocateMemory()); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad p010 color gamut"; + } + + { + const int kWidth = 32, kHeight = 32; + UhdrUnCompressedStructWrapper rawImg(kWidth, kHeight, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + auto rawImgP010 = rawImg.getImageHandle(); + + rawImgP010->width = kWidth - 1; + rawImgP010->height = kHeight; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad image width"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight - 1; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad image height"; + + rawImgP010->width = 0; + rawImgP010->height = kHeight; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad image width"; + + rawImgP010->width = kWidth; + rawImgP010->height = 0; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad image height"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->luma_stride = kWidth - 2; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad luma stride"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->luma_stride = kWidth + 64; + rawImgP010->chroma_data = rawImgP010->data; + rawImgP010->chroma_stride = kWidth - 2; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad chroma stride"; + } } /* Test Encode API-1 invalid arguments */ -TEST_F(JpegRTest, encodeAPI1ForInvalidArgs) { - int ret; - - // we are not really compressing anything so lets keep allocs to a minimum - jpegr_compressed_struct jpegR; - jpegR.maxLength = 16 * sizeof(uint8_t); - jpegR.data = malloc(jpegR.maxLength); - - JpegR jpegRCodec; - - // we are not really compressing anything so lets keep allocs to a minimum - mRawP010ImageWithStride.data = malloc(16); - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_STRIDE; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - - // we are not really compressing anything so lets keep allocs to a minimum - mRawYuv420Image.data = malloc(16); - mRawYuv420Image.width = TEST_IMAGE_WIDTH; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT; - mRawYuv420Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709; - - // test quality factor - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, -1, nullptr)) << "fail, API allows bad jpeg quality factor"; - - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, 101, nullptr)) << "fail, API allows bad jpeg quality factor"; - - // test hdr transfer function - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, - ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED, &jpegR, DEFAULT_JPEG_QUALITY, - nullptr)) << "fail, API allows bad hdr transfer function"; - - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, - static_cast(ultrahdr_transfer_function::ULTRAHDR_TF_MAX + 1), - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad hdr transfer function"; - - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, - static_cast(-10), - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad hdr transfer function"; +TEST(JpegRTest, EncodeAPI1WithInvalidArgs) { + JpegR uHdrLib; + + UhdrCompressedStructWrapper jpgImg(16, 16); + ASSERT_TRUE(jpgImg.allocateMemory()); + + // test quality factor and transfer function + { + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2.allocateMemory()); + + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), -1, nullptr), + OK) + << "fail, API allows bad jpeg quality factor"; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), 101, nullptr), + OK) + << "fail, API allows bad jpeg quality factor"; + + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad hdr transfer function"; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + static_cast( + ultrahdr_transfer_function::ULTRAHDR_TF_MAX + 1), + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad hdr transfer function"; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + static_cast(-10), + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad hdr transfer function"; + } // test dest - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - nullptr, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows nullptr dest"; + { + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2.allocateMemory()); + + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, nullptr, kQuality, + nullptr), + OK) + << "fail, API allows nullptr dest"; + UhdrCompressedStructWrapper jpgImg2(16, 16); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows nullptr dest"; + } // test p010 input - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - nullptr, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows nullptr p010 image"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad p010 color gamut"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.colorGamut = static_cast( - ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1); - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad p010 color gamut"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH - 1; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad image width"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT - 1; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad image height"; - - mRawP010ImageWithStride.width = 0; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad image width"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = 0; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad image height"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_WIDTH - 2; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad luma stride"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_STRIDE; - mRawP010ImageWithStride.chroma_data = mRawP010ImageWithStride.data; - mRawP010ImageWithStride.chroma_stride = TEST_IMAGE_WIDTH - 2; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad chroma stride"; + { + UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2.allocateMemory()); + ASSERT_NE(uHdrLib.encodeJPEGR(nullptr, rawImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows nullptr p010 image"; + + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows nullptr p010 image"; + } + + { + const int kWidth = 32, kHeight = 32; + UhdrUnCompressedStructWrapper rawImg(kWidth, kHeight, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + auto rawImgP010 = rawImg.getImageHandle(); + UhdrUnCompressedStructWrapper rawImg2(kWidth, kHeight, YCbCr_420); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2.allocateMemory()); + auto rawImg420 = rawImg2.getImageHandle(); + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad p010 color gamut"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->colorGamut = + static_cast(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad p010 color gamut"; + + rawImgP010->width = kWidth - 1; + rawImgP010->height = kHeight; + rawImgP010->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad image width"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight - 1; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad image height"; + + rawImgP010->width = 0; + rawImgP010->height = kHeight; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad image width"; + + rawImgP010->width = kWidth; + rawImgP010->height = 0; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad image height"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->luma_stride = kWidth - 2; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad luma stride"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->luma_stride = kWidth + 64; + rawImgP010->chroma_data = rawImgP010->data; + rawImgP010->chroma_stride = kWidth - 2; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad chroma stride"; + } // test 420 input - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_STRIDE; - mRawP010ImageWithStride.chroma_data = nullptr; - mRawP010ImageWithStride.chroma_stride = 0; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, nullptr, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows nullptr for 420 image"; - - mRawYuv420Image.width = TEST_IMAGE_WIDTH; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT - 2; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad 420 image width"; - - mRawYuv420Image.width = TEST_IMAGE_WIDTH - 2; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad 420 image height"; - - mRawYuv420Image.width = TEST_IMAGE_WIDTH; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT; - mRawYuv420Image.luma_stride = TEST_IMAGE_STRIDE; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad luma stride for 420"; - - mRawYuv420Image.width = TEST_IMAGE_WIDTH; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT; - mRawYuv420Image.luma_stride = 0; - mRawYuv420Image.chroma_data = mRawYuv420Image.data; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows chroma pointer for 420"; - - mRawYuv420Image.width = TEST_IMAGE_WIDTH; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT; - mRawYuv420Image.luma_stride = 0; - mRawYuv420Image.chroma_data = nullptr; - mRawYuv420Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad 420 color gamut"; - - mRawYuv420Image.colorGamut = static_cast( - ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1); - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR, DEFAULT_JPEG_QUALITY, nullptr)) << "fail, API allows bad 420 color gamut"; - - free(jpegR.data); + { + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), nullptr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows nullptr 420 image"; + + UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows nullptr 420 image"; + } + { + const int kWidth = 32, kHeight = 32; + UhdrUnCompressedStructWrapper rawImg(kWidth, kHeight, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + auto rawImgP010 = rawImg.getImageHandle(); + UhdrUnCompressedStructWrapper rawImg2(kWidth, kHeight, YCbCr_420); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2.allocateMemory()); + auto rawImg420 = rawImg2.getImageHandle(); + + rawImg420->width = kWidth; + rawImg420->height = kHeight; + rawImg420->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad 420 color gamut"; + + rawImg420->width = kWidth; + rawImg420->height = kHeight; + rawImg420->colorGamut = + static_cast(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad 420 color gamut"; + + rawImg420->width = kWidth - 1; + rawImg420->height = kHeight; + rawImg420->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad image width for 420"; + + rawImg420->width = kWidth; + rawImg420->height = kHeight - 1; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad image height for 420"; + + rawImg420->width = 0; + rawImg420->height = kHeight; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad image width for 420"; + + rawImg420->width = kWidth; + rawImg420->height = 0; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad image height for 420"; + + rawImg420->width = kWidth; + rawImg420->height = kHeight; + rawImg420->luma_stride = kWidth; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows luma stride for 420"; + + rawImg420->width = kWidth; + rawImg420->height = kHeight; + rawImg420->luma_stride = 0; + rawImg420->chroma_data = rawImgP010->data; + rawImg420->chroma_stride = kWidth; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK) + << "fail, API allows bad chroma pointer for 420"; + } } /* Test Encode API-2 invalid arguments */ -TEST_F(JpegRTest, encodeAPI2ForInvalidArgs) { - int ret; - - // we are not really compressing anything so lets keep allocs to a minimum - jpegr_compressed_struct jpegR; - jpegR.maxLength = 16 * sizeof(uint8_t); - jpegR.data = malloc(jpegR.maxLength); - - JpegR jpegRCodec; - - // we are not really compressing anything so lets keep allocs to a minimum - mRawP010ImageWithStride.data = malloc(16); - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_STRIDE; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - - // we are not really compressing anything so lets keep allocs to a minimum - mRawYuv420Image.data = malloc(16); - mRawYuv420Image.width = TEST_IMAGE_WIDTH; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT; - mRawYuv420Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709; - - // test hdr transfer function - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED, - &jpegR)) << "fail, API allows bad hdr transfer function"; - - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - static_cast(ultrahdr_transfer_function::ULTRAHDR_TF_MAX + 1), - &jpegR)) << "fail, API allows bad hdr transfer function"; - - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - static_cast(-10), - &jpegR)) << "fail, API allows bad hdr transfer function"; +TEST(JpegRTest, EncodeAPI2WithInvalidArgs) { + JpegR uHdrLib; + + UhdrCompressedStructWrapper jpgImg(16, 16); + ASSERT_TRUE(jpgImg.allocateMemory()); + + // test quality factor and transfer function + { + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2.allocateMemory()); + + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad hdr transfer function"; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + jpgImg.getImageHandle(), + static_cast( + ultrahdr_transfer_function::ULTRAHDR_TF_MAX + 1), + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad hdr transfer function"; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + jpgImg.getImageHandle(), + static_cast(-10), + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad hdr transfer function"; + } // test dest - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, nullptr)) << "fail, API allows nullptr dest"; + { + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2.allocateMemory()); + + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, nullptr), + OK) + << "fail, API allows nullptr dest"; + UhdrCompressedStructWrapper jpgImg2(16, 16); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle()), + OK) + << "fail, API allows nullptr dest"; + } + + // test compressed image + { + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2.allocateMemory()); + + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), nullptr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr for compressed image"; + UhdrCompressedStructWrapper jpgImg2(16, 16); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + jpgImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr for compressed image"; + } // test p010 input - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - nullptr, &mRawYuv420Image, &jpegR, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows nullptr p010 image"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad p010 color gamut"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.colorGamut = static_cast( - ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1); - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad p010 color gamut"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH - 1; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR)) << "fail, API allows bad image width"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT - 1; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR)) << "fail, API allows bad image height"; - - mRawP010ImageWithStride.width = 0; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR)) << "fail, API allows bad image width"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = 0; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR)) << "fail, API allows bad image height"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_WIDTH - 2; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR)) << "fail, API allows bad luma stride"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_STRIDE; - mRawP010ImageWithStride.chroma_data = mRawP010ImageWithStride.data; - mRawP010ImageWithStride.chroma_stride = TEST_IMAGE_WIDTH - 2; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad chroma stride"; + { + UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2.allocateMemory()); + ASSERT_NE(uHdrLib.encodeJPEGR(nullptr, rawImg2.getImageHandle(), jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr p010 image"; + + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr p010 image"; + } + + { + const int kWidth = 32, kHeight = 32; + UhdrUnCompressedStructWrapper rawImg(kWidth, kHeight, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + auto rawImgP010 = rawImg.getImageHandle(); + UhdrUnCompressedStructWrapper rawImg2(kWidth, kHeight, YCbCr_420); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2.allocateMemory()); + auto rawImg420 = rawImg2.getImageHandle(); + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad p010 color gamut"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->colorGamut = + static_cast(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad p010 color gamut"; + + rawImgP010->width = kWidth - 1; + rawImgP010->height = kHeight; + rawImgP010->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad image width"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight - 1; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad image height"; + + rawImgP010->width = 0; + rawImgP010->height = kHeight; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad image width"; + + rawImgP010->width = kWidth; + rawImgP010->height = 0; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad image height"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->luma_stride = kWidth - 2; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad luma stride"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->luma_stride = kWidth + 64; + rawImgP010->chroma_data = rawImgP010->data; + rawImgP010->chroma_stride = kWidth - 2; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad chroma stride"; + } // test 420 input - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_STRIDE; - mRawP010ImageWithStride.chroma_data = nullptr; - mRawP010ImageWithStride.chroma_stride = 0; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, nullptr, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows nullptr for 420 image"; - - mRawYuv420Image.width = TEST_IMAGE_WIDTH; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT - 2; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad 420 image width"; - - mRawYuv420Image.width = TEST_IMAGE_WIDTH - 2; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad 420 image height"; - - mRawYuv420Image.width = TEST_IMAGE_WIDTH; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT; - mRawYuv420Image.luma_stride = TEST_IMAGE_STRIDE; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad luma stride for 420"; - - mRawYuv420Image.width = TEST_IMAGE_WIDTH; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT; - mRawYuv420Image.luma_stride = 0; - mRawYuv420Image.chroma_data = mRawYuv420Image.data; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows chroma pointer for 420"; - - mRawYuv420Image.width = TEST_IMAGE_WIDTH; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT; - mRawYuv420Image.luma_stride = 0; - mRawYuv420Image.chroma_data = nullptr; - mRawYuv420Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad 420 color gamut"; - - mRawYuv420Image.colorGamut = static_cast( - ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1); - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, &jpegR, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad 420 color gamut"; - - // bad compressed image - mRawYuv420Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &mRawYuv420Image, nullptr, - ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad 420 color gamut"; - - free(jpegR.data); + { + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), nullptr, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr 420 image"; + + UhdrUnCompressedStructWrapper rawImg2(16, 16, YCbCr_420); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), rawImg2.getImageHandle(), + jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr 420 image"; + } + { + const int kWidth = 32, kHeight = 32; + UhdrUnCompressedStructWrapper rawImg(kWidth, kHeight, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + auto rawImgP010 = rawImg.getImageHandle(); + UhdrUnCompressedStructWrapper rawImg2(kWidth, kHeight, YCbCr_420); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2.allocateMemory()); + auto rawImg420 = rawImg2.getImageHandle(); + + rawImg420->width = kWidth; + rawImg420->height = kHeight; + rawImg420->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad 420 color gamut"; + + rawImg420->width = kWidth; + rawImg420->height = kHeight; + rawImg420->colorGamut = + static_cast(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad 420 color gamut"; + + rawImg420->width = kWidth - 1; + rawImg420->height = kHeight; + rawImg420->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad image width for 420"; + + rawImg420->width = kWidth; + rawImg420->height = kHeight - 1; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad image height for 420"; + + rawImg420->width = 0; + rawImg420->height = kHeight; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad image width for 420"; + + rawImg420->width = kWidth; + rawImg420->height = 0; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad image height for 420"; + + rawImg420->width = kWidth; + rawImg420->height = kHeight; + rawImg420->luma_stride = kWidth; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows luma stride for 420"; + + rawImg420->width = kWidth; + rawImg420->height = kHeight; + rawImg420->luma_stride = 0; + rawImg420->chroma_data = rawImgP010->data; + rawImg420->chroma_stride = kWidth; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad chroma pointer for 420"; + } } /* Test Encode API-3 invalid arguments */ -TEST_F(JpegRTest, encodeAPI3ForInvalidArgs) { - int ret; - - // we are not really compressing anything so lets keep allocs to a minimum - jpegr_compressed_struct jpegR; - jpegR.maxLength = 16 * sizeof(uint8_t); - jpegR.data = malloc(jpegR.maxLength); - - JpegR jpegRCodec; - - // we are not really compressing anything so lets keep allocs to a minimum - mRawP010ImageWithStride.data = malloc(16); - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_STRIDE; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - - // test hdr transfer function - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &jpegR, ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED, - &jpegR)) << "fail, API allows bad hdr transfer function"; - - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &jpegR, - static_cast(ultrahdr_transfer_function::ULTRAHDR_TF_MAX + 1), - &jpegR)) << "fail, API allows bad hdr transfer function"; - - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &jpegR, static_cast(-10), - &jpegR)) << "fail, API allows bad hdr transfer function"; +TEST(JpegRTest, EncodeAPI3WithInvalidArgs) { + JpegR uHdrLib; + + UhdrCompressedStructWrapper jpgImg(16, 16); + ASSERT_TRUE(jpgImg.allocateMemory()); + + // test quality factor and transfer function + { + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_UNSPECIFIED, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad hdr transfer function"; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg.getImageHandle(), + static_cast( + ultrahdr_transfer_function::ULTRAHDR_TF_MAX + 1), + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad hdr transfer function"; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg.getImageHandle(), + static_cast(-10), + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad hdr transfer function"; + } // test dest - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &jpegR, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - nullptr)) << "fail, API allows nullptr dest"; + { + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, nullptr), + OK) + << "fail, API allows nullptr dest"; + UhdrCompressedStructWrapper jpgImg2(16, 16); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle()), + OK) + << "fail, API allows nullptr dest"; + } + + // test compressed image + { + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), nullptr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr for compressed image"; + UhdrCompressedStructWrapper jpgImg2(16, 16); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr for compressed image"; + } // test p010 input - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - nullptr, &jpegR, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows nullptr p010 image"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &jpegR, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad p010 color gamut"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.colorGamut = static_cast( - ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1); - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &jpegR, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad p010 color gamut"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH - 1; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &jpegR, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad image width"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT - 1; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &jpegR, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad image height"; - - mRawP010ImageWithStride.width = 0; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &jpegR, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad image width"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = 0; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &jpegR, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad image height"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_WIDTH - 2; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &jpegR, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad luma stride"; - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_STRIDE; - mRawP010ImageWithStride.chroma_data = mRawP010ImageWithStride.data; - mRawP010ImageWithStride.chroma_stride = TEST_IMAGE_WIDTH - 2; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, &jpegR, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad chroma stride"; - mRawP010ImageWithStride.chroma_data = nullptr; - - // bad compressed image - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, nullptr, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR)) << "fail, API allows bad 420 color gamut"; - - free(jpegR.data); + { + ASSERT_NE(uHdrLib.encodeJPEGR(nullptr, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr p010 image"; + + UhdrUnCompressedStructWrapper rawImg(16, 16, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr p010 image"; + } + + { + const int kWidth = 32, kHeight = 32; + UhdrUnCompressedStructWrapper rawImg(kWidth, kHeight, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + auto rawImgP010 = rawImg.getImageHandle(); + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_UNSPECIFIED; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad p010 color gamut"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->colorGamut = + static_cast(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_MAX + 1); + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad p010 color gamut"; + + rawImgP010->width = kWidth - 1; + rawImgP010->height = kHeight; + rawImgP010->colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad image width"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight - 1; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad image height"; + + rawImgP010->width = 0; + rawImgP010->height = kHeight; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad image width"; + + rawImgP010->width = kWidth; + rawImgP010->height = 0; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad image height"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->luma_stride = kWidth - 2; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad luma stride"; + + rawImgP010->width = kWidth; + rawImgP010->height = kHeight; + rawImgP010->luma_stride = kWidth + 64; + rawImgP010->chroma_data = rawImgP010->data; + rawImgP010->chroma_stride = kWidth - 2; + ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, jpgImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad chroma stride"; + } } /* Test Encode API-4 invalid arguments */ -TEST_F(JpegRTest, encodeAPI4ForInvalidArgs) { - int ret; - - // we are not really compressing anything so lets keep allocs to a minimum - jpegr_compressed_struct jpegR; - jpegR.maxLength = 16 * sizeof(uint8_t); - jpegR.data = malloc(jpegR.maxLength); - - JpegR jpegRCodec; +TEST(JpegRTest, EncodeAPI4WithInvalidArgs) { + UhdrCompressedStructWrapper jpgImg(16, 16); + ASSERT_TRUE(jpgImg.allocateMemory()); + UhdrCompressedStructWrapper jpgImg2(16, 16); + JpegR uHdrLib; // test dest - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &jpegR, &jpegR, nullptr, nullptr)) << "fail, API allows nullptr dest"; + ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), nullptr, nullptr), + OK) + << "fail, API allows nullptr dest"; + ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), nullptr, + jpgImg2.getImageHandle()), + OK) + << "fail, API allows nullptr dest"; // test primary image - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - nullptr, &jpegR, nullptr, &jpegR)) << "fail, API allows nullptr primary image"; + ASSERT_NE(uHdrLib.encodeJPEGR(nullptr, jpgImg.getImageHandle(), nullptr, jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr primary image"; + ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg2.getImageHandle(), jpgImg.getImageHandle(), nullptr, + jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr primary image"; // test gain map - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &jpegR, nullptr, nullptr, &jpegR)) << "fail, API allows nullptr gainmap image"; + ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), nullptr, nullptr, jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr gain map image"; + ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg2.getImageHandle(), nullptr, + jpgImg.getImageHandle()), + OK) + << "fail, API allows nullptr gain map image"; // test metadata ultrahdr_metadata_struct good_metadata; @@ -832,82 +1254,95 @@ TEST_F(JpegRTest, encodeAPI4ForInvalidArgs) { ultrahdr_metadata_struct metadata = good_metadata; metadata.version = "1.1"; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata version"; + ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad metadata version"; metadata = good_metadata; metadata.minContentBoost = 3.0f; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata content boost"; + ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad metadata content boost"; metadata = good_metadata; metadata.gamma = -0.1f; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata gamma"; + ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad metadata gamma"; metadata = good_metadata; metadata.offsetSdr = -0.1f; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata offset sdr"; + ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad metadata offset sdr"; metadata = good_metadata; metadata.offsetHdr = -0.1f; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata offset hdr"; + ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad metadata offset hdr"; metadata = good_metadata; metadata.hdrCapacityMax = 0.5f; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata hdr capacity max"; + ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad metadata hdr capacity max"; metadata = good_metadata; metadata.hdrCapacityMin = 0.5f; - EXPECT_NE(OK, jpegRCodec.encodeJPEGR( - &jpegR, nullptr, &metadata, &jpegR)) << "fail, API allows bad metadata hdr capacity min"; - - free(jpegR.data); + ASSERT_NE(uHdrLib.encodeJPEGR(jpgImg.getImageHandle(), jpgImg.getImageHandle(), &metadata, + jpgImg.getImageHandle()), + OK) + << "fail, API allows bad metadata hdr capacity min"; } /* Test Decode API invalid arguments */ -TEST_F(JpegRTest, decodeAPIForInvalidArgs) { - int ret; - - // we are not really compressing anything so lets keep allocs to a minimum - jpegr_compressed_struct jpegR; - jpegR.maxLength = 16 * sizeof(uint8_t); - jpegR.data = malloc(jpegR.maxLength); +TEST(JpegRTest, DecodeAPIWithInvalidArgs) { + JpegR uHdrLib; - // we are not really decoding anything so lets keep allocs to a minimum - mRawP010Image.data = malloc(16); - - JpegR jpegRCodec; + UhdrCompressedStructWrapper jpgImg(16, 16); + jpegr_uncompressed_struct destImage{}; + size_t outSize = 16 * 16 * 8; + std::unique_ptr data = std::make_unique(outSize); + destImage.data = data.get(); // test jpegr image - EXPECT_NE(OK, jpegRCodec.decodeJPEGR( - nullptr, &mRawP010Image)) << "fail, API allows nullptr for jpegr img"; + ASSERT_NE(uHdrLib.decodeJPEGR(nullptr, &destImage), OK) + << "fail, API allows nullptr for jpegr img"; + ASSERT_NE(uHdrLib.decodeJPEGR(jpgImg.getImageHandle(), &destImage), OK) + << "fail, API allows nullptr for jpegr img"; + ASSERT_TRUE(jpgImg.allocateMemory()); // test dest image - EXPECT_NE(OK, jpegRCodec.decodeJPEGR( - &jpegR, nullptr)) << "fail, API allows nullptr for dest"; + ASSERT_NE(uHdrLib.decodeJPEGR(jpgImg.getImageHandle(), nullptr), OK) + << "fail, API allows nullptr for dest"; + destImage.data = nullptr; + ASSERT_NE(uHdrLib.decodeJPEGR(jpgImg.getImageHandle(), &destImage), OK) + << "fail, API allows nullptr for dest"; + destImage.data = data.get(); // test max display boost - EXPECT_NE(OK, jpegRCodec.decodeJPEGR( - &jpegR, &mRawP010Image, 0.5)) << "fail, API allows invalid max display boost"; + ASSERT_NE(uHdrLib.decodeJPEGR(jpgImg.getImageHandle(), &destImage, 0.5), OK) + << "fail, API allows invalid max display boost"; // test output format - EXPECT_NE(OK, jpegRCodec.decodeJPEGR( - &jpegR, &mRawP010Image, 0.5, nullptr, - static_cast(-1))) << "fail, API allows invalid output format"; - - EXPECT_NE(OK, jpegRCodec.decodeJPEGR( - &jpegR, &mRawP010Image, 0.5, nullptr, - static_cast(ULTRAHDR_OUTPUT_MAX + 1))) - << "fail, API allows invalid output format"; - - free(jpegR.data); + ASSERT_NE(uHdrLib.decodeJPEGR(jpgImg.getImageHandle(), &destImage, FLT_MAX, nullptr, + static_cast(-1)), + OK) + << "fail, API allows invalid output format"; + ASSERT_NE(uHdrLib.decodeJPEGR(jpgImg.getImageHandle(), &destImage, FLT_MAX, nullptr, + static_cast(ULTRAHDR_OUTPUT_MAX + 1)), + OK) + << "fail, API allows invalid output format"; } -TEST_F(JpegRTest, writeXmpThenRead) { +TEST(JpegRTest, writeXmpThenRead) { ultrahdr_metadata_struct metadata_expected; metadata_expected.version = "1.0"; metadata_expected.maxContentBoost = 1.25f; @@ -918,16 +1353,16 @@ TEST_F(JpegRTest, writeXmpThenRead) { metadata_expected.hdrCapacityMin = 1.0f; metadata_expected.hdrCapacityMax = metadata_expected.maxContentBoost; const std::string nameSpace = "http://ns.adobe.com/xap/1.0/\0"; - const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator + const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator std::string xmp = generateXmpForSecondaryImage(metadata_expected); std::vector xmpData; xmpData.reserve(nameSpaceLength + xmp.size()); xmpData.insert(xmpData.end(), reinterpret_cast(nameSpace.c_str()), - reinterpret_cast(nameSpace.c_str()) + nameSpaceLength); + reinterpret_cast(nameSpace.c_str()) + nameSpaceLength); xmpData.insert(xmpData.end(), reinterpret_cast(xmp.c_str()), - reinterpret_cast(xmp.c_str()) + xmp.size()); + reinterpret_cast(xmp.c_str()) + xmp.size()); ultrahdr_metadata_struct metadata_read; EXPECT_TRUE(getMetadataFromXMP(xmpData.data(), xmpData.size(), &metadata_read)); @@ -940,436 +1375,441 @@ TEST_F(JpegRTest, writeXmpThenRead) { EXPECT_FLOAT_EQ(metadata_expected.hdrCapacityMax, metadata_read.hdrCapacityMax); } -/* Test Encode API-0 */ -TEST_F(JpegRTest, encodeFromP010) { - int ret; - - mRawP010Image.width = TEST_IMAGE_WIDTH; - mRawP010Image.height = TEST_IMAGE_HEIGHT; - mRawP010Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - // Load input files. - if (!loadP010Image(RAW_P010_IMAGE, &mRawP010Image, true)) { - FAIL() << "Load file " << RAW_P010_IMAGE << " failed"; - } - - JpegR jpegRCodec; - - jpegr_compressed_struct jpegR; - jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t); - jpegR.data = malloc(jpegR.maxLength); - ret = jpegRCodec.encodeJPEGR( - &mRawP010Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, DEFAULT_JPEG_QUALITY, - nullptr); - if (ret != OK) { - FAIL() << "Error code is " << ret; - } - - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_WIDTH + 128; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - // Load input files. - if (!loadP010Image(RAW_P010_IMAGE, &mRawP010ImageWithStride, true)) { - FAIL() << "Load file " << RAW_P010_IMAGE << " failed"; - } - - jpegr_compressed_struct jpegRWithStride; - jpegRWithStride.maxLength = jpegR.length; - jpegRWithStride.data = malloc(jpegRWithStride.maxLength); - ret = jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegRWithStride, - DEFAULT_JPEG_QUALITY, nullptr); - if (ret != OK) { - FAIL() << "Error code is " << ret; - } - ASSERT_EQ(jpegR.length, jpegRWithStride.length) - << "Same input is yielding different output"; - ASSERT_EQ(0, memcmp(jpegR.data, jpegRWithStride.data, jpegR.length)) - << "Same input is yielding different output"; - - mRawP010ImageWithChromaData.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithChromaData.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithChromaData.luma_stride = TEST_IMAGE_WIDTH + 64; - mRawP010ImageWithChromaData.chroma_stride = TEST_IMAGE_WIDTH + 256; - mRawP010ImageWithChromaData.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - // Load input files. - if (!loadP010Image(RAW_P010_IMAGE, &mRawP010ImageWithChromaData, false)) { - FAIL() << "Load file " << RAW_P010_IMAGE << " failed"; - } - jpegr_compressed_struct jpegRWithChromaData; - jpegRWithChromaData.maxLength = jpegR.length; - jpegRWithChromaData.data = malloc(jpegRWithChromaData.maxLength); - ret = jpegRCodec.encodeJPEGR( - &mRawP010ImageWithChromaData, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegRWithChromaData, DEFAULT_JPEG_QUALITY, nullptr); - if (ret != OK) { - FAIL() << "Error code is " << ret; - } - ASSERT_EQ(jpegR.length, jpegRWithChromaData.length) - << "Same input is yielding different output"; - ASSERT_EQ(0, memcmp(jpegR.data, jpegRWithChromaData.data, jpegR.length)) - << "Same input is yielding different output"; - - free(jpegR.data); - free(jpegRWithStride.data); - free(jpegRWithChromaData.data); -} - -/* Test Encode API-0 and decode */ -TEST_F(JpegRTest, encodeFromP010ThenDecode) { - int ret; - - // Load input files. - if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) { - FAIL() << "Load file " << RAW_P010_IMAGE << " failed"; +/* Test Encode API-0 and Decode */ +TEST(JpegRTest, EncodeAPI0AndDecodeTest) { + // reference encode + UhdrUnCompressedStructWrapper rawImg(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.allocateMemory()); + ASSERT_TRUE(rawImg.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg.allocateMemory()); + JpegR uHdrLib; + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK); + // encode with luma stride set + { + UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2.setImageStride(kImageWidth + 128, 0)); + ASSERT_TRUE(rawImg2.allocateMemory()); + ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - mRawP010Image.width = TEST_IMAGE_WIDTH; - mRawP010Image.height = TEST_IMAGE_HEIGHT; - mRawP010Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - - JpegR jpegRCodec; - - jpegr_compressed_struct jpegR; - jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t); - jpegR.data = malloc(jpegR.maxLength); - ret = jpegRCodec.encodeJPEGR( - &mRawP010Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, DEFAULT_JPEG_QUALITY, - nullptr); - if (ret != OK) { - FAIL() << "Error code is " << ret; + // encode with luma and chroma stride set + { + UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2.setImageStride(kImageWidth + 128, kImageWidth + 256)); + ASSERT_TRUE(rawImg2.setChromaMode(false)); + ASSERT_TRUE(rawImg2.allocateMemory()); + ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - if (SAVE_ENCODING_RESULT) { - // Output image data to file - std::string filePath = "/sdcard/Documents/encoded_from_p010_input.jpgr"; - std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); - if (!imageFile.is_open()) { - ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); - } - imageFile.write((const char*)jpegR.data, jpegR.length); + // encode with chroma stride set + { + UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2.setImageStride(0, kImageWidth + 64)); + ASSERT_TRUE(rawImg2.setChromaMode(false)); + ASSERT_TRUE(rawImg2.allocateMemory()); + ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - jpegr_uncompressed_struct decodedJpegR; - int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8; - decodedJpegR.data = malloc(decodedJpegRSize); - ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR); - if (ret != OK) { - FAIL() << "Error code is " << ret; - } - if (SAVE_DECODING_RESULT) { - // Output image data to file - std::string filePath = "/sdcard/Documents/decoded_from_p010_input.rgb"; - std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); - if (!imageFile.is_open()) { - ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); - } - imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize); + auto jpg1 = jpgImg.getImageHandle(); +#ifdef DUMP_OUTPUT + if (!writeFile("encode_api0_output.jpeg", jpg1->data, jpg1->length)) { + std::cerr << "unable to write output file" << std::endl; } +#endif - free(jpegR.data); - free(decodedJpegR.data); + ASSERT_NO_FATAL_FAILURE(decodeJpegRImg(jpg1, "decode_api0_output.rgb")); } -/* Test Encode API-0 (with stride) and decode */ -TEST_F(JpegRTest, encodeFromP010WithStrideThenDecode) { - int ret; - - // Load input files. - if (!loadFile(RAW_P010_IMAGE_WITH_STRIDE, mRawP010ImageWithStride.data, nullptr)) { - FAIL() << "Load file " << RAW_P010_IMAGE_WITH_STRIDE << " failed"; +/* Test Encode API-1 and Decode */ +TEST(JpegRTest, EncodeAPI1AndDecodeTest) { + UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImgP010.allocateMemory()); + ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName)); + UhdrUnCompressedStructWrapper rawImg420(kImageWidth, kImageHeight, YCbCr_420); + ASSERT_TRUE(rawImg420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg420.allocateMemory()); + ASSERT_TRUE(rawImg420.loadRawResource(kYCbCr420FileName)); + UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg.allocateMemory()); + JpegR uHdrLib; + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg420.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle(), kQuality, nullptr), + OK); + // encode with luma stride set + { + UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, 0)); + ASSERT_TRUE(rawImg2P010.allocateMemory()); + ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - mRawP010ImageWithStride.width = TEST_IMAGE_WIDTH; - mRawP010ImageWithStride.height = TEST_IMAGE_HEIGHT; - mRawP010ImageWithStride.luma_stride = TEST_IMAGE_STRIDE; - mRawP010ImageWithStride.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - - JpegR jpegRCodec; - - jpegr_compressed_struct jpegR; - jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t); - jpegR.data = malloc(jpegR.maxLength); - ret = jpegRCodec.encodeJPEGR( - &mRawP010ImageWithStride, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr); - if (ret != OK) { - FAIL() << "Error code is " << ret; + // encode with luma and chroma stride set + { + UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, kImageWidth + 256)); + ASSERT_TRUE(rawImg2P010.setChromaMode(false)); + ASSERT_TRUE(rawImg2P010.allocateMemory()); + ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - if (SAVE_ENCODING_RESULT) { - // Output image data to file - std::string filePath = "/sdcard/Documents/encoded_from_p010_input.jpgr"; - std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); - if (!imageFile.is_open()) { - ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); - } - imageFile.write((const char*)jpegR.data, jpegR.length); + // encode with chroma stride set + { + UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageStride(0, kImageWidth + 64)); + ASSERT_TRUE(rawImg2P010.setChromaMode(false)); + ASSERT_TRUE(rawImg2P010.allocateMemory()); + ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - jpegr_uncompressed_struct decodedJpegR; - int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8; - decodedJpegR.data = malloc(decodedJpegRSize); - ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR); - if (ret != OK) { - FAIL() << "Error code is " << ret; - } - if (SAVE_DECODING_RESULT) { - // Output image data to file - std::string filePath = "/sdcard/Documents/decoded_from_p010_input.rgb"; - std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); - if (!imageFile.is_open()) { - ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); - } - imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize); + auto jpg1 = jpgImg.getImageHandle(); + +#ifdef DUMP_OUTPUT + if (!writeFile("encode_api1_output.jpeg", jpg1->data, jpg1->length)) { + std::cerr << "unable to write output file" << std::endl; } +#endif - free(jpegR.data); - free(decodedJpegR.data); + ASSERT_NO_FATAL_FAILURE(decodeJpegRImg(jpg1, "decode_api1_output.rgb")); } -/* Test Encode API-1 and decode */ -TEST_F(JpegRTest, encodeFromRawHdrAndSdrThenDecode) { - int ret; - - // Load input files. - if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) { - FAIL() << "Load file " << RAW_P010_IMAGE << " failed"; +/* Test Encode API-2 and Decode */ +TEST(JpegRTest, EncodeAPI2AndDecodeTest) { + UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImgP010.allocateMemory()); + ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName)); + UhdrUnCompressedStructWrapper rawImg420(kImageWidth, kImageHeight, YCbCr_420); + ASSERT_TRUE(rawImg420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg420.allocateMemory()); + ASSERT_TRUE(rawImg420.loadRawResource(kYCbCr420FileName)); + UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg.allocateMemory()); + UhdrCompressedStructWrapper jpgSdr(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgSdr.allocateMemory()); + auto sdr = jpgSdr.getImageHandle(); + ASSERT_TRUE(readFile(kSdrJpgFileName, sdr->data, sdr->maxLength, sdr->length)); + JpegR uHdrLib; + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg420.getImageHandle(), sdr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK); + // encode with luma stride set + { + UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, 0)); + ASSERT_TRUE(rawImg2P010.allocateMemory()); + ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(), sdr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle()), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - mRawP010Image.width = TEST_IMAGE_WIDTH; - mRawP010Image.height = TEST_IMAGE_HEIGHT; - mRawP010Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - - if (!loadFile(RAW_YUV420_IMAGE, mRawYuv420Image.data, nullptr)) { - FAIL() << "Load file " << RAW_P010_IMAGE << " failed"; - } - mRawYuv420Image.width = TEST_IMAGE_WIDTH; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT; - mRawYuv420Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709; - - JpegR jpegRCodec; - - jpegr_compressed_struct jpegR; - jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t); - jpegR.data = malloc(jpegR.maxLength); - ret = jpegRCodec.encodeJPEGR( - &mRawP010Image, &mRawYuv420Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR, - DEFAULT_JPEG_QUALITY, nullptr); - if (ret != OK) { - FAIL() << "Error code is " << ret; + // encode with luma and chroma stride set + { + UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, kImageWidth + 256)); + ASSERT_TRUE(rawImg2P010.setChromaMode(false)); + ASSERT_TRUE(rawImg2P010.allocateMemory()); + ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(), sdr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle()), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - if (SAVE_ENCODING_RESULT) { - // Output image data to file - std::string filePath = "/sdcard/Documents/encoded_from_p010_yuv420p_input.jpgr"; - std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); - if (!imageFile.is_open()) { - ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); - } - imageFile.write((const char*)jpegR.data, jpegR.length); + // encode with chroma stride set + { + UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageStride(0, kImageWidth + 64)); + ASSERT_TRUE(rawImg2P010.setChromaMode(false)); + ASSERT_TRUE(rawImg2P010.allocateMemory()); + ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(), sdr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle()), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - jpegr_uncompressed_struct decodedJpegR; - int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8; - decodedJpegR.data = malloc(decodedJpegRSize); - ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR); - if (ret != OK) { - FAIL() << "Error code is " << ret; - } - if (SAVE_DECODING_RESULT) { - // Output image data to file - std::string filePath = "/sdcard/Documents/decoded_from_p010_yuv420p_input.rgb"; - std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); - if (!imageFile.is_open()) { - ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); - } - imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize); - } + auto jpg1 = jpgImg.getImageHandle(); - free(jpegR.data); - free(decodedJpegR.data); -} - -/* Test Encode API-2 and decode */ -TEST_F(JpegRTest, encodeFromRawHdrAndSdrAndJpegThenDecode) { - int ret; - - // Load input files. - if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) { - FAIL() << "Load file " << RAW_P010_IMAGE << " failed"; +#ifdef DUMP_OUTPUT + if (!writeFile("encode_api2_output.jpeg", jpg1->data, jpg1->length)) { + std::cerr << "unable to write output file" << std::endl; } - mRawP010Image.width = TEST_IMAGE_WIDTH; - mRawP010Image.height = TEST_IMAGE_HEIGHT; - mRawP010Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; +#endif - if (!loadFile(RAW_YUV420_IMAGE, mRawYuv420Image.data, nullptr)) { - FAIL() << "Load file " << RAW_P010_IMAGE << " failed"; - } - mRawYuv420Image.width = TEST_IMAGE_WIDTH; - mRawYuv420Image.height = TEST_IMAGE_HEIGHT; - mRawYuv420Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709; + ASSERT_NO_FATAL_FAILURE(decodeJpegRImg(jpg1, "decode_api2_output.rgb")); +} - if (!loadFile(JPEG_IMAGE, mJpegImage.data, &mJpegImage.length)) { - FAIL() << "Load file " << JPEG_IMAGE << " failed"; +/* Test Encode API-3 and Decode */ +TEST(JpegRTest, EncodeAPI3AndDecodeTest) { + UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImgP010.allocateMemory()); + ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg.allocateMemory()); + UhdrCompressedStructWrapper jpgSdr(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgSdr.allocateMemory()); + auto sdr = jpgSdr.getImageHandle(); + ASSERT_TRUE(readFile(kSdrJpgFileName, sdr->data, sdr->maxLength, sdr->length)); + JpegR uHdrLib; + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), sdr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg.getImageHandle()), + OK); + // encode with luma stride set + { + UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, 0)); + ASSERT_TRUE(rawImg2P010.allocateMemory()); + ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), sdr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle()), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - mJpegImage.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709; - - JpegR jpegRCodec; - - jpegr_compressed_struct jpegR; - jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t); - jpegR.data = malloc(jpegR.maxLength); - ret = jpegRCodec.encodeJPEGR( - &mRawP010Image, &mRawYuv420Image, &mJpegImage, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, - &jpegR); - if (ret != OK) { - FAIL() << "Error code is " << ret; + // encode with luma and chroma stride set + { + UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, kImageWidth + 256)); + ASSERT_TRUE(rawImg2P010.setChromaMode(false)); + ASSERT_TRUE(rawImg2P010.allocateMemory()); + ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), sdr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle()), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - if (SAVE_ENCODING_RESULT) { - // Output image data to file - std::string filePath = "/sdcard/Documents/encoded_from_p010_yuv420p_jpeg_input.jpgr"; - std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); - if (!imageFile.is_open()) { - ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); - } - imageFile.write((const char*)jpegR.data, jpegR.length); + // encode with chroma stride set + { + UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageStride(0, kImageWidth + 64)); + ASSERT_TRUE(rawImg2P010.setChromaMode(false)); + ASSERT_TRUE(rawImg2P010.allocateMemory()); + ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), sdr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle()), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - jpegr_uncompressed_struct decodedJpegR; - int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8; - decodedJpegR.data = malloc(decodedJpegRSize); - ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR); - if (ret != OK) { - FAIL() << "Error code is " << ret; - } - if (SAVE_DECODING_RESULT) { - // Output image data to file - std::string filePath = "/sdcard/Documents/decoded_from_p010_yuv420p_jpeg_input.rgb"; - std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); - if (!imageFile.is_open()) { - ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); - } - imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize); + auto jpg1 = jpgImg.getImageHandle(); + +#ifdef DUMP_OUTPUT + if (!writeFile("encode_api3_output.jpeg", jpg1->data, jpg1->length)) { + std::cerr << "unable to write output file" << std::endl; } +#endif - free(jpegR.data); - free(decodedJpegR.data); + ASSERT_NO_FATAL_FAILURE(decodeJpegRImg(jpg1, "decode_api3_output.rgb")); } -/* Test Encode API-3 and decode */ -TEST_F(JpegRTest, encodeFromJpegThenDecode) { - int ret; +// ============================================================================ +// Profiling +// ============================================================================ - // Load input files. - if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) { - FAIL() << "Load file " << RAW_P010_IMAGE << " failed"; - } - mRawP010Image.width = TEST_IMAGE_WIDTH; - mRawP010Image.height = TEST_IMAGE_HEIGHT; - mRawP010Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; - - if (SAVE_INPUT_RGBA) { - size_t rgbaSize = mRawP010Image.width * mRawP010Image.height * sizeof(uint32_t); - uint32_t *data = (uint32_t *)malloc(rgbaSize); - - for (size_t y = 0; y < mRawP010Image.height; ++y) { - for (size_t x = 0; x < mRawP010Image.width; ++x) { - Color hdr_yuv_gamma = getP010Pixel(&mRawP010Image, x, y); - Color hdr_rgb_gamma = bt2100YuvToRgb(hdr_yuv_gamma); - uint32_t rgba1010102 = colorToRgba1010102(hdr_rgb_gamma); - size_t pixel_idx = x + y * mRawP010Image.width; - reinterpret_cast(data)[pixel_idx] = rgba1010102; - } - } - - // Output image data to file - std::string filePath = "/sdcard/Documents/input_from_p010.rgb10"; - std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); - if (!imageFile.is_open()) { - ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); - } - imageFile.write((const char*)data, rgbaSize); - free(data); - } - if (!loadFile(JPEG_IMAGE, mJpegImage.data, &mJpegImage.length)) { - FAIL() << "Load file " << JPEG_IMAGE << " failed"; - } - mJpegImage.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709; +class Profiler { +public: + void timerStart() { gettimeofday(&mStartingTime, nullptr); } - JpegR jpegRCodec; + void timerStop() { gettimeofday(&mEndingTime, nullptr); } - jpegr_compressed_struct jpegR; - jpegR.maxLength = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * sizeof(uint8_t); - jpegR.data = malloc(jpegR.maxLength); - ret = jpegRCodec.encodeJPEGR( - &mRawP010Image, &mJpegImage, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, &jpegR); - if (ret != OK) { - FAIL() << "Error code is " << ret; - } - if (SAVE_ENCODING_RESULT) { - // Output image data to file - std::string filePath = "/sdcard/Documents/encoded_from_p010_jpeg_input.jpgr"; - std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); - if (!imageFile.is_open()) { - ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); - } - imageFile.write((const char*)jpegR.data, jpegR.length); + int64_t elapsedTime() { + struct timeval elapsedMicroseconds; + elapsedMicroseconds.tv_sec = mEndingTime.tv_sec - mStartingTime.tv_sec; + elapsedMicroseconds.tv_usec = mEndingTime.tv_usec - mStartingTime.tv_usec; + return elapsedMicroseconds.tv_sec * 1000000 + elapsedMicroseconds.tv_usec; } - jpegr_uncompressed_struct decodedJpegR; - int decodedJpegRSize = TEST_IMAGE_WIDTH * TEST_IMAGE_HEIGHT * 8; - decodedJpegR.data = malloc(decodedJpegRSize); - ret = jpegRCodec.decodeJPEGR(&jpegR, &decodedJpegR); - if (ret != OK) { - FAIL() << "Error code is " << ret; - } - if (SAVE_DECODING_RESULT) { - // Output image data to file - std::string filePath = "/sdcard/Documents/decoded_from_p010_jpeg_input.rgb"; - std::ofstream imageFile(filePath.c_str(), std::ofstream::binary); - if (!imageFile.is_open()) { - ALOGE("%s: Unable to create file %s", __FUNCTION__, filePath.c_str()); - } - imageFile.write((const char*)decodedJpegR.data, decodedJpegRSize); - } +private: + struct timeval mStartingTime; + struct timeval mEndingTime; +}; - free(jpegR.data); - free(decodedJpegR.data); -} +class JpegRBenchmark : public JpegR { +public: + void BenchmarkGenerateGainMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr p010Image, + ultrahdr_metadata_ptr metadata, jr_uncompressed_ptr map); + void BenchmarkApplyGainMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr map, + ultrahdr_metadata_ptr metadata, jr_uncompressed_ptr dest); -TEST_F(JpegRTest, ProfileGainMapFuncs) { - const size_t kWidth = TEST_IMAGE_WIDTH; - const size_t kHeight = TEST_IMAGE_HEIGHT; +private: + const int kProfileCount = 10; +}; - // Load input files. - if (!loadFile(RAW_P010_IMAGE, mRawP010Image.data, nullptr)) { - FAIL() << "Load file " << RAW_P010_IMAGE << " failed"; +void JpegRBenchmark::BenchmarkGenerateGainMap(jr_uncompressed_ptr yuv420Image, + jr_uncompressed_ptr p010Image, + ultrahdr_metadata_ptr metadata, + jr_uncompressed_ptr map) { + ASSERT_EQ(yuv420Image->width, p010Image->width); + ASSERT_EQ(yuv420Image->height, p010Image->height); + Profiler profileGenerateMap; + profileGenerateMap.timerStart(); + for (auto i = 0; i < kProfileCount; i++) { + ASSERT_EQ(OK, + generateGainMap(yuv420Image, p010Image, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + metadata, map)); + if (i != kProfileCount - 1) delete[] static_cast(map->data); } - mRawP010Image.width = kWidth; - mRawP010Image.height = kHeight; - mRawP010Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100; + profileGenerateMap.timerStop(); + ALOGE("Generate Gain Map:- Res = %i x %i, time = %f ms", yuv420Image->width, yuv420Image->height, + profileGenerateMap.elapsedTime() / (kProfileCount * 1000.f)); +} - if (!loadFile(RAW_YUV420_IMAGE, mRawYuv420Image.data, nullptr)) { - FAIL() << "Load file " << RAW_P010_IMAGE << " failed"; +void JpegRBenchmark::BenchmarkApplyGainMap(jr_uncompressed_ptr yuv420Image, jr_uncompressed_ptr map, + ultrahdr_metadata_ptr metadata, + jr_uncompressed_ptr dest) { + Profiler profileRecMap; + profileRecMap.timerStart(); + for (auto i = 0; i < kProfileCount; i++) { + ASSERT_EQ(OK, + applyGainMap(yuv420Image, map, metadata, ULTRAHDR_OUTPUT_HDR_HLG, + metadata->maxContentBoost /* displayBoost */, dest)); } - mRawYuv420Image.width = kWidth; - mRawYuv420Image.height = kHeight; - mRawYuv420Image.colorGamut = ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709; + profileRecMap.timerStop(); + ALOGE("Apply Gain Map:- Res = %i x %i, time = %f ms", yuv420Image->width, yuv420Image->height, + profileRecMap.elapsedTime() / (kProfileCount * 1000.f)); +} +TEST(JpegRTest, ProfileGainMapFuncs) { + UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImgP010.allocateMemory()); + ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName)); + UhdrUnCompressedStructWrapper rawImg420(kImageWidth, kImageHeight, YCbCr_420); + ASSERT_TRUE(rawImg420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg420.allocateMemory()); + ASSERT_TRUE(rawImg420.loadRawResource(kYCbCr420FileName)); + ultrahdr_metadata_struct metadata = {.version = "1.0"}; + jpegr_uncompressed_struct map = {.data = NULL, + .width = 0, + .height = 0, + .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; JpegRBenchmark benchmark; + ASSERT_NO_FATAL_FAILURE(benchmark.BenchmarkGenerateGainMap(rawImg420.getImageHandle(), + rawImgP010.getImageHandle(), &metadata, + &map)); - ultrahdr_metadata_struct metadata = { .version = "1.0" }; - - jpegr_uncompressed_struct map = { .data = NULL, + const int dstSize = kImageWidth * kImageWidth * 4; + auto bufferDst = std::make_unique(dstSize); + jpegr_uncompressed_struct dest = {.data = bufferDst.get(), .width = 0, .height = 0, - .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED }; - - benchmark.BenchmarkGenerateGainMap(&mRawYuv420Image, &mRawP010Image, &metadata, &map); - - const int dstSize = mRawYuv420Image.width * mRawYuv420Image.height * 4; - auto bufferDst = std::make_unique(dstSize); - jpegr_uncompressed_struct dest = { .data = bufferDst.get(), - .width = 0, - .height = 0, - .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED }; + .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; - benchmark.BenchmarkApplyGainMap(&mRawYuv420Image, &map, &metadata, &dest); + ASSERT_NO_FATAL_FAILURE( + benchmark.BenchmarkApplyGainMap(rawImg420.getImageHandle(), &map, &metadata, &dest)); } } // namespace android::ultrahdr -- GitLab From c6b1fc26c4f109540e0071af267704c28d1effb3 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 26 Jul 2023 23:53:58 +0000 Subject: [PATCH 0357/1187] dumpstate: avoid ':' in lshal files Windows computers don't like this. Fixes: 288211597 Test: bugreport Change-Id: I13aa9c3eb596521bed5485e480a8ec652f1bcc31 --- cmds/dumpstate/dumpstate.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index dc0e26b9a3..f550e13bc8 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1414,12 +1414,12 @@ static void DumpHals(int out_fd = STDOUT_FILENO) { auto ret = sm->list([&](const auto& interfaces) { for (const std::string& interface : interfaces) { std::string cleanName = interface; - std::replace_if(cleanName.begin(), - cleanName.end(), - [](char c) { - return !isalnum(c) && - std::string("@-_:.").find(c) == std::string::npos; - }, '_'); + std::replace_if( + cleanName.begin(), cleanName.end(), + [](char c) { + return !isalnum(c) && std::string("@-_.").find(c) == std::string::npos; + }, + '_'); const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName; bool empty = false; -- GitLab From 9b68dde53e402365c08293cda42938c3c7f6f220 Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Tue, 18 Jul 2023 22:00:27 +0000 Subject: [PATCH 0358/1187] rpc_binder: Add a trusty binder rpc fuzzer This uses `trusty_tipc_fuzzer` to fuzz: * `com.android.trusty.binder.test.service` * `com.android.trusty.binderRpcTestService.V0` Test: Build and run in trusty emulator Bug: 291817651 Change-Id: I1e1d35c32589017b1e45bc9d937f81229fc01823 --- libs/binder/trusty/fuzzer/Android.bp | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 libs/binder/trusty/fuzzer/Android.bp diff --git a/libs/binder/trusty/fuzzer/Android.bp b/libs/binder/trusty/fuzzer/Android.bp new file mode 100644 index 0000000000..2f1f54b0a6 --- /dev/null +++ b/libs/binder/trusty/fuzzer/Android.bp @@ -0,0 +1,39 @@ +// Copyright (C) 2023 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. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_fuzz { + name: "trusty_binder_fuzzer", + defaults: ["trusty_fuzzer_defaults"], + srcs: [":trusty_tipc_fuzzer"], + cflags: [ + "-DTRUSTY_APP_PORT=\"com.android.trusty.binder.test.service\"", + "-DTRUSTY_APP_UUID=\"d42f06c5-9dc5-455b-9914-cf094116cfa8\"", + "-DTRUSTY_APP_FILENAME=\"binder-test-service.syms.elf\"", + ], +} + +cc_fuzz { + name: "trusty_binder_rpc_fuzzer", + defaults: ["trusty_fuzzer_defaults"], + srcs: [":trusty_tipc_fuzzer"], + cflags: [ + "-DTRUSTY_APP_PORT=\"com.android.trusty.binderRpcTestService.V0\"", + "-DTRUSTY_APP_UUID=\"87e424e5-69d7-4bbd-8b7c-7e24812cbc94\"", + "-DTRUSTY_APP_FILENAME=\"binderRpcTestService.syms.elf\"", + ], +} -- GitLab From edcd885f845304ee7fc41351f036d76be8cffc22 Mon Sep 17 00:00:00 2001 From: John Reck Date: Tue, 25 Jul 2023 16:03:44 -0400 Subject: [PATCH 0359/1187] Implement Gralloc5::dump() Also fix size padding for allocator dump Test: dumpsys gfxinfo on Cuttlefish Change-Id: I8fcfd85bde9308423858d59da0c45d6a79448a82 --- libs/ui/Gralloc5.cpp | 207 ++++++++++++++++++++++++++++- libs/ui/GraphicBufferAllocator.cpp | 4 +- 2 files changed, 202 insertions(+), 9 deletions(-) diff --git a/libs/ui/Gralloc5.cpp b/libs/ui/Gralloc5.cpp index c3b2d3d808..37ebfc4617 100644 --- a/libs/ui/Gralloc5.cpp +++ b/libs/ui/Gralloc5.cpp @@ -31,10 +31,15 @@ using namespace aidl::android::hardware::graphics::allocator; using namespace aidl::android::hardware::graphics::common; using namespace ::android::hardware::graphics::mapper; +using ADataspace = aidl::android::hardware::graphics::common::Dataspace; +using APixelFormat = aidl::android::hardware::graphics::common::PixelFormat; + namespace android { static const auto kIAllocatorServiceName = IAllocator::descriptor + std::string("/default"); static const auto kIAllocatorMinimumVersion = 2; +constexpr const char* kStandardMetadataName = + "android.hardware.graphics.common.StandardMetadataType"; // TODO(b/72323293, b/72703005): Remove these invalid bits from callers static constexpr uint64_t kRemovedUsageBits = static_cast((1 << 10) | (1 << 13)); @@ -284,17 +289,205 @@ bool Gralloc5Mapper::isLoaded() const { return mMapper != nullptr && mMapper->version >= AIMAPPER_VERSION_5; } +static bool isStandardMetadata(AIMapper_MetadataType metadataType) { + return strcmp(kStandardMetadataName, metadataType.name) == 0; +} + +struct DumpBufferResult { + uint64_t bufferId; + std::string name; + uint64_t width; + uint64_t height; + uint64_t layerCount; + APixelFormat pixelFormatRequested; + uint32_t pixelFormatFourCC; + uint64_t pixelFormatModifier; + BufferUsage usage; + ADataspace dataspace; + uint64_t allocationSize; + uint64_t protectedContent; + ExtendableType compression; + ExtendableType interlaced; + ExtendableType chromaSiting; + std::vector planeLayouts; +}; + +#define DECODE_TO(name, output) \ + case StandardMetadataType::name: \ + output = StandardMetadata::value ::decode(value, valueSize) \ + .value(); \ + break + +static void dumpBufferCommon(DumpBufferResult* outResult, AIMapper_MetadataType metadataType, + const void* value, size_t valueSize) { + if (!isStandardMetadata(metadataType)) { + return; + } + StandardMetadataType type = (StandardMetadataType)metadataType.value; + switch (type) { + DECODE_TO(BUFFER_ID, outResult->bufferId); + DECODE_TO(NAME, outResult->name); + DECODE_TO(WIDTH, outResult->width); + DECODE_TO(HEIGHT, outResult->height); + DECODE_TO(LAYER_COUNT, outResult->layerCount); + DECODE_TO(PIXEL_FORMAT_REQUESTED, outResult->pixelFormatRequested); + DECODE_TO(PIXEL_FORMAT_FOURCC, outResult->pixelFormatFourCC); + DECODE_TO(PIXEL_FORMAT_MODIFIER, outResult->pixelFormatModifier); + DECODE_TO(USAGE, outResult->usage); + DECODE_TO(DATASPACE, outResult->dataspace); + DECODE_TO(ALLOCATION_SIZE, outResult->allocationSize); + DECODE_TO(PROTECTED_CONTENT, outResult->protectedContent); + DECODE_TO(COMPRESSION, outResult->compression); + DECODE_TO(INTERLACED, outResult->interlaced); + DECODE_TO(CHROMA_SITING, outResult->chromaSiting); + DECODE_TO(PLANE_LAYOUTS, outResult->planeLayouts); + default: + break; + } +} + +#undef DECODE_TO + +template {}>> +constexpr std::underlying_type_t to_underlying(EnumT e) noexcept { + return static_cast>(e); +} + +static void writeDumpToStream(const DumpBufferResult& bufferDump, std::ostream& outDump, + bool less) { + double allocationSizeKiB = static_cast(bufferDump.allocationSize) / 1024; + + outDump << "+ name:" << bufferDump.name << ", id:" << bufferDump.bufferId + << ", size:" << std::fixed << allocationSizeKiB << "KiB, w/h:" << bufferDump.width + << "x" << bufferDump.height << ", usage: 0x" << std::hex + << to_underlying(bufferDump.usage) << std::dec + << ", req fmt:" << to_underlying(bufferDump.pixelFormatRequested) + << ", fourcc/mod:" << bufferDump.pixelFormatFourCC << "/" + << bufferDump.pixelFormatModifier << ", dataspace: 0x" << std::hex + << to_underlying(bufferDump.dataspace) << std::dec << ", compressed: "; + + if (less) { + bool isCompressed = !gralloc4::isStandardCompression(bufferDump.compression) || + (gralloc4::getStandardCompressionValue(bufferDump.compression) != + ui::Compression::NONE); + outDump << std::boolalpha << isCompressed << "\n"; + } else { + outDump << gralloc4::getCompressionName(bufferDump.compression) << "\n"; + } + + if (!less) { + bool firstPlane = true; + for (const auto& planeLayout : bufferDump.planeLayouts) { + if (firstPlane) { + firstPlane = false; + outDump << "\tplanes: "; + } else { + outDump << "\t "; + } + + for (size_t i = 0; i < planeLayout.components.size(); i++) { + const auto& planeLayoutComponent = planeLayout.components[i]; + outDump << gralloc4::getPlaneLayoutComponentTypeName(planeLayoutComponent.type); + if (i < planeLayout.components.size() - 1) { + outDump << "/"; + } else { + outDump << ":\t"; + } + } + outDump << " w/h:" << planeLayout.widthInSamples << "x" << planeLayout.heightInSamples + << ", stride:" << planeLayout.strideInBytes + << " bytes, size:" << planeLayout.totalSizeInBytes; + outDump << ", inc:" << planeLayout.sampleIncrementInBits + << " bits, subsampling w/h:" << planeLayout.horizontalSubsampling << "x" + << planeLayout.verticalSubsampling; + outDump << "\n"; + } + + outDump << "\tlayer cnt: " << bufferDump.layerCount + << ", protected content: " << bufferDump.protectedContent + << ", interlaced: " << gralloc4::getInterlacedName(bufferDump.interlaced) + << ", chroma siting:" << gralloc4::getChromaSitingName(bufferDump.chromaSiting) + << "\n"; + } +} + std::string Gralloc5Mapper::dumpBuffer(buffer_handle_t bufferHandle, bool less) const { - // TODO(b/261858392): Implement - (void)bufferHandle; - (void)less; - return {}; + DumpBufferResult bufferInfo; + AIMapper_DumpBufferCallback dumpBuffer = [](void* contextPtr, + AIMapper_MetadataType metadataType, + const void* _Nonnull value, size_t valueSize) { + DumpBufferResult* context = reinterpret_cast(contextPtr); + dumpBufferCommon(context, metadataType, value, valueSize); + }; + AIMapper_Error error = mMapper->v5.dumpBuffer(bufferHandle, dumpBuffer, &bufferInfo); + if (error != AIMAPPER_ERROR_NONE) { + ALOGE("Error dumping buffer: %d", error); + return std::string{}; + } + std::ostringstream stream; + stream.precision(2); + writeDumpToStream(bufferInfo, stream, less); + return stream.str(); } std::string Gralloc5Mapper::dumpBuffers(bool less) const { - // TODO(b/261858392): Implement - (void)less; - return {}; + class DumpAllBuffersContext { + private: + bool mHasPending = false; + DumpBufferResult mPending; + std::vector mResults; + + public: + DumpAllBuffersContext() { mResults.reserve(10); } + + void commit() { + if (mHasPending) { + mResults.push_back(mPending); + mHasPending = false; + } + } + + DumpBufferResult* write() { + mHasPending = true; + return &mPending; + } + + const std::vector& results() { + commit(); + return mResults; + } + } context; + + AIMapper_BeginDumpBufferCallback beginCallback = [](void* contextPtr) { + DumpAllBuffersContext* context = reinterpret_cast(contextPtr); + context->commit(); + }; + + AIMapper_DumpBufferCallback dumpBuffer = [](void* contextPtr, + AIMapper_MetadataType metadataType, + const void* _Nonnull value, size_t valueSize) { + DumpAllBuffersContext* context = reinterpret_cast(contextPtr); + dumpBufferCommon(context->write(), metadataType, value, valueSize); + }; + + AIMapper_Error error = mMapper->v5.dumpAllBuffers(beginCallback, dumpBuffer, &context); + if (error != AIMAPPER_ERROR_NONE) { + ALOGE("Error dumping buffers: %d", error); + return std::string{}; + } + uint64_t totalAllocationSize = 0; + std::ostringstream stream; + stream.precision(2); + stream << "Imported gralloc buffers:\n"; + + for (const auto& bufferDump : context.results()) { + writeDumpToStream(bufferDump, stream, less); + totalAllocationSize += bufferDump.allocationSize; + } + + double totalAllocationSizeKiB = static_cast(totalAllocationSize) / 1024; + stream << "Total imported by gralloc: " << totalAllocationSizeKiB << "KiB\n"; + return stream.str(); } status_t Gralloc5Mapper::importBuffer(const native_handle_t *rawHandle, diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp index c0abec23e0..eb0bd4ed0a 100644 --- a/libs/ui/GraphicBufferAllocator.cpp +++ b/libs/ui/GraphicBufferAllocator.cpp @@ -89,14 +89,14 @@ void GraphicBufferAllocator::dump(std::string& result, bool less) const { uint64_t total = 0; result.append("GraphicBufferAllocator buffers:\n"); const size_t count = list.size(); - StringAppendF(&result, "%10s | %11s | %18s | %s | %8s | %10s | %s\n", "Handle", "Size", + StringAppendF(&result, "%14s | %11s | %18s | %s | %8s | %10s | %s\n", "Handle", "Size", "W (Stride) x H", "Layers", "Format", "Usage", "Requestor"); for (size_t i = 0; i < count; i++) { const alloc_rec_t& rec(list.valueAt(i)); std::string sizeStr = (rec.size) ? base::StringPrintf("%7.2f KiB", static_cast(rec.size) / 1024.0) : "unknown"; - StringAppendF(&result, "%10p | %11s | %4u (%4u) x %4u | %6u | %8X | 0x%8" PRIx64 " | %s\n", + StringAppendF(&result, "%14p | %11s | %4u (%4u) x %4u | %6u | %8X | 0x%8" PRIx64 " | %s\n", list.keyAt(i), sizeStr.c_str(), rec.width, rec.stride, rec.height, rec.layerCount, rec.format, rec.usage, rec.requestorName.c_str()); total += rec.size; -- GitLab From fa64e6412bd607e198a199b39cc18024e6e99105 Mon Sep 17 00:00:00 2001 From: Kevin Jeon Date: Thu, 27 Jul 2023 11:36:41 -0400 Subject: [PATCH 0360/1187] Add sysprop for identifying strict-run bugreports This change adds 'dumpstate.strict_run', which sets stricter timeouts on flaky sections. The default value for this property is 'true'. Test: Build, wipe, and flash, then verify that: 1) the strict-run log is emitted when taking a bug report 2) manually running 'setprop dumpstate.strict_run false' results in the strict-run log not being emitted in the next bug report Bug: 283326935 Change-Id: Ic40b235f710b2858ec8ca463a8f6a796d9e6c98e --- cmds/dumpstate/DumpstateUtil.cpp | 9 +++++++++ cmds/dumpstate/DumpstateUtil.h | 8 ++++++++ cmds/dumpstate/dumpstate.cpp | 18 ++++++++++++++---- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp index aa42541a66..615701ccc1 100644 --- a/cmds/dumpstate/DumpstateUtil.cpp +++ b/cmds/dumpstate/DumpstateUtil.cpp @@ -207,6 +207,7 @@ std::string PropertiesHelper::build_type_ = ""; int PropertiesHelper::dry_run_ = -1; int PropertiesHelper::unroot_ = -1; int PropertiesHelper::parallel_run_ = -1; +int PropertiesHelper::strict_run_ = -1; bool PropertiesHelper::IsUserBuild() { if (build_type_.empty()) { @@ -237,6 +238,14 @@ bool PropertiesHelper::IsParallelRun() { return parallel_run_ == 1; } +bool PropertiesHelper::IsStrictRun() { + if (strict_run_ == -1) { + // Defaults to using stricter timeouts. + strict_run_ = android::base::GetBoolProperty("dumpstate.strict_run", true) ? 1 : 0; + } + return strict_run_ == 1; +} + int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC))); if (fd.get() < 0) { diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h index b00c46e0db..9e955e3c04 100644 --- a/cmds/dumpstate/DumpstateUtil.h +++ b/cmds/dumpstate/DumpstateUtil.h @@ -193,11 +193,19 @@ class PropertiesHelper { */ static bool IsParallelRun(); + /* + * Strict-run mode is determined by the `dumpstate.strict_run` sysprop which + * will default to true. This results in shortened timeouts for flaky + * sections. + */ + static bool IsStrictRun(); + private: static std::string build_type_; static int dry_run_; static int unroot_; static int parallel_run_; + static int strict_run_; }; /* diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index dc0e26b9a3..f5200460a2 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -820,9 +820,12 @@ void Dumpstate::PrintHeader() const { RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"}, CommandOptions::WithTimeout(1).Always().Build()); printf("Bugreport format version: %s\n", version_.c_str()); - printf("Dumpstate info: id=%d pid=%d dry_run=%d parallel_run=%d args=%s bugreport_mode=%s\n", - id_, pid_, PropertiesHelper::IsDryRun(), PropertiesHelper::IsParallelRun(), - options_->args.c_str(), options_->bugreport_mode_string.c_str()); + printf( + "Dumpstate info: id=%d pid=%d dry_run=%d parallel_run=%d strict_run=%d args=%s " + "bugreport_mode=%s\n", + id_, pid_, PropertiesHelper::IsDryRun(), PropertiesHelper::IsParallelRun(), + PropertiesHelper::IsStrictRun(), options_->args.c_str(), + options_->bugreport_mode_string.c_str()); printf("\n"); } @@ -1044,7 +1047,8 @@ static void DumpIncidentReport() { MYLOGE("Could not open %s to dump incident report.\n", path.c_str()); return; } - RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(20).Build()); + RunCommandToFd(fd, "", {"incident", "-u"}, + CommandOptions::WithTimeout(PropertiesHelper::IsStrictRun() ? 20 : 120).Build()); bool empty = 0 == lseek(fd, 0, SEEK_END); if (!empty) { // Use a different name from "incident.proto" @@ -3053,6 +3057,12 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n"); } + if (PropertiesHelper::IsStrictRun()) { + MYLOGI( + "Running on strict-run mode, which has shorter timeouts " + "(to disable, call 'setprop dumpstate.strict_run false')\n"); + } + MYLOGI("dumpstate info: id=%d, args='%s', bugreport_mode= %s bugreport format version: %s\n", id_, options_->args.c_str(), options_->bugreport_mode_string.c_str(), version_.c_str()); -- GitLab From ed4745df9f4985e68e04fda86f272870dbb2686e Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Thu, 27 Jul 2023 17:35:19 -0500 Subject: [PATCH 0361/1187] Fix flaky BBQ tests Updates several tests to use transaction committed callbacks and BBQ's mergeWithNextTransaction to correctly wait before taking screenshots. Bug: 288344458 Test: tested the updated tests with at least 200 runs each Change-Id: I821d8673162ec22be6c3060e24491c3ee4941640 --- libs/gui/tests/BLASTBufferQueue_test.cpp | 39 +++++++++++++++++++----- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index cd90168784..cce28926ea 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -351,6 +351,24 @@ protected: sp mProducerListener; }; +// Helper class to ensure the provided BBQ frame number has been committed in SurfaceFlinger. +class BBQSyncHelper { +public: + BBQSyncHelper(BLASTBufferQueueHelper& bbqHelper, uint64_t frameNumber) { + t.addTransactionCompletedCallback(callbackHelper.function, callbackHelper.getContext()); + bbqHelper.mergeWithNextTransaction(&t, frameNumber); + } + + void wait() { + CallbackData callbackData; + callbackHelper.getCallbackData(&callbackData); + } + +private: + Transaction t; + CallbackHelper callbackHelper; +}; + TEST_F(BLASTBufferQueueTest, CreateBLASTBufferQueue) { // create BLASTBufferQueue adapter associated with this surface BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); @@ -422,6 +440,7 @@ TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); sp igbProducer; setUpProducer(adapter, igbProducer); + BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; @@ -447,7 +466,7 @@ TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) { igbProducer->queueBuffer(slot, input, &qbOutput); ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); - adapter.waitForCallbacks(); + syncHelper.wait(); // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); @@ -507,6 +526,7 @@ TEST_F(BLASTBufferQueueTest, SetCrop_Item) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); sp igbProducer; setUpProducer(adapter, igbProducer); + BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; sp buf; @@ -531,7 +551,7 @@ TEST_F(BLASTBufferQueueTest, SetCrop_Item) { igbProducer->queueBuffer(slot, input, &qbOutput); ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); - adapter.waitForCallbacks(); + syncHelper.wait(); // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); @@ -562,6 +582,7 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { BLASTBufferQueueHelper adapter(mSurfaceControl, bufferSideLength, bufferSideLength); sp igbProducer; setUpProducer(adapter, igbProducer); + BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; sp buf; @@ -590,7 +611,7 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { igbProducer->queueBuffer(slot, input, &qbOutput); ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); - adapter.waitForCallbacks(); + syncHelper.wait(); // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b, @@ -621,6 +642,7 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) { BLASTBufferQueueHelper adapter(mSurfaceControl, windowSize.getWidth(), windowSize.getHeight()); sp igbProducer; setUpProducer(adapter, igbProducer); + BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; sp buf; @@ -653,7 +675,7 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) { igbProducer->queueBuffer(slot, input, &qbOutput); ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); - adapter.waitForCallbacks(); + syncHelper.wait(); ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); @@ -688,6 +710,7 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) { BLASTBufferQueueHelper adapter(mSurfaceControl, windowSize.getWidth(), windowSize.getHeight()); sp igbProducer; setUpProducer(adapter, igbProducer); + BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; sp buf; @@ -720,7 +743,7 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) { igbProducer->queueBuffer(slot, input, &qbOutput); ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); - adapter.waitForCallbacks(); + syncHelper.wait(); ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); // Verify cropped region is scaled correctly. @@ -746,6 +769,7 @@ TEST_F(BLASTBufferQueueTest, ScalingModeChanges) { sp igbProducer; setUpProducer(adapter, igbProducer); { + BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; sp buf; @@ -767,7 +791,7 @@ TEST_F(BLASTBufferQueueTest, ScalingModeChanges) { NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); igbProducer->queueBuffer(slot, input, &qbOutput); - adapter.waitForCallbacks(); + syncHelper.wait(); } // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); @@ -780,6 +804,7 @@ TEST_F(BLASTBufferQueueTest, ScalingModeChanges) { adapter.update(mSurfaceControl, mDisplayWidth, mDisplayHeight / 2); { + BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; sp buf; @@ -802,7 +827,7 @@ TEST_F(BLASTBufferQueueTest, ScalingModeChanges) { NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, 0, Fence::NO_FENCE); igbProducer->queueBuffer(slot, input, &qbOutput); - adapter.waitForCallbacks(); + syncHelper.wait(); } // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); -- GitLab From 1030142fbc887c564bb6165946d06ccf43dd9591 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Wed, 26 Jul 2023 21:48:30 +0000 Subject: [PATCH 0362/1187] Move absolute axis validation from EventHub to InputDevice We recently added a crash when a we receive a misconfigured event froma device. However, it seems like our critera for determining if an absolute axis is correctly configured has issues. In this case, we ignore an axis if its min and max value are equal. Since the min and max are inclusive, it's perfectly valid for them to be equal. As long as evdev is reporting valid events, EventHub should continue to track and report them. Deeming axes with min and max values that are equal is an artificial constraint we have placed in InputReader historically. To maintain that same constraint as before, we move the validation to InputDevice. Bug: 293156873 Test: Presubmit Change-Id: Id7c841f2d06668536a1b61c0e9e5250c15aad550 --- services/inputflinger/reader/EventHub.cpp | 26 ++++++++++++------- .../inputflinger/reader/include/InputDevice.h | 13 +++++++++- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index bc4cdd1192..e69c99e9b5 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -643,9 +643,6 @@ void EventHub::Device::populateAbsoluteAxisStates() { identifier.name.c_str(), fd, strerror(errno)); continue; } - if (info.minimum == info.maximum) { - continue; - } auto& [axisInfo, value] = absState[axis]; axisInfo.valid = true; axisInfo.minValue = info.minimum; @@ -778,26 +775,35 @@ void EventHub::Device::trackInputEvent(const struct input_event& event) { LOG_ALWAYS_FATAL_IF(!currentFrameDropped && !keyState.set(static_cast(event.code), event.value != 0), - "%s: received invalid EV_KEY event code: %s", __func__, + "%s: device '%s' received invalid EV_KEY event code: %s value: %d", + __func__, identifier.name.c_str(), InputEventLookup::getLinuxEvdevLabel(EV_KEY, event.code, 1) - .code.c_str()); + .code.c_str(), + event.value); break; } case EV_SW: { LOG_ALWAYS_FATAL_IF(!currentFrameDropped && !swState.set(static_cast(event.code), event.value != 0), - "%s: received invalid EV_SW event code: %s", __func__, + "%s: device '%s' received invalid EV_SW event code: %s value: %d", + __func__, identifier.name.c_str(), InputEventLookup::getLinuxEvdevLabel(EV_SW, event.code, 1) - .code.c_str()); + .code.c_str(), + event.value); break; } case EV_ABS: { + if (currentFrameDropped) { + break; + } auto it = absState.find(event.code); - LOG_ALWAYS_FATAL_IF(!currentFrameDropped && it == absState.end(), - "%s: received invalid EV_ABS event code: %s", __func__, + LOG_ALWAYS_FATAL_IF(it == absState.end(), + "%s: device '%s' received invalid EV_ABS event code: %s value: %d", + __func__, identifier.name.c_str(), InputEventLookup::getLinuxEvdevLabel(EV_ABS, event.code, 0) - .code.c_str()); + .code.c_str(), + event.value); it->second.value = event.value; break; } diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index aae3fe79e0..1cbcbf47b4 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -289,7 +289,18 @@ public: return mEventHub->getDeviceControllerNumber(mId); } inline status_t getAbsoluteAxisInfo(int32_t code, RawAbsoluteAxisInfo* axisInfo) const { - return mEventHub->getAbsoluteAxisInfo(mId, code, axisInfo); + if (const auto status = mEventHub->getAbsoluteAxisInfo(mId, code, axisInfo); status != OK) { + return status; + } + + // Validate axis info for InputDevice. + if (axisInfo->valid && axisInfo->minValue == axisInfo->maxValue) { + // Historically, we deem axes with the same min and max values as invalid to avoid + // dividing by zero when scaling by max - min. + // TODO(b/291772515): Perform axis info validation on a per-axis basis when it is used. + axisInfo->valid = false; + } + return OK; } inline bool hasRelativeAxis(int32_t code) const { return mEventHub->hasRelativeAxis(mId, code); -- GitLab From 2f13e022e739737f0a6cc4a31c6bcbb4cdadf387 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 21 Jul 2023 18:31:00 +0000 Subject: [PATCH 0363/1187] InputEventLabels: Support lookup of evdev event codes by label Bug: 293327283 Test: atest CtsInputTestCases Change-Id: I846e1dc1eb450ea92d35ac7e403b06e2a029f25b --- include/input/InputEventLabels.h | 6 ++++++ libs/input/InputEventLabels.cpp | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h index 909bf087dd..44247c1249 100644 --- a/include/input/InputEventLabels.h +++ b/include/input/InputEventLabels.h @@ -69,6 +69,12 @@ public: static EvdevEventLabel getLinuxEvdevLabel(int32_t type, int32_t code, int32_t value); + static std::optional getLinuxEvdevEventTypeByLabel(const char* label); + + static std::optional getLinuxEvdevEventCodeByLabel(int32_t type, const char* label); + + static std::optional getLinuxEvdevInputPropByLabel(const char* label); + private: InputEventLookup(); diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index 50efac1314..c218e1e858 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -18,6 +18,7 @@ #include #include +#include #define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key } #define DEFINE_AXIS(axis) { #axis, AMOTION_EVENT_AXIS_##axis } @@ -523,6 +524,14 @@ std::string getLabel(const label* labels, int value) { return labels->name != nullptr ? labels->name : std::to_string(value); } +std::optional getValue(const label* labels, const char* searchLabel) { + if (labels == nullptr) return {}; + while (labels->name != nullptr && ::strcasecmp(labels->name, searchLabel) != 0) { + labels++; + } + return labels->name != nullptr ? std::make_optional(labels->value) : std::nullopt; +} + const label* getCodeLabelsForType(int32_t type) { switch (type) { case EV_SYN: @@ -572,4 +581,17 @@ EvdevEventLabel InputEventLookup::getLinuxEvdevLabel(int32_t type, int32_t code, }; } +std::optional InputEventLookup::getLinuxEvdevEventTypeByLabel(const char* label) { + return getValue(ev_labels, label); +} + +std::optional InputEventLookup::getLinuxEvdevEventCodeByLabel(int32_t type, + const char* label) { + return getValue(getCodeLabelsForType(type), label); +} + +std::optional InputEventLookup::getLinuxEvdevInputPropByLabel(const char* label) { + return getValue(input_prop_labels, label); +} + } // namespace android -- GitLab From c85c0d6cbe6626797fb84907d50d7b3a6c9768f0 Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Fri, 28 Jul 2023 21:26:53 +0530 Subject: [PATCH 0364/1187] ultrahdr: fix visual artifacts in api-1 due to overflows Bug: Test: ./ultrahdr_unit_test Change-Id: If31016ece14372579aa14c1007806258384f30ab --- libs/ultrahdr/gainmapmath.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/ultrahdr/gainmapmath.cpp b/libs/ultrahdr/gainmapmath.cpp index ee15363b69..8015a4ebeb 100644 --- a/libs/ultrahdr/gainmapmath.cpp +++ b/libs/ultrahdr/gainmapmath.cpp @@ -547,13 +547,13 @@ void transformYuv420(jr_uncompressed_ptr image, size_t x_chroma, size_t y_chroma uint8_t& u_uint = reinterpret_cast(image->data)[pixel_count + pixel_uv_idx]; uint8_t& v_uint = reinterpret_cast(image->data)[pixel_count * 5 / 4 + pixel_uv_idx]; - y1_uint = static_cast(floor(yuv1.y * 255.0f + 0.5f)); - y2_uint = static_cast(floor(yuv2.y * 255.0f + 0.5f)); - y3_uint = static_cast(floor(yuv3.y * 255.0f + 0.5f)); - y4_uint = static_cast(floor(yuv4.y * 255.0f + 0.5f)); + y1_uint = static_cast(CLIP3((yuv1.y * 255.0f + 0.5f), 0, 255)); + y2_uint = static_cast(CLIP3((yuv2.y * 255.0f + 0.5f), 0, 255)); + y3_uint = static_cast(CLIP3((yuv3.y * 255.0f + 0.5f), 0, 255)); + y4_uint = static_cast(CLIP3((yuv4.y * 255.0f + 0.5f), 0, 255)); - u_uint = static_cast(floor(new_uv.u * 255.0f + 128.0f + 0.5f)); - v_uint = static_cast(floor(new_uv.v * 255.0f + 128.0f + 0.5f)); + u_uint = static_cast(CLIP3((new_uv.u * 255.0f + 128.0f + 0.5f), 0, 255)); + v_uint = static_cast(CLIP3((new_uv.v * 255.0f + 128.0f + 0.5f), 0, 255)); } //////////////////////////////////////////////////////////////////////////////// -- GitLab From f6e7740b2f89823cfc84fe4e75fc57db864f1dc8 Mon Sep 17 00:00:00 2001 From: Lais Andrade Date: Fri, 28 Jul 2023 18:35:17 +0100 Subject: [PATCH 0365/1187] Exclude flaky test from libvibratorservice_test presubmit Also add postsubmit mapping to the excluded tests can be monitored and returned to presubmit. Bug: 293603710 Test: atest --test-mapping services/vibratorservice:presubmit Change-Id: I4cc55a58b4b0e9f5482e300e04f8c583e62e0555 --- services/vibratorservice/TEST_MAPPING | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/services/vibratorservice/TEST_MAPPING b/services/vibratorservice/TEST_MAPPING index b033adbd05..1f8c42a762 100644 --- a/services/vibratorservice/TEST_MAPPING +++ b/services/vibratorservice/TEST_MAPPING @@ -1,5 +1,16 @@ { "presubmit": [ + { + "name": "libvibratorservice_test", + "options": [ + // TODO(b/293603710): Fix flakiness + { + "exclude-filter": "VibratorCallbackSchedulerTest#TestScheduleRunsOnlyAfterDelay" + } + ] + } + ], + "postsubmit": [ { "name": "libvibratorservice_test" } -- GitLab From 0eb09c635ac13dbe3df1267a4e810fba205b9775 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Fri, 28 Jul 2023 11:24:35 -0500 Subject: [PATCH 0366/1187] Use synchronous transactions to simplify BBQ test Bug: 288344458 Test: ran each test 200 times Change-Id: I9c3d83ac1790628c205bdabc67ec66a16e9d11b9 --- libs/gui/tests/BLASTBufferQueue_test.cpp | 51 +++++++++--------------- 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index cce28926ea..e092aa6e43 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -351,24 +351,6 @@ protected: sp mProducerListener; }; -// Helper class to ensure the provided BBQ frame number has been committed in SurfaceFlinger. -class BBQSyncHelper { -public: - BBQSyncHelper(BLASTBufferQueueHelper& bbqHelper, uint64_t frameNumber) { - t.addTransactionCompletedCallback(callbackHelper.function, callbackHelper.getContext()); - bbqHelper.mergeWithNextTransaction(&t, frameNumber); - } - - void wait() { - CallbackData callbackData; - callbackHelper.getCallbackData(&callbackData); - } - -private: - Transaction t; - CallbackHelper callbackHelper; -}; - TEST_F(BLASTBufferQueueTest, CreateBLASTBufferQueue) { // create BLASTBufferQueue adapter associated with this surface BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); @@ -440,7 +422,6 @@ TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); sp igbProducer; setUpProducer(adapter, igbProducer); - BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; @@ -466,7 +447,8 @@ TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) { igbProducer->queueBuffer(slot, input, &qbOutput); ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); - syncHelper.wait(); + // ensure the buffer queue transaction has been committed + Transaction().apply(true /* synchronous */); // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); @@ -526,7 +508,6 @@ TEST_F(BLASTBufferQueueTest, SetCrop_Item) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); sp igbProducer; setUpProducer(adapter, igbProducer); - BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; sp buf; @@ -551,7 +532,9 @@ TEST_F(BLASTBufferQueueTest, SetCrop_Item) { igbProducer->queueBuffer(slot, input, &qbOutput); ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); - syncHelper.wait(); + // ensure the buffer queue transaction has been committed + Transaction().apply(true /* synchronous */); + // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); @@ -582,7 +565,6 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { BLASTBufferQueueHelper adapter(mSurfaceControl, bufferSideLength, bufferSideLength); sp igbProducer; setUpProducer(adapter, igbProducer); - BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; sp buf; @@ -611,7 +593,9 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { igbProducer->queueBuffer(slot, input, &qbOutput); ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); - syncHelper.wait(); + // ensure the buffer queue transaction has been committed + Transaction().apply(true /* synchronous */); + // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b, @@ -642,7 +626,6 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) { BLASTBufferQueueHelper adapter(mSurfaceControl, windowSize.getWidth(), windowSize.getHeight()); sp igbProducer; setUpProducer(adapter, igbProducer); - BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; sp buf; @@ -675,7 +658,8 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) { igbProducer->queueBuffer(slot, input, &qbOutput); ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); - syncHelper.wait(); + // ensure the buffer queue transaction has been committed + Transaction().apply(true /* synchronous */); ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); @@ -710,7 +694,6 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) { BLASTBufferQueueHelper adapter(mSurfaceControl, windowSize.getWidth(), windowSize.getHeight()); sp igbProducer; setUpProducer(adapter, igbProducer); - BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; sp buf; @@ -743,7 +726,8 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) { igbProducer->queueBuffer(slot, input, &qbOutput); ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); - syncHelper.wait(); + // ensure the buffer queue transaction has been committed + Transaction().apply(true /* synchronous */); ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); // Verify cropped region is scaled correctly. @@ -769,7 +753,6 @@ TEST_F(BLASTBufferQueueTest, ScalingModeChanges) { sp igbProducer; setUpProducer(adapter, igbProducer); { - BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; sp buf; @@ -791,7 +774,9 @@ TEST_F(BLASTBufferQueueTest, ScalingModeChanges) { NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); igbProducer->queueBuffer(slot, input, &qbOutput); - syncHelper.wait(); + + // ensure the buffer queue transaction has been committed + Transaction().apply(true /* synchronous */); } // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); @@ -804,7 +789,6 @@ TEST_F(BLASTBufferQueueTest, ScalingModeChanges) { adapter.update(mSurfaceControl, mDisplayWidth, mDisplayHeight / 2); { - BBQSyncHelper syncHelper{adapter, 1}; int slot; sp fence; sp buf; @@ -827,7 +811,8 @@ TEST_F(BLASTBufferQueueTest, ScalingModeChanges) { NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, 0, Fence::NO_FENCE); igbProducer->queueBuffer(slot, input, &qbOutput); - syncHelper.wait(); + // ensure the buffer queue transaction has been committed + Transaction().apply(true /* synchronous */); } // capture screen and verify that it is red ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); @@ -1457,7 +1442,7 @@ public: igbProducer->queueBuffer(slot, input, &qbOutput); ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); - adapter.waitForCallbacks(); + Transaction().apply(true /* synchronous */); ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); switch (tr) { -- GitLab From 79ae59602fdce988492682289212873e78d7937c Mon Sep 17 00:00:00 2001 From: Lais Andrade Date: Fri, 28 Jul 2023 19:14:52 +0000 Subject: [PATCH 0367/1187] Exclude flaky test from libvibratorservice_test presubmit Bug: 293623689 Change-Id: Ia23932155ca8709cdb6456d8dc68ee5159a8103f Test: atest --test-mapping services/vibratorservice:presubmit --- services/vibratorservice/TEST_MAPPING | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/vibratorservice/TEST_MAPPING b/services/vibratorservice/TEST_MAPPING index 63a2bd0059..7e382a3841 100644 --- a/services/vibratorservice/TEST_MAPPING +++ b/services/vibratorservice/TEST_MAPPING @@ -6,6 +6,10 @@ // TODO(b/293603710): Fix flakiness { "exclude-filter": "VibratorCallbackSchedulerTest#TestScheduleRunsOnlyAfterDelay" + }, + // TODO(b/293623689): Fix flakiness + { + "exclude-filter": "VibratorCallbackSchedulerTest#TestScheduleMultipleCallbacksRunsInDelayOrder" } ] } -- GitLab From 51d8d5d3f852d753fe91b77d0192c414dce88f11 Mon Sep 17 00:00:00 2001 From: Brian Johnson Date: Fri, 28 Jul 2023 10:18:47 -0700 Subject: [PATCH 0368/1187] SF: Add a sf backdoor to enable mirroring one display to another. This is Useful for testing mirroring on two-screen devices. Test: Manual, running all three mirroring commands Change-Id: I7d4519e5212b9a2c4fbfb1bb68886b96844064ff --- services/surfaceflinger/SurfaceFlinger.cpp | 75 ++++++++++++++++++++-- services/surfaceflinger/SurfaceFlinger.h | 4 ++ 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9de623fff9..9f24dd6341 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -68,6 +68,7 @@ #include #include #include +#include #include #include #include @@ -91,13 +92,12 @@ #include #include #include +#include #include #include #include #include #include - -#include #include #include #include @@ -6522,9 +6522,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { code == IBinder::SYSPROPS_TRANSACTION) { return OK; } - // Numbers from 1000 to 1043 are currently used for backdoors. The code + // Numbers from 1000 to 1044 are currently used for backdoors. The code // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1043) { + if (code >= 1000 && code <= 1044) { ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); return OK; } @@ -7003,6 +7003,73 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r future.wait(); return NO_ERROR; } + + case 1044: { // Enable/Disable mirroring from one display to another + /* + * Mirror one display onto another. + * Ensure the source and destination displays are on. + * Commands: + * 0: Mirror one display to another + * 1: Disable mirroring to a previously mirrored display + * 2: Disable mirroring on previously mirrored displays + * + * Ex: + * Get the display ids: + * adb shell dumpsys SurfaceFlinger --display-id + * Mirror first display to the second: + * adb shell service call SurfaceFlinger 1044 i64 0 i64 4619827677550801152 i64 + * 4619827677550801153 + * Stop mirroring: + * adb shell service call SurfaceFlinger 1044 i64 1 + */ + + int64_t arg0 = data.readInt64(); + + switch (arg0) { + case 0: { + // Mirror arg1 to arg2 + int64_t arg1 = data.readInt64(); + int64_t arg2 = data.readInt64(); + // Enable mirroring for one display + const auto display1id = DisplayId::fromValue(arg1); + auto mirrorRoot = SurfaceComposerClient::getDefault()->mirrorDisplay( + display1id.value()); + auto id2 = DisplayId::fromValue(arg2); + const auto token2 = getPhysicalDisplayToken(*id2); + ui::LayerStack layerStack; + { + Mutex::Autolock lock(mStateLock); + sp display = getDisplayDeviceLocked(token2); + layerStack = display->getLayerStack(); + } + SurfaceComposerClient::Transaction t; + t.setDisplayLayerStack(token2, layerStack); + t.setLayer(mirrorRoot, INT_MAX); // Top-most layer + t.setLayerStack(mirrorRoot, layerStack); + t.apply(); + + mMirrorMapForDebug.emplace_or_replace(arg2, mirrorRoot); + break; + } + + case 1: { + // Disable mirroring for arg1 + int64_t arg1 = data.readInt64(); + mMirrorMapForDebug.erase(arg1); + break; + } + + case 2: { + // Disable mirroring for all displays + mMirrorMapForDebug.clear(); + break; + } + + default: + return BAD_VALUE; + } + return NO_ERROR; + } } } return err; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 4374f9408f..b07910d360 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1443,6 +1443,10 @@ private: // WindowInfo ids visible during the last commit. std::unordered_set mVisibleWindowIds; + + // Mirroring + // Map of displayid to mirrorRoot + ftl::SmallMap, 3> mMirrorMapForDebug; }; class SurfaceComposerAIDL : public gui::BnSurfaceComposer { -- GitLab From b469f43982354eb7a36c1ad80580d94f7384b3b6 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 28 Jul 2023 22:13:47 +0000 Subject: [PATCH 0369/1187] binderRpcTest: -= tuple += named values Tuple by index is hard to verify the same semantics are preserved in all places, but when we get values directly by name, local checks make it clear that we use the same semantics everywhere. This change supports optimizing these tests, so we can easily select the combinations we want to run later. Bug: 292808096 Bug: 292820454 Test: binderRpcTest Change-Id: I8cac77d631cd2bb7d5a4c47ae4bbc267b050b0ce --- libs/binder/tests/binderRpcTest.cpp | 73 ++++++++++++++----- libs/binder/tests/binderRpcTestFixture.h | 35 +++++---- libs/binder/tests/binderRpcTestTrusty.cpp | 33 ++++++--- libs/binder/tests/binderRpcUniversalTests.cpp | 2 +- 4 files changed, 101 insertions(+), 42 deletions(-) diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index d352ce5bca..bf43edcbe5 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -249,12 +249,12 @@ std::unique_ptr BinderRpc::createRpcTestSocketServerProcessEtc( CHECK_EQ(options.numIncomingConnectionsBySession.size(), options.numSessions); } - SocketType socketType = std::get<0>(GetParam()); - RpcSecurity rpcSecurity = std::get<1>(GetParam()); - uint32_t clientVersion = std::get<2>(GetParam()); - uint32_t serverVersion = std::get<3>(GetParam()); - bool singleThreaded = std::get<4>(GetParam()); - bool noKernel = std::get<5>(GetParam()); + SocketType socketType = GetParam().type; + RpcSecurity rpcSecurity = GetParam().security; + uint32_t clientVersion = GetParam().clientVersion; + uint32_t serverVersion = GetParam().serverVersion; + bool singleThreaded = GetParam().singleThreaded; + bool noKernel = GetParam().noKernel; std::string path = android::base::GetExecutableDirectory(); auto servicePath = android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(), @@ -1121,12 +1121,27 @@ TEST_P(BinderRpc, Fds) { } #ifdef BINDER_RPC_TO_TRUSTY_TEST -INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, - ::testing::Combine(::testing::Values(SocketType::TIPC), - ::testing::Values(RpcSecurity::RAW), - ::testing::ValuesIn(testVersions()), - ::testing::ValuesIn(testVersions()), - ::testing::Values(true), ::testing::Values(true)), + +static std::vector getTrustyBinderRpcParams() { + std::vector ret; + + for (const auto& clientVersion : testVersions()) { + for (const auto& serverVersion : testVersions()) { + ret.push_back(BinderRpc::ParamType{ + .type = SocketType::TIPC, + .security = RpcSecurity::RAW, + .clientVersion = clientVersion, + .serverVersion = serverVersion, + .singleThreaded = true, + .noKernel = true, + }); + } + } + + return ret; +} + +INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, ::testing::ValuesIn(getTrustyBinderRpcParams()), BinderRpc::PrintParamInfo); #else // BINDER_RPC_TO_TRUSTY_TEST bool testSupportVsockLoopback() { @@ -1246,13 +1261,33 @@ static std::vector testSocketTypes(bool hasPreconnected = true) { return ret; } -INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc, - ::testing::Combine(::testing::ValuesIn(testSocketTypes()), - ::testing::ValuesIn(RpcSecurityValues()), - ::testing::ValuesIn(testVersions()), - ::testing::ValuesIn(testVersions()), - ::testing::Values(false, true), - ::testing::Values(false, true)), +static std::vector getBinderRpcParams() { + std::vector ret; + + for (const auto& type : testSocketTypes()) { + for (const auto& security : RpcSecurityValues()) { + for (const auto& clientVersion : testVersions()) { + for (const auto& serverVersion : testVersions()) { + for (bool singleThreaded : {false, true}) { + for (bool noKernel : {false, true}) { + ret.push_back(BinderRpc::ParamType{ + .type = type, + .security = security, + .clientVersion = clientVersion, + .serverVersion = serverVersion, + .singleThreaded = singleThreaded, + .noKernel = noKernel, + }); + } + } + } + } + } + } + return ret; +} + +INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc, ::testing::ValuesIn(getBinderRpcParams()), BinderRpc::PrintParamInfo); class BinderRpcServerRootObject diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h index 0b8920b5a6..2c9646b30e 100644 --- a/libs/binder/tests/binderRpcTestFixture.h +++ b/libs/binder/tests/binderRpcTestFixture.h @@ -106,15 +106,23 @@ struct BinderRpcTestProcessSession { } }; -class BinderRpc : public ::testing::TestWithParam< - std::tuple> { +struct BinderRpcParam { + SocketType type; + RpcSecurity security; + uint32_t clientVersion; + uint32_t serverVersion; + bool singleThreaded; + bool noKernel; +}; +class BinderRpc : public ::testing::TestWithParam { public: - SocketType socketType() const { return std::get<0>(GetParam()); } - RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); } - uint32_t clientVersion() const { return std::get<2>(GetParam()); } - uint32_t serverVersion() const { return std::get<3>(GetParam()); } - bool serverSingleThreaded() const { return std::get<4>(GetParam()); } - bool noKernel() const { return std::get<5>(GetParam()); } + // TODO: avoid unnecessary layer of indirection + SocketType socketType() const { return GetParam().type; } + RpcSecurity rpcSecurity() const { return GetParam().security; } + uint32_t clientVersion() const { return GetParam().clientVersion; } + uint32_t serverVersion() const { return GetParam().serverVersion; } + bool serverSingleThreaded() const { return GetParam().singleThreaded; } + bool noKernel() const { return GetParam().noKernel; } bool clientOrServerSingleThreaded() const { return !kEnableRpcThreads || serverSingleThreaded(); @@ -148,15 +156,16 @@ public: } static std::string PrintParamInfo(const testing::TestParamInfo& info) { - auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param; - auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" + - std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion); - if (singleThreaded) { + auto ret = PrintToString(info.param.type) + "_" + + newFactory(info.param.security)->toCString() + "_clientV" + + std::to_string(info.param.clientVersion) + "_serverV" + + std::to_string(info.param.serverVersion); + if (info.param.singleThreaded) { ret += "_single_threaded"; } else { ret += "_multi_threaded"; } - if (noKernel) { + if (info.param.noKernel) { ret += "_no_kernel"; } else { ret += "_with_kernel"; diff --git a/libs/binder/tests/binderRpcTestTrusty.cpp b/libs/binder/tests/binderRpcTestTrusty.cpp index 28be10db76..fcb83bdabd 100644 --- a/libs/binder/tests/binderRpcTestTrusty.cpp +++ b/libs/binder/tests/binderRpcTestTrusty.cpp @@ -57,9 +57,9 @@ std::unique_ptr BinderRpc::createRpcTestSocketServerProcessEtc( [](size_t n) { return n != 0; }), "Non-zero incoming connections on Trusty"); - RpcSecurity rpcSecurity = std::get<1>(GetParam()); - uint32_t clientVersion = std::get<2>(GetParam()); - uint32_t serverVersion = std::get<3>(GetParam()); + RpcSecurity rpcSecurity = GetParam().security; + uint32_t clientVersion = GetParam().clientVersion; + uint32_t serverVersion = GetParam().serverVersion; auto ret = std::make_unique(); @@ -89,12 +89,27 @@ std::unique_ptr BinderRpc::createRpcTestSocketServerProcessEtc( return ret; } -INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, - ::testing::Combine(::testing::Values(SocketType::TIPC), - ::testing::Values(RpcSecurity::RAW), - ::testing::ValuesIn(testVersions()), - ::testing::ValuesIn(testVersions()), - ::testing::Values(false), ::testing::Values(true)), +static std::vector getTrustyBinderRpcParams() { + std::vector ret; + + for (const auto& clientVersion : testVersions()) { + for (const auto& serverVersion : testVersions()) { + ret.push_back(BinderRpc::ParamType{ + .type = SocketType::TIPC, + .security = RpcSecurity::RAW, + .clientVersion = clientVersion, + .serverVersion = serverVersion, + // TODO: should we test both versions here? + .singleThreaded = false, + .noKernel = true, + }); + } + } + + return ret; +} + +INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, ::testing::ValuesIn(getTrustyBinderRpcParams()), BinderRpc::PrintParamInfo); } // namespace android diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp index 1f4601010c..e43508ee79 100644 --- a/libs/binder/tests/binderRpcUniversalTests.cpp +++ b/libs/binder/tests/binderRpcUniversalTests.cpp @@ -84,7 +84,7 @@ TEST_P(BinderRpc, SeparateRootObject) { GTEST_SKIP() << "This test requires a multi-threaded service"; } - SocketType type = std::get<0>(GetParam()); + SocketType type = GetParam().type; if (type == SocketType::PRECONNECTED || type == SocketType::UNIX || type == SocketType::UNIX_BOOTSTRAP || type == SocketType::UNIX_RAW) { // we can't get port numbers for unix sockets -- GitLab From a681d7df1da3cd2ab156a68a79c56139b6983533 Mon Sep 17 00:00:00 2001 From: Kevin Jeon Date: Fri, 28 Jul 2023 18:37:32 -0400 Subject: [PATCH 0370/1187] Update IsStrictRun to be framework-only This change guards IsStrictRun using __ANDROID_VNDK__ to avoid needing to update the prebuilt ABI dumps in internal, since IsStrictRun is only needed in the framework and does not need to be made available to vendors. This avoids updating the API surface unnecessarily. Test: Cherry-pick this change to internal and verify that internal builds work without needing to update the prebuilt ABI dumps. Bug: 283326935 Change-Id: I9dfdf3306b6a9b0faa9f8f7871b1fc244bde1a97 --- cmds/dumpstate/DumpstateUtil.cpp | 4 ++++ cmds/dumpstate/DumpstateUtil.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp index 615701ccc1..484231225d 100644 --- a/cmds/dumpstate/DumpstateUtil.cpp +++ b/cmds/dumpstate/DumpstateUtil.cpp @@ -207,7 +207,9 @@ std::string PropertiesHelper::build_type_ = ""; int PropertiesHelper::dry_run_ = -1; int PropertiesHelper::unroot_ = -1; int PropertiesHelper::parallel_run_ = -1; +#if !defined(__ANDROID_VNDK__) int PropertiesHelper::strict_run_ = -1; +#endif bool PropertiesHelper::IsUserBuild() { if (build_type_.empty()) { @@ -238,6 +240,7 @@ bool PropertiesHelper::IsParallelRun() { return parallel_run_ == 1; } +#if !defined(__ANDROID_VNDK__) bool PropertiesHelper::IsStrictRun() { if (strict_run_ == -1) { // Defaults to using stricter timeouts. @@ -245,6 +248,7 @@ bool PropertiesHelper::IsStrictRun() { } return strict_run_ == 1; } +#endif int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC))); diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h index 9e955e3c04..6049e3e19d 100644 --- a/cmds/dumpstate/DumpstateUtil.h +++ b/cmds/dumpstate/DumpstateUtil.h @@ -198,14 +198,18 @@ class PropertiesHelper { * will default to true. This results in shortened timeouts for flaky * sections. */ +#if !defined(__ANDROID_VNDK__) static bool IsStrictRun(); +#endif private: static std::string build_type_; static int dry_run_; static int unroot_; static int parallel_run_; +#if !defined(__ANDROID_VNDK__) static int strict_run_; +#endif }; /* -- GitLab From 0a4981aa442449df00643e43fd6f5fed19e475d7 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Fri, 28 Jul 2023 15:08:52 -0500 Subject: [PATCH 0371/1187] Fix flaky InputSurfacesTest tests This CL updates InputSurfacesTest to use a WindowInfosReportedListener to ensure window changes have made their way to InputFlinger before injecting taps. Bug: 288344458 Test: ran each flaky test 200+ times Change-Id: Iec9de64b20750f1292ac09437dff1a747eade98c --- libs/gui/tests/EndToEndNativeInputTest.cpp | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 4d5bd5b3fa..662e9fe74a 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -24,6 +24,7 @@ #include +#include #include #include @@ -74,6 +75,26 @@ sp getInputFlinger() { static const int LAYER_BASE = INT32_MAX - 10; static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 5s; +class SynchronousWindowInfosReportedListener : public gui::BnWindowInfosReportedListener { +public: + binder::Status onWindowInfosReported() override { + std::lock_guard lock{mMutex}; + mWindowInfosReported = true; + mConditionVariable.notify_one(); + return binder::Status::ok(); + } + + void wait() { + std::unique_lock lock{mMutex}; + mConditionVariable.wait(lock, [&] { return mWindowInfosReported; }); + } + +private: + std::mutex mMutex; + std::condition_variable mConditionVariable; + bool mWindowInfosReported{false}; +}; + class InputSurface { public: InputSurface(const sp &sc, int width, int height, bool noInputChannel = false) { @@ -264,7 +285,10 @@ public: t.setPosition(mSurfaceControl, x, y); t.setCrop(mSurfaceControl, crop); t.setAlpha(mSurfaceControl, 1); - t.apply(true); + auto reportedListener = sp::make(); + t.addWindowInfosReportedListener(reportedListener); + t.apply(); + reportedListener->wait(); } void requestFocus(int displayId = ADISPLAY_ID_DEFAULT) { -- GitLab From f7421438375b98158021f7bc511c2cd074092d29 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 28 Jul 2023 22:41:44 +0000 Subject: [PATCH 0372/1187] binderRpcTest: meet presubmit SLO time Now, we only do all combinations with UNIX raw sockets, and with the other socket types, we run tests in the most common mode. This may cause some issues to be missed, but it's required to hit SLO for Android testing now. Fixes: 292808096 Fixes: 292820454 Test: binderRpcTest (which is the slowest variant) takes about 5 minutes now Change-Id: I069e633f4fce34de431595af91a6cd91e89239fb --- libs/binder/tests/binderRpcTest.cpp | 40 +++++++++++++++++++---------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index bf43edcbe5..5ed9603793 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -1264,26 +1264,40 @@ static std::vector testSocketTypes(bool hasPreconnected = true) { static std::vector getBinderRpcParams() { std::vector ret; + constexpr bool full = false; + for (const auto& type : testSocketTypes()) { - for (const auto& security : RpcSecurityValues()) { - for (const auto& clientVersion : testVersions()) { - for (const auto& serverVersion : testVersions()) { - for (bool singleThreaded : {false, true}) { - for (bool noKernel : {false, true}) { - ret.push_back(BinderRpc::ParamType{ - .type = type, - .security = security, - .clientVersion = clientVersion, - .serverVersion = serverVersion, - .singleThreaded = singleThreaded, - .noKernel = noKernel, - }); + if (full || type == SocketType::UNIX) { + for (const auto& security : RpcSecurityValues()) { + for (const auto& clientVersion : testVersions()) { + for (const auto& serverVersion : testVersions()) { + for (bool singleThreaded : {false, true}) { + for (bool noKernel : {false, true}) { + ret.push_back(BinderRpc::ParamType{ + .type = type, + .security = security, + .clientVersion = clientVersion, + .serverVersion = serverVersion, + .singleThreaded = singleThreaded, + .noKernel = noKernel, + }); + } } } } } + } else { + ret.push_back(BinderRpc::ParamType{ + .type = type, + .security = RpcSecurity::RAW, + .clientVersion = RPC_WIRE_PROTOCOL_VERSION, + .serverVersion = RPC_WIRE_PROTOCOL_VERSION, + .singleThreaded = false, + .noKernel = false, + }); } } + return ret; } -- GitLab From 21e1447a7189b2d3e17797255b6a448de11b3c00 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Sat, 29 Jul 2023 00:43:43 +0000 Subject: [PATCH 0373/1187] libbinder_ndk_unit_test: avoid race Avoid race where the test starts before the service it is testing is started. Bug: 290569617 Test: libbinder_ndk_unit_test Change-Id: I487f1ce59c6d21c87c7b54bfd721da9883f0501b --- libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 27ce615565..089e55ffb1 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -377,18 +377,24 @@ TEST(NdkBinder, CantHaveTwoLocalBinderClassesWithSameDescriptor) { } TEST(NdkBinder, GetTestServiceStressTest) { - // libbinder has some complicated logic to make sure only one instance of - // ABpBinder is associated with each binder. - constexpr size_t kNumThreads = 10; constexpr size_t kNumCalls = 1000; std::vector threads; + // this is not a lazy service, but we must make sure that it's started before calling + // checkService on it, since the other process serving it might not be started yet. + { + // getService, not waitForService, to take advantage of timeout + auto binder = ndk::SpAIBinder(AServiceManager_getService(IFoo::kSomeInstanceName)); + ASSERT_NE(nullptr, binder.get()); + } + for (size_t i = 0; i < kNumThreads; i++) { threads.push_back(std::thread([&]() { for (size_t j = 0; j < kNumCalls; j++) { auto binder = ndk::SpAIBinder(AServiceManager_checkService(IFoo::kSomeInstanceName)); + ASSERT_NE(nullptr, binder.get()); EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get())); } })); -- GitLab From d173bf6d2ecdd07003bc0ef681d400f72df689ad Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Sat, 29 Jul 2023 01:23:58 +0000 Subject: [PATCH 0374/1187] libbinder_ndk: remove dup clang-format rule Bug: N/A Test: N/A Change-Id: I089505790e90c74c9c9e2a83f869d957b86c2565 --- libs/binder/ndk/.clang-format | 2 -- 1 file changed, 2 deletions(-) diff --git a/libs/binder/ndk/.clang-format b/libs/binder/ndk/.clang-format index 9a9d936f15..60774143ee 100644 --- a/libs/binder/ndk/.clang-format +++ b/libs/binder/ndk/.clang-format @@ -2,9 +2,7 @@ BasedOnStyle: Google ColumnLimit: 100 IndentWidth: 4 ContinuationIndentWidth: 8 -PointerAlignment: Left TabWidth: 4 AllowShortFunctionsOnASingleLine: Inline PointerAlignment: Left -TabWidth: 4 UseTab: Never -- GitLab From 25b25fc6fe0e43d7bcd407c5e134374897668c90 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Sat, 29 Jul 2023 01:22:05 +0000 Subject: [PATCH 0375/1187] SpAIBinder: allow comparison with pointers It's pretty annoying to need to manually de-reference this. I fixed it on sp<> a long, long time ago, so I'm not sure why I never fixed it when I created this type. Bug: N/A Test: libbinder_ndk_unit_test Change-Id: I3143dde25ccc043ee60d85db894eb6e6aedf5690 --- .../include_cpp/android/binder_auto_utils.h | 26 ++++++++++++++----- .../ndk/tests/libbinder_ndk_unit_test.cpp | 6 ++--- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h index d6937c2c52..ed53891e3d 100644 --- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h +++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h @@ -115,17 +115,29 @@ class SpAIBinder { */ AIBinder** getR() { return &mBinder; } - bool operator!=(const SpAIBinder& rhs) const { return get() != rhs.get(); } - bool operator<(const SpAIBinder& rhs) const { return get() < rhs.get(); } - bool operator<=(const SpAIBinder& rhs) const { return get() <= rhs.get(); } - bool operator==(const SpAIBinder& rhs) const { return get() == rhs.get(); } - bool operator>(const SpAIBinder& rhs) const { return get() > rhs.get(); } - bool operator>=(const SpAIBinder& rhs) const { return get() >= rhs.get(); } - private: AIBinder* mBinder = nullptr; }; +#define SP_AIBINDER_COMPARE(_op_) \ + static inline bool operator _op_(const SpAIBinder& lhs, const SpAIBinder& rhs) { \ + return lhs.get() _op_ rhs.get(); \ + } \ + static inline bool operator _op_(const SpAIBinder& lhs, const AIBinder* rhs) { \ + return lhs.get() _op_ rhs; \ + } \ + static inline bool operator _op_(const AIBinder* lhs, const SpAIBinder& rhs) { \ + return lhs _op_ rhs.get(); \ + } + +SP_AIBINDER_COMPARE(!=) +SP_AIBINDER_COMPARE(<) +SP_AIBINDER_COMPARE(<=) +SP_AIBINDER_COMPARE(==) +SP_AIBINDER_COMPARE(>) +SP_AIBINDER_COMPARE(>=) +#undef SP_AIBINDER_COMPARE + namespace impl { /** diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 27ce615565..1b61e702b8 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -755,9 +755,9 @@ TEST(NdkBinder, ConvertToPlatformBinder) { // local ndk::SharedRefBase::make()->asBinder()}) { // convert to platform binder - EXPECT_NE(binder.get(), nullptr); + EXPECT_NE(binder, nullptr); sp platformBinder = AIBinder_toPlatformBinder(binder.get()); - EXPECT_NE(platformBinder.get(), nullptr); + EXPECT_NE(platformBinder, nullptr); auto proxy = interface_cast(platformBinder); EXPECT_NE(proxy, nullptr); @@ -768,7 +768,7 @@ TEST(NdkBinder, ConvertToPlatformBinder) { // convert back ndk::SpAIBinder backBinder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(platformBinder)); - EXPECT_EQ(backBinder.get(), binder.get()); + EXPECT_EQ(backBinder, binder); } } -- GitLab From d074638dacd55a4030d97541d18bbafa030361b6 Mon Sep 17 00:00:00 2001 From: Josep del Rio Date: Sat, 29 Jul 2023 13:18:25 +0000 Subject: [PATCH 0376/1187] Allow touchpads to expose associated display After landing ag/24209603, a touchpad test started failing; the reason is that the device never exposed the associated display id, even though it became associated to a viewport. This CL makes the necessary changes so the associated display id is properly propagated. Bug: 293488187 Test: atest of the failing test Change-Id: Ia1480012bd339de92abd284c6d00f7ac93505735 --- .../reader/mapper/TouchpadInputMapper.cpp | 39 ++- .../reader/mapper/TouchpadInputMapper.h | 7 + .../mapper/gestures/GestureConverter.cpp | 7 +- .../reader/mapper/gestures/GestureConverter.h | 3 + .../tests/GestureConverter_test.cpp | 291 +++++++++++------- 5 files changed, 233 insertions(+), 114 deletions(-) diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp index 986dabb6fc..eca0f86794 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp @@ -350,6 +350,7 @@ void TouchpadInputMapper::dump(std::string& dump) { dump += addLinePrefix(mPropertyProvider.dump(), INDENT4); dump += INDENT3 "Captured event converter:\n"; dump += addLinePrefix(mCapturedEventConverter.dump(), INDENT4); + dump += StringPrintf(INDENT3 "DisplayId: %s\n", toString(mDisplayId).c_str()); } std::list TouchpadInputMapper::reconfigure(nsecs_t when, @@ -361,13 +362,31 @@ std::list TouchpadInputMapper::reconfigure(nsecs_t when, } if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO)) { - std::optional displayId = mPointerController->getDisplayId(); + mDisplayId = ADISPLAY_ID_NONE; + if (auto viewport = mDeviceContext.getAssociatedViewport(); viewport) { + // This InputDevice is associated with a viewport. + // Only generate events for the associated display. + const bool mismatchedPointerDisplay = + (viewport->displayId != mPointerController->getDisplayId()); + if (mismatchedPointerDisplay) { + ALOGW("Touchpad \"%s\" associated viewport display does not match pointer " + "controller", + mDeviceContext.getName().c_str()); + } + mDisplayId = mismatchedPointerDisplay ? std::nullopt + : std::make_optional(viewport->displayId); + } else { + // The InputDevice is not associated with a viewport, but it controls the mouse pointer. + mDisplayId = mPointerController->getDisplayId(); + } + ui::Rotation orientation = ui::ROTATION_0; - if (displayId.has_value()) { - if (auto viewport = config.getDisplayViewportById(*displayId); viewport) { + if (mDisplayId.has_value()) { + if (auto viewport = config.getDisplayViewportById(*mDisplayId); viewport) { orientation = getInverseRotation(viewport->orientation); } } + mGestureConverter.setDisplayId(mDisplayId); mGestureConverter.setOrientation(orientation); } if (!changes.any() || changes.test(InputReaderConfiguration::Change::TOUCHPAD_SETTINGS)) { @@ -497,13 +516,19 @@ void TouchpadInputMapper::consumeGesture(const Gesture* gesture) { std::list TouchpadInputMapper::processGestures(nsecs_t when, nsecs_t readTime) { std::list out = {}; - MetricsAccumulator& metricsAccumulator = MetricsAccumulator::getInstance(); - for (Gesture& gesture : mGesturesToProcess) { - out += mGestureConverter.handleGesture(when, readTime, gesture); - metricsAccumulator.processGesture(mMetricsId, gesture); + if (mDisplayId) { + MetricsAccumulator& metricsAccumulator = MetricsAccumulator::getInstance(); + for (Gesture& gesture : mGesturesToProcess) { + out += mGestureConverter.handleGesture(when, readTime, gesture); + metricsAccumulator.processGesture(mMetricsId, gesture); + } } mGesturesToProcess.clear(); return out; } +std::optional TouchpadInputMapper::getAssociatedDisplayId() { + return mDisplayId; +} + } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h index 73ca5afa04..47d712ef27 100644 --- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h @@ -64,6 +64,8 @@ public: using MetricsIdentifier = std::tuple; + std::optional getAssociatedDisplayId() override; + private: void resetGestureInterpreter(nsecs_t when); explicit TouchpadInputMapper(InputDeviceContext& deviceContext, @@ -102,6 +104,11 @@ private: std::set mLastFrameTrackingIds; // Tracking IDs for touches that have at some point been reported as palms by the touchpad. std::set mPalmTrackingIds; + + // The display that events generated by this mapper should target. This can be set to + // ADISPLAY_ID_NONE to target the focused display. If there is no display target (i.e. + // std::nullopt), all events will be ignored. + std::optional mDisplayId; }; } // namespace android diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp index 3abf2bd60b..7006e9efc1 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp @@ -124,6 +124,11 @@ void GestureConverter::populateMotionRanges(InputDeviceInfo& info) const { std::list GestureConverter::handleGesture(nsecs_t when, nsecs_t readTime, const Gesture& gesture) { + if (!mDisplayId) { + // Ignore gestures when there is no target display configured. + return {}; + } + switch (gesture.type) { case kGestureTypeMove: return {handleMove(when, readTime, gesture)}; @@ -556,7 +561,7 @@ NotifyMotionArgs GestureConverter::makeMotionArgs(nsecs_t when, nsecs_t readTime readTime, mDeviceId, SOURCE, - mPointerController->getDisplayId(), + *mDisplayId, /* policyFlags= */ POLICY_FLAG_WAKE, action, /* actionButton= */ actionButton, diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h index 3ea3790620..e6cf617500 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h @@ -46,6 +46,8 @@ public: void setOrientation(ui::Rotation orientation) { mOrientation = orientation; } [[nodiscard]] std::list reset(nsecs_t when); + void setDisplayId(std::optional displayId) { mDisplayId = displayId; } + void populateMotionRanges(InputDeviceInfo& info) const; [[nodiscard]] std::list handleGesture(nsecs_t when, nsecs_t readTime, @@ -84,6 +86,7 @@ private: InputReaderContext& mReaderContext; std::shared_ptr mPointerController; + std::optional mDisplayId; ui::Rotation mOrientation = ui::ROTATION_0; RawAbsoluteAxisInfo mXAxisInfo; RawAbsoluteAxisInfo mYAxisInfo; diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp index 4df0f69481..74ce359cac 100644 --- a/services/inputflinger/tests/GestureConverter_test.cpp +++ b/services/inputflinger/tests/GestureConverter_test.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "FakeEventHub.h" #include "FakeInputReaderPolicy.h" @@ -85,6 +86,7 @@ protected: TEST_F(GestureConverterTest, Move) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); std::list args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, moveGesture); @@ -93,8 +95,8 @@ TEST_F(GestureConverterTest, Move) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(POINTER_X - 5, POINTER_Y + 10), WithRelativeMotion(-5, 10), - WithToolType(ToolType::FINGER), WithButtonState(0), - WithPressure(0.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 5, POINTER_Y + 10)); } @@ -103,6 +105,7 @@ TEST_F(GestureConverterTest, Move_Rotated) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setOrientation(ui::ROTATION_90); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); std::list args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, moveGesture); @@ -111,8 +114,8 @@ TEST_F(GestureConverterTest, Move_Rotated) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(POINTER_X + 10, POINTER_Y + 5), WithRelativeMotion(10, 5), - WithToolType(ToolType::FINGER), WithButtonState(0), - WithPressure(0.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X + 10, POINTER_Y + 5)); } @@ -120,6 +123,7 @@ TEST_F(GestureConverterTest, Move_Rotated) { TEST_F(GestureConverterTest, ButtonsChange) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); // Press left and right buttons at once Gesture downGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, @@ -132,23 +136,23 @@ TEST_F(GestureConverterTest, ButtonsChange) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY), - WithCoords(POINTER_X, POINTER_Y), - WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), - WithCoords(POINTER_X, POINTER_Y), - WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY), - WithCoords(POINTER_X, POINTER_Y), - WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); // Then release the left button Gesture leftUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, @@ -161,8 +165,8 @@ TEST_F(GestureConverterTest, ButtonsChange) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), - WithCoords(POINTER_X, POINTER_Y), - WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); // Finally release the right button Gesture rightUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, @@ -174,22 +178,24 @@ TEST_F(GestureConverterTest, ButtonsChange) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(0), - WithCoords(POINTER_X, POINTER_Y), - WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0), - WithCoords(POINTER_X, POINTER_Y), - WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithButtonState(0), - WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, DragWithButton) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); // Press the button Gesture downGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, @@ -201,15 +207,15 @@ TEST_F(GestureConverterTest, DragWithButton) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), - WithCoords(POINTER_X, POINTER_Y), - WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), - WithCoords(POINTER_X, POINTER_Y), - WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); // Move Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); @@ -219,8 +225,8 @@ TEST_F(GestureConverterTest, DragWithButton) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(POINTER_X - 5, POINTER_Y + 10), WithRelativeMotion(-5, 10), - WithToolType(ToolType::FINGER), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f))); + WithToolType(ToolType::FINGER), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), + WithPressure(1.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 5, POINTER_Y + 10)); @@ -234,23 +240,25 @@ TEST_F(GestureConverterTest, DragWithButton) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(0), - WithCoords(POINTER_X - 5, POINTER_Y + 10), - WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X - 5, POINTER_Y + 10), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0), - WithCoords(POINTER_X - 5, POINTER_Y + 10), - WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X - 5, POINTER_Y + 10), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithButtonState(0), - WithCoords(POINTER_X - 5, POINTER_Y + 10), WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X - 5, POINTER_Y + 10), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, Scroll) { const nsecs_t downTime = 12345; InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); std::list args = converter.handleGesture(downTime, READ_TIME, startGesture); @@ -261,7 +269,8 @@ TEST_F(GestureConverterTest, Scroll) { WithGestureScrollDistance(0, 0, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), WithToolType(ToolType::FINGER), WithDownTime(downTime), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))); + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), @@ -269,7 +278,8 @@ TEST_F(GestureConverterTest, Scroll) { WithGestureScrollDistance(0, 10, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), WithToolType(ToolType::FINGER), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))); + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))); Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5); args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); @@ -280,7 +290,8 @@ TEST_F(GestureConverterTest, Scroll) { WithGestureScrollDistance(0, 5, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), WithToolType(ToolType::FINGER), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))); + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, GESTURES_FLING_START); @@ -292,7 +303,8 @@ TEST_F(GestureConverterTest, Scroll) { WithGestureScrollDistance(0, 0, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), WithToolType(ToolType::FINGER), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))); + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, Scroll_Rotated) { @@ -300,6 +312,7 @@ TEST_F(GestureConverterTest, Scroll_Rotated) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setOrientation(ui::ROTATION_90); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); std::list args = converter.handleGesture(downTime, READ_TIME, startGesture); @@ -309,14 +322,15 @@ TEST_F(GestureConverterTest, Scroll_Rotated) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y), WithGestureScrollDistance(0, 0, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER), WithDownTime(downTime))); + WithToolType(ToolType::FINGER), WithDownTime(downTime), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(POINTER_X - 10, POINTER_Y), WithGestureScrollDistance(0, 10, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); Gesture continueGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -5); args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, continueGesture); @@ -326,7 +340,7 @@ TEST_F(GestureConverterTest, Scroll_Rotated) { WithCoords(POINTER_X - 15, POINTER_Y), WithGestureScrollDistance(0, 5, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 1, 1, GESTURES_FLING_START); @@ -337,12 +351,13 @@ TEST_F(GestureConverterTest, Scroll_Rotated) { WithCoords(POINTER_X - 15, POINTER_Y), WithGestureScrollDistance(0, 0, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, Scroll_ClearsClassificationAfterGesture) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); std::list args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); @@ -358,12 +373,14 @@ TEST_F(GestureConverterTest, Scroll_ClearsClassificationAfterGesture) { args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, moveGesture); ASSERT_EQ(1u, args.size()); EXPECT_THAT(std::get(args.front()), - WithMotionClassification(MotionClassification::NONE)); + AllOf(WithMotionClassification(MotionClassification::NONE), + WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, Scroll_ClearsScrollDistanceAfterGesture) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); std::list args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); @@ -387,6 +404,7 @@ TEST_F(GestureConverterTest, Scroll_ClearsScrollDistanceAfterGesture) { TEST_F(GestureConverterTest, ThreeFingerSwipe_ClearsClassificationAfterGesture) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/0); @@ -406,6 +424,7 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_ClearsClassificationAfterGesture) TEST_F(GestureConverterTest, ThreeFingerSwipe_ClearsGestureAxesAfterGesture) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/5, /*dy=*/5); @@ -431,6 +450,7 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { // only checks movement in one dimension. InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 0, /* dy= */ 10); @@ -444,7 +464,8 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(3), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(ToolType::FINGER))); + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); PointerCoords finger0Start = arg.pointerCoords[0]; args.pop_front(); arg = std::get(args.front()); @@ -453,7 +474,8 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(3), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(ToolType::FINGER))); + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); PointerCoords finger1Start = arg.pointerCoords[1]; args.pop_front(); arg = std::get(args.front()); @@ -462,7 +484,8 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(3), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(ToolType::FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); PointerCoords finger2Start = arg.pointerCoords[2]; args.pop_front(); @@ -471,7 +494,8 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithGestureOffset(0, -0.01, EPSILON), WithGestureSwipeFingerCount(3), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(ToolType::FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX()); EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX()); EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX()); @@ -488,7 +512,8 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithGestureOffset(0, -0.005, EPSILON), WithGestureSwipeFingerCount(3), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(ToolType::FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX()); EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX()); EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX()); @@ -504,26 +529,30 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Vertical) { 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(3), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(ToolType::FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(3), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(ToolType::FINGER))); + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(3), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(ToolType::FINGER))); + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, ThreeFingerSwipe_Rotated) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); converter.setOrientation(ui::ROTATION_90); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 0, /* dy= */ 10); @@ -535,28 +564,31 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Rotated) { NotifyMotionArgs arg = std::get(args.front()); ASSERT_THAT(arg, AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithGestureOffset(0, 0, EPSILON), - WithPointerCount(1u))); + WithPointerCount(1u), WithDisplayId(ADISPLAY_ID_DEFAULT))); PointerCoords finger0Start = arg.pointerCoords[0]; args.pop_front(); arg = std::get(args.front()); ASSERT_THAT(arg, AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithPointerCount(2u))); + WithGestureOffset(0, 0, EPSILON), WithPointerCount(2u), + WithDisplayId(ADISPLAY_ID_DEFAULT))); PointerCoords finger1Start = arg.pointerCoords[1]; args.pop_front(); arg = std::get(args.front()); ASSERT_THAT(arg, AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithPointerCount(3u))); + WithGestureOffset(0, 0, EPSILON), WithPointerCount(3u), + WithDisplayId(ADISPLAY_ID_DEFAULT))); PointerCoords finger2Start = arg.pointerCoords[2]; args.pop_front(); arg = std::get(args.front()); ASSERT_THAT(arg, AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithGestureOffset(0, -0.01, EPSILON), WithPointerCount(3u))); + WithGestureOffset(0, -0.01, EPSILON), WithPointerCount(3u), + WithDisplayId(ADISPLAY_ID_DEFAULT))); EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX() - 10); EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX() - 10); EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX() - 10); @@ -571,7 +603,8 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Rotated) { arg = std::get(args.front()); ASSERT_THAT(arg, AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithGestureOffset(0, -0.005, EPSILON), WithPointerCount(3u))); + WithGestureOffset(0, -0.005, EPSILON), WithPointerCount(3u), + WithDisplayId(ADISPLAY_ID_DEFAULT))); EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX() - 15); EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX() - 15); EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX() - 15); @@ -585,21 +618,24 @@ TEST_F(GestureConverterTest, ThreeFingerSwipe_Rotated) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithPointerCount(3u))); + WithGestureOffset(0, 0, EPSILON), WithPointerCount(3u), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), - WithGestureOffset(0, 0, EPSILON), WithPointerCount(2u))); + WithGestureOffset(0, 0, EPSILON), WithPointerCount(2u), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), - WithPointerCount(1u))); + WithPointerCount(1u), WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureFourFingerSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dx= */ 10, /* dy= */ 0); @@ -613,7 +649,8 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(ToolType::FINGER))); + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); PointerCoords finger0Start = arg.pointerCoords[0]; args.pop_front(); arg = std::get(args.front()); @@ -622,7 +659,8 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(ToolType::FINGER))); + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); PointerCoords finger1Start = arg.pointerCoords[1]; args.pop_front(); arg = std::get(args.front()); @@ -631,7 +669,8 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(ToolType::FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); PointerCoords finger2Start = arg.pointerCoords[2]; args.pop_front(); arg = std::get(args.front()); @@ -640,7 +679,8 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { 3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(4u), WithToolType(ToolType::FINGER))); + WithPointerCount(4u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); PointerCoords finger3Start = arg.pointerCoords[3]; args.pop_front(); @@ -649,7 +689,8 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithGestureOffset(0.01, 0, EPSILON), WithGestureSwipeFingerCount(4), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(4u), WithToolType(ToolType::FINGER))); + WithPointerCount(4u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX() + 10); EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX() + 10); EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX() + 10); @@ -668,7 +709,8 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithGestureOffset(0.005, 0, EPSILON), WithGestureSwipeFingerCount(4), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(4u), WithToolType(ToolType::FINGER))); + WithPointerCount(4u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); EXPECT_EQ(arg.pointerCoords[0].getX(), finger0Start.getX() + 15); EXPECT_EQ(arg.pointerCoords[1].getX(), finger1Start.getX() + 15); EXPECT_EQ(arg.pointerCoords[2].getX(), finger2Start.getX() + 15); @@ -686,32 +728,37 @@ TEST_F(GestureConverterTest, FourFingerSwipe_Horizontal) { 3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(4u), WithToolType(ToolType::FINGER))); + WithPointerCount(4u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(ToolType::FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(ToolType::FINGER))); + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), WithGestureSwipeFingerCount(4), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(ToolType::FINGER))); + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, Pinch_Inwards) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_START); @@ -722,7 +769,7 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithCoords(POINTER_X - 100, POINTER_Y), WithPointerCount(1u), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | @@ -730,7 +777,7 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCoords(1, POINTER_X + 100, POINTER_Y), WithPointerCount(2u), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 0.8, GESTURES_ZOOM_UPDATE); @@ -742,7 +789,7 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { WithGesturePinchScaleFactor(0.8f, EPSILON), WithPointerCoords(0, POINTER_X - 80, POINTER_Y), WithPointerCoords(1, POINTER_X + 80, POINTER_Y), WithPointerCount(2u), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_END); @@ -753,18 +800,19 @@ TEST_F(GestureConverterTest, Pinch_Inwards) { 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, Pinch_Outwards) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_START); @@ -775,7 +823,7 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithCoords(POINTER_X - 100, POINTER_Y), WithPointerCount(1u), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | @@ -783,7 +831,7 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCoords(1, POINTER_X + 100, POINTER_Y), WithPointerCount(2u), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); Gesture updateGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1.2, GESTURES_ZOOM_UPDATE); @@ -795,7 +843,7 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { WithGesturePinchScaleFactor(1.2f, EPSILON), WithPointerCoords(0, POINTER_X - 120, POINTER_Y), WithPointerCoords(1, POINTER_X + 120, POINTER_Y), WithPointerCount(2u), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); Gesture endGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* dz= */ 1, GESTURES_ZOOM_END); @@ -806,18 +854,19 @@ TEST_F(GestureConverterTest, Pinch_Outwards) { 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, Pinch_ClearsClassificationAfterGesture) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_START); @@ -841,6 +890,7 @@ TEST_F(GestureConverterTest, Pinch_ClearsClassificationAfterGesture) { TEST_F(GestureConverterTest, Pinch_ClearsScaleFactorAfterGesture) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_START); @@ -866,6 +916,7 @@ TEST_F(GestureConverterTest, Pinch_ClearsScaleFactorAfterGesture) { TEST_F(GestureConverterTest, ResetWithButtonPressed) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture downGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*down=*/GESTURES_BUTTON_LEFT | GESTURES_BUTTON_RIGHT, @@ -879,24 +930,25 @@ TEST_F(GestureConverterTest, ResetWithButtonPressed) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY), - WithCoords(POINTER_X, POINTER_Y), - WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); EXPECT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(0), - WithCoords(POINTER_X, POINTER_Y), - WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithButtonState(0), - WithCoords(POINTER_X, POINTER_Y), - WithToolType(ToolType::FINGER))); + WithCoords(POINTER_X, POINTER_Y), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, ResetDuringScroll) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureScroll, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, 0, -10); (void)converter.handleGesture(ARBITRARY_TIME, READ_TIME, startGesture); @@ -909,12 +961,14 @@ TEST_F(GestureConverterTest, ResetDuringScroll) { WithGestureScrollDistance(0, 0, EPSILON), WithMotionClassification(MotionClassification::TWO_FINGER_SWIPE), WithToolType(ToolType::FINGER), - WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE))); + WithFlags(AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE), + WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, ResetDuringThreeFingerSwipe) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGestureSwipe, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dx=*/0, /*dy=*/10); @@ -927,24 +981,28 @@ TEST_F(GestureConverterTest, ResetDuringThreeFingerSwipe) { 2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(3u), WithToolType(ToolType::FINGER))); + WithPointerCount(3u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); EXPECT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(2u), WithToolType(ToolType::FINGER))); + WithPointerCount(2u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); EXPECT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithGestureOffset(0, 0, EPSILON), WithMotionClassification(MotionClassification::MULTI_FINGER_SWIPE), - WithPointerCount(1u), WithToolType(ToolType::FINGER))); + WithPointerCount(1u), WithToolType(ToolType::FINGER), + WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, ResetDuringPinch) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture startGesture(kGesturePinch, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*dz=*/1, GESTURES_ZOOM_START); @@ -957,18 +1015,19 @@ TEST_F(GestureConverterTest, ResetDuringPinch) { 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(2u), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); EXPECT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithMotionClassification(MotionClassification::PINCH), WithGesturePinchScaleFactor(1.0f, EPSILON), WithPointerCount(1u), - WithToolType(ToolType::FINGER))); + WithToolType(ToolType::FINGER), WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, FlingTapDown) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture tapDownGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /*vx=*/0.f, /*vy=*/0.f, GESTURES_FLING_TAP_DOWN); @@ -977,7 +1036,8 @@ TEST_F(GestureConverterTest, FlingTapDown) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X, POINTER_Y)); ASSERT_TRUE(mFakePointerController->isPointerShown()); @@ -987,6 +1047,7 @@ TEST_F(GestureConverterTest, Tap) { // Tap should produce button press/release events InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0, /* vy= */ 0, GESTURES_FLING_TAP_DOWN); @@ -996,7 +1057,8 @@ TEST_F(GestureConverterTest, Tap) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); Gesture tapGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* down= */ GESTURES_BUTTON_LEFT, @@ -1007,7 +1069,8 @@ TEST_F(GestureConverterTest, Tap) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f))); + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), @@ -1015,29 +1078,32 @@ TEST_F(GestureConverterTest, Tap) { WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), - WithPressure(1.0f))); + WithPressure(1.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(0), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(1.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(1.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(0), WithPressure(0.0f))); + WithButtonState(0), WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, Click) { // Click should produce button press/release events InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0, /* vy= */ 0, GESTURES_FLING_TAP_DOWN); @@ -1047,7 +1113,8 @@ TEST_F(GestureConverterTest, Click) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); Gesture buttonDownGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* down= */ GESTURES_BUTTON_LEFT, @@ -1058,7 +1125,8 @@ TEST_F(GestureConverterTest, Click) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f))); + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), @@ -1066,7 +1134,7 @@ TEST_F(GestureConverterTest, Click) { WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), - WithPressure(1.0f))); + WithPressure(1.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); Gesture buttonUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* down= */ GESTURES_BUTTON_NONE, @@ -1078,17 +1146,19 @@ TEST_F(GestureConverterTest, Click) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(0), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(1.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(1.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(0), WithPressure(0.0f))); + WithButtonState(0), WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); } TEST_F(GestureConverterTest, TapWithTapToClickDisabled) { @@ -1097,6 +1167,7 @@ TEST_F(GestureConverterTest, TapWithTapToClickDisabled) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0, /* vy= */ 0, GESTURES_FLING_TAP_DOWN); @@ -1106,7 +1177,8 @@ TEST_F(GestureConverterTest, TapWithTapToClickDisabled) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); Gesture tapGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, @@ -1127,6 +1199,7 @@ TEST_F(GestureConverterTest, ClickWithTapToClickDisabled) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture flingGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* vx= */ 0, /* vy= */ 0, GESTURES_FLING_TAP_DOWN); @@ -1136,7 +1209,8 @@ TEST_F(GestureConverterTest, ClickWithTapToClickDisabled) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); Gesture buttonDownGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* down= */ GESTURES_BUTTON_LEFT, @@ -1147,7 +1221,8 @@ TEST_F(GestureConverterTest, ClickWithTapToClickDisabled) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f))); + WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithPressure(1.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), @@ -1155,7 +1230,7 @@ TEST_F(GestureConverterTest, ClickWithTapToClickDisabled) { WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY), - WithPressure(1.0f))); + WithPressure(1.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); Gesture buttonUpGesture(kGestureButtonsChange, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, /* down= */ GESTURES_BUTTON_NONE, @@ -1167,17 +1242,19 @@ TEST_F(GestureConverterTest, ClickWithTapToClickDisabled) { AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), WithButtonState(0), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(1.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(1.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f), WithToolType(ToolType::FINGER), - WithButtonState(0), WithPressure(0.0f))); + WithButtonState(0), WithPressure(0.0f), WithDisplayId(ADISPLAY_ID_DEFAULT))); args.pop_front(); ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0, 0), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); // Future taps should be re-enabled ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); @@ -1189,6 +1266,7 @@ TEST_F(GestureConverterTest, MoveEnablesTapToClick) { InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID); GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID); + converter.setDisplayId(ADISPLAY_ID_DEFAULT); Gesture moveGesture(kGestureMove, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME, -5, 10); std::list args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, moveGesture); @@ -1197,7 +1275,8 @@ TEST_F(GestureConverterTest, MoveEnablesTapToClick) { ASSERT_THAT(std::get(args.front()), AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE), WithCoords(POINTER_X - 5, POINTER_Y + 10), WithRelativeMotion(-5, 10), - WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f))); + WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f), + WithDisplayId(ADISPLAY_ID_DEFAULT))); ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X - 5, POINTER_Y + 10)); -- GitLab From 624375fd4fb8d3075fa6a8535201e5b6ca270adf Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Mon, 24 Jul 2023 22:45:44 +0000 Subject: [PATCH 0377/1187] BQ: Fix deadlock introduced by onFrameDequeued BufferQueueCore::mMutex should never be locked when calling consumerListener's callbacks. The reason is that the consumerListener callback could in turn acquire BufferQueueCore::mMutex, resulting in deadlock. The deadlock stack trace for onFrameDequeued is: - BufferQueueProduer::dequeueBuffer acquires Core::mMutex - ProxyConsumerListener::onFrameDequeued::onFrameDequeued promotes a ConsumerListener wp to sp - The sp becomes the last reference to the ConsumerListener object, when onFrameDequeued() goes out of scope, ~ConsumerListener is called - BufferQueueConsumer::disconnect is called as part of ~ConsumerListener(), and disconnect needs to acquire Core::mMutex The same issue applies to onFrameCancelled and onFrameDetached. Test: atest BufferQueueThreading::TestProducerDequeueConsumerDestroy Bug: 270004534 Change-Id: I22fdc637ccc937594656d6f5bc1ee9b7c506490a --- libs/gui/BufferQueueProducer.cpp | 126 +++++++++++++++++++------------ 1 file changed, 76 insertions(+), 50 deletions(-) diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 808388fca3..b872541fec 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -418,6 +418,9 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp* ou EGLSyncKHR eglFence = EGL_NO_SYNC_KHR; bool attachedByConsumer = false; + sp listener; + bool callOnFrameDequeued = false; + uint64_t bufferId = 0; // Only used if callOnFrameDequeued == true { // Autolock scope std::unique_lock lock(mCore->mMutex); @@ -561,10 +564,11 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp* ou } if (!(returnFlags & BUFFER_NEEDS_REALLOCATION)) { - if (mCore->mConsumerListener != nullptr) { - mCore->mConsumerListener->onFrameDequeued(mSlots[*outSlot].mGraphicBuffer->getId()); - } + callOnFrameDequeued = true; + bufferId = mSlots[*outSlot].mGraphicBuffer->getId(); } + + listener = mCore->mConsumerListener; } // Autolock scope if (returnFlags & BUFFER_NEEDS_REALLOCATION) { @@ -581,10 +585,8 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp* ou if (error == NO_ERROR && !mCore->mIsAbandoned) { graphicBuffer->setGenerationNumber(mCore->mGenerationNumber); mSlots[*outSlot].mGraphicBuffer = graphicBuffer; - if (mCore->mConsumerListener != nullptr) { - mCore->mConsumerListener->onFrameDequeued( - mSlots[*outSlot].mGraphicBuffer->getId()); - } + callOnFrameDequeued = true; + bufferId = mSlots[*outSlot].mGraphicBuffer->getId(); } mCore->mIsAllocating = false; @@ -608,6 +610,10 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp* ou } // Autolock scope } + if (listener != nullptr && callOnFrameDequeued) { + listener->onFrameDequeued(bufferId); + } + if (attachedByConsumer) { returnFlags |= BUFFER_NEEDS_REALLOCATION; } @@ -647,6 +653,8 @@ status_t BufferQueueProducer::detachBuffer(int slot) { BQ_LOGV("detachBuffer: slot %d", slot); sp listener; + bool callOnFrameDetached = false; + uint64_t bufferId = 0; // Only used if callOnFrameDetached is true { std::lock_guard lock(mCore->mMutex); @@ -684,8 +692,9 @@ status_t BufferQueueProducer::detachBuffer(int slot) { listener = mCore->mConsumerListener; auto gb = mSlots[slot].mGraphicBuffer; - if (listener != nullptr && gb != nullptr) { - listener->onFrameDetached(gb->getId()); + if (gb != nullptr) { + callOnFrameDetached = true; + bufferId = gb->getId(); } mSlots[slot].mBufferState.detachProducer(); mCore->mActiveBuffers.erase(slot); @@ -695,6 +704,10 @@ status_t BufferQueueProducer::detachBuffer(int slot) { VALIDATE_CONSISTENCY(); } + if (listener != nullptr && callOnFrameDetached) { + listener->onFrameDetached(bufferId); + } + if (listener != nullptr) { listener->onBuffersReleased(); } @@ -1105,57 +1118,70 @@ status_t BufferQueueProducer::queueBuffer(int slot, status_t BufferQueueProducer::cancelBuffer(int slot, const sp& fence) { ATRACE_CALL(); BQ_LOGV("cancelBuffer: slot %d", slot); - std::lock_guard lock(mCore->mMutex); - if (mCore->mIsAbandoned) { - BQ_LOGE("cancelBuffer: BufferQueue has been abandoned"); - return NO_INIT; - } + sp listener; + bool callOnFrameCancelled = false; + uint64_t bufferId = 0; // Only used if callOnFrameCancelled == true + { + std::lock_guard lock(mCore->mMutex); - if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { - BQ_LOGE("cancelBuffer: BufferQueue has no connected producer"); - return NO_INIT; - } + if (mCore->mIsAbandoned) { + BQ_LOGE("cancelBuffer: BufferQueue has been abandoned"); + return NO_INIT; + } - if (mCore->mSharedBufferMode) { - BQ_LOGE("cancelBuffer: cannot cancel a buffer in shared buffer mode"); - return BAD_VALUE; - } + if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { + BQ_LOGE("cancelBuffer: BufferQueue has no connected producer"); + return NO_INIT; + } - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)", - slot, BufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } else if (!mSlots[slot].mBufferState.isDequeued()) { - BQ_LOGE("cancelBuffer: slot %d is not owned by the producer " - "(state = %s)", slot, mSlots[slot].mBufferState.string()); - return BAD_VALUE; - } else if (fence == nullptr) { - BQ_LOGE("cancelBuffer: fence is NULL"); - return BAD_VALUE; - } + if (mCore->mSharedBufferMode) { + BQ_LOGE("cancelBuffer: cannot cancel a buffer in shared buffer mode"); + return BAD_VALUE; + } + + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { + BQ_LOGE("cancelBuffer: slot index %d out of range [0, %d)", slot, + BufferQueueDefs::NUM_BUFFER_SLOTS); + return BAD_VALUE; + } else if (!mSlots[slot].mBufferState.isDequeued()) { + BQ_LOGE("cancelBuffer: slot %d is not owned by the producer " + "(state = %s)", + slot, mSlots[slot].mBufferState.string()); + return BAD_VALUE; + } else if (fence == nullptr) { + BQ_LOGE("cancelBuffer: fence is NULL"); + return BAD_VALUE; + } - mSlots[slot].mBufferState.cancel(); + mSlots[slot].mBufferState.cancel(); - // After leaving shared buffer mode, the shared buffer will still be around. - // Mark it as no longer shared if this operation causes it to be free. - if (!mCore->mSharedBufferMode && mSlots[slot].mBufferState.isFree()) { - mSlots[slot].mBufferState.mShared = false; - } + // After leaving shared buffer mode, the shared buffer will still be around. + // Mark it as no longer shared if this operation causes it to be free. + if (!mCore->mSharedBufferMode && mSlots[slot].mBufferState.isFree()) { + mSlots[slot].mBufferState.mShared = false; + } - // Don't put the shared buffer on the free list. - if (!mSlots[slot].mBufferState.isShared()) { - mCore->mActiveBuffers.erase(slot); - mCore->mFreeBuffers.push_back(slot); + // Don't put the shared buffer on the free list. + if (!mSlots[slot].mBufferState.isShared()) { + mCore->mActiveBuffers.erase(slot); + mCore->mFreeBuffers.push_back(slot); + } + + auto gb = mSlots[slot].mGraphicBuffer; + if (gb != nullptr) { + callOnFrameCancelled = true; + bufferId = gb->getId(); + } + mSlots[slot].mFence = fence; + mCore->mDequeueCondition.notify_all(); + listener = mCore->mConsumerListener; + VALIDATE_CONSISTENCY(); } - auto gb = mSlots[slot].mGraphicBuffer; - if (mCore->mConsumerListener != nullptr && gb != nullptr) { - mCore->mConsumerListener->onFrameCancelled(gb->getId()); + if (listener != nullptr && callOnFrameCancelled) { + listener->onFrameCancelled(bufferId); } - mSlots[slot].mFence = fence; - mCore->mDequeueCondition.notify_all(); - VALIDATE_CONSISTENCY(); return NO_ERROR; } -- GitLab From 12daff94ce51c27f2407e20eddcd07dd5d50537d Mon Sep 17 00:00:00 2001 From: John Reck Date: Fri, 28 Jul 2023 16:36:27 -0400 Subject: [PATCH 0378/1187] Add dequeue deadlock test for consumer listener Test: this Bug: 270004534 Change-Id: Ib661d09ee6834f146955dd8f77077fd944162100 --- libs/gui/tests/BufferQueue_test.cpp | 85 +++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index d585881582..0168877478 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -21,8 +21,10 @@ #include "MockConsumer.h" #include +#include #include #include +#include #include @@ -37,6 +39,7 @@ #include +#include #include using namespace std::chrono_literals; @@ -1258,4 +1261,86 @@ TEST_F(BufferQueueTest, TestProducerConnectDisconnect) { ASSERT_EQ(NO_INIT, mProducer->disconnect(NATIVE_WINDOW_API_CPU)); } +class Latch { +public: + explicit Latch(int expected) : mExpected(expected) {} + Latch(const Latch&) = delete; + Latch& operator=(const Latch&) = delete; + + void CountDown() { + std::unique_lock lock(mLock); + mExpected--; + if (mExpected <= 0) { + mCV.notify_all(); + } + } + + void Wait() { + std::unique_lock lock(mLock); + mCV.wait(lock, [&] { return mExpected == 0; }); + } + +private: + int mExpected; + std::mutex mLock; + std::condition_variable mCV; +}; + +struct OneshotOnDequeuedListener final : public BufferItemConsumer::FrameAvailableListener { + OneshotOnDequeuedListener(std::function&& oneshot) + : mOneshotRunnable(std::move(oneshot)) {} + + std::function mOneshotRunnable; + + void run() { + if (mOneshotRunnable) { + mOneshotRunnable(); + mOneshotRunnable = nullptr; + } + } + + void onFrameDequeued(const uint64_t) override { run(); } + + void onFrameAvailable(const BufferItem&) override {} +}; + +// See b/270004534 +TEST(BufferQueueThreading, TestProducerDequeueConsumerDestroy) { + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp bufferConsumer = + sp::make(consumer, GRALLOC_USAGE_SW_READ_OFTEN, 2); + ASSERT_NE(nullptr, bufferConsumer.get()); + sp surface = sp::make(producer); + native_window_set_buffers_format(surface.get(), PIXEL_FORMAT_RGBA_8888); + native_window_set_buffers_dimensions(surface.get(), 100, 100); + + Latch triggerDisconnect(1); + Latch resumeCallback(1); + auto luckyListener = sp::make([&]() { + triggerDisconnect.CountDown(); + resumeCallback.Wait(); + }); + bufferConsumer->setFrameAvailableListener(luckyListener); + + std::future disconnecter = std::async(std::launch::async, [&]() { + triggerDisconnect.Wait(); + luckyListener = nullptr; + bufferConsumer = nullptr; + resumeCallback.CountDown(); + }); + + std::future render = std::async(std::launch::async, [=]() { + ANativeWindow_Buffer buffer; + surface->lock(&buffer, nullptr); + surface->unlockAndPost(); + }); + + ASSERT_EQ(std::future_status::ready, render.wait_for(1s)); + EXPECT_EQ(nullptr, luckyListener.get()); + EXPECT_EQ(nullptr, bufferConsumer.get()); +} + } // namespace android -- GitLab From dfc8febc3ac84a59b456428e026516376915ed36 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Fri, 21 Jul 2023 17:43:02 -0400 Subject: [PATCH 0379/1187] Reduce memory churn in KawaseBlurFilter::generate We may use up to 4 passes for generating the blur. Rather than generating a new Surface (all of the same size) for each pass, generate at most 2 surfaces and ping pong back and forth. In addition, early exit if blurRadius is zero. Bug: 290294055 Bug: 279894071 Bug: 275754150 Test: manual (pull down notification shade) Test: atest BlurTests Change-Id: I7ad2438a0e5d9e437b0256eb302fe2fd44e9c093 --- .../skia/filters/KawaseBlurFilter.cpp | 63 ++++++++++--------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp index 0c7335c05d..7bf2b0c16f 100644 --- a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp +++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp @@ -61,25 +61,7 @@ KawaseBlurFilter::KawaseBlurFilter(): BlurFilter() { // Draws the given runtime shader on a GPU (Ganesh) surface and returns the result as an // SkImage. -static sk_sp makeImage(GrRecordingContext* context, SkRuntimeShaderBuilder* builder, - const SkImageInfo& resultInfo) { - if (resultInfo.alphaType() == kUnpremul_SkAlphaType || - resultInfo.alphaType() == kUnknown_SkAlphaType) { - return nullptr; - } - constexpr int kSampleCount = 1; - constexpr bool kMipmapped = false; - - sk_sp surface = SkSurfaces::RenderTarget(context, - skgpu::Budgeted::kYes, - resultInfo, - kSampleCount, - kTopLeft_GrSurfaceOrigin, - nullptr, - kMipmapped); - if (!surface) { - return nullptr; - } +static sk_sp makeImage(SkSurface* surface, SkRuntimeShaderBuilder* builder) { sk_sp shader = builder->makeShader(nullptr); if (!shader) { return nullptr; @@ -97,11 +79,16 @@ sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, const SkRect& blurRect) const { LOG_ALWAYS_FATAL_IF(context == nullptr, "%s: Needs GPU context", __func__); LOG_ALWAYS_FATAL_IF(input == nullptr, "%s: Invalid input image", __func__); + + if (blurRadius == 0) { + return input; + } + // Kawase is an approximation of Gaussian, but it behaves differently from it. // A radius transformation is required for approximating them, and also to introduce // non-integer steps, necessary to smoothly interpolate large radii. float tmpRadius = (float)blurRadius / 2.0f; - float numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius)); + uint32_t numberOfPasses = std::min(kMaxPasses, (uint32_t)ceil(tmpRadius)); float radiusByPasses = tmpRadius / (float)numberOfPasses; // create blur surface with the bit depth and colorspace of the original surface @@ -121,15 +108,33 @@ sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix); blurBuilder.uniform("in_blurOffset") = radiusByPasses * kInputScale; - sk_sp tmpBlur = makeImage(context, &blurBuilder, scaledInfo); - - // And now we'll build our chain of scaled blur stages - for (auto i = 1; i < numberOfPasses; i++) { - LOG_ALWAYS_FATAL_IF(tmpBlur == nullptr, "%s: tmpBlur is null for pass %d", __func__, i); - blurBuilder.child("child") = - tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear); - blurBuilder.uniform("in_blurOffset") = (float) i * radiusByPasses * kInputScale; - tmpBlur = makeImage(context, &blurBuilder, scaledInfo); + constexpr int kSampleCount = 1; + constexpr bool kMipmapped = false; + constexpr SkSurfaceProps* kProps = nullptr; + sk_sp surface = + SkSurfaces::RenderTarget(context, skgpu::Budgeted::kYes, scaledInfo, kSampleCount, + kTopLeft_GrSurfaceOrigin, kProps, kMipmapped); + LOG_ALWAYS_FATAL_IF(!surface, "%s: Failed to create surface for blurring!", __func__); + sk_sp tmpBlur = makeImage(surface.get(), &blurBuilder); + + // And now we'll build our chain of scaled blur stages. If there is more than one pass, + // create a second surface and ping pong between them. + sk_sp surfaceTwo; + if (numberOfPasses <= 1) { + LOG_ALWAYS_FATAL_IF(tmpBlur == nullptr, "%s: tmpBlur is null", __func__); + } else { + surfaceTwo = surface->makeSurface(scaledInfo); + LOG_ALWAYS_FATAL_IF(!surfaceTwo, "%s: Failed to create second blur surface!", __func__); + + for (auto i = 1; i < numberOfPasses; i++) { + LOG_ALWAYS_FATAL_IF(tmpBlur == nullptr, "%s: tmpBlur is null for pass %d", __func__, i); + blurBuilder.child("child") = + tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear); + blurBuilder.uniform("in_blurOffset") = (float) i * radiusByPasses * kInputScale; + tmpBlur = makeImage(surfaceTwo.get(), &blurBuilder); + using std::swap; + swap(surface, surfaceTwo); + } } return tmpBlur; -- GitLab From c638470eccb89b0ec9594f968d9ccc07c5a6854b Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 31 Jul 2023 12:22:20 -0700 Subject: [PATCH 0380/1187] [sf] respect parent alpha when calculating blur radius and blur regions Fixes a regression caused by breaking front end and composition engine dependencies. Test: atest BlurTests Bug: 293532283 Change-Id: If9962a46bc7dba3b8f4256ae23307094a9c93290 --- services/surfaceflinger/Layer.cpp | 8 ++++---- services/surfaceflinger/LayerFE.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3a41f1599b..1a0517ac0d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -594,8 +594,8 @@ void Layer::prepareBasicGeometryCompositionState() { snapshot->localTransformInverse = snapshot->localTransform.inverse(); snapshot->blendMode = static_cast(blendMode); snapshot->alpha = alpha; - snapshot->backgroundBlurRadius = drawingState.backgroundBlurRadius; - snapshot->blurRegions = drawingState.blurRegions; + snapshot->backgroundBlurRadius = getBackgroundBlurRadius(); + snapshot->blurRegions = getBlurRegions(); snapshot->stretchEffect = getStretchEffect(); } @@ -664,8 +664,8 @@ void Layer::preparePerFrameCompositionState() { snapshot->forceClientComposition = true; } // If there are no visible region changes, we still need to update blur parameters. - snapshot->blurRegions = drawingState.blurRegions; - snapshot->backgroundBlurRadius = drawingState.backgroundBlurRadius; + snapshot->blurRegions = getBlurRegions(); + snapshot->backgroundBlurRadius = getBackgroundBlurRadius(); // Layer framerate is used in caching decisions. // Retrieve it from the scheduler which maintains an instance of LayerHistory, and store it in diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index f855f278c3..4d3e04861b 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -16,7 +16,7 @@ // #define LOG_NDEBUG 0 #undef LOG_TAG -#define LOG_TAG "LayerFE" +#define LOG_TAG "SurfaceFlinger" #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include -- GitLab From 9be7d0c3ce3c17cfaab528db7203905eb40c6bf3 Mon Sep 17 00:00:00 2001 From: jeimysantiago Date: Wed, 12 Jul 2023 18:37:06 +0000 Subject: [PATCH 0381/1187] Make screenCapture calls to SF async The captureDisplay and captureLayers aidl calls have been made one-way and the functions void. A new function called invokeScreenCaptureError has been created that takes the error and listener as input and passes the captureResult to onScreenCaptureCompleted. Bug: 287081404 Test: atest layerScreenshot Change-Id: Iaa07a3525a2ff0ed8409cac27e9f8ac7b01183df --- .../aidl/android/gui/ISurfaceComposer.aidl | 6 +- services/surfaceflinger/SurfaceFlinger.cpp | 116 +++++++++++------- services/surfaceflinger/SurfaceFlinger.h | 13 +- 3 files changed, 78 insertions(+), 57 deletions(-) diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index 539a1c140e..5e8e9043c1 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -230,20 +230,20 @@ interface ISurfaceComposer { * The subregion can be optionally rotated. It will also be scaled to * match the size of the output buffer. */ - void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener); + oneway void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener); /** * Capture the specified screen. This requires the READ_FRAME_BUFFER * permission. */ - void captureDisplayById(long displayId, IScreenCaptureListener listener); + oneway void captureDisplayById(long displayId, IScreenCaptureListener listener); /** * Capture a subtree of the layer hierarchy, potentially ignoring the root node. * This requires READ_FRAME_BUFFER permission. This function will fail if there * is a secure window on screen */ - void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener); + oneway void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener); /** * Clears the frame statistics for animations. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9f24dd6341..cbda10e2d4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -7311,16 +7311,27 @@ ui::Dataspace pickBestDataspace(ui::Dataspace requestedDataspace, const DisplayD } // namespace -status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, - const sp& captureListener) { +static void invokeScreenCaptureError(const status_t status, + const sp& captureListener) { + ScreenCaptureResults captureResults; + captureResults.fenceResult = base::unexpected(status); + captureListener->onScreenCaptureCompleted(captureResults); +} + +void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, + const sp& captureListener) { ATRACE_CALL(); status_t validate = validateScreenshotPermissions(args); if (validate != OK) { - return validate; + invokeScreenCaptureError(validate, captureListener); + return; } - if (!args.displayToken) return BAD_VALUE; + if (!args.displayToken) { + invokeScreenCaptureError(BAD_VALUE, captureListener); + return; + } wp displayWeak; ui::LayerStack layerStack; @@ -7329,7 +7340,10 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, { Mutex::Autolock lock(mStateLock); sp display = getDisplayDeviceLocked(args.displayToken); - if (!display) return NAME_NOT_FOUND; + if (!display) { + invokeScreenCaptureError(NAME_NOT_FOUND, captureListener); + return; + } displayWeak = display; layerStack = display->getLayerStack(); @@ -7344,7 +7358,8 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, excludeLayerIds.emplace(excludeLayer); } else { ALOGW("Invalid layer handle passed as excludeLayer to captureDisplay"); - return NAME_NOT_FOUND; + invokeScreenCaptureError(NAME_NOT_FOUND, captureListener); + return; } } } @@ -7367,14 +7382,12 @@ status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, getLayerSnapshots = RenderArea::fromTraverseLayersLambda(traverseLayers); } - auto future = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, reqSize, - args.pixelFormat, args.allowProtected, args.grayscale, - captureListener); - return fenceStatus(future.get()); + captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, reqSize, args.pixelFormat, + args.allowProtected, args.grayscale, captureListener); } -status_t SurfaceFlinger::captureDisplay(DisplayId displayId, - const sp& captureListener) { +void SurfaceFlinger::captureDisplay(DisplayId displayId, + const sp& captureListener) { ui::LayerStack layerStack; wp displayWeak; ui::Size size; @@ -7383,7 +7396,8 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId, const auto display = getDisplayDeviceLocked(displayId); if (!display) { - return NAME_NOT_FOUND; + invokeScreenCaptureError(NAME_NOT_FOUND, captureListener); + return; } displayWeak = display; @@ -7411,25 +7425,25 @@ status_t SurfaceFlinger::captureDisplay(DisplayId displayId, if (captureListener == nullptr) { ALOGE("capture screen must provide a capture listener callback"); - return BAD_VALUE; + invokeScreenCaptureError(BAD_VALUE, captureListener); + return; } constexpr bool kAllowProtected = false; constexpr bool kGrayscale = false; - auto future = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, size, - ui::PixelFormat::RGBA_8888, kAllowProtected, kGrayscale, - captureListener); - return fenceStatus(future.get()); + captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, size, + ui::PixelFormat::RGBA_8888, kAllowProtected, kGrayscale, captureListener); } -status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, - const sp& captureListener) { +void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, + const sp& captureListener) { ATRACE_CALL(); status_t validate = validateScreenshotPermissions(args); if (validate != OK) { - return validate; + invokeScreenCaptureError(validate, captureListener); + return; } ui::Size reqSize; @@ -7447,13 +7461,15 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, parent = LayerHandle::getLayer(args.layerHandle); if (parent == nullptr) { ALOGE("captureLayers called with an invalid or removed parent"); - return NAME_NOT_FOUND; + invokeScreenCaptureError(NAME_NOT_FOUND, captureListener); + return; } if (!canCaptureBlackoutContent && parent->getDrawingState().flags & layer_state_t::eLayerSecure) { ALOGW("Attempting to capture secure layer: PERMISSION_DENIED"); - return PERMISSION_DENIED; + invokeScreenCaptureError(PERMISSION_DENIED, captureListener); + return; } Rect parentSourceBounds = parent->getCroppedBufferSize(parent->getDrawingState()); @@ -7470,7 +7486,8 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, if (crop.isEmpty() || args.frameScaleX <= 0.0f || args.frameScaleY <= 0.0f) { // Error out if the layer has no source bounds (i.e. they are boundless) and a source // crop was not specified, or an invalid frame scale was provided. - return BAD_VALUE; + invokeScreenCaptureError(BAD_VALUE, captureListener); + return; } reqSize = ui::Size(crop.width() * args.frameScaleX, crop.height() * args.frameScaleY); @@ -7480,7 +7497,8 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, excludeLayerIds.emplace(excludeLayer); } else { ALOGW("Invalid layer handle passed as excludeLayer to captureLayers"); - return NAME_NOT_FOUND; + invokeScreenCaptureError(NAME_NOT_FOUND, captureListener); + return; } } } // mStateLock @@ -7488,7 +7506,8 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, // really small crop or frameScale if (reqSize.width <= 0 || reqSize.height <= 0) { ALOGW("Failed to captureLayes: crop or scale too small"); - return BAD_VALUE; + invokeScreenCaptureError(BAD_VALUE, captureListener); + return; } bool childrenOnly = args.childrenOnly; @@ -7552,26 +7571,27 @@ status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, if (captureListener == nullptr) { ALOGE("capture screen must provide a capture listener callback"); - return BAD_VALUE; + invokeScreenCaptureError(BAD_VALUE, captureListener); + return; } - auto future = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, reqSize, - args.pixelFormat, args.allowProtected, args.grayscale, - captureListener); - return fenceStatus(future.get()); + captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, reqSize, args.pixelFormat, + args.allowProtected, args.grayscale, captureListener); } -ftl::SharedFuture SurfaceFlinger::captureScreenCommon( - RenderAreaFuture renderAreaFuture, GetLayerSnapshotsFunction getLayerSnapshots, - ui::Size bufferSize, ui::PixelFormat reqPixelFormat, bool allowProtected, bool grayscale, - const sp& captureListener) { +void SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, + GetLayerSnapshotsFunction getLayerSnapshots, + ui::Size bufferSize, ui::PixelFormat reqPixelFormat, + bool allowProtected, bool grayscale, + const sp& captureListener) { ATRACE_CALL(); if (exceedsMaxRenderTargetSize(bufferSize.getWidth(), bufferSize.getHeight())) { ALOGE("Attempted to capture screen with size (%" PRId32 ", %" PRId32 ") that exceeds render target size limit.", bufferSize.getWidth(), bufferSize.getHeight()); - return ftl::yield(base::unexpected(BAD_VALUE)).share(); + invokeScreenCaptureError(BAD_VALUE, captureListener); + return; } // Loop over all visible layers to see whether there's any protected layer. A protected layer is @@ -7611,14 +7631,16 @@ ftl::SharedFuture SurfaceFlinger::captureScreenCommon( // Otherwise an irreponsible process may cause an SF crash by allocating // too much. ALOGE("%s: Buffer failed to allocate: %d", __func__, bufferStatus); - return ftl::yield(base::unexpected(bufferStatus)).share(); + invokeScreenCaptureError(bufferStatus, captureListener); + return; } const std::shared_ptr texture = std::make_shared< renderengine::impl::ExternalTexture>(buffer, getRenderEngine(), renderengine::impl::ExternalTexture::Usage:: WRITEABLE); - return captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, texture, - false /* regionSampling */, grayscale, captureListener); + auto fence = captureScreenCommon(std::move(renderAreaFuture), getLayerSnapshots, texture, + false /* regionSampling */, grayscale, captureListener); + fence.get(); } ftl::SharedFuture SurfaceFlinger::captureScreenCommon( @@ -9055,28 +9077,28 @@ binder::Status SurfaceComposerAIDL::setGameContentType(const sp& displa binder::Status SurfaceComposerAIDL::captureDisplay( const DisplayCaptureArgs& args, const sp& captureListener) { - status_t status = mFlinger->captureDisplay(args, captureListener); - return binderStatusFromStatusT(status); + mFlinger->captureDisplay(args, captureListener); + return binderStatusFromStatusT(NO_ERROR); } binder::Status SurfaceComposerAIDL::captureDisplayById( int64_t displayId, const sp& captureListener) { - status_t status; + // status_t status; IPCThreadState* ipc = IPCThreadState::self(); const int uid = ipc->getCallingUid(); if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) { std::optional id = DisplayId::fromValue(static_cast(displayId)); - status = mFlinger->captureDisplay(*id, captureListener); + mFlinger->captureDisplay(*id, captureListener); } else { - status = PERMISSION_DENIED; + invokeScreenCaptureError(PERMISSION_DENIED, captureListener); } - return binderStatusFromStatusT(status); + return binderStatusFromStatusT(NO_ERROR); } binder::Status SurfaceComposerAIDL::captureLayers( const LayerCaptureArgs& args, const sp& captureListener) { - status_t status = mFlinger->captureLayers(args, captureListener); - return binderStatusFromStatusT(status); + mFlinger->captureLayers(args, captureListener); + return binderStatusFromStatusT(NO_ERROR); } binder::Status SurfaceComposerAIDL::overrideHdrTypes(const sp& display, diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b07910d360..9f4658da90 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -535,9 +535,9 @@ private: EventRegistrationFlags eventRegistration = {}, const sp& layerHandle = nullptr); - status_t captureDisplay(const DisplayCaptureArgs&, const sp&); - status_t captureDisplay(DisplayId, const sp&); - status_t captureLayers(const LayerCaptureArgs&, const sp&); + void captureDisplay(const DisplayCaptureArgs&, const sp&); + void captureDisplay(DisplayId, const sp&); + void captureLayers(const LayerCaptureArgs&, const sp&); status_t getDisplayStats(const sp& displayToken, DisplayStatInfo* stats); status_t getDisplayState(const sp& displayToken, ui::DisplayState*) @@ -836,10 +836,9 @@ private: // Boot animation, on/off animations and screen capture void startBootAnim(); - ftl::SharedFuture captureScreenCommon(RenderAreaFuture, GetLayerSnapshotsFunction, - ui::Size bufferSize, ui::PixelFormat, - bool allowProtected, bool grayscale, - const sp&); + void captureScreenCommon(RenderAreaFuture, GetLayerSnapshotsFunction, ui::Size bufferSize, + ui::PixelFormat, bool allowProtected, bool grayscale, + const sp&); ftl::SharedFuture captureScreenCommon( RenderAreaFuture, GetLayerSnapshotsFunction, const std::shared_ptr&, bool regionSampling, -- GitLab From 1cd73f8a6869ed5b600312b7eacbfb6fc2ef0d31 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Mon, 31 Jul 2023 15:54:48 -0500 Subject: [PATCH 0382/1187] Replace BLASTBufferQueueTest#OutOfOrderTransactionTest Deletes BLASTBufferQueueTest#OutOfOrderTransactionTest and replaces it with a new unit test, TransactionApplicationTest#ApplyTokensUseDifferentQueues. Bug: 288344458 Test: TransactionApplicationTest#ApplyTokensUseDifferentQueues Change-Id: If12f97ab6df4eb717b5813431f22037b4f458b29 --- libs/gui/tests/BLASTBufferQueue_test.cpp | 37 ----------------- .../unittests/TransactionApplicationTest.cpp | 41 +++++++++++++++++++ 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index cce28926ea..cc6f3ddd4e 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -1348,43 +1348,6 @@ TEST_F(BLASTBufferQueueTest, QueryNativeWindowQueuesToWindowComposer) { ASSERT_EQ(queuesToNativeWindow, 1); } -// Test a slow producer doesn't hold up a faster producer from the same client. Essentially tests -// BBQ uses separate transaction queues. -TEST_F(BLASTBufferQueueTest, OutOfOrderTransactionTest) { - sp bgSurface = - mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceBufferState); - ASSERT_NE(nullptr, bgSurface.get()); - Transaction t; - t.setLayerStack(bgSurface, ui::DEFAULT_LAYER_STACK) - .show(bgSurface) - .setDataspace(bgSurface, ui::Dataspace::V0_SRGB) - .setLayer(bgSurface, std::numeric_limits::max() - 1) - .apply(); - - BLASTBufferQueueHelper slowAdapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); - sp slowIgbProducer; - setUpProducer(slowAdapter, slowIgbProducer); - nsecs_t presentTimeDelay = std::chrono::nanoseconds(500ms).count(); - queueBuffer(slowIgbProducer, 0 /* r */, 255 /* g */, 0 /* b */, presentTimeDelay); - - BLASTBufferQueueHelper fastAdapter(bgSurface, mDisplayWidth, mDisplayHeight); - sp fastIgbProducer; - setUpProducer(fastAdapter, fastIgbProducer); - uint8_t r = 255; - uint8_t g = 0; - uint8_t b = 0; - queueBuffer(fastIgbProducer, r, g, b, 0 /* presentTimeDelay */); - fastAdapter.waitForCallbacks(); - - // capture screen and verify that it is red - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); - - ASSERT_NO_FATAL_FAILURE( - checkScreenCapture(r, g, b, - {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight / 2})); -} - TEST_F(BLASTBufferQueueTest, TransformHint) { // Transform hint is provided to BBQ via the surface control passed by WM mSurfaceControl->setTransformHint(ui::Transform::ROT_90); diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 644b8c70c6..1f2a1edb77 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -306,6 +306,47 @@ public: ~FakeExternalTexture() = default; }; +TEST_F(TransactionApplicationTest, ApplyTokensUseDifferentQueues) { + auto applyToken1 = sp::make(); + auto applyToken2 = sp::make(); + + // Transaction 1 has a buffer with an unfired fence. It should not be ready to be applied. + TransactionState transaction1; + transaction1.applyToken = applyToken1; + transaction1.id = 42069; + transaction1.states.emplace_back(); + transaction1.states[0].state.what |= layer_state_t::eBufferChanged; + transaction1.states[0].state.bufferData = + std::make_shared(/* bufferId */ 1, /* width */ 1, /* height */ 1, + /* pixelFormat */ 0, /* outUsage */ 0); + transaction1.states[0].externalTexture = + std::make_shared(*transaction1.states[0].state.bufferData); + transaction1.states[0].state.surface = + sp::make(LayerCreationArgs(mFlinger.flinger(), nullptr, "TestLayer", 0, {})) + ->getHandle(); + auto fence = sp::make(); + EXPECT_CALL(*fence, getStatus()).WillRepeatedly(Return(Fence::Status::Unsignaled)); + transaction1.states[0].state.bufferData->acquireFence = std::move(fence); + transaction1.states[0].state.bufferData->flags = BufferData::BufferDataChange::fenceChanged; + transaction1.isAutoTimestamp = true; + + // Transaction 2 should be ready to be applied. + TransactionState transaction2; + transaction2.applyToken = applyToken2; + transaction2.id = 2; + transaction2.isAutoTimestamp = true; + + mFlinger.setTransactionStateInternal(transaction1); + mFlinger.setTransactionStateInternal(transaction2); + mFlinger.flushTransactionQueues(); + auto transactionQueues = mFlinger.getPendingTransactionQueue(); + + // Transaction 1 is still in its queue. + EXPECT_EQ(transactionQueues[applyToken1].size(), 1u); + // Transaction 2 has been dequeued. + EXPECT_EQ(transactionQueues[applyToken2].size(), 0u); +} + class LatchUnsignaledTest : public TransactionApplicationTest { public: void TearDown() override { -- GitLab From 43c3a8058683472fa3bf3039238f71b27b001a0b Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Mon, 24 Jul 2023 18:33:49 +0530 Subject: [PATCH 0383/1187] ultrahdr: add support for stride for 420 input Bug: Test: ./ultrahdr_unit_test Change-Id: Ia35f81a450dd13307f7f5e62e141c28648edd59e --- libs/ultrahdr/gainmapmath.cpp | 44 ++++-- libs/ultrahdr/include/ultrahdr/jpegr.h | 19 ++- libs/ultrahdr/jpegr.cpp | 93 +++++++---- libs/ultrahdr/tests/jpegr_test.cpp | 206 +++++++++++++++++++++++-- 4 files changed, 298 insertions(+), 64 deletions(-) diff --git a/libs/ultrahdr/gainmapmath.cpp b/libs/ultrahdr/gainmapmath.cpp index 8015a4ebeb..27157227c3 100644 --- a/libs/ultrahdr/gainmapmath.cpp +++ b/libs/ultrahdr/gainmapmath.cpp @@ -598,14 +598,26 @@ Color applyGainLUT(Color e, float gain, GainLUT& gainLUT) { } Color getYuv420Pixel(jr_uncompressed_ptr image, size_t x, size_t y) { - size_t pixel_count = image->width * image->height; + uint8_t* luma_data = reinterpret_cast(image->data); + size_t luma_stride = image->luma_stride == 0 ? image->width : image->luma_stride; + + uint8_t* chroma_data; + size_t chroma_stride; + if (image->chroma_data == nullptr) { + chroma_stride = luma_stride / 2; + chroma_data = &reinterpret_cast(image->data)[luma_stride * image->height]; + } else { + chroma_stride = image->chroma_stride; + chroma_data = reinterpret_cast(image->chroma_data); + } - size_t pixel_y_idx = x + y * image->width; - size_t pixel_uv_idx = x / 2 + (y / 2) * (image->width / 2); + size_t offset_cr = chroma_stride * (image->height / 2); + size_t pixel_y_idx = x + y * luma_stride; + size_t pixel_chroma_idx = x / 2 + (y / 2) * chroma_stride; - uint8_t y_uint = reinterpret_cast(image->data)[pixel_y_idx]; - uint8_t u_uint = reinterpret_cast(image->data)[pixel_count + pixel_uv_idx]; - uint8_t v_uint = reinterpret_cast(image->data)[pixel_count * 5 / 4 + pixel_uv_idx]; + uint8_t y_uint = luma_data[pixel_y_idx]; + uint8_t u_uint = chroma_data[pixel_chroma_idx]; + uint8_t v_uint = chroma_data[offset_cr + pixel_chroma_idx]; // 128 bias for UV given we are using jpeglib; see: // https://github.com/kornelski/libjpeg/blob/master/structure.doc @@ -615,19 +627,17 @@ Color getYuv420Pixel(jr_uncompressed_ptr image, size_t x, size_t y) { } Color getP010Pixel(jr_uncompressed_ptr image, size_t x, size_t y) { - size_t luma_stride = image->luma_stride; - size_t chroma_stride = image->chroma_stride; uint16_t* luma_data = reinterpret_cast(image->data); - uint16_t* chroma_data = reinterpret_cast(image->chroma_data); + size_t luma_stride = image->luma_stride == 0 ? image->width : image->luma_stride; - if (luma_stride == 0) { - luma_stride = image->width; - } - if (chroma_stride == 0) { - chroma_stride = luma_stride; - } - if (chroma_data == nullptr) { - chroma_data = &reinterpret_cast(image->data)[luma_stride * image->height]; + uint16_t* chroma_data; + size_t chroma_stride; + if (image->chroma_data == nullptr) { + chroma_stride = luma_stride; + chroma_data = &reinterpret_cast(image->data)[luma_stride * image->height]; + } else { + chroma_stride = image->chroma_stride; + chroma_data = reinterpret_cast(image->chroma_data); } size_t pixel_y_idx = y * luma_stride + x; diff --git a/libs/ultrahdr/include/ultrahdr/jpegr.h b/libs/ultrahdr/include/ultrahdr/jpegr.h index f80496a758..e539e47944 100644 --- a/libs/ultrahdr/include/ultrahdr/jpegr.h +++ b/libs/ultrahdr/include/ultrahdr/jpegr.h @@ -49,16 +49,19 @@ struct jpegr_uncompressed_struct { // Values below are optional // Pointer to chroma data, if it's NULL, chroma plane is considered to be immediately - // following after the luma plane. - // Note: currently this feature is only supported for P010 image (HDR input). + // after the luma plane. void* chroma_data = nullptr; - // Strides of Y plane in number of pixels, using 0 to present uninitialized, must be - // larger than or equal to luma width. - // Note: currently this feature is only supported for P010 image (HDR input). + // Stride of Y plane in number of pixels. 0 indicates the member is uninitialized. If + // non-zero this value must be larger than or equal to luma width. If stride is + // uninitialized then it is assumed to be equal to luma width. int luma_stride = 0; - // Strides of UV plane in number of pixels, using 0 to present uninitialized, must be - // larger than or equal to chroma width. - // Note: currently this feature is only supported for P010 image (HDR input). + // Stride of UV plane in number of pixels. + // 1. If this handle points to P010 image then this value must be larger than + // or equal to luma width. + // 2. If this handle points to 420 image then this value must be larger than + // or equal to (luma width / 2). + // NOTE: if chroma_data is nullptr, chroma_stride is irrelevant. Just as the way, + // chroma_data is derived from luma ptr, chroma stride is derived from luma stride. int chroma_stride = 0; }; diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp index 5a601bd6b9..0191fea9e8 100644 --- a/libs/ultrahdr/jpegr.cpp +++ b/libs/ultrahdr/jpegr.cpp @@ -167,15 +167,18 @@ status_t JpegR::areInputArgumentsValid(jr_uncompressed_ptr uncompressed_p010_ima return ERROR_JPEGR_INVALID_NULL_PTR; } - if (uncompressed_yuv_420_image->luma_stride != 0) { - ALOGE("Stride is not supported for YUV420 image"); - return ERROR_JPEGR_UNSUPPORTED_FEATURE; + if (uncompressed_yuv_420_image->luma_stride != 0 + && uncompressed_yuv_420_image->luma_stride < uncompressed_yuv_420_image->width) { + ALOGE("Luma stride can not be smaller than width, stride=%d, width=%d", + uncompressed_yuv_420_image->luma_stride, uncompressed_yuv_420_image->width); + return ERROR_JPEGR_INVALID_INPUT_TYPE; } - if (uncompressed_yuv_420_image->chroma_data != nullptr) { - ALOGE("Pointer to chroma plane is not supported for YUV420 image, chroma data must" - "be immediately after the luma data."); - return ERROR_JPEGR_UNSUPPORTED_FEATURE; + if (uncompressed_yuv_420_image->chroma_data != nullptr + && uncompressed_yuv_420_image->chroma_stride < uncompressed_yuv_420_image->width / 2) { + ALOGE("Chroma stride can not be smaller than 1/2 of the width, stride=%d, width=%d", + uncompressed_yuv_420_image->chroma_stride, uncompressed_yuv_420_image->width); + return ERROR_JPEGR_INVALID_INPUT_TYPE; } if (uncompressed_p010_image->width != uncompressed_yuv_420_image->width @@ -323,11 +326,49 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, sp icc = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, uncompressed_yuv_420_image->colorGamut); - // Convert to Bt601 YUV encoding for JPEG encode; make a copy so as to no clobber client data + // Convert to Bt601 YUV encoding for JPEG encode and remove stride if needed; + // make a copy so as to no clobber client data unique_ptr yuv_420_bt601_data = make_unique( uncompressed_yuv_420_image->width * uncompressed_yuv_420_image->height * 3 / 2); - memcpy(yuv_420_bt601_data.get(), uncompressed_yuv_420_image->data, - uncompressed_yuv_420_image->width * uncompressed_yuv_420_image->height * 3 / 2); + // copy data + { + uint8_t* src_luma_data = reinterpret_cast(uncompressed_yuv_420_image->data); + size_t src_luma_stride = uncompressed_yuv_420_image->luma_stride == 0 + ? uncompressed_yuv_420_image->width : uncompressed_yuv_420_image->luma_stride; + uint8_t* src_chroma_data = reinterpret_cast(uncompressed_yuv_420_image->chroma_data); + size_t src_chroma_stride = uncompressed_yuv_420_image->chroma_stride; + if (uncompressed_yuv_420_image->chroma_data == nullptr) { + src_chroma_data = + &reinterpret_cast(uncompressed_yuv_420_image->data)[src_luma_stride + * uncompressed_yuv_420_image->height]; + } + if (src_chroma_stride == 0) { + src_chroma_stride = src_luma_stride / 2; + } + // copy luma + for (size_t i = 0; i < uncompressed_yuv_420_image->height; i++) { + memcpy(yuv_420_bt601_data.get() + i * uncompressed_yuv_420_image->width, + src_luma_data + i * src_luma_stride, + uncompressed_yuv_420_image->width); + } + // copy cb + for (size_t i = 0; i < uncompressed_yuv_420_image->height / 2; i++) { + memcpy(yuv_420_bt601_data.get() + + uncompressed_yuv_420_image->width * uncompressed_yuv_420_image->height + + i * uncompressed_yuv_420_image->width / 2, + src_chroma_data + i * src_chroma_stride, + uncompressed_yuv_420_image->width / 2); + } + // copy cr + for (size_t i = 0; i < uncompressed_yuv_420_image->height / 2; i++) { + memcpy(yuv_420_bt601_data.get() + + uncompressed_yuv_420_image->width * uncompressed_yuv_420_image->height * 5 / 4 + + i * uncompressed_yuv_420_image->width / 2, + src_chroma_data + src_chroma_stride * (uncompressed_yuv_420_image->height / 2) + + i * src_chroma_stride, + uncompressed_yuv_420_image->width / 2); + } + } jpegr_uncompressed_struct yuv_420_bt601_image = { yuv_420_bt601_data.get(), uncompressed_yuv_420_image->width, uncompressed_yuv_420_image->height, @@ -792,16 +833,15 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, size_t image_width = uncompressed_yuv_420_image->width; size_t image_height = uncompressed_yuv_420_image->height; - size_t map_width = image_width / kMapDimensionScaleFactor; - size_t map_height = image_height / kMapDimensionScaleFactor; - size_t map_stride = static_cast( - floor((map_width + kJpegBlock - 1) / kJpegBlock)) * kJpegBlock; - size_t map_height_aligned = ((map_height + 1) >> 1) << 1; - - dest->width = map_stride; - dest->height = map_height_aligned; + size_t map_width = static_cast( + floor((image_width + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); + size_t map_height = static_cast( + floor((image_height + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); + + dest->width = map_width; + dest->height = map_height; dest->colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; - dest->data = new uint8_t[map_stride * map_height_aligned]; + dest->data = new uint8_t[map_width * map_height]; std::unique_ptr map_data; map_data.reset(reinterpret_cast(dest->data)); @@ -895,11 +935,9 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, luminanceFn, sdrYuvToRgbFn, hdrYuvToRgbFn, hdr_white_nits, log2MinBoost, log2MaxBoost, &jobQueue]() -> void { size_t rowStart, rowEnd; - size_t dest_map_width = uncompressed_yuv_420_image->width / kMapDimensionScaleFactor; - size_t dest_map_stride = dest->width; while (jobQueue.dequeueJob(rowStart, rowEnd)) { for (size_t y = rowStart; y < rowEnd; ++y) { - for (size_t x = 0; x < dest_map_width; ++x) { + for (size_t x = 0; x < dest->width; ++x) { Color sdr_yuv_gamma = sampleYuv420(uncompressed_yuv_420_image, kMapDimensionScaleFactor, x, y); Color sdr_rgb_gamma = sdrYuvToRgbFn(sdr_yuv_gamma); @@ -917,7 +955,7 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, hdr_rgb = hdrGamutConversionFn(hdr_rgb); float hdr_y_nits = luminanceFn(hdr_rgb) * hdr_white_nits; - size_t pixel_idx = x + y * dest_map_stride; + size_t pixel_idx = x + y * dest->width; reinterpret_cast(dest->data)[pixel_idx] = encodeGain(sdr_y_nits, hdr_y_nits, metadata, log2MinBoost, log2MaxBoost); } @@ -981,11 +1019,10 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, // TODO: remove once map scaling factor is computed based on actual map dims size_t image_width = uncompressed_yuv_420_image->width; size_t image_height = uncompressed_yuv_420_image->height; - size_t map_width = image_width / kMapDimensionScaleFactor; - size_t map_height = image_height / kMapDimensionScaleFactor; - map_width = static_cast( - floor((map_width + kJpegBlock - 1) / kJpegBlock)) * kJpegBlock; - map_height = ((map_height + 1) >> 1) << 1; + size_t map_width = static_cast( + floor((image_width + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); + size_t map_height = static_cast( + floor((image_height + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); if (map_width != uncompressed_gain_map->width || map_height != uncompressed_gain_map->height) { ALOGE("gain map dimensions and primary image dimensions are not to scale"); diff --git a/libs/ultrahdr/tests/jpegr_test.cpp b/libs/ultrahdr/tests/jpegr_test.cpp index 7837bcfc31..e8e5883573 100644 --- a/libs/ultrahdr/tests/jpegr_test.cpp +++ b/libs/ultrahdr/tests/jpegr_test.cpp @@ -728,23 +728,23 @@ TEST(JpegRTest, EncodeAPI1WithInvalidArgs) { rawImg420->width = kWidth; rawImg420->height = kHeight; - rawImg420->luma_stride = kWidth; + rawImg420->luma_stride = kWidth - 2; ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, jpgImg.getImageHandle(), kQuality, nullptr), OK) - << "fail, API allows luma stride for 420"; + << "fail, API allows bad luma stride for 420"; rawImg420->width = kWidth; rawImg420->height = kHeight; rawImg420->luma_stride = 0; rawImg420->chroma_data = rawImgP010->data; - rawImg420->chroma_stride = kWidth; + rawImg420->chroma_stride = kWidth / 2 - 2; ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, ultrahdr_transfer_function::ULTRAHDR_TF_HLG, jpgImg.getImageHandle(), kQuality, nullptr), OK) - << "fail, API allows bad chroma pointer for 420"; + << "fail, API allows bad chroma stride for 420"; } } @@ -1021,23 +1021,23 @@ TEST(JpegRTest, EncodeAPI2WithInvalidArgs) { rawImg420->width = kWidth; rawImg420->height = kHeight; - rawImg420->luma_stride = kWidth; + rawImg420->luma_stride = kWidth - 2; ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), ultrahdr_transfer_function::ULTRAHDR_TF_HLG, jpgImg.getImageHandle()), OK) - << "fail, API allows luma stride for 420"; + << "fail, API allows bad luma stride for 420"; rawImg420->width = kWidth; rawImg420->height = kHeight; rawImg420->luma_stride = 0; rawImg420->chroma_data = rawImgP010->data; - rawImg420->chroma_stride = kWidth; + rawImg420->chroma_stride = kWidth / 2 - 2; ASSERT_NE(uHdrLib.encodeJPEGR(rawImgP010, rawImg420, jpgImg.getImageHandle(), ultrahdr_transfer_function::ULTRAHDR_TF_HLG, jpgImg.getImageHandle()), OK) - << "fail, API allows bad chroma pointer for 420"; + << "fail, API allows bad chroma stride for 420"; } } @@ -1445,6 +1445,24 @@ TEST(JpegRTest, EncodeAPI0AndDecodeTest) { ASSERT_EQ(jpg1->length, jpg2->length); ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } + // encode with luma and chroma stride set but no chroma ptr + { + UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2.setImageStride(kImageWidth, kImageWidth + 256)); + ASSERT_TRUE(rawImg2.allocateMemory()); + ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); + } auto jpg1 = jpgImg.getImageHandle(); #ifdef DUMP_OUTPUT @@ -1473,7 +1491,7 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { ultrahdr_transfer_function::ULTRAHDR_TF_HLG, jpgImg.getImageHandle(), kQuality, nullptr), OK); - // encode with luma stride set + // encode with luma stride set p010 { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); @@ -1491,7 +1509,7 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { ASSERT_EQ(jpg1->length, jpg2->length); ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - // encode with luma and chroma stride set + // encode with luma and chroma stride set p010 { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); @@ -1510,7 +1528,7 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { ASSERT_EQ(jpg1->length, jpg2->length); ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } - // encode with chroma stride set + // encode with chroma stride set p010 { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); @@ -1529,6 +1547,98 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { ASSERT_EQ(jpg1->length, jpg2->length); ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } + // encode with luma and chroma stride set but no chroma ptr p010 + { + UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 64, kImageWidth + 256)); + ASSERT_TRUE(rawImg2P010.allocateMemory()); + ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), rawImg420.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); + } + // encode with luma stride set 420 + { + UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); + ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, 0)); + ASSERT_TRUE(rawImg2420.allocateMemory()); + ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); + } + // encode with luma and chroma stride set 420 + { + UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); + ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, kImageWidth / 2 + 256)); + ASSERT_TRUE(rawImg2420.setChromaMode(false)); + ASSERT_TRUE(rawImg2420.allocateMemory()); + ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); + } + // encode with chroma stride set 420 + { + UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); + ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2420.setImageStride(0, kImageWidth / 2 + 64)); + ASSERT_TRUE(rawImg2420.setChromaMode(false)); + ASSERT_TRUE(rawImg2420.allocateMemory()); + ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); + } + // encode with luma and chroma stride set but no chroma ptr 420 + { + UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); + ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, kImageWidth / 2 + 64)); + ASSERT_TRUE(rawImg2420.allocateMemory()); + ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(), + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle(), kQuality, nullptr), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); + } auto jpg1 = jpgImg.getImageHandle(); @@ -1618,6 +1728,62 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { ASSERT_EQ(jpg1->length, jpg2->length); ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } + // encode with luma stride set + { + UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); + ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, 0)); + ASSERT_TRUE(rawImg2420.allocateMemory()); + ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(), sdr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle()), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); + } + // encode with luma and chroma stride set + { + UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); + ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, kImageWidth + 256)); + ASSERT_TRUE(rawImg2420.setChromaMode(false)); + ASSERT_TRUE(rawImg2420.allocateMemory()); + ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(), sdr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle()), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); + } + // encode with chroma stride set + { + UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); + ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2420.setImageStride(0, kImageWidth + 64)); + ASSERT_TRUE(rawImg2420.setChromaMode(false)); + ASSERT_TRUE(rawImg2420.allocateMemory()); + ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImgP010.getImageHandle(), rawImg2420.getImageHandle(), sdr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle()), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); + } auto jpg1 = jpgImg.getImageHandle(); @@ -1703,6 +1869,24 @@ TEST(JpegRTest, EncodeAPI3AndDecodeTest) { ASSERT_EQ(jpg1->length, jpg2->length); ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); } + // encode with luma and chroma stride set and no chroma ptr + { + UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 32, kImageWidth + 256)); + ASSERT_TRUE(rawImg2P010.allocateMemory()); + ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); + UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); + ASSERT_TRUE(jpgImg2.allocateMemory()); + ASSERT_EQ(uHdrLib.encodeJPEGR(rawImg2P010.getImageHandle(), sdr, + ultrahdr_transfer_function::ULTRAHDR_TF_HLG, + jpgImg2.getImageHandle()), + OK); + auto jpg1 = jpgImg.getImageHandle(); + auto jpg2 = jpgImg2.getImageHandle(); + ASSERT_EQ(jpg1->length, jpg2->length); + ASSERT_EQ(0, memcmp(jpg1->data, jpg2->data, jpg1->length)); + } auto jpg1 = jpgImg.getImageHandle(); -- GitLab From f63125c42183c26fe871348d213d5628c8dfe32d Mon Sep 17 00:00:00 2001 From: Dichen Zhang Date: Mon, 31 Jul 2023 22:27:27 +0000 Subject: [PATCH 0384/1187] ultrahdr: handle unsupported sampling formats If primary/gain-map image sampling format is not as expected mark the api call for failure Bug: 290504502 Test: ./ultrahdr_dec_fuzzer Change-Id: I039bd2d198c13d236cc8687461519194451e63d4 --- libs/ultrahdr/jpegdecoderhelper.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/libs/ultrahdr/jpegdecoderhelper.cpp b/libs/ultrahdr/jpegdecoderhelper.cpp index fef544452a..d22f4eca9a 100644 --- a/libs/ultrahdr/jpegdecoderhelper.cpp +++ b/libs/ultrahdr/jpegdecoderhelper.cpp @@ -227,10 +227,20 @@ bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA) mHeight = cinfo.image_height; if (decodeToRGBA) { - if (cinfo.jpeg_color_space == JCS_GRAYSCALE) { - // We don't intend to support decoding grayscale to RGBA - status = false; - ALOGE("%s: decoding grayscale to RGBA is unsupported", __func__); + // The primary image is expected to be yuv420 sampling + if (cinfo.jpeg_color_space != JCS_YCbCr) { + status = false; + ALOGE("%s: decodeToRGBA unexpected jpeg color space ", __func__); + goto CleanUp; + } + if (cinfo.comp_info[0].h_samp_factor != 2 || + cinfo.comp_info[1].h_samp_factor != 1 || + cinfo.comp_info[2].h_samp_factor != 1 || + cinfo.comp_info[0].v_samp_factor != 2 || + cinfo.comp_info[1].v_samp_factor != 1 || + cinfo.comp_info[2].v_samp_factor != 1 ) { + status = false; + ALOGE("%s: decodeToRGBA unexpected primary image sub-sampling", __func__); goto CleanUp; } // 4 bytes per pixel @@ -251,6 +261,10 @@ bool JpegDecoderHelper::decode(const void* image, int length, bool decodeToRGBA) mResultBuffer.resize(cinfo.image_width * cinfo.image_height * 3 / 2, 0); } else if (cinfo.jpeg_color_space == JCS_GRAYSCALE) { mResultBuffer.resize(cinfo.image_width * cinfo.image_height, 0); + } else { + status = false; + ALOGE("%s: decodeToYUV unexpected jpeg color space", __func__); + goto CleanUp; } cinfo.out_color_space = cinfo.jpeg_color_space; cinfo.raw_data_out = TRUE; -- GitLab From da593c88c09efb1fbe533da90042dcb498ed02a0 Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Tue, 1 Aug 2023 15:47:23 +0000 Subject: [PATCH 0385/1187] Allow sensors list to be empty Test: atest VtsHalSensorManagerV1_0TargetTest Bug: 278013275 Bug: 269014004 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:49600b10aa5675d4e7e985203d69f252ead13e45) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:fa585b555879c88a24004510a7477bade49c9cbe) Merged-In: I091f57de9570b0ace3a8da76f16fe0e83f0aa624 Change-Id: I091f57de9570b0ace3a8da76f16fe0e83f0aa624 --- libs/sensor/SensorManager.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp index 40061cde61..9f814f1c48 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -176,11 +176,8 @@ status_t SensorManager::assertStateLocked() { mSensors = mSensorServer->getSensorList(mOpPackageName); size_t count = mSensors.size(); - if (count == 0) { - ALOGE("Failed to get Sensor list"); - mSensorServer.clear(); - return UNKNOWN_ERROR; - } + // If count is 0, mSensorList will be non-null. This is old + // existing behavior and callers expect this. mSensorList = static_cast(malloc(count * sizeof(Sensor*))); LOG_ALWAYS_FATAL_IF(mSensorList == nullptr, "mSensorList NULL"); -- GitLab From fdac5651f516b543f7c2073d058405bfa425d39b Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Thu, 29 Jun 2023 12:01:13 -0400 Subject: [PATCH 0386/1187] SF: Fix mode setting for secondary displays Desired modes were only propagated to HWC for the "active" display, i.e. generally the primary display and specially the rear display when in the folded state. In other words, mode setting did not happen for external displays, and the rear display when driving both displays concurrently. Store per-display state for whether a mode set is pending. Propagate the desired mode for both internal and external displays as long as they are powered on. Fixes: 277776378 Fixes: 289182528 Bug: 255635711 Bug: 255635821 Test: The 60 Hz constraint applies to both displays in concurrent mode. Test: ADB `set-user-preferred-display-mode` applies to external display. Test: DisplayModeSwitchingTest#inner{Xor,And}OuterDisplay Test: DisplayModeSwitchingTest#powerOffDuringModeSet Change-Id: I9da3a0be07f9fbb08f11485aa6ab9400259a4e09 --- services/surfaceflinger/DisplayDevice.cpp | 17 +- services/surfaceflinger/DisplayDevice.h | 7 + .../surfaceflinger/Scheduler/Scheduler.cpp | 12 +- .../include/scheduler/interface/ICompositor.h | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 183 ++++++++++-------- services/surfaceflinger/SurfaceFlinger.h | 19 +- .../fuzzer/surfaceflinger_fuzzers_utils.h | 2 +- .../tests/unittests/MessageQueueTest.cpp | 2 +- .../SurfaceFlinger_DisplayModeSwitching.cpp | 160 ++++++++++++--- .../tests/unittests/TestableScheduler.h | 2 +- .../tests/unittests/TestableSurfaceFlinger.h | 13 +- 11 files changed, 292 insertions(+), 128 deletions(-) diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 32bd890aee..3c7cbe693f 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -38,7 +38,6 @@ #include #include -#include "Display/DisplaySnapshot.h" #include "DisplayDevice.h" #include "FrontEnd/DisplayInfo.h" #include "HdrSdrRatioOverlay.h" @@ -231,10 +230,18 @@ status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info, return BAD_VALUE; } mUpcomingActiveMode = info; - ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), info.modeOpt->modePtr->getFps().getIntValue()); - return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), - info.modeOpt->modePtr->getHwcId(), constraints, - outTimeline); + mIsModeSetPending = true; + + const auto& pendingMode = *info.modeOpt->modePtr; + ATRACE_INT(mActiveModeFPSHwcTrace.c_str(), pendingMode.getFps().getIntValue()); + + return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), pendingMode.getHwcId(), + constraints, outTimeline); +} + +void DisplayDevice::finalizeModeChange(DisplayModeId modeId, Fps displayFps, Fps renderFps) { + setActiveMode(modeId, displayFps, renderFps); + mIsModeSetPending = false; } nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index e92125a45d..a3fa701be2 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -218,6 +218,8 @@ public: return mUpcomingActiveMode; } + bool isModeSetPending() const REQUIRES(kMainThreadContext) { return mIsModeSetPending; } + scheduler::FrameRateMode getActiveMode() const REQUIRES(kMainThreadContext) { return mRefreshRateSelector->getActiveMode(); } @@ -229,6 +231,9 @@ public: hal::VsyncPeriodChangeTimeline* outTimeline) REQUIRES(kMainThreadContext); + void finalizeModeChange(DisplayModeId, Fps displayFps, Fps renderFps) + REQUIRES(kMainThreadContext); + scheduler::RefreshRateSelector& refreshRateSelector() const { return *mRefreshRateSelector; } // Extends the lifetime of the RefreshRateSelector, so it can outlive this DisplayDevice. @@ -313,7 +318,9 @@ private: ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock); TracedOrdinal mDesiredActiveModeChanged GUARDED_BY(mActiveModeLock) = {ftl::Concat("DesiredActiveModeChanged-", getId().value).c_str(), false}; + ActiveModeInfo mUpcomingActiveMode GUARDED_BY(kMainThreadContext); + bool mIsModeSetPending GUARDED_BY(kMainThreadContext) = false; }; struct DisplayDeviceState { diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index d6d7725f6c..5a19ec5095 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -186,7 +186,17 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, FrameTargeter& pacesetterTargeter = *pacesetterOpt->get().targeterPtr; pacesetterTargeter.beginFrame(beginFrameArgs, *pacesetterOpt->get().schedulePtr); - if (!compositor.commit(pacesetterTargeter.target())) return; + FrameTargets targets; + targets.try_emplace(pacesetterId, &pacesetterTargeter.target()); + + for (const auto& [id, display] : mDisplays) { + if (id == pacesetterId) continue; + + const FrameTargeter& targeter = *display.targeterPtr; + targets.try_emplace(id, &targeter.target()); + } + + if (!compositor.commit(pacesetterId, targets)) return; // TODO(b/256196556): Choose the frontrunner display. FrameTargeters targeters; diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h index 6fe813a181..12ee36e084 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h @@ -29,6 +29,7 @@ namespace scheduler { class FrameTarget; class FrameTargeter; +using FrameTargets = ui::PhysicalDisplayMap; using FrameTargeters = ui::PhysicalDisplayMap; } // namespace scheduler @@ -39,7 +40,7 @@ struct ICompositor { // Commits transactions for layers and displays. Returns whether any state has been invalidated, // i.e. whether a frame should be composited for each display. - virtual bool commit(const scheduler::FrameTarget&) = 0; + virtual bool commit(PhysicalDisplayId pacesetterId, const scheduler::FrameTargets&) = 0; // Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition // via RenderEngine and the Composer HAL, respectively. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9f24dd6341..6caf5df0e2 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1195,9 +1195,9 @@ status_t SurfaceFlinger::getDisplayStats(const sp& displayToken, } void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request, bool force) { - ATRACE_CALL(); - const auto displayId = request.mode.modePtr->getPhysicalDisplayId(); + ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str()); + const auto display = getDisplayDeviceLocked(displayId); if (!display) { ALOGW("%s: display is no longer valid", __func__); @@ -1225,17 +1225,24 @@ void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request, // As we called to set period, we will call to onRefreshRateChangeCompleted once // VsyncController model is locked. mScheduler->modulateVsync(displayId, &VsyncModulator::onRefreshRateChangeInitiated); - updatePhaseConfiguration(mode.fps); + + if (displayId == mActiveDisplayId) { + updatePhaseConfiguration(mode.fps); + } + mScheduler->setModeChangePending(true); break; case DisplayDevice::DesiredActiveModeAction::InitiateRenderRateSwitch: mScheduler->setRenderRate(displayId, mode.fps); - updatePhaseConfiguration(mode.fps); - mRefreshRateStats->setRefreshRate(mode.fps); - if (display->getPhysicalId() == mActiveDisplayId && emitEvent) { - mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, mode); + + if (displayId == mActiveDisplayId) { + updatePhaseConfiguration(mode.fps); + mRefreshRateStats->setRefreshRate(mode.fps); } + if (emitEvent) { + dispatchDisplayModeChangeEvent(displayId, mode); + } break; case DisplayDevice::DesiredActiveModeAction::None: break; @@ -1291,24 +1298,20 @@ status_t SurfaceFlinger::setActiveModeFromBackdoor(const spgetUpcomingActiveMode(); + const auto upcomingModeInfo = display.getUpcomingActiveMode(); if (!upcomingModeInfo.modeOpt) { // There is no pending mode change. This can happen if the active // display changed and the mode change happened on a different display. return; } - if (display->getActiveMode().modePtr->getResolution() != + if (display.getActiveMode().modePtr->getResolution() != upcomingModeInfo.modeOpt->modePtr->getResolution()) { - auto& state = mCurrentState.displays.editValueFor(display->getDisplayToken()); + auto& state = mCurrentState.displays.editValueFor(display.getDisplayToken()); // We need to generate new sequenceId in order to recreate the display (and this // way the framebuffer). state.sequenceId = DisplayDeviceState{}.sequenceId; @@ -1319,27 +1322,24 @@ void SurfaceFlinger::updateInternalStateWithChangedMode() { return; } - mPhysicalDisplays.get(display->getPhysicalId()) - .transform(&PhysicalDisplay::snapshotRef) - .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) { - FTL_FAKE_GUARD(kMainThreadContext, - display->setActiveMode(upcomingModeInfo.modeOpt->modePtr->getId(), - upcomingModeInfo.modeOpt->modePtr->getFps(), - upcomingModeInfo.modeOpt->fps)); - })); - - const Fps refreshRate = upcomingModeInfo.modeOpt->fps; - mRefreshRateStats->setRefreshRate(refreshRate); - updatePhaseConfiguration(refreshRate); + const auto& activeMode = *upcomingModeInfo.modeOpt; + display.finalizeModeChange(activeMode.modePtr->getId(), activeMode.modePtr->getFps(), + activeMode.fps); + + if (displayId == mActiveDisplayId) { + mRefreshRateStats->setRefreshRate(activeMode.fps); + updatePhaseConfiguration(activeMode.fps); + } if (upcomingModeInfo.event != scheduler::DisplayModeEvent::None) { - mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, *upcomingModeInfo.modeOpt); + dispatchDisplayModeChangeEvent(displayId, activeMode); } } void SurfaceFlinger::clearDesiredActiveModeState(const sp& display) { display->clearDesiredActiveModeState(); if (display->getPhysicalId() == mActiveDisplayId) { + // TODO(b/255635711): Check for pending mode changes on other displays. mScheduler->setModeChangePending(false); } } @@ -1353,21 +1353,18 @@ void SurfaceFlinger::desiredActiveModeChangeDone(const sp& displa clearDesiredActiveModeState(display); mScheduler->resyncToHardwareVsync(displayId, true /* allowToEnable */, displayFps); mScheduler->setRenderRate(displayId, renderFps); - updatePhaseConfiguration(renderFps); + + if (displayId == mActiveDisplayId) { + updatePhaseConfiguration(renderFps); + } } -void SurfaceFlinger::setActiveModeInHwcIfNeeded() { +void SurfaceFlinger::initiateDisplayModeChanges() { ATRACE_CALL(); std::optional displayToUpdateImmediately; for (const auto& [id, physical] : mPhysicalDisplays) { - const auto& snapshot = physical.snapshot(); - - if (snapshot.connectionType() != ui::DisplayConnectionType::Internal) { - continue; - } - const auto display = getDisplayDeviceLocked(id); if (!display) continue; @@ -1378,14 +1375,14 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { continue; } - if (id != mActiveDisplayId) { - // Display is no longer the active display, so abort the mode change. + if (!display->isPoweredOn()) { + // Display is no longer powered on, so abort the mode change. clearDesiredActiveModeState(display); continue; } const auto desiredModeId = desiredActiveMode->modeOpt->modePtr->getId(); - const auto displayModePtrOpt = snapshot.displayModes().get(desiredModeId); + const auto displayModePtrOpt = physical.snapshot().displayModes().get(desiredModeId); if (!displayModePtrOpt) { ALOGW("Desired display mode is no longer supported. Mode ID = %d", @@ -1435,19 +1432,18 @@ void SurfaceFlinger::setActiveModeInHwcIfNeeded() { if (outTimeline.refreshRequired) { scheduleComposite(FrameHint::kNone); - mSetActiveModePending = true; } else { - // Updating the internal state should be done outside the loop, - // because it can recreate a DisplayDevice and modify mDisplays - // which will invalidate the iterator. + // TODO(b/255635711): Remove `displayToUpdateImmediately` to `finalizeDisplayModeChange` + // for all displays. This was only needed when the loop iterated over `mDisplays` rather + // than `mPhysicalDisplays`. displayToUpdateImmediately = display->getPhysicalId(); } } if (displayToUpdateImmediately) { - updateInternalStateWithChangedMode(); - const auto display = getDisplayDeviceLocked(*displayToUpdateImmediately); + finalizeDisplayModeChange(*display); + const auto desiredActiveMode = display->getDesiredActiveMode(); if (desiredActiveMode && display->getActiveMode() == desiredActiveMode->modeOpt) { desiredActiveModeChangeDone(display); @@ -2398,7 +2394,10 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, return mustComposite; } -bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) { +bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, + const scheduler::FrameTargets& frameTargets) { + const scheduler::FrameTarget& pacesetterFrameTarget = *frameTargets.get(pacesetterId)->get(); + const VsyncId vsyncId = pacesetterFrameTarget.vsyncId(); ATRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str()); @@ -2411,20 +2410,35 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) mTracingEnabledChanged = false; } - // If we are in the middle of a mode change and the fence hasn't - // fired yet just wait for the next commit. - if (mSetActiveModePending) { - if (pacesetterFrameTarget.isFramePending()) { - mScheduler->scheduleFrame(); - return false; - } + // If a mode set is pending and the fence hasn't fired yet, wait for the next commit. + if (std::any_of(frameTargets.begin(), frameTargets.end(), + [this](const auto& pair) FTL_FAKE_GUARD(mStateLock) + FTL_FAKE_GUARD(kMainThreadContext) { + if (!pair.second->isFramePending()) return false; - // We received the present fence from the HWC, so we assume it successfully updated - // the mode, hence we update SF. - mSetActiveModePending = false; - { - Mutex::Autolock lock(mStateLock); - updateInternalStateWithChangedMode(); + if (const auto display = getDisplayDeviceLocked(pair.first)) { + return display->isModeSetPending(); + } + + return false; + })) { + mScheduler->scheduleFrame(); + return false; + } + + { + Mutex::Autolock lock(mStateLock); + + for (const auto [id, target] : frameTargets) { + // TODO(b/241285876): This is `nullptr` when the DisplayDevice is about to be removed in + // this commit, since the PhysicalDisplay has already been removed. Rather than checking + // for `nullptr` below, change Scheduler::onFrameSignal to filter out the FrameTarget of + // the removed display. + const auto display = getDisplayDeviceLocked(id); + + if (display && display->isModeSetPending()) { + finalizeDisplayModeChange(*display); + } } } @@ -2515,7 +2529,7 @@ bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) ? &mLayerHierarchyBuilder.getHierarchy() : nullptr, updateAttachedChoreographer); - setActiveModeInHwcIfNeeded(); + initiateDisplayModeChanges(); } updateCursorAsync(); @@ -3322,6 +3336,16 @@ void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bo mScheduler->onHotplugReceived(mSfConnectionHandle, displayId, connected); } +void SurfaceFlinger::dispatchDisplayModeChangeEvent(PhysicalDisplayId displayId, + const scheduler::FrameRateMode& mode) { + // TODO(b/255635821): Merge code paths and move to Scheduler. + const auto onDisplayModeChanged = displayId == mActiveDisplayId + ? &scheduler::Scheduler::onPrimaryDisplayModeChanged + : &scheduler::Scheduler::onNonPrimaryDisplayModeChanged; + + ((*mScheduler).*onDisplayModeChanged)(mAppConnectionHandle, mode); +} + sp SurfaceFlinger::setupNewDisplayDeviceInternal( const wp& displayToken, std::shared_ptr compositionDisplay, @@ -3420,14 +3444,8 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( RenderIntent::COLORIMETRIC}); if (const auto& physical = state.physical) { - mPhysicalDisplays.get(physical->id) - .transform(&PhysicalDisplay::snapshotRef) - .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) { - FTL_FAKE_GUARD(kMainThreadContext, - display->setActiveMode(physical->activeMode->getId(), - physical->activeMode->getFps(), - physical->activeMode->getFps())); - })); + const auto& mode = *physical->activeMode; + display->setActiveMode(mode.getId(), mode.getFps(), mode.getFps()); } display->setLayerFilter(makeLayerFilterForDisplay(display->getId(), state.layerStack)); @@ -3946,12 +3964,8 @@ void SurfaceFlinger::requestDisplayModes(std::vectorisPoweredOn()) { + ALOGV("%s(%s): Display is powered off", __func__, to_string(displayId).c_str()); continue; } @@ -3959,7 +3973,7 @@ void SurfaceFlinger::requestDisplayModes(std::vectorgetId().value(), - to_string(display->getId()).c_str()); + to_string(displayId).c_str()); } } } @@ -7922,6 +7936,7 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( const sp& display, const scheduler::RefreshRateSelector::PolicyVariant& policy) { const auto displayId = display->getPhysicalId(); + ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str()); Mutex::Autolock lock(mStateLock); @@ -7942,13 +7957,11 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( break; } - const bool isInternalDisplay = mPhysicalDisplays.get(displayId) - .transform(&PhysicalDisplay::isInternal) - .value_or(false); - - if (isInternalDisplay && displayId != mActiveDisplayId) { - // The policy will be be applied when the display becomes active. - ALOGV("%s(%s): Inactive display", __func__, to_string(displayId).c_str()); + // TODO(b/255635711): Apply the policy once the display is powered on, which is currently only + // done for the internal display that becomes active on fold/unfold. For now, assume that DM + // always powers on the secondary (internal or external) display before setting its policy. + if (!display->isPoweredOn()) { + ALOGV("%s(%s): Display is powered off", __func__, to_string(displayId).c_str()); return NO_ERROR; } @@ -8311,7 +8324,9 @@ void SurfaceFlinger::onActiveDisplayChangedLocked(const DisplayDevice* inactiveD resetPhaseConfiguration(activeDisplay.getActiveMode().fps); + // TODO(b/255635711): Check for pending mode changes on other displays. mScheduler->setModeChangePending(false); + mScheduler->setPacesetterDisplay(mActiveDisplayId); onActiveDisplaySizeChanged(activeDisplay); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b07910d360..f61f9a2345 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -638,7 +638,8 @@ private: // ICompositor overrides: void configure() override REQUIRES(kMainThreadContext); - bool commit(const scheduler::FrameTarget&) override REQUIRES(kMainThreadContext); + bool commit(PhysicalDisplayId pacesetterId, const scheduler::FrameTargets&) override + REQUIRES(kMainThreadContext); CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters&) override REQUIRES(kMainThreadContext); @@ -684,11 +685,10 @@ private: REQUIRES(mStateLock); status_t setActiveModeFromBackdoor(const sp&, DisplayModeId); - // Sets the active mode and a new refresh rate in SF. - void updateInternalStateWithChangedMode() REQUIRES(mStateLock, kMainThreadContext); - // Calls to setActiveMode on the main thread if there is a pending mode change - // that needs to be applied. - void setActiveModeInHwcIfNeeded() REQUIRES(mStateLock, kMainThreadContext); + + void initiateDisplayModeChanges() REQUIRES(mStateLock, kMainThreadContext); + void finalizeDisplayModeChange(DisplayDevice&) REQUIRES(mStateLock, kMainThreadContext); + void clearDesiredActiveModeState(const sp&) REQUIRES(mStateLock); // Called when active mode is no longer is progress void desiredActiveModeChangeDone(const sp&) REQUIRES(mStateLock); @@ -1011,7 +1011,9 @@ private: const DisplayDeviceState& drawingState) REQUIRES(mStateLock, kMainThreadContext); - void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected); + void dispatchDisplayHotplugEvent(PhysicalDisplayId, bool connected); + void dispatchDisplayModeChangeEvent(PhysicalDisplayId, const scheduler::FrameRateMode&) + REQUIRES(mStateLock); /* * VSYNC @@ -1330,9 +1332,6 @@ private: std::unique_ptr mRefreshRateStats; scheduler::PresentLatencyTracker mPresentLatencyTracker GUARDED_BY(kMainThreadContext); - // below flags are set by main thread only - bool mSetActiveModePending = false; - bool mLumaSampling = true; sp mRegionSamplingThread; sp mFpsReporter; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 28ac664ba3..ca1af6ed84 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -286,7 +286,7 @@ public: private: // ICompositor overrides: void configure() override {} - bool commit(const scheduler::FrameTarget&) override { return false; } + bool commit(PhysicalDisplayId, const scheduler::FrameTargets&) override { return false; } CompositeResultsPerDisplay composite(PhysicalDisplayId, const scheduler::FrameTargeters&) override { return {}; diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp index 1dcf222834..9aa089f900 100644 --- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp @@ -35,7 +35,7 @@ using CallbackToken = scheduler::VSyncDispatch::CallbackToken; struct NoOpCompositor final : ICompositor { void configure() override {} - bool commit(const scheduler::FrameTarget&) override { return false; } + bool commit(PhysicalDisplayId, const scheduler::FrameTargets&) override { return false; } CompositeResultsPerDisplay composite(PhysicalDisplayId, const scheduler::FrameTargeters&) override { return {}; diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index 703bdda694..24eb31821a 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -67,10 +67,36 @@ public: .WillByDefault(Return(true)); } + static constexpr HWDisplayId kInnerDisplayHwcId = PrimaryDisplayVariant::HWC_DISPLAY_ID; + static constexpr HWDisplayId kOuterDisplayHwcId = kInnerDisplayHwcId + 1; + + auto injectOuterDisplay() { + constexpr PhysicalDisplayId kOuterDisplayId = PhysicalDisplayId::fromPort(254u); + + constexpr bool kIsPrimary = false; + TestableSurfaceFlinger::FakeHwcDisplayInjector(kOuterDisplayId, hal::DisplayType::PHYSICAL, + kIsPrimary) + .setHwcDisplayId(kOuterDisplayHwcId) + .setPowerMode(hal::PowerMode::OFF) + .inject(&mFlinger, mComposer); + + mOuterDisplay = mFakeDisplayInjector.injectInternalDisplay( + [&](FakeDisplayDeviceInjector& injector) { + injector.setPowerMode(hal::PowerMode::OFF); + injector.setDisplayModes(mock::cloneForDisplay(kOuterDisplayId, kModes), + kModeId120); + }, + {.displayId = kOuterDisplayId, + .hwcDisplayId = kOuterDisplayHwcId, + .isPrimary = kIsPrimary}); + + return std::forward_as_tuple(mDisplay, mOuterDisplay); + } + protected: void setupScheduler(std::shared_ptr); - sp mDisplay; + sp mDisplay, mOuterDisplay; mock::EventThread* mAppEventThread; static constexpr DisplayModeId kModeId60{0}; @@ -328,32 +354,16 @@ MATCHER_P(ModeSettledTo, modeId, "") { return true; } -TEST_F(DisplayModeSwitchingTest, multiDisplay) { - constexpr HWDisplayId kInnerDisplayHwcId = PrimaryDisplayVariant::HWC_DISPLAY_ID; - constexpr HWDisplayId kOuterDisplayHwcId = kInnerDisplayHwcId + 1; - - constexpr PhysicalDisplayId kOuterDisplayId = PhysicalDisplayId::fromPort(254u); +TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) { + const auto [innerDisplay, outerDisplay] = injectOuterDisplay(); - constexpr bool kIsPrimary = false; - TestableSurfaceFlinger::FakeHwcDisplayInjector(kOuterDisplayId, hal::DisplayType::PHYSICAL, - kIsPrimary) - .setHwcDisplayId(kOuterDisplayHwcId) - .inject(&mFlinger, mComposer); - - const auto outerDisplay = mFakeDisplayInjector.injectInternalDisplay( - [&](FakeDisplayDeviceInjector& injector) { - injector.setDisplayModes(mock::cloneForDisplay(kOuterDisplayId, kModes), - kModeId120); - }, - {.displayId = kOuterDisplayId, - .hwcDisplayId = kOuterDisplayHwcId, - .isPrimary = kIsPrimary}); - - const auto& innerDisplay = mDisplay; + EXPECT_TRUE(innerDisplay->isPoweredOn()); + EXPECT_FALSE(outerDisplay->isPoweredOn()); EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60)); EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120)); + // Only the inner display is powered on. mFlinger.onActiveDisplayChanged(nullptr, *innerDisplay); EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60)); @@ -388,6 +398,10 @@ TEST_F(DisplayModeSwitchingTest, multiDisplay) { EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90)); EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120)); + innerDisplay->setPowerMode(hal::PowerMode::OFF); + outerDisplay->setPowerMode(hal::PowerMode::ON); + + // Only the outer display is powered on. mFlinger.onActiveDisplayChanged(innerDisplay.get(), *outerDisplay); EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90)); @@ -409,5 +423,107 @@ TEST_F(DisplayModeSwitchingTest, multiDisplay) { EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId60)); } +TEST_F(DisplayModeSwitchingTest, innerAndOuterDisplay) { + const auto [innerDisplay, outerDisplay] = injectOuterDisplay(); + + EXPECT_TRUE(innerDisplay->isPoweredOn()); + EXPECT_FALSE(outerDisplay->isPoweredOn()); + + EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60)); + EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120)); + + outerDisplay->setPowerMode(hal::PowerMode::ON); + + // Both displays are powered on. + mFlinger.onActiveDisplayChanged(nullptr, *innerDisplay); + + EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60)); + EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120)); + + EXPECT_EQ(NO_ERROR, + mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(), + mock::createDisplayModeSpecs(kModeId90.value(), + false, 0.f, 120.f))); + + EXPECT_EQ(NO_ERROR, + mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(), + mock::createDisplayModeSpecs(kModeId60.value(), + false, 0.f, 120.f))); + + EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90)); + EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60)); + + const VsyncPeriodChangeTimeline timeline{.refreshRequired = true}; + EXPECT_CALL(*mComposer, + setActiveConfigWithConstraints(kInnerDisplayHwcId, + hal::HWConfigId(kModeId90.value()), _, _)) + .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))); + + EXPECT_CALL(*mComposer, + setActiveConfigWithConstraints(kOuterDisplayHwcId, + hal::HWConfigId(kModeId60.value()), _, _)) + .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))); + + mFlinger.commit(); + + EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90)); + EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60)); + + mFlinger.commit(); + + EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90)); + EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId60)); +} + +TEST_F(DisplayModeSwitchingTest, powerOffDuringModeSet) { + const auto [innerDisplay, outerDisplay] = injectOuterDisplay(); + + EXPECT_TRUE(innerDisplay->isPoweredOn()); + EXPECT_FALSE(outerDisplay->isPoweredOn()); + + EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60)); + EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120)); + + outerDisplay->setPowerMode(hal::PowerMode::ON); + + // Both displays are powered on. + mFlinger.onActiveDisplayChanged(nullptr, *innerDisplay); + + EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId60)); + EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120)); + + EXPECT_EQ(NO_ERROR, + mFlinger.setDesiredDisplayModeSpecs(innerDisplay->getDisplayToken().promote(), + mock::createDisplayModeSpecs(kModeId90.value(), + false, 0.f, 120.f))); + + EXPECT_EQ(NO_ERROR, + mFlinger.setDesiredDisplayModeSpecs(outerDisplay->getDisplayToken().promote(), + mock::createDisplayModeSpecs(kModeId60.value(), + false, 0.f, 120.f))); + + EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90)); + EXPECT_THAT(outerDisplay, ModeSwitchingTo(&mFlinger, kModeId60)); + + // Power off the outer display before the mode has been set. + outerDisplay->setPowerMode(hal::PowerMode::OFF); + + const VsyncPeriodChangeTimeline timeline{.refreshRequired = true}; + EXPECT_CALL(*mComposer, + setActiveConfigWithConstraints(kInnerDisplayHwcId, + hal::HWConfigId(kModeId90.value()), _, _)) + .WillOnce(DoAll(SetArgPointee<3>(timeline), Return(Error::NONE))); + + mFlinger.commit(); + + EXPECT_THAT(innerDisplay, ModeSwitchingTo(&mFlinger, kModeId90)); + EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120)); + + mFlinger.commit(); + + EXPECT_THAT(innerDisplay, ModeSettledTo(kModeId90)); + EXPECT_THAT(outerDisplay, ModeSettledTo(kModeId120)); +} + } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index f3c9d0dd44..151b178c01 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -180,7 +180,7 @@ public: private: // ICompositor overrides: void configure() override {} - bool commit(const scheduler::FrameTarget&) override { return false; } + bool commit(PhysicalDisplayId, const scheduler::FrameTargets&) override { return false; } CompositeResultsPerDisplay composite(PhysicalDisplayId, const scheduler::FrameTargeters&) override { return {}; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 9b3a893409..e59d44d745 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -386,10 +386,19 @@ public: .sfWorkDuration = 10ms}, *mScheduler->getVsyncSchedule()); - mFlinger->commit(frameTargeter.target()); + scheduler::FrameTargets targets; + scheduler::FrameTargeters targeters; + + for (const auto& [id, display] : + FTL_FAKE_GUARD(mFlinger->mStateLock, mFlinger->mPhysicalDisplays)) { + targets.try_emplace(id, &frameTargeter.target()); + targeters.try_emplace(id, &frameTargeter); + } + + mFlinger->commit(displayId, targets); if (composite) { - mFlinger->composite(displayId, ftl::init::map(displayId, &frameTargeter)); + mFlinger->composite(displayId, targeters); } } -- GitLab From a069f0328ba069a5084843de89f49ebf5e13f9f5 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Mon, 31 Jul 2023 15:35:42 +0000 Subject: [PATCH 0387/1187] Revert^2 "Revert "Load native GLES driver when specified."" Revert reason: PcmaPhotoEditingV3 regressed, see b/293486861. Original change id: I6a2e716d340d9be3610c31abbcbe7984bf472f9f Bug: b/283858001 Bug: b/293486861 Test: atest CtsAngleDeveloperOptionHostTest -c with ANGLE being default Test: atest CtsAngleDeveloperOptionHostTest -c with native being default Change-Id: Id08acb6e18db095c632aa8d1a7810ede0c1a1ad2 --- libs/graphicsenv/GraphicsEnv.cpp | 19 ++---------- .../include/graphicsenv/GraphicsEnv.h | 8 +---- opengl/libs/EGL/Loader.cpp | 29 ++++--------------- 3 files changed, 10 insertions(+), 46 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 732ca36b44..715822b4e4 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -512,11 +512,7 @@ bool GraphicsEnv::shouldUseAngle() { return mShouldUseAngle; } -// Set ANGLE information. -// If path is "system", it means system ANGLE must be used for the process. -// If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. -// If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. -void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, +void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSystemAngle, const std::string& packageName, const std::vector eglFeatures) { if (mShouldUseAngle) { @@ -533,13 +529,8 @@ void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNati mAnglePath = std::move(path); ALOGV("setting app package name to '%s'", packageName.c_str()); mPackageName = std::move(packageName); - if (mAnglePath == "system") { - mShouldUseSystemAngle = true; - } - if (!mAnglePath.empty()) { - mShouldUseAngle = true; - } - mShouldUseNativeDriver = shouldUseNativeDriver; + mShouldUseAngle = true; + mShouldUseSystemAngle = shouldUseSystemAngle; } std::string& GraphicsEnv::getPackageName() { @@ -616,10 +607,6 @@ bool GraphicsEnv::shouldUseSystemAngle() { return mShouldUseSystemAngle; } -bool GraphicsEnv::shouldUseNativeDriver() { - return mShouldUseNativeDriver; -} - /** * APIs for debuggable layers */ diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index 6cce3f6998..fbf2902869 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -108,10 +108,7 @@ public: // (libraries must be stored uncompressed and page aligned); such elements // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a - // If the search patch is "system", then it means the system ANGLE should be used. - // If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. - // If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. - void setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, + void setAngleInfo(const std::string& path, const bool useSystemAngle, const std::string& packageName, const std::vector eglFeatures); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); @@ -121,7 +118,6 @@ public: // Set the persist.graphics.egl system property value. void nativeToggleAngleAsSystemDriver(bool enabled); bool shouldUseSystemAngle(); - bool shouldUseNativeDriver(); /* * Apis for debug layer @@ -179,8 +175,6 @@ private: bool mShouldUseAngle = false; // Whether loader should load system ANGLE. bool mShouldUseSystemAngle = false; - // Whether loader should load native GLES driver. - bool mShouldUseNativeDriver = false; // ANGLE namespace. android_namespace_t* mAngleNamespace = nullptr; diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 654e5b7c03..8d0eb590bf 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -169,11 +169,6 @@ static bool should_unload_system_driver(egl_connection_t* cnx) { } } - // Return true if native GLES drivers should be used and ANGLE is already loaded. - if (android::GraphicsEnv::getInstance().shouldUseNativeDriver() && cnx->angleLoaded) { - return true; - } - // Return true if updated driver namespace is set. ns = android::GraphicsEnv::getInstance().getDriverNamespace(); if (ns) { @@ -245,28 +240,16 @@ void* Loader::open(egl_connection_t* cnx) { if (!hnd) { // Secondly, try to load from driver apk. hnd = attempt_to_load_updated_driver(cnx); - - // If updated driver apk is set but fail to load, abort here. - LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace(), - "couldn't find an OpenGL ES implementation from %s", - android::GraphicsEnv::getInstance().getDriverPath().c_str()); } - // Attempt to load native GLES drivers specified by ro.hardware.egl if native is selected. - // If native is selected but fail to load, abort. - if (!hnd && android::GraphicsEnv::getInstance().shouldUseNativeDriver()) { - auto driverSuffix = base::GetProperty(RO_DRIVER_SUFFIX_PROPERTY, ""); - LOG_ALWAYS_FATAL_IF(driverSuffix.empty(), - "Native GLES driver is selected but not specified in %s", - RO_DRIVER_SUFFIX_PROPERTY); - hnd = attempt_to_load_system_driver(cnx, driverSuffix.c_str(), true); - LOG_ALWAYS_FATAL_IF(!hnd, "Native GLES driver is selected but failed to load. %s=%s", - RO_DRIVER_SUFFIX_PROPERTY, driverSuffix.c_str()); - } - - // Finally, try to load default driver. bool failToLoadFromDriverSuffixProperty = false; if (!hnd) { + // If updated driver apk is set but fail to load, abort here. + if (android::GraphicsEnv::getInstance().getDriverNamespace()) { + LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s", + android::GraphicsEnv::getInstance().getDriverPath().c_str()); + } + // Finally, try to load system driver. // Start by searching for the library name appended by the system // properties of the GLES userspace driver in both locations. // i.e.: -- GitLab From d6df2edb89026a676c6e0cc609dd5a8cac62fd7c Mon Sep 17 00:00:00 2001 From: Serdar Kocdemir Date: Tue, 1 Aug 2023 18:17:29 +0100 Subject: [PATCH 0388/1187] Duplicate the file descriptors for shellCommand Fixes the fdsan issues regarding the ownership of the file descriptors when running adb gpu commands. Bug: b/293209452 Test: adb shell cmd gpu vkjson Change-Id: Ifb624b888706759cf3689dbc34040e08e3d2d70b --- libs/graphicsenv/IGpuService.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp index 4c070aec01..1c0439ec1e 100644 --- a/libs/graphicsenv/IGpuService.cpp +++ b/libs/graphicsenv/IGpuService.cpp @@ -180,9 +180,9 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* rep return reply->writeUtf8AsUtf16(driverPath); } case SHELL_COMMAND_TRANSACTION: { - int in = data.readFileDescriptor(); - int out = data.readFileDescriptor(); - int err = data.readFileDescriptor(); + int in = dup(data.readFileDescriptor()); + int out = dup(data.readFileDescriptor()); + int err = dup(data.readFileDescriptor()); std::vector args; data.readString16Vector(&args); @@ -195,6 +195,9 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* rep status = shellCommand(in, out, err, args); if (resultReceiver != nullptr) resultReceiver->send(status); + ::close(in); + ::close(out); + ::close(err); return OK; } -- GitLab From 639ffc46598b9ab4f34abdb3e6d52ac0829f5a39 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 1 Aug 2023 17:53:56 +0000 Subject: [PATCH 0389/1187] libfakeservicemanager: thread safe Wasn't, used in fuzzers in a way that is hard to prove whether it's really needed or not. Avoid possibly hard to diagnose future issues. Bug: N/A Test: libfakeservicemanager_test Change-Id: I91d4d769ce40c1c3b82fb64fff748a380b43b8b6 --- libs/fakeservicemanager/FakeServiceManager.cpp | 12 ++++++++++++ .../include/fakeservicemanager/FakeServiceManager.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/libs/fakeservicemanager/FakeServiceManager.cpp b/libs/fakeservicemanager/FakeServiceManager.cpp index 3272bbc1aa..80661c1cbd 100644 --- a/libs/fakeservicemanager/FakeServiceManager.cpp +++ b/libs/fakeservicemanager/FakeServiceManager.cpp @@ -26,6 +26,8 @@ sp FakeServiceManager::getService( const String16& name) const { } sp FakeServiceManager::checkService( const String16& name) const { + std::lock_guard l(mMutex); + auto it = mNameToService.find(name); if (it == mNameToService.end()) { return nullptr; @@ -36,6 +38,8 @@ sp FakeServiceManager::checkService( const String16& name) const { status_t FakeServiceManager::addService(const String16& name, const sp& service, bool /*allowIsolated*/, int /*dumpsysFlags*/) { + std::lock_guard l(mMutex); + if (service == nullptr) { return UNEXPECTED_NULL; } @@ -44,6 +48,8 @@ status_t FakeServiceManager::addService(const String16& name, const sp& } Vector FakeServiceManager::listServices(int /*dumpsysFlags*/) { + std::lock_guard l(mMutex); + Vector services; for (auto const& [name, service] : mNameToService) { (void) service; @@ -61,10 +67,14 @@ sp FakeServiceManager::waitForService(const String16& name) { } bool FakeServiceManager::isDeclared(const String16& name) { + std::lock_guard l(mMutex); + return mNameToService.find(name) != mNameToService.end(); } Vector FakeServiceManager::getDeclaredInstances(const String16& name) { + std::lock_guard l(mMutex); + Vector out; const String16 prefix = name + String16("/"); for (const auto& [registeredName, service] : mNameToService) { @@ -108,6 +118,8 @@ std::vector FakeServiceManager::getServiceDeb } void FakeServiceManager::clear() { + std::lock_guard l(mMutex); + mNameToService.clear(); } } // namespace android diff --git a/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h b/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h index 97add24ac8..f62241d9c2 100644 --- a/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h +++ b/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -68,6 +69,7 @@ public: void clear(); private: + mutable std::mutex mMutex; std::map> mNameToService; }; -- GitLab From 568dbe780ba29e6f7ab444eef5634a7b1d0ff62b Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 28 Jul 2023 00:56:10 +0000 Subject: [PATCH 0390/1187] EventHub: Enforce that absolute axis values are within reported range Crash when an absolute axis value that is outside its reported range is sent from the kernel. This will help us identify cases where drivers are reporting events that do not conform to the evdev interface. Bug: 293156873 Test: presubmit Change-Id: I5080a031866f0dd7dabf06a20d75c52954303ae5 --- services/inputflinger/reader/EventHub.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index e69c99e9b5..db4070e1b9 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -456,6 +456,16 @@ static std::unordered_map readLightsConfigura return lightInfos; } +static bool isValidEvAbsValue(int32_t code, int32_t value, const RawAbsoluteAxisInfo& info) { + if (code == ABS_MT_TRACKING_ID && value == -1) { + return true; + } + if (value >= info.minValue && value <= info.maxValue) { + return true; + } + return false; +} + // --- Global Functions --- ftl::Flags getAbsAxisUsage(int32_t axis, @@ -804,6 +814,13 @@ void EventHub::Device::trackInputEvent(const struct input_event& event) { InputEventLookup::getLinuxEvdevLabel(EV_ABS, event.code, 0) .code.c_str(), event.value); + LOG_ALWAYS_FATAL_IF(!isValidEvAbsValue(event.code, event.value, it->second.info), + "%s: device '%s' received invalid value %d for EV_ABS code %s with " + "range [%d, %d]", + __func__, identifier.name.c_str(), event.value, + InputEventLookup::getLinuxEvdevLabel(EV_ABS, event.code, 0) + .code.c_str(), + it->second.info.minValue, it->second.info.maxValue); it->second.value = event.value; break; } -- GitLab From 8a33f042688a6e4c5cd1ace8073265ca4bfa4d12 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 31 Jul 2023 22:14:43 +0000 Subject: [PATCH 0391/1187] [sf] remove flaky tests from presubmit Change-Id: I75f647ef47e8cd4c78499bfddff91ea34134cb52 Test: presubmit --- services/surfaceflinger/TEST_MAPPING | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/TEST_MAPPING b/services/surfaceflinger/TEST_MAPPING index bfa5997e30..55127349eb 100644 --- a/services/surfaceflinger/TEST_MAPPING +++ b/services/surfaceflinger/TEST_MAPPING @@ -15,7 +15,16 @@ "name": "libscheduler_test" }, { - "name": "CtsGraphicsTestCases" + "name": "CtsGraphicsTestCases", + // flaky on mixed gsi builds + "options": [ + { + "exclude-filter": "android.graphics.cts.CameraGpuTest#testCameraImageCaptureAndRendering" + }, + { + "exclude-filter": "android.graphics.cts.AnimatorLeakTest#testPauseResume" + } + ] }, { "name": "CtsSurfaceControlTests" -- GitLab From adea715927393577ea95b1a31acf64e2e8e18aa9 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 27 Jul 2023 16:43:42 +0000 Subject: [PATCH 0392/1187] Adding a separate lib for random seed generation Adding a lib which produces fuzzer seeds from recorded transaction. It includes utility which reverses bytes from given value based on the ranges provided. Test: m libbinder_random_parcel_seeds Bug: 278975837 Change-Id: Ic6f27b4d8eec6329a9437af9a8ec217c76fbef19 --- libs/binder/tests/parcel_fuzzer/Android.bp | 25 +++ .../fuzzseeds/random_parcel_seeds.h | 47 ++++++ .../parcel_fuzzer/random_parcel_seeds.cpp | 146 ++++++++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h create mode 100644 libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp index 35866adf20..0d1503eda0 100644 --- a/libs/binder/tests/parcel_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/Android.bp @@ -104,3 +104,28 @@ cc_library_static { local_include_dirs: ["include_random_parcel"], export_include_dirs: ["include_random_parcel"], } + +cc_library { + name: "libbinder_random_parcel_seeds", + host_supported: true, + vendor_available: true, + target: { + darwin: { + enabled: false, + }, + }, + srcs: [ + "random_parcel_seeds.cpp", + ], + shared_libs: [ + "libbase", + "libbinder", + "libbinder_ndk", + "libcutils", + "libutils", + ], + local_include_dirs: [ + "include_random_parcel_seeds", + ], + export_include_dirs: ["include_random_parcel_seeds"], +} diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h new file mode 100644 index 0000000000..6cceb06b82 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2023 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 +#include +#include + +#include +#include +#include + +#include + +#include + +using android::Parcel; +using android::base::HexString; +using std::vector; + +namespace android { +namespace impl { +// computes the bytes so that if they are passed to FuzzedDataProvider and +// provider.ConsumeIntegralInRange(min, max) is called, it will return val +template +void writeReversedBuffer(std::vector& integralBuffer, T min, T max, T val); + +// Calls writeInBuffer method with min and max numeric limits of type T. This method +// is reversal of ConsumeIntegral() in FuzzedDataProvider +template +void writeReversedBuffer(std::vector& integralBuffer, T val); +} // namespace impl +void generateSeedsFromRecording(base::borrowed_fd fd, + binder::debug::RecordedTransaction&& transaction); +} // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp new file mode 100644 index 0000000000..7c66683252 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2023 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 +#include + +#include + +#include + +using android::base::WriteFully; + +namespace android { +namespace impl { +template +std::vector reverseBytes(T min, T max, T val) { + uint64_t range = static_cast(max) - min; + uint64_t result = val - min; + size_t offset = 0; + + std::vector reverseData; + uint8_t reversed = 0; + reversed |= result; + + while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0) { + reverseData.push_back(reversed); + reversed = 0; + reversed |= (result >> CHAR_BIT); + result = result >> CHAR_BIT; + offset += CHAR_BIT; + } + + return std::move(reverseData); +} + +template +void writeReversedBuffer(std::vector& integralBuffer, T min, T max, T val) { + std::vector reversedData = reverseBytes(min, max, val); + // ConsumeIntegral Calls read buffer from the end. Keep inserting at the front of the buffer + // so that we can align fuzzService operations with seed generation for readability. + integralBuffer.insert(integralBuffer.begin(), reversedData.begin(), reversedData.end()); +} + +template +void writeReversedBuffer(std::vector& integralBuffer, T val) { + // For ConsumeIntegral() calls, FuzzedDataProvider uses numeric limits min and max + // as range + writeReversedBuffer(integralBuffer, std::numeric_limits::min(), + std::numeric_limits::max(), val); +} + +} // namespace impl + +void generateSeedsFromRecording(base::borrowed_fd fd, + binder::debug::RecordedTransaction&& transaction) { + // Write Reserved bytes for future use + std::vector reservedBytes(8); + CHECK(WriteFully(fd, reservedBytes.data(), reservedBytes.size())) << fd.get(); + + std::vector integralBuffer; + + // Write UID array : Array elements are initialized in the order that they are declared + // UID array index 2 element + // int64_t aidRoot = 0; + impl::writeReversedBuffer(integralBuffer, static_cast(AID_ROOT) << 32, + static_cast(AID_USER) << 32, + static_cast(AID_ROOT) << 32); + + // UID array index 3 element + impl::writeReversedBuffer(integralBuffer, static_cast(AID_ROOT) << 32); + + // always pick AID_ROOT -> index 0 + size_t uidIndex = 0; + impl::writeReversedBuffer(integralBuffer, static_cast(0), static_cast(3), + uidIndex); + + // Never set uid in seed corpus + uint8_t writeUid = 0; + impl::writeReversedBuffer(integralBuffer, writeUid); + + // Read random code. this will be from recorded transaction + uint8_t selectCode = 1; + impl::writeReversedBuffer(integralBuffer, selectCode); + + // Get from recorded transaction + uint32_t code = transaction.getCode(); + impl::writeReversedBuffer(integralBuffer, code); + + // Get from recorded transaction + uint32_t flags = transaction.getFlags(); + impl::writeReversedBuffer(integralBuffer, flags); + + // always fuzz primary binder + size_t extraBindersIndex = 0; + impl::writeReversedBuffer(integralBuffer, static_cast(0), static_cast(0), + extraBindersIndex); + + const Parcel& dataParcel = transaction.getDataParcel(); + + // This buffer holds the bytes which will be used for fillRandomParcel API + std::vector fillParcelBuffer; + + // Don't take rpc path + uint8_t rpcBranch = 0; + impl::writeReversedBuffer(fillParcelBuffer, rpcBranch); + + // Implicit branch on this path -> options->writeHeader(p, provider) + uint8_t writeHeaderInternal = 0; + impl::writeReversedBuffer(fillParcelBuffer, writeHeaderInternal); + + // Choose to write data in parcel + size_t fillFuncIndex = 0; + impl::writeReversedBuffer(fillParcelBuffer, static_cast(0), static_cast(2), + fillFuncIndex); + + // Write parcel data size from recorded transaction + size_t toWrite = transaction.getDataParcel().dataBufferSize(); + impl::writeReversedBuffer(fillParcelBuffer, static_cast(0), toWrite, toWrite); + + // Write parcel data with size towrite from recorded transaction + CHECK(WriteFully(fd, dataParcel.data(), toWrite)) << fd.get(); + + // Write Fill Parcel buffer size in integralBuffer so that fuzzService knows size of data + size_t subDataSize = toWrite + fillParcelBuffer.size(); + impl::writeReversedBuffer(integralBuffer, static_cast(0), subDataSize, subDataSize); + + // Write fill parcel buffer + CHECK(WriteFully(fd, fillParcelBuffer.data(), fillParcelBuffer.size())) << fd.get(); + + // Write the integralBuffer to data + CHECK(WriteFully(fd, integralBuffer.data(), integralBuffer.size())) << fd.get(); +} +} // namespace android -- GitLab From ee6bf58e913545d2cb85156aad3a5b7b9ced72d7 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 27 Jul 2023 16:53:29 +0000 Subject: [PATCH 0393/1187] Read reserved bytes in fuzzService Updating fuzzService to read the reserved bytes for future needs. By reading reserved bytes already, we don't have to change the fuzzer corpus if any additional branches are introduced in fuzzService. Test: m libbinder_random_parcel Bug: 278975837 Change-Id: Ice0703e168b904ad959da0b41033e1056cdb6307 --- libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index b268c5dcd4..47d2a0a701 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -35,6 +35,11 @@ void fuzzService(const std::vector>& binders, FuzzedDataProvider&& p .extraFds = {}, }; + // Reserved bytes so that we don't have to change fuzzers and seed corpus if + // we introduce anything new in fuzzService. + std::vector reservedBytes = provider.ConsumeBytes(8); + (void)reservedBytes; + // always refresh the calling identity, because we sometimes set it below, but also, // the code we're fuzzing might reset it IPCThreadState::self()->clearCallingIdentity(); -- GitLab From 9d9c50a9ae39122b1fb62396ef008304fb6a91c2 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Tue, 1 Aug 2023 21:43:10 +0000 Subject: [PATCH 0394/1187] Revert "Adding ServiceManagerTestFuzzer to use seed corpus" This reverts commit 1b6e52ff3a8657f1e20c26dee82c321ed7dc8f78. Reason for revert: Reverting as seed corpus with fuzzService is now generated. Change-Id: I470e9eb69161306ed35e3044d49e2be498ea3615 --- cmds/servicemanager/Android.bp | 19 ++----- .../fuzzers/ServiceManagerTestFuzzer.cpp | 48 ------------------ .../Transaction_1 | Bin 40 -> 0 bytes .../Transaction_10 | Bin 136 -> 0 bytes .../Transaction_11 | Bin 40 -> 0 bytes .../Transaction_12 | Bin 136 -> 0 bytes .../Transaction_13 | Bin 40 -> 0 bytes .../Transaction_14 | Bin 136 -> 0 bytes .../Transaction_15 | Bin 40 -> 0 bytes .../Transaction_16 | Bin 136 -> 0 bytes .../Transaction_17 | Bin 40 -> 0 bytes .../Transaction_18 | Bin 144 -> 0 bytes .../Transaction_19 | Bin 144 -> 0 bytes .../Transaction_2 | Bin 136 -> 0 bytes .../Transaction_20 | Bin 40 -> 0 bytes .../Transaction_21 | Bin 144 -> 0 bytes .../Transaction_22 | Bin 144 -> 0 bytes .../Transaction_23 | Bin 40 -> 0 bytes .../Transaction_24 | Bin 144 -> 0 bytes .../Transaction_25 | Bin 144 -> 0 bytes .../Transaction_26 | Bin 40 -> 0 bytes .../Transaction_27 | Bin 144 -> 0 bytes .../Transaction_28 | Bin 144 -> 0 bytes .../Transaction_29 | Bin 40 -> 0 bytes .../Transaction_3 | Bin 40 -> 0 bytes .../Transaction_30 | Bin 144 -> 0 bytes .../Transaction_31 | Bin 144 -> 0 bytes .../Transaction_32 | Bin 40 -> 0 bytes .../Transaction_33 | Bin 144 -> 0 bytes .../Transaction_34 | Bin 144 -> 0 bytes .../Transaction_35 | Bin 40 -> 0 bytes .../Transaction_36 | Bin 144 -> 0 bytes .../Transaction_37 | Bin 144 -> 0 bytes .../Transaction_38 | Bin 40 -> 0 bytes .../Transaction_39 | Bin 136 -> 0 bytes .../Transaction_4 | Bin 144 -> 0 bytes .../Transaction_40 | Bin 40 -> 0 bytes .../Transaction_41 | Bin 136 -> 0 bytes .../Transaction_42 | Bin 168 -> 0 bytes .../Transaction_43 | Bin 152 -> 0 bytes .../Transaction_44 | Bin 168 -> 0 bytes .../Transaction_45 | Bin 40 -> 0 bytes .../Transaction_46 | Bin 136 -> 0 bytes .../Transaction_5 | Bin 40 -> 0 bytes .../Transaction_6 | Bin 136 -> 0 bytes .../Transaction_7 | Bin 40 -> 0 bytes .../Transaction_8 | Bin 136 -> 0 bytes .../Transaction_9 | Bin 40 -> 0 bytes 48 files changed, 3 insertions(+), 64 deletions(-) delete mode 100644 cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8 delete mode 100644 cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9 diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index fb69513d24..d73a30bf9b 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -93,22 +93,9 @@ cc_fuzz { libfuzzer_options: [ "max_len=50000", ], - }, -} - -// Adding this new fuzzer to test the corpus generated by record_binder -cc_fuzz { - name: "servicemanager_test_fuzzer", - defaults: [ - "servicemanager_defaults", - "service_fuzzer_defaults", - ], - host_supported: true, - srcs: ["fuzzers/ServiceManagerTestFuzzer.cpp"], - fuzz_config: { - libfuzzer_options: [ - "max_len=50000", + cc: [ + "smoreland@google.com", + "waghpawan@google.com", ], }, - corpus: ["fuzzers/servicemamanager_fuzzer_corpus/*"], } diff --git a/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp b/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp deleted file mode 100644 index e19b6eb279..0000000000 --- a/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2023 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 -#include - -#include "Access.h" -#include "ServiceManager.h" - -using ::android::Access; -using ::android::Parcel; -using ::android::ServiceManager; -using ::android::sp; - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - FuzzedDataProvider provider(data, size); - auto accessPtr = std::make_unique(); - auto serviceManager = sp::make(std::move(accessPtr)); - - // Reserved bytes - provider.ConsumeBytes(8); - uint32_t code = provider.ConsumeIntegral(); - uint32_t flag = provider.ConsumeIntegral(); - std::vector parcelData = provider.ConsumeRemainingBytes(); - - Parcel inputParcel; - inputParcel.setData(parcelData.data(), parcelData.size()); - - Parcel reply; - serviceManager->transact(code, inputParcel, &reply, flag); - - serviceManager->clear(); - - return 0; -} diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1 deleted file mode 100644 index 39e510492747e4e37c44114bc2ec47a6edfd92db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40 bcmZR80(ZZFco0(nL@+Qg{Qv(S%!1JXY1;=+ diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10 deleted file mode 100644 index 07319f864e46deabad8816b6a8f998de6f19443c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 136 zcmZR80wyRe0Hqli7#jZn|NlQEI5Jp@fq@~BA&()2p@<=$A(J76L60Gyp_oCB!IL4F zA(f$sp^PDuA(}m7#jZn|NlQEI5Jp@fq@~BA&()2p@<=$A(J76L60Gyp_oCB!IL4F zA(f$sp^PDuA(}m7#cv#kl@H*DFz0HM20+u6ow*(e1=Sh6b3zpe1>8MJqAyPV1`tN zB8D=COon8JR0dzLx;M1& diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20 deleted file mode 100644 index 39e510492747e4e37c44114bc2ec47a6edfd92db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40 bcmZR80(ZZFco0(nL@+Qg{Qv(S%!1JXY1;=+ diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21 deleted file mode 100644 index 88ad474f0944e99b479840294c5b26059cff5baf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144 zcmZR80wyRe1f>}m7#jZn|NlQEI5Jp@fq@~BA&()2p@<=$A(J76L60Gyp_oCB!IL4F zA(f$sp^PDuA(}m7#cv#kl@H*DFz0HM20+u6ow*(e1=Sh6b3zpe1>8MJqAyPV1`tN zB8D=COon8JR0dzLx}m7#jZn|NlQEI5Jp@fq@~BA&()2p@<=$A(J76L60Gyp_oCB!IL4F zA(f$sp^PDuA(}m7#cv#kl@H*DFz0HM20+u6ow*(e1=Sh6b3zpe1>8MJqAyPV1`tN zB8D=COon8JR0dzLx}m7#jZn|NlQEI5Jp@fq@~BA&()2p@<=$A(J76L60Gyp_oCB!IL4F zA(f$sp^PDuA(}m7#cv#kl@H*DFz0HM20+u6ow*(e1=Sh6b3zpe1>8MJqAyPV1`tN zB8D=COon8JR0dzLx}m7#jZn|NlQEI5Jp@fq@~BA&()2p@<=$A(J76L60Gyp_oCB!IL4F zA(f$sp^PDuA(}m7#cv#kl@H*DFz0HM20+u6ow*(e1=Sh6b3zpe1>8MJqAyPV1`tN zB8D=COon8JR0dzLx}m7#jZn|NlQEI5Jp@fq@~BA&()2p@<=$A(J76L60Gyp_oCB!IL4F zA(f$sp^PDuA(}m7#cv#kl@H*DFz0HM20+u6ow*(e1=Sh6b3zpe1>8MJqAyPV1`tN zB8D=COon8JR0dzLx}m7#jZn|NlQEI5Jp@fq@~BA&()2p@<=$A(J76L60Gyp_oCB!IL4F zA(f$sp^PDuA(}m7#cv#kl@H*DFz0HM20+u6ow*(e1=Sh6b3zpe1>8MJqAyPV1`tN zB8D=COon8JR0dzLx}m7#dzMGcbe%M+QqVFfb%C}m7#dzMGcbe%M+QqVFfb%C Date: Tue, 1 Aug 2023 23:31:34 +0000 Subject: [PATCH 0395/1187] Revert^3 "Revert "Load native GLES driver when specified."" Reason for revert: Revert to reland the patch. Original patch was reverted due to PcmaPhotoEditingV3 regression, see b/293486861. Original commit message: """ Load native GLES driver when specified. Since ANGLE and native GLES drivers can coexist, when native is specified, the loader must load the native GLES drivers specified in ro.hardware.egl. This patch passes this information down to the native graphics environment so that the EGL loader can properly check. Bug: b/283858001 Test: atest CtsAngleDeveloperOptionHostTest -c with ANGLE being default Test: atest CtsAngleDeveloperOptionHostTest -c with native being default """ Bug: b/283858001 Test: atest CtsAngleDeveloperOptionHostTest -c with ANGLE being default Test: atest CtsAngleDeveloperOptionHostTest -c with native being default Change-Id: Ibcf9d765ce1bd8931859d1c11e849a311adda172 --- libs/graphicsenv/GraphicsEnv.cpp | 19 ++++++++++-- .../include/graphicsenv/GraphicsEnv.h | 8 ++++- opengl/libs/EGL/Loader.cpp | 29 +++++++++++++++---- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 715822b4e4..732ca36b44 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -512,7 +512,11 @@ bool GraphicsEnv::shouldUseAngle() { return mShouldUseAngle; } -void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSystemAngle, +// Set ANGLE information. +// If path is "system", it means system ANGLE must be used for the process. +// If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. +// If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. +void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, const std::string& packageName, const std::vector eglFeatures) { if (mShouldUseAngle) { @@ -529,8 +533,13 @@ void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSyst mAnglePath = std::move(path); ALOGV("setting app package name to '%s'", packageName.c_str()); mPackageName = std::move(packageName); - mShouldUseAngle = true; - mShouldUseSystemAngle = shouldUseSystemAngle; + if (mAnglePath == "system") { + mShouldUseSystemAngle = true; + } + if (!mAnglePath.empty()) { + mShouldUseAngle = true; + } + mShouldUseNativeDriver = shouldUseNativeDriver; } std::string& GraphicsEnv::getPackageName() { @@ -607,6 +616,10 @@ bool GraphicsEnv::shouldUseSystemAngle() { return mShouldUseSystemAngle; } +bool GraphicsEnv::shouldUseNativeDriver() { + return mShouldUseNativeDriver; +} + /** * APIs for debuggable layers */ diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index fbf2902869..6cce3f6998 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -108,7 +108,10 @@ public: // (libraries must be stored uncompressed and page aligned); such elements // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a - void setAngleInfo(const std::string& path, const bool useSystemAngle, + // If the search patch is "system", then it means the system ANGLE should be used. + // If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. + // If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. + void setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, const std::string& packageName, const std::vector eglFeatures); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); @@ -118,6 +121,7 @@ public: // Set the persist.graphics.egl system property value. void nativeToggleAngleAsSystemDriver(bool enabled); bool shouldUseSystemAngle(); + bool shouldUseNativeDriver(); /* * Apis for debug layer @@ -175,6 +179,8 @@ private: bool mShouldUseAngle = false; // Whether loader should load system ANGLE. bool mShouldUseSystemAngle = false; + // Whether loader should load native GLES driver. + bool mShouldUseNativeDriver = false; // ANGLE namespace. android_namespace_t* mAngleNamespace = nullptr; diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 8d0eb590bf..654e5b7c03 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -169,6 +169,11 @@ static bool should_unload_system_driver(egl_connection_t* cnx) { } } + // Return true if native GLES drivers should be used and ANGLE is already loaded. + if (android::GraphicsEnv::getInstance().shouldUseNativeDriver() && cnx->angleLoaded) { + return true; + } + // Return true if updated driver namespace is set. ns = android::GraphicsEnv::getInstance().getDriverNamespace(); if (ns) { @@ -240,16 +245,28 @@ void* Loader::open(egl_connection_t* cnx) { if (!hnd) { // Secondly, try to load from driver apk. hnd = attempt_to_load_updated_driver(cnx); + + // If updated driver apk is set but fail to load, abort here. + LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace(), + "couldn't find an OpenGL ES implementation from %s", + android::GraphicsEnv::getInstance().getDriverPath().c_str()); } + // Attempt to load native GLES drivers specified by ro.hardware.egl if native is selected. + // If native is selected but fail to load, abort. + if (!hnd && android::GraphicsEnv::getInstance().shouldUseNativeDriver()) { + auto driverSuffix = base::GetProperty(RO_DRIVER_SUFFIX_PROPERTY, ""); + LOG_ALWAYS_FATAL_IF(driverSuffix.empty(), + "Native GLES driver is selected but not specified in %s", + RO_DRIVER_SUFFIX_PROPERTY); + hnd = attempt_to_load_system_driver(cnx, driverSuffix.c_str(), true); + LOG_ALWAYS_FATAL_IF(!hnd, "Native GLES driver is selected but failed to load. %s=%s", + RO_DRIVER_SUFFIX_PROPERTY, driverSuffix.c_str()); + } + + // Finally, try to load default driver. bool failToLoadFromDriverSuffixProperty = false; if (!hnd) { - // If updated driver apk is set but fail to load, abort here. - if (android::GraphicsEnv::getInstance().getDriverNamespace()) { - LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s", - android::GraphicsEnv::getInstance().getDriverPath().c_str()); - } - // Finally, try to load system driver. // Start by searching for the library name appended by the system // properties of the GLES userspace driver in both locations. // i.e.: -- GitLab From abf991c2e076597f1daf91ffb9196d5b29befb38 Mon Sep 17 00:00:00 2001 From: Andrei Homescu Date: Fri, 7 Jul 2023 05:10:43 +0000 Subject: [PATCH 0396/1187] libbinder_rs: Use a bindgen flag file Store the bindgen flags in a file so they can be shared between the Android and Trusty build systems. Bug: 242243245 Test: presubmit Change-Id: Id579628660d05eaddb05b5ac7d7fd12e7d75c4d9 --- libs/binder/rust/Android.bp | 26 ++----------------- .../rust/libbinder_ndk_bindgen_flags.txt | 11 ++++++++ 2 files changed, 13 insertions(+), 24 deletions(-) create mode 100644 libs/binder/rust/libbinder_ndk_bindgen_flags.txt diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp index d36ebac109..672d6cf5d0 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -97,34 +97,12 @@ rust_bindgen { crate_name: "binder_ndk_bindgen", wrapper_src: "sys/BinderBindings.hpp", source_stem: "bindings", - bindgen_flags: [ + bindgen_flag_files: [ // Unfortunately the only way to specify the rust_non_exhaustive enum // style for a type is to make it the default - "--default-enum-style", - "rust_non_exhaustive", // and then specify constified enums for the enums we don't want // rustified - "--constified-enum", - "android::c_interface::consts::.*", - - "--allowlist-type", - "android::c_interface::.*", - "--allowlist-type", - "AStatus", - "--allowlist-type", - "AIBinder_Class", - "--allowlist-type", - "AIBinder", - "--allowlist-type", - "AIBinder_Weak", - "--allowlist-type", - "AIBinder_DeathRecipient", - "--allowlist-type", - "AParcel", - "--allowlist-type", - "binder_status_t", - "--allowlist-function", - ".*", + "libbinder_ndk_bindgen_flags.txt", ], shared_libs: [ "libbinder_ndk", diff --git a/libs/binder/rust/libbinder_ndk_bindgen_flags.txt b/libs/binder/rust/libbinder_ndk_bindgen_flags.txt new file mode 100644 index 0000000000..551c59f671 --- /dev/null +++ b/libs/binder/rust/libbinder_ndk_bindgen_flags.txt @@ -0,0 +1,11 @@ +--default-enum-style=rust_non_exhaustive +--constified-enum=android::c_interface::consts::.* +--allowlist-type=android::c_interface::.* +--allowlist-type=AStatus +--allowlist-type=AIBinder_Class +--allowlist-type=AIBinder +--allowlist-type=AIBinder_Weak +--allowlist-type=AIBinder_DeathRecipient +--allowlist-type=AParcel +--allowlist-type=binder_status_t +--allowlist-function=.* -- GitLab From f17efd092aa969b55923bc20bd72d39348b107fa Mon Sep 17 00:00:00 2001 From: Yi Kong Date: Wed, 2 Aug 2023 03:36:13 +0900 Subject: [PATCH 0397/1187] Turn on LTO optmisations for libbinder This improves app launch performance by 0.13%. http://go/art-benchmark?p=BootImageProfileId:36062 Test: presubmit Change-Id: If438da2f0a814e951687b50e46187bbf450a7629 --- libs/binder/Android.bp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index deff76b3a5..f634c1dcde 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -190,6 +190,9 @@ cc_defaults { "-performance-move-const-arg", // b/273486801 "portability*", ], + lto: { + thin: true, + }, } cc_library_headers { -- GitLab From bfbf68aa7a509698afc8ef51956a557859234cd2 Mon Sep 17 00:00:00 2001 From: Kangping Dong Date: Wed, 2 Aug 2023 16:27:41 +0800 Subject: [PATCH 0398/1187] [Thread] rename threadnetwork to thread_network Per requests from API councilor. See b/293245448 for details. Bug: 293245448 Change-Id: Ia6f5c9429ebf872e7f48684c66daabcfb333b2e5 --- data/etc/Android.bp | 4 ++-- ....threadnetwork.xml => android.hardware.thread_network.xml} | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename data/etc/{android.hardware.threadnetwork.xml => android.hardware.thread_network.xml} (83%) diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 92dc46ed8d..60fb134c3c 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -173,8 +173,8 @@ prebuilt_etc { } prebuilt_etc { - name: "android.hardware.threadnetwork.prebuilt.xml", - src: "android.hardware.threadnetwork.xml", + name: "android.hardware.thread_network.prebuilt.xml", + src: "android.hardware.thread_network.xml", defaults: ["frameworks_native_data_etc_defaults"], } diff --git a/data/etc/android.hardware.threadnetwork.xml b/data/etc/android.hardware.thread_network.xml similarity index 83% rename from data/etc/android.hardware.threadnetwork.xml rename to data/etc/android.hardware.thread_network.xml index 9cbdc905fb..b116ed6bf8 100644 --- a/data/etc/android.hardware.threadnetwork.xml +++ b/data/etc/android.hardware.thread_network.xml @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. --> - + - + -- GitLab From 8fa4561dda2d18fb7646d03b01c43fa74a0df28d Mon Sep 17 00:00:00 2001 From: Serdar Kocdemir Date: Fri, 9 Jun 2023 15:45:43 +0100 Subject: [PATCH 0399/1187] Add deqp.level-latest.xml files Adding following files to ease targeting latest dEQP levels for devices: * data/etc/android.software.vulkan.deqp.level-latest.xml * data/etc/android.software.opengles.deqp.level-latest.xml Devices that will always target latest Android version can use these new xml files to avoid updating device.mk files each year. Files will be updated with the latest dEQP level once new test lists are created. Bug: b/286805604 Test: manual Change-Id: I5c683871eae261bf809da3a02939ee17fd6ab96a --- data/etc/Android.bp | 12 +++++++++++ ...id.software.opengles.deqp.level-latest.xml | 21 +++++++++++++++++++ ...roid.software.vulkan.deqp.level-latest.xml | 21 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 data/etc/android.software.opengles.deqp.level-latest.xml create mode 100644 data/etc/android.software.vulkan.deqp.level-latest.xml diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 2143d93632..3ce586bcd6 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -340,6 +340,12 @@ prebuilt_etc { defaults: ["frameworks_native_data_etc_defaults"], } +prebuilt_etc { + name: "android.software.opengles.deqp.level-latest.prebuilt.xml", + src: "android.software.opengles.deqp.level-latest.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + prebuilt_etc { name: "android.software.sip.voip.prebuilt.xml", src: "android.software.sip.voip.xml", @@ -370,6 +376,12 @@ prebuilt_etc { defaults: ["frameworks_native_data_etc_defaults"], } +prebuilt_etc { + name: "android.software.vulkan.deqp.level-latest.prebuilt.xml", + src: "android.software.vulkan.deqp.level-latest.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + prebuilt_etc { name: "aosp_excluded_hardware.prebuilt.xml", src: "aosp_excluded_hardware.xml", diff --git a/data/etc/android.software.opengles.deqp.level-latest.xml b/data/etc/android.software.opengles.deqp.level-latest.xml new file mode 100644 index 0000000000..bd15eb6eb2 --- /dev/null +++ b/data/etc/android.software.opengles.deqp.level-latest.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/data/etc/android.software.vulkan.deqp.level-latest.xml b/data/etc/android.software.vulkan.deqp.level-latest.xml new file mode 100644 index 0000000000..87be0709d6 --- /dev/null +++ b/data/etc/android.software.vulkan.deqp.level-latest.xml @@ -0,0 +1,21 @@ + + + + + + + -- GitLab From 6c658cc4b29414bfc0e70141820eca1badf9cf06 Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Wed, 2 Aug 2023 14:40:40 +0000 Subject: [PATCH 0400/1187] InputTransport: allow resampling logs to be enabled without restart To debug a flaky CTS test I'd like to add the resampling logs to the DebugInputRule, for which they need to be enabled without restarting on debuggable builds. Bug: 292544797 Test: set the sysprop to DEBUG, touch the screen, and check resampling logs appear in logcat. Set the sysprop to UNKNOWN, touch the screen, and check that they no longer appear Change-Id: Ibf7fe9b842374d0ee48f86c67e22a2fb3c78273f --- libs/input/InputTransport.cpp | 38 ++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index d9b7700f4f..3446540ccf 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -75,10 +75,20 @@ bool debugTransportPublisher() { /** * Log debug messages about touch event resampling. - * Enable this via "adb shell setprop log.tag.InputTransportResampling DEBUG" (requires restart) + * + * Enable this via "adb shell setprop log.tag.InputTransportResampling DEBUG". + * This requires a restart on non-debuggable (e.g. user) builds, but should take effect immediately + * on debuggable builds (e.g. userdebug). */ -const bool DEBUG_RESAMPLING = - __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Resampling", ANDROID_LOG_INFO); +bool debugResampling() { + if (!IS_DEBUGGABLE_BUILD) { + static const bool DEBUG_TRANSPORT_RESAMPLING = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Resampling", + ANDROID_LOG_INFO); + return DEBUG_TRANSPORT_RESAMPLING; + } + return __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Resampling", ANDROID_LOG_INFO); +} } // namespace @@ -1158,7 +1168,7 @@ void InputConsumer::rewriteMessage(TouchState& state, InputMessage& msg) { state.recentCoordinatesAreIdentical(id)) { PointerCoords& msgCoords = msg.body.motion.pointers[i].coords; const PointerCoords& resampleCoords = state.lastResample.getPointerById(id); - ALOGD_IF(DEBUG_RESAMPLING, "[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id, + ALOGD_IF(debugResampling(), "[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id, resampleCoords.getX(), resampleCoords.getY(), msgCoords.getX(), msgCoords.getY()); msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX()); @@ -1181,13 +1191,13 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, ssize_t index = findTouchState(event->getDeviceId(), event->getSource()); if (index < 0) { - ALOGD_IF(DEBUG_RESAMPLING, "Not resampled, no touch state for device."); + ALOGD_IF(debugResampling(), "Not resampled, no touch state for device."); return; } TouchState& touchState = mTouchStates[index]; if (touchState.historySize < 1) { - ALOGD_IF(DEBUG_RESAMPLING, "Not resampled, no history for device."); + ALOGD_IF(debugResampling(), "Not resampled, no history for device."); return; } @@ -1197,7 +1207,7 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, for (size_t i = 0; i < pointerCount; i++) { uint32_t id = event->getPointerId(i); if (!current->idBits.hasBit(id)) { - ALOGD_IF(DEBUG_RESAMPLING, "Not resampled, missing id %d", id); + ALOGD_IF(debugResampling(), "Not resampled, missing id %d", id); return; } } @@ -1213,7 +1223,7 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, other = &future; nsecs_t delta = future.eventTime - current->eventTime; if (delta < RESAMPLE_MIN_DELTA) { - ALOGD_IF(DEBUG_RESAMPLING, "Not resampled, delta time is too small: %" PRId64 " ns.", + ALOGD_IF(debugResampling(), "Not resampled, delta time is too small: %" PRId64 " ns.", delta); return; } @@ -1224,17 +1234,17 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, other = touchState.getHistory(1); nsecs_t delta = current->eventTime - other->eventTime; if (delta < RESAMPLE_MIN_DELTA) { - ALOGD_IF(DEBUG_RESAMPLING, "Not resampled, delta time is too small: %" PRId64 " ns.", + ALOGD_IF(debugResampling(), "Not resampled, delta time is too small: %" PRId64 " ns.", delta); return; } else if (delta > RESAMPLE_MAX_DELTA) { - ALOGD_IF(DEBUG_RESAMPLING, "Not resampled, delta time is too large: %" PRId64 " ns.", + ALOGD_IF(debugResampling(), "Not resampled, delta time is too large: %" PRId64 " ns.", delta); return; } nsecs_t maxPredict = current->eventTime + min(delta / 2, RESAMPLE_MAX_PREDICTION); if (sampleTime > maxPredict) { - ALOGD_IF(DEBUG_RESAMPLING, + ALOGD_IF(debugResampling(), "Sample time is too far in the future, adjusting prediction " "from %" PRId64 " to %" PRId64 " ns.", sampleTime - current->eventTime, maxPredict - current->eventTime); @@ -1242,7 +1252,7 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, } alpha = float(current->eventTime - sampleTime) / delta; } else { - ALOGD_IF(DEBUG_RESAMPLING, "Not resampled, insufficient data."); + ALOGD_IF(debugResampling(), "Not resampled, insufficient data."); return; } @@ -1284,13 +1294,13 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, lerp(currentCoords.getY(), otherCoords.getY(), alpha)); resampledCoords.isResampled = true; - ALOGD_IF(DEBUG_RESAMPLING, + ALOGD_IF(debugResampling(), "[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f), " "other (%0.3f, %0.3f), alpha %0.3f", id, resampledCoords.getX(), resampledCoords.getY(), currentCoords.getX(), currentCoords.getY(), otherCoords.getX(), otherCoords.getY(), alpha); } else { - ALOGD_IF(DEBUG_RESAMPLING, "[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f)", id, + ALOGD_IF(debugResampling(), "[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f)", id, resampledCoords.getX(), resampledCoords.getY(), currentCoords.getX(), currentCoords.getY()); } -- GitLab From 60ed836681de81911b702390c7e6d1929aab5fe8 Mon Sep 17 00:00:00 2001 From: Vladimir Komsiyski Date: Fri, 16 Jun 2023 10:03:16 +0200 Subject: [PATCH 0401/1187] Process runtime sensor events in a separate thread. SensorService::threadLoop blocks while polling from the device, which causes the runtime sensor events to never be processed in case there are no "real" sensor events. Separating the threads that handle the "real" and the runtime sensor events solves the issue - verified by adding a long sleep in poll() and VirtualSensorTest still passes. The new thread is only started when the the first runtime sensor is registered. Bug: 281452823 Bug: 288383960 Test: atest VirtualSensorTest Test: atest cts/tests/sensor Change-Id: I96bb217c72462d29c68c510bd7cea97ac925ccb2 --- services/sensorservice/SensorService.cpp | 95 ++++++++++++++++-------- services/sensorservice/SensorService.h | 19 ++++- 2 files changed, 83 insertions(+), 31 deletions(-) diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 398d60242b..cfafc69484 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -63,8 +63,10 @@ #include #include +#include #include #include +#include #include #include @@ -196,6 +198,16 @@ int SensorService::registerRuntimeSensor( if (mRuntimeSensorCallbacks.find(deviceId) == mRuntimeSensorCallbacks.end()) { mRuntimeSensorCallbacks.emplace(deviceId, callback); } + + if (mRuntimeSensorHandler == nullptr) { + mRuntimeSensorEventBuffer = + new sensors_event_t[SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT]; + mRuntimeSensorHandler = new RuntimeSensorHandler(this); + // Use PRIORITY_URGENT_DISPLAY as the injected sensor events should be dispatched as soon as + // possible, and also for consistency within the SensorService. + mRuntimeSensorHandler->run("RuntimeSensorHandler", PRIORITY_URGENT_DISPLAY); + } + return handle; } @@ -232,8 +244,9 @@ status_t SensorService::unregisterRuntimeSensor(int handle) { } status_t SensorService::sendRuntimeSensorEvent(const sensors_event_t& event) { - Mutex::Autolock _l(mLock); + std::unique_lock lock(mRutimeSensorThreadMutex); mRuntimeSensorEventQueue.push(event); + mRuntimeSensorsCv.notify_all(); return OK; } @@ -458,6 +471,7 @@ void SensorService::onFirstRef() { const size_t minBufferSize = SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT; mSensorEventBuffer = new sensors_event_t[minBufferSize]; mSensorEventScratch = new sensors_event_t[minBufferSize]; + mRuntimeSensorEventBuffer = nullptr; mMapFlushEventsToConnections = new wp [minBufferSize]; mCurrentOperatingMode = NORMAL; @@ -1089,7 +1103,6 @@ bool SensorService::threadLoop() { recordLastValueLocked(mSensorEventBuffer, count); // handle virtual sensors - bool bufferNeedsSorting = false; if (count && vcount) { sensors_event_t const * const event = mSensorEventBuffer; if (!mActiveVirtualSensors.empty()) { @@ -1125,37 +1138,11 @@ bool SensorService::threadLoop() { // record the last synthesized values recordLastValueLocked(&mSensorEventBuffer[count], k); count += k; - bufferNeedsSorting = true; + sortEventBuffer(mSensorEventBuffer, count); } } } - // handle runtime sensors - { - size_t k = 0; - while (!mRuntimeSensorEventQueue.empty()) { - if (count + k >= minBufferSize) { - ALOGE("buffer too small to hold all events: count=%zd, k=%zu, size=%zu", - count, k, minBufferSize); - break; - } - mSensorEventBuffer[count + k] = mRuntimeSensorEventQueue.front(); - mRuntimeSensorEventQueue.pop(); - k++; - } - if (k) { - // record the last synthesized values - recordLastValueLocked(&mSensorEventBuffer[count], k); - count += k; - bufferNeedsSorting = true; - } - } - - if (bufferNeedsSorting) { - // sort the buffer by time-stamps - sortEventBuffer(mSensorEventBuffer, count); - } - // handle backward compatibility for RotationVector sensor if (halVersion < SENSORS_DEVICE_API_VERSION_1_0) { for (int i = 0; i < count; i++) { @@ -1234,7 +1221,7 @@ bool SensorService::threadLoop() { bool needsWakeLock = false; for (const sp& connection : activeConnections) { connection->sendEvents(mSensorEventBuffer, count, mSensorEventScratch, - mMapFlushEventsToConnections); + mMapFlushEventsToConnections); needsWakeLock |= connection->needsWakeLock(); // If the connection has one-shot sensors, it may be cleaned up after first trigger. // Early check for one-shot sensors. @@ -1253,6 +1240,46 @@ bool SensorService::threadLoop() { return false; } +void SensorService::processRuntimeSensorEvents() { + size_t count = 0; + const size_t maxBufferSize = SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT; + + { + std::unique_lock lock(mRutimeSensorThreadMutex); + + if (mRuntimeSensorEventQueue.empty()) { + mRuntimeSensorsCv.wait(lock, [this] { return !mRuntimeSensorEventQueue.empty(); }); + } + + // Pop the events from the queue into the buffer until it's empty or the buffer is full. + while (!mRuntimeSensorEventQueue.empty()) { + if (count >= maxBufferSize) { + ALOGE("buffer too small to hold all events: count=%zd, size=%zu", count, + maxBufferSize); + break; + } + mRuntimeSensorEventBuffer[count] = mRuntimeSensorEventQueue.front(); + mRuntimeSensorEventQueue.pop(); + count++; + } + } + + if (count) { + ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock); + + recordLastValueLocked(mRuntimeSensorEventBuffer, count); + sortEventBuffer(mRuntimeSensorEventBuffer, count); + + for (const sp& connection : connLock.getActiveConnections()) { + connection->sendEvents(mRuntimeSensorEventBuffer, count, /* scratch= */ nullptr, + /* mapFlushEventsToConnections= */ nullptr); + if (connection->hasOneShotSensors()) { + cleanupAutoDisabledSensorLocked(connection, mRuntimeSensorEventBuffer, count); + } + } + } +} + sp SensorService::getLooper() const { return mLooper; } @@ -1300,6 +1327,14 @@ bool SensorService::SensorEventAckReceiver::threadLoop() { return false; } +bool SensorService::RuntimeSensorHandler::threadLoop() { + ALOGD("new thread RuntimeSensorHandler"); + do { + mService->processRuntimeSensorEvents(); + } while (!Thread::exitPending()); + return false; +} + void SensorService::recordLastValueLocked( const sensors_event_t* buffer, size_t count) { for (size_t i = 0; i < count; i++) { diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 545f6c25d5..bf4310119d 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -42,6 +42,8 @@ #include #include +#include +#include #include #include #include @@ -208,6 +210,7 @@ private: class SensorEventAckReceiver; class SensorRecord; class SensorRegistrationInfo; + class RuntimeSensorHandler; // Promoting a SensorEventConnection or SensorDirectConnection from wp to sp must be done with // mLock held, but destroying that sp must be done unlocked to avoid a race condition that @@ -264,6 +267,14 @@ private: SortedVector< wp > mDirectConnections; }; + class RuntimeSensorHandler : public Thread { + sp const mService; + public: + virtual bool threadLoop(); + explicit RuntimeSensorHandler(const sp& service) : mService(service) { + } + }; + // If accessing a sensor we need to make sure the UID has access to it. If // the app UID is idle then it cannot access sensors and gets no trigger // events, no on-change events, flush event behavior does not change, and @@ -368,6 +379,8 @@ private: // Thread interface virtual bool threadLoop(); + void processRuntimeSensorEvents(); + // ISensorServer interface virtual Vector getSensorList(const String16& opPackageName); virtual Vector getDynamicSensorList(const String16& opPackageName); @@ -512,6 +525,10 @@ private: uint32_t mSocketBufferSize; sp mLooper; sp mAckReceiver; + sp mRuntimeSensorHandler; + // Mutex and CV used to notify the mRuntimeSensorHandler thread that there are new events. + std::mutex mRutimeSensorThreadMutex; + std::condition_variable mRuntimeSensorsCv; // protected by mLock mutable Mutex mLock; @@ -519,7 +536,7 @@ private: std::unordered_set mActiveVirtualSensors; SensorConnectionHolder mConnectionHolder; bool mWakeLockAcquired; - sensors_event_t *mSensorEventBuffer, *mSensorEventScratch; + sensors_event_t *mSensorEventBuffer, *mSensorEventScratch, *mRuntimeSensorEventBuffer; // WARNING: these SensorEventConnection instances must not be promoted to sp, except via // modification to add support for them in ConnectionSafeAutolock wp * mMapFlushEventsToConnections; -- GitLab From b2359cd302da157979a585b797130e3c1c705497 Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Fri, 28 Jul 2023 14:33:49 +0530 Subject: [PATCH 0402/1187] ultrahdr: updates to jpegr impl - clang-format the code to a common guideline - return status of areInputArgumentsValid call as-is - rename variables for easier understanding - reduce control code by assigning stride(s) and chroma ptr after input validation - if 420 color space is bt601, do not perform copy before compressImage TODO: ensure compressImage function takes luma ptr, chroma ptrs, luma stride, chroma stride as well there by avoiding all clobbering/intermediate copying Bug: Test: ./ultrahdr_unit_test Change-Id: I9cda53419e1a7e8d68ddae571ea1bdd2ba5168f4 --- libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp | 18 +- libs/ultrahdr/gainmapmath.cpp | 42 +- libs/ultrahdr/include/ultrahdr/jpegr.h | 242 ++-- libs/ultrahdr/include/ultrahdr/ultrahdr.h | 2 + libs/ultrahdr/jpegencoderhelper.cpp | 76 +- libs/ultrahdr/jpegr.cpp | 1166 ++++++++---------- libs/ultrahdr/tests/gainmapmath_test.cpp | 10 +- libs/ultrahdr/tests/jpegr_test.cpp | 2 +- 8 files changed, 717 insertions(+), 841 deletions(-) diff --git a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp index bbe58e0f2e..1dce57c7c5 100644 --- a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp +++ b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp @@ -24,21 +24,11 @@ // User include files #include "ultrahdr/gainmapmath.h" #include "ultrahdr/jpegencoderhelper.h" +#include "ultrahdr/jpegdecoderhelper.h" #include "utils/Log.h" using namespace android::ultrahdr; -// constants -const int kMinWidth = 8; -const int kMaxWidth = 7680; - -const int kMinHeight = 8; -const int kMaxHeight = 4320; - -const int kScaleFactor = 4; - -const int kJpegBlock = 16; - // Color gamuts for image data, sync with ultrahdr.h const int kCgMin = ULTRAHDR_COLORGAMUT_UNSPECIFIED + 1; const int kCgMax = ULTRAHDR_COLORGAMUT_MAX; @@ -164,8 +154,8 @@ void UltraHdrEncFuzzer::process() { fillP010Buffer(bufferUV.get(), width, height / 2, uvStride); } } else { - int map_width = width / kScaleFactor; - int map_height = height / kScaleFactor; + int map_width = width / kMapDimensionScaleFactor; + int map_height = height / kMapDimensionScaleFactor; map_width = static_cast(floor((map_width + kJpegBlock - 1) / kJpegBlock)) * kJpegBlock; map_height = ((map_height + 1) >> 1) << 1; @@ -249,7 +239,7 @@ void UltraHdrEncFuzzer::process() { jpegGainMap.data = gainMapEncoder.getCompressedImagePtr(); jpegGainMap.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; ultrahdr_metadata_struct metadata; - metadata.version = "1.0"; + metadata.version = kJpegrVersion; if (tf == ULTRAHDR_TF_HLG) { metadata.maxContentBoost = kHlgMaxNits / kSdrWhiteNits; } else if (tf == ULTRAHDR_TF_PQ) { diff --git a/libs/ultrahdr/gainmapmath.cpp b/libs/ultrahdr/gainmapmath.cpp index 27157227c3..e1c5085b14 100644 --- a/libs/ultrahdr/gainmapmath.cpp +++ b/libs/ultrahdr/gainmapmath.cpp @@ -531,21 +531,21 @@ void transformYuv420(jr_uncompressed_ptr image, size_t x_chroma, size_t y_chroma Color new_uv = (yuv1 + yuv2 + yuv3 + yuv4) / 4.0f; - size_t pixel_y1_idx = x_chroma * 2 + y_chroma * 2 * image->width; - size_t pixel_y2_idx = (x_chroma * 2 + 1) + y_chroma * 2 * image->width; - size_t pixel_y3_idx = x_chroma * 2 + (y_chroma * 2 + 1) * image->width; - size_t pixel_y4_idx = (x_chroma * 2 + 1) + (y_chroma * 2 + 1) * image->width; + size_t pixel_y1_idx = x_chroma * 2 + y_chroma * 2 * image->luma_stride; + size_t pixel_y2_idx = (x_chroma * 2 + 1) + y_chroma * 2 * image->luma_stride; + size_t pixel_y3_idx = x_chroma * 2 + (y_chroma * 2 + 1) * image->luma_stride; + size_t pixel_y4_idx = (x_chroma * 2 + 1) + (y_chroma * 2 + 1) * image->luma_stride; uint8_t& y1_uint = reinterpret_cast(image->data)[pixel_y1_idx]; uint8_t& y2_uint = reinterpret_cast(image->data)[pixel_y2_idx]; uint8_t& y3_uint = reinterpret_cast(image->data)[pixel_y3_idx]; uint8_t& y4_uint = reinterpret_cast(image->data)[pixel_y4_idx]; - size_t pixel_count = image->width * image->height; - size_t pixel_uv_idx = x_chroma + y_chroma * (image->width / 2); + size_t pixel_count = image->chroma_stride * image->height / 2; + size_t pixel_uv_idx = x_chroma + y_chroma * (image->chroma_stride); - uint8_t& u_uint = reinterpret_cast(image->data)[pixel_count + pixel_uv_idx]; - uint8_t& v_uint = reinterpret_cast(image->data)[pixel_count * 5 / 4 + pixel_uv_idx]; + uint8_t& u_uint = reinterpret_cast(image->chroma_data)[pixel_uv_idx]; + uint8_t& v_uint = reinterpret_cast(image->chroma_data)[pixel_count + pixel_uv_idx]; y1_uint = static_cast(CLIP3((yuv1.y * 255.0f + 0.5f), 0, 255)); y2_uint = static_cast(CLIP3((yuv2.y * 255.0f + 0.5f), 0, 255)); @@ -599,17 +599,9 @@ Color applyGainLUT(Color e, float gain, GainLUT& gainLUT) { Color getYuv420Pixel(jr_uncompressed_ptr image, size_t x, size_t y) { uint8_t* luma_data = reinterpret_cast(image->data); - size_t luma_stride = image->luma_stride == 0 ? image->width : image->luma_stride; - - uint8_t* chroma_data; - size_t chroma_stride; - if (image->chroma_data == nullptr) { - chroma_stride = luma_stride / 2; - chroma_data = &reinterpret_cast(image->data)[luma_stride * image->height]; - } else { - chroma_stride = image->chroma_stride; - chroma_data = reinterpret_cast(image->chroma_data); - } + size_t luma_stride = image->luma_stride; + uint8_t* chroma_data = reinterpret_cast(image->chroma_data); + size_t chroma_stride = image->chroma_stride; size_t offset_cr = chroma_stride * (image->height / 2); size_t pixel_y_idx = x + y * luma_stride; @@ -629,16 +621,8 @@ Color getYuv420Pixel(jr_uncompressed_ptr image, size_t x, size_t y) { Color getP010Pixel(jr_uncompressed_ptr image, size_t x, size_t y) { uint16_t* luma_data = reinterpret_cast(image->data); size_t luma_stride = image->luma_stride == 0 ? image->width : image->luma_stride; - - uint16_t* chroma_data; - size_t chroma_stride; - if (image->chroma_data == nullptr) { - chroma_stride = luma_stride; - chroma_data = &reinterpret_cast(image->data)[luma_stride * image->height]; - } else { - chroma_stride = image->chroma_stride; - chroma_data = reinterpret_cast(image->chroma_data); - } + uint16_t* chroma_data = reinterpret_cast(image->chroma_data); + size_t chroma_stride = image->chroma_stride; size_t pixel_y_idx = y * luma_stride + x; size_t pixel_u_idx = (y >> 1) * chroma_stride + (x & ~0x1); diff --git a/libs/ultrahdr/include/ultrahdr/jpegr.h b/libs/ultrahdr/include/ultrahdr/jpegr.h index e539e47944..850cb32e75 100644 --- a/libs/ultrahdr/include/ultrahdr/jpegr.h +++ b/libs/ultrahdr/include/ultrahdr/jpegr.h @@ -17,9 +17,13 @@ #ifndef ANDROID_ULTRAHDR_JPEGR_H #define ANDROID_ULTRAHDR_JPEGR_H -#include "jpegencoderhelper.h" -#include "jpegrerrorcode.h" -#include "ultrahdr.h" +#include +#include + +#include "ultrahdr/jpegdecoderhelper.h" +#include "ultrahdr/jpegencoderhelper.h" +#include "ultrahdr/jpegrerrorcode.h" +#include "ultrahdr/ultrahdr.h" #ifndef FLT_MAX #define FLT_MAX 0x1.fffffep127f @@ -27,6 +31,27 @@ namespace android::ultrahdr { +// The current JPEGR version that we encode to +static const char* const kJpegrVersion = "1.0"; + +// Map is quarter res / sixteenth size +static const size_t kMapDimensionScaleFactor = 4; + +// Gain Map width is (image_width / kMapDimensionScaleFactor). If we were to +// compress 420 GainMap in jpeg, then we need at least 2 samples. For Grayscale +// 1 sample is sufficient. We are using 2 here anyways +static const int kMinWidth = 2 * kMapDimensionScaleFactor; +static const int kMinHeight = 2 * kMapDimensionScaleFactor; + +// Minimum Codec Unit(MCU) for 420 sub-sampling is decided by JPEG encoder by parameter +// JpegEncoderHelper::kCompressBatchSize. +// The width and height of image under compression is expected to be a multiple of MCU size. +// If this criteria is not satisfied, padding is done. +static const size_t kJpegBlock = JpegEncoderHelper::kCompressBatchSize; + +/* + * Holds information of jpegr image + */ struct jpegr_info_struct { size_t width; size_t height; @@ -105,10 +130,10 @@ public: * Tonemap the HDR input to a SDR image, generate gain map from the HDR and SDR images, * compress SDR YUV to 8-bit JPEG and append the gain map to the end of the compressed * JPEG. - * @param uncompressed_p010_image uncompressed HDR image in P010 color format + * @param p010_image_ptr uncompressed HDR image in P010 color format * @param hdr_tf transfer function of the HDR image * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} - * represents the maximum available size of the desitination buffer, and it must be + * represents the maximum available size of the destination buffer, and it must be * set before calling this method. If the encoded JPEGR size exceeds * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. * @param quality target quality of the JPEG encoding, must be in range of 0-100 where 100 is @@ -116,11 +141,8 @@ public: * @param exif pointer to the exif metadata. * @return NO_ERROR if encoding succeeds, error code if error occurs. */ - status_t encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, - ultrahdr_transfer_function hdr_tf, - jr_compressed_ptr dest, - int quality, - jr_exif_ptr exif); + status_t encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfer_function hdr_tf, + jr_compressed_ptr dest, int quality, jr_exif_ptr exif); /* * Encode API-1 @@ -129,8 +151,8 @@ public: * Generate gain map from the HDR and SDR inputs, compress SDR YUV to 8-bit JPEG and append * the gain map to the end of the compressed JPEG. HDR and SDR inputs must be the same * resolution. SDR input is assumed to use the sRGB transfer function. - * @param uncompressed_p010_image uncompressed HDR image in P010 color format - * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format + * @param p010_image_ptr uncompressed HDR image in P010 color format + * @param yuv420_image_ptr uncompressed SDR image in YUV_420 color format * @param hdr_tf transfer function of the HDR image * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} * represents the maximum available size of the desitination buffer, and it must be @@ -141,11 +163,8 @@ public: * @param exif pointer to the exif metadata. * @return NO_ERROR if encoding succeeds, error code if error occurs. */ - status_t encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, - jr_uncompressed_ptr uncompressed_yuv_420_image, - ultrahdr_transfer_function hdr_tf, - jr_compressed_ptr dest, - int quality, + status_t encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, jr_uncompressed_ptr yuv420_image_ptr, + ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest, int quality, jr_exif_ptr exif); /* @@ -158,11 +177,11 @@ public: * compressed JPEG. Adds an ICC profile if one isn't present in the input JPEG image. HDR and * SDR inputs must be the same resolution and color space. SDR image is assumed to use the sRGB * transfer function. - * @param uncompressed_p010_image uncompressed HDR image in P010 color format - * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format - * Note: the SDR image must be the decoded version of the JPEG - * input - * @param compressed_jpeg_image compressed 8-bit JPEG image + * @param p010_image_ptr uncompressed HDR image in P010 color format + * @param yuv420_image_ptr uncompressed SDR image in YUV_420 color format + * @param yuv420jpg_image_ptr SDR image compressed in jpeg format + * Note: the compressed SDR image must be the compressed + * yuv420_image_ptr image in JPEG format. * @param hdr_tf transfer function of the HDR image * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} * represents the maximum available size of the desitination buffer, and it must be @@ -170,10 +189,8 @@ public: * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. * @return NO_ERROR if encoding succeeds, error code if error occurs. */ - status_t encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, - jr_uncompressed_ptr uncompressed_yuv_420_image, - jr_compressed_ptr compressed_jpeg_image, - ultrahdr_transfer_function hdr_tf, + status_t encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, jr_uncompressed_ptr yuv420_image_ptr, + jr_compressed_ptr yuv420jpg_image_ptr, ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest); /* @@ -186,8 +203,8 @@ public: * and the decoded SDR result, append the gain map to the end of the compressed JPEG. Adds an * ICC profile if one isn't present in the input JPEG image. HDR and SDR inputs must be the same * resolution. JPEG image is assumed to use the sRGB transfer function. - * @param uncompressed_p010_image uncompressed HDR image in P010 color format - * @param compressed_jpeg_image compressed 8-bit JPEG image + * @param p010_image_ptr uncompressed HDR image in P010 color format + * @param yuv420jpg_image_ptr SDR image compressed in jpeg format * @param hdr_tf transfer function of the HDR image * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} * represents the maximum available size of the desitination buffer, and it must be @@ -195,10 +212,8 @@ public: * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. * @return NO_ERROR if encoding succeeds, error code if error occurs. */ - status_t encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, - jr_compressed_ptr compressed_jpeg_image, - ultrahdr_transfer_function hdr_tf, - jr_compressed_ptr dest); + status_t encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, jr_compressed_ptr yuv420jpg_image_ptr, + ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest); /* * Encode API-4 @@ -206,8 +221,8 @@ public: * * Assemble the primary JPEG image, the gain map and the metadata to JPEG/R format. Adds an ICC * profile if one isn't present in the input JPEG image. - * @param compressed_jpeg_image compressed 8-bit JPEG image - * @param compressed_gainmap compressed 8-bit JPEG single channel image + * @param yuv420jpg_image_ptr SDR image compressed in jpeg format + * @param gainmapjpg_image_ptr gain map image compressed in jpeg format * @param metadata metadata to be written in XMP of the primary jpeg * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} * represents the maximum available size of the desitination buffer, and it must be @@ -215,9 +230,8 @@ public: * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. * @return NO_ERROR if encoding succeeds, error code if error occurs. */ - status_t encodeJPEGR(jr_compressed_ptr compressed_jpeg_image, - jr_compressed_ptr compressed_gainmap, - ultrahdr_metadata_ptr metadata, + status_t encodeJPEGR(jr_compressed_ptr yuv420jpg_image_ptr, + jr_compressed_ptr gainmapjpg_image_ptr, ultrahdr_metadata_ptr metadata, jr_compressed_ptr dest); /* @@ -230,8 +244,7 @@ public: * * This method only supports single gain map metadata values for fields that allow multi-channel * metadata values. - * - * @param compressed_jpegr_image compressed JPEGR image. + * @param jpegr_image_ptr compressed JPEGR image. * @param dest destination of the uncompressed JPEGR image. * @param max_display_boost (optional) the maximum available boost supported by a display, * the value must be greater than or equal to 1.0. @@ -251,57 +264,55 @@ public: ---------------------------------------------------------------------- | JPEGR_OUTPUT_HDR_HLG | RGBA_1010102 HLG | ---------------------------------------------------------------------- - * @param gain_map destination of the decoded gain map. The default value is NULL where - the decoder will do nothing about it. If configured not NULL the decoder - will write the decoded gain_map data into this structure. The format - is defined in {@code jpegr_uncompressed_struct}. + * @param gainmap_image_ptr destination of the decoded gain map. The default value is NULL + where the decoder will do nothing about it. If configured not NULL + the decoder will write the decoded gain_map data into this + structure. The format is defined in + {@code jpegr_uncompressed_struct}. * @param metadata destination of the decoded metadata. The default value is NULL where the decoder will do nothing about it. If configured not NULL the decoder will write metadata into this structure. the format of metadata is defined in {@code ultrahdr_metadata_struct}. * @return NO_ERROR if decoding succeeds, error code if error occurs. */ - status_t decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, - jr_uncompressed_ptr dest, - float max_display_boost = FLT_MAX, - jr_exif_ptr exif = nullptr, + status_t decodeJPEGR(jr_compressed_ptr jpegr_image_ptr, jr_uncompressed_ptr dest, + float max_display_boost = FLT_MAX, jr_exif_ptr exif = nullptr, ultrahdr_output_format output_format = ULTRAHDR_OUTPUT_HDR_LINEAR, - jr_uncompressed_ptr gain_map = nullptr, + jr_uncompressed_ptr gainmap_image_ptr = nullptr, ultrahdr_metadata_ptr metadata = nullptr); /* - * Gets Info from JPEGR file without decoding it. - * - * This method only supports single gain map metadata values for fields that allow multi-channel - * metadata values. - * - * The output is filled jpegr_info structure - * @param compressed_jpegr_image compressed JPEGR image - * @param jpegr_info pointer to output JPEGR info. Members of jpegr_info - * are owned by the caller - * @return NO_ERROR if JPEGR parsing succeeds, error code otherwise - */ - status_t getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image, - jr_info_ptr jpegr_info); + * Gets Info from JPEGR file without decoding it. + * + * This method only supports single gain map metadata values for fields that allow multi-channel + * metadata values. + * + * The output is filled jpegr_info structure + * @param jpegr_image_ptr compressed JPEGR image + * @param jpeg_image_info_ptr pointer to jpegr info struct. Members of jpegr_info + * are owned by the caller + * @return NO_ERROR if JPEGR parsing succeeds, error code otherwise + */ + status_t getJPEGRInfo(jr_compressed_ptr jpegr_image_ptr, jr_info_ptr jpeg_image_info_ptr); + protected: /* * This method is called in the encoding pipeline. It will take the uncompressed 8-bit and * 10-bit yuv images as input, and calculate the uncompressed gain map. The input images * must be the same resolution. The SDR input is assumed to use the sRGB transfer function. * - * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format - * @param uncompressed_p010_image uncompressed HDR image in P010 color format + * @param yuv420_image_ptr uncompressed SDR image in YUV_420 color format + * @param p010_image_ptr uncompressed HDR image in P010 color format * @param hdr_tf transfer function of the HDR image - * @param dest gain map; caller responsible for memory of data - * @param metadata max_content_boost is filled in + * @param metadata everything but "version" is filled in this struct + * @param dest location at which gain map image is stored (caller responsible for memory + of data). * @param sdr_is_601 if true, then use BT.601 decoding of YUV regardless of SDR image gamut * @return NO_ERROR if calculation succeeds, error code if error occurs. */ - status_t generateGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, - jr_uncompressed_ptr uncompressed_p010_image, - ultrahdr_transfer_function hdr_tf, - ultrahdr_metadata_ptr metadata, - jr_uncompressed_ptr dest, + status_t generateGainMap(jr_uncompressed_ptr yuv420_image_ptr, + jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfer_function hdr_tf, + ultrahdr_metadata_ptr metadata, jr_uncompressed_ptr dest, bool sdr_is_601 = false); /* @@ -312,8 +323,8 @@ protected: * The SDR image is assumed to use the sRGB transfer function. The SDR image is also assumed to * be a decoded JPEG for the purpose of YUV interpration. * - * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format - * @param uncompressed_gain_map uncompressed gain map + * @param yuv420_image_ptr uncompressed SDR image in YUV_420 color format + * @param gainmap_image_ptr pointer to uncompressed gain map image struct. * @param metadata JPEG/R metadata extracted from XMP. * @param output_format flag for setting output color format. if set to * {@code JPEGR_OUTPUT_SDR}, decoder will only decode the primary image @@ -322,35 +333,33 @@ protected: * @param dest reconstructed HDR image * @return NO_ERROR if calculation succeeds, error code if error occurs. */ - status_t applyGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, - jr_uncompressed_ptr uncompressed_gain_map, - ultrahdr_metadata_ptr metadata, - ultrahdr_output_format output_format, - float max_display_boost, + status_t applyGainMap(jr_uncompressed_ptr yuv420_image_ptr, + jr_uncompressed_ptr gainmap_image_ptr, ultrahdr_metadata_ptr metadata, + ultrahdr_output_format output_format, float max_display_boost, jr_uncompressed_ptr dest); private: /* * This method is called in the encoding pipeline. It will encode the gain map. * - * @param uncompressed_gain_map uncompressed gain map - * @param resource to compress gain map + * @param gainmap_image_ptr pointer to uncompressed gain map image struct + * @param jpeg_enc_obj_ptr helper resource to compress gain map * @return NO_ERROR if encoding succeeds, error code if error occurs. */ - status_t compressGainMap(jr_uncompressed_ptr uncompressed_gain_map, - JpegEncoderHelper* jpeg_encoder); + status_t compressGainMap(jr_uncompressed_ptr gainmap_image_ptr, + JpegEncoderHelper* jpeg_enc_obj_ptr); /* - * This methoud is called to separate primary image and gain map image from JPEGR + * This method is called to separate primary image and gain map image from JPEGR * - * @param compressed_jpegr_image compressed JPEGR image - * @param primary_image destination of primary image - * @param gain_map destination of compressed gain map + * @param jpegr_image_ptr pointer to compressed JPEGR image. + * @param primary_jpg_image_ptr destination of primary image + * @param gainmap_jpg_image_ptr destination of compressed gain map image * @return NO_ERROR if calculation succeeds, error code if error occurs. - */ - status_t extractPrimaryImageAndGainMap(jr_compressed_ptr compressed_jpegr_image, - jr_compressed_ptr primary_image, - jr_compressed_ptr gain_map); + */ + status_t extractPrimaryImageAndGainMap(jr_compressed_ptr jpegr_image_ptr, + jr_compressed_ptr primary_jpg_image_ptr, + jr_compressed_ptr gainmap_jpg_image_ptr); /* * This method is called in the encoding pipeline. It will take the standard 8-bit JPEG image, @@ -361,8 +370,9 @@ private: * API-3 this parameter is null, but the primary image in JPEG/R may still have EXIF as long as * the input JPEG has EXIF. * - * @param compressed_jpeg_image compressed 8-bit JPEG image - * @param compress_gain_map compressed recover map + + * @param primary_jpg_image_ptr destination of primary image + * @param gainmap_jpg_image_ptr destination of compressed gain map image * @param (nullable) exif EXIF package * @param (nullable) icc ICC package * @param icc_size length in bytes of ICC package @@ -370,22 +380,18 @@ private: * @param dest compressed JPEGR image * @return NO_ERROR if calculation succeeds, error code if error occurs. */ - status_t appendGainMap(jr_compressed_ptr compressed_jpeg_image, - jr_compressed_ptr compressed_gain_map, - jr_exif_ptr exif, - void* icc, size_t icc_size, - ultrahdr_metadata_ptr metadata, - jr_compressed_ptr dest); + status_t appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, + jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr exif, void* icc, + size_t icc_size, ultrahdr_metadata_ptr metadata, jr_compressed_ptr dest); /* * This method will tone map a HDR image to an SDR image. * - * @param src (input) uncompressed P010 image - * @param dest (output) tone mapping result as a YUV_420 image - * @return NO_ERROR if calculation succeeds, error code if error occurs. + * @param src pointer to uncompressed HDR image struct. HDR image is expected to be + * in p010 color format + * @param dest pointer to store tonemapped SDR image */ - status_t toneMap(jr_uncompressed_ptr src, - jr_uncompressed_ptr dest); + status_t toneMap(jr_uncompressed_ptr src, jr_uncompressed_ptr dest); /* * This method will convert a YUV420 image from one YUV encoding to another in-place (eg. @@ -399,15 +405,15 @@ private: * @param dest_encoding output YUV encoding * @return NO_ERROR if calculation succeeds, error code if error occurs. */ - status_t convertYuv(jr_uncompressed_ptr image, - ultrahdr_color_gamut src_encoding, + status_t convertYuv(jr_uncompressed_ptr image, ultrahdr_color_gamut src_encoding, ultrahdr_color_gamut dest_encoding); /* * This method will check the validity of the input arguments. * - * @param uncompressed_p010_image uncompressed HDR image in P010 color format - * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format + * @param p010_image_ptr uncompressed HDR image in P010 color format + * @param yuv420_image_ptr pointer to uncompressed SDR image struct. HDR image is expected to + * be in 420p color format * @param hdr_tf transfer function of the HDR image * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} * represents the maximum available size of the desitination buffer, and it must be @@ -415,32 +421,30 @@ private: * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. * @return NO_ERROR if the input args are valid, error code is not valid. */ - status_t areInputArgumentsValid(jr_uncompressed_ptr uncompressed_p010_image, - jr_uncompressed_ptr uncompressed_yuv_420_image, - ultrahdr_transfer_function hdr_tf, - jr_compressed_ptr dest); + status_t areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr, + jr_uncompressed_ptr yuv420_image_ptr, + ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest_ptr); /* * This method will check the validity of the input arguments. * - * @param uncompressed_p010_image uncompressed HDR image in P010 color format - * @param uncompressed_yuv_420_image uncompressed SDR image in YUV_420 color format + * @param p010_image_ptr uncompressed HDR image in P010 color format + * @param yuv420_image_ptr pointer to uncompressed SDR image struct. HDR image is expected to + * be in 420p color format * @param hdr_tf transfer function of the HDR image * @param dest destination of the compressed JPEGR image. Please note that {@code maxLength} - * represents the maximum available size of the desitination buffer, and it must be + * represents the maximum available size of the destination buffer, and it must be * set before calling this method. If the encoded JPEGR size exceeds * {@code maxLength}, this method will return {@code ERROR_JPEGR_BUFFER_TOO_SMALL}. * @param quality target quality of the JPEG encoding, must be in range of 0-100 where 100 is * the highest quality * @return NO_ERROR if the input args are valid, error code is not valid. */ - status_t areInputArgumentsValid(jr_uncompressed_ptr uncompressed_p010_image, - jr_uncompressed_ptr uncompressed_yuv_420_image, - ultrahdr_transfer_function hdr_tf, - jr_compressed_ptr dest, - int quality); + status_t areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr, + jr_uncompressed_ptr yuv420_image_ptr, + ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest, + int quality); }; - } // namespace android::ultrahdr #endif // ANDROID_ULTRAHDR_JPEGR_H diff --git a/libs/ultrahdr/include/ultrahdr/ultrahdr.h b/libs/ultrahdr/include/ultrahdr/ultrahdr.h index 17cc97173c..66f70889fb 100644 --- a/libs/ultrahdr/include/ultrahdr/ultrahdr.h +++ b/libs/ultrahdr/include/ultrahdr/ultrahdr.h @@ -17,6 +17,8 @@ #ifndef ANDROID_ULTRAHDR_ULTRAHDR_H #define ANDROID_ULTRAHDR_ULTRAHDR_H +#include + namespace android::ultrahdr { // Color gamuts for image data typedef enum { diff --git a/libs/ultrahdr/jpegencoderhelper.cpp b/libs/ultrahdr/jpegencoderhelper.cpp index de621bd24f..9394a83e46 100644 --- a/libs/ultrahdr/jpegencoderhelper.cpp +++ b/libs/ultrahdr/jpegencoderhelper.cpp @@ -14,38 +14,36 @@ * limitations under the License. */ -#include +#include +#include +#include +#include #include -#include - namespace android::ultrahdr { -#define ALIGNM(x, m) ((((x) + ((m) - 1)) / (m)) * (m)) +#define ALIGNM(x, m) ((((x) + ((m)-1)) / (m)) * (m)) // The destination manager that can access |mResultBuffer| in JpegEncoderHelper. struct destination_mgr { -public: struct jpeg_destination_mgr mgr; JpegEncoderHelper* encoder; }; -JpegEncoderHelper::JpegEncoderHelper() { -} +JpegEncoderHelper::JpegEncoderHelper() {} -JpegEncoderHelper::~JpegEncoderHelper() { -} +JpegEncoderHelper::~JpegEncoderHelper() {} bool JpegEncoderHelper::compressImage(const void* image, int width, int height, int quality, - const void* iccBuffer, unsigned int iccSize, - bool isSingleChannel) { + const void* iccBuffer, unsigned int iccSize, + bool isSingleChannel) { mResultBuffer.clear(); if (!encode(image, width, height, quality, iccBuffer, iccSize, isSingleChannel)) { return false; } - ALOGI("Compressed JPEG: %d[%dx%d] -> %zu bytes", - (width * height * 12) / 8, width, height, mResultBuffer.size()); + ALOGI("Compressed JPEG: %d[%dx%d] -> %zu bytes", (width * height * 12) / 8, width, height, + mResultBuffer.size()); return true; } @@ -85,12 +83,12 @@ void JpegEncoderHelper::outputErrorMessage(j_common_ptr cinfo) { char buffer[JMSG_LENGTH_MAX]; /* Create the message */ - (*cinfo->err->format_message) (cinfo, buffer); + (*cinfo->err->format_message)(cinfo, buffer); ALOGE("%s\n", buffer); } bool JpegEncoderHelper::encode(const void* image, int width, int height, int jpegQuality, - const void* iccBuffer, unsigned int iccSize, bool isSingleChannel) { + const void* iccBuffer, unsigned int iccSize, bool isSingleChannel) { jpeg_compress_struct cinfo; jpeg_error_mgr jerr; @@ -115,8 +113,9 @@ bool JpegEncoderHelper::encode(const void* image, int width, int height, int jpe } void JpegEncoderHelper::setJpegDestination(jpeg_compress_struct* cinfo) { - destination_mgr* dest = static_cast((*cinfo->mem->alloc_small) ( - (j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(destination_mgr))); + destination_mgr* dest = static_cast( + (*cinfo->mem->alloc_small)((j_common_ptr)cinfo, JPOOL_PERMANENT, + sizeof(destination_mgr))); dest->encoder = this; dest->mgr.init_destination = &initDestination; dest->mgr.empty_output_buffer = &emptyOutputBuffer; @@ -125,48 +124,33 @@ void JpegEncoderHelper::setJpegDestination(jpeg_compress_struct* cinfo) { } void JpegEncoderHelper::setJpegCompressStruct(int width, int height, int quality, - jpeg_compress_struct* cinfo, bool isSingleChannel) { + jpeg_compress_struct* cinfo, bool isSingleChannel) { cinfo->image_width = width; cinfo->image_height = height; - if (isSingleChannel) { - cinfo->input_components = 1; - cinfo->in_color_space = JCS_GRAYSCALE; - } else { - cinfo->input_components = 3; - cinfo->in_color_space = JCS_YCbCr; - } + cinfo->input_components = isSingleChannel ? 1 : 3; + cinfo->in_color_space = isSingleChannel ? JCS_GRAYSCALE : JCS_YCbCr; jpeg_set_defaults(cinfo); - jpeg_set_quality(cinfo, quality, TRUE); - jpeg_set_colorspace(cinfo, isSingleChannel ? JCS_GRAYSCALE : JCS_YCbCr); cinfo->raw_data_in = TRUE; cinfo->dct_method = JDCT_ISLOW; - - if (!isSingleChannel) { - // Configure sampling factors. The sampling factor is JPEG subsampling 420 because the - // source format is YUV420. - cinfo->comp_info[0].h_samp_factor = 2; - cinfo->comp_info[0].v_samp_factor = 2; - cinfo->comp_info[1].h_samp_factor = 1; - cinfo->comp_info[1].v_samp_factor = 1; - cinfo->comp_info[2].h_samp_factor = 1; - cinfo->comp_info[2].v_samp_factor = 1; + cinfo->comp_info[0].h_samp_factor = cinfo->in_color_space == JCS_GRAYSCALE ? 1 : 2; + cinfo->comp_info[0].v_samp_factor = cinfo->in_color_space == JCS_GRAYSCALE ? 1 : 2; + for (int i = 1; i < cinfo->num_components; i++) { + cinfo->comp_info[i].h_samp_factor = 1; + cinfo->comp_info[i].v_samp_factor = 1; } } -bool JpegEncoderHelper::compress( - jpeg_compress_struct* cinfo, const uint8_t* image, bool isSingleChannel) { - if (isSingleChannel) { - return compressSingleChannel(cinfo, image); - } - return compressYuv(cinfo, image); +bool JpegEncoderHelper::compress(jpeg_compress_struct* cinfo, const uint8_t* image, + bool isSingleChannel) { + return isSingleChannel ? compressSingleChannel(cinfo, image) : compressYuv(cinfo, image); } bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yuv) { JSAMPROW y[kCompressBatchSize]; JSAMPROW cb[kCompressBatchSize / 2]; JSAMPROW cr[kCompressBatchSize / 2]; - JSAMPARRAY planes[3] {y, cb, cr}; + JSAMPARRAY planes[3]{y, cb, cr}; size_t y_plane_size = cinfo->image_width * cinfo->image_height; size_t uv_plane_size = y_plane_size / 4; @@ -246,7 +230,7 @@ bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* bool JpegEncoderHelper::compressSingleChannel(jpeg_compress_struct* cinfo, const uint8_t* image) { JSAMPROW y[kCompressBatchSize]; - JSAMPARRAY planes[1] {y}; + JSAMPARRAY planes[1]{y}; uint8_t* y_plane = const_cast(image); std::unique_ptr empty = std::make_unique(cinfo->image_width); @@ -291,4 +275,4 @@ bool JpegEncoderHelper::compressSingleChannel(jpeg_compress_struct* cinfo, const return true; } -} // namespace ultrahdr +} // namespace android::ultrahdr diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp index 0191fea9e8..fdfbb9cec2 100644 --- a/libs/ultrahdr/jpegr.cpp +++ b/libs/ultrahdr/jpegr.cpp @@ -14,31 +14,26 @@ * limitations under the License. */ -#include -#include -#include +#include +#include +#include +#include +#include +#include + #include +#include +#include #include #include -#include -#include +#include #include -#include #include -#include -#include +#include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include using namespace std; using namespace photos_editing_formats::image_io; @@ -60,25 +55,6 @@ namespace android::ultrahdr { } \ } -// The current JPEGR version that we encode to -static const char* const kJpegrVersion = "1.0"; - -// Map is quarter res / sixteenth size -static const size_t kMapDimensionScaleFactor = 4; - -// Gain Map width is (image_width / kMapDimensionScaleFactor). If we were to -// compress 420 GainMap in jpeg, then we need at least 2 samples. For Grayscale -// 1 sample is sufficient. We are using 2 here anyways -static const int kMinWidth = 2 * kMapDimensionScaleFactor; -static const int kMinHeight = 2 * kMapDimensionScaleFactor; - -// JPEG block size. -// JPEG encoding / decoding will require block based DCT transform 16 x 16 for luma, -// and 8 x 8 for chroma. -// Width must be 16 dividable for luma, and 8 dividable for chroma. -// If this criteria is not facilitated, we will pad zeros based to each line on the -// required block size. -static const size_t kJpegBlock = JpegEncoderHelper::kCompressBatchSize; // JPEG compress quality (0 ~ 100) for gain map static const int kMapCompressQuality = 85; @@ -96,187 +72,176 @@ int GetCPUCoreCount() { return cpuCoreCount; } -status_t JpegR::areInputArgumentsValid(jr_uncompressed_ptr uncompressed_p010_image, - jr_uncompressed_ptr uncompressed_yuv_420_image, +status_t JpegR::areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr, + jr_uncompressed_ptr yuv420_image_ptr, ultrahdr_transfer_function hdr_tf, - jr_compressed_ptr dest) { - if (uncompressed_p010_image == nullptr || uncompressed_p010_image->data == nullptr) { - ALOGE("received nullptr for uncompressed p010 image"); + jr_compressed_ptr dest_ptr) { + if (p010_image_ptr == nullptr || p010_image_ptr->data == nullptr) { + ALOGE("Received nullptr for input p010 image"); return ERROR_JPEGR_INVALID_NULL_PTR; } - - if (uncompressed_p010_image->width % 2 != 0 - || uncompressed_p010_image->height % 2 != 0) { - ALOGE("Image dimensions cannot be odd, image dimensions %dx%d", - uncompressed_p010_image->width, uncompressed_p010_image->height); + if (p010_image_ptr->width % 2 != 0 || p010_image_ptr->height % 2 != 0) { + ALOGE("Image dimensions cannot be odd, image dimensions %dx%d", p010_image_ptr->width, + p010_image_ptr->height); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - - if (uncompressed_p010_image->width < kMinWidth - || uncompressed_p010_image->height < kMinHeight) { - ALOGE("Image dimensions cannot be less than %dx%d, image dimensions %dx%d", - kMinWidth, kMinHeight, uncompressed_p010_image->width, uncompressed_p010_image->height); + if (p010_image_ptr->width < kMinWidth || p010_image_ptr->height < kMinHeight) { + ALOGE("Image dimensions cannot be less than %dx%d, image dimensions %dx%d", kMinWidth, + kMinHeight, p010_image_ptr->width, p010_image_ptr->height); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - - if (uncompressed_p010_image->width > kMaxWidth - || uncompressed_p010_image->height > kMaxHeight) { - ALOGE("Image dimensions cannot be larger than %dx%d, image dimensions %dx%d", - kMaxWidth, kMaxHeight, uncompressed_p010_image->width, uncompressed_p010_image->height); + if (p010_image_ptr->width > kMaxWidth || p010_image_ptr->height > kMaxHeight) { + ALOGE("Image dimensions cannot be larger than %dx%d, image dimensions %dx%d", kMaxWidth, + kMaxHeight, p010_image_ptr->width, p010_image_ptr->height); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - - if (uncompressed_p010_image->colorGamut <= ULTRAHDR_COLORGAMUT_UNSPECIFIED - || uncompressed_p010_image->colorGamut > ULTRAHDR_COLORGAMUT_MAX) { - ALOGE("Unrecognized p010 color gamut %d", uncompressed_p010_image->colorGamut); + if (p010_image_ptr->colorGamut <= ULTRAHDR_COLORGAMUT_UNSPECIFIED || + p010_image_ptr->colorGamut > ULTRAHDR_COLORGAMUT_MAX) { + ALOGE("Unrecognized p010 color gamut %d", p010_image_ptr->colorGamut); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - - if (uncompressed_p010_image->luma_stride != 0 - && uncompressed_p010_image->luma_stride < uncompressed_p010_image->width) { - ALOGE("Luma stride can not be smaller than width, stride=%d, width=%d", - uncompressed_p010_image->luma_stride, uncompressed_p010_image->width); + if (p010_image_ptr->luma_stride != 0 && p010_image_ptr->luma_stride < p010_image_ptr->width) { + ALOGE("Luma stride must not be smaller than width, stride=%d, width=%d", + p010_image_ptr->luma_stride, p010_image_ptr->width); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - - if (uncompressed_p010_image->chroma_data != nullptr - && uncompressed_p010_image->chroma_stride < uncompressed_p010_image->width) { - ALOGE("Chroma stride can not be smaller than width, stride=%d, width=%d", - uncompressed_p010_image->chroma_stride, - uncompressed_p010_image->width); + if (p010_image_ptr->chroma_data != nullptr && + p010_image_ptr->chroma_stride < p010_image_ptr->width) { + ALOGE("Chroma stride must not be smaller than width, stride=%d, width=%d", + p010_image_ptr->chroma_stride, p010_image_ptr->width); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - - if (dest == nullptr || dest->data == nullptr) { - ALOGE("received nullptr for destination"); + if (dest_ptr == nullptr || dest_ptr->data == nullptr) { + ALOGE("Received nullptr for destination"); return ERROR_JPEGR_INVALID_NULL_PTR; } - - if (hdr_tf <= ULTRAHDR_TF_UNSPECIFIED || hdr_tf > ULTRAHDR_TF_MAX - || hdr_tf == ULTRAHDR_TF_SRGB) { + if (hdr_tf <= ULTRAHDR_TF_UNSPECIFIED || hdr_tf > ULTRAHDR_TF_MAX || hdr_tf == ULTRAHDR_TF_SRGB) { ALOGE("Invalid hdr transfer function %d", hdr_tf); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - - if (uncompressed_yuv_420_image == nullptr) { + if (yuv420_image_ptr == nullptr) { return NO_ERROR; } - - if (uncompressed_yuv_420_image->data == nullptr) { - ALOGE("received nullptr for uncompressed 420 image"); + if (yuv420_image_ptr->data == nullptr) { + ALOGE("Received nullptr for uncompressed 420 image"); return ERROR_JPEGR_INVALID_NULL_PTR; } - - if (uncompressed_yuv_420_image->luma_stride != 0 - && uncompressed_yuv_420_image->luma_stride < uncompressed_yuv_420_image->width) { - ALOGE("Luma stride can not be smaller than width, stride=%d, width=%d", - uncompressed_yuv_420_image->luma_stride, uncompressed_yuv_420_image->width); + if (yuv420_image_ptr->luma_stride != 0 && + yuv420_image_ptr->luma_stride < yuv420_image_ptr->width) { + ALOGE("Luma stride must not be smaller than width, stride=%d, width=%d", + yuv420_image_ptr->luma_stride, yuv420_image_ptr->width); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - - if (uncompressed_yuv_420_image->chroma_data != nullptr - && uncompressed_yuv_420_image->chroma_stride < uncompressed_yuv_420_image->width / 2) { - ALOGE("Chroma stride can not be smaller than 1/2 of the width, stride=%d, width=%d", - uncompressed_yuv_420_image->chroma_stride, uncompressed_yuv_420_image->width); + if (yuv420_image_ptr->chroma_data != nullptr && + yuv420_image_ptr->chroma_stride < yuv420_image_ptr->width / 2) { + ALOGE("Chroma stride must not be smaller than (width / 2), stride=%d, width=%d", + yuv420_image_ptr->chroma_stride, yuv420_image_ptr->width); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - - if (uncompressed_p010_image->width != uncompressed_yuv_420_image->width - || uncompressed_p010_image->height != uncompressed_yuv_420_image->height) { - ALOGE("Image resolutions mismatch: P010: %dx%d, YUV420: %dx%d", - uncompressed_p010_image->width, - uncompressed_p010_image->height, - uncompressed_yuv_420_image->width, - uncompressed_yuv_420_image->height); + if (p010_image_ptr->width != yuv420_image_ptr->width || + p010_image_ptr->height != yuv420_image_ptr->height) { + ALOGE("Image resolutions mismatch: P010: %dx%d, YUV420: %dx%d", p010_image_ptr->width, + p010_image_ptr->height, yuv420_image_ptr->width, yuv420_image_ptr->height); return ERROR_JPEGR_RESOLUTION_MISMATCH; } - - if (uncompressed_yuv_420_image->colorGamut <= ULTRAHDR_COLORGAMUT_UNSPECIFIED - || uncompressed_yuv_420_image->colorGamut > ULTRAHDR_COLORGAMUT_MAX) { - ALOGE("Unrecognized 420 color gamut %d", uncompressed_yuv_420_image->colorGamut); + if (yuv420_image_ptr->colorGamut <= ULTRAHDR_COLORGAMUT_UNSPECIFIED || + yuv420_image_ptr->colorGamut > ULTRAHDR_COLORGAMUT_MAX) { + ALOGE("Unrecognized 420 color gamut %d", yuv420_image_ptr->colorGamut); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - return NO_ERROR; } -status_t JpegR::areInputArgumentsValid(jr_uncompressed_ptr uncompressed_p010_image, - jr_uncompressed_ptr uncompressed_yuv_420_image, +status_t JpegR::areInputArgumentsValid(jr_uncompressed_ptr p010_image_ptr, + jr_uncompressed_ptr yuv420_image_ptr, ultrahdr_transfer_function hdr_tf, - jr_compressed_ptr dest, - int quality) { - if (status_t ret = areInputArgumentsValid( - uncompressed_p010_image, uncompressed_yuv_420_image, hdr_tf, dest) != NO_ERROR) { - return ret; - } - + jr_compressed_ptr dest_ptr, int quality) { if (quality < 0 || quality > 100) { ALOGE("quality factor is out side range [0-100], quality factor : %d", quality); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - - return NO_ERROR; + return areInputArgumentsValid(p010_image_ptr, yuv420_image_ptr, hdr_tf, dest_ptr); } /* Encode API-0 */ -status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, - ultrahdr_transfer_function hdr_tf, - jr_compressed_ptr dest, - int quality, - jr_exif_ptr exif) { - if (status_t ret = areInputArgumentsValid( - uncompressed_p010_image, /* uncompressed_yuv_420_image */ nullptr, - hdr_tf, dest, quality) != NO_ERROR) { +status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfer_function hdr_tf, + jr_compressed_ptr dest, int quality, jr_exif_ptr exif) { + // validate input arguments + if (auto ret = areInputArgumentsValid(p010_image_ptr, nullptr, hdr_tf, dest, quality); + ret != NO_ERROR) { return ret; } - if (exif != nullptr && exif->data == nullptr) { ALOGE("received nullptr for exif metadata"); return ERROR_JPEGR_INVALID_NULL_PTR; } - ultrahdr_metadata_struct metadata; - metadata.version = kJpegrVersion; + // clean up input structure for later usage + jpegr_uncompressed_struct p010_image = *p010_image_ptr; + if (p010_image.luma_stride == 0) p010_image.luma_stride = p010_image.width; + if (!p010_image.chroma_data) { + uint16_t* data = reinterpret_cast(p010_image.data); + p010_image.chroma_data = data + p010_image.luma_stride * p010_image.height; + p010_image.chroma_stride = p010_image.luma_stride; + } + + unique_ptr yuv420_image_data = + make_unique(p010_image.width * p010_image.height * 3 / 2); + jpegr_uncompressed_struct yuv420_image = {.data = yuv420_image_data.get(), + .width = p010_image.width, + .height = p010_image.height, + .colorGamut = p010_image.colorGamut, + .luma_stride = 0, + .chroma_data = nullptr, + .chroma_stride = 0}; + if (yuv420_image.luma_stride == 0) yuv420_image.luma_stride = yuv420_image.width; + if (!yuv420_image.chroma_data) { + uint8_t* data = reinterpret_cast(yuv420_image.data); + yuv420_image.chroma_data = data + yuv420_image.luma_stride * yuv420_image.height; + yuv420_image.chroma_stride = yuv420_image.luma_stride >> 1; + } + + // tone map + JPEGR_CHECK(toneMap(&p010_image, &yuv420_image)); + + // gain map + ultrahdr_metadata_struct metadata = {.version = kJpegrVersion}; + jpegr_uncompressed_struct gainmap_image; + JPEGR_CHECK(generateGainMap(&yuv420_image, &p010_image, hdr_tf, &metadata, &gainmap_image)); + std::unique_ptr map_data; + map_data.reset(reinterpret_cast(gainmap_image.data)); - jpegr_uncompressed_struct uncompressed_yuv_420_image; - unique_ptr uncompressed_yuv_420_image_data = make_unique( - uncompressed_p010_image->width * uncompressed_p010_image->height * 3 / 2); - uncompressed_yuv_420_image.data = uncompressed_yuv_420_image_data.get(); - JPEGR_CHECK(toneMap(uncompressed_p010_image, &uncompressed_yuv_420_image)); + // compress gain map + JpegEncoderHelper jpeg_enc_obj_gm; + JPEGR_CHECK(compressGainMap(&gainmap_image, &jpeg_enc_obj_gm)); + jpegr_compressed_struct compressed_map = {.data = jpeg_enc_obj_gm.getCompressedImagePtr(), + .length = static_cast( + jpeg_enc_obj_gm.getCompressedImageSize()), + .maxLength = static_cast( + jpeg_enc_obj_gm.getCompressedImageSize()), + .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; - jpegr_uncompressed_struct map; - JPEGR_CHECK(generateGainMap( - &uncompressed_yuv_420_image, uncompressed_p010_image, hdr_tf, &metadata, &map)); - std::unique_ptr map_data; - map_data.reset(reinterpret_cast(map.data)); - - JpegEncoderHelper jpeg_encoder_gainmap; - JPEGR_CHECK(compressGainMap(&map, &jpeg_encoder_gainmap)); - jpegr_compressed_struct compressed_map; - compressed_map.maxLength = jpeg_encoder_gainmap.getCompressedImageSize(); - compressed_map.length = compressed_map.maxLength; - compressed_map.data = jpeg_encoder_gainmap.getCompressedImagePtr(); - compressed_map.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; - - sp icc = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, - uncompressed_yuv_420_image.colorGamut); - - // Convert to Bt601 YUV encoding for JPEG encode - JPEGR_CHECK(convertYuv(&uncompressed_yuv_420_image, uncompressed_yuv_420_image.colorGamut, - ULTRAHDR_COLORGAMUT_P3)); - - JpegEncoderHelper jpeg_encoder; - if (!jpeg_encoder.compressImage(uncompressed_yuv_420_image.data, - uncompressed_yuv_420_image.width, - uncompressed_yuv_420_image.height, quality, - icc->getData(), icc->getLength())) { + sp icc = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, yuv420_image.colorGamut); + + // convert to Bt601 YUV encoding for JPEG encode + if (yuv420_image.colorGamut != ULTRAHDR_COLORGAMUT_P3) { + JPEGR_CHECK(convertYuv(&yuv420_image, yuv420_image.colorGamut, ULTRAHDR_COLORGAMUT_P3)); + } + + // compress 420 image + JpegEncoderHelper jpeg_enc_obj_yuv420; + if (!jpeg_enc_obj_yuv420.compressImage(yuv420_image.data, yuv420_image.width, yuv420_image.height, + quality, icc->getData(), icc->getLength())) { return ERROR_JPEGR_ENCODE_ERROR; } - jpegr_compressed_struct jpeg; - jpeg.data = jpeg_encoder.getCompressedImagePtr(); - jpeg.length = jpeg_encoder.getCompressedImageSize(); + jpegr_compressed_struct jpeg = {.data = jpeg_enc_obj_yuv420.getCompressedImagePtr(), + .length = static_cast( + jpeg_enc_obj_yuv420.getCompressedImageSize()), + .maxLength = static_cast( + jpeg_enc_obj_yuv420.getCompressedImageSize()), + .colorGamut = yuv420_image.colorGamut}; - // No ICC since JPEG encode already did it + // append gain map, no ICC since JPEG encode already did it JPEGR_CHECK(appendGainMap(&jpeg, &compressed_map, exif, /* icc */ nullptr, /* icc size */ 0, &metadata, dest)); @@ -284,264 +249,262 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, } /* Encode API-1 */ -status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, - jr_uncompressed_ptr uncompressed_yuv_420_image, - ultrahdr_transfer_function hdr_tf, - jr_compressed_ptr dest, - int quality, - jr_exif_ptr exif) { - if (uncompressed_yuv_420_image == nullptr) { +status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, + jr_uncompressed_ptr yuv420_image_ptr, ultrahdr_transfer_function hdr_tf, + jr_compressed_ptr dest, int quality, jr_exif_ptr exif) { + // validate input arguments + if (yuv420_image_ptr == nullptr) { ALOGE("received nullptr for uncompressed 420 image"); return ERROR_JPEGR_INVALID_NULL_PTR; } - if (exif != nullptr && exif->data == nullptr) { ALOGE("received nullptr for exif metadata"); return ERROR_JPEGR_INVALID_NULL_PTR; } - - if (status_t ret = areInputArgumentsValid( - uncompressed_p010_image, uncompressed_yuv_420_image, hdr_tf, - dest, quality) != NO_ERROR) { + if (auto ret = areInputArgumentsValid(p010_image_ptr, yuv420_image_ptr, hdr_tf, dest, quality); + ret != NO_ERROR) { return ret; } - ultrahdr_metadata_struct metadata; - metadata.version = kJpegrVersion; + // clean up input structure for later usage + jpegr_uncompressed_struct p010_image = *p010_image_ptr; + if (p010_image.luma_stride == 0) p010_image.luma_stride = p010_image.width; + if (!p010_image.chroma_data) { + uint16_t* data = reinterpret_cast(p010_image.data); + p010_image.chroma_data = data + p010_image.luma_stride * p010_image.height; + p010_image.chroma_stride = p010_image.luma_stride; + } + jpegr_uncompressed_struct yuv420_image = *yuv420_image_ptr; + if (yuv420_image.luma_stride == 0) yuv420_image.luma_stride = yuv420_image.width; + if (!yuv420_image.chroma_data) { + uint8_t* data = reinterpret_cast(yuv420_image.data); + yuv420_image.chroma_data = data + yuv420_image.luma_stride * yuv420_image.height; + yuv420_image.chroma_stride = yuv420_image.luma_stride >> 1; + } - jpegr_uncompressed_struct map; - JPEGR_CHECK(generateGainMap( - uncompressed_yuv_420_image, uncompressed_p010_image, hdr_tf, &metadata, &map)); + // gain map + ultrahdr_metadata_struct metadata = {.version = kJpegrVersion}; + jpegr_uncompressed_struct gainmap_image; + JPEGR_CHECK(generateGainMap(&yuv420_image, &p010_image, hdr_tf, &metadata, &gainmap_image)); std::unique_ptr map_data; - map_data.reset(reinterpret_cast(map.data)); - - JpegEncoderHelper jpeg_encoder_gainmap; - JPEGR_CHECK(compressGainMap(&map, &jpeg_encoder_gainmap)); - jpegr_compressed_struct compressed_map; - compressed_map.maxLength = jpeg_encoder_gainmap.getCompressedImageSize(); - compressed_map.length = compressed_map.maxLength; - compressed_map.data = jpeg_encoder_gainmap.getCompressedImagePtr(); - compressed_map.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; - - sp icc = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, - uncompressed_yuv_420_image->colorGamut); - - // Convert to Bt601 YUV encoding for JPEG encode and remove stride if needed; - // make a copy so as to no clobber client data - unique_ptr yuv_420_bt601_data = make_unique( - uncompressed_yuv_420_image->width * uncompressed_yuv_420_image->height * 3 / 2); - // copy data - { - uint8_t* src_luma_data = reinterpret_cast(uncompressed_yuv_420_image->data); - size_t src_luma_stride = uncompressed_yuv_420_image->luma_stride == 0 - ? uncompressed_yuv_420_image->width : uncompressed_yuv_420_image->luma_stride; - uint8_t* src_chroma_data = reinterpret_cast(uncompressed_yuv_420_image->chroma_data); - size_t src_chroma_stride = uncompressed_yuv_420_image->chroma_stride; - if (uncompressed_yuv_420_image->chroma_data == nullptr) { - src_chroma_data = - &reinterpret_cast(uncompressed_yuv_420_image->data)[src_luma_stride - * uncompressed_yuv_420_image->height]; - } - if (src_chroma_stride == 0) { - src_chroma_stride = src_luma_stride / 2; - } - // copy luma - for (size_t i = 0; i < uncompressed_yuv_420_image->height; i++) { - memcpy(yuv_420_bt601_data.get() + i * uncompressed_yuv_420_image->width, - src_luma_data + i * src_luma_stride, - uncompressed_yuv_420_image->width); - } - // copy cb - for (size_t i = 0; i < uncompressed_yuv_420_image->height / 2; i++) { - memcpy(yuv_420_bt601_data.get() - + uncompressed_yuv_420_image->width * uncompressed_yuv_420_image->height - + i * uncompressed_yuv_420_image->width / 2, - src_chroma_data + i * src_chroma_stride, - uncompressed_yuv_420_image->width / 2); + map_data.reset(reinterpret_cast(gainmap_image.data)); + + // compress gain map + JpegEncoderHelper jpeg_enc_obj_gm; + JPEGR_CHECK(compressGainMap(&gainmap_image, &jpeg_enc_obj_gm)); + jpegr_compressed_struct compressed_map = {.data = jpeg_enc_obj_gm.getCompressedImagePtr(), + .length = static_cast( + jpeg_enc_obj_gm.getCompressedImageSize()), + .maxLength = static_cast( + jpeg_enc_obj_gm.getCompressedImageSize()), + .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; + + sp icc = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, yuv420_image.colorGamut); + + jpegr_uncompressed_struct yuv420_bt601_image = yuv420_image; + unique_ptr yuv_420_bt601_data; + // Convert to bt601 YUV encoding for JPEG encode + if (yuv420_image.colorGamut != ULTRAHDR_COLORGAMUT_P3) { + yuv_420_bt601_data = make_unique(yuv420_image.width * yuv420_image.height * 3 / 2); + yuv420_bt601_image.data = yuv_420_bt601_data.get(); + yuv420_bt601_image.colorGamut = yuv420_image.colorGamut; + yuv420_bt601_image.luma_stride = yuv420_image.width; + uint8_t* data = reinterpret_cast(yuv420_bt601_image.data); + yuv420_bt601_image.chroma_data = data + yuv420_bt601_image.luma_stride * yuv420_image.height; + yuv420_bt601_image.chroma_stride = yuv420_bt601_image.luma_stride >> 1; + + { + // copy luma + uint8_t* y_dst = reinterpret_cast(yuv420_bt601_image.data); + uint8_t* y_src = reinterpret_cast(yuv420_image.data); + if (yuv420_bt601_image.luma_stride == yuv420_image.luma_stride) { + memcpy(y_dst, y_src, yuv420_bt601_image.luma_stride * yuv420_image.height); + } else { + for (size_t i = 0; i < yuv420_image.height; i++) { + memcpy(y_dst, y_src, yuv420_image.width); + y_dst += yuv420_bt601_image.luma_stride; + y_src += yuv420_image.luma_stride; + } + } } - // copy cr - for (size_t i = 0; i < uncompressed_yuv_420_image->height / 2; i++) { - memcpy(yuv_420_bt601_data.get() - + uncompressed_yuv_420_image->width * uncompressed_yuv_420_image->height * 5 / 4 - + i * uncompressed_yuv_420_image->width / 2, - src_chroma_data + src_chroma_stride * (uncompressed_yuv_420_image->height / 2) - + i * src_chroma_stride, - uncompressed_yuv_420_image->width / 2); + + if (yuv420_bt601_image.chroma_stride == yuv420_image.chroma_stride) { + // copy luma + uint8_t* ch_dst = reinterpret_cast(yuv420_bt601_image.chroma_data); + uint8_t* ch_src = reinterpret_cast(yuv420_image.chroma_data); + memcpy(ch_dst, ch_src, yuv420_bt601_image.chroma_stride * yuv420_image.height); + } else { + // copy cb & cr + uint8_t* cb_dst = reinterpret_cast(yuv420_bt601_image.chroma_data); + uint8_t* cb_src = reinterpret_cast(yuv420_image.chroma_data); + uint8_t* cr_dst = cb_dst + (yuv420_bt601_image.chroma_stride * yuv420_bt601_image.height / 2); + uint8_t* cr_src = cb_src + (yuv420_image.chroma_stride * yuv420_image.height / 2); + for (size_t i = 0; i < yuv420_image.height / 2; i++) { + memcpy(cb_dst, cb_src, yuv420_image.width / 2); + memcpy(cr_dst, cr_src, yuv420_image.width / 2); + cb_dst += yuv420_bt601_image.chroma_stride; + cb_src += yuv420_image.chroma_stride; + cr_dst += yuv420_bt601_image.chroma_stride; + cr_src += yuv420_image.chroma_stride; + } } + JPEGR_CHECK(convertYuv(&yuv420_bt601_image, yuv420_image.colorGamut, ULTRAHDR_COLORGAMUT_P3)); } - jpegr_uncompressed_struct yuv_420_bt601_image = { - yuv_420_bt601_data.get(), uncompressed_yuv_420_image->width, uncompressed_yuv_420_image->height, - uncompressed_yuv_420_image->colorGamut }; - JPEGR_CHECK(convertYuv(&yuv_420_bt601_image, yuv_420_bt601_image.colorGamut, - ULTRAHDR_COLORGAMUT_P3)); - - JpegEncoderHelper jpeg_encoder; - if (!jpeg_encoder.compressImage(yuv_420_bt601_image.data, - yuv_420_bt601_image.width, - yuv_420_bt601_image.height, quality, - icc->getData(), icc->getLength())) { + // compress 420 image + JpegEncoderHelper jpeg_enc_obj_yuv420; + if (!jpeg_enc_obj_yuv420.compressImage(yuv420_bt601_image.data, yuv420_bt601_image.width, + yuv420_bt601_image.height, quality, icc->getData(), + icc->getLength())) { return ERROR_JPEGR_ENCODE_ERROR; } - jpegr_compressed_struct jpeg; - jpeg.data = jpeg_encoder.getCompressedImagePtr(); - jpeg.length = jpeg_encoder.getCompressedImageSize(); - // No ICC since jpeg encode already did it + jpegr_compressed_struct jpeg = {.data = jpeg_enc_obj_yuv420.getCompressedImagePtr(), + .length = static_cast( + jpeg_enc_obj_yuv420.getCompressedImageSize()), + .maxLength = static_cast( + jpeg_enc_obj_yuv420.getCompressedImageSize()), + .colorGamut = yuv420_image.colorGamut}; + + // append gain map, no ICC since JPEG encode already did it JPEGR_CHECK(appendGainMap(&jpeg, &compressed_map, exif, /* icc */ nullptr, /* icc size */ 0, &metadata, dest)); - return NO_ERROR; } /* Encode API-2 */ -status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, - jr_uncompressed_ptr uncompressed_yuv_420_image, - jr_compressed_ptr compressed_jpeg_image, - ultrahdr_transfer_function hdr_tf, - jr_compressed_ptr dest) { - if (uncompressed_yuv_420_image == nullptr) { +status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, + jr_uncompressed_ptr yuv420_image_ptr, + jr_compressed_ptr yuv420jpg_image_ptr, + ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest) { + // validate input arguments + if (yuv420_image_ptr == nullptr) { ALOGE("received nullptr for uncompressed 420 image"); return ERROR_JPEGR_INVALID_NULL_PTR; } - - if (compressed_jpeg_image == nullptr || compressed_jpeg_image->data == nullptr) { + if (yuv420jpg_image_ptr == nullptr || yuv420jpg_image_ptr->data == nullptr) { ALOGE("received nullptr for compressed jpeg image"); return ERROR_JPEGR_INVALID_NULL_PTR; } - - if (status_t ret = areInputArgumentsValid( - uncompressed_p010_image, uncompressed_yuv_420_image, hdr_tf, dest) != NO_ERROR) { + if (auto ret = areInputArgumentsValid(p010_image_ptr, yuv420_image_ptr, hdr_tf, dest); + ret != NO_ERROR) { return ret; } - ultrahdr_metadata_struct metadata; - metadata.version = kJpegrVersion; - - jpegr_uncompressed_struct map; - JPEGR_CHECK(generateGainMap( - uncompressed_yuv_420_image, uncompressed_p010_image, hdr_tf, &metadata, &map)); - std::unique_ptr map_data; - map_data.reset(reinterpret_cast(map.data)); - - JpegEncoderHelper jpeg_encoder_gainmap; - JPEGR_CHECK(compressGainMap(&map, &jpeg_encoder_gainmap)); - jpegr_compressed_struct compressed_map; - compressed_map.maxLength = jpeg_encoder_gainmap.getCompressedImageSize(); - compressed_map.length = compressed_map.maxLength; - compressed_map.data = jpeg_encoder_gainmap.getCompressedImagePtr(); - compressed_map.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; - - // We just want to check if ICC is present, so don't do a full decode. Note, - // this doesn't verify that the ICC is valid. - JpegDecoderHelper decoder; - std::vector icc; - decoder.getCompressedImageParameters(compressed_jpeg_image->data, compressed_jpeg_image->length, - /* pWidth */ nullptr, /* pHeight */ nullptr, - &icc, /* exifData */ nullptr); - - // Add ICC if not already present. - if (icc.size() > 0) { - JPEGR_CHECK(appendGainMap(compressed_jpeg_image, &compressed_map, /* exif */ nullptr, - /* icc */ nullptr, /* icc size */ 0, &metadata, dest)); - } else { - sp newIcc = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, - uncompressed_yuv_420_image->colorGamut); - JPEGR_CHECK(appendGainMap(compressed_jpeg_image, &compressed_map, /* exif */ nullptr, - newIcc->getData(), newIcc->getLength(), &metadata, dest)); + // clean up input structure for later usage + jpegr_uncompressed_struct p010_image = *p010_image_ptr; + if (p010_image.luma_stride == 0) p010_image.luma_stride = p010_image.width; + if (!p010_image.chroma_data) { + uint16_t* data = reinterpret_cast(p010_image.data); + p010_image.chroma_data = data + p010_image.luma_stride * p010_image.height; + p010_image.chroma_stride = p010_image.luma_stride; + } + jpegr_uncompressed_struct yuv420_image = *yuv420_image_ptr; + if (yuv420_image.luma_stride == 0) yuv420_image.luma_stride = yuv420_image.width; + if (!yuv420_image.chroma_data) { + uint8_t* data = reinterpret_cast(yuv420_image.data); + yuv420_image.chroma_data = data + yuv420_image.luma_stride * p010_image.height; + yuv420_image.chroma_stride = yuv420_image.luma_stride >> 1; } - return NO_ERROR; + // gain map + ultrahdr_metadata_struct metadata = {.version = kJpegrVersion}; + jpegr_uncompressed_struct gainmap_image; + JPEGR_CHECK(generateGainMap(&yuv420_image, &p010_image, hdr_tf, &metadata, &gainmap_image)); + std::unique_ptr map_data; + map_data.reset(reinterpret_cast(gainmap_image.data)); + + // compress gain map + JpegEncoderHelper jpeg_enc_obj_gm; + JPEGR_CHECK(compressGainMap(&gainmap_image, &jpeg_enc_obj_gm)); + jpegr_compressed_struct gainmapjpg_image = {.data = jpeg_enc_obj_gm.getCompressedImagePtr(), + .length = static_cast( + jpeg_enc_obj_gm.getCompressedImageSize()), + .maxLength = static_cast( + jpeg_enc_obj_gm.getCompressedImageSize()), + .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; + + return encodeJPEGR(yuv420jpg_image_ptr, &gainmapjpg_image, &metadata, dest); } /* Encode API-3 */ -status_t JpegR::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image, - jr_compressed_ptr compressed_jpeg_image, - ultrahdr_transfer_function hdr_tf, - jr_compressed_ptr dest) { - if (compressed_jpeg_image == nullptr || compressed_jpeg_image->data == nullptr) { +status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, + jr_compressed_ptr yuv420jpg_image_ptr, + ultrahdr_transfer_function hdr_tf, jr_compressed_ptr dest) { + // validate input arguments + if (yuv420jpg_image_ptr == nullptr || yuv420jpg_image_ptr->data == nullptr) { ALOGE("received nullptr for compressed jpeg image"); return ERROR_JPEGR_INVALID_NULL_PTR; } - - if (status_t ret = areInputArgumentsValid( - uncompressed_p010_image, /* uncompressed_yuv_420_image */ nullptr, - hdr_tf, dest) != NO_ERROR) { + if (auto ret = areInputArgumentsValid(p010_image_ptr, nullptr, hdr_tf, dest); ret != NO_ERROR) { return ret; } - // Note: output is Bt.601 YUV encoded regardless of gamut, due to jpeg decode. - JpegDecoderHelper jpeg_decoder; - if (!jpeg_decoder.decompressImage(compressed_jpeg_image->data, compressed_jpeg_image->length)) { + // clean up input structure for later usage + jpegr_uncompressed_struct p010_image = *p010_image_ptr; + if (p010_image.luma_stride == 0) p010_image.luma_stride = p010_image.width; + if (!p010_image.chroma_data) { + uint16_t* data = reinterpret_cast(p010_image.data); + p010_image.chroma_data = data + p010_image.luma_stride * p010_image.height; + p010_image.chroma_stride = p010_image.luma_stride; + } + + // decode input jpeg, gamut is going to be bt601. + JpegDecoderHelper jpeg_dec_obj_yuv420; + if (!jpeg_dec_obj_yuv420.decompressImage(yuv420jpg_image_ptr->data, + yuv420jpg_image_ptr->length)) { return ERROR_JPEGR_DECODE_ERROR; } - jpegr_uncompressed_struct uncompressed_yuv_420_image; - uncompressed_yuv_420_image.data = jpeg_decoder.getDecompressedImagePtr(); - uncompressed_yuv_420_image.width = jpeg_decoder.getDecompressedImageWidth(); - uncompressed_yuv_420_image.height = jpeg_decoder.getDecompressedImageHeight(); - uncompressed_yuv_420_image.colorGamut = compressed_jpeg_image->colorGamut; + jpegr_uncompressed_struct yuv420_image{}; + yuv420_image.data = jpeg_dec_obj_yuv420.getDecompressedImagePtr(); + yuv420_image.width = jpeg_dec_obj_yuv420.getDecompressedImageWidth(); + yuv420_image.height = jpeg_dec_obj_yuv420.getDecompressedImageHeight(); + yuv420_image.colorGamut = yuv420jpg_image_ptr->colorGamut; + if (yuv420_image.luma_stride == 0) yuv420_image.luma_stride = yuv420_image.width; + if (!yuv420_image.chroma_data) { + uint8_t* data = reinterpret_cast(yuv420_image.data); + yuv420_image.chroma_data = data + yuv420_image.luma_stride * p010_image.height; + yuv420_image.chroma_stride = yuv420_image.luma_stride >> 1; + } - if (uncompressed_p010_image->width != uncompressed_yuv_420_image.width - || uncompressed_p010_image->height != uncompressed_yuv_420_image.height) { + if (p010_image_ptr->width != yuv420_image.width || + p010_image_ptr->height != yuv420_image.height) { return ERROR_JPEGR_RESOLUTION_MISMATCH; } - ultrahdr_metadata_struct metadata; - metadata.version = kJpegrVersion; - - jpegr_uncompressed_struct map; - // Indicate that the SDR image is Bt.601 YUV encoded. - JPEGR_CHECK(generateGainMap( - &uncompressed_yuv_420_image, uncompressed_p010_image, hdr_tf, &metadata, &map, - true /* sdr_is_601 */ )); + // gain map + ultrahdr_metadata_struct metadata = {.version = kJpegrVersion}; + jpegr_uncompressed_struct gainmap_image; + JPEGR_CHECK(generateGainMap(&yuv420_image, &p010_image, hdr_tf, &metadata, &gainmap_image, + true /* sdr_is_601 */)); std::unique_ptr map_data; - map_data.reset(reinterpret_cast(map.data)); - - JpegEncoderHelper jpeg_encoder_gainmap; - JPEGR_CHECK(compressGainMap(&map, &jpeg_encoder_gainmap)); - jpegr_compressed_struct compressed_map; - compressed_map.maxLength = jpeg_encoder_gainmap.getCompressedImageSize(); - compressed_map.length = compressed_map.maxLength; - compressed_map.data = jpeg_encoder_gainmap.getCompressedImagePtr(); - compressed_map.colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; - - // We just want to check if ICC is present, so don't do a full decode. Note, - // this doesn't verify that the ICC is valid. - JpegDecoderHelper decoder; - std::vector icc; - decoder.getCompressedImageParameters(compressed_jpeg_image->data, compressed_jpeg_image->length, - /* pWidth */ nullptr, /* pHeight */ nullptr, - &icc, /* exifData */ nullptr); - - // Add ICC if not already present. - if (icc.size() > 0) { - JPEGR_CHECK(appendGainMap(compressed_jpeg_image, &compressed_map, /* exif */ nullptr, - /* icc */ nullptr, /* icc size */ 0, &metadata, dest)); - } else { - sp newIcc = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, - uncompressed_yuv_420_image.colorGamut); - JPEGR_CHECK(appendGainMap(compressed_jpeg_image, &compressed_map, /* exif */ nullptr, - newIcc->getData(), newIcc->getLength(), &metadata, dest)); - } - - return NO_ERROR; + map_data.reset(reinterpret_cast(gainmap_image.data)); + + // compress gain map + JpegEncoderHelper jpeg_enc_obj_gm; + JPEGR_CHECK(compressGainMap(&gainmap_image, &jpeg_enc_obj_gm)); + jpegr_compressed_struct gainmapjpg_image = {.data = jpeg_enc_obj_gm.getCompressedImagePtr(), + .length = static_cast( + jpeg_enc_obj_gm.getCompressedImageSize()), + .maxLength = static_cast( + jpeg_enc_obj_gm.getCompressedImageSize()), + .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; + + return encodeJPEGR(yuv420jpg_image_ptr, &gainmapjpg_image, &metadata, dest); } /* Encode API-4 */ -status_t JpegR::encodeJPEGR(jr_compressed_ptr compressed_jpeg_image, - jr_compressed_ptr compressed_gainmap, - ultrahdr_metadata_ptr metadata, +status_t JpegR::encodeJPEGR(jr_compressed_ptr yuv420jpg_image_ptr, + jr_compressed_ptr gainmapjpg_image_ptr, ultrahdr_metadata_ptr metadata, jr_compressed_ptr dest) { - if (compressed_jpeg_image == nullptr || compressed_jpeg_image->data == nullptr) { + if (yuv420jpg_image_ptr == nullptr || yuv420jpg_image_ptr->data == nullptr) { ALOGE("received nullptr for compressed jpeg image"); return ERROR_JPEGR_INVALID_NULL_PTR; } - - if (compressed_gainmap == nullptr || compressed_gainmap->data == nullptr) { + if (gainmapjpg_image_ptr == nullptr || gainmapjpg_image_ptr->data == nullptr) { ALOGE("received nullptr for compressed gain map"); return ERROR_JPEGR_INVALID_NULL_PTR; } - if (dest == nullptr || dest->data == nullptr) { ALOGE("received nullptr for destination"); return ERROR_JPEGR_INVALID_NULL_PTR; @@ -551,46 +514,46 @@ status_t JpegR::encodeJPEGR(jr_compressed_ptr compressed_jpeg_image, // this doesn't verify that the ICC is valid. JpegDecoderHelper decoder; std::vector icc; - decoder.getCompressedImageParameters(compressed_jpeg_image->data, compressed_jpeg_image->length, - /* pWidth */ nullptr, /* pHeight */ nullptr, - &icc, /* exifData */ nullptr); + decoder.getCompressedImageParameters(yuv420jpg_image_ptr->data, yuv420jpg_image_ptr->length, + /* pWidth */ nullptr, /* pHeight */ nullptr, &icc, + /* exifData */ nullptr); // Add ICC if not already present. if (icc.size() > 0) { - JPEGR_CHECK(appendGainMap(compressed_jpeg_image, compressed_gainmap, /* exif */ nullptr, - /* icc */ nullptr, /* icc size */ 0, metadata, dest)); + JPEGR_CHECK(appendGainMap(yuv420jpg_image_ptr, gainmapjpg_image_ptr, /* exif */ nullptr, + /* icc */ nullptr, /* icc size */ 0, metadata, dest)); } else { - sp newIcc = IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, - compressed_jpeg_image->colorGamut); - JPEGR_CHECK(appendGainMap(compressed_jpeg_image, compressed_gainmap, /* exif */ nullptr, - newIcc->getData(), newIcc->getLength(), metadata, dest)); + sp newIcc = + IccHelper::writeIccProfile(ULTRAHDR_TF_SRGB, yuv420jpg_image_ptr->colorGamut); + JPEGR_CHECK(appendGainMap(yuv420jpg_image_ptr, gainmapjpg_image_ptr, /* exif */ nullptr, + newIcc->getData(), newIcc->getLength(), metadata, dest)); } return NO_ERROR; } -status_t JpegR::getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image, jr_info_ptr jpegr_info) { - if (compressed_jpegr_image == nullptr || compressed_jpegr_image->data == nullptr) { +status_t JpegR::getJPEGRInfo(jr_compressed_ptr jpegr_image_ptr, jr_info_ptr jpeg_image_info_ptr) { + if (jpegr_image_ptr == nullptr || jpegr_image_ptr->data == nullptr) { ALOGE("received nullptr for compressed jpegr image"); return ERROR_JPEGR_INVALID_NULL_PTR; } - - if (jpegr_info == nullptr) { + if (jpeg_image_info_ptr == nullptr) { ALOGE("received nullptr for compressed jpegr info struct"); return ERROR_JPEGR_INVALID_NULL_PTR; } jpegr_compressed_struct primary_image, gainmap_image; - status_t status = - extractPrimaryImageAndGainMap(compressed_jpegr_image, &primary_image, &gainmap_image); + status_t status = extractPrimaryImageAndGainMap(jpegr_image_ptr, &primary_image, &gainmap_image); if (status != NO_ERROR && status != ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND) { return status; } - JpegDecoderHelper jpeg_decoder; - if (!jpeg_decoder.getCompressedImageParameters(primary_image.data, primary_image.length, - &jpegr_info->width, &jpegr_info->height, - jpegr_info->iccData, jpegr_info->exifData)) { + JpegDecoderHelper jpeg_dec_obj_hdr; + if (!jpeg_dec_obj_hdr.getCompressedImageParameters(primary_image.data, primary_image.length, + &jpeg_image_info_ptr->width, + &jpeg_image_info_ptr->height, + jpeg_image_info_ptr->iccData, + jpeg_image_info_ptr->exifData)) { return ERROR_JPEGR_DECODE_ERROR; } @@ -598,41 +561,34 @@ status_t JpegR::getJPEGRInfo(jr_compressed_ptr compressed_jpegr_image, jr_info_p } /* Decode API */ -status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, - jr_uncompressed_ptr dest, - float max_display_boost, - jr_exif_ptr exif, +status_t JpegR::decodeJPEGR(jr_compressed_ptr jpegr_image_ptr, jr_uncompressed_ptr dest, + float max_display_boost, jr_exif_ptr exif, ultrahdr_output_format output_format, - jr_uncompressed_ptr gain_map, - ultrahdr_metadata_ptr metadata) { - if (compressed_jpegr_image == nullptr || compressed_jpegr_image->data == nullptr) { + jr_uncompressed_ptr gainmap_image_ptr, ultrahdr_metadata_ptr metadata) { + if (jpegr_image_ptr == nullptr || jpegr_image_ptr->data == nullptr) { ALOGE("received nullptr for compressed jpegr image"); return ERROR_JPEGR_INVALID_NULL_PTR; } - if (dest == nullptr || dest->data == nullptr) { ALOGE("received nullptr for dest image"); return ERROR_JPEGR_INVALID_NULL_PTR; } - if (max_display_boost < 1.0f) { ALOGE("received bad value for max_display_boost %f", max_display_boost); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - if (exif != nullptr && exif->data == nullptr) { ALOGE("received nullptr address for exif data"); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - if (output_format <= ULTRAHDR_OUTPUT_UNSPECIFIED || output_format > ULTRAHDR_OUTPUT_MAX) { ALOGE("received bad value for output format %d", output_format); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - jpegr_compressed_struct primary_image, gainmap_image; + jpegr_compressed_struct primary_jpeg_image, gainmap_jpeg_image; status_t status = - extractPrimaryImageAndGainMap(compressed_jpegr_image, &primary_image, &gainmap_image); + extractPrimaryImageAndGainMap(jpegr_image_ptr, &primary_jpeg_image, &gainmap_jpeg_image); if (status != NO_ERROR) { if (output_format != ULTRAHDR_OUTPUT_SDR || status != ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND) { ALOGE("received invalid compressed jpegr image"); @@ -640,22 +596,22 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, } } - JpegDecoderHelper jpeg_decoder; - if (!jpeg_decoder.decompressImage(primary_image.data, primary_image.length, - (output_format == ULTRAHDR_OUTPUT_SDR))) { + JpegDecoderHelper jpeg_dec_obj_yuv420; + if (!jpeg_dec_obj_yuv420.decompressImage(primary_jpeg_image.data, primary_jpeg_image.length, + (output_format == ULTRAHDR_OUTPUT_SDR))) { return ERROR_JPEGR_DECODE_ERROR; } if (output_format == ULTRAHDR_OUTPUT_SDR) { - if ((jpeg_decoder.getDecompressedImageWidth() * - jpeg_decoder.getDecompressedImageHeight() * 4) > - jpeg_decoder.getDecompressedImageSize()) { + if ((jpeg_dec_obj_yuv420.getDecompressedImageWidth() * + jpeg_dec_obj_yuv420.getDecompressedImageHeight() * 4) > + jpeg_dec_obj_yuv420.getDecompressedImageSize()) { return ERROR_JPEGR_CALCULATION_ERROR; } } else { - if ((jpeg_decoder.getDecompressedImageWidth() * - jpeg_decoder.getDecompressedImageHeight() * 3 / 2) > - jpeg_decoder.getDecompressedImageSize()) { + if ((jpeg_dec_obj_yuv420.getDecompressedImageWidth() * + jpeg_dec_obj_yuv420.getDecompressedImageHeight() * 3 / 2) > + jpeg_dec_obj_yuv420.getDecompressedImageSize()) { return ERROR_JPEGR_CALCULATION_ERROR; } } @@ -664,46 +620,46 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, if (exif->data == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } - if (exif->length < jpeg_decoder.getEXIFSize()) { + if (exif->length < jpeg_dec_obj_yuv420.getEXIFSize()) { return ERROR_JPEGR_BUFFER_TOO_SMALL; } - memcpy(exif->data, jpeg_decoder.getEXIFPtr(), jpeg_decoder.getEXIFSize()); - exif->length = jpeg_decoder.getEXIFSize(); + memcpy(exif->data, jpeg_dec_obj_yuv420.getEXIFPtr(), jpeg_dec_obj_yuv420.getEXIFSize()); + exif->length = jpeg_dec_obj_yuv420.getEXIFSize(); } if (output_format == ULTRAHDR_OUTPUT_SDR) { - dest->width = jpeg_decoder.getDecompressedImageWidth(); - dest->height = jpeg_decoder.getDecompressedImageHeight(); - memcpy(dest->data, jpeg_decoder.getDecompressedImagePtr(), dest->width * dest->height * 4); + dest->width = jpeg_dec_obj_yuv420.getDecompressedImageWidth(); + dest->height = jpeg_dec_obj_yuv420.getDecompressedImageHeight(); + memcpy(dest->data, jpeg_dec_obj_yuv420.getDecompressedImagePtr(), + dest->width * dest->height * 4); return NO_ERROR; } - JpegDecoderHelper gain_map_decoder; - if (!gain_map_decoder.decompressImage(gainmap_image.data, gainmap_image.length)) { + JpegDecoderHelper jpeg_dec_obj_gm; + if (!jpeg_dec_obj_gm.decompressImage(gainmap_jpeg_image.data, gainmap_jpeg_image.length)) { return ERROR_JPEGR_DECODE_ERROR; } - if ((gain_map_decoder.getDecompressedImageWidth() * - gain_map_decoder.getDecompressedImageHeight()) > - gain_map_decoder.getDecompressedImageSize()) { + if ((jpeg_dec_obj_gm.getDecompressedImageWidth() * jpeg_dec_obj_gm.getDecompressedImageHeight()) > + jpeg_dec_obj_gm.getDecompressedImageSize()) { return ERROR_JPEGR_CALCULATION_ERROR; } - jpegr_uncompressed_struct map; - map.data = gain_map_decoder.getDecompressedImagePtr(); - map.width = gain_map_decoder.getDecompressedImageWidth(); - map.height = gain_map_decoder.getDecompressedImageHeight(); + jpegr_uncompressed_struct gainmap_image; + gainmap_image.data = jpeg_dec_obj_gm.getDecompressedImagePtr(); + gainmap_image.width = jpeg_dec_obj_gm.getDecompressedImageWidth(); + gainmap_image.height = jpeg_dec_obj_gm.getDecompressedImageHeight(); - if (gain_map != nullptr) { - gain_map->width = map.width; - gain_map->height = map.height; - int size = gain_map->width * gain_map->height; - gain_map->data = malloc(size); - memcpy(gain_map->data, map.data, size); + if (gainmap_image_ptr != nullptr) { + gainmap_image_ptr->width = gainmap_image.width; + gainmap_image_ptr->height = gainmap_image.height; + int size = gainmap_image_ptr->width * gainmap_image_ptr->height; + gainmap_image_ptr->data = malloc(size); + memcpy(gainmap_image_ptr->data, gainmap_image.data, size); } ultrahdr_metadata_struct uhdr_metadata; - if (!getMetadataFromXMP(static_cast(gain_map_decoder.getXMPPtr()), - gain_map_decoder.getXMPSize(), &uhdr_metadata)) { + if (!getMetadataFromXMP(static_cast(jpeg_dec_obj_gm.getXMPPtr()), + jpeg_dec_obj_gm.getXMPSize(), &uhdr_metadata)) { return ERROR_JPEGR_INVALID_METADATA; } @@ -718,32 +674,32 @@ status_t JpegR::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image, metadata->hdrCapacityMax = uhdr_metadata.hdrCapacityMax; } - jpegr_uncompressed_struct uncompressed_yuv_420_image; - uncompressed_yuv_420_image.data = jpeg_decoder.getDecompressedImagePtr(); - uncompressed_yuv_420_image.width = jpeg_decoder.getDecompressedImageWidth(); - uncompressed_yuv_420_image.height = jpeg_decoder.getDecompressedImageHeight(); - uncompressed_yuv_420_image.colorGamut = IccHelper::readIccColorGamut( - jpeg_decoder.getICCPtr(), jpeg_decoder.getICCSize()); + jpegr_uncompressed_struct yuv420_image; + yuv420_image.data = jpeg_dec_obj_yuv420.getDecompressedImagePtr(); + yuv420_image.width = jpeg_dec_obj_yuv420.getDecompressedImageWidth(); + yuv420_image.height = jpeg_dec_obj_yuv420.getDecompressedImageHeight(); + yuv420_image.colorGamut = IccHelper::readIccColorGamut(jpeg_dec_obj_yuv420.getICCPtr(), + jpeg_dec_obj_yuv420.getICCSize()); + yuv420_image.luma_stride = yuv420_image.width; + uint8_t* data = reinterpret_cast(yuv420_image.data); + yuv420_image.chroma_data = data + yuv420_image.luma_stride * yuv420_image.height; + yuv420_image.chroma_stride = yuv420_image.width >> 1; - JPEGR_CHECK(applyGainMap(&uncompressed_yuv_420_image, &map, &uhdr_metadata, output_format, + JPEGR_CHECK(applyGainMap(&yuv420_image, &gainmap_image, &uhdr_metadata, output_format, max_display_boost, dest)); return NO_ERROR; } -status_t JpegR::compressGainMap(jr_uncompressed_ptr uncompressed_gain_map, - JpegEncoderHelper* jpeg_encoder) { - if (uncompressed_gain_map == nullptr || jpeg_encoder == nullptr) { +status_t JpegR::compressGainMap(jr_uncompressed_ptr gainmap_image_ptr, + JpegEncoderHelper* jpeg_enc_obj_ptr) { + if (gainmap_image_ptr == nullptr || jpeg_enc_obj_ptr == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } // Don't need to convert YUV to Bt601 since single channel - if (!jpeg_encoder->compressImage(uncompressed_gain_map->data, - uncompressed_gain_map->width, - uncompressed_gain_map->height, - kMapCompressQuality, - nullptr, - 0, - true /* isSingleChannel */)) { + if (!jpeg_enc_obj_ptr->compressImage(gainmap_image_ptr->data, gainmap_image_ptr->width, + gainmap_image_ptr->height, kMapCompressQuality, nullptr, 0, + true /* isSingleChannel */)) { return ERROR_JPEGR_ENCODE_ERROR; } @@ -755,13 +711,13 @@ static_assert(kJobSzInRows > 0 && kJobSzInRows % kMapDimensionScaleFactor == 0, "align job size to kMapDimensionScaleFactor"); class JobQueue { - public: +public: bool dequeueJob(size_t& rowStart, size_t& rowEnd); void enqueueJob(size_t rowStart, size_t rowEnd); void markQueueForEnd(); void reset(); - private: +private: bool mQueuedAllJobs = false; std::deque> mJobs; std::mutex mMutex; @@ -808,40 +764,37 @@ void JobQueue::reset() { mQueuedAllJobs = false; } -status_t JpegR::generateGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, - jr_uncompressed_ptr uncompressed_p010_image, - ultrahdr_transfer_function hdr_tf, - ultrahdr_metadata_ptr metadata, - jr_uncompressed_ptr dest, - bool sdr_is_601) { - if (uncompressed_yuv_420_image == nullptr - || uncompressed_p010_image == nullptr - || metadata == nullptr - || dest == nullptr) { +status_t JpegR::generateGainMap(jr_uncompressed_ptr yuv420_image_ptr, + jr_uncompressed_ptr p010_image_ptr, + ultrahdr_transfer_function hdr_tf, ultrahdr_metadata_ptr metadata, + jr_uncompressed_ptr dest, bool sdr_is_601) { + if (yuv420_image_ptr == nullptr || p010_image_ptr == nullptr || metadata == nullptr || + dest == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } - - if (uncompressed_yuv_420_image->width != uncompressed_p010_image->width - || uncompressed_yuv_420_image->height != uncompressed_p010_image->height) { + if (yuv420_image_ptr->width != p010_image_ptr->width || + yuv420_image_ptr->height != p010_image_ptr->height) { return ERROR_JPEGR_RESOLUTION_MISMATCH; } - - if (uncompressed_yuv_420_image->colorGamut == ULTRAHDR_COLORGAMUT_UNSPECIFIED - || uncompressed_p010_image->colorGamut == ULTRAHDR_COLORGAMUT_UNSPECIFIED) { + if (yuv420_image_ptr->colorGamut == ULTRAHDR_COLORGAMUT_UNSPECIFIED || + p010_image_ptr->colorGamut == ULTRAHDR_COLORGAMUT_UNSPECIFIED) { return ERROR_JPEGR_INVALID_COLORGAMUT; } - size_t image_width = uncompressed_yuv_420_image->width; - size_t image_height = uncompressed_yuv_420_image->height; + size_t image_width = yuv420_image_ptr->width; + size_t image_height = yuv420_image_ptr->height; size_t map_width = static_cast( floor((image_width + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); size_t map_height = static_cast( floor((image_height + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); + dest->data = new uint8_t[map_width * map_height]; dest->width = map_width; dest->height = map_height; dest->colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED; - dest->data = new uint8_t[map_width * map_height]; + dest->luma_stride = map_width; + dest->chroma_data = nullptr; + dest->chroma_stride = 0; std::unique_ptr map_data; map_data.reset(reinterpret_cast(dest->data)); @@ -883,12 +836,12 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, float log2MinBoost = log2(metadata->minContentBoost); float log2MaxBoost = log2(metadata->maxContentBoost); - ColorTransformFn hdrGamutConversionFn = getHdrConversionFn( - uncompressed_yuv_420_image->colorGamut, uncompressed_p010_image->colorGamut); + ColorTransformFn hdrGamutConversionFn = + getHdrConversionFn(yuv420_image_ptr->colorGamut, p010_image_ptr->colorGamut); ColorCalculationFn luminanceFn = nullptr; ColorTransformFn sdrYuvToRgbFn = nullptr; - switch (uncompressed_yuv_420_image->colorGamut) { + switch (yuv420_image_ptr->colorGamut) { case ULTRAHDR_COLORGAMUT_BT709: luminanceFn = srgbLuminance; sdrYuvToRgbFn = srgbYuvToRgb; @@ -910,7 +863,7 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, } ColorTransformFn hdrYuvToRgbFn = nullptr; - switch (uncompressed_p010_image->colorGamut) { + switch (p010_image_ptr->colorGamut) { case ULTRAHDR_COLORGAMUT_BT709: hdrYuvToRgbFn = srgbYuvToRgb; break; @@ -930,16 +883,15 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, size_t rowStep = threads == 1 ? image_height : kJobSzInRows; JobQueue jobQueue; - std::function generateMap = [uncompressed_yuv_420_image, uncompressed_p010_image, - metadata, dest, hdrInvOetf, hdrGamutConversionFn, - luminanceFn, sdrYuvToRgbFn, hdrYuvToRgbFn, hdr_white_nits, - log2MinBoost, log2MaxBoost, &jobQueue]() -> void { + std::function generateMap = [yuv420_image_ptr, p010_image_ptr, metadata, dest, hdrInvOetf, + hdrGamutConversionFn, luminanceFn, sdrYuvToRgbFn, + hdrYuvToRgbFn, hdr_white_nits, log2MinBoost, log2MaxBoost, + &jobQueue]() -> void { size_t rowStart, rowEnd; while (jobQueue.dequeueJob(rowStart, rowEnd)) { for (size_t y = rowStart; y < rowEnd; ++y) { for (size_t x = 0; x < dest->width; ++x) { - Color sdr_yuv_gamma = - sampleYuv420(uncompressed_yuv_420_image, kMapDimensionScaleFactor, x, y); + Color sdr_yuv_gamma = sampleYuv420(yuv420_image_ptr, kMapDimensionScaleFactor, x, y); Color sdr_rgb_gamma = sdrYuvToRgbFn(sdr_yuv_gamma); // We are assuming the SDR input is always sRGB transfer. #if USE_SRGB_INVOETF_LUT @@ -949,7 +901,7 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, #endif float sdr_y_nits = luminanceFn(sdr_rgb) * kSdrWhiteNits; - Color hdr_yuv_gamma = sampleP010(uncompressed_p010_image, kMapDimensionScaleFactor, x, y); + Color hdr_yuv_gamma = sampleP010(p010_image_ptr, kMapDimensionScaleFactor, x, y); Color hdr_rgb_gamma = hdrYuvToRgbFn(hdr_yuv_gamma); Color hdr_rgb = hdrInvOetf(hdr_rgb_gamma); hdr_rgb = hdrGamutConversionFn(hdr_rgb); @@ -957,7 +909,7 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, size_t pixel_idx = x + y * dest->width; reinterpret_cast(dest->data)[pixel_idx] = - encodeGain(sdr_y_nits, hdr_y_nits, metadata, log2MinBoost, log2MaxBoost); + encodeGain(sdr_y_nits, hdr_y_nits, metadata, log2MinBoost, log2MaxBoost); } } } @@ -983,70 +935,63 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, return NO_ERROR; } -status_t JpegR::applyGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, - jr_uncompressed_ptr uncompressed_gain_map, - ultrahdr_metadata_ptr metadata, - ultrahdr_output_format output_format, - float max_display_boost, +status_t JpegR::applyGainMap(jr_uncompressed_ptr yuv420_image_ptr, + jr_uncompressed_ptr gainmap_image_ptr, ultrahdr_metadata_ptr metadata, + ultrahdr_output_format output_format, float max_display_boost, jr_uncompressed_ptr dest) { - if (uncompressed_yuv_420_image == nullptr - || uncompressed_gain_map == nullptr - || metadata == nullptr - || dest == nullptr) { + if (yuv420_image_ptr == nullptr || gainmap_image_ptr == nullptr || metadata == nullptr || + dest == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } - - if (metadata->version.compare("1.0")) { - ALOGE("Unsupported metadata version: %s", metadata->version.c_str()); - return ERROR_JPEGR_UNSUPPORTED_METADATA; + if (metadata->version.compare(kJpegrVersion)) { + ALOGE("Unsupported metadata version: %s", metadata->version.c_str()); + return ERROR_JPEGR_UNSUPPORTED_METADATA; } if (metadata->gamma != 1.0f) { - ALOGE("Unsupported metadata gamma: %f", metadata->gamma); - return ERROR_JPEGR_UNSUPPORTED_METADATA; + ALOGE("Unsupported metadata gamma: %f", metadata->gamma); + return ERROR_JPEGR_UNSUPPORTED_METADATA; } if (metadata->offsetSdr != 0.0f || metadata->offsetHdr != 0.0f) { - ALOGE("Unsupported metadata offset sdr, hdr: %f, %f", metadata->offsetSdr, - metadata->offsetHdr); - return ERROR_JPEGR_UNSUPPORTED_METADATA; + ALOGE("Unsupported metadata offset sdr, hdr: %f, %f", metadata->offsetSdr, metadata->offsetHdr); + return ERROR_JPEGR_UNSUPPORTED_METADATA; } - if (metadata->hdrCapacityMin != metadata->minContentBoost - || metadata->hdrCapacityMax != metadata->maxContentBoost) { - ALOGE("Unsupported metadata hdr capacity min, max: %f, %f", metadata->hdrCapacityMin, - metadata->hdrCapacityMax); - return ERROR_JPEGR_UNSUPPORTED_METADATA; + if (metadata->hdrCapacityMin != metadata->minContentBoost || + metadata->hdrCapacityMax != metadata->maxContentBoost) { + ALOGE("Unsupported metadata hdr capacity min, max: %f, %f", metadata->hdrCapacityMin, + metadata->hdrCapacityMax); + return ERROR_JPEGR_UNSUPPORTED_METADATA; } // TODO: remove once map scaling factor is computed based on actual map dims - size_t image_width = uncompressed_yuv_420_image->width; - size_t image_height = uncompressed_yuv_420_image->height; + size_t image_width = yuv420_image_ptr->width; + size_t image_height = yuv420_image_ptr->height; size_t map_width = static_cast( floor((image_width + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); size_t map_height = static_cast( floor((image_height + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); - if (map_width != uncompressed_gain_map->width - || map_height != uncompressed_gain_map->height) { + if (map_width != gainmap_image_ptr->width || map_height != gainmap_image_ptr->height) { ALOGE("gain map dimensions and primary image dimensions are not to scale"); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - dest->width = uncompressed_yuv_420_image->width; - dest->height = uncompressed_yuv_420_image->height; + dest->width = yuv420_image_ptr->width; + dest->height = yuv420_image_ptr->height; ShepardsIDW idwTable(kMapDimensionScaleFactor); float display_boost = std::min(max_display_boost, metadata->maxContentBoost); GainLUT gainLUT(metadata, display_boost); JobQueue jobQueue; - std::function applyRecMap = [uncompressed_yuv_420_image, uncompressed_gain_map, - metadata, dest, &jobQueue, &idwTable, output_format, - &gainLUT, display_boost]() -> void { - size_t width = uncompressed_yuv_420_image->width; - size_t height = uncompressed_yuv_420_image->height; + std::function applyRecMap = [yuv420_image_ptr, gainmap_image_ptr, metadata, dest, + &jobQueue, &idwTable, output_format, &gainLUT, + display_boost]() -> void { + size_t width = yuv420_image_ptr->width; + size_t height = yuv420_image_ptr->height; size_t rowStart, rowEnd; while (jobQueue.dequeueJob(rowStart, rowEnd)) { for (size_t y = rowStart; y < rowEnd; ++y) { for (size_t x = 0; x < width; ++x) { - Color yuv_gamma_sdr = getYuv420Pixel(uncompressed_yuv_420_image, x, y); + Color yuv_gamma_sdr = getYuv420Pixel(yuv420_image_ptr, x, y); // Assuming the sdr image is a decoded JPEG, we should always use Rec.601 YUV coefficients Color rgb_gamma_sdr = p3YuvToRgb(yuv_gamma_sdr); // We are assuming the SDR base image is always sRGB transfer. @@ -1062,9 +1007,9 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, // Currently map_scale_factor is of type size_t, but it could be changed to a float // later. if (map_scale_factor != floorf(map_scale_factor)) { - gain = sampleMap(uncompressed_gain_map, map_scale_factor, x, y); + gain = sampleMap(gainmap_image_ptr, map_scale_factor, x, y); } else { - gain = sampleMap(uncompressed_gain_map, map_scale_factor, x, y, idwTable); + gain = sampleMap(gainmap_image_ptr, map_scale_factor, x, y, idwTable); } #if USE_APPLY_GAIN_LUT @@ -1076,14 +1021,12 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, size_t pixel_idx = x + y * width; switch (output_format) { - case ULTRAHDR_OUTPUT_HDR_LINEAR: - { + case ULTRAHDR_OUTPUT_HDR_LINEAR: { uint64_t rgba_f16 = colorToRgbaF16(rgb_hdr); reinterpret_cast(dest->data)[pixel_idx] = rgba_f16; break; } - case ULTRAHDR_OUTPUT_HDR_HLG: - { + case ULTRAHDR_OUTPUT_HDR_HLG: { #if USE_HLG_OETF_LUT ColorTransformFn hdrOetf = hlgOetfLUT; #else @@ -1094,8 +1037,7 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, reinterpret_cast(dest->data)[pixel_idx] = rgba_1010102; break; } - case ULTRAHDR_OUTPUT_HDR_PQ: - { + case ULTRAHDR_OUTPUT_HDR_PQ: { #if USE_PQ_OETF_LUT ColorTransformFn hdrOetf = pqOetfLUT; #else @@ -1106,8 +1048,8 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, reinterpret_cast(dest->data)[pixel_idx] = rgba_1010102; break; } - default: - {} + default: { + } // Should be impossible to hit after input validation. } } @@ -1120,9 +1062,9 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, for (int th = 0; th < threads - 1; th++) { workers.push_back(std::thread(applyRecMap)); } - const int rowStep = threads == 1 ? uncompressed_yuv_420_image->height : kJobSzInRows; - for (int rowStart = 0; rowStart < uncompressed_yuv_420_image->height;) { - int rowEnd = std::min(rowStart + rowStep, uncompressed_yuv_420_image->height); + const int rowStep = threads == 1 ? yuv420_image_ptr->height : kJobSzInRows; + for (int rowStart = 0; rowStart < yuv420_image_ptr->height;) { + int rowEnd = std::min(rowStart + rowStep, yuv420_image_ptr->height); jobQueue.enqueueJob(rowStart, rowEnd); rowStart = rowEnd; } @@ -1132,18 +1074,18 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr uncompressed_yuv_420_image, return NO_ERROR; } -status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr compressed_jpegr_image, - jr_compressed_ptr primary_image, - jr_compressed_ptr gain_map) { - if (compressed_jpegr_image == nullptr) { +status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr jpegr_image_ptr, + jr_compressed_ptr primary_jpg_image_ptr, + jr_compressed_ptr gainmap_jpg_image_ptr) { + if (jpegr_image_ptr == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } MessageHandler msg_handler; std::shared_ptr seg = - DataSegment::Create(DataRange(0, compressed_jpegr_image->length), - static_cast(compressed_jpegr_image->data), - DataSegment::BufferDispositionPolicy::kDontDelete); + DataSegment::Create(DataRange(0, jpegr_image_ptr->length), + static_cast(jpegr_image_ptr->data), + DataSegment::BufferDispositionPolicy::kDontDelete); DataSegmentDataSource data_source(seg); JpegInfoBuilder jpeg_info_builder; jpeg_info_builder.SetImageLimit(2); @@ -1162,20 +1104,20 @@ status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr compressed_jpegr return ERROR_JPEGR_INVALID_INPUT_TYPE; } - if (primary_image != nullptr) { - primary_image->data = static_cast(compressed_jpegr_image->data) + - image_ranges[0].GetBegin(); - primary_image->length = image_ranges[0].GetLength(); + if (primary_jpg_image_ptr != nullptr) { + primary_jpg_image_ptr->data = + static_cast(jpegr_image_ptr->data) + image_ranges[0].GetBegin(); + primary_jpg_image_ptr->length = image_ranges[0].GetLength(); } if (image_ranges.size() == 1) { return ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND; } - if (gain_map != nullptr) { - gain_map->data = static_cast(compressed_jpegr_image->data) + - image_ranges[1].GetBegin(); - gain_map->length = image_ranges[1].GetLength(); + if (gainmap_jpg_image_ptr != nullptr) { + gainmap_jpg_image_ptr->data = + static_cast(jpegr_image_ptr->data) + image_ranges[1].GetBegin(); + gainmap_jpg_image_ptr->length = image_ranges[1].GetLength(); } // TODO: choose primary image and gain map image carefully @@ -1220,58 +1162,48 @@ status_t JpegR::extractPrimaryImageAndGainMap(jr_compressed_ptr compressed_jpegr // Exif 2.2 spec for EXIF marker // Adobe XMP spec part 3 for XMP marker // ICC v4.3 spec for ICC -status_t JpegR::appendGainMap(jr_compressed_ptr compressed_jpeg_image, - jr_compressed_ptr compressed_gain_map, - jr_exif_ptr exif, - void* icc, size_t icc_size, - ultrahdr_metadata_ptr metadata, +status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, + jr_compressed_ptr gainmap_jpg_image_ptr, jr_exif_ptr exif, void* icc, + size_t icc_size, ultrahdr_metadata_ptr metadata, jr_compressed_ptr dest) { - if (compressed_jpeg_image == nullptr - || compressed_gain_map == nullptr - || metadata == nullptr - || dest == nullptr) { + if (primary_jpg_image_ptr == nullptr || gainmap_jpg_image_ptr == nullptr || metadata == nullptr || + dest == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } - if (metadata->version.compare("1.0")) { ALOGE("received bad value for version: %s", metadata->version.c_str()); return ERROR_JPEGR_INVALID_INPUT_TYPE; } if (metadata->maxContentBoost < metadata->minContentBoost) { ALOGE("received bad value for content boost min %f, max %f", metadata->minContentBoost, - metadata->maxContentBoost); + metadata->maxContentBoost); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - if (metadata->hdrCapacityMax < metadata->hdrCapacityMin || metadata->hdrCapacityMin < 1.0f) { ALOGE("received bad value for hdr capacity min %f, max %f", metadata->hdrCapacityMin, - metadata->hdrCapacityMax); + metadata->hdrCapacityMax); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - if (metadata->offsetSdr < 0.0f || metadata->offsetHdr < 0.0f) { - ALOGE("received bad value for offset sdr %f, hdr %f", metadata->offsetSdr, - metadata->offsetHdr); + ALOGE("received bad value for offset sdr %f, hdr %f", metadata->offsetSdr, metadata->offsetHdr); return ERROR_JPEGR_INVALID_INPUT_TYPE; } - if (metadata->gamma <= 0.0f) { ALOGE("received bad value for gamma %f", metadata->gamma); return ERROR_JPEGR_INVALID_INPUT_TYPE; } const string nameSpace = "http://ns.adobe.com/xap/1.0/"; - const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator + const int nameSpaceLength = nameSpace.size() + 1; // need to count the null terminator // calculate secondary image length first, because the length will be written into the primary // image xmp const string xmp_secondary = generateXmpForSecondaryImage(*metadata); const int xmp_secondary_length = 2 /* 2 bytes representing the length of the package */ - + nameSpaceLength /* 29 bytes length of name space including \0 */ - + xmp_secondary.size(); /* length of xmp packet */ + + nameSpaceLength /* 29 bytes length of name space including \0 */ + + xmp_secondary.size(); /* length of xmp packet */ const int secondary_image_size = 2 /* 2 bytes length of APP1 sign */ - + xmp_secondary_length - + compressed_gain_map->length; + + xmp_secondary_length + gainmap_jpg_image_ptr->length; // primary image const string xmp_primary = generateXmpForPrimaryImage(secondary_image_size, *metadata); // same as primary @@ -1310,41 +1242,39 @@ status_t JpegR::appendGainMap(jr_compressed_ptr compressed_jpeg_image, // Write ICC if (icc != nullptr && icc_size > 0) { - const int length = icc_size + 2; - const uint8_t lengthH = ((length >> 8) & 0xff); - const uint8_t lengthL = (length & 0xff); - JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos)); - JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP2, 1, pos)); - JPEGR_CHECK(Write(dest, &lengthH, 1, pos)); - JPEGR_CHECK(Write(dest, &lengthL, 1, pos)); - JPEGR_CHECK(Write(dest, icc, icc_size, pos)); + const int length = icc_size + 2; + const uint8_t lengthH = ((length >> 8) & 0xff); + const uint8_t lengthL = (length & 0xff); + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos)); + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP2, 1, pos)); + JPEGR_CHECK(Write(dest, &lengthH, 1, pos)); + JPEGR_CHECK(Write(dest, &lengthL, 1, pos)); + JPEGR_CHECK(Write(dest, icc, icc_size, pos)); } // Prepare and write MPF { - const int length = 2 + calculateMpfSize(); - const uint8_t lengthH = ((length >> 8) & 0xff); - const uint8_t lengthL = (length & 0xff); - int primary_image_size = pos + length + compressed_jpeg_image->length; - // between APP2 + package size + signature - // ff e2 00 58 4d 50 46 00 - // 2 + 2 + 4 = 8 (bytes) - // and ff d8 sign of the secondary image - int secondary_image_offset = primary_image_size - pos - 8; - sp mpf = generateMpf(primary_image_size, - 0, /* primary_image_offset */ - secondary_image_size, - secondary_image_offset); - JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos)); - JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP2, 1, pos)); - JPEGR_CHECK(Write(dest, &lengthH, 1, pos)); - JPEGR_CHECK(Write(dest, &lengthL, 1, pos)); - JPEGR_CHECK(Write(dest, (void*)mpf->getData(), mpf->getLength(), pos)); + const int length = 2 + calculateMpfSize(); + const uint8_t lengthH = ((length >> 8) & 0xff); + const uint8_t lengthL = (length & 0xff); + int primary_image_size = pos + length + primary_jpg_image_ptr->length; + // between APP2 + package size + signature + // ff e2 00 58 4d 50 46 00 + // 2 + 2 + 4 = 8 (bytes) + // and ff d8 sign of the secondary image + int secondary_image_offset = primary_image_size - pos - 8; + sp mpf = generateMpf(primary_image_size, 0, /* primary_image_offset */ + secondary_image_size, secondary_image_offset); + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kStart, 1, pos)); + JPEGR_CHECK(Write(dest, &photos_editing_formats::image_io::JpegMarker::kAPP2, 1, pos)); + JPEGR_CHECK(Write(dest, &lengthH, 1, pos)); + JPEGR_CHECK(Write(dest, &lengthL, 1, pos)); + JPEGR_CHECK(Write(dest, (void*)mpf->getData(), mpf->getLength(), pos)); } // Write primary image - JPEGR_CHECK(Write(dest, - (uint8_t*)compressed_jpeg_image->data + 2, compressed_jpeg_image->length - 2, pos)); + JPEGR_CHECK(Write(dest, (uint8_t*)primary_jpg_image_ptr->data + 2, + primary_jpg_image_ptr->length - 2, pos)); // Finish primary image // Begin secondary image (gain map) @@ -1366,8 +1296,8 @@ status_t JpegR::appendGainMap(jr_compressed_ptr compressed_jpeg_image, } // Write secondary image - JPEGR_CHECK(Write(dest, - (uint8_t*)compressed_gain_map->data + 2, compressed_gain_map->length - 2, pos)); + JPEGR_CHECK(Write(dest, (uint8_t*)gainmap_jpg_image_ptr->data + 2, + gainmap_jpg_image_ptr->length - 2, pos)); // Set back length dest->length = pos; @@ -1380,62 +1310,44 @@ status_t JpegR::toneMap(jr_uncompressed_ptr src, jr_uncompressed_ptr dest) { if (src == nullptr || dest == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } - - uint16_t* src_luma_data = reinterpret_cast(src->data); - size_t src_luma_stride = src->luma_stride == 0 ? src->width : src->luma_stride; - - uint16_t* src_chroma_data; - size_t src_chroma_stride; - if (src->chroma_data == nullptr) { - src_chroma_stride = src_luma_stride; - src_chroma_data = &reinterpret_cast(src->data)[src_luma_stride * src->height]; - } else { - src_chroma_stride = src->chroma_stride; - src_chroma_data = reinterpret_cast(src->chroma_data); + if (src->width != dest->width || src->height != dest->height) { + return ERROR_JPEGR_INVALID_INPUT_TYPE; } - dest->width = src->width; - dest->height = src->height; - - size_t dest_luma_pixel_count = dest->width * dest->height; - + uint16_t* src_y_data = reinterpret_cast(src->data); + uint16_t* src_uv_data = reinterpret_cast(src->chroma_data); + uint8_t* dst_y_data = reinterpret_cast(dest->data); + uint8_t* dst_u_data = reinterpret_cast(dest->chroma_data); + size_t v_offset = (dest->chroma_stride * dest->height / 2); + uint8_t* dst_v_data = dst_u_data + v_offset; for (size_t y = 0; y < src->height; ++y) { for (size_t x = 0; x < src->width; ++x) { - size_t src_y_idx = y * src_luma_stride + x; - size_t src_u_idx = (y >> 1) * src_chroma_stride + (x & ~0x1); + size_t src_y_idx = y * src->luma_stride + x; + size_t src_u_idx = (y >> 1) * src->chroma_stride + (x & ~0x1); size_t src_v_idx = src_u_idx + 1; - uint16_t y_uint = src_luma_data[src_y_idx] >> 6; - uint16_t u_uint = src_chroma_data[src_u_idx] >> 6; - uint16_t v_uint = src_chroma_data[src_v_idx] >> 6; + uint16_t y_uint = src_y_data[src_y_idx] >> 6; + uint16_t u_uint = src_uv_data[src_u_idx] >> 6; + uint16_t v_uint = src_uv_data[src_v_idx] >> 6; - size_t dest_y_idx = x + y * dest->width; - size_t dest_uv_idx = x / 2 + (y / 2) * (dest->width / 2); + size_t dest_y_idx = x + y * dest->luma_stride; + size_t dest_chroma_idx = (x / 2) + (y / 2) * (dest->chroma_stride); - uint8_t* y = &reinterpret_cast(dest->data)[dest_y_idx]; - uint8_t* u = &reinterpret_cast(dest->data)[dest_luma_pixel_count + dest_uv_idx]; - uint8_t* v = &reinterpret_cast( - dest->data)[dest_luma_pixel_count * 5 / 4 + dest_uv_idx]; - - *y = static_cast((y_uint >> 2) & 0xff); - *u = static_cast((u_uint >> 2) & 0xff); - *v = static_cast((v_uint >> 2) & 0xff); + dst_y_data[dest_y_idx] = static_cast((y_uint >> 2) & 0xff); + dst_u_data[dest_chroma_idx] = static_cast((u_uint >> 2) & 0xff); + dst_v_data[dest_chroma_idx] = static_cast((v_uint >> 2) & 0xff); } } - dest->colorGamut = src->colorGamut; - return NO_ERROR; } -status_t JpegR::convertYuv(jr_uncompressed_ptr image, - ultrahdr_color_gamut src_encoding, +status_t JpegR::convertYuv(jr_uncompressed_ptr image, ultrahdr_color_gamut src_encoding, ultrahdr_color_gamut dest_encoding) { if (image == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } - - if (src_encoding == ULTRAHDR_COLORGAMUT_UNSPECIFIED - || dest_encoding == ULTRAHDR_COLORGAMUT_UNSPECIFIED) { + if (src_encoding == ULTRAHDR_COLORGAMUT_UNSPECIFIED || + dest_encoding == ULTRAHDR_COLORGAMUT_UNSPECIFIED) { return ERROR_JPEGR_INVALID_COLORGAMUT; } diff --git a/libs/ultrahdr/tests/gainmapmath_test.cpp b/libs/ultrahdr/tests/gainmapmath_test.cpp index af90365e56..69cd36cd46 100644 --- a/libs/ultrahdr/tests/gainmapmath_test.cpp +++ b/libs/ultrahdr/tests/gainmapmath_test.cpp @@ -625,7 +625,7 @@ TEST_F(GainMapMathTest, Bt2100ToBt601YuvConversion) { EXPECT_YUV_NEAR(yuv2100To601(yuv_b), P3YuvBlue()); } -TEST_F(GainMapMathTest, TransformYuv420) { +TEST_F(GainMapMathTest, DISABLED_TransformYuv420) { ColorTransformFn transforms[] = { yuv709To601, yuv709To2100, yuv601To709, yuv601To2100, yuv2100To709, yuv2100To601 }; for (const ColorTransformFn& transform : transforms) { @@ -1042,7 +1042,7 @@ TEST_F(GainMapMathTest, ApplyGain) { applyGain(e, 1.0f, &metadata, displayBoost)); } -TEST_F(GainMapMathTest, GetYuv420Pixel) { +TEST_F(GainMapMathTest, DISABLED_GetYuv420Pixel) { jpegr_uncompressed_struct image = Yuv420Image(); Color (*colors)[4] = Yuv420Colors(); @@ -1053,7 +1053,7 @@ TEST_F(GainMapMathTest, GetYuv420Pixel) { } } -TEST_F(GainMapMathTest, GetP010Pixel) { +TEST_F(GainMapMathTest, DISABLED_GetP010Pixel) { jpegr_uncompressed_struct image = P010Image(); Color (*colors)[4] = P010Colors(); @@ -1064,7 +1064,7 @@ TEST_F(GainMapMathTest, GetP010Pixel) { } } -TEST_F(GainMapMathTest, SampleYuv420) { +TEST_F(GainMapMathTest, DISABLED_SampleYuv420) { jpegr_uncompressed_struct image = Yuv420Image(); Color (*colors)[4] = Yuv420Colors(); @@ -1090,7 +1090,7 @@ TEST_F(GainMapMathTest, SampleYuv420) { } } -TEST_F(GainMapMathTest, SampleP010) { +TEST_F(GainMapMathTest, DISABLED_SampleP010) { jpegr_uncompressed_struct image = P010Image(); Color (*colors)[4] = P010Colors(); diff --git a/libs/ultrahdr/tests/jpegr_test.cpp b/libs/ultrahdr/tests/jpegr_test.cpp index e8e5883573..e69c50964a 100644 --- a/libs/ultrahdr/tests/jpegr_test.cpp +++ b/libs/ultrahdr/tests/jpegr_test.cpp @@ -1966,7 +1966,7 @@ void JpegRBenchmark::BenchmarkApplyGainMap(jr_uncompressed_ptr yuv420Image, jr_u profileRecMap.elapsedTime() / (kProfileCount * 1000.f)); } -TEST(JpegRTest, ProfileGainMapFuncs) { +TEST(JpegRTest, DISABLED_ProfileGainMapFuncs) { UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010); ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); ASSERT_TRUE(rawImgP010.allocateMemory()); -- GitLab From 2aea00b81119465788a0526bd07ebf389ea7a25f Mon Sep 17 00:00:00 2001 From: Martin Stjernholm Date: Wed, 2 Aug 2023 17:44:43 +0100 Subject: [PATCH 0403/1187] Ensure dex2oat is run with background priority for OTA dexopt. This makes us query `dalvik.vm.background-dex2oat-cpu-set` and `dalvik.vm.background-dex2oat-threads` for those runs. A test run shows that `DEXOPT_BOOTCOMPLETE` is propagated from `OtaDexoptService`, but set it anyway to be certain. Test: Apply OTA and check that `boot_complete` and `background_job_compile` get set in `android::installd::dexopt`. Bug: 237017087 Change-Id: I48627dd062fb6155c826d48b7caefeec36f0cfff --- cmds/installd/otapreopt.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index 7cabdb09e1..407cb244e3 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -471,13 +471,18 @@ private: // TODO(calin): embed the profile name in the parameters. int Dexopt() { std::string error; + + int dexopt_flags = parameters_.dexopt_flags; + // Make sure dex2oat is run with background priority. + dexopt_flags |= DEXOPT_BOOTCOMPLETE | DEXOPT_IDLE_BACKGROUND_JOB; + int res = dexopt(parameters_.apk_path, parameters_.uid, parameters_.pkgName, parameters_.instruction_set, parameters_.dexopt_needed, parameters_.oat_dir, - parameters_.dexopt_flags, + dexopt_flags, parameters_.compiler_filter, parameters_.volume_uuid, parameters_.shared_libraries, -- GitLab From 877d087af7ad0a435b27d36068bd0d0162a91f45 Mon Sep 17 00:00:00 2001 From: Martin Stjernholm Date: Wed, 2 Aug 2023 17:54:27 +0100 Subject: [PATCH 0404/1187] Remove 1s sleep between each package in the A/B OTA postinstall dexopt process. This sleep makes OTA dexopt runs take significantly longer, but even so it's not sufficient to avoid jank (cf. b/237017087). If this process takes too much resources then it can be tuned through the `OtaProfiles` task profile, `dalvik.vm.background-dex2oat-cpu-set` and/or `dalvik.vm.background-dex2oat-threads`. It's also possible to cut down the work done before the OTA reboot with `MAXIMUM_PACKAGES`. Test: Manual OTA update Bug: 199756868 Bug: 237017087 Change-Id: Id2b460a99da19d42238d3aa0165c1792fe303398 --- cmds/installd/otapreopt_script.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh index db5c34edc2..e483d54a2a 100644 --- a/cmds/installd/otapreopt_script.sh +++ b/cmds/installd/otapreopt_script.sh @@ -72,7 +72,6 @@ while ((i Date: Wed, 2 Aug 2023 22:45:48 +0530 Subject: [PATCH 0405/1187] ultrahdr: minor fixes in encoder and decoder fuzzer - Moved declarations to header so that fuzzer app can make use of it. - Fixed alloc, initializations in fuzzer applications Bug: 294218453 Test: ./ultrahdr_enc_fuzzer Change-Id: I058200caca57a8f7fe0087f9511d19857a4abef4 --- libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp | 2 +- libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp index ad1d57aaee..f1f403548d 100644 --- a/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp +++ b/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp @@ -54,7 +54,7 @@ void UltraHdrDecFuzzer::process() { std::cout << "input buffer size " << jpegImgR.length << std::endl; std::cout << "image dimensions " << info.width << " x " << info.width << std::endl; #endif - size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_SDR) ? 4 : 8); + size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_HDR_LINEAR) ? 8 : 4); jpegr_uncompressed_struct decodedJpegR; auto decodedRaw = std::make_unique(outSize); decodedJpegR.data = decodedRaw.get(); diff --git a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp index 1dce57c7c5..5d6242cb56 100644 --- a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp +++ b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp @@ -60,11 +60,12 @@ void UltraHdrEncFuzzer::fillP010Buffer(uint16_t* data, int width, int height, in uint16_t* tmp = data; std::vector buffer(16); for (int i = 0; i < buffer.size(); i++) { - buffer[i] = mFdp.ConsumeIntegralInRange(0, (1 << 10) - 1); + buffer[i] = (mFdp.ConsumeIntegralInRange(0, (1 << 10) - 1)) << 6; } for (int j = 0; j < height; j++) { for (int i = 0; i < width; i += buffer.size()) { - memcpy(data + i, buffer.data(), std::min((int)buffer.size(), (width - i))); + memcpy(tmp + i, buffer.data(), + std::min((int)buffer.size(), (width - i)) * sizeof(*data)); std::shuffle(buffer.begin(), buffer.end(), std::default_random_engine(std::random_device{}())); } @@ -264,7 +265,8 @@ void UltraHdrEncFuzzer::process() { jpegr_info_struct info{0, 0, &iccData, &exifData}; status = jpegHdr.getJPEGRInfo(&jpegImgR, &info); if (status == android::OK) { - size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_SDR) ? 4 : 8); + size_t outSize = + info.width * info.height * ((of == ULTRAHDR_OUTPUT_HDR_LINEAR) ? 8 : 4); jpegr_uncompressed_struct decodedJpegR; auto decodedRaw = std::make_unique(outSize); decodedJpegR.data = decodedRaw.get(); -- GitLab From 88c57a25cf91b6a69848940a36d9303b929c8837 Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Mon, 24 Jul 2023 16:04:46 +0530 Subject: [PATCH 0406/1187] ultrahdr: correct offset used during look ups The offset that is used during look ups, has a bias. This is corrected. Bug: 294199334 Test: ./libultrahdr_test Change-Id: Ib8f5fbefd93a6d9afaa5db3f845746becd0fcce1 --- libs/ultrahdr/gainmapmath.cpp | 10 +++++----- libs/ultrahdr/include/ultrahdr/gainmapmath.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/ultrahdr/gainmapmath.cpp b/libs/ultrahdr/gainmapmath.cpp index e1c5085b14..ae9c4ca338 100644 --- a/libs/ultrahdr/gainmapmath.cpp +++ b/libs/ultrahdr/gainmapmath.cpp @@ -168,7 +168,7 @@ Color srgbInvOetf(Color e_gamma) { // See IEC 61966-2-1, Equations F.5 and F.6. float srgbInvOetfLUT(float e_gamma) { - uint32_t value = static_cast(e_gamma * kSrgbInvOETFNumEntries); + uint32_t value = static_cast(e_gamma * (kSrgbInvOETFNumEntries - 1) + 0.5); //TODO() : Remove once conversion modules have appropriate clamping in place value = CLIP3(value, 0, kSrgbInvOETFNumEntries - 1); return kSrgbInvOETF[value]; @@ -288,7 +288,7 @@ Color hlgOetf(Color e) { } float hlgOetfLUT(float e) { - uint32_t value = static_cast(e * kHlgOETFNumEntries); + uint32_t value = static_cast(e * (kHlgOETFNumEntries - 1) + 0.5); //TODO() : Remove once conversion modules have appropriate clamping in place value = CLIP3(value, 0, kHlgOETFNumEntries - 1); @@ -315,7 +315,7 @@ Color hlgInvOetf(Color e_gamma) { } float hlgInvOetfLUT(float e_gamma) { - uint32_t value = static_cast(e_gamma * kHlgInvOETFNumEntries); + uint32_t value = static_cast(e_gamma * (kHlgInvOETFNumEntries - 1) + 0.5); //TODO() : Remove once conversion modules have appropriate clamping in place value = CLIP3(value, 0, kHlgInvOETFNumEntries - 1); @@ -344,7 +344,7 @@ Color pqOetf(Color e) { } float pqOetfLUT(float e) { - uint32_t value = static_cast(e * kPqOETFNumEntries); + uint32_t value = static_cast(e * (kPqOETFNumEntries - 1) + 0.5); //TODO() : Remove once conversion modules have appropriate clamping in place value = CLIP3(value, 0, kPqOETFNumEntries - 1); @@ -376,7 +376,7 @@ Color pqInvOetf(Color e_gamma) { } float pqInvOetfLUT(float e_gamma) { - uint32_t value = static_cast(e_gamma * kPqInvOETFNumEntries); + uint32_t value = static_cast(e_gamma * (kPqInvOETFNumEntries - 1) + 0.5); //TODO() : Remove once conversion modules have appropriate clamping in place value = CLIP3(value, 0, kPqInvOETFNumEntries - 1); diff --git a/libs/ultrahdr/include/ultrahdr/gainmapmath.h b/libs/ultrahdr/include/ultrahdr/gainmapmath.h index 50b4d2fab1..9f1238f718 100644 --- a/libs/ultrahdr/include/ultrahdr/gainmapmath.h +++ b/libs/ultrahdr/include/ultrahdr/gainmapmath.h @@ -172,7 +172,7 @@ struct GainLUT { } float getGainFactor(float gain) { - uint32_t idx = static_cast(gain * (kGainFactorNumEntries - 1)); + uint32_t idx = static_cast(gain * (kGainFactorNumEntries - 1) + 0.5); //TODO() : Remove once conversion modules have appropriate clamping in place idx = CLIP3(idx, 0, kGainFactorNumEntries - 1); return mGainTable[idx]; -- GitLab From eca8194f745da58ad96eaabeb21b16da8c39dc31 Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Sat, 29 Jul 2023 14:41:48 +0530 Subject: [PATCH 0407/1187] ultrahdr: update jpegencoderhelper to accept uncompressed struct fields With this change we can now pass luma/chroma ptrs and stride information to jpegencoderhelper class during compression. This by passes intermediate copy whenever possible Also updated fuzzer to incorporate 420 stride support updated jpegr unit tests for more combinations of gamuts and unusual strides Bug: 294218453 Test: ./ultrahdr_unit_test Test: ./ultrahdr_enc_fuzzer Change-Id: Ic50dd34b0c680618e73e0cb27f554b9bf8272e8f --- libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp | 116 +++++++++++------ .../include/ultrahdr/jpegencoderhelper.h | 21 ++-- libs/ultrahdr/jpegencoderhelper.cpp | 73 +++++------ libs/ultrahdr/jpegr.cpp | 109 ++++++++++------ libs/ultrahdr/tests/gainmapmath_test.cpp | 17 +-- .../ultrahdr/tests/jpegencoderhelper_test.cpp | 25 ++-- libs/ultrahdr/tests/jpegr_test.cpp | 118 ++++++++++++------ 7 files changed, 298 insertions(+), 181 deletions(-) diff --git a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp index 5d6242cb56..bf9b0318bd 100644 --- a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp +++ b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp @@ -23,8 +23,8 @@ // User include files #include "ultrahdr/gainmapmath.h" -#include "ultrahdr/jpegencoderhelper.h" #include "ultrahdr/jpegdecoderhelper.h" +#include "ultrahdr/jpegencoderhelper.h" #include "utils/Log.h" using namespace android::ultrahdr; @@ -50,7 +50,7 @@ public: UltraHdrEncFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; void process(); void fillP010Buffer(uint16_t* data, int width, int height, int stride); - void fill420Buffer(uint8_t* data, int size); + void fill420Buffer(uint8_t* data, int width, int height, int stride); private: FuzzedDataProvider mFdp; @@ -73,13 +73,18 @@ void UltraHdrEncFuzzer::fillP010Buffer(uint16_t* data, int width, int height, in } } -void UltraHdrEncFuzzer::fill420Buffer(uint8_t* data, int size) { +void UltraHdrEncFuzzer::fill420Buffer(uint8_t* data, int width, int height, int stride) { + uint8_t* tmp = data; std::vector buffer(16); mFdp.ConsumeData(buffer.data(), buffer.size()); - for (int i = 0; i < size; i += buffer.size()) { - memcpy(data + i, buffer.data(), std::min((int)buffer.size(), (size - i))); - std::shuffle(buffer.begin(), buffer.end(), - std::default_random_engine(std::random_device{}())); + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i += buffer.size()) { + memcpy(tmp + i, buffer.data(), + std::min((int)buffer.size(), (width - i)) * sizeof(*data)); + std::shuffle(buffer.begin(), buffer.end(), + std::default_random_engine(std::random_device{}())); + } + tmp += stride; } } @@ -120,9 +125,10 @@ void UltraHdrEncFuzzer::process() { int height = mFdp.ConsumeIntegralInRange(kMinHeight, kMaxHeight); height = (height >> 1) << 1; - std::unique_ptr bufferY = nullptr; - std::unique_ptr bufferUV = nullptr; - std::unique_ptr yuv420ImgRaw = nullptr; + std::unique_ptr bufferYHdr = nullptr; + std::unique_ptr bufferUVHdr = nullptr; + std::unique_ptr bufferYSdr = nullptr; + std::unique_ptr bufferUVSdr = nullptr; std::unique_ptr grayImgRaw = nullptr; if (muxSwitch != 4) { // init p010 image @@ -136,30 +142,29 @@ void UltraHdrEncFuzzer::process() { int bppP010 = 2; if (isUVContiguous) { size_t p010Size = yStride * height * 3 / 2; - bufferY = std::make_unique(p010Size); - p010Img.data = bufferY.get(); + bufferYHdr = std::make_unique(p010Size); + p010Img.data = bufferYHdr.get(); p010Img.chroma_data = nullptr; p010Img.chroma_stride = 0; - fillP010Buffer(bufferY.get(), width, height, yStride); - fillP010Buffer(bufferY.get() + yStride * height, width, height / 2, yStride); + fillP010Buffer(bufferYHdr.get(), width, height, yStride); + fillP010Buffer(bufferYHdr.get() + yStride * height, width, height / 2, yStride); } else { int uvStride = mFdp.ConsumeIntegralInRange(width, width + 128); size_t p010YSize = yStride * height; - bufferY = std::make_unique(p010YSize); - p010Img.data = bufferY.get(); - fillP010Buffer(bufferY.get(), width, height, yStride); + bufferYHdr = std::make_unique(p010YSize); + p010Img.data = bufferYHdr.get(); + fillP010Buffer(bufferYHdr.get(), width, height, yStride); size_t p010UVSize = uvStride * p010Img.height / 2; - bufferUV = std::make_unique(p010UVSize); - p010Img.chroma_data = bufferUV.get(); + bufferUVHdr = std::make_unique(p010UVSize); + p010Img.chroma_data = bufferUVHdr.get(); p010Img.chroma_stride = uvStride; - fillP010Buffer(bufferUV.get(), width, height / 2, uvStride); + fillP010Buffer(bufferUVHdr.get(), width, height / 2, uvStride); } } else { - int map_width = width / kMapDimensionScaleFactor; - int map_height = height / kMapDimensionScaleFactor; - map_width = static_cast(floor((map_width + kJpegBlock - 1) / kJpegBlock)) * - kJpegBlock; - map_height = ((map_height + 1) >> 1) << 1; + size_t map_width = static_cast( + floor((width + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); + size_t map_height = static_cast( + floor((height + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); // init 400 image grayImg.width = map_width; grayImg.height = map_height; @@ -168,7 +173,7 @@ void UltraHdrEncFuzzer::process() { const size_t graySize = map_width * map_height; grayImgRaw = std::make_unique(graySize); grayImg.data = grayImgRaw.get(); - fill420Buffer(grayImgRaw.get(), graySize); + fill420Buffer(grayImgRaw.get(), map_width, map_height, map_width); grayImg.chroma_data = nullptr; grayImg.luma_stride = 0; grayImg.chroma_stride = 0; @@ -176,17 +181,38 @@ void UltraHdrEncFuzzer::process() { if (muxSwitch > 0) { // init 420 image + bool isUVContiguous = mFdp.ConsumeBool(); + bool hasYStride = mFdp.ConsumeBool(); + int yStride = hasYStride ? mFdp.ConsumeIntegralInRange(width, width + 128) : width; yuv420Img.width = width; yuv420Img.height = height; yuv420Img.colorGamut = yuv420Cg; - - const size_t yuv420Size = (yuv420Img.width * yuv420Img.height * 3) / 2; - yuv420ImgRaw = std::make_unique(yuv420Size); - yuv420Img.data = yuv420ImgRaw.get(); - fill420Buffer(yuv420ImgRaw.get(), yuv420Size); - yuv420Img.chroma_data = nullptr; - yuv420Img.luma_stride = 0; - yuv420Img.chroma_stride = 0; + yuv420Img.luma_stride = hasYStride ? yStride : 0; + if (isUVContiguous) { + size_t yuv420Size = yStride * height * 3 / 2; + bufferYSdr = std::make_unique(yuv420Size); + yuv420Img.data = bufferYSdr.get(); + yuv420Img.chroma_data = nullptr; + yuv420Img.chroma_stride = 0; + fill420Buffer(bufferYSdr.get(), width, height, yStride); + fill420Buffer(bufferYSdr.get() + yStride * height, width / 2, height / 2, + yStride / 2); + fill420Buffer(bufferYSdr.get() + yStride * height * 5 / 4, width / 2, height / 2, + yStride / 2); + } else { + int uvStride = mFdp.ConsumeIntegralInRange(width / 2, width / 2 + 128); + size_t yuv420YSize = yStride * height; + bufferYSdr = std::make_unique(yuv420YSize); + yuv420Img.data = bufferYSdr.get(); + fill420Buffer(bufferYSdr.get(), width, height, yStride); + size_t yuv420UVSize = uvStride * yuv420Img.height / 2 * 2; + bufferUVSdr = std::make_unique(yuv420UVSize); + yuv420Img.chroma_data = bufferYSdr.get(); + yuv420Img.chroma_stride = uvStride; + fill420Buffer(bufferUVSdr.get(), width / 2, height / 2, uvStride); + fill420Buffer(bufferUVSdr.get() + uvStride * height / 2, width / 2, height / 2, + uvStride); + } } // dest @@ -203,6 +229,8 @@ void UltraHdrEncFuzzer::process() { std::cout << "p010 luma stride " << p010Img.luma_stride << std::endl; std::cout << "p010 chroma stride " << p010Img.chroma_stride << std::endl; std::cout << "420 color gamut " << yuv420Img.colorGamut << std::endl; + std::cout << "420 luma stride " << yuv420Img.luma_stride << std::endl; + std::cout << "420 chroma stride " << yuv420Img.chroma_stride << std::endl; std::cout << "quality factor " << quality << std::endl; #endif @@ -217,8 +245,19 @@ void UltraHdrEncFuzzer::process() { } else { // compressed img JpegEncoderHelper encoder; - if (encoder.compressImage(yuv420Img.data, yuv420Img.width, yuv420Img.height, quality, - nullptr, 0)) { + struct jpegr_uncompressed_struct yuv420ImgCopy = yuv420Img; + if (yuv420ImgCopy.luma_stride == 0) yuv420ImgCopy.luma_stride = yuv420Img.width; + if (!yuv420ImgCopy.chroma_data) { + uint8_t* data = reinterpret_cast(yuv420Img.data); + yuv420ImgCopy.chroma_data = data + yuv420Img.luma_stride * yuv420Img.height; + yuv420ImgCopy.chroma_stride = yuv420Img.luma_stride >> 1; + } + + if (encoder.compressImage(reinterpret_cast(yuv420ImgCopy.data), + reinterpret_cast(yuv420ImgCopy.chroma_data), + yuv420ImgCopy.width, yuv420ImgCopy.height, + yuv420ImgCopy.luma_stride, yuv420ImgCopy.chroma_stride, + quality, nullptr, 0)) { jpegImg.length = encoder.getCompressedImageSize(); jpegImg.maxLength = jpegImg.length; jpegImg.data = encoder.getCompressedImagePtr(); @@ -233,8 +272,9 @@ void UltraHdrEncFuzzer::process() { } else if (muxSwitch == 4) { // api 4 jpegImgR.length = 0; JpegEncoderHelper gainMapEncoder; - if (gainMapEncoder.compressImage(grayImg.data, grayImg.width, grayImg.height, - quality, nullptr, 0, true)) { + if (gainMapEncoder.compressImage(reinterpret_cast(grayImg.data), + nullptr, grayImg.width, grayImg.height, + grayImg.width, 0, quality, nullptr, 0)) { jpegGainMap.length = gainMapEncoder.getCompressedImageSize(); jpegGainMap.maxLength = jpegImg.length; jpegGainMap.data = gainMapEncoder.getCompressedImagePtr(); diff --git a/libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h b/libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h index 2c6778e299..9d06415cb3 100644 --- a/libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h +++ b/libs/ultrahdr/include/ultrahdr/jpegencoderhelper.h @@ -19,6 +19,7 @@ // We must include cstdio before jpeglib.h. It is a requirement of libjpeg. #include +#include extern "C" { #include @@ -26,10 +27,11 @@ extern "C" { } #include -#include namespace android::ultrahdr { +#define ALIGNM(x, m) ((((x) + ((m)-1)) / (m)) * (m)) + /* * Encapsulates a converter from raw image (YUV420planer or grey-scale) to JPEG format. * This class is not thread-safe. @@ -46,8 +48,9 @@ public: * ICC segment which will be added to the compressed image. * Returns false if errors occur during compression. */ - bool compressImage(const void* image, int width, int height, int quality, - const void* iccBuffer, unsigned int iccSize, bool isSingleChannel = false); + bool compressImage(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width, int height, + int lumaStride, int chromaStride, int quality, const void* iccBuffer, + unsigned int iccSize); /* * Returns the compressed JPEG buffer pointer. This method must be called only after calling @@ -66,6 +69,7 @@ public: * We must pass at least 16 scanlines according to libjpeg documentation. */ static const int kCompressBatchSize = 16; + private: // initDestination(), emptyOutputBuffer() and emptyOutputBuffer() are callback functions to be // passed into jpeg library. @@ -75,15 +79,16 @@ private: static void outputErrorMessage(j_common_ptr cinfo); // Returns false if errors occur. - bool encode(const void* inYuv, int width, int height, int jpegQuality, - const void* iccBuffer, unsigned int iccSize, bool isSingleChannel); + bool encode(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width, int height, + int lumaStride, int chromaStride, int quality, const void* iccBuffer, + unsigned int iccSize); void setJpegDestination(jpeg_compress_struct* cinfo); void setJpegCompressStruct(int width, int height, int quality, jpeg_compress_struct* cinfo, bool isSingleChannel); // Returns false if errors occur. - bool compress(jpeg_compress_struct* cinfo, const uint8_t* image, bool isSingleChannel); - bool compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yuv); - bool compressSingleChannel(jpeg_compress_struct* cinfo, const uint8_t* image); + bool compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yBuffer, const uint8_t* uvBuffer, + int lumaStride, int chromaStride); + bool compressY(jpeg_compress_struct* cinfo, const uint8_t* yBuffer, int lumaStride); // The block size for encoded jpeg image buffer. static const int kBlockSize = 16384; diff --git a/libs/ultrahdr/jpegencoderhelper.cpp b/libs/ultrahdr/jpegencoderhelper.cpp index 9394a83e46..13ae7424d5 100644 --- a/libs/ultrahdr/jpegencoderhelper.cpp +++ b/libs/ultrahdr/jpegencoderhelper.cpp @@ -23,8 +23,6 @@ namespace android::ultrahdr { -#define ALIGNM(x, m) ((((x) + ((m)-1)) / (m)) * (m)) - // The destination manager that can access |mResultBuffer| in JpegEncoderHelper. struct destination_mgr { struct jpeg_destination_mgr mgr; @@ -35,11 +33,12 @@ JpegEncoderHelper::JpegEncoderHelper() {} JpegEncoderHelper::~JpegEncoderHelper() {} -bool JpegEncoderHelper::compressImage(const void* image, int width, int height, int quality, - const void* iccBuffer, unsigned int iccSize, - bool isSingleChannel) { +bool JpegEncoderHelper::compressImage(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width, + int height, int lumaStride, int chromaStride, int quality, + const void* iccBuffer, unsigned int iccSize) { mResultBuffer.clear(); - if (!encode(image, width, height, quality, iccBuffer, iccSize, isSingleChannel)) { + if (!encode(yBuffer, uvBuffer, width, height, lumaStride, chromaStride, quality, iccBuffer, + iccSize)) { return false; } ALOGI("Compressed JPEG: %d[%dx%d] -> %zu bytes", (width * height * 12) / 8, width, height, @@ -87,25 +86,24 @@ void JpegEncoderHelper::outputErrorMessage(j_common_ptr cinfo) { ALOGE("%s\n", buffer); } -bool JpegEncoderHelper::encode(const void* image, int width, int height, int jpegQuality, - const void* iccBuffer, unsigned int iccSize, bool isSingleChannel) { +bool JpegEncoderHelper::encode(const uint8_t* yBuffer, const uint8_t* uvBuffer, int width, + int height, int lumaStride, int chromaStride, int quality, + const void* iccBuffer, unsigned int iccSize) { jpeg_compress_struct cinfo; jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); - // Override output_message() to print error log with ALOGE(). cinfo.err->output_message = &outputErrorMessage; jpeg_create_compress(&cinfo); setJpegDestination(&cinfo); - - setJpegCompressStruct(width, height, jpegQuality, &cinfo, isSingleChannel); + setJpegCompressStruct(width, height, quality, &cinfo, uvBuffer == nullptr); jpeg_start_compress(&cinfo, TRUE); - if (iccBuffer != nullptr && iccSize > 0) { jpeg_write_marker(&cinfo, JPEG_APP0 + 2, static_cast(iccBuffer), iccSize); } - - bool status = compress(&cinfo, static_cast(image), isSingleChannel); + bool status = cinfo.num_components == 1 + ? compressY(&cinfo, yBuffer, lumaStride) + : compressYuv(&cinfo, yBuffer, uvBuffer, lumaStride, chromaStride); jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); @@ -141,27 +139,23 @@ void JpegEncoderHelper::setJpegCompressStruct(int width, int height, int quality } } -bool JpegEncoderHelper::compress(jpeg_compress_struct* cinfo, const uint8_t* image, - bool isSingleChannel) { - return isSingleChannel ? compressSingleChannel(cinfo, image) : compressYuv(cinfo, image); -} - -bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yuv) { +bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yBuffer, + const uint8_t* uvBuffer, int lumaStride, int chromaStride) { JSAMPROW y[kCompressBatchSize]; JSAMPROW cb[kCompressBatchSize / 2]; JSAMPROW cr[kCompressBatchSize / 2]; JSAMPARRAY planes[3]{y, cb, cr}; - size_t y_plane_size = cinfo->image_width * cinfo->image_height; - size_t uv_plane_size = y_plane_size / 4; - uint8_t* y_plane = const_cast(yuv); - uint8_t* u_plane = const_cast(yuv + y_plane_size); - uint8_t* v_plane = const_cast(yuv + y_plane_size + uv_plane_size); + size_t y_plane_size = lumaStride * cinfo->image_height; + size_t u_plane_size = chromaStride * cinfo->image_height / 2; + uint8_t* y_plane = const_cast(yBuffer); + uint8_t* u_plane = const_cast(uvBuffer); + uint8_t* v_plane = const_cast(u_plane + u_plane_size); std::unique_ptr empty = std::make_unique(cinfo->image_width); memset(empty.get(), 0, cinfo->image_width); const int aligned_width = ALIGNM(cinfo->image_width, kCompressBatchSize); - const bool is_width_aligned = (aligned_width == cinfo->image_width); + const bool need_padding = (lumaStride < aligned_width); std::unique_ptr buffer_intrm = nullptr; uint8_t* y_plane_intrm = nullptr; uint8_t* u_plane_intrm = nullptr; @@ -170,7 +164,7 @@ bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* JSAMPROW cb_intrm[kCompressBatchSize / 2]; JSAMPROW cr_intrm[kCompressBatchSize / 2]; JSAMPARRAY planes_intrm[3]{y_intrm, cb_intrm, cr_intrm}; - if (!is_width_aligned) { + if (need_padding) { size_t mcu_row_size = aligned_width * kCompressBatchSize * 3 / 2; buffer_intrm = std::make_unique(mcu_row_size); y_plane_intrm = buffer_intrm.get(); @@ -195,11 +189,11 @@ bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* for (int i = 0; i < kCompressBatchSize; ++i) { size_t scanline = cinfo->next_scanline + i; if (scanline < cinfo->image_height) { - y[i] = y_plane + scanline * cinfo->image_width; + y[i] = y_plane + scanline * lumaStride; } else { y[i] = empty.get(); } - if (!is_width_aligned) { + if (need_padding) { memcpy(y_intrm[i], y[i], cinfo->image_width); } } @@ -207,18 +201,18 @@ bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* for (int i = 0; i < kCompressBatchSize / 2; ++i) { size_t scanline = cinfo->next_scanline / 2 + i; if (scanline < cinfo->image_height / 2) { - int offset = scanline * (cinfo->image_width / 2); + int offset = scanline * chromaStride; cb[i] = u_plane + offset; cr[i] = v_plane + offset; } else { cb[i] = cr[i] = empty.get(); } - if (!is_width_aligned) { + if (need_padding) { memcpy(cb_intrm[i], cb[i], cinfo->image_width / 2); memcpy(cr_intrm[i], cr[i], cinfo->image_width / 2); } } - int processed = jpeg_write_raw_data(cinfo, is_width_aligned ? planes : planes_intrm, + int processed = jpeg_write_raw_data(cinfo, need_padding ? planes_intrm : planes, kCompressBatchSize); if (processed != kCompressBatchSize) { ALOGE("Number of processed lines does not equal input lines."); @@ -228,22 +222,23 @@ bool JpegEncoderHelper::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* return true; } -bool JpegEncoderHelper::compressSingleChannel(jpeg_compress_struct* cinfo, const uint8_t* image) { +bool JpegEncoderHelper::compressY(jpeg_compress_struct* cinfo, const uint8_t* yBuffer, + int lumaStride) { JSAMPROW y[kCompressBatchSize]; JSAMPARRAY planes[1]{y}; - uint8_t* y_plane = const_cast(image); + uint8_t* y_plane = const_cast(yBuffer); std::unique_ptr empty = std::make_unique(cinfo->image_width); memset(empty.get(), 0, cinfo->image_width); const int aligned_width = ALIGNM(cinfo->image_width, kCompressBatchSize); - bool is_width_aligned = (aligned_width == cinfo->image_width); + const bool need_padding = (lumaStride < aligned_width); std::unique_ptr buffer_intrm = nullptr; uint8_t* y_plane_intrm = nullptr; uint8_t* u_plane_intrm = nullptr; JSAMPROW y_intrm[kCompressBatchSize]; JSAMPARRAY planes_intrm[]{y_intrm}; - if (!is_width_aligned) { + if (need_padding) { size_t mcu_row_size = aligned_width * kCompressBatchSize; buffer_intrm = std::make_unique(mcu_row_size); y_plane_intrm = buffer_intrm.get(); @@ -257,15 +252,15 @@ bool JpegEncoderHelper::compressSingleChannel(jpeg_compress_struct* cinfo, const for (int i = 0; i < kCompressBatchSize; ++i) { size_t scanline = cinfo->next_scanline + i; if (scanline < cinfo->image_height) { - y[i] = y_plane + scanline * cinfo->image_width; + y[i] = y_plane + scanline * lumaStride; } else { y[i] = empty.get(); } - if (!is_width_aligned) { + if (need_padding) { memcpy(y_intrm[i], y[i], cinfo->image_width); } } - int processed = jpeg_write_raw_data(cinfo, is_width_aligned ? planes : planes_intrm, + int processed = jpeg_write_raw_data(cinfo, need_padding ? planes_intrm : planes, kCompressBatchSize); if (processed != kCompressBatchSize / 2) { ALOGE("Number of processed lines does not equal input lines."); diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp index fdfbb9cec2..dc439d785a 100644 --- a/libs/ultrahdr/jpegr.cpp +++ b/libs/ultrahdr/jpegr.cpp @@ -185,21 +185,18 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfe p010_image.chroma_stride = p010_image.luma_stride; } + const int yu420_luma_stride = ALIGNM(p010_image.width, kJpegBlock); unique_ptr yuv420_image_data = - make_unique(p010_image.width * p010_image.height * 3 / 2); + make_unique(yu420_luma_stride * p010_image.height * 3 / 2); jpegr_uncompressed_struct yuv420_image = {.data = yuv420_image_data.get(), .width = p010_image.width, .height = p010_image.height, .colorGamut = p010_image.colorGamut, - .luma_stride = 0, + .luma_stride = yu420_luma_stride, .chroma_data = nullptr, - .chroma_stride = 0}; - if (yuv420_image.luma_stride == 0) yuv420_image.luma_stride = yuv420_image.width; - if (!yuv420_image.chroma_data) { - uint8_t* data = reinterpret_cast(yuv420_image.data); - yuv420_image.chroma_data = data + yuv420_image.luma_stride * yuv420_image.height; - yuv420_image.chroma_stride = yuv420_image.luma_stride >> 1; - } + .chroma_stride = yu420_luma_stride >> 1}; + uint8_t* data = reinterpret_cast(yuv420_image.data); + yuv420_image.chroma_data = data + yuv420_image.luma_stride * yuv420_image.height; // tone map JPEGR_CHECK(toneMap(&p010_image, &yuv420_image)); @@ -230,7 +227,10 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, ultrahdr_transfe // compress 420 image JpegEncoderHelper jpeg_enc_obj_yuv420; - if (!jpeg_enc_obj_yuv420.compressImage(yuv420_image.data, yuv420_image.width, yuv420_image.height, + if (!jpeg_enc_obj_yuv420.compressImage(reinterpret_cast(yuv420_image.data), + reinterpret_cast(yuv420_image.chroma_data), + yuv420_image.width, yuv420_image.height, + yuv420_image.luma_stride, yuv420_image.chroma_stride, quality, icc->getData(), icc->getLength())) { return ERROR_JPEGR_ENCODE_ERROR; } @@ -305,13 +305,15 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, unique_ptr yuv_420_bt601_data; // Convert to bt601 YUV encoding for JPEG encode if (yuv420_image.colorGamut != ULTRAHDR_COLORGAMUT_P3) { - yuv_420_bt601_data = make_unique(yuv420_image.width * yuv420_image.height * 3 / 2); + const int yuv_420_bt601_luma_stride = ALIGNM(yuv420_image.width, kJpegBlock); + yuv_420_bt601_data = + make_unique(yuv_420_bt601_luma_stride * yuv420_image.height * 3 / 2); yuv420_bt601_image.data = yuv_420_bt601_data.get(); yuv420_bt601_image.colorGamut = yuv420_image.colorGamut; - yuv420_bt601_image.luma_stride = yuv420_image.width; + yuv420_bt601_image.luma_stride = yuv_420_bt601_luma_stride; uint8_t* data = reinterpret_cast(yuv420_bt601_image.data); - yuv420_bt601_image.chroma_data = data + yuv420_bt601_image.luma_stride * yuv420_image.height; - yuv420_bt601_image.chroma_stride = yuv420_bt601_image.luma_stride >> 1; + yuv420_bt601_image.chroma_data = data + yuv_420_bt601_luma_stride * yuv420_image.height; + yuv420_bt601_image.chroma_stride = yuv_420_bt601_luma_stride >> 1; { // copy luma @@ -322,6 +324,10 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, } else { for (size_t i = 0; i < yuv420_image.height; i++) { memcpy(y_dst, y_src, yuv420_image.width); + if (yuv420_image.width != yuv420_bt601_image.luma_stride) { + memset(y_dst + yuv420_image.width, 0, + yuv420_bt601_image.luma_stride - yuv420_image.width); + } y_dst += yuv420_bt601_image.luma_stride; y_src += yuv420_image.luma_stride; } @@ -342,6 +348,12 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, for (size_t i = 0; i < yuv420_image.height / 2; i++) { memcpy(cb_dst, cb_src, yuv420_image.width / 2); memcpy(cr_dst, cr_src, yuv420_image.width / 2); + if (yuv420_bt601_image.width / 2 != yuv420_bt601_image.chroma_stride) { + memset(cb_dst + yuv420_image.width / 2, 0, + yuv420_bt601_image.chroma_stride - yuv420_image.width / 2); + memset(cr_dst + yuv420_image.width / 2, 0, + yuv420_bt601_image.chroma_stride - yuv420_image.width / 2); + } cb_dst += yuv420_bt601_image.chroma_stride; cb_src += yuv420_image.chroma_stride; cr_dst += yuv420_bt601_image.chroma_stride; @@ -353,8 +365,11 @@ status_t JpegR::encodeJPEGR(jr_uncompressed_ptr p010_image_ptr, // compress 420 image JpegEncoderHelper jpeg_enc_obj_yuv420; - if (!jpeg_enc_obj_yuv420.compressImage(yuv420_bt601_image.data, yuv420_bt601_image.width, - yuv420_bt601_image.height, quality, icc->getData(), + if (!jpeg_enc_obj_yuv420.compressImage(reinterpret_cast(yuv420_bt601_image.data), + reinterpret_cast(yuv420_bt601_image.chroma_data), + yuv420_bt601_image.width, yuv420_bt601_image.height, + yuv420_bt601_image.luma_stride, + yuv420_bt601_image.chroma_stride, quality, icc->getData(), icc->getLength())) { return ERROR_JPEGR_ENCODE_ERROR; } @@ -697,9 +712,10 @@ status_t JpegR::compressGainMap(jr_uncompressed_ptr gainmap_image_ptr, } // Don't need to convert YUV to Bt601 since single channel - if (!jpeg_enc_obj_ptr->compressImage(gainmap_image_ptr->data, gainmap_image_ptr->width, - gainmap_image_ptr->height, kMapCompressQuality, nullptr, 0, - true /* isSingleChannel */)) { + if (!jpeg_enc_obj_ptr->compressImage(reinterpret_cast(gainmap_image_ptr->data), nullptr, + gainmap_image_ptr->width, gainmap_image_ptr->height, + gainmap_image_ptr->luma_stride, 0, kMapCompressQuality, + nullptr, 0)) { return ERROR_JPEGR_ENCODE_ERROR; } @@ -769,7 +785,9 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr yuv420_image_ptr, ultrahdr_transfer_function hdr_tf, ultrahdr_metadata_ptr metadata, jr_uncompressed_ptr dest, bool sdr_is_601) { if (yuv420_image_ptr == nullptr || p010_image_ptr == nullptr || metadata == nullptr || - dest == nullptr) { + dest == nullptr || yuv420_image_ptr->data == nullptr || + yuv420_image_ptr->chroma_data == nullptr || p010_image_ptr->data == nullptr || + p010_image_ptr->chroma_data == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } if (yuv420_image_ptr->width != p010_image_ptr->width || @@ -940,7 +958,8 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr yuv420_image_ptr, ultrahdr_output_format output_format, float max_display_boost, jr_uncompressed_ptr dest) { if (yuv420_image_ptr == nullptr || gainmap_image_ptr == nullptr || metadata == nullptr || - dest == nullptr) { + dest == nullptr || yuv420_image_ptr->data == nullptr || + yuv420_image_ptr->chroma_data == nullptr || gainmap_image_ptr->data == nullptr) { return ERROR_JPEGR_INVALID_NULL_PTR; } if (metadata->version.compare(kJpegrVersion)) { @@ -970,7 +989,9 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr yuv420_image_ptr, size_t map_height = static_cast( floor((image_height + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); if (map_width != gainmap_image_ptr->width || map_height != gainmap_image_ptr->height) { - ALOGE("gain map dimensions and primary image dimensions are not to scale"); + ALOGE("gain map dimensions and primary image dimensions are not to scale, computed gain map " + "resolution is %dx%d, received gain map resolution is %dx%d", + (int)map_width, (int)map_height, gainmap_image_ptr->width, gainmap_image_ptr->height); return ERROR_JPEGR_INVALID_INPUT_TYPE; } @@ -1314,27 +1335,35 @@ status_t JpegR::toneMap(jr_uncompressed_ptr src, jr_uncompressed_ptr dest) { return ERROR_JPEGR_INVALID_INPUT_TYPE; } uint16_t* src_y_data = reinterpret_cast(src->data); - uint16_t* src_uv_data = reinterpret_cast(src->chroma_data); uint8_t* dst_y_data = reinterpret_cast(dest->data); - uint8_t* dst_u_data = reinterpret_cast(dest->chroma_data); - size_t v_offset = (dest->chroma_stride * dest->height / 2); - uint8_t* dst_v_data = dst_u_data + v_offset; for (size_t y = 0; y < src->height; ++y) { + uint16_t* src_y_row = src_y_data + y * src->luma_stride; + uint8_t* dst_y_row = dst_y_data + y * dest->luma_stride; for (size_t x = 0; x < src->width; ++x) { - size_t src_y_idx = y * src->luma_stride + x; - size_t src_u_idx = (y >> 1) * src->chroma_stride + (x & ~0x1); - size_t src_v_idx = src_u_idx + 1; - - uint16_t y_uint = src_y_data[src_y_idx] >> 6; - uint16_t u_uint = src_uv_data[src_u_idx] >> 6; - uint16_t v_uint = src_uv_data[src_v_idx] >> 6; - - size_t dest_y_idx = x + y * dest->luma_stride; - size_t dest_chroma_idx = (x / 2) + (y / 2) * (dest->chroma_stride); - - dst_y_data[dest_y_idx] = static_cast((y_uint >> 2) & 0xff); - dst_u_data[dest_chroma_idx] = static_cast((u_uint >> 2) & 0xff); - dst_v_data[dest_chroma_idx] = static_cast((v_uint >> 2) & 0xff); + uint16_t y_uint = src_y_row[x] >> 6; + dst_y_row[x] = static_cast((y_uint >> 2) & 0xff); + } + if (dest->width != dest->luma_stride) { + memset(dst_y_row + dest->width, 0, dest->luma_stride - dest->width); + } + } + uint16_t* src_uv_data = reinterpret_cast(src->chroma_data); + uint8_t* dst_u_data = reinterpret_cast(dest->chroma_data); + size_t dst_v_offset = (dest->chroma_stride * dest->height / 2); + uint8_t* dst_v_data = dst_u_data + dst_v_offset; + for (size_t y = 0; y < src->height / 2; ++y) { + uint16_t* src_uv_row = src_uv_data + y * src->chroma_stride; + uint8_t* dst_u_row = dst_u_data + y * dest->chroma_stride; + uint8_t* dst_v_row = dst_v_data + y * dest->chroma_stride; + for (size_t x = 0; x < src->width / 2; ++x) { + uint16_t u_uint = src_uv_row[x << 1] >> 6; + uint16_t v_uint = src_uv_row[(x << 1) + 1] >> 6; + dst_u_row[x] = static_cast((u_uint >> 2) & 0xff); + dst_v_row[x] = static_cast((v_uint >> 2) & 0xff); + } + if (dest->width / 2 != dest->chroma_stride) { + memset(dst_u_row + dest->width / 2, 0, dest->chroma_stride - dest->width / 2); + memset(dst_v_row + dest->width / 2, 0, dest->chroma_stride - dest->width / 2); } } dest->colorGamut = src->colorGamut; diff --git a/libs/ultrahdr/tests/gainmapmath_test.cpp b/libs/ultrahdr/tests/gainmapmath_test.cpp index 69cd36cd46..7c2d076992 100644 --- a/libs/ultrahdr/tests/gainmapmath_test.cpp +++ b/libs/ultrahdr/tests/gainmapmath_test.cpp @@ -120,7 +120,7 @@ public: 0xB0, 0xB1, 0xB2, 0xB3, }; - return { pixels, 4, 4, ULTRAHDR_COLORGAMUT_BT709 }; + return { pixels, 4, 4, ULTRAHDR_COLORGAMUT_BT709, pixels + 16, 4, 2 }; } Color (*Yuv420Colors())[4] { @@ -153,7 +153,7 @@ public: 0xA0 << 6, 0xB0 << 6, 0xA1 << 6, 0xB1 << 6, 0xA2 << 6, 0xB2 << 6, 0xA3 << 6, 0xB3 << 6, }; - return { pixels, 4, 4, ULTRAHDR_COLORGAMUT_BT709 }; + return { pixels, 4, 4, ULTRAHDR_COLORGAMUT_BT709, pixels + 16, 4, 4 }; } Color (*P010Colors())[4] { @@ -625,7 +625,7 @@ TEST_F(GainMapMathTest, Bt2100ToBt601YuvConversion) { EXPECT_YUV_NEAR(yuv2100To601(yuv_b), P3YuvBlue()); } -TEST_F(GainMapMathTest, DISABLED_TransformYuv420) { +TEST_F(GainMapMathTest, TransformYuv420) { ColorTransformFn transforms[] = { yuv709To601, yuv709To2100, yuv601To709, yuv601To2100, yuv2100To709, yuv2100To601 }; for (const ColorTransformFn& transform : transforms) { @@ -636,6 +636,9 @@ TEST_F(GainMapMathTest, DISABLED_TransformYuv420) { memcpy(out_buf.get(), input.data, out_buf_size); jpegr_uncompressed_struct output = Yuv420Image(); output.data = out_buf.get(); + output.chroma_data = out_buf.get() + input.width * input.height; + output.luma_stride = input.width; + output.chroma_stride = input.width / 2; transformYuv420(&output, 1, 1, transform); @@ -1042,7 +1045,7 @@ TEST_F(GainMapMathTest, ApplyGain) { applyGain(e, 1.0f, &metadata, displayBoost)); } -TEST_F(GainMapMathTest, DISABLED_GetYuv420Pixel) { +TEST_F(GainMapMathTest, GetYuv420Pixel) { jpegr_uncompressed_struct image = Yuv420Image(); Color (*colors)[4] = Yuv420Colors(); @@ -1053,7 +1056,7 @@ TEST_F(GainMapMathTest, DISABLED_GetYuv420Pixel) { } } -TEST_F(GainMapMathTest, DISABLED_GetP010Pixel) { +TEST_F(GainMapMathTest, GetP010Pixel) { jpegr_uncompressed_struct image = P010Image(); Color (*colors)[4] = P010Colors(); @@ -1064,7 +1067,7 @@ TEST_F(GainMapMathTest, DISABLED_GetP010Pixel) { } } -TEST_F(GainMapMathTest, DISABLED_SampleYuv420) { +TEST_F(GainMapMathTest, SampleYuv420) { jpegr_uncompressed_struct image = Yuv420Image(); Color (*colors)[4] = Yuv420Colors(); @@ -1090,7 +1093,7 @@ TEST_F(GainMapMathTest, DISABLED_SampleYuv420) { } } -TEST_F(GainMapMathTest, DISABLED_SampleP010) { +TEST_F(GainMapMathTest, SampleP010) { jpegr_uncompressed_struct image = P010Image(); Color (*colors)[4] = P010Colors(); diff --git a/libs/ultrahdr/tests/jpegencoderhelper_test.cpp b/libs/ultrahdr/tests/jpegencoderhelper_test.cpp index f0e1fa4968..33cb9f658f 100644 --- a/libs/ultrahdr/tests/jpegencoderhelper_test.cpp +++ b/libs/ultrahdr/tests/jpegencoderhelper_test.cpp @@ -42,6 +42,7 @@ public: }; JpegEncoderHelperTest(); ~JpegEncoderHelperTest(); + protected: virtual void SetUp(); virtual void TearDown(); @@ -103,24 +104,32 @@ void JpegEncoderHelperTest::TearDown() {} TEST_F(JpegEncoderHelperTest, encodeAlignedImage) { JpegEncoderHelper encoder; - EXPECT_TRUE(encoder.compressImage(mAlignedImage.buffer.get(), mAlignedImage.width, - mAlignedImage.height, JPEG_QUALITY, NULL, 0)); + EXPECT_TRUE(encoder.compressImage(mAlignedImage.buffer.get(), + mAlignedImage.buffer.get() + + mAlignedImage.width * mAlignedImage.height, + mAlignedImage.width, mAlignedImage.height, + mAlignedImage.width, mAlignedImage.width / 2, JPEG_QUALITY, + NULL, 0)); ASSERT_GT(encoder.getCompressedImageSize(), static_cast(0)); } TEST_F(JpegEncoderHelperTest, encodeUnalignedImage) { JpegEncoderHelper encoder; - EXPECT_TRUE(encoder.compressImage(mUnalignedImage.buffer.get(), mUnalignedImage.width, - mUnalignedImage.height, JPEG_QUALITY, NULL, 0)); + EXPECT_TRUE(encoder.compressImage(mUnalignedImage.buffer.get(), + mUnalignedImage.buffer.get() + + mUnalignedImage.width * mUnalignedImage.height, + mUnalignedImage.width, mUnalignedImage.height, + mUnalignedImage.width, mUnalignedImage.width / 2, + JPEG_QUALITY, NULL, 0)); ASSERT_GT(encoder.getCompressedImageSize(), static_cast(0)); } TEST_F(JpegEncoderHelperTest, encodeSingleChannelImage) { JpegEncoderHelper encoder; - EXPECT_TRUE(encoder.compressImage(mSingleChannelImage.buffer.get(), mSingleChannelImage.width, - mSingleChannelImage.height, JPEG_QUALITY, NULL, 0, true)); + EXPECT_TRUE(encoder.compressImage(mSingleChannelImage.buffer.get(), nullptr, + mSingleChannelImage.width, mSingleChannelImage.height, + mSingleChannelImage.width, 0, JPEG_QUALITY, NULL, 0)); ASSERT_GT(encoder.getCompressedImageSize(), static_cast(0)); } -} // namespace android::ultrahdr - +} // namespace android::ultrahdr diff --git a/libs/ultrahdr/tests/jpegr_test.cpp b/libs/ultrahdr/tests/jpegr_test.cpp index e69c50964a..a75086755a 100644 --- a/libs/ultrahdr/tests/jpegr_test.cpp +++ b/libs/ultrahdr/tests/jpegr_test.cpp @@ -1375,11 +1375,21 @@ TEST(JpegRTest, writeXmpThenRead) { EXPECT_FLOAT_EQ(metadata_expected.hdrCapacityMax, metadata_read.hdrCapacityMax); } +class JpegRAPIEncodeAndDecodeTest + : public ::testing::TestWithParam> { +public: + JpegRAPIEncodeAndDecodeTest() + : mP010ColorGamut(std::get<0>(GetParam())), mYuv420ColorGamut(std::get<1>(GetParam())){}; + + const ultrahdr_color_gamut mP010ColorGamut; + const ultrahdr_color_gamut mYuv420ColorGamut; +}; + /* Test Encode API-0 and Decode */ -TEST(JpegRTest, EncodeAPI0AndDecodeTest) { +TEST_P(JpegRAPIEncodeAndDecodeTest, EncodeAPI0AndDecodeTest) { // reference encode UhdrUnCompressedStructWrapper rawImg(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg.allocateMemory()); ASSERT_TRUE(rawImg.loadRawResource(kYCbCrP010FileName)); UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight); @@ -1392,8 +1402,8 @@ TEST(JpegRTest, EncodeAPI0AndDecodeTest) { // encode with luma stride set { UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); - ASSERT_TRUE(rawImg2.setImageStride(kImageWidth + 128, 0)); + ASSERT_TRUE(rawImg2.setImageColorGamut(mP010ColorGamut)); + ASSERT_TRUE(rawImg2.setImageStride(kImageWidth + 18, 0)); ASSERT_TRUE(rawImg2.allocateMemory()); ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName)); UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); @@ -1410,8 +1420,8 @@ TEST(JpegRTest, EncodeAPI0AndDecodeTest) { // encode with luma and chroma stride set { UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); - ASSERT_TRUE(rawImg2.setImageStride(kImageWidth + 128, kImageWidth + 256)); + ASSERT_TRUE(rawImg2.setImageColorGamut(mP010ColorGamut)); + ASSERT_TRUE(rawImg2.setImageStride(kImageWidth + 18, kImageWidth + 28)); ASSERT_TRUE(rawImg2.setChromaMode(false)); ASSERT_TRUE(rawImg2.allocateMemory()); ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName)); @@ -1429,8 +1439,8 @@ TEST(JpegRTest, EncodeAPI0AndDecodeTest) { // encode with chroma stride set { UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); - ASSERT_TRUE(rawImg2.setImageStride(0, kImageWidth + 64)); + ASSERT_TRUE(rawImg2.setImageColorGamut(mP010ColorGamut)); + ASSERT_TRUE(rawImg2.setImageStride(0, kImageWidth + 34)); ASSERT_TRUE(rawImg2.setChromaMode(false)); ASSERT_TRUE(rawImg2.allocateMemory()); ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName)); @@ -1448,8 +1458,8 @@ TEST(JpegRTest, EncodeAPI0AndDecodeTest) { // encode with luma and chroma stride set but no chroma ptr { UhdrUnCompressedStructWrapper rawImg2(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); - ASSERT_TRUE(rawImg2.setImageStride(kImageWidth, kImageWidth + 256)); + ASSERT_TRUE(rawImg2.setImageColorGamut(mP010ColorGamut)); + ASSERT_TRUE(rawImg2.setImageStride(kImageWidth, kImageWidth + 38)); ASSERT_TRUE(rawImg2.allocateMemory()); ASSERT_TRUE(rawImg2.loadRawResource(kYCbCrP010FileName)); UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); @@ -1475,13 +1485,13 @@ TEST(JpegRTest, EncodeAPI0AndDecodeTest) { } /* Test Encode API-1 and Decode */ -TEST(JpegRTest, EncodeAPI1AndDecodeTest) { +TEST_P(JpegRAPIEncodeAndDecodeTest, EncodeAPI1AndDecodeTest) { UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImgP010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImgP010.allocateMemory()); ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName)); UhdrUnCompressedStructWrapper rawImg420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg420.setImageColorGamut(mYuv420ColorGamut)); ASSERT_TRUE(rawImg420.allocateMemory()); ASSERT_TRUE(rawImg420.loadRawResource(kYCbCr420FileName)); UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight); @@ -1494,7 +1504,7 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with luma stride set p010 { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, 0)); ASSERT_TRUE(rawImg2P010.allocateMemory()); ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); @@ -1512,7 +1522,7 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with luma and chroma stride set p010 { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, kImageWidth + 256)); ASSERT_TRUE(rawImg2P010.setChromaMode(false)); ASSERT_TRUE(rawImg2P010.allocateMemory()); @@ -1531,7 +1541,7 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with chroma stride set p010 { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(0, kImageWidth + 64)); ASSERT_TRUE(rawImg2P010.setChromaMode(false)); ASSERT_TRUE(rawImg2P010.allocateMemory()); @@ -1550,7 +1560,7 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with luma and chroma stride set but no chroma ptr p010 { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 64, kImageWidth + 256)); ASSERT_TRUE(rawImg2P010.allocateMemory()); ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); @@ -1568,8 +1578,8 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with luma stride set 420 { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); - ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, 0)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); + ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 14, 0)); ASSERT_TRUE(rawImg2420.allocateMemory()); ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); @@ -1586,8 +1596,8 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with luma and chroma stride set 420 { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); - ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, kImageWidth / 2 + 256)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); + ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 46, kImageWidth / 2 + 34)); ASSERT_TRUE(rawImg2420.setChromaMode(false)); ASSERT_TRUE(rawImg2420.allocateMemory()); ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); @@ -1605,8 +1615,8 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with chroma stride set 420 { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); - ASSERT_TRUE(rawImg2420.setImageStride(0, kImageWidth / 2 + 64)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); + ASSERT_TRUE(rawImg2420.setImageStride(0, kImageWidth / 2 + 38)); ASSERT_TRUE(rawImg2420.setChromaMode(false)); ASSERT_TRUE(rawImg2420.allocateMemory()); ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); @@ -1624,8 +1634,8 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { // encode with luma and chroma stride set but no chroma ptr 420 { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); - ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, kImageWidth / 2 + 64)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); + ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 26, kImageWidth / 2 + 44)); ASSERT_TRUE(rawImg2420.allocateMemory()); ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); UhdrCompressedStructWrapper jpgImg2(kImageWidth, kImageHeight); @@ -1652,13 +1662,13 @@ TEST(JpegRTest, EncodeAPI1AndDecodeTest) { } /* Test Encode API-2 and Decode */ -TEST(JpegRTest, EncodeAPI2AndDecodeTest) { +TEST_P(JpegRAPIEncodeAndDecodeTest, EncodeAPI2AndDecodeTest) { UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImgP010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImgP010.allocateMemory()); ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName)); UhdrUnCompressedStructWrapper rawImg420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg420.setImageColorGamut(mYuv420ColorGamut)); ASSERT_TRUE(rawImg420.allocateMemory()); ASSERT_TRUE(rawImg420.loadRawResource(kYCbCr420FileName)); UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight); @@ -1675,7 +1685,7 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { // encode with luma stride set { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, 0)); ASSERT_TRUE(rawImg2P010.allocateMemory()); ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); @@ -1693,7 +1703,7 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { // encode with luma and chroma stride set { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, kImageWidth + 256)); ASSERT_TRUE(rawImg2P010.setChromaMode(false)); ASSERT_TRUE(rawImg2P010.allocateMemory()); @@ -1712,7 +1722,7 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { // encode with chroma stride set { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(0, kImageWidth + 64)); ASSERT_TRUE(rawImg2P010.setChromaMode(false)); ASSERT_TRUE(rawImg2P010.allocateMemory()); @@ -1731,7 +1741,7 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { // encode with luma stride set { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, 0)); ASSERT_TRUE(rawImg2420.allocateMemory()); ASSERT_TRUE(rawImg2420.loadRawResource(kYCbCr420FileName)); @@ -1749,7 +1759,7 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { // encode with luma and chroma stride set { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); ASSERT_TRUE(rawImg2420.setImageStride(kImageWidth + 128, kImageWidth + 256)); ASSERT_TRUE(rawImg2420.setChromaMode(false)); ASSERT_TRUE(rawImg2420.allocateMemory()); @@ -1768,7 +1778,7 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { // encode with chroma stride set { UhdrUnCompressedStructWrapper rawImg2420(kImageWidth, kImageHeight, YCbCr_420); - ASSERT_TRUE(rawImg2420.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT709)); + ASSERT_TRUE(rawImg2420.setImageColorGamut(mYuv420ColorGamut)); ASSERT_TRUE(rawImg2420.setImageStride(0, kImageWidth + 64)); ASSERT_TRUE(rawImg2420.setChromaMode(false)); ASSERT_TRUE(rawImg2420.allocateMemory()); @@ -1797,9 +1807,9 @@ TEST(JpegRTest, EncodeAPI2AndDecodeTest) { } /* Test Encode API-3 and Decode */ -TEST(JpegRTest, EncodeAPI3AndDecodeTest) { +TEST_P(JpegRAPIEncodeAndDecodeTest, EncodeAPI3AndDecodeTest) { UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImgP010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImgP010.allocateMemory()); ASSERT_TRUE(rawImgP010.loadRawResource(kYCbCrP010FileName)); UhdrCompressedStructWrapper jpgImg(kImageWidth, kImageHeight); @@ -1816,7 +1826,7 @@ TEST(JpegRTest, EncodeAPI3AndDecodeTest) { // encode with luma stride set { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, 0)); ASSERT_TRUE(rawImg2P010.allocateMemory()); ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); @@ -1834,7 +1844,7 @@ TEST(JpegRTest, EncodeAPI3AndDecodeTest) { // encode with luma and chroma stride set { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 128, kImageWidth + 256)); ASSERT_TRUE(rawImg2P010.setChromaMode(false)); ASSERT_TRUE(rawImg2P010.allocateMemory()); @@ -1853,7 +1863,7 @@ TEST(JpegRTest, EncodeAPI3AndDecodeTest) { // encode with chroma stride set { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(0, kImageWidth + 64)); ASSERT_TRUE(rawImg2P010.setChromaMode(false)); ASSERT_TRUE(rawImg2P010.allocateMemory()); @@ -1872,7 +1882,7 @@ TEST(JpegRTest, EncodeAPI3AndDecodeTest) { // encode with luma and chroma stride set and no chroma ptr { UhdrUnCompressedStructWrapper rawImg2P010(kImageWidth, kImageHeight, YCbCr_p010); - ASSERT_TRUE(rawImg2P010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); + ASSERT_TRUE(rawImg2P010.setImageColorGamut(mP010ColorGamut)); ASSERT_TRUE(rawImg2P010.setImageStride(kImageWidth + 32, kImageWidth + 256)); ASSERT_TRUE(rawImg2P010.allocateMemory()); ASSERT_TRUE(rawImg2P010.loadRawResource(kYCbCrP010FileName)); @@ -1899,6 +1909,13 @@ TEST(JpegRTest, EncodeAPI3AndDecodeTest) { ASSERT_NO_FATAL_FAILURE(decodeJpegRImg(jpg1, "decode_api3_output.rgb")); } +INSTANTIATE_TEST_SUITE_P( + JpegRAPIParameterizedTests, JpegRAPIEncodeAndDecodeTest, + ::testing::Combine(::testing::Values(ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, + ULTRAHDR_COLORGAMUT_BT2100), + ::testing::Values(ULTRAHDR_COLORGAMUT_BT709, ULTRAHDR_COLORGAMUT_P3, + ULTRAHDR_COLORGAMUT_BT2100))); + // ============================================================================ // Profiling // ============================================================================ @@ -1966,7 +1983,7 @@ void JpegRBenchmark::BenchmarkApplyGainMap(jr_uncompressed_ptr yuv420Image, jr_u profileRecMap.elapsedTime() / (kProfileCount * 1000.f)); } -TEST(JpegRTest, DISABLED_ProfileGainMapFuncs) { +TEST(JpegRTest, ProfileGainMapFuncs) { UhdrUnCompressedStructWrapper rawImgP010(kImageWidth, kImageHeight, YCbCr_p010); ASSERT_TRUE(rawImgP010.setImageColorGamut(ultrahdr_color_gamut::ULTRAHDR_COLORGAMUT_BT2100)); ASSERT_TRUE(rawImgP010.allocateMemory()); @@ -1980,6 +1997,25 @@ TEST(JpegRTest, DISABLED_ProfileGainMapFuncs) { .width = 0, .height = 0, .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; + { + auto rawImg = rawImgP010.getImageHandle(); + if (rawImg->luma_stride == 0) rawImg->luma_stride = rawImg->width; + if (!rawImg->chroma_data) { + uint16_t* data = reinterpret_cast(rawImg->data); + rawImg->chroma_data = data + rawImg->luma_stride * rawImg->height; + rawImg->chroma_stride = rawImg->luma_stride; + } + } + { + auto rawImg = rawImg420.getImageHandle(); + if (rawImg->luma_stride == 0) rawImg->luma_stride = rawImg->width; + if (!rawImg->chroma_data) { + uint8_t* data = reinterpret_cast(rawImg->data); + rawImg->chroma_data = data + rawImg->luma_stride * rawImg->height; + rawImg->chroma_stride = rawImg->luma_stride / 2; + } + } + JpegRBenchmark benchmark; ASSERT_NO_FATAL_FAILURE(benchmark.BenchmarkGenerateGainMap(rawImg420.getImageHandle(), rawImgP010.getImageHandle(), &metadata, -- GitLab From e0bb6f4ff13cc45b61a1b0edccbf875bb3871c89 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 2 Aug 2023 22:41:52 +0000 Subject: [PATCH 0408/1187] Fix extended range handling when Gamma OETF is used Populating fakeOutputDataspace got dropped, which turned off the one-off workaround to bypass skia's color management to encode as gamma 2.2. Turn it back on to prevent flickers on some devices. Bug: 293311643 Test: SilkFX test app Change-Id: I4370756c48fe79c1b4fcbd88a3bf2579fde1bf65 --- libs/renderengine/skia/SkiaRenderEngine.cpp | 15 ++++++++++----- libs/renderengine/skia/SkiaRenderEngine.h | 1 + libs/shaders/shaders.cpp | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index 871d258ce7..387998865f 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -511,7 +511,8 @@ sk_sp SkiaRenderEngine::createRuntimeEffectShader( auto effect = shaders::LinearEffect{.inputDataspace = parameters.layer.sourceDataspace, .outputDataspace = parameters.outputDataSpace, - .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha}; + .undoPremultipliedAlpha = parameters.undoPremultipliedAlpha, + .fakeOutputDataspace = parameters.fakeOutputDataspace}; auto effectIter = mRuntimeEffects.find(effect); sk_sp runtimeEffect = nullptr; @@ -892,12 +893,14 @@ void SkiaRenderEngine::drawLayersInternal( (display.outputDataspace & ui::Dataspace::TRANSFER_MASK) == static_cast(ui::Dataspace::TRANSFER_SRGB); - const ui::Dataspace runtimeEffectDataspace = !dimInLinearSpace && isExtendedHdr + const bool useFakeOutputDataspaceForRuntimeEffect = !dimInLinearSpace && isExtendedHdr; + + const ui::Dataspace fakeDataspace = useFakeOutputDataspaceForRuntimeEffect ? static_cast( (display.outputDataspace & ui::Dataspace::STANDARD_MASK) | ui::Dataspace::TRANSFER_GAMMA2_2 | (display.outputDataspace & ui::Dataspace::RANGE_MASK)) - : display.outputDataspace; + : ui::Dataspace::UNKNOWN; // If the input dataspace is range extended, the output dataspace transfer is sRGB // and dimmingStage is GAMMA_OETF, dim in linear space instead, and @@ -1004,7 +1007,8 @@ void SkiaRenderEngine::drawLayersInternal( .layerDimmingRatio = dimInLinearSpace ? layerDimmingRatio : 1.f, - .outputDataSpace = runtimeEffectDataspace})); + .outputDataSpace = display.outputDataspace, + .fakeOutputDataspace = fakeDataspace})); // Turn on dithering when dimming beyond this (arbitrary) threshold... static constexpr float kDimmingThreshold = 0.2f; @@ -1068,7 +1072,8 @@ void SkiaRenderEngine::drawLayersInternal( .undoPremultipliedAlpha = false, .requiresLinearEffect = requiresLinearEffect, .layerDimmingRatio = layerDimmingRatio, - .outputDataSpace = runtimeEffectDataspace})); + .outputDataSpace = display.outputDataspace, + .fakeOutputDataspace = fakeDataspace})); } if (layer.disableBlending) { diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 6457bfa9eb..723e73c29e 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -157,6 +157,7 @@ private: bool requiresLinearEffect; float layerDimmingRatio; const ui::Dataspace outputDataSpace; + const ui::Dataspace fakeOutputDataspace; }; sk_sp createRuntimeEffectShader(const RuntimeEffectShaderParameters&); diff --git a/libs/shaders/shaders.cpp b/libs/shaders/shaders.cpp index c85517a976..ef039e5c36 100644 --- a/libs/shaders/shaders.cpp +++ b/libs/shaders/shaders.cpp @@ -168,8 +168,8 @@ void generateOOTF(ui::Dataspace inputDataspace, ui::Dataspace outputDataspace, void generateOETF(std::string& shader) { // Only support gamma 2.2 for now shader.append(R"( - float OETF(float3 linear) { - return sign(linear) * pow(abs(linear), (1.0 / 2.2)); + float3 OETF(float3 linear) { + return sign(linear) * pow(abs(linear), float3(1.0 / 2.2)); } )"); } -- GitLab From cc14642e946fbf57ebc6d7fb08fa6093228ad637 Mon Sep 17 00:00:00 2001 From: Matt Buckley Date: Wed, 28 Jun 2023 19:14:02 +0000 Subject: [PATCH 0409/1187] Add plumbing for ADPF Power Efficiency hint These patches introduce a new power efficiency mode for hint sessions to the public API, and internally expose a new setMode API for hint sessions that resembles the setMode API for iPower, to control different session operating modes. This set of patches: - Updates the PowerHAL AIDL to version 5, and updates relevant bp files - Exposes new setPreferPowerEfficiency(bool enabled) method from the SDK and NDK - Exposes new setMode(int mode, bool enabled) method from PowerHAL AIDL and HintManagerService - Adds support for new setMode call in PowerHAL Bug: b/288117936 Test: atest cts/tests/tests/os/src/android/os/cts/PerformanceHintManagerTest.java Change-Id: Ib6669238b7e030c0dad2ac89781217515cef3967 --- include/android/performance_hint.h | 101 +++++++++++------- libs/gui/fuzzer/Android.bp | 2 +- services/powermanager/Android.bp | 4 +- services/powermanager/benchmarks/Android.bp | 2 +- services/powermanager/tests/Android.bp | 5 +- services/surfaceflinger/Android.bp | 2 +- .../CompositionEngine/Android.bp | 2 +- .../surfaceflinger/tests/unittests/Android.bp | 2 +- .../DisplayHardware/MockIPowerHintSession.h | 2 + 9 files changed, 75 insertions(+), 47 deletions(-) diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h index b494f897d5..8d204baea3 100644 --- a/include/android/performance_hint.h +++ b/include/android/performance_hint.h @@ -14,6 +14,23 @@ * limitations under the License. */ + /** + * @defgroup APerformanceHint Performance Hint Manager + * + * APerformanceHint allows apps to create performance hint sessions for groups + * of threads, and provide hints to the system about the workload of those threads, + * to help the system more accurately allocate power for them. It is the NDK + * counterpart to the Java PerformanceHintManager SDK API. + * + * @{ + */ + +/** + * @file performance_hint.h + * @brief API for creating and managing a hint session. + */ + + #ifndef ANDROID_NATIVE_PERFORMANCE_HINT_H #define ANDROID_NATIVE_PERFORMANCE_HINT_H @@ -48,7 +65,7 @@ struct APerformanceHintSession; * An opaque type representing a handle to a performance hint manager. * It must be released after use. * - *

To use:

    + * To use:
      *
    • Obtain the performance hint manager instance by calling * {@link APerformanceHint_getManager} function.
    • *
    • Create an {@link APerformanceHintSession} with @@ -61,50 +78,43 @@ typedef struct APerformanceHintManager APerformanceHintManager; /** * An opaque type representing a handle to a performance hint session. * A session can only be acquired from a {@link APerformanceHintManager} - * with {@link APerformanceHint_getPreferredUpdateRateNanos}. It must be + * with {@link APerformanceHint_createSession}. It must be * freed with {@link APerformanceHint_closeSession} after use. * * A Session represents a group of threads with an inter-related workload such that hints for * their performance should be considered as a unit. The threads in a given session should be - * long-life and not created or destroyed dynamically. - * - *

      Each session is expected to have a periodic workload with a target duration for each - * cycle. The cycle duration is likely greater than the target work duration to allow other - * parts of the pipeline to run within the available budget. For example, a renderer thread may - * work at 60hz in order to produce frames at the display's frame but have a target work - * duration of only 6ms.

      - * - *

      After each cycle of work, the client is expected to use - * {@link APerformanceHint_reportActualWorkDuration} to report the actual time taken to - * complete.

      - * - *

      To use:

        - *
      • Update a sessions target duration for each cycle of work - * with {@link APerformanceHint_updateTargetWorkDuration}.
      • - *
      • Report the actual duration for the last cycle of work with - * {@link APerformanceHint_reportActualWorkDuration}.
      • - *
      • Release the session instance with - * {@link APerformanceHint_closeSession}.

      + * long-lived and not created or destroyed dynamically. + * + * The work duration API can be used with periodic workloads to dynamically adjust thread + * performance and keep the work on schedule while optimizing the available power budget. + * When using the work duration API, the starting target duration should be specified + * while creating the session, and can later be adjusted with + * {@link APerformanceHint_updateTargetWorkDuration}. While using the work duration + * API, the client is expected to call {@link APerformanceHint_reportActualWorkDuration} each + * cycle to report the actual time taken to complete to the system. + * + * All timings should be from `std::chrono::steady_clock` or `clock_gettime(CLOCK_MONOTONIC, ...)` */ typedef struct APerformanceHintSession APerformanceHintSession; /** * Acquire an instance of the performance hint manager. * - * @return manager instance on success, nullptr on failure. + * @return APerformanceHintManager instance on success, nullptr on failure. */ APerformanceHintManager* APerformanceHint_getManager() __INTRODUCED_IN(__ANDROID_API_T__); /** * Creates a session for the given set of threads and sets their initial target work * duration. + * * @param manager The performance hint manager instance. * @param threadIds The list of threads to be associated with this session. They must be part of - * this app's thread group. - * @param size the size of threadIds. - * @param initialTargetWorkDurationNanos The desired duration in nanoseconds for the new session. - * This must be positive. - * @return manager instance on success, nullptr on failure. + * this process' thread group. + * @param size The size of the list of threadIds. + * @param initialTargetWorkDurationNanos The target duration in nanoseconds for the new session. + * This must be positive if using the work duration API, or 0 otherwise. + * @return APerformanceHintManager instance on success, nullptr on failure. */ APerformanceHintSession* APerformanceHint_createSession( APerformanceHintManager* manager, @@ -124,8 +134,8 @@ int64_t APerformanceHint_getPreferredUpdateRateNanos( * Updates this session's target duration for each cycle of work. * * @param session The performance hint session instance to update. - * @param targetDurationNanos the new desired duration in nanoseconds. This must be positive. - * @return 0 on success + * @param targetDurationNanos The new desired duration in nanoseconds. This must be positive. + * @return 0 on success. * EINVAL if targetDurationNanos is not positive. * EPIPE if communication with the system service has failed. */ @@ -136,14 +146,13 @@ int APerformanceHint_updateTargetWorkDuration( /** * Reports the actual duration for the last cycle of work. * - *

      The system will attempt to adjust the core placement of the threads within the thread - * group and/or the frequency of the core on which they are run to bring the actual duration - * close to the target duration.

      + * The system will attempt to adjust the scheduling and performance of the + * threads within the thread group to bring the actual duration close to the target duration. * * @param session The performance hint session instance to update. - * @param actualDurationNanos how long the thread group took to complete its last task in - * nanoseconds. This must be positive. - * @return 0 on success + * @param actualDurationNanos The duration of time the thread group took to complete its last + * task in nanoseconds. This must be positive. + * @return 0 on success. * EINVAL if actualDurationNanos is not positive. * EPIPE if communication with the system service has failed. */ @@ -164,12 +173,13 @@ void APerformanceHint_closeSession( * Set a list of threads to the performance hint session. This operation will replace * the current list of threads with the given list of threads. * - * @param session The performance hint session instance for the threads. + * @param session The performance hint session instance to update. * @param threadIds The list of threads to be associated with this session. They must be part of * this app's thread group. - * @param size the size of the list of threadIds. + * @param size The size of the list of threadIds. * @return 0 on success. - * EINVAL if the list of thread ids is empty or if any of the thread ids is not part of the thread group. + * EINVAL if the list of thread ids is empty or if any of the thread ids are not part of + the thread group. * EPIPE if communication with the system service has failed. */ int APerformanceHint_setThreads( @@ -177,6 +187,21 @@ int APerformanceHint_setThreads( const pid_t* threadIds, size_t size) __INTRODUCED_IN(__ANDROID_API_U__); +/** + * This tells the session that these threads can be + * safely scheduled to prefer power efficiency over performance. + * + * @param session The performance hint session instance to update. + * @param enabled The flag which sets whether this session will use power-efficient scheduling. + * @return 0 on success. + * EPIPE if communication with the system service has failed. + */ +int APerformanceHint_setPreferPowerEfficiency( + APerformanceHintSession* session, + bool enabled) __INTRODUCED_IN(__ANDROID_API_V__); + __END_DECLS #endif // ANDROID_NATIVE_PERFORMANCE_HINT_H + +/** @} */ \ No newline at end of file diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp index 75bae7650f..5352f06422 100644 --- a/libs/gui/fuzzer/Android.bp +++ b/libs/gui/fuzzer/Android.bp @@ -24,6 +24,7 @@ package { cc_defaults { name: "libgui_fuzzer_defaults", + defaults: ["android.hardware.power-ndk_shared"], static_libs: [ "android.hidl.token@1.0-utils", "libbinder_random_parcel", @@ -46,7 +47,6 @@ cc_defaults { "android.hardware.configstore-utils", "android.hardware.graphics.bufferqueue@1.0", "android.hardware.graphics.bufferqueue@2.0", - "android.hardware.power-V4-ndk", "android.hidl.token@1.0", "libSurfaceFlingerProp", "libgui", diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp index 2523f3b6a6..8b16890a45 100644 --- a/services/powermanager/Android.bp +++ b/services/powermanager/Android.bp @@ -9,7 +9,7 @@ package { cc_library_shared { name: "libpowermanager", - + defaults: ["android.hardware.power-ndk_export_shared"], srcs: [ "BatterySaverPolicyConfig.cpp", "CoolingDevice.cpp", @@ -41,7 +41,6 @@ cc_library_shared { "android.hardware.power@1.1", "android.hardware.power@1.2", "android.hardware.power@1.3", - "android.hardware.power-V4-ndk", ], export_shared_lib_headers: [ @@ -49,7 +48,6 @@ cc_library_shared { "android.hardware.power@1.1", "android.hardware.power@1.2", "android.hardware.power@1.3", - "android.hardware.power-V4-ndk", ], cflags: [ diff --git a/services/powermanager/benchmarks/Android.bp b/services/powermanager/benchmarks/Android.bp index 03fc38d304..2b5ddb1460 100644 --- a/services/powermanager/benchmarks/Android.bp +++ b/services/powermanager/benchmarks/Android.bp @@ -23,6 +23,7 @@ package { cc_benchmark { name: "libpowermanager_benchmarks", + defaults: ["android.hardware.power-ndk_shared"], srcs: [ "main.cpp", "PowerHalAidlBenchmarks.cpp", @@ -41,7 +42,6 @@ cc_benchmark { "android.hardware.power@1.1", "android.hardware.power@1.2", "android.hardware.power@1.3", - "android.hardware.power-V4-ndk", ], static_libs: [ "libtestUtil", diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp index 08fcdc8275..6fc96c0959 100644 --- a/services/powermanager/tests/Android.bp +++ b/services/powermanager/tests/Android.bp @@ -23,6 +23,10 @@ package { cc_test { name: "libpowermanager_test", + defaults: [ + "android.hardware.power-ndk_shared", + "android.hardware.power-ndk_shared", + ], test_suites: ["device-tests"], srcs: [ "IThermalManagerTest.cpp", @@ -52,7 +56,6 @@ cc_test { "android.hardware.power@1.1", "android.hardware.power@1.2", "android.hardware.power@1.3", - "android.hardware.power-V4-ndk", ], static_libs: [ "libgmock", diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 89c80bc83a..c85a725d60 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -26,6 +26,7 @@ cc_defaults { name: "libsurfaceflinger_defaults", defaults: [ "android.hardware.graphics.composer3-ndk_shared", + "android.hardware.power-ndk_shared", "librenderengine_deps", "libtimestats_deps", "surfaceflinger_defaults", @@ -48,7 +49,6 @@ cc_defaults { "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.4", - "android.hardware.power-V4-ndk", "libbase", "libbinder", "libbinder_ndk", diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 3426495297..06c5e4c933 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -11,6 +11,7 @@ cc_defaults { name: "libcompositionengine_defaults", defaults: [ "android.hardware.graphics.composer3-ndk_shared", + "android.hardware.power-ndk_shared", "librenderengine_deps", "libtimestats_deps", "surfaceflinger_defaults", @@ -27,7 +28,6 @@ cc_defaults { "android.hardware.graphics.composer@2.4", "android.hardware.power@1.0", "android.hardware.power@1.3", - "android.hardware.power-V4-ndk", "libbase", "libcutils", "libgui", diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index fa5fa956ed..3dd33b9957 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -148,6 +148,7 @@ cc_defaults { defaults: [ "android.hardware.graphics.common-ndk_static", "android.hardware.graphics.composer3-ndk_static", + "android.hardware.power-ndk_static", "librenderengine_deps", ], static_libs: [ @@ -161,7 +162,6 @@ cc_defaults { "android.hardware.power@1.1", "android.hardware.power@1.2", "android.hardware.power@1.3", - "android.hardware.power-V4-ndk", "libaidlcommonsupport", "libcompositionengine_mocks", "libcompositionengine", diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h index 2b9520fca7..364618d61a 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h @@ -23,6 +23,7 @@ using aidl::android::hardware::power::IPowerHintSession; using aidl::android::hardware::power::SessionHint; +using aidl::android::hardware::power::SessionMode; using android::binder::Status; using namespace aidl::android::hardware::power; @@ -45,6 +46,7 @@ public: (override)); MOCK_METHOD(ndk::ScopedAStatus, sendHint, (SessionHint), (override)); MOCK_METHOD(ndk::ScopedAStatus, setThreads, (const ::std::vector&), (override)); + MOCK_METHOD(ndk::ScopedAStatus, setMode, (SessionMode, bool), (override)); }; } // namespace android::Hwc2::mock -- GitLab From 94bf30334f4dc74b03f5eea8212f294d4a202eab Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 27 Jul 2023 17:15:02 +0000 Subject: [PATCH 0410/1187] Adding tests for fuzzer corpus in binderRecordReplay Expanding binderRecordReplay tests to test generated fuzzer corpus from recorded transactions. Test: atest binderRecordReplayTest Bug: 278975837 Change-Id: I12f19fbeee22131b920c9b0ae5da51f2a14876ab --- libs/binder/tests/Android.bp | 2 + libs/binder/tests/binderRecordReplayTest.cpp | 127 ++++++++++++------ .../fuzzseeds/random_parcel_seeds.h | 2 +- .../parcel_fuzzer/random_parcel_seeds.cpp | 2 +- 4 files changed, 89 insertions(+), 44 deletions(-) diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 41856f9b79..cd3e7c0fef 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -77,6 +77,8 @@ cc_test { static_libs: [ "binderRecordReplayTestIface-cpp", "binderReadParcelIface-cpp", + "libbinder_random_parcel_seeds", + "libbinder_random_parcel", ], test_suites: ["general-tests"], require_root: true, diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp index 17d5c8a219..6773c95ed6 100644 --- a/libs/binder/tests/binderRecordReplayTest.cpp +++ b/libs/binder/tests/binderRecordReplayTest.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -23,6 +24,11 @@ #include #include #include + +#include +#include +#include + #include #include @@ -30,6 +36,7 @@ #include "parcelables/SingleDataParcelable.h" using namespace android; +using android::generateSeedsFromRecording; using android::binder::Status; using android::binder::debug::RecordedTransaction; using parcelables::SingleDataParcelable; @@ -84,6 +91,44 @@ public: GENERATE_GETTER_SETTER(SingleDataParcelableArray, std::vector); }; +std::vector retrieveData(base::borrowed_fd fd) { + struct stat fdStat; + EXPECT_TRUE(fstat(fd.get(), &fdStat) != -1); + EXPECT_TRUE(fdStat.st_size != 0); + + std::vector buffer(fdStat.st_size); + auto readResult = android::base::ReadFully(fd, buffer.data(), fdStat.st_size); + EXPECT_TRUE(readResult != 0); + return std::move(buffer); +} + +void replayFuzzService(const sp& binder, const RecordedTransaction& transaction) { + base::unique_fd seedFd(open("/data/local/tmp/replayFuzzService", + O_RDWR | O_CREAT | O_CLOEXEC | O_TRUNC, 0666)); + ASSERT_TRUE(seedFd.ok()); + + // generate corpus from this transaction. + generateSeedsFromRecording(seedFd, transaction); + + // Read the data which has been written to seed corpus + ASSERT_EQ(0, lseek(seedFd.get(), 0, SEEK_SET)); + std::vector seedData = retrieveData(seedFd); + + // use fuzzService to replay the corpus + FuzzedDataProvider provider(seedData.data(), seedData.size()); + fuzzService(binder, std::move(provider)); +} + +void replayBinder(const sp& binder, const RecordedTransaction& transaction) { + // TODO: move logic to replay RecordedTransaction into RecordedTransaction + Parcel data; + data.setData(transaction.getDataParcel().data(), transaction.getDataParcel().dataSize()); + auto result = binder->transact(transaction.getCode(), data, nullptr, transaction.getFlags()); + + // make sure recording does the thing we expect it to do + EXPECT_EQ(OK, result); +} + class BinderRecordReplayTest : public ::testing::Test { public: void SetUp() override { @@ -98,48 +143,46 @@ public: template void recordReplay(Status (IBinderRecordReplayTest::*set)(T), U recordedValue, Status (IBinderRecordReplayTest::*get)(U*), U changedValue) { - base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec", - O_RDWR | O_CREAT | O_CLOEXEC, 0666)); - ASSERT_TRUE(fd.ok()); - - // record a transaction - mBpBinder->startRecordingBinder(fd); - auto status = (*mInterface.*set)(recordedValue); - EXPECT_TRUE(status.isOk()); - mBpBinder->stopRecordingBinder(); - - // test transaction does the thing we expect it to do - U output; - status = (*mInterface.*get)(&output); - EXPECT_TRUE(status.isOk()); - EXPECT_EQ(output, recordedValue); - - // write over the existing state - status = (*mInterface.*set)(changedValue); - EXPECT_TRUE(status.isOk()); - - status = (*mInterface.*get)(&output); - EXPECT_TRUE(status.isOk()); - - EXPECT_EQ(output, changedValue); - - // replay transaction - ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET)); - std::optional transaction = RecordedTransaction::fromFile(fd); - ASSERT_NE(transaction, std::nullopt); - - // TODO: move logic to replay RecordedTransaction into RecordedTransaction - Parcel data; - data.setData(transaction->getDataParcel().data(), transaction->getDataParcel().dataSize()); - auto result = - mBpBinder->transact(transaction->getCode(), data, nullptr, transaction->getFlags()); - - // make sure recording does the thing we expect it to do - EXPECT_EQ(OK, result); - - status = (*mInterface.*get)(&output); - EXPECT_TRUE(status.isOk()); - EXPECT_EQ(output, recordedValue); + auto replayFunctions = {&replayBinder, &replayFuzzService}; + for (auto replayFunc : replayFunctions) { + base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec", + O_RDWR | O_CREAT | O_CLOEXEC, 0666)); + ASSERT_TRUE(fd.ok()); + + // record a transaction + mBpBinder->startRecordingBinder(fd); + auto status = (*mInterface.*set)(recordedValue); + EXPECT_TRUE(status.isOk()); + mBpBinder->stopRecordingBinder(); + + // test transaction does the thing we expect it to do + U output; + status = (*mInterface.*get)(&output); + EXPECT_TRUE(status.isOk()); + EXPECT_EQ(output, recordedValue); + + // write over the existing state + status = (*mInterface.*set)(changedValue); + EXPECT_TRUE(status.isOk()); + + status = (*mInterface.*get)(&output); + EXPECT_TRUE(status.isOk()); + + EXPECT_EQ(output, changedValue); + + // replay transaction + ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET)); + std::optional transaction = RecordedTransaction::fromFile(fd); + ASSERT_NE(transaction, std::nullopt); + + const RecordedTransaction& recordedTransaction = *transaction; + // call replay function with recorded transaction + (*replayFunc)(mBpBinder, recordedTransaction); + + status = (*mInterface.*get)(&output); + EXPECT_TRUE(status.isOk()); + EXPECT_EQ(output, recordedValue); + } } private: diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h index 6cceb06b82..5755239c8b 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h @@ -43,5 +43,5 @@ template void writeReversedBuffer(std::vector& integralBuffer, T val); } // namespace impl void generateSeedsFromRecording(base::borrowed_fd fd, - binder::debug::RecordedTransaction&& transaction); + const binder::debug::RecordedTransaction& transaction); } // namespace android diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp index 7c66683252..9e3e2aba77 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp @@ -65,7 +65,7 @@ void writeReversedBuffer(std::vector& integralBuffer, T val) { } // namespace impl void generateSeedsFromRecording(base::borrowed_fd fd, - binder::debug::RecordedTransaction&& transaction) { + const binder::debug::RecordedTransaction& transaction) { // Write Reserved bytes for future use std::vector reservedBytes(8); CHECK(WriteFully(fd, reservedBytes.data(), reservedBytes.size())) << fd.get(); -- GitLab From fc4b6ed24402460e52bb4dc2c672c65c2984f998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Do=C4=9Fancan=20Emek?= Date: Wed, 26 Jul 2023 15:24:04 +0000 Subject: [PATCH 0411/1187] Adding DPI to Traces To enable Flickr testing on large screen devices, a DPI value needed to be added on the traces Test: add_dpi_to_traces Bug: 284145257 Change-Id: I1063c971dbddabf670004147944ee398cd832c9a --- services/surfaceflinger/SurfaceFlinger.cpp | 7 +++++++ services/surfaceflinger/layerproto/display.proto | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4f7df3f285..86937f5829 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -6127,6 +6127,13 @@ google::protobuf::RepeatedPtrField SurfaceFlinger::dumpDisplayProt displayProto->set_id(display->getId().value); displayProto->set_name(display->getDisplayName()); displayProto->set_layer_stack(display->getLayerStack().id); + + if (!display->isVirtual()) { + const auto dpi = display->refreshRateSelector().getActiveMode().modePtr->getDpi(); + displayProto->set_dpi_x(dpi.x); + displayProto->set_dpi_y(dpi.y); + } + LayerProtoHelper::writeSizeToProto(display->getWidth(), display->getHeight(), [&]() { return displayProto->mutable_size(); }); LayerProtoHelper::writeToProto(display->getLayerStackSpaceRect(), [&]() { diff --git a/services/surfaceflinger/layerproto/display.proto b/services/surfaceflinger/layerproto/display.proto index c8cd9266a7..64de775b8b 100644 --- a/services/surfaceflinger/layerproto/display.proto +++ b/services/surfaceflinger/layerproto/display.proto @@ -35,4 +35,8 @@ message DisplayProto { TransformProto transform = 6; bool is_virtual = 7; + + double dpi_x = 8; + + double dpi_y = 9; } -- GitLab From 3799422958117fd1cee9127fda73a789dd1dcd1a Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Thu, 3 Aug 2023 12:16:28 +0000 Subject: [PATCH 0412/1187] Allow unsafe operations in unsafe functions in generated code. This will soon be denied by default, but we trust that what cxx does is correct. Bug: 290018030 Test: m rust Change-Id: If38e434a5d9e3320cfa7e6f686a078f7ee764435 --- libs/input/rust/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs index 688d941bf6..1d3c434f76 100644 --- a/libs/input/rust/lib.rs +++ b/libs/input/rust/lib.rs @@ -23,6 +23,7 @@ pub use input::{DeviceId, MotionAction, MotionFlags}; pub use input_verifier::InputVerifier; #[cxx::bridge(namespace = "android::input")] +#[allow(unsafe_op_in_unsafe_fn)] mod ffi { #[namespace = "android"] unsafe extern "C++" { -- GitLab From 870b3b992565885cd570e5ddee912a1511a27d69 Mon Sep 17 00:00:00 2001 From: Kevin Jeon Date: Thu, 3 Aug 2023 13:56:54 +0000 Subject: [PATCH 0413/1187] Revert "Update IsStrictRun to be framework-only" Revert submission 2681060-dumpstate-isstrictrun Reason for revert: This change has been successfully cherry-picked to udc-d1-dev, and can now be reverted in AOSP so that libdumpstateutil doesn't need a vendor variant. Reverted changes: /q/submissionid:2681060-dumpstate-isstrictrun Change-Id: Ie411d7002fb1d3bff7325cc1b3f11a34e509ab8e --- cmds/dumpstate/DumpstateUtil.cpp | 4 ---- cmds/dumpstate/DumpstateUtil.h | 4 ---- 2 files changed, 8 deletions(-) diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp index 484231225d..615701ccc1 100644 --- a/cmds/dumpstate/DumpstateUtil.cpp +++ b/cmds/dumpstate/DumpstateUtil.cpp @@ -207,9 +207,7 @@ std::string PropertiesHelper::build_type_ = ""; int PropertiesHelper::dry_run_ = -1; int PropertiesHelper::unroot_ = -1; int PropertiesHelper::parallel_run_ = -1; -#if !defined(__ANDROID_VNDK__) int PropertiesHelper::strict_run_ = -1; -#endif bool PropertiesHelper::IsUserBuild() { if (build_type_.empty()) { @@ -240,7 +238,6 @@ bool PropertiesHelper::IsParallelRun() { return parallel_run_ == 1; } -#if !defined(__ANDROID_VNDK__) bool PropertiesHelper::IsStrictRun() { if (strict_run_ == -1) { // Defaults to using stricter timeouts. @@ -248,7 +245,6 @@ bool PropertiesHelper::IsStrictRun() { } return strict_run_ == 1; } -#endif int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC))); diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h index 6049e3e19d..9e955e3c04 100644 --- a/cmds/dumpstate/DumpstateUtil.h +++ b/cmds/dumpstate/DumpstateUtil.h @@ -198,18 +198,14 @@ class PropertiesHelper { * will default to true. This results in shortened timeouts for flaky * sections. */ -#if !defined(__ANDROID_VNDK__) static bool IsStrictRun(); -#endif private: static std::string build_type_; static int dry_run_; static int unroot_; static int parallel_run_; -#if !defined(__ANDROID_VNDK__) static int strict_run_; -#endif }; /* -- GitLab From e219354953f3aca56ad3b5ff8641f99b0c0da481 Mon Sep 17 00:00:00 2001 From: Arthur Ishiguro Date: Thu, 3 Aug 2023 15:29:55 +0000 Subject: [PATCH 0414/1187] Fix test documentation error There is no guarantee that createDirectChannel will fail with a specific error code. Bug: 293817236 Test: None Change-Id: Ic1facb36f9289dce4aae79025b9c36db4fc5a352 --- services/sensorservice/tests/sensorservicetest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp index e939d51f5b..1baf397905 100644 --- a/services/sensorservice/tests/sensorservicetest.cpp +++ b/services/sensorservice/tests/sensorservicetest.cpp @@ -87,7 +87,7 @@ void testInvalidSharedMem_NoCrash(SensorManager &mgr) { int ret = mgr.createDirectChannel( kMemSize, ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY, resourceHandle); - // Should print -22 (BAD_VALUE) and the device runtime shouldn't restart + // Should not succeed (ret != OK) and the device runtime shouldn't restart printf("createInvalidDirectChannel=%d\n", ret); // Secondary test: correct channel creation & destruction (should print 0) -- GitLab From 4c70edcf974184c3e3864034217e4c12cf15757d Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Thu, 3 Aug 2023 16:02:51 +0000 Subject: [PATCH 0415/1187] Add missing safety comments. These will soon be required by a lint. Bug: 290018030 Test: m rust Change-Id: Iaa33bab93c458d963d45ec68daf243057b9f1c15 --- libs/nativewindow/rust/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index a5bcc6293a..0ed381eac5 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -199,6 +199,7 @@ mod ahardwarebuffer_tests { #[test] #[should_panic] fn take_from_raw_panics_on_null() { + // SAFETY: Passing a null pointer is safe, it should just panic. unsafe { AHardwareBuffer::take_from_raw(ptr::null_mut()) }; } @@ -216,9 +217,13 @@ mod ahardwarebuffer_tests { }; let mut raw_buffer_ptr = ptr::null_mut(); + // SAFETY: The pointers are valid because they come from references, and + // `AHardwareBuffer_allocate` doesn't retain them after it returns. let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) }; assert_eq!(status, 0); + // SAFETY: The pointer must be valid because it was just allocated successfully, and we + // don't use it after calling this. let buffer = unsafe { AHardwareBuffer::take_from_raw(raw_buffer_ptr as *mut c_void) }; assert_eq!(buffer.width(), 1024); } -- GitLab From db8c0f9c4d22835bf556f462035e9e64d815ba21 Mon Sep 17 00:00:00 2001 From: Jiakai Zhang Date: Thu, 3 Aug 2023 14:55:16 +0100 Subject: [PATCH 0416/1187] Skip "verify" packages in otapreopt. Since http://r.android.com/1590077, the runtime is able to use the vdex files even if the dependencies have changed. There is no more need to re-generate the vdex files. Bug: 199756868 Test: Run system/update_engine/scripts/update_device.py on a clean Pixel 5 device and see that the time spent on the otapreopt step went down from 7 minutes to 2.5 minutes. Change-Id: I455554ad905ec3513ce1fd4e5d209a43fa27dbac --- cmds/installd/dexopt.h | 5 ++++ cmds/installd/otapreopt.cpp | 46 ++++++++++++++++++++++++++++++++----- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h index 5cf402c54c..df02588a22 100644 --- a/cmds/installd/dexopt.h +++ b/cmds/installd/dexopt.h @@ -18,6 +18,7 @@ #define DEXOPT_H_ #include "installd_constants.h" +#include "unique_file.h" #include @@ -156,6 +157,10 @@ const char* select_execution_binary( // artifacts. int get_odex_visibility(const char* apk_path, const char* instruction_set, const char* oat_dir); +UniqueFile maybe_open_reference_profile(const std::string& pkgname, const std::string& dex_path, + const char* profile_name, bool profile_guided, + bool is_public, int uid, bool is_secondary_dex); + } // namespace installd } // namespace android diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index 407cb244e3..818fd8066e 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -14,20 +14,21 @@ ** limitations under the License. */ -#include #include -#include -#include -#include #include #include #include #include #include +#include #include #include -#include #include +#include +#include +#include +#include +#include #include #include @@ -47,6 +48,7 @@ #include "otapreopt_parameters.h" #include "otapreopt_utils.h" #include "system_properties.h" +#include "unique_file.h" #include "utils.h" #ifndef LOG_TAG @@ -87,6 +89,9 @@ static_assert(DEXOPT_GENERATE_APP_IMAGE == 1 << 12, "DEXOPT_GENERATE_APP_IMAGE u static_assert(DEXOPT_MASK == (0x3dfe | DEXOPT_IDLE_BACKGROUND_JOB), "DEXOPT_MASK unexpected."); +constexpr const char* kAotCompilerFilters[]{ + "space-profile", "space", "speed-profile", "speed", "everything-profile", "everything", +}; template static constexpr bool IsPowerOfTwo(T x) { @@ -415,6 +420,32 @@ private: return (strcmp(arg, "!") == 0) ? nullptr : arg; } + bool IsAotCompilation() const { + if (std::find(std::begin(kAotCompilerFilters), std::end(kAotCompilerFilters), + parameters_.compiler_filter) == std::end(kAotCompilerFilters)) { + return false; + } + + int dexopt_flags = parameters_.dexopt_flags; + bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0; + bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0; + bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0; + + if (profile_guided) { + UniqueFile reference_profile = + maybe_open_reference_profile(parameters_.pkgName, parameters_.apk_path, + parameters_.profile_name, profile_guided, + is_public, parameters_.uid, is_secondary_dex); + struct stat sbuf; + if (reference_profile.fd() == -1 || + (fstat(reference_profile.fd(), &sbuf) != -1 && sbuf.st_size == 0)) { + return false; + } + } + + return true; + } + bool ShouldSkipPreopt() const { // There's one thing we have to be careful about: we may/will be asked to compile an app // living in the system image. This may be a valid request - if the app wasn't compiled, @@ -439,9 +470,12 @@ private: // (This is ugly as it's the only thing where we need to understand the contents // of parameters_, but it beats postponing the decision or using the call- // backs to do weird things.) + + // In addition, no need to preopt for "verify". The existing vdex files in the OTA package + // and the /data partition will still be usable after the OTA update is applied. const char* apk_path = parameters_.apk_path; CHECK(apk_path != nullptr); - if (StartsWith(apk_path, android_root_)) { + if (StartsWith(apk_path, android_root_) || !IsAotCompilation()) { const char* last_slash = strrchr(apk_path, '/'); if (last_slash != nullptr) { std::string path(apk_path, last_slash - apk_path + 1); -- GitLab From 1b07384be5b36edab6b329f0c35cca423122b6a9 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Thu, 3 Aug 2023 19:12:49 +0000 Subject: [PATCH 0417/1187] Clean up EGL Loader. Removes deprecated driver loading path, clean up comments and misc. Bug: b/293503000 Test: boot Change-Id: Ibc62bf59ed7b0cb3671583d2af853c457977d1d1 --- opengl/libs/EGL/Loader.cpp | 107 ++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 56 deletions(-) diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 8d0eb590bf..1cb7718572 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -41,24 +41,44 @@ namespace android { /* * EGL userspace drivers must be provided either: * - as a single library: - * /vendor/lib/egl/libGLES.so + * /vendor/${LIB}/egl/libGLES.so * * - as separate libraries: - * /vendor/lib/egl/libEGL.so - * /vendor/lib/egl/libGLESv1_CM.so - * /vendor/lib/egl/libGLESv2.so + * /vendor/${LIB}/egl/libEGL.so + * /vendor/${LIB}/egl/libGLESv1_CM.so + * /vendor/${LIB}/egl/libGLESv2.so * * For backward compatibility and to facilitate the transition to * this new naming scheme, the loader will additionally look for: * - * /{vendor|system}/lib/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_*.so + * /vendor/${LIB}/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_${SUFFIX}.so * */ -Loader& Loader::getInstance() { - static Loader loader; - return loader; -} +#ifndef SYSTEM_LIB_PATH +#if defined(__LP64__) +#define SYSTEM_LIB_PATH "/system/lib64" +#else +#define SYSTEM_LIB_PATH "/system/lib" +#endif +#endif + +static const char* PERSIST_DRIVER_SUFFIX_PROPERTY = "persist.graphics.egl"; +static const char* RO_DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl"; +static const char* RO_BOARD_PLATFORM_PROPERTY = "ro.board.platform"; + +static const char* HAL_SUBNAME_KEY_PROPERTIES[3] = { + PERSIST_DRIVER_SUFFIX_PROPERTY, + RO_DRIVER_SUFFIX_PROPERTY, + RO_BOARD_PLATFORM_PROPERTY, +}; + +static const char* const VENDOR_LIB_EGL_DIR = +#if defined(__LP64__) + "/vendor/lib64/egl"; +#else + "/vendor/lib/egl"; +#endif static void* do_dlopen(const char* path, int mode) { ATRACE_CALL(); @@ -80,6 +100,17 @@ static int do_android_unload_sphal_library(void* dso) { return android_unload_sphal_library(dso); } +static void* load_wrapper(const char* path) { + void* so = do_dlopen(path, RTLD_NOW | RTLD_LOCAL); + ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror()); + return so; +} + +Loader& Loader::getInstance() { + static Loader loader; + return loader; +} + Loader::driver_t::driver_t(void* gles) { dso[0] = gles; @@ -123,30 +154,6 @@ Loader::Loader() Loader::~Loader() { } -static void* load_wrapper(const char* path) { - void* so = do_dlopen(path, RTLD_NOW | RTLD_LOCAL); - ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror()); - return so; -} - -#ifndef EGL_WRAPPER_DIR -#if defined(__LP64__) -#define EGL_WRAPPER_DIR "/system/lib64" -#else -#define EGL_WRAPPER_DIR "/system/lib" -#endif -#endif - -static const char* PERSIST_DRIVER_SUFFIX_PROPERTY = "persist.graphics.egl"; -static const char* RO_DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl"; -static const char* RO_BOARD_PLATFORM_PROPERTY = "ro.board.platform"; - -static const char* HAL_SUBNAME_KEY_PROPERTIES[3] = { - PERSIST_DRIVER_SUFFIX_PROPERTY, - RO_DRIVER_SUFFIX_PROPERTY, - RO_BOARD_PLATFORM_PROPERTY, -}; - // Check whether the loaded system drivers should be unloaded in order to // load ANGLE or the updatable graphics drivers. // If ANGLE namespace is set, it means the application is identified to run on top of ANGLE. @@ -306,13 +313,13 @@ void* Loader::open(egl_connection_t* cnx) { HAL_SUBNAME_KEY_PROPERTIES[2]); if (!cnx->libEgl) { - cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so"); + cnx->libEgl = load_wrapper(SYSTEM_LIB_PATH "/libEGL.so"); } if (!cnx->libGles1) { - cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so"); + cnx->libGles1 = load_wrapper(SYSTEM_LIB_PATH "/libGLESv1_CM.so"); } if (!cnx->libGles2) { - cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so"); + cnx->libGles2 = load_wrapper(SYSTEM_LIB_PATH "/libGLESv2.so"); } if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) { @@ -415,31 +422,19 @@ static void* load_system_driver(const char* kind, const char* suffix, const bool class MatchFile { public: static std::string find(const char* libraryName, const bool exact) { - const char* const searchPaths[] = { -#if defined(__LP64__) - "/vendor/lib64/egl", - "/system/lib64/egl" -#else - "/vendor/lib/egl", - "/system/lib/egl" -#endif - }; - - for (auto dir : searchPaths) { - std::string absolutePath; - if (find(absolutePath, libraryName, dir, exact)) { - return absolutePath; - } + std::string absolutePath; + if (findLibPath(absolutePath, libraryName, exact)) { + return absolutePath; } // Driver not found. gah. return std::string(); } private: - static bool find(std::string& result, - const std::string& pattern, const char* const search, bool exact) { + static bool findLibPath(std::string& result, const std::string& pattern, bool exact) { + const std::string vendorLibEglDirString = std::string(VENDOR_LIB_EGL_DIR); if (exact) { - std::string absolutePath = std::string(search) + "/" + pattern + ".so"; + std::string absolutePath = vendorLibEglDirString + "/" + pattern + ".so"; if (!access(absolutePath.c_str(), R_OK)) { result = absolutePath; return true; @@ -447,7 +442,7 @@ static void* load_system_driver(const char* kind, const char* suffix, const bool return false; } - DIR* d = opendir(search); + DIR* d = opendir(VENDOR_LIB_EGL_DIR); if (d != nullptr) { struct dirent* e; while ((e = readdir(d)) != nullptr) { @@ -460,7 +455,7 @@ static void* load_system_driver(const char* kind, const char* suffix, const bool } if (strstr(e->d_name, pattern.c_str()) == e->d_name) { if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) { - result = std::string(search) + "/" + e->d_name; + result = vendorLibEglDirString + "/" + e->d_name; closedir(d); return true; } -- GitLab From 689c80f4cb31d6903295aa69a706e7a2c16f8500 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Mon, 5 Jun 2023 17:49:32 -0400 Subject: [PATCH 0418/1187] HWComposer: setPowerMode to DOZE even if support is unknown If a display has not been turned on since boot, we do not know whether it supports doze. Rather than treating this as not supported, make Display::supportsDoze return an error if the capabilities have not been queried yet. If supportsDoze returns this error, try to set the mode to DOZE(_SUSPEND) anyway. This allows properly waking from AOD. If the call to Display::setPowerMode fails, this means it truly is not supported, so fallback to the old behavior of turning it ON. Fixes: 274722476 Test: manual Test: GraphicsComposerAidlTest#SetPowerModeUnsupported Change-Id: Ia88603565713ea4b6ec5142b693d2df1302131ea --- .../surfaceflinger/DisplayHardware/HWC2.cpp | 8 +++++++ .../DisplayHardware/HWComposer.cpp | 22 ++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index aaf2523338..0c2b77de7d 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -311,6 +311,14 @@ bool Display::hasCapability(DisplayCapability capability) const { } Error Display::supportsDoze(bool* outSupport) const { + { + std::scoped_lock lock(mDisplayCapabilitiesMutex); + if (!mDisplayCapabilities) { + // The display has not turned on since boot, so DOZE support is unknown. + ALOGW("%s: haven't queried capabilities yet!", __func__); + return Error::NO_RESOURCES; + } + } *outSupport = hasCapability(DisplayCapability::DOZE); return Error::NONE; } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 3177b33538..a9bb928f59 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -616,19 +616,29 @@ status_t HWComposer::setPowerMode(PhysicalDisplayId displayId, hal::PowerMode mo ALOGV("setPowerMode: Calling HWC %s", to_string(mode).c_str()); { bool supportsDoze = false; - auto error = hwcDisplay->supportsDoze(&supportsDoze); - if (error != hal::Error::NONE) { - LOG_HWC_ERROR("supportsDoze", error, displayId); - } + const auto queryDozeError = hwcDisplay->supportsDoze(&supportsDoze); - if (!supportsDoze) { + // queryDozeError might be NO_RESOURCES, in the case of a display that has never + // been turned on. In that case, attempt to set to DOZE anyway. + if (!supportsDoze && queryDozeError == hal::Error::NONE) { mode = hal::PowerMode::ON; } - error = hwcDisplay->setPowerMode(mode); + auto error = hwcDisplay->setPowerMode(mode); if (error != hal::Error::NONE) { LOG_HWC_ERROR(("setPowerMode(" + to_string(mode) + ")").c_str(), error, displayId); + // If the display had never been turned on, so its doze + // support was unknown, it may truly not support doze. Try + // switching it to ON instead. + if (queryDozeError == hal::Error::NO_RESOURCES) { + ALOGD("%s: failed to set %s to %s. Trying again with ON", __func__, + to_string(displayId).c_str(), to_string(mode).c_str()); + error = hwcDisplay->setPowerMode(hal::PowerMode::ON); + if (error != hal::Error::NONE) { + LOG_HWC_ERROR("setPowerMode(ON)", error, displayId); + } + } } } break; -- GitLab From 6f209e2d55e4ab5381eb21b311f14a38d5f20a16 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 4 Aug 2023 16:33:23 +0000 Subject: [PATCH 0419/1187] [sf] Fix wakeup related to CE#needsAnotherUpdate Layers track if they have a frame ready to be latched using hasReadyFrame. Once the buffer is latched for a layer, the states are cleared so hasReadyFrame is only true if we have another buffer to be latched (not possible) or if the auto refresh flag is set. In post composition, this flag is checked to schedule a commit. With the new frontend, we update the snapshot once every commit. This means hasReadyFrame should only track the auto refresh state. Bug: 238781169 Test: atest android.graphics.cts.FrameRateOverrideTest#testAppBackpressure --rerun-until-failure with mixed gsi builds Change-Id: I73fe6d69c5f34e4ce5d0efc6b7f39ae72c50b8aa --- .../surfaceflinger/FrontEnd/LayerSnapshot.cpp | 5 ++--- .../surfaceflinger/FrontEnd/LayerSnapshot.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 20 ++++++++++--------- services/surfaceflinger/SurfaceFlinger.h | 2 ++ 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index d389a799ad..8dbe2514d6 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -345,10 +345,9 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate clientChanges = requested.what; changes = requested.changes; contentDirty = requested.what & layer_state_t::CONTENT_DIRTY; - // TODO(b/238781169) scope down the changes to only buffer updates. - hasReadyFrame = requested.hasReadyFrame(); + hasReadyFrame = requested.autoRefresh; sidebandStreamHasFrame = requested.hasSidebandStreamFrame(); - updateSurfaceDamage(requested, hasReadyFrame, forceFullDamage, surfaceDamage); + updateSurfaceDamage(requested, requested.hasReadyFrame(), forceFullDamage, surfaceDamage); if (forceUpdate || requested.what & layer_state_t::eTransparentRegionChanged) { transparentRegionHint = requested.transparentRegion; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 1afcef9e44..19477fa419 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -79,7 +79,7 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { std::shared_ptr externalTexture; gui::LayerMetadata layerMetadata; gui::LayerMetadata relativeLayerMetadata; - bool hasReadyFrame; + bool hasReadyFrame; // used in post composition to check if there is another frame ready ui::Transform localTransformInverse; gui::WindowInfo inputInfo; ui::Transform localTransform; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9de623fff9..31bdf20116 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2363,19 +2363,20 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, mLayersWithBuffersRemoved.emplace(it->second); } it->second->latchBufferImpl(unused, latchTime, bgColorOnly); + newDataLatched = true; mLayersWithQueuedFrames.emplace(it->second); + mLayersIdsWithQueuedFrames.emplace(it->second->sequence); } - for (auto& snapshot : mLayerSnapshotBuilder.getSnapshots()) { - updateLayerHistory(*snapshot); - if (!snapshot->hasReadyFrame) continue; - newDataLatched = true; - if (!snapshot->isVisible) break; - + mLayerSnapshotBuilder.forEachVisibleSnapshot([&](const frontend::LayerSnapshot& snapshot) { + updateLayerHistory(snapshot); + if (mLayersIdsWithQueuedFrames.find(snapshot.path.id) == + mLayersIdsWithQueuedFrames.end()) + return; Region visibleReg; - visibleReg.set(snapshot->transformedBoundsWithoutTransparentRegion); - invalidateLayerStack(snapshot->outputFilter, visibleReg); - } + visibleReg.set(snapshot.transformedBoundsWithoutTransparentRegion); + invalidateLayerStack(snapshot.outputFilter, visibleReg); + }); for (auto& destroyedLayer : mLayerLifecycleManager.getDestroyedLayers()) { mLegacyLayers.erase(destroyedLayer->id); @@ -2727,6 +2728,7 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( mScheduler->modulateVsync({}, &VsyncModulator::onDisplayRefresh, hasGpuUseOrReuse); mLayersWithQueuedFrames.clear(); + mLayersIdsWithQueuedFrames.clear(); if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { // This will block and should only be used for debugging. addToLayerTracing(mVisibleRegionsDirty, pacesetterTarget.frameBeginTime(), vsyncId); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 4374f9408f..e28f23e1ac 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1206,6 +1206,8 @@ private: // latched. std::unordered_set, SpHash> mLayersWithQueuedFrames; std::unordered_set, SpHash> mLayersWithBuffersRemoved; + std::unordered_set mLayersIdsWithQueuedFrames; + // Tracks layers that need to update a display's dirty region. std::vector> mLayersPendingRefresh; // Sorted list of layers that were composed during previous frame. This is used to -- GitLab From f2afa6b8c2625158ef80c57b1c84a15f70889d81 Mon Sep 17 00:00:00 2001 From: Lais Andrade Date: Fri, 4 Aug 2023 18:27:39 +0100 Subject: [PATCH 0420/1187] Fix VibratorCallbackSchedulerTest flakiness Add test timeout to wait for scheduler to trigger callbacks before failing. Also update scheduled callback durations to reduce flakiness. Bug: 293623689 Test: atest VibratorCallbackSchedulerTest Change-Id: I49a9cae3f1622a4902ae9e56b37892060eba5c91 --- .../test/VibratorCallbackSchedulerTest.cpp | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp index 4c0910a75e..106ab9e858 100644 --- a/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp +++ b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp @@ -38,6 +38,9 @@ using namespace testing; // ------------------------------------------------------------------------------------------------- +// Delay allowed for the scheduler to process callbacks during this test. +static const auto TEST_TIMEOUT = 50ms; + class VibratorCallbackSchedulerTest : public Test { public: void SetUp() override { @@ -67,46 +70,51 @@ protected: return std::vector(mExpiredCallbacks); } - bool waitForCallbacks(uint32_t callbackCount, milliseconds timeout) { - time_point expiration = steady_clock::now() + timeout; + int32_t waitForCallbacks(int32_t callbackCount, milliseconds timeout) { + time_point expiration = steady_clock::now() + timeout + TEST_TIMEOUT; + int32_t expiredCallbackCount = 0; while (steady_clock::now() < expiration) { std::lock_guard lock(mMutex); - if (callbackCount <= mExpiredCallbacks.size()) { - return true; + expiredCallbackCount = mExpiredCallbacks.size(); + if (callbackCount <= expiredCallbackCount) { + return expiredCallbackCount; } mCondition.wait_until(mMutex, expiration); } - return false; + return expiredCallbackCount; } }; // ------------------------------------------------------------------------------------------------- TEST_F(VibratorCallbackSchedulerTest, TestScheduleRunsOnlyAfterDelay) { - mScheduler->schedule(createCallback(1), 15ms); + time_point startTime = steady_clock::now(); + mScheduler->schedule(createCallback(1), 50ms); - // Not triggered before delay. - ASSERT_FALSE(waitForCallbacks(1, 10ms)); - ASSERT_TRUE(getExpiredCallbacks().empty()); + ASSERT_EQ(1, waitForCallbacks(1, 50ms)); + time_point callbackTime = steady_clock::now(); - ASSERT_TRUE(waitForCallbacks(1, 10ms)); + // Callback happened at least 50ms after the beginning of the test. + ASSERT_TRUE(startTime + 50ms <= callbackTime); ASSERT_THAT(getExpiredCallbacks(), ElementsAre(1)); } TEST_F(VibratorCallbackSchedulerTest, TestScheduleMultipleCallbacksRunsInDelayOrder) { - mScheduler->schedule(createCallback(1), 10ms); - mScheduler->schedule(createCallback(2), 5ms); - mScheduler->schedule(createCallback(3), 1ms); + // Schedule first callbacks long enough that all 3 will be scheduled together and run in order. + mScheduler->schedule(createCallback(1), 50ms); + mScheduler->schedule(createCallback(2), 40ms); + mScheduler->schedule(createCallback(3), 10ms); - ASSERT_TRUE(waitForCallbacks(3, 15ms)); + ASSERT_EQ(3, waitForCallbacks(3, 50ms)); ASSERT_THAT(getExpiredCallbacks(), ElementsAre(3, 2, 1)); } TEST_F(VibratorCallbackSchedulerTest, TestDestructorDropsPendingCallbacksAndKillsThread) { - mScheduler->schedule(createCallback(1), 5ms); + // Schedule callback long enough that scheduler will be destroyed while it's still scheduled. + mScheduler->schedule(createCallback(1), 50ms); mScheduler.reset(nullptr); - // Should time out waiting for callback to run. - ASSERT_FALSE(waitForCallbacks(1, 10ms)); + // Should timeout waiting for callback to run. + ASSERT_EQ(0, waitForCallbacks(1, 50ms)); ASSERT_TRUE(getExpiredCallbacks().empty()); } -- GitLab From 5ce0c7e677d0a76f072e142a3412211a8620f84a Mon Sep 17 00:00:00 2001 From: Nolan Scobie Date: Fri, 4 Aug 2023 18:21:53 +0000 Subject: [PATCH 0421/1187] Add SurfaceFlinger component to OWNERS for SF, RE, and libgui Raised on b/288345762#comment3 go/xts-owners-policy is XTS-specific, but the syntax is applicable Bug: N/A Test: N/A Change-Id: I97e95ad89f0226e196675cbbf7bf0fd3a948b5a2 --- libs/gui/OWNERS | 2 ++ libs/renderengine/OWNERS | 2 ++ services/surfaceflinger/OWNERS | 2 ++ 3 files changed, 6 insertions(+) diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS index 826a418aab..070f6bf532 100644 --- a/libs/gui/OWNERS +++ b/libs/gui/OWNERS @@ -1,3 +1,5 @@ +# Bug component: 1075131 + chrisforbes@google.com jreck@google.com diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS index 5d23a5ef8d..66e1aa1ca1 100644 --- a/libs/renderengine/OWNERS +++ b/libs/renderengine/OWNERS @@ -1,3 +1,5 @@ +# Bug component: 1075131 + adyabr@google.com alecmouri@google.com djsollen@google.com diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS index 473409715f..3270e4c95c 100644 --- a/services/surfaceflinger/OWNERS +++ b/services/surfaceflinger/OWNERS @@ -1,3 +1,5 @@ +# Bug component: 1075131 + adyabr@google.com alecmouri@google.com chaviw@google.com -- GitLab From 9f64cc89030657b250977e6d0ebeeb5482a4bcda Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Fri, 4 Aug 2023 12:26:30 -0400 Subject: [PATCH 0422/1187] Remove redundant check for blurRegions to force client composition If there are blurRegions on a Layer, we *should* force client composition, but this is already handled in Output::updateCompositionState + Output::findLayerRequestingBackgroundComposition. The check on Layer is redundant, so remove it. Moreover, the check on Layer doesn't do enough. It doesn't handle blur- behind, and it doesn't force the Layers below to use client composition, which is also necessary. This allows us to remove blurs and client composition from protected surfaces on devices that do not have EGL_EXT_protected_content. (See I9763eb22884e611568b36b2e221ee6d75ec3363e.) Bug: 196271643 Test: OutputUpdateAndWriteCompositionStateTest Change-Id: I055d221b1fcb36fb5fbc6747c353d3fb72f4d684 --- services/surfaceflinger/FrontEnd/LayerSnapshot.cpp | 2 +- services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp | 2 +- services/surfaceflinger/Layer.cpp | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index d389a799ad..8f3606667d 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -481,7 +481,7 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate layer_state_t::eApiChanged | layer_state_t::eShadowRadiusChanged | layer_state_t::eBlurRegionsChanged | layer_state_t::eStretchChanged)) { forceClientComposition = isHdrY410 || shadowSettings.length > 0 || - requested.blurRegions.size() > 0 || stretchEffect.hasEffect(); + stretchEffect.hasEffect(); } if (forceUpdate || diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 23cfe928f5..cf39187f0d 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -871,7 +871,7 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a // computed snapshot properties snapshot.forceClientComposition = snapshot.isHdrY410 || snapshot.shadowSettings.length > 0 || - requested.blurRegions.size() > 0 || snapshot.stretchEffect.hasEffect(); + snapshot.stretchEffect.hasEffect(); snapshot.contentOpaque = snapshot.isContentOpaque(); snapshot.isOpaque = snapshot.contentOpaque && !snapshot.roundedCorner.hasRoundedCorners() && snapshot.color.a == 1.f; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3a41f1599b..83d8d9f81d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -659,8 +659,7 @@ void Layer::preparePerFrameCompositionState() { // Force client composition for special cases known only to the front-end. // Rounded corners no longer force client composition, since we may use a // hole punch so that the layer will appear to have rounded corners. - if (isHdrY410() || drawShadows() || drawingState.blurRegions.size() > 0 || - snapshot->stretchEffect.hasEffect()) { + if (isHdrY410() || drawShadows() || snapshot->stretchEffect.hasEffect()) { snapshot->forceClientComposition = true; } // If there are no visible region changes, we still need to update blur parameters. -- GitLab From c1dbfcb35a5b2720afb3e5135ad6f7850159422d Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Mon, 21 Mar 2022 16:48:10 -0400 Subject: [PATCH 0423/1187] Avoid blurring and rounded corners without EGL_EXT_protected_content If the GPU does not support protected content, avoid forcing client composition for protected layers. This means removing rounded corners. It also means avoiding blurring when it would require blurring a layer with protected content. Bug: 196271643 Test: manual (Netflix, YouTube, ExoDefault) with modified RenderEngine::supportsProtectedContent() Change-Id: I9763eb22884e611568b36b2e221ee6d75ec3363e --- services/surfaceflinger/CompositionEngine/src/Output.cpp | 8 +++++++- services/surfaceflinger/Layer.cpp | 7 +++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index d4230f5575..0b11e747ca 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -895,13 +895,19 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const { compositionengine::OutputLayer* layerRequestingBgComposition = nullptr; for (auto* layer : getOutputLayersOrderedByZ()) { - auto* compState = layer->getLayerFE().getCompositionState(); + const auto* compState = layer->getLayerFE().getCompositionState(); // If any layer has a sideband stream, we will disable blurs. In that case, we don't // want to force client composition because of the blur. if (compState->sidebandStream != nullptr) { return nullptr; } + + // If RenderEngine cannot render protected content, we cannot blur. + if (compState->hasProtectedContent && + !getCompositionEngine().getRenderEngine().supportsProtectedContent()) { + return nullptr; + } if (compState->isOpaque) { continue; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 83d8d9f81d..6c9311370e 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2110,6 +2110,13 @@ const std::vector Layer::getBlurRegions() const { } RoundedCornerState Layer::getRoundedCornerState() const { + // Today's DPUs cannot do rounded corners. If RenderEngine cannot render + // protected content, remove rounded corners from protected content so it + // can be rendered by the DPU. + if (isProtected() && !mFlinger->getRenderEngine().supportsProtectedContent()) { + return {}; + } + // Get parent settings RoundedCornerState parentSettings; const auto& parent = mDrawingParent.promote(); -- GitLab From d571b48458d420f3cdebac044c85c2fb673c327d Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 24 Jul 2023 16:41:28 +0000 Subject: [PATCH 0424/1187] [sf] enable new sf frontend Change-Id: Ia83ccd4dac8c8ce6ccc00ee3912bf7ee7d64c673 Test: presubmit Bug: 238781169 --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 31bdf20116..baa35c9cb8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -484,7 +484,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false); mLayerLifecycleManagerEnabled = - base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false); + base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, true); mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled || base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); } -- GitLab From a40046918a046a5996bb441bbb3d87eab7ed9230 Mon Sep 17 00:00:00 2001 From: Carlos Martinez Romero Date: Thu, 20 Jul 2023 21:34:15 +0000 Subject: [PATCH 0425/1187] Added the initial traits for bufferstreams. Bug: 290409936 Pair: jshargo Test: Pending tests Change-Id: I4d1344650bf7ce2a677e21e4c69e5884230b53a3 --- libs/bufferstreams/rust/Android.bp | 5 +- libs/bufferstreams/rust/src/lib.rs | 134 +++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 2 deletions(-) diff --git a/libs/bufferstreams/rust/Android.bp b/libs/bufferstreams/rust/Android.bp index 95a85b550f..ff951487bc 100644 --- a/libs/bufferstreams/rust/Android.bp +++ b/libs/bufferstreams/rust/Android.bp @@ -17,7 +17,8 @@ rust_library { crate_name: "bufferstreams", srcs: ["src/lib.rs"], edition: "2021", - vendor_available: true, - host_supported: true, + rlibs: [ + "libnativewindow_rs", + ], min_sdk_version: "30", } diff --git a/libs/bufferstreams/rust/src/lib.rs b/libs/bufferstreams/rust/src/lib.rs index 51f1c73c49..1d321c833d 100644 --- a/libs/bufferstreams/rust/src/lib.rs +++ b/libs/bufferstreams/rust/src/lib.rs @@ -14,9 +14,143 @@ //! libbufferstreams: Reactive Streams for Graphics Buffers +use nativewindow::*; +use std::sync::{Arc, Weak}; +use std::time::Instant; + /// This function will print Hello World. #[no_mangle] pub extern "C" fn hello() -> bool { println!("Hello world."); true } + +/// BufferPublishers provide buffers to BufferSusbscribers. Depending on the +/// particular object in question, these could be allocated locally or provided +/// over IPC. +/// +/// BufferPublishers are required to adhere to the following, based on the +/// reactive streams specification: +/// * The total number of on_next´s signalled by a Publisher to a Subscriber +/// MUST be less than or equal to the total number of elements requested by that +/// Subscriber´s Subscription at all times. +/// * A Publisher MAY signal fewer on_next than requested and terminate the +/// Subscription by calling on_complete or on_error. +/// * on_subscribe, on_next, on_error and on_complete signaled to a Subscriber +/// MUST be signaled serially. +/// * If a Publisher fails it MUST signal an on_error. +/// * If a Publisher terminates successfully (finite stream) it MUST signal an +/// on_complete. +/// * If a Publisher signals either on_error or on_complete on a Subscriber, +/// that Subscriber’s Subscription MUST be considered cancelled. +/// * Once a terminal state has been signaled (on_error, on_complete) it is +/// REQUIRED that no further signals occur. +/// * If a Subscription is cancelled its Subscriber MUST eventually stop being +/// signaled. +/// * A Publisher MAY support multiple Subscribers and decides whether each +/// Subscription is unicast or multicast. +pub trait BufferPublisher { + /// This function will create the subscription between the publisher and + /// the subscriber. + fn subscribe(&self, subscriber: Weak); +} + +/// BufferSubscribers can subscribe to BufferPublishers. They can request Frames +/// via the BufferSubscription they get from the publisher, then receive Frames +/// via on_next. +/// +/// BufferSubcribers are required to adhere to the following, based on the +/// reactive streams specification: +/// * The total number of on_next´s signalled by a Publisher to a Subscriber +/// MUST be less than or equal to the total number of elements requested by that +/// Subscriber´s Subscription at all times. +/// * A Publisher MAY signal fewer on_next than requested and terminate the +/// Subscription by calling on_complete or on_error. +/// * on_subscribe, on_next, on_error and on_complete signaled to a Subscriber +/// MUST be signaled serially. +/// * If a Publisher fails it MUST signal an on_error. +/// * If a Publisher terminates successfully (finite stream) it MUST signal an +/// on_complete. +/// * If a Publisher signals either on_error or on_complete on a Subscriber, +/// that Subscriber’s Subscription MUST be considered cancelled. +/// * Once a terminal state has been signaled (on_error, on_complete) it is +/// REQUIRED that no further signals occur. +/// * If a Subscription is cancelled its Subscriber MUST eventually stop being +/// signaled. +/// * Publisher.subscribe MAY be called as many times as wanted but MUST be +/// with a different Subscriber each time. +/// * A Publisher MAY support multiple Subscribers and decides whether each +/// Subscription is unicast or multicast. +pub trait BufferSubscriber { + /// This function will be called at the beginning of the subscription. + fn on_subscribe(&self, subscription: Arc); + /// This function will be called for buffer that comes in. + fn on_next(&self, frame: Frame); + /// This function will be called in case of an error. + fn on_error(&self, error: BufferError); + /// This function will be called on finite streams when done. + fn on_complete(&self); +} + +/// BufferSubscriptions serve as the bridge between BufferPublishers and +/// BufferSubscribers. BufferSubscribers receive a BufferSubscription when they +/// subscribe to a BufferPublisher via on_subscribe. +/// This object is to be used by the BufferSubscriber to cancel its subscription +/// or request more buffers. +/// +/// BufferSubcriptions are required to adhere to the following, based on the +/// reactive streams specification: +/// * Subscription.request and Subscription.cancel MUST only be called inside +/// of its Subscriber context. +/// * The Subscription MUST allow the Subscriber to call Subscription.request +/// synchronously from within on_next or on_subscribe. +/// * Subscription.request MUST place an upper bound on possible synchronous +/// recursion between Publisher and Subscriber. +/// * Subscription.request SHOULD respect the responsivity of its caller by +/// returning in a timely manner. +/// * Subscription.cancel MUST respect the responsivity of its caller by +/// returning in a timely manner, MUST be idempotent and MUST be thread-safe. +/// * After the Subscription is cancelled, additional +/// Subscription.request(n: u64) MUST be NOPs. +/// * After the Subscription is cancelled, additional Subscription.cancel() +/// MUST be NOPs. +/// * While the Subscription is not cancelled, Subscription.request(n: u64) +/// MUST register the given number of additional elements to be produced to the +/// respective subscriber. +/// * While the Subscription is not cancelled, Subscription.request(n: u64) +/// MUST signal on_error if the argument is <= 0. The cause message SHOULD +/// explain that non-positive request signals are illegal. +/// * While the Subscription is not cancelled, Subscription.request(n: u64) +/// MAY synchronously call on_next on this (or other) subscriber(s). +/// * While the Subscription is not cancelled, Subscription.request(n: u64) +/// MAY synchronously call on_complete or on_error on this (or other) +/// subscriber(s). +/// * While the Subscription is not cancelled, Subscription.cancel() MUST +/// request the Publisher to eventually stop signaling its Subscriber. The +/// operation is NOT REQUIRED to affect the Subscription immediately. +/// * While the Subscription is not cancelled, Subscription.cancel() MUST +/// request the Publisher to eventually drop any references to the corresponding +/// subscriber. +/// * While the Subscription is not cancelled, calling Subscription.cancel MAY +/// cause the Publisher, if stateful, to transition into the shut-down state if +/// no other Subscription exists at this point. +/// * Calling Subscription.cancel MUST return normally. +/// * Calling Subscription.request MUST return normally. +pub trait BufferSubscription { + /// request + fn request(&self, n: u64); + /// cancel + fn cancel(&self); +} +/// Type used to describe errors produced by subscriptions. +type BufferError = Box; + +/// Struct used to contain the buffer. +pub struct Frame { + /// A handle to the C buffer interface. + pub buffer: AHardwareBuffer, + /// The time at which the buffer was dispatched. + pub present_time: Instant, + /// A fence used for reading/writing safely. + pub fence: i32, +} -- GitLab From e731c4900ba0bd9872da6645720ebb8963e2e54b Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Fri, 4 Aug 2023 11:36:41 +0900 Subject: [PATCH 0426/1187] Add IntoBinderResult trait to simplify binder error handling Before this change, returning binder::Result was a bit cumbersome, and the integration with anyhow was not nice: ``` use anyhow::{Context, Result}; fn file_exists(name: &str) -> binder::Result { std::fs::metadata(name) .with_context("cannot find {}") .map_err(|e| { Status::new_service_specific_err_str( NOT_FOUND, Some("{:?}", e) ) })? } ``` With this change, above can be simplified as below: ``` use binder::IntoBinderResult; use anyhow::{Context, Result}; fn file_exists(name: &str) -> binder::Result { std::fs::metadata(name) .with_context("cannot find {}", name) .or_service_specific_exception(NOT_FOUND)? } ``` Bug: 294348831 Test: atest libbinder_rs-internal_test Change-Id: I4c669ac39c01f648f68ecf6db7e088edec034825 --- libs/binder/rust/src/error.rs | 150 ++++++++++++++++++++++++++++++++++ libs/binder/rust/src/lib.rs | 2 +- 2 files changed, 151 insertions(+), 1 deletion(-) diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs index 8d9ce0e731..eb04cc3153 100644 --- a/libs/binder/rust/src/error.rs +++ b/libs/binder/rust/src/error.rs @@ -370,6 +370,94 @@ unsafe impl AsNative for Status { } } +/// A conversion from `std::result::Result` to `binder::Result`. If this type is `Ok(T)`, +/// it's returned as is. If this type is `Err(E)`, `E` is converted into `Status` which can be +/// either a general binder exception, or a service-specific exception. +/// +/// # Examples +/// +/// ``` +/// // std::io::Error is formatted as the exception's message +/// fn file_exists(name: &str) -> binder::Result { +/// std::fs::metadata(name) +/// .or_service_specific_exception(NOT_FOUND)? +/// } +/// +/// // A custom function is used to create the exception's message +/// fn file_exists(name: &str) -> binder::Result { +/// std::fs::metadata(name) +/// .or_service_specific_exception_with(NOT_FOUND, +/// |e| format!("file {} not found: {:?}", name, e))? +/// } +/// +/// // anyhow::Error is formatted as the exception's message +/// use anyhow::{Context, Result}; +/// fn file_exists(name: &str) -> binder::Result { +/// std::fs::metadata(name) +/// .context("file {} not found") +/// .or_service_specific_exception(NOT_FOUND)? +/// } +/// +/// // General binder exceptions can be created similarly +/// fn file_exists(name: &str) -> binder::Result { +/// std::fs::metadata(name) +/// .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT)? +/// } +/// ``` +pub trait IntoBinderResult { + /// Converts the embedded error into a general binder exception of code `exception`. The + /// message of the exception is set by formatting the error for debugging. + fn or_binder_exception(self, exception: ExceptionCode) -> result::Result; + + /// Converts the embedded error into a general binder exception of code `exception`. The + /// message of the exception is set by lazily evaluating the `op` function. + fn or_binder_exception_with, O: FnOnce(E) -> M>( + self, + exception: ExceptionCode, + op: O, + ) -> result::Result; + + /// Converts the embedded error into a service-specific binder exception. `error_code` is used + /// to distinguish different service-specific binder exceptions. The message of the exception + /// is set by formatting the error for debugging. + fn or_service_specific_exception(self, error_code: i32) -> result::Result; + + /// Converts the embedded error into a service-specific binder exception. `error_code` is used + /// to distinguish different service-specific binder exceptions. The message of the exception + /// is set by lazily evaluating the `op` function. + fn or_service_specific_exception_with, O: FnOnce(E) -> M>( + self, + error_code: i32, + op: O, + ) -> result::Result; +} + +impl IntoBinderResult for result::Result { + fn or_binder_exception(self, exception: ExceptionCode) -> result::Result { + self.or_binder_exception_with(exception, |e| format!("{:?}", e)) + } + + fn or_binder_exception_with, O: FnOnce(E) -> M>( + self, + exception: ExceptionCode, + op: O, + ) -> result::Result { + self.map_err(|e| Status::new_exception_str(exception, Some(op(e)))) + } + + fn or_service_specific_exception(self, error_code: i32) -> result::Result { + self.or_service_specific_exception_with(error_code, |e| format!("{:?}", e)) + } + + fn or_service_specific_exception_with, O: FnOnce(E) -> M>( + self, + error_code: i32, + op: O, + ) -> result::Result { + self.map_err(|e| Status::new_service_specific_error_str(error_code, Some(op(e)))) + } +} + #[cfg(test)] mod tests { use super::*; @@ -406,4 +494,66 @@ mod tests { assert_eq!(status.service_specific_error(), 0); assert_eq!(status.get_description(), "Status(-5, EX_ILLEGAL_STATE): ''".to_string()); } + + #[test] + fn convert_to_service_specific_exception() { + let res: std::result::Result<(), Status> = + Err("message").or_service_specific_exception(-42); + + assert!(res.is_err()); + let status = res.unwrap_err(); + assert_eq!(status.exception_code(), ExceptionCode::SERVICE_SPECIFIC); + assert_eq!(status.service_specific_error(), -42); + assert_eq!( + status.get_description(), + "Status(-8, EX_SERVICE_SPECIFIC): '-42: \"message\"'".to_string() + ); + } + + #[test] + fn convert_to_service_specific_exception_with() { + let res: std::result::Result<(), Status> = Err("message") + .or_service_specific_exception_with(-42, |e| format!("outer message: {:?}", e)); + + assert!(res.is_err()); + let status = res.unwrap_err(); + assert_eq!(status.exception_code(), ExceptionCode::SERVICE_SPECIFIC); + assert_eq!(status.service_specific_error(), -42); + assert_eq!( + status.get_description(), + "Status(-8, EX_SERVICE_SPECIFIC): '-42: outer message: \"message\"'".to_string() + ); + } + + #[test] + fn convert_to_binder_exception() { + let res: std::result::Result<(), Status> = + Err("message").or_binder_exception(ExceptionCode::ILLEGAL_STATE); + + assert!(res.is_err()); + let status = res.unwrap_err(); + assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE); + assert_eq!(status.service_specific_error(), 0); + assert_eq!( + status.get_description(), + "Status(-5, EX_ILLEGAL_STATE): '\"message\"'".to_string() + ); + } + + #[test] + fn convert_to_binder_exception_with() { + let res: std::result::Result<(), Status> = Err("message") + .or_binder_exception_with(ExceptionCode::ILLEGAL_STATE, |e| { + format!("outer message: {:?}", e) + }); + + assert!(res.is_err()); + let status = res.unwrap_err(); + assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE); + assert_eq!(status.service_specific_error(), 0); + assert_eq!( + status.get_description(), + "Status(-5, EX_ILLEGAL_STATE): 'outer message: \"message\"'".to_string() + ); + } } diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs index 0c8b48f1f5..8841fe640b 100644 --- a/libs/binder/rust/src/lib.rs +++ b/libs/binder/rust/src/lib.rs @@ -106,7 +106,7 @@ use binder_ndk_sys as sys; pub use crate::binder_async::{BinderAsyncPool, BoxFuture}; pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak}; -pub use error::{ExceptionCode, Status, StatusCode}; +pub use error::{ExceptionCode, IntoBinderResult, Status, StatusCode}; pub use native::{ add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service, LazyServiceGuard, -- GitLab From 994761f2ddc1b266158f72ef3d15c153bceeb9f1 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 4 Aug 2023 21:50:55 +0000 Subject: [PATCH 0427/1187] Remove Y410 fields from SurfaceFlinger Ever since RenderEngine started to use skia this was never used. It will have been three releases since then, so finish cleaning this up. Bug: 130025362 Test: builds Change-Id: Ib0328903e04d754e08b6960949898b282e3d529b --- libs/renderengine/gl/GLESRenderEngine.cpp | 6 ---- libs/renderengine/gl/GLESRenderEngine.h | 1 - libs/renderengine/gl/ProgramCache.cpp | 32 +++---------------- libs/renderengine/gl/ProgramCache.h | 6 ---- .../include/renderengine/LayerSettings.h | 7 +--- .../renderengine/private/Description.h | 3 -- .../src/ClientCompositionRequestCache.cpp | 3 +- .../surfaceflinger/FrontEnd/LayerSnapshot.cpp | 12 +------ .../surfaceflinger/FrontEnd/LayerSnapshot.h | 1 - .../FrontEnd/LayerSnapshotBuilder.cpp | 4 +-- services/surfaceflinger/Layer.cpp | 10 +----- services/surfaceflinger/Layer.h | 2 -- services/surfaceflinger/LayerFE.cpp | 1 - .../tests/unittests/CompositionTest.cpp | 1 - 14 files changed, 10 insertions(+), 79 deletions(-) diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 0d7df101f4..e7a2c7a411 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -1251,7 +1251,6 @@ void GLESRenderEngine::drawLayersInternal( texture.setFiltering(layer.source.buffer.useTextureFiltering); texture.setDimensions(gBuf->getWidth(), gBuf->getHeight()); - setSourceY410BT2020(layer.source.buffer.isY410BT2020); renderengine::Mesh::VertexArray texCoords(mesh.getTexCoordArray()); texCoords[0] = vec2(0.0, 0.0); @@ -1294,7 +1293,6 @@ void GLESRenderEngine::drawLayersInternal( // Cleanup if there's a buffer source if (layer.source.buffer.buffer != nullptr) { disableBlending(); - setSourceY410BT2020(false); disableTexturing(); } } @@ -1357,10 +1355,6 @@ void GLESRenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, } } -void GLESRenderEngine::setSourceY410BT2020(bool enable) { - mState.isY410BT2020 = enable; -} - void GLESRenderEngine::setSourceDataSpace(Dataspace source) { mDataSpace = source; } diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 402ff529d7..ea75e215cd 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -183,7 +183,6 @@ private: void setupCornerRadiusCropSize(float width, float height); // HDR and color management related functions and state - void setSourceY410BT2020(bool enable); void setSourceDataSpace(ui::Dataspace source); void setOutputDataSpace(ui::Dataspace dataspace); void setDisplayMaxLuminance(const float maxLuminance); diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp index f7f2d54515..812dda04fa 100644 --- a/libs/renderengine/gl/ProgramCache.cpp +++ b/libs/renderengine/gl/ProgramCache.cpp @@ -98,9 +98,6 @@ void ProgramCache::primeCache( shaderKey.set(Key::INPUT_TF_MASK, (i & 1) ? Key::INPUT_TF_HLG : Key::INPUT_TF_ST2084); - // Cache Y410 input on or off - shaderKey.set(Key::Y410_BT2020_MASK, (i & 2) ? - Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF); if (cache.count(shaderKey) == 0) { cache.emplace(shaderKey, generateProgram(shaderKey)); shaderCount++; @@ -161,13 +158,11 @@ void ProgramCache::primeCache( ProgramCache::Key ProgramCache::computeKey(const Description& description) { Key needs; needs.set(Key::TEXTURE_MASK, - !description.textureEnabled - ? Key::TEXTURE_OFF + !description.textureEnabled ? Key::TEXTURE_OFF : description.texture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES - ? Key::TEXTURE_EXT - : description.texture.getTextureTarget() == GL_TEXTURE_2D - ? Key::TEXTURE_2D - : Key::TEXTURE_OFF) + ? Key::TEXTURE_EXT + : description.texture.getTextureTarget() == GL_TEXTURE_2D ? Key::TEXTURE_2D + : Key::TEXTURE_OFF) .set(Key::ALPHA_MASK, (description.color.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE) .set(Key::BLEND_MASK, description.isPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL) @@ -186,8 +181,6 @@ ProgramCache::Key ProgramCache::computeKey(const Description& description) { .set(Key::ROUNDED_CORNERS_MASK, description.cornerRadius > 0 ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF) .set(Key::SHADOW_MASK, description.drawShadows ? Key::SHADOW_ON : Key::SHADOW_OFF); - needs.set(Key::Y410_BT2020_MASK, - description.isY410BT2020 ? Key::Y410_BT2020_ON : Key::Y410_BT2020_OFF); if (needs.hasTransformMatrix() || (description.inputTransferFunction != description.outputTransferFunction)) { @@ -650,20 +643,6 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { fs << "uniform vec4 color;"; } - if (needs.isY410BT2020()) { - fs << R"__SHADER__( - vec3 convertY410BT2020(const vec3 color) { - const vec3 offset = vec3(0.0625, 0.5, 0.5); - const mat3 transform = mat3( - vec3(1.1678, 1.1678, 1.1678), - vec3( 0.0, -0.1878, 2.1481), - vec3(1.6836, -0.6523, 0.0)); - // Y is in G, U is in R, and V is in B - return clamp(transform * (color.grb - offset), 0.0, 1.0); - } - )__SHADER__"; - } - if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF()) || needs.hasDisplayColorMatrix()) { if (needs.needsToneMapping()) { @@ -730,9 +709,6 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) { } else { if (needs.isTexturing()) { fs << "gl_FragColor = texture2D(sampler, outTexCoords);"; - if (needs.isY410BT2020()) { - fs << "gl_FragColor.rgb = convertY410BT2020(gl_FragColor.rgb);"; - } } else { fs << "gl_FragColor.rgb = color.rgb;"; fs << "gl_FragColor.a = 1.0;"; diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h index 535d21cd52..b18914fd5e 100644 --- a/libs/renderengine/gl/ProgramCache.h +++ b/libs/renderengine/gl/ProgramCache.h @@ -108,11 +108,6 @@ public: OUTPUT_TF_ST2084 = 2 << OUTPUT_TF_SHIFT, OUTPUT_TF_HLG = 3 << OUTPUT_TF_SHIFT, - Y410_BT2020_SHIFT = 12, - Y410_BT2020_MASK = 1 << Y410_BT2020_SHIFT, - Y410_BT2020_OFF = 0 << Y410_BT2020_SHIFT, - Y410_BT2020_ON = 1 << Y410_BT2020_SHIFT, - SHADOW_SHIFT = 13, SHADOW_MASK = 1 << SHADOW_SHIFT, SHADOW_OFF = 0 << SHADOW_SHIFT, @@ -180,7 +175,6 @@ public: outputTF >>= Key::OUTPUT_TF_SHIFT; return inputTF != outputTF; } - inline bool isY410BT2020() const { return (mKey & Y410_BT2020_MASK) == Y410_BT2020_ON; } // for use by std::unordered_map diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index b3a617c04b..b501c4074b 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -64,9 +64,6 @@ struct Buffer { // overrides the alpha channel of the buffer. bool isOpaque = false; - // HDR color-space setting for Y410. - bool isY410BT2020 = false; - float maxLuminanceNits = 0.0; }; @@ -189,8 +186,7 @@ static inline bool operator==(const Buffer& lhs, const Buffer& rhs) { lhs.useTextureFiltering == rhs.useTextureFiltering && lhs.textureTransform == rhs.textureTransform && lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha && - lhs.isOpaque == rhs.isOpaque && lhs.isY410BT2020 == rhs.isY410BT2020 && - lhs.maxLuminanceNits == rhs.maxLuminanceNits; + lhs.isOpaque == rhs.isOpaque && lhs.maxLuminanceNits == rhs.maxLuminanceNits; } static inline bool operator==(const Geometry& lhs, const Geometry& rhs) { @@ -247,7 +243,6 @@ static inline void PrintTo(const Buffer& settings, ::std::ostream* os) { PrintMatrix(settings.textureTransform, os); *os << "\n .usePremultipliedAlpha = " << settings.usePremultipliedAlpha; *os << "\n .isOpaque = " << settings.isOpaque; - *os << "\n .isY410BT2020 = " << settings.isY410BT2020; *os << "\n .maxLuminanceNits = " << settings.maxLuminanceNits; *os << "\n}"; } diff --git a/libs/renderengine/include/renderengine/private/Description.h b/libs/renderengine/include/renderengine/private/Description.h index fa6ec10b6e..2873ad7148 100644 --- a/libs/renderengine/include/renderengine/private/Description.h +++ b/libs/renderengine/include/renderengine/private/Description.h @@ -64,9 +64,6 @@ struct Description { // color used when texturing is disabled or when setting alpha. half4 color; - // true if the sampled pixel values are in Y410/BT2020 rather than RGBA - bool isY410BT2020 = false; - // transfer functions for the input/output TransferFunction inputTransferFunction = TransferFunction::LINEAR; TransferFunction outputTransferFunction = TransferFunction::LINEAR; diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp index 7e020ee1c1..752257b810 100644 --- a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp +++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp @@ -45,8 +45,7 @@ inline bool equalIgnoringBuffer(const renderengine::Buffer& lhs, const rendereng lhs.useTextureFiltering == rhs.useTextureFiltering && lhs.textureTransform == rhs.textureTransform && lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha && - lhs.isOpaque == rhs.isOpaque && lhs.isY410BT2020 == rhs.isY410BT2020 && - lhs.maxLuminanceNits == rhs.maxLuminanceNits; + lhs.isOpaque == rhs.isOpaque && lhs.maxLuminanceNits == rhs.maxLuminanceNits; } inline bool equalIgnoringBuffer(const renderengine::LayerSettings& lhs, diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index ee589c3ce8..5d41fddd98 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -465,22 +465,12 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate color.rgb = requested.getColor().rgb; } - if (forceUpdate || - requested.what & - (layer_state_t::eBufferChanged | layer_state_t::eDataspaceChanged | - layer_state_t::eApiChanged)) { - isHdrY410 = requested.dataspace == ui::Dataspace::BT2020_ITU_PQ && - requested.api == NATIVE_WINDOW_API_MEDIA && - requested.bufferData->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102; - } - if (forceUpdate || requested.what & (layer_state_t::eBufferChanged | layer_state_t::eDataspaceChanged | layer_state_t::eApiChanged | layer_state_t::eShadowRadiusChanged | layer_state_t::eBlurRegionsChanged | layer_state_t::eStretchChanged)) { - forceClientComposition = isHdrY410 || shadowSettings.length > 0 || - stretchEffect.hasEffect(); + forceClientComposition = shadowSettings.length > 0 || stretchEffect.hasEffect(); } if (forceUpdate || diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 19477fa419..92d23e2724 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -72,7 +72,6 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { Rect transformedBoundsWithoutTransparentRegion; renderengine::ShadowSettings shadowSettings; bool premultipliedAlpha; - bool isHdrY410; ui::Transform parentTransform; Rect bufferSize; Rect croppedBufferSize; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index cf39187f0d..162b546426 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -870,8 +870,8 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a } // computed snapshot properties - snapshot.forceClientComposition = snapshot.isHdrY410 || snapshot.shadowSettings.length > 0 || - snapshot.stretchEffect.hasEffect(); + snapshot.forceClientComposition = + snapshot.shadowSettings.length > 0 || snapshot.stretchEffect.hasEffect(); snapshot.contentOpaque = snapshot.isContentOpaque(); snapshot.isOpaque = snapshot.contentOpaque && !snapshot.roundedCorner.hasRoundedCorners() && snapshot.color.a == 1.f; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index cfcc424622..1737bdf04d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -659,7 +659,7 @@ void Layer::preparePerFrameCompositionState() { // Force client composition for special cases known only to the front-end. // Rounded corners no longer force client composition, since we may use a // hole punch so that the layer will appear to have rounded corners. - if (isHdrY410() || drawShadows() || snapshot->stretchEffect.hasEffect()) { + if (drawShadows() || snapshot->stretchEffect.hasEffect()) { snapshot->forceClientComposition = true; } // If there are no visible region changes, we still need to update blur parameters. @@ -3887,13 +3887,6 @@ bool Layer::isSimpleBufferUpdate(const layer_state_t& s) const { return true; } -bool Layer::isHdrY410() const { - // pixel format is HDR Y410 masquerading as RGBA_1010102 - return (mBufferInfo.mDataspace == ui::Dataspace::BT2020_ITU_PQ && - mBufferInfo.mApi == NATIVE_WINDOW_API_MEDIA && - mBufferInfo.mPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102); -} - sp Layer::getCompositionEngineLayerFE() const { // There's no need to get a CE Layer if the layer isn't going to draw anything. return hasSomethingToDraw() ? mLegacyLayerFE : nullptr; @@ -4295,7 +4288,6 @@ void Layer::updateSnapshot(bool updateGeometry) { snapshot->contentOpaque = isOpaque(mDrawingState); snapshot->layerOpaqueFlagSet = (mDrawingState.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque; - snapshot->isHdrY410 = isHdrY410(); sp p = mDrawingParent.promote(); if (p != nullptr) { snapshot->parentTransform = p->getTransform(); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 5d77657415..25a684500b 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -431,8 +431,6 @@ public: void updateCloneBufferInfo(); uint64_t mPreviousFrameNumber = 0; - bool isHdrY410() const; - /* * called after composition. * returns true if the layer latched a new buffer this frame. diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index 4d3e04861b..5ae52abe7b 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -225,7 +225,6 @@ void LayerFE::prepareBufferStateClientComposition( layerSettings.source.buffer.fence = mSnapshot->acquireFence; layerSettings.source.buffer.textureName = mSnapshot->textureName; layerSettings.source.buffer.usePremultipliedAlpha = mSnapshot->premultipliedAlpha; - layerSettings.source.buffer.isY410BT2020 = mSnapshot->isHdrY410; bool hasSmpte2086 = mSnapshot->hdrMetadata.validTypes & HdrMetadata::SMPTE2086; bool hasCta861_3 = mSnapshot->hdrMetadata.validTypes & HdrMetadata::CTA861_3; float maxLuminance = 0.f; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index e8a9cfe9d7..14fa492576 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -600,7 +600,6 @@ struct BaseLayerProperties { EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull())); EXPECT_THAT(layer.source.buffer.fence, Not(IsNull())); EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName); - EXPECT_EQ(false, layer.source.buffer.isY410BT2020); EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha); EXPECT_EQ(false, layer.source.buffer.isOpaque); EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.x); -- GitLab From c6aced205bfd3a23ff8f97f3214dc62e93e30909 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 4 Aug 2023 22:16:46 +0000 Subject: [PATCH 0428/1187] Remove extra layering of HDR capabilities on top of HWC SurfaceFlinger claimed to always handle HDR10 and HLG content. This was because initial handling of HDR content was done by hacking in Y410 support and applying a special GPU shader. However, the Y410 path has not been used since at least Android 12 when SkiaRenderEngine stopped supporting it. The resulting side effect is that some WCG-capable devices are reporting themselves as HDR-capable to apps. This is not desirable by OEMs who may install a low dynamic range panel. And, on such panels, an SDR rendition would likely both look better and have cheaper power consumption. This change allows for OEMs to report that they don't support HDR. Note that this patch does not change color management: OEMs will still be required to accept HLG or HDR10 content and color manage correctly if the display receives this content. I.e., the HdrCapabilities API will tell the app that they *should not* submit HDR content, not that they *cannot*. Bug: 281623165 Test: libcompositionengine_test Change-Id: I7c7dc150fd92e580330e31f9ebfe29e645510cdf --- .../src/DisplayColorProfile.cpp | 11 ------- .../tests/DisplayColorProfileTest.cpp | 33 ------------------- 2 files changed, 44 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp index 8f67f3683a..97725ea636 100644 --- a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp @@ -220,17 +220,6 @@ DisplayColorProfile::DisplayColorProfile(const DisplayColorProfileCreationArgs& minLuminance = minLuminance <= 0.0 ? sDefaultMinLumiance : minLuminance; maxLuminance = maxLuminance <= 0.0 ? sDefaultMaxLumiance : maxLuminance; maxAverageLuminance = maxAverageLuminance <= 0.0 ? sDefaultMaxLumiance : maxAverageLuminance; - if (args.hasWideColorGamut) { - // insert HDR10/HLG as we will force client composition for HDR10/HLG - // layers - if (!hasHDR10Support()) { - types.push_back(ui::Hdr::HDR10); - } - - if (!hasHLGSupport()) { - types.push_back(ui::Hdr::HLG); - } - } mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance); } diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp index b3ff2ec6a0..03a97dc770 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp @@ -282,39 +282,6 @@ TEST_F(DisplayColorProfileTest, ctorUsesOrDefaultsLuminanceValuesFromInputArgs) } } -TEST_F(DisplayColorProfileTest, ctorSignalsHdrSupportForAnyWideColorGamutDevice) { - { - // If the output does not profile wide color gamut, then no HDR modes - // will be profileed in the generated HDR capabilities. - auto profile = ProfileFactory().setHasWideColorGamut(false).build(); - - EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), IsEmpty()); - } - - { - // If the HWC does not show profile for certain HDR modes, then the - // generated HDR capabilities will indicate profile anyway. - auto profile = ProfileFactory().setHasWideColorGamut(true).build(); - - EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), SizeIs(2)); - EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HDR10)); - EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HLG)); - } - - { - // If the HWC profiles the HDR modes, then the generated capabilities - // still has one entry for each HDR type. - auto profile = ProfileFactory() - .setHasWideColorGamut(true) - .addHdrTypes({Hdr::HLG, Hdr::HDR10}) - .build(); - - EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), SizeIs(2)); - EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HDR10)); - EXPECT_THAT(profile.getHdrCapabilities().getSupportedHdrTypes(), Contains(Hdr::HLG)); - } -} - /* ------------------------------------------------------------------------ * DisplayColorProfile::hasRenderIntent */ -- GitLab From 15f58d7635cb29adea504dcbce201e950038d937 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Mon, 7 Aug 2023 15:00:58 +0000 Subject: [PATCH 0429/1187] [native] Migrate deprecated GL GrSurfaceBackend related functions Skia-side changes: - https://skia-review.googlesource.com/c/skia/+/735976 - https://skia-review.googlesource.com/c/skia/+/701398 Change-Id: I1f3a68e980ee3a0fb77b3d3804049ae26184ed1e --- libs/renderengine/skia/AutoBackendTexture.cpp | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp index dad3c1993b..90dcae4369 100644 --- a/libs/renderengine/skia/AutoBackendTexture.cpp +++ b/libs/renderengine/skia/AutoBackendTexture.cpp @@ -23,7 +23,7 @@ #include #include #include - +#include #include #include "ColorSpaces.h" #include "log/log_main.h" @@ -40,13 +40,44 @@ AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer AHardwareBuffer_Desc desc; AHardwareBuffer_describe(buffer, &desc); bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT); - GrBackendFormat backendFormat = - GrAHardwareBufferUtils::GetBackendFormat(context, buffer, desc.format, false); - mBackendTexture = - GrAHardwareBufferUtils::MakeBackendTexture(context, buffer, desc.width, desc.height, - &mDeleteProc, &mUpdateProc, &mImageCtx, - createProtectedImage, backendFormat, - isOutputBuffer); + GrBackendFormat backendFormat; + + GrBackendApi backend = context->backend(); + if (backend == GrBackendApi::kOpenGL) { + backendFormat = + GrAHardwareBufferUtils::GetGLBackendFormat(context, desc.format, false); + mBackendTexture = + GrAHardwareBufferUtils::MakeGLBackendTexture(context, + buffer, + desc.width, + desc.height, + &mDeleteProc, + &mUpdateProc, + &mImageCtx, + createProtectedImage, + backendFormat, + isOutputBuffer); + } else if (backend == GrBackendApi::kVulkan) { + backendFormat = + GrAHardwareBufferUtils::GetVulkanBackendFormat(context, + buffer, + desc.format, + false); + mBackendTexture = + GrAHardwareBufferUtils::MakeVulkanBackendTexture(context, + buffer, + desc.width, + desc.height, + &mDeleteProc, + &mUpdateProc, + &mImageCtx, + createProtectedImage, + backendFormat, + isOutputBuffer); + } else { + LOG_ALWAYS_FATAL("Unexpected backend %d", backend); + } + mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format); if (!mBackendTexture.isValid() || !desc.width || !desc.height) { LOG_ALWAYS_FATAL("Failed to create a valid texture. [%p]:[%d,%d] isProtected:%d " @@ -94,7 +125,7 @@ void logFatalTexture(const char* msg, const GrBackendTexture& tex, ui::Dataspace switch (tex.backend()) { case GrBackendApi::kOpenGL: { GrGLTextureInfo textureInfo; - bool retrievedTextureInfo = tex.getGLTextureInfo(&textureInfo); + bool retrievedTextureInfo = GrBackendTextures::GetGLTextureInfo(tex, &textureInfo); LOG_ALWAYS_FATAL("%s isTextureValid:%d dataspace:%d" "\n\tGrBackendTexture: (%i x %i) hasMipmaps: %i isProtected: %i " "texType: %i\n\t\tGrGLTextureInfo: success: %i fTarget: %u fFormat: %u" -- GitLab From 47a9d99468d183c9862e46bd9c9317c9e83865d2 Mon Sep 17 00:00:00 2001 From: Martin Stjernholm Date: Fri, 28 Jul 2023 21:43:36 +0100 Subject: [PATCH 0430/1187] Use a single otapreopt_chroot invocation for all otapreopt runs. Instead of taking the dexopt command on the command line it reads a sequence of commands from stdin. Since this change revamps the interface between the script and the chroot binary, and also requires an sepolicy change, OTA packages with this change won't work with older system images. In that case we just give up and don't preopt anything. Since T (Android 13) there's no blocking at boot reverifying all packages (the old vdex'es are still used, even though the boot classpath has changed), so the effect of skipping OTA preopt is much less severe than it used to be. It's possible to provide a compat mode in the script for the old otapreopt_chroot binary, at the cost of one invocation per package. That's not done here since dex2oat still won't work correctly with the sepolicy in such system images (b/291974157). In a local test on Cuttlefish this reduces the OTA dexopt time with about 1.5 seconds per package. Test: Manual OTA where the system image and the OTA package are built with the change, then run DexOptOtaTests. Test: Manual OTA where only the OTA package is built with the change, then check that the postinstall script exits early. Bug: 293639539 Bug: 291974157 Bug: 199756868 Change-Id: Ie4e29beaee398428680a0c003f7cb01f2cdd76f9 --- cmds/installd/otapreopt_chroot.cpp | 122 ++++++++++++++++++----------- cmds/installd/otapreopt_script.sh | 58 +++++++++----- 2 files changed, 114 insertions(+), 66 deletions(-) diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp index c86993cb06..c40caf56d8 100644 --- a/cmds/installd/otapreopt_chroot.cpp +++ b/cmds/installd/otapreopt_chroot.cpp @@ -19,9 +19,12 @@ #include #include #include +#include +#include #include #include +#include #include #include @@ -29,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -37,7 +41,7 @@ #include "otapreopt_utils.h" #ifndef LOG_TAG -#define LOG_TAG "otapreopt" +#define LOG_TAG "otapreopt_chroot" #endif using android::base::StringPrintf; @@ -49,20 +53,22 @@ namespace installd { // so just try the possibilities one by one. static constexpr std::array kTryMountFsTypes = {"ext4", "erofs"}; -static void CloseDescriptor(int fd) { - if (fd >= 0) { - int result = close(fd); - UNUSED(result); // Ignore result. Printing to logcat will open a new descriptor - // that we do *not* want. - } -} - static void CloseDescriptor(const char* descriptor_string) { int fd = -1; std::istringstream stream(descriptor_string); stream >> fd; if (!stream.fail()) { - CloseDescriptor(fd); + if (fd >= 0) { + if (close(fd) < 0) { + PLOG(ERROR) << "Failed to close " << fd; + } + } + } +} + +static void SetCloseOnExec(int fd) { + if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { + PLOG(ERROR) << "Failed to set FD_CLOEXEC on " << fd; } } @@ -129,24 +135,39 @@ static void TryExtraMount(const char* name, const char* slot, const char* target } // Entry for otapreopt_chroot. Expected parameters are: -// [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params] -// The file descriptor denoted by status-fd will be closed. The rest of the parameters will -// be passed on to otapreopt in the chroot. +// +// [cmd] [status-fd] [target-slot-suffix] +// +// The file descriptor denoted by status-fd will be closed. Dexopt commands on +// the form +// +// "dexopt" [dexopt-params] +// +// are then read from stdin until EOF and passed on to /system/bin/otapreopt one +// by one. After each call a line with the current command count is written to +// stdout and flushed. static int otapreopt_chroot(const int argc, char **arg) { // Validate arguments - // We need the command, status channel and target slot, at a minimum. - if(argc < 3) { - PLOG(ERROR) << "Not enough arguments."; + if (argc == 2 && std::string_view(arg[1]) == "--version") { + // Accept a single --version flag, to allow the script to tell this binary + // from the earlier one. + std::cout << "2" << std::endl; + return 0; + } + if (argc != 3) { + LOG(ERROR) << "Wrong number of arguments: " << argc; exit(208); } - // Close all file descriptors. They are coming from the caller, we do not want to pass them - // on across our fork/exec into a different domain. - // 1) Default descriptors. - CloseDescriptor(STDIN_FILENO); - CloseDescriptor(STDOUT_FILENO); - CloseDescriptor(STDERR_FILENO); - // 2) The status channel. - CloseDescriptor(arg[1]); + const char* status_fd = arg[1]; + const char* slot_suffix = arg[2]; + + // Set O_CLOEXEC on standard fds. They are coming from the caller, we do not + // want to pass them on across our fork/exec into a different domain. + SetCloseOnExec(STDIN_FILENO); + SetCloseOnExec(STDOUT_FILENO); + SetCloseOnExec(STDERR_FILENO); + // Close the status channel. + CloseDescriptor(status_fd); // We need to run the otapreopt tool from the postinstall partition. As such, set up a // mount namespace and change root. @@ -185,20 +206,20 @@ static int otapreopt_chroot(const int argc, char **arg) { // 2) We're in a mount namespace here, so when we die, this will be cleaned up. // 3) Ignore errors. Printing anything at this stage will open a file descriptor // for logging. - if (!ValidateTargetSlotSuffix(arg[2])) { - LOG(ERROR) << "Target slot suffix not legal: " << arg[2]; + if (!ValidateTargetSlotSuffix(slot_suffix)) { + LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix; exit(207); } - TryExtraMount("vendor", arg[2], "/postinstall/vendor"); + TryExtraMount("vendor", slot_suffix, "/postinstall/vendor"); // Try to mount the product partition. update_engine doesn't do this for us, but we // want it for product APKs. Same notes as vendor above. - TryExtraMount("product", arg[2], "/postinstall/product"); + TryExtraMount("product", slot_suffix, "/postinstall/product"); // Try to mount the system_ext partition. update_engine doesn't do this for // us, but we want it for system_ext APKs. Same notes as vendor and product // above. - TryExtraMount("system_ext", arg[2], "/postinstall/system_ext"); + TryExtraMount("system_ext", slot_suffix, "/postinstall/system_ext"); constexpr const char* kPostInstallLinkerconfig = "/postinstall/linkerconfig"; // Try to mount /postinstall/linkerconfig. we will set it up after performing the chroot @@ -329,30 +350,37 @@ static int otapreopt_chroot(const int argc, char **arg) { exit(218); } - // Now go on and run otapreopt. + // Now go on and read dexopt lines from stdin and pass them on to otapreopt. - // Incoming: cmd + status-fd + target-slot + cmd... | Incoming | = argc - // Outgoing: cmd + target-slot + cmd... | Outgoing | = argc - 1 - std::vector cmd; - cmd.reserve(argc); - cmd.push_back("/system/bin/otapreopt"); + int count = 1; + for (std::array linebuf; + std::cin.clear(), std::cin.getline(&linebuf[0], linebuf.size()); ++count) { + // Subtract one from gcount() since getline() counts the newline. + std::string line(&linebuf[0], std::cin.gcount() - 1); - // The first parameter is the status file descriptor, skip. - for (size_t i = 2; i < static_cast(argc); ++i) { - cmd.push_back(arg[i]); - } + if (std::cin.fail()) { + LOG(ERROR) << "Command exceeds max length " << linebuf.size() << " - skipped: " << line; + continue; + } - // Fork and execute otapreopt in its own process. - std::string error_msg; - bool exec_result = Exec(cmd, &error_msg); - if (!exec_result) { - LOG(ERROR) << "Running otapreopt failed: " << error_msg; - } + std::vector tokenized_line = android::base::Tokenize(line, " "); + std::vector cmd{"/system/bin/otapreopt", slot_suffix}; + std::move(tokenized_line.begin(), tokenized_line.end(), std::back_inserter(cmd)); - if (!exec_result) { - exit(213); + LOG(INFO) << "Command " << count << ": " << android::base::Join(cmd, " "); + + // Fork and execute otapreopt in its own process. + std::string error_msg; + bool exec_result = Exec(cmd, &error_msg); + if (!exec_result) { + LOG(ERROR) << "Running otapreopt failed: " << error_msg; + } + + // Print the count to stdout and flush to indicate progress. + std::cout << count << std::endl; } + LOG(INFO) << "No more dexopt commands"; return 0; } diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh index e483d54a2a..28bd7932a2 100644 --- a/cmds/installd/otapreopt_script.sh +++ b/cmds/installd/otapreopt_script.sh @@ -16,7 +16,9 @@ # limitations under the License. # -# This script will run as a postinstall step to drive otapreopt. +# This script runs as a postinstall step to drive otapreopt. It comes with the +# OTA package, but runs /system/bin/otapreopt_chroot in the (old) active system +# image. See system/extras/postinst/postinst.sh for some docs. TARGET_SLOT="$1" STATUS_FD="$2" @@ -31,12 +33,11 @@ BOOT_PROPERTY_NAME="dev.bootcomplete" BOOT_COMPLETE=$(getprop $BOOT_PROPERTY_NAME) if [ "$BOOT_COMPLETE" != "1" ] ; then - echo "Error: boot-complete not detected." + echo "$0: Error: boot-complete not detected." # We must return 0 to not block sideload. exit 0 fi - # Compute target slot suffix. # TODO: Once bootctl is not restricted, we should query from there. Or get this from # update_engine as a parameter. @@ -45,44 +46,63 @@ if [ "$TARGET_SLOT" = "0" ] ; then elif [ "$TARGET_SLOT" = "1" ] ; then TARGET_SLOT_SUFFIX="_b" else - echo "Unknown target slot $TARGET_SLOT" + echo "$0: Unknown target slot $TARGET_SLOT" exit 1 fi +if [ "$(/system/bin/otapreopt_chroot --version)" != 2 ]; then + # We require an updated chroot wrapper that reads dexopt commands from stdin. + # Even if we kept compat with the old binary, the OTA preopt wouldn't work due + # to missing sepolicy rules, so there's no use spending time trying to dexopt + # (b/291974157). + echo "$0: Current system image is too old to work with OTA preopt - skipping." + exit 0 +fi PREPARE=$(cmd otadexopt prepare) # Note: Ignore preparation failures. Step and done will fail and exit this. # This is necessary to support suspends - the OTA service will keep # the state around for us. -PROGRESS=$(cmd otadexopt progress) -print -u${STATUS_FD} "global_progress $PROGRESS" - -i=0 -while ((i&- 2>&- +echo "$0: Using streaming otapreopt_chroot on ${#otadexopt_cmds[@]} packages" - PROGRESS=$(cmd otadexopt progress) - print -u${STATUS_FD} "global_progress $PROGRESS" +function print_otadexopt_cmds { + for cmd in "${otadexopt_cmds[@]}" ; do + print "$cmd" + done +} - i=$((i+1)) -done +function report_progress { + while read count ; do + # mksh can't do floating point arithmetic, so emulate a fixed point calculation. + (( permilles = 1000 * count / ${#otadexopt_cmds[@]} )) + printf 'global_progress %d.%03d\n' $((permilles / 1000)) $((permilles % 1000)) >&${STATUS_FD} + done +} + +print_otadexopt_cmds | \ + /system/bin/otapreopt_chroot $STATUS_FD $TARGET_SLOT_SUFFIX | \ + report_progress -DONE=$(cmd otadexopt done) if [ "$DONE" = "OTA incomplete." ] ; then - echo "Incomplete." + echo "$0: Incomplete." else - echo "Complete or error." + echo "$0: Complete or error." fi print -u${STATUS_FD} "global_progress 1.0" -cmd otadexopt cleanup exit 0 -- GitLab From 85cf63e021153926a5165b0a8b9e4b1238bb0df5 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 7 Aug 2023 21:02:13 +0000 Subject: [PATCH 0431/1187] Add test to verify external stylus connection does not interrupt touch Bug: 291746265 Test: atest inputflinger_tests Change-Id: I8f183fab2862001c152ff1e8149eddb29a084688 --- .../inputflinger/tests/InputReader_test.cpp | 52 +++++++++++++++++++ .../inputflinger/tests/TestInputListener.cpp | 12 +++++ .../inputflinger/tests/TestInputListener.h | 4 ++ .../tests/TestInputListenerMatchers.h | 4 ++ 4 files changed, 72 insertions(+) diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 477beaf7f6..15140969f4 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1356,6 +1356,7 @@ protected: ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyInputDevicesChangedWasCalled()); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled()); + mTestListener->clearNotifyDeviceResetCalls(); } void TearDown() override { @@ -1828,6 +1829,57 @@ TEST_F(TouchIntegrationTest, NotifiesPolicyWhenStylusGestureStarted) { ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertStylusGestureNotified(mDeviceInfo.getId())); } +TEST_F(TouchIntegrationTest, ExternalStylusConnectedDuringTouchGesture) { + ASSERT_NO_FATAL_FAILURE( + mTestListener->assertNotifyDeviceResetWasCalled(WithDeviceId(mDeviceInfo.getId()))); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyDeviceResetWasNotCalled()); + const Point centerPoint = mDevice->getCenterPoint(); + + // Down + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendTrackingId(FIRST_TRACKING_ID); + mDevice->sendDown(centerPoint); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + WithMotionAction(AMOTION_EVENT_ACTION_DOWN))); + + // Move + mDevice->sendMove(centerPoint + Point(1, 1)); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE))); + + // Connecting an external stylus mid-gesture should not interrupt the ongoing gesture stream. + auto externalStylus = createUinputDevice(); + ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled()); + const auto stylusInfo = findDeviceByName(externalStylus->getName()); + ASSERT_TRUE(stylusInfo); + ASSERT_NO_FATAL_FAILURE( + mTestListener->assertNotifyDeviceResetWasCalled(WithDeviceId(stylusInfo->getId()))); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyDeviceResetWasNotCalled()); + + // Move + mDevice->sendMove(centerPoint + Point(2, 2)); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE))); + + // Disconnecting an external stylus mid-gesture should not interrupt the ongoing gesture stream. + externalStylus.reset(); + ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled()); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled()); + + // Up + mDevice->sendUp(); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE( + mTestListener->assertNotifyMotionWasCalled(WithMotionAction(AMOTION_EVENT_ACTION_UP))); + + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled()); +} + // --- StylusButtonIntegrationTest --- // Verify the behavior of button presses reported by various kinds of styluses, including buttons diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp index fc917dd582..41e250f789 100644 --- a/services/inputflinger/tests/TestInputListener.cpp +++ b/services/inputflinger/tests/TestInputListener.cpp @@ -57,6 +57,18 @@ void TestInputListener::assertNotifyDeviceResetWasCalled(NotifyDeviceResetArgs* "Expected notifyDeviceReset() to have been called.")); } +void TestInputListener::clearNotifyDeviceResetCalls() { + std::scoped_lock lock(mLock); + std::get>(mQueues).clear(); +} + +void TestInputListener::assertNotifyDeviceResetWasCalled( + const ::testing::Matcher& matcher) { + NotifyDeviceResetArgs outEventArgs; + ASSERT_NO_FATAL_FAILURE(assertNotifyDeviceResetWasCalled(&outEventArgs)); + ASSERT_THAT(outEventArgs, matcher); +} + void TestInputListener::assertNotifyDeviceResetWasNotCalled() { ASSERT_NO_FATAL_FAILURE( assertNotCalled("notifyDeviceReset() should not be called.")); diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h index deb60483fb..3c5e0146d6 100644 --- a/services/inputflinger/tests/TestInputListener.h +++ b/services/inputflinger/tests/TestInputListener.h @@ -43,6 +43,10 @@ public: void assertNotifyConfigurationChangedWasNotCalled(); + void clearNotifyDeviceResetCalls(); + + void assertNotifyDeviceResetWasCalled(const ::testing::Matcher& matcher); + void assertNotifyDeviceResetWasCalled(NotifyDeviceResetArgs* outEventArgs = nullptr); void assertNotifyDeviceResetWasNotCalled(); diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h index 020ea86da2..183383f57d 100644 --- a/services/inputflinger/tests/TestInputListenerMatchers.h +++ b/services/inputflinger/tests/TestInputListenerMatchers.h @@ -139,6 +139,10 @@ public: return mDeviceId == args.deviceId; } + bool MatchAndExplain(const NotifyDeviceResetArgs& args, std::ostream*) const { + return mDeviceId == args.deviceId; + } + bool MatchAndExplain(const InputEvent& event, std::ostream*) const { return mDeviceId == event.getDeviceId(); } -- GitLab From f78903ad7651b3a03d9e1a090d8d20813f4bc117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Sebechlebsk=C3=BD?= Date: Tue, 8 Aug 2023 11:36:54 +0000 Subject: [PATCH 0432/1187] Revert "EventHub: Enforce that absolute axis values are within reported range" This reverts commit 568dbe780ba29e6f7ab444eef5634a7b1d0ff62b. Reason for revert: See https://b.corp.google.com/issues/293156873#comment13 Change-Id: I8011b81b7c29fcf1fcdd67ee4a887a992a3a3c0c --- services/inputflinger/reader/EventHub.cpp | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index db4070e1b9..e69c99e9b5 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -456,16 +456,6 @@ static std::unordered_map readLightsConfigura return lightInfos; } -static bool isValidEvAbsValue(int32_t code, int32_t value, const RawAbsoluteAxisInfo& info) { - if (code == ABS_MT_TRACKING_ID && value == -1) { - return true; - } - if (value >= info.minValue && value <= info.maxValue) { - return true; - } - return false; -} - // --- Global Functions --- ftl::Flags getAbsAxisUsage(int32_t axis, @@ -814,13 +804,6 @@ void EventHub::Device::trackInputEvent(const struct input_event& event) { InputEventLookup::getLinuxEvdevLabel(EV_ABS, event.code, 0) .code.c_str(), event.value); - LOG_ALWAYS_FATAL_IF(!isValidEvAbsValue(event.code, event.value, it->second.info), - "%s: device '%s' received invalid value %d for EV_ABS code %s with " - "range [%d, %d]", - __func__, identifier.name.c_str(), event.value, - InputEventLookup::getLinuxEvdevLabel(EV_ABS, event.code, 0) - .code.c_str(), - it->second.info.minValue, it->second.info.maxValue); it->second.value = event.value; break; } -- GitLab From 0808ae628904f5f9d31935ae4fd28571506692b6 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 7 Aug 2023 21:42:42 -0700 Subject: [PATCH 0433/1187] [sf] Avoid rounded corners without EGL_EXT_protected_content with new frontend Override the rounded corner state in the layer snapshots if the device doesn't support EGL_EXT_protected_content. This is passed in via a new arg to LayerSnapshotBuilder. Test: libsurfaceflinger_unittest Fixes: 196271643 Change-Id: I8cbe6ea2818305c93494177df239381b0d02b464 --- .../FrontEnd/LayerSnapshotBuilder.cpp | 12 +++- .../FrontEnd/LayerSnapshotBuilder.h | 3 +- .../FrontEnd/RequestedLayerState.cpp | 10 ++++ .../FrontEnd/RequestedLayerState.h | 2 + services/surfaceflinger/SurfaceFlinger.cpp | 12 +++- .../tests/unittests/LayerHierarchyTest.h | 28 +++++++++ .../tests/unittests/LayerSnapshotTest.cpp | 59 ++++++++++++++++++- 7 files changed, 116 insertions(+), 10 deletions(-) diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 23cfe928f5..f7b685de8a 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -854,8 +854,9 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a } if (forceUpdate || snapshot.clientChanges & layer_state_t::eCornerRadiusChanged || - snapshot.changes.any(RequestedLayerState::Changes::Geometry)) { - updateRoundedCorner(snapshot, requested, parentSnapshot); + snapshot.changes.any(RequestedLayerState::Changes::Geometry | + RequestedLayerState::Changes::BufferUsageFlags)) { + updateRoundedCorner(snapshot, requested, parentSnapshot, args); } if (forceUpdate || snapshot.clientChanges & layer_state_t::eShadowRadiusChanged || @@ -886,7 +887,12 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a void LayerSnapshotBuilder::updateRoundedCorner(LayerSnapshot& snapshot, const RequestedLayerState& requested, - const LayerSnapshot& parentSnapshot) { + const LayerSnapshot& parentSnapshot, + const Args& args) { + if (args.skipRoundCornersWhenProtected && requested.isProtected()) { + snapshot.roundedCorner = RoundedCornerState(); + return; + } snapshot.roundedCorner = RoundedCornerState(); RoundedCornerState parentRoundedCorner; if (parentSnapshot.roundedCorner.hasRoundedCorners()) { diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h index d361605875..3d64b362ea 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h @@ -54,6 +54,7 @@ public: std::unordered_set excludeLayerIds; const std::unordered_map& supportedLayerGenericMetadata; const std::unordered_map& genericLayerMetadataKeyMap; + bool skipRoundCornersWhenProtected = false; }; LayerSnapshotBuilder(); @@ -103,7 +104,7 @@ private: bool parentIsRelative, const Args& args); static void resetRelativeState(LayerSnapshot& snapshot); static void updateRoundedCorner(LayerSnapshot& snapshot, const RequestedLayerState& layerState, - const LayerSnapshot& parentSnapshot); + const LayerSnapshot& parentSnapshot, const Args& args); void updateLayerBounds(LayerSnapshot& snapshot, const RequestedLayerState& layerState, const LayerSnapshot& parentSnapshot, uint32_t displayRotationFlags); static void updateShadows(LayerSnapshot& snapshot, const RequestedLayerState& requested, diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index a4777d1148..d979c4662e 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -147,6 +147,8 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta const ui::Size oldBufferSize = hadBuffer ? ui::Size(externalTexture->getWidth(), externalTexture->getHeight()) : ui::Size(); + const uint64_t oldUsageFlags = hadBuffer ? externalTexture->getUsage() : 0; + const bool hadSideStream = sidebandStream != nullptr; const layer_state_t& clientState = resolvedComposerState.state; const bool hadBlur = hasBlur(); @@ -177,6 +179,10 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta changes |= RequestedLayerState::Changes::BufferSize; changes |= RequestedLayerState::Changes::Geometry; } + const uint64_t usageFlags = hasBuffer ? externalTexture->getUsage() : 0; + if (oldUsageFlags != usageFlags) { + changes |= RequestedLayerState::Changes::BufferUsageFlags; + } } if (hasBuffer != hadBuffer) { @@ -570,6 +576,10 @@ bool RequestedLayerState::isSimpleBufferUpdate(const layer_state_t& s) const { return true; } +bool RequestedLayerState::isProtected() const { + return externalTexture && externalTexture->getUsage() & GRALLOC_USAGE_PROTECTED; +} + void RequestedLayerState::clearChanges() { what = 0; changes.clear(); diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h index 1c19d6d5fc..030930289d 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h @@ -56,6 +56,7 @@ struct RequestedLayerState : layer_state_t { Animation = 1u << 17, BufferSize = 1u << 18, GameMode = 1u << 19, + BufferUsageFlags = 1u << 20, }; static Rect reduce(const Rect& win, const Region& exclude); RequestedLayerState(const LayerCreationArgs&); @@ -85,6 +86,7 @@ struct RequestedLayerState : layer_state_t { bool willReleaseBufferOnLatch() const; bool backpressureEnabled() const; bool isSimpleBufferUpdate(const layer_state_t&) const; + bool isProtected() const; // Layer serial number. This gives layers an explicit ordering, so we // have a stable sort order when their layer stack and Z-order are diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9de623fff9..bcce2a6771 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2315,7 +2315,9 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, .forceFullDamage = mForceFullDamage, .supportedLayerGenericMetadata = getHwComposer().getSupportedLayerGenericMetadata(), - .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap()}; + .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap(), + .skipRoundCornersWhenProtected = + !getRenderEngine().supportsProtectedContent()}; mLayerSnapshotBuilder.update(args); } @@ -8547,7 +8549,9 @@ SurfaceFlinger::getLayerSnapshotsForScreenshots(std::optional la .excludeLayerIds = std::move(excludeLayerIds), .supportedLayerGenericMetadata = getHwComposer().getSupportedLayerGenericMetadata(), - .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap()}; + .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap(), + .skipRoundCornersWhenProtected = + !getRenderEngine().supportsProtectedContent()}; mLayerSnapshotBuilder.update(args); auto getLayerSnapshotsFn = @@ -8582,7 +8586,9 @@ SurfaceFlinger::getLayerSnapshotsForScreenshots(uint32_t rootLayerId, uint32_t u .excludeLayerIds = std::move(excludeLayerIds), .supportedLayerGenericMetadata = getHwComposer().getSupportedLayerGenericMetadata(), - .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap()}; + .genericLayerMetadataKeyMap = getGenericLayerMetadataKeyMap(), + .skipRoundCornersWhenProtected = + !getRenderEngine().supportsProtectedContent()}; mLayerSnapshotBuilder.update(args); auto getLayerSnapshotsFn = diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index e475b843c9..13805550aa 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -17,6 +17,8 @@ #include #include +#include + #include "Client.h" // temporarily needed for LayerCreationArgs #include "FrontEnd/LayerCreationArgs.h" #include "FrontEnd/LayerHierarchy.h" @@ -333,6 +335,32 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setRoundedCorners(uint32_t id, float radius) { + std::vector transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = layer_state_t::eCornerRadiusChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.cornerRadius = radius; + mLifecycleManager.applyTransactions(transactions); + } + + void setBuffer(uint32_t id, std::shared_ptr texture) { + std::vector transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = layer_state_t::eBufferChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().externalTexture = texture; + transactions.back().states.front().state.bufferData = + std::make_shared(texture->getId(), texture->getWidth(), + texture->getHeight(), texture->getPixelFormat(), + texture->getUsage()); + mLifecycleManager.applyTransactions(transactions); + } + LayerLifecycleManager mLifecycleManager; }; diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index a581d5b6ff..65bac00461 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -17,6 +17,8 @@ #include #include +#include + #include "FrontEnd/LayerHierarchy.h" #include "FrontEnd/LayerLifecycleManager.h" #include "FrontEnd/LayerSnapshotBuilder.h" @@ -68,12 +70,17 @@ protected: setColor(id); } - void updateAndVerify(LayerSnapshotBuilder& actualBuilder, bool hasDisplayChanges, - const std::vector expectedVisibleLayerIdsInZOrder) { + void update(LayerSnapshotBuilder& actualBuilder, LayerSnapshotBuilder::Args& args) { if (mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)) { mHierarchyBuilder.update(mLifecycleManager.getLayers(), mLifecycleManager.getDestroyedLayers()); } + args.root = mHierarchyBuilder.getHierarchy(); + actualBuilder.update(args); + } + + void updateAndVerify(LayerSnapshotBuilder& actualBuilder, bool hasDisplayChanges, + const std::vector expectedVisibleLayerIdsInZOrder) { LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(), .layerLifecycleManager = mLifecycleManager, .includeMetadata = false, @@ -83,7 +90,7 @@ protected: .supportsBlur = true, .supportedLayerGenericMetadata = {}, .genericLayerMetadataKeyMap = {}}; - actualBuilder.update(args); + update(actualBuilder, args); // rebuild layer snapshots from scratch and verify that it matches the updated state. LayerSnapshotBuilder expectedBuilder(args); @@ -596,4 +603,50 @@ TEST_F(LayerSnapshotTest, framerate) { scheduler::LayerInfo::FrameRateCompatibility::Default); } +TEST_F(LayerSnapshotTest, skipRoundCornersWhenProtected) { + setRoundedCorners(1, 42.f); + setRoundedCorners(2, 42.f); + setCrop(1, Rect{1000, 1000}); + setCrop(2, Rect{1000, 1000}); + + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_TRUE(getSnapshot({.id = 1})->roundedCorner.hasRoundedCorners()); + EXPECT_EQ(getSnapshot({.id = 1})->roundedCorner.radius.x, 42.f); + EXPECT_TRUE(getSnapshot({.id = 2})->roundedCorner.hasRoundedCorners()); + + // add a buffer with the protected bit, check rounded corners are not set when + // skipRoundCornersWhenProtected == true + setBuffer(1, + std::make_shared< + renderengine::mock::FakeExternalTexture>(1U /*width*/, 1U /*height*/, + 1ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + GRALLOC_USAGE_PROTECTED /*usage*/)); + + LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(), + .layerLifecycleManager = mLifecycleManager, + .includeMetadata = false, + .displays = mFrontEndDisplayInfos, + .displayChanges = false, + .globalShadowSettings = globalShadowSettings, + .supportsBlur = true, + .supportedLayerGenericMetadata = {}, + .genericLayerMetadataKeyMap = {}, + .skipRoundCornersWhenProtected = true}; + update(mSnapshotBuilder, args); + EXPECT_FALSE(getSnapshot({.id = 1})->roundedCorner.hasRoundedCorners()); + // layer 2 doesn't have a buffer and should be unaffected + EXPECT_TRUE(getSnapshot({.id = 2})->roundedCorner.hasRoundedCorners()); + + // remove protected bit, check rounded corners are set + setBuffer(1, + std::make_shared(1U /*width*/, 1U /*height*/, + 2ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0 /*usage*/)); + update(mSnapshotBuilder, args); + EXPECT_TRUE(getSnapshot({.id = 1})->roundedCorner.hasRoundedCorners()); + EXPECT_EQ(getSnapshot({.id = 1})->roundedCorner.radius.x, 42.f); +} + } // namespace android::surfaceflinger::frontend -- GitLab From 2a9b118e1f8a7fc9b8db5d18ad3ca6b263a9d985 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 8 Aug 2023 16:14:02 +0000 Subject: [PATCH 0434/1187] Revert "[sf] enable new sf frontend" This reverts commit d571b48458d420f3cdebac044c85c2fb673c327d. Reason for revert: b/294935709 Change-Id: I05a9b259f29640ef0e4cb54a96a53375e4782708 --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index baa35c9cb8..31bdf20116 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -484,7 +484,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false); mLayerLifecycleManagerEnabled = - base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, true); + base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false); mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled || base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false); } -- GitLab From 452c84ef3d0b658109b11336dbc38dcfbe7de933 Mon Sep 17 00:00:00 2001 From: Jim Shargo Date: Mon, 7 Aug 2023 16:46:45 +0000 Subject: [PATCH 0435/1187] nativewindow: Add C++/Rust benchmarks Test: atest nativewindow_buffer_benchmarks_rs nativewindow_buffer_benchmarks_cc Change-Id: Ia2898439da46e57cf65e3d64030d98f052a694c6 --- libs/nativewindow/rust/src/lib.rs | 1 + libs/nativewindow/tests/benchmark/Android.bp | 50 +++++++++++++++++++ libs/nativewindow/tests/benchmark/README.md | 22 ++++++++ .../tests/benchmark/buffer_benchmarks.cc | 38 ++++++++++++++ .../tests/benchmark/buffer_benchmarks.rs | 40 +++++++++++++++ 5 files changed, 151 insertions(+) create mode 100644 libs/nativewindow/tests/benchmark/Android.bp create mode 100644 libs/nativewindow/tests/benchmark/README.md create mode 100644 libs/nativewindow/tests/benchmark/buffer_benchmarks.cc create mode 100644 libs/nativewindow/tests/benchmark/buffer_benchmarks.rs diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index 0ed381eac5..a2ec57cd3c 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -61,6 +61,7 @@ impl AHardwareBuffer { /// program termination. /// /// Available since API level 26. + #[inline] pub fn new( width: u32, height: u32, diff --git a/libs/nativewindow/tests/benchmark/Android.bp b/libs/nativewindow/tests/benchmark/Android.bp new file mode 100644 index 0000000000..6f844cf864 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/Android.bp @@ -0,0 +1,50 @@ +// Copyright (C) 2023 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. + +cc_defaults { + name: "nativewindow_benchmark_defaults_cc", + shared_libs: ["libnativewindow"], + static_libs: [ + "libbase", + "libgoogle-benchmark-main", + ], + test_suites: [ + "device-tests", + "NativeWindowBenchmarks", + ], +} + +cc_benchmark { + name: "nativewindow_buffer_benchmarks_cc", + srcs: ["buffer_benchmarks.cc"], + defaults: ["nativewindow_benchmark_defaults_cc"], +} + +rust_defaults { + name: "nativewindow_benchmark_defaults_rs", + rustlibs: [ + "libnativewindow_rs", + "libcriterion", + ], + test_suites: [ + "device-tests", + "NativeWindowBenchmarks", + ], +} + +rust_benchmark { + name: "nativewindow_buffer_benchmarks_rs", + srcs: ["buffer_benchmarks.rs"], + defaults: ["nativewindow_benchmark_defaults_rs"], +} diff --git a/libs/nativewindow/tests/benchmark/README.md b/libs/nativewindow/tests/benchmark/README.md new file mode 100644 index 0000000000..7eae538dd2 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/README.md @@ -0,0 +1,22 @@ +# libnativewindow Benchmarks + +This directory contains benchmarks for the C++ and Rust variants of +libnativewindow. + +## Running + +It is currently a little tricky to get statistics from Rust benchmarks directly +from tradefed. But we can hack it by using atest to build/push, then running +the benchmarks by hand to get stats. + +``` + $ atest nativewindow_buffer_benchmarks_rs nativewindow_buffer_benchmarks_cc -d + $ adb shell /data/local/tmp/nativewindow_buffer_benchmarks_cc/x86_64/nativewindow_buffer_benchmarks_cc + $ adb shell /data/local/tmp/nativewindow_buffer_benchmarks_rs/x86_64/nativewindow_buffer_benchmarks_rs --bench +``` + +## Results + +On a remote emulator, the results we see from the benchmarks from Rust and C++ +seem to be roughly equivalent! Allocating/deallocating a 720p buffer takes +~2.3ms on each. diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc new file mode 100644 index 0000000000..0ead1a2926 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc @@ -0,0 +1,38 @@ +// Copyright (C) 2023 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 +#include +#include + +static void BM_BufferAllocationDeallocation(benchmark::State& state) { + AHardwareBuffer_Desc buffer_desc = {.width = 1280, + .height = 720, + .layers = 1, + .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + .stride = 0}; + AHardwareBuffer* buffer = nullptr; + for (auto _ : state) { + int status = AHardwareBuffer_allocate(&buffer_desc, &buffer); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to allocate buffer."); + } + AHardwareBuffer_release(buffer); + buffer = nullptr; + } +} +BENCHMARK(BM_BufferAllocationDeallocation); + +BENCHMARK_MAIN(); \ No newline at end of file diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs new file mode 100644 index 0000000000..3ef0f5e8c7 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs @@ -0,0 +1,40 @@ +// Copyright (C) 2023 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. + +//! Benchmark for libnativewindow AHardwareBuffer bindings + +#![allow(dead_code)] +#![allow(missing_docs)] + +use criterion::*; +use nativewindow::*; + +fn allocate_deallocate() { + let buffer = AHardwareBuffer::new( + 1280, + 720, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .unwrap(); + drop(buffer); +} + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("allocate_deallocate", |b| b.iter(allocate_deallocate)); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); -- GitLab From c2a796df3fc509fbe7141c9b05f7571e1d970e65 Mon Sep 17 00:00:00 2001 From: Harsh Abichandani Date: Wed, 9 Aug 2023 10:30:27 +0530 Subject: [PATCH 0436/1187] surfaceflinger_fuzzer: Bug Fix Resolved Abort due to improper message handling. Handled the messages scheduled via postMessage() in fuzzer. exec/s: 40 Test: ./surfaceflinger_fuzzer clusterfuzz-testcase-minimized-surfaceflinger_fuzzer-5382002773655552 Test: ./surfaceflinger_fuzzer clusterfuzz-testcase-minimized-surfaceflinger_fuzzer-5163836271296512 Bug: 291500072 Bug: 294639179 Change-Id: I874f95bfe92de7e8adc462b66867429c2d8834b5 --- services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 867a1985bd..c679b14d7b 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -278,7 +278,7 @@ private: // MessageQueue overrides: void scheduleFrame() override {} - void postMessage(sp&&) override {} + void postMessage(sp&& handler) override { handler->handleMessage(Message()); } }; } // namespace scheduler -- GitLab From 2dbcb1fe112ee5a73b5aac77650ef2d51c4df4bd Mon Sep 17 00:00:00 2001 From: Jim Shargo Date: Wed, 9 Aug 2023 20:20:17 +0000 Subject: [PATCH 0437/1187] nativewindow: Add more benchmarks to evaluate FFI costs This CL adds two new benchmarks, one for getting an AHardwareBuffer's ID and another for getting its description. These should (and do) ultimately take the same amount of time. Test: just adding new tests Change-Id: I5e09a2736ab829ca465aaa4073b439a605d49b5a --- .../tests/benchmark/buffer_benchmarks.cc | 52 ++++++++++++++++--- .../tests/benchmark/buffer_benchmarks.rs | 30 +++++++++-- 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc index 0ead1a2926..9b31993809 100644 --- a/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc @@ -16,16 +16,17 @@ #include #include +constexpr AHardwareBuffer_Desc k720pDesc = {.width = 1280, + .height = 720, + .layers = 1, + .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + .stride = 0}; + static void BM_BufferAllocationDeallocation(benchmark::State& state) { - AHardwareBuffer_Desc buffer_desc = {.width = 1280, - .height = 720, - .layers = 1, - .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, - .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, - .stride = 0}; AHardwareBuffer* buffer = nullptr; for (auto _ : state) { - int status = AHardwareBuffer_allocate(&buffer_desc, &buffer); + int status = AHardwareBuffer_allocate(&k720pDesc, &buffer); if (UNLIKELY(status != 0)) { state.SkipWithError("Unable to allocate buffer."); } @@ -35,4 +36,39 @@ static void BM_BufferAllocationDeallocation(benchmark::State& state) { } BENCHMARK(BM_BufferAllocationDeallocation); -BENCHMARK_MAIN(); \ No newline at end of file +static void BM_AHardwareBuffer_Id(benchmark::State& state) { + AHardwareBuffer* buffer = nullptr; + int status = AHardwareBuffer_allocate(&k720pDesc, &buffer); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to allocate buffer."); + } + + for (auto _ : state) { + uint64_t id = 0; + int status = AHardwareBuffer_getId(buffer, &id); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to get ID."); + } + } + + AHardwareBuffer_release(buffer); +} +BENCHMARK(BM_AHardwareBuffer_Id); + +static void BM_AHardwareBuffer_Desc(benchmark::State& state) { + AHardwareBuffer* buffer = nullptr; + int status = AHardwareBuffer_allocate(&k720pDesc, &buffer); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to allocate buffer."); + } + + for (auto _ : state) { + AHardwareBuffer_Desc desc = {}; + AHardwareBuffer_describe(buffer, &desc); + } + + AHardwareBuffer_release(buffer); +} +BENCHMARK(BM_AHardwareBuffer_Desc); + +BENCHMARK_MAIN(); diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs index 3ef0f5e8c7..fbd49c0b50 100644 --- a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs @@ -20,20 +20,40 @@ use criterion::*; use nativewindow::*; -fn allocate_deallocate() { - let buffer = AHardwareBuffer::new( +#[inline] +fn create_720p_buffer() -> AHardwareBuffer { + AHardwareBuffer::new( 1280, 720, 1, AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, ) - .unwrap(); - drop(buffer); + .unwrap() } fn criterion_benchmark(c: &mut Criterion) { - c.bench_function("allocate_deallocate", |b| b.iter(allocate_deallocate)); + c.bench_function("allocate_deallocate", |b| { + b.iter(|| { + let buffer = create_720p_buffer(); + drop(buffer); + }) + }); + + let buffer = create_720p_buffer(); + c.bench_with_input(BenchmarkId::new("id", "buffer"), &buffer, |b, buffer| { + b.iter(|| { + buffer.id(); + }) + }); + + // This benchmark exercises getters that need to fetch data via an + // underlying call to AHardwareBuffer_describe. + c.bench_with_input(BenchmarkId::new("desc", "buffer"), &buffer, |b, buffer| { + b.iter(|| { + buffer.width(); + }) + }); } criterion_group!(benches, criterion_benchmark); -- GitLab From 66f3a96a7969837beaffc92e04c7a92d1c76f2ae Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Wed, 9 Aug 2023 15:47:20 -0700 Subject: [PATCH 0438/1187] libvulkan: Remove use of hardcoded PAGE_SIZE 4096 bionic hard codes the PAGE_SIZE macro as 4096. This is going away as Android begins to support larger page sizes. Remove the usage of this assumption from libvulkan source; use instead getpagesize() which provides the real pagesize. Test: mma Bug: 295227858 Change-Id: Ie7c2c2f47d8c61c7495dbd3d88bb63ccf7a74063 Signed-off-by: Kalesh Singh --- vulkan/libvulkan/layers_extensions.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp index a14fed222a..d059f8fe4c 100644 --- a/vulkan/libvulkan/layers_extensions.cpp +++ b/vulkan/libvulkan/layers_extensions.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -362,6 +363,7 @@ template void ForEachFileInZip(const std::string& zipname, const std::string& dir_in_zip, Functor functor) { + static const size_t kPageSize = getpagesize(); int32_t err; ZipArchiveHandle zip = nullptr; if ((err = OpenArchive(zipname.c_str(), &zip)) != 0) { @@ -389,7 +391,7 @@ void ForEachFileInZip(const std::string& zipname, // the APK. Loading still may fail for other reasons, but this at least // lets us avoid failed-to-load log messages in the typical case of // compressed and/or unaligned libraries. - if (entry.method != kCompressStored || entry.offset % PAGE_SIZE != 0) + if (entry.method != kCompressStored || entry.offset % kPageSize != 0) continue; functor(filename); } -- GitLab From 3c722da347953b10762d74a12b7cc9840698b005 Mon Sep 17 00:00:00 2001 From: ramindani Date: Wed, 12 Jul 2023 20:37:59 -0700 Subject: [PATCH 0439/1187] [SF] Update to use updateRefreshRateOverlayRate from setActiveMode setActiveMode updates the refresh rate on the overlay when changes the refresh rate not caused by the HWC callback, updating overlay directly created the race condition for the updates. Updates the order to enable the overlay first and then making the call to HWC to enableRefreshRateCallbackDebugEnabled BUG: 279544150 Test: manual test Change-Id: I42eed19242944479e5f9e6edf10565417f358a73 --- services/surfaceflinger/DisplayDevice.cpp | 7 ++---- services/surfaceflinger/SurfaceFlinger.cpp | 27 ++++++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 3c7cbe693f..70ccaf883e 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -213,10 +213,7 @@ void DisplayDevice::setActiveMode(DisplayModeId modeId, Fps displayFps, Fps rend ATRACE_INT(mRenderFrameRateFPSTrace.c_str(), renderFps.getIntValue()); mRefreshRateSelector->setActiveMode(modeId, renderFps); - - if (mRefreshRateOverlay) { - mRefreshRateOverlay->changeRefreshRate(displayFps, renderFps); - } + updateRefreshRateOverlayRate(displayFps, renderFps); } status_t DisplayDevice::initiateModeChange(const ActiveModeInfo& info, @@ -473,7 +470,7 @@ void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc, bool sh mRefreshRateOverlay = std::make_unique(fpsRange, features); mRefreshRateOverlay->setLayerStack(getLayerStack()); mRefreshRateOverlay->setViewport(getSize()); - updateRefreshRateOverlayRate(getActiveMode().modePtr->getFps(), getActiveMode().fps); + updateRefreshRateOverlayRate(getActiveMode().modePtr->getFps(), getActiveMode().fps, setByHwc); } void DisplayDevice::updateRefreshRateOverlayRate(Fps displayFps, Fps renderFps, bool setByHwc) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 13a6e485b9..e459f03f07 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -8207,19 +8207,22 @@ void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { bool setByHwc = getHwComposer().hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG); for (const auto& [id, display] : mPhysicalDisplays) { if (display.snapshot().connectionType() == ui::DisplayConnectionType::Internal) { - if (setByHwc) { - const auto status = - getHwComposer().setRefreshRateChangedCallbackDebugEnabled(id, enable); - if (status != NO_ERROR) { - ALOGE("Error updating the refresh rate changed callback debug enabled"); - return; - } - } - if (const auto device = getDisplayDeviceLocked(id)) { - device->enableRefreshRateOverlay(enable, setByHwc, mRefreshRateOverlaySpinner, - mRefreshRateOverlayRenderRate, - mRefreshRateOverlayShowInMiddle); + const auto enableOverlay = [&](const bool setByHwc) FTL_FAKE_GUARD( + kMainThreadContext) { + device->enableRefreshRateOverlay(enable, setByHwc, mRefreshRateOverlaySpinner, + mRefreshRateOverlayRenderRate, + mRefreshRateOverlayShowInMiddle); + }; + enableOverlay(setByHwc); + if (setByHwc) { + const auto status = + getHwComposer().setRefreshRateChangedCallbackDebugEnabled(id, enable); + if (status != NO_ERROR) { + ALOGE("Error updating the refresh rate changed callback debug enabled"); + enableOverlay(/*setByHwc*/ false); + } + } } } } -- GitLab From c6b37fcda8eed1d0e8a82d966fb4f871727efd6a Mon Sep 17 00:00:00 2001 From: Sungtak Lee Date: Thu, 2 Feb 2023 00:57:30 +0000 Subject: [PATCH 0440/1187] OMX: Add 64bit consumer usage flag parameter Bug: 185896428 Change-Id: Ie3621e71681d81caa78409487795dec0f3173f0f Merged-In: Ie3621e71681d81caa78409487795dec0f3173f0f --- headers/media_plugin/media/openmax/OMX_AsString.h | 1 + headers/media_plugin/media/openmax/OMX_IndexExt.h | 1 + 2 files changed, 2 insertions(+) diff --git a/headers/media_plugin/media/openmax/OMX_AsString.h b/headers/media_plugin/media/openmax/OMX_AsString.h index ce30b417e0..165a868d57 100644 --- a/headers/media_plugin/media/openmax/OMX_AsString.h +++ b/headers/media_plugin/media/openmax/OMX_AsString.h @@ -561,6 +561,7 @@ inline static const char *asString(OMX_INDEXEXTTYPE i, const char *def = "??") { case OMX_IndexConfigPriority: return "ConfigPriority"; case OMX_IndexConfigOperatingRate: return "ConfigOperatingRate"; case OMX_IndexParamConsumerUsageBits: return "ParamConsumerUsageBits"; + case OMX_IndexParamConsumerUsageBits64: return "ParamConsumerUsageBits64"; case OMX_IndexConfigLatency: return "ConfigLatency"; default: return asString((OMX_INDEXTYPE)i, def); } diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h index 0af40dd28e..5ddd719ba1 100644 --- a/headers/media_plugin/media/openmax/OMX_IndexExt.h +++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h @@ -105,6 +105,7 @@ typedef enum OMX_INDEXEXTTYPE { OMX_IndexConfigLowLatency, /**< reference: OMX_CONFIG_BOOLEANTYPE */ OMX_IndexConfigAndroidTunnelPeek, /**< reference: OMX_CONFIG_BOOLEANTYPE */ OMX_IndexConfigAndroidTunnelPeekLegacyMode, /**< reference: OMX_CONFIG_BOOLEANTYPE */ + OMX_IndexParamConsumerUsageBits64, /**< reference: OMX_PARAM_U64TYPE */ OMX_IndexExtOtherEndUnused, /* Time configurations */ -- GitLab From 8e401ad1a921fa35b907e507f2a730025001c6f5 Mon Sep 17 00:00:00 2001 From: Elis Elliott Date: Tue, 8 Aug 2023 11:18:59 +0000 Subject: [PATCH 0441/1187] Add bugreport mode for debugging onboarding. Bug: 294990844 Test: atest android.bugreport.cts.BugreportManagerTest#testOnboardingBugreport Change-Id: I7e344fbd65977b7300ffcceae2ba6c9f35ae8a7a --- cmds/dumpstate/DumpstateService.cpp | 1 + cmds/dumpstate/binder/android/os/IDumpstate.aidl | 3 +++ cmds/dumpstate/dumpstate.cpp | 15 +++++++++++++++ cmds/dumpstate/dumpstate.h | 2 ++ 4 files changed, 21 insertions(+) diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp index a7bc018ff6..c787113765 100644 --- a/cmds/dumpstate/DumpstateService.cpp +++ b/cmds/dumpstate/DumpstateService.cpp @@ -141,6 +141,7 @@ binder::Status DumpstateService::startBugreport(int32_t calling_uid, bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WEAR && bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_TELEPHONY && bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_WIFI && + bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_ONBOARDING && bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_DEFAULT) { MYLOGE("Invalid input: bad bugreport mode: %d", bugreport_mode); signalErrorAndExit(listener, IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT); diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl index 0dc8f5ad64..fa9bcf351c 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl @@ -49,6 +49,9 @@ interface IDumpstate { // Default mode. const int BUGREPORT_MODE_DEFAULT = 6; + // Bugreport taken for onboarding related flows. + const int BUGREPORT_MODE_ONBOARDING = 7; + // Use pre-dumped data. const int BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA = 0x1; diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index e132b35996..376d57a624 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -2176,6 +2176,11 @@ static void DumpstateWifiOnly() { printf("========================================================\n"); } +// Collects a lightweight dumpstate to be used for debugging onboarding related flows. +static void DumpstateOnboardingOnly() { + ds.AddDir(LOGPERSIST_DATA_DIR, false); +} + Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) { const std::string temp_file_pattern = ds.bugreport_internal_dir_ + "/dumptrace_XXXXXX"; const size_t buf_size = temp_file_pattern.length() + 1; @@ -2308,6 +2313,7 @@ static dumpstate_hal_hidl::DumpstateMode GetDumpstateHalModeHidl( return dumpstate_hal_hidl::DumpstateMode::CONNECTIVITY; case Dumpstate::BugreportMode::BUGREPORT_WIFI: return dumpstate_hal_hidl::DumpstateMode::WIFI; + case Dumpstate::BugreportMode::BUGREPORT_ONBOARDING: case Dumpstate::BugreportMode::BUGREPORT_DEFAULT: return dumpstate_hal_hidl::DumpstateMode::DEFAULT; } @@ -2329,6 +2335,7 @@ static dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode GetDumpstateHalModeAi return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::CONNECTIVITY; case Dumpstate::BugreportMode::BUGREPORT_WIFI: return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::WIFI; + case Dumpstate::BugreportMode::BUGREPORT_ONBOARDING: case Dumpstate::BugreportMode::BUGREPORT_DEFAULT: return dumpstate_hal_aidl::IDumpstateDevice::DumpstateMode::DEFAULT; } @@ -2812,6 +2819,8 @@ static inline const char* ModeToString(Dumpstate::BugreportMode mode) { return "BUGREPORT_TELEPHONY"; case Dumpstate::BugreportMode::BUGREPORT_WIFI: return "BUGREPORT_WIFI"; + case Dumpstate::BugreportMode::BUGREPORT_ONBOARDING: + return "BUGREPORT_ONBOARDING"; case Dumpstate::BugreportMode::BUGREPORT_DEFAULT: return "BUGREPORT_DEFAULT"; } @@ -2857,6 +2866,10 @@ static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOpt options->wifi_only = true; options->do_screenshot = false; break; + case Dumpstate::BugreportMode::BUGREPORT_ONBOARDING: + options->onboarding_only = true; + options->do_screenshot = false; + break; case Dumpstate::BugreportMode::BUGREPORT_DEFAULT: break; } @@ -3276,6 +3289,8 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, DumpstateWifiOnly(); } else if (options_->limited_only) { DumpstateLimitedOnly(); + } else if (options_->onboarding_only) { + DumpstateOnboardingOnly(); } else { // Dump state for the default case. This also drops root. RunStatus s = DumpstateDefaultAfterCritical(); diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 8a31c314d9..0a032ecfc3 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -201,6 +201,7 @@ class Dumpstate { BUGREPORT_WEAR = android::os::IDumpstate::BUGREPORT_MODE_WEAR, BUGREPORT_TELEPHONY = android::os::IDumpstate::BUGREPORT_MODE_TELEPHONY, BUGREPORT_WIFI = android::os::IDumpstate::BUGREPORT_MODE_WIFI, + BUGREPORT_ONBOARDING = android::os::IDumpstate::BUGREPORT_MODE_ONBOARDING, BUGREPORT_DEFAULT = android::os::IDumpstate::BUGREPORT_MODE_DEFAULT }; @@ -412,6 +413,7 @@ class Dumpstate { bool show_header_only = false; bool telephony_only = false; bool wifi_only = false; + bool onboarding_only = false; // Trimmed-down version of dumpstate to only include whitelisted logs. bool limited_only = false; // Whether progress updates should be published. -- GitLab From 28839ed47580d59d8861462bc410eeed092fecc1 Mon Sep 17 00:00:00 2001 From: Martin Stjernholm Date: Thu, 10 Aug 2023 16:10:21 +0100 Subject: [PATCH 0442/1187] Clean up dead code. It was left behind in https://r.android.com/1271089. #codehealth Test: m droid Bug: 149794809 Bug: 295082613 Change-Id: Iece1fed3ab62de1ad59f796a699afefefee2f632 --- cmds/installd/otapreopt.cpp | 55 ------------------------------------- 1 file changed, 55 deletions(-) diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index 818fd8066e..27ae8f6e6f 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -560,61 +560,6 @@ private: return Dexopt(); } - //////////////////////////////////// - // Helpers, mostly taken from ART // - //////////////////////////////////// - - // Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc. - static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) { - constexpr size_t kPageSize = PAGE_SIZE; - static_assert(IsPowerOfTwo(kPageSize), "page size must be power of two"); - CHECK_EQ(min_delta % kPageSize, 0u); - CHECK_EQ(max_delta % kPageSize, 0u); - CHECK_LT(min_delta, max_delta); - - std::default_random_engine generator; - generator.seed(GetSeed()); - std::uniform_int_distribution distribution(min_delta, max_delta); - int32_t r = distribution(generator); - if (r % 2 == 0) { - r = RoundUp(r, kPageSize); - } else { - r = RoundDown(r, kPageSize); - } - CHECK_LE(min_delta, r); - CHECK_GE(max_delta, r); - CHECK_EQ(r % kPageSize, 0u); - return r; - } - - static uint64_t GetSeed() { -#ifdef __BIONIC__ - // Bionic exposes arc4random, use it. - uint64_t random_data; - arc4random_buf(&random_data, sizeof(random_data)); - return random_data; -#else -#error "This is only supposed to run with bionic. Otherwise, implement..." -#endif - } - - void AddCompilerOptionFromSystemProperty(const char* system_property, - const char* prefix, - bool runtime, - std::vector& out) const { - const std::string* value = system_properties_.GetProperty(system_property); - if (value != nullptr) { - if (runtime) { - out.push_back("--runtime-arg"); - } - if (prefix != nullptr) { - out.push_back(StringPrintf("%s%s", prefix, value->c_str())); - } else { - out.push_back(*value); - } - } - } - static constexpr const char* kBootClassPathPropertyName = "BOOTCLASSPATH"; static constexpr const char* kAndroidRootPathPropertyName = "ANDROID_ROOT"; static constexpr const char* kAndroidDataPathPropertyName = "ANDROID_DATA"; -- GitLab From 6f4d2f5423e74ac31a79e3a112a3b31bfb5d2015 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 10 Aug 2023 12:33:12 -0700 Subject: [PATCH 0443/1187] [SurfaceComposerClient] Avoid mSurfaceStats mutex contention Previous logic acquired mSurfaceStats mutex and called the listeners with the mutex held between buffer releases. Instead release all the buffers before handling surface stats listener callbacks and updating jank data. Bug: 294935709 Test: presubmit and perfetto traces Change-Id: Ie90ccde431059bdcdb6900148c6027d313e7434f --- libs/gui/SurfaceComposerClient.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index db99726739..ae0cdc92ac 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -450,7 +450,9 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener callbackFunction(transactionStats.latchTime, transactionStats.presentFence, surfaceControlStats); } + } + for (const auto& transactionStats : listenerStats.transactionStats) { for (const auto& surfaceStats : transactionStats.surfaceStats) { // The callbackMap contains the SurfaceControl object, which we need to look up the // layerId. Since we don't know which callback contains the SurfaceControl, iterate -- GitLab From c1d19d7cd16cee779f7984b690fb8629d3a1bb29 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 10 Aug 2023 12:35:11 -0700 Subject: [PATCH 0444/1187] [sf] Add bufferless surfaceframe to frametime in new fe Bug: 238781169 Test: presubmit Test: crystall ball perftests via forrest Change-Id: Ic8cae03e732e41de26d7a530ef06b902b064056c --- services/surfaceflinger/Layer.cpp | 4 ++-- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 1 + .../tests/unittests/FrameRateSelectionPriorityTest.cpp | 3 +-- services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp | 3 +-- .../tests/unittests/TransactionFrameTracerTest.cpp | 5 +---- .../tests/unittests/TransactionSurfaceFrameTest.cpp | 5 +---- 7 files changed, 8 insertions(+), 15 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 3a41f1599b..ba6f967908 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -836,12 +836,12 @@ uint32_t Layer::doTransaction(uint32_t flags) { mFlinger->mUpdateInputInfo = true; } - commitTransaction(mDrawingState); + commitTransaction(); return flags; } -void Layer::commitTransaction(State&) { +void Layer::commitTransaction() { // Set the present state for all bufferlessSurfaceFramesTX to Presented. The // bufferSurfaceFrameTX will be presented in latchBuffer. for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 5d77657415..2ceea7068c 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -912,6 +912,7 @@ public: void setTransformHint(std::optional transformHint) { mTransformHint = transformHint; } + void commitTransaction(); // Keeps track of the previously presented layer stacks. This is used to get // the release fences from the correct displays when we release the last buffer // from the layer. @@ -932,7 +933,6 @@ protected: void preparePerFrameCompositionState(); void preparePerFrameBufferCompositionState(); void preparePerFrameEffectsCompositionState(); - virtual void commitTransaction(State& stateToCommit); void gatherBufferInfo(); void onSurfaceFrameCreated(const std::shared_ptr&); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9de623fff9..8e7aa1a306 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2339,6 +2339,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, if (!mLegacyFrontEndEnabled) { ATRACE_NAME("DisplayCallbackAndStatsUpdates"); applyTransactions(update.transactions, vsyncId); + traverseLegacyLayers([&](Layer* layer) { layer->commitTransaction(); }); const nsecs_t latchTime = systemTime(); bool unused = false; diff --git a/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp index 1c9aee7443..d30d5b8223 100644 --- a/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp @@ -99,8 +99,7 @@ void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) { } void RefreshRateSelectionTest::commitTransaction(Layer* layer) { - auto c = layer->getDrawingState(); - layer->commitTransaction(c); + layer->commitTransaction(); } namespace { diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 44ab569bd1..a1e4e25c06 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -85,8 +85,7 @@ void SetFrameRateTest::removeChild(sp layer, sp child) { void SetFrameRateTest::commitTransaction() { for (auto layer : mLayers) { - auto c = layer->getDrawingState(); - layer->commitTransaction(c); + layer->commitTransaction(); } } diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp index 764d19be0b..00b5bf0506 100644 --- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp @@ -61,10 +61,7 @@ public: return sp::make(args); } - void commitTransaction(Layer* layer) { - auto c = layer->getDrawingState(); - layer->commitTransaction(c); - } + void commitTransaction(Layer* layer) { layer->commitTransaction(); } TestableSurfaceFlinger mFlinger; renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index e2c64917dc..caa265fcd9 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -60,10 +60,7 @@ public: return sp::make(args); } - void commitTransaction(Layer* layer) { - auto c = layer->getDrawingState(); - layer->commitTransaction(c); - } + void commitTransaction(Layer* layer) { layer->commitTransaction(); } TestableSurfaceFlinger mFlinger; renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); -- GitLab From 391ead5b5ab41933582f28e480a69901f0f27a5c Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Wed, 9 Aug 2023 21:39:46 +0000 Subject: [PATCH 0445/1187] Adding binder2corpus to generate fuzzer corpus Tool will take recording file generated from record_binder and convert each transaction as seed corpus for fuzzService. Usage: binder2corpus Test: m binder2corpus && $ANDROID_HOST_OUT/bin/binder2corpus recordings/manager service_manager_corpus/ Bug: 278975837 Change-Id: If6b2560113b0da1d3458a775a36a677570221fac --- libs/binder/tests/parcel_fuzzer/Android.bp | 15 ++++ .../parcel_fuzzer/binder2corpus/README.md | 31 +++++++ .../binder2corpus/binder2corpus.cpp | 90 +++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 libs/binder/tests/parcel_fuzzer/binder2corpus/README.md create mode 100644 libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp index 0d1503eda0..383795eff5 100644 --- a/libs/binder/tests/parcel_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/Android.bp @@ -129,3 +129,18 @@ cc_library { ], export_include_dirs: ["include_random_parcel_seeds"], } + +cc_binary_host { + name: "binder2corpus", + static_libs: [ + "libbinder_random_parcel_seeds", + ], + srcs: [ + "binder2corpus/binder2corpus.cpp", + ], + shared_libs: [ + "libbase", + "libbinder", + "libutils", + ], +} diff --git a/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md b/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md new file mode 100644 index 0000000000..59bf9f31c0 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md @@ -0,0 +1,31 @@ +# binder2corpus + +This tool converts recordings generated by record_binder tool to fuzzer seeds for fuzzService. + +# Steps to add corpus: + +## Start recording the service binder +ex. record_binder start manager + +## Run test on device or keep device idle +ex. atest servicemanager_test + +## Stop the recording +record_binder stop manager + +## Pull the recording on host +Recordings are present on device at /data/local/recordings/. Use adb pull. +Use inspect command of record_binder to check if there are some transactions captured. +ex. record_binder inspect manager + +## run corpus generator tool +binder2corpus + +## Build fuzzer and sync data directory +ex. m servicemanager_fuzzer && adb sync data + +## Push corpus on device +ex. adb push servicemanager_fuzzer_corpus/ /data/fuzz/x86_64/servicemanager_fuzzer/ + +## Run fuzzer with corpus directory as argument +ex. adb shell /data/fuzz/x86_64/servicemanager_fuzzer/servicemanager_fuzzer /data/fuzz/x86_64/servicemanager_fuzzer/servicemanager_fuzzer_corpus \ No newline at end of file diff --git a/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp b/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp new file mode 100644 index 0000000000..c0fdaea0a8 --- /dev/null +++ b/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2023 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 +#include +#include +#include + +#include + +#include + +using android::generateSeedsFromRecording; +using android::status_t; +using android::base::unique_fd; +using android::binder::debug::RecordedTransaction; + +status_t generateCorpus(const char* recordingPath, const char* corpusDir) { + unique_fd fd(open(recordingPath, O_RDONLY)); + if (!fd.ok()) { + std::cerr << "Failed to open recording file at path " << recordingPath + << " with error: " << strerror(errno) << '\n'; + return android::BAD_VALUE; + } + + if (auto res = mkdir(corpusDir, 0766); res != 0) { + std::cerr + << "Failed to create corpus directory at path. Delete directory if already exists: " + << corpusDir << std::endl; + return android::BAD_VALUE; + } + + int transactionNumber = 0; + while (auto transaction = RecordedTransaction::fromFile(fd)) { + ++transactionNumber; + std::string filePath = std::string(corpusDir) + std::string("transaction_") + + std::to_string(transactionNumber); + constexpr int openFlags = O_WRONLY | O_CREAT | O_BINARY | O_CLOEXEC; + android::base::unique_fd corpusFd(open(filePath.c_str(), openFlags, 0666)); + if (!corpusFd.ok()) { + std::cerr << "Failed to open fd. Path " << filePath + << " with error: " << strerror(errno) << std::endl; + return android::UNKNOWN_ERROR; + } + generateSeedsFromRecording(corpusFd, transaction.value()); + } + + if (transactionNumber == 0) { + std::cerr << "No valid transaction has been found in recording file: " << recordingPath + << std::endl; + return android::BAD_VALUE; + } + + return android::NO_ERROR; +} + +void printHelp(const char* toolName) { + std::cout << "Usage: \n\n" + << toolName + << " \n\n*Use " + "record_binder tool for recording binder transactions." + << std::endl; +} + +int main(int argc, char** argv) { + if (argc != 3) { + printHelp(argv[0]); + return 1; + } + const char* sourcePath = argv[1]; + const char* corpusDir = argv[2]; + if (android::NO_ERROR != generateCorpus(sourcePath, corpusDir)) { + std::cerr << "Failed to generate fuzzer corpus." << std::endl; + return 1; + } + return 0; +} -- GitLab From 5b527a04badf4f2aeca1b9bd7a94375a7a8aea5b Mon Sep 17 00:00:00 2001 From: Ian Elliott Date: Thu, 10 Aug 2023 13:32:55 -0600 Subject: [PATCH 0446/1187] Vulkan: Avoid buffer overflow by ignoring duplicate extensions For any instance extension that a Vulkan driver supports, if a VkInstance is created with that extension listed multiple times, the 2nd-nth times should be ignored. That avoids overwriting an array in CreateInfoWrapper::FilterExtension(). Test: Manual testing with logcat Bug: 288929054 Change-Id: I096a6752e0f4abef868efdb6f8b4bcbd0c0c79cd --- vulkan/libvulkan/driver.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index a99355f047..f92078d8dc 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -747,6 +747,17 @@ void CreateInfoWrapper::FilterExtension(const char* name) { if (strcmp(name, props.extensionName) != 0) continue; + // Ignore duplicate extensions (see: b/288929054) + bool duplicate_entry = false; + for (uint32_t j = 0; j < filter.name_count; j++) { + if (strcmp(name, filter.names[j]) == 0) { + duplicate_entry = true; + break; + } + } + if (duplicate_entry == true) + continue; + filter.names[filter.name_count++] = name; if (ext_bit != ProcHook::EXTENSION_UNKNOWN) { if (ext_bit == ProcHook::ANDROID_native_buffer) -- GitLab From e88097d7de5a20eec81f504e66264d481f3535f2 Mon Sep 17 00:00:00 2001 From: Andrei Homescu Date: Mon, 8 May 2023 23:44:58 +0000 Subject: [PATCH 0447/1187] libbinder_rs: Build libbinder_ndk_sys on Trusty Adds a rules.mk build file to build the C wrapper crate on Trusty with bindgen. Bug: 242243245 Test: build binder_ndk_sys as a dependency of skel_rust Change-Id: I54af010a49763bda785230261d56485ffd15e98f --- libs/binder/rust/sys/lib.rs | 15 +++++++- .../trusty/rust/binder_ndk_sys/rules.mk | 38 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 libs/binder/trusty/rust/binder_ndk_sys/rules.mk diff --git a/libs/binder/rust/sys/lib.rs b/libs/binder/rust/sys/lib.rs index 1d1a295221..c5c847b874 100644 --- a/libs/binder/rust/sys/lib.rs +++ b/libs/binder/rust/sys/lib.rs @@ -19,7 +19,20 @@ use std::error::Error; use std::fmt; -include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +#[cfg(not(target_os = "trusty"))] +mod bindings { + include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +} + +// Trusty puts the full path to the auto-generated file in BINDGEN_INC_FILE +// and builds it with warnings-as-errors, so we need to use #[allow(bad_style)] +#[cfg(target_os = "trusty")] +#[allow(bad_style)] +mod bindings { + include!(env!("BINDGEN_INC_FILE")); +} + +pub use bindings::*; impl Error for android_c_interface_StatusCode {} diff --git a/libs/binder/trusty/rust/binder_ndk_sys/rules.mk b/libs/binder/trusty/rust/binder_ndk_sys/rules.mk new file mode 100644 index 0000000000..672d9b75ec --- /dev/null +++ b/libs/binder/trusty/rust/binder_ndk_sys/rules.mk @@ -0,0 +1,38 @@ +# Copyright (C) 2023 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. +# + +LOCAL_DIR := $(GET_LOCAL_DIR) +LIBBINDER_DIR := $(LOCAL_DIR)/../../.. +LIBBINDER_NDK_BINDGEN_FLAG_FILE := \ + $(LIBBINDER_DIR)/rust/libbinder_ndk_bindgen_flags.txt + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS := $(LIBBINDER_DIR)/rust/sys/lib.rs + +MODULE_CRATE_NAME := binder_ndk_sys + +MODULE_LIBRARY_DEPS += \ + $(LIBBINDER_DIR)/trusty \ + $(LIBBINDER_DIR)/trusty/ndk \ + trusty/user/base/lib/trusty-sys \ + +MODULE_BINDGEN_SRC_HEADER := $(LIBBINDER_DIR)/rust/sys/BinderBindings.hpp + +# Add the flags from the flag file +MODULE_BINDGEN_FLAGS += $(shell cat $(LIBBINDER_NDK_BINDGEN_FLAG_FILE)) +MODULE_SRCDEPS += $(LIBBINDER_NDK_BINDGEN_FLAG_FILE) + +include make/library.mk -- GitLab From 004f311e46238eca8ae198e69d03aec3324c9171 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 10 Aug 2023 21:09:24 +0000 Subject: [PATCH 0448/1187] Fix flakiness for ExternalStylusConnectedDuringTouchGesture Remove assertions on NotifyDeviceReset args for the integration test, as these can be flaky and inconsistent for different device types based on how many displays, touchscreen devices, etc. that the device has. Bug: 295149130 Test: atest inputflinger_tests:TouchIntegrationTest#ExternalStylusConnectedDuringTouchGesture --rerun-until-failure Change-Id: Ic8cb4d7053c95a3f955b203017e2a72db9facaee --- services/inputflinger/tests/InputReader_test.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 15140969f4..02c2f650a1 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1830,9 +1830,6 @@ TEST_F(TouchIntegrationTest, NotifiesPolicyWhenStylusGestureStarted) { } TEST_F(TouchIntegrationTest, ExternalStylusConnectedDuringTouchGesture) { - ASSERT_NO_FATAL_FAILURE( - mTestListener->assertNotifyDeviceResetWasCalled(WithDeviceId(mDeviceInfo.getId()))); - ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyDeviceResetWasNotCalled()); const Point centerPoint = mDevice->getCenterPoint(); // Down @@ -1855,9 +1852,6 @@ TEST_F(TouchIntegrationTest, ExternalStylusConnectedDuringTouchGesture) { ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled()); const auto stylusInfo = findDeviceByName(externalStylus->getName()); ASSERT_TRUE(stylusInfo); - ASSERT_NO_FATAL_FAILURE( - mTestListener->assertNotifyDeviceResetWasCalled(WithDeviceId(stylusInfo->getId()))); - ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyDeviceResetWasNotCalled()); // Move mDevice->sendMove(centerPoint + Point(2, 2)); -- GitLab From a48858e46f4d99c4f261a52d43d09dbea5608715 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 11 Aug 2023 16:30:37 +0000 Subject: [PATCH 0449/1187] run_dex2oat: remove FDE-specific code run_dex2oat had special behavior when the device is running a minimal framework for unlocking Full Disk Encryption (FDE), as indicated by the vold.decrypt system property. As FDE support was removed in Android 13 in favor of File Based Encryption (FBE), this code is no longer needed. Bug: 208476087 Test: atest run_dex2oat_test Change-Id: I2d7be81b0f4a9fc4378b01627708f53ea04455f2 --- cmds/installd/run_dex2oat.cpp | 37 ++++++------------------------ cmds/installd/run_dex2oat_test.cpp | 18 --------------- 2 files changed, 7 insertions(+), 48 deletions(-) diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp index 4221a3a593..7648265f0f 100644 --- a/cmds/installd/run_dex2oat.cpp +++ b/cmds/installd/run_dex2oat.cpp @@ -208,36 +208,13 @@ void RunDex2Oat::PrepareCompilerConfigFlags(const UniqueFile& input_vdex, } // Compute compiler filter. - { - std::string dex2oat_compiler_filter_arg; - { - // If we are booting without the real /data, don't spend time compiling. - std::string vold_decrypt = GetProperty("vold.decrypt", ""); - bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" || - vold_decrypt == "1"; - - bool have_dex2oat_relocation_skip_flag = false; - if (skip_compilation) { - dex2oat_compiler_filter_arg = "--compiler-filter=extract"; - have_dex2oat_relocation_skip_flag = true; - } else if (compiler_filter != nullptr) { - dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", - compiler_filter); - } - if (have_dex2oat_relocation_skip_flag) { - AddRuntimeArg("-Xnorelocate"); - } - } - - if (dex2oat_compiler_filter_arg.empty()) { - dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter", - "--compiler-filter=%s"); - } - AddArg(dex2oat_compiler_filter_arg); - - if (compilation_reason != nullptr) { - AddArg(std::string("--compilation-reason=") + compilation_reason); - } + if (compiler_filter != nullptr) { + AddArg(StringPrintf("--compiler-filter=%s", compiler_filter)); + } else { + AddArg(MapPropertyToArg("dalvik.vm.dex2oat-filter", "--compiler-filter=%s")); + } + if (compilation_reason != nullptr) { + AddArg(std::string("--compilation-reason=") + compilation_reason); } AddArg(MapPropertyToArg("dalvik.vm.dex2oat-max-image-block-size", diff --git a/cmds/installd/run_dex2oat_test.cpp b/cmds/installd/run_dex2oat_test.cpp index 304ba7b04f..56f84a5e12 100644 --- a/cmds/installd/run_dex2oat_test.cpp +++ b/cmds/installd/run_dex2oat_test.cpp @@ -441,24 +441,6 @@ TEST_F(RunDex2OatTest, Runtime) { VerifyExpectedFlags(); } -TEST_F(RunDex2OatTest, SkipRelocationInMinFramework) { - setSystemProperty("vold.decrypt", "trigger_restart_min_framework"); - CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs()); - - SetExpectedFlagUsed("--compiler-filter", "=extract"); - SetExpectedFlagUsed("-Xnorelocate", ""); - VerifyExpectedFlags(); -} - -TEST_F(RunDex2OatTest, SkipRelocationIfDecryptedWithFullDiskEncryption) { - setSystemProperty("vold.decrypt", "1"); - CallRunDex2Oat(RunDex2OatArgs::MakeDefaultTestArgs()); - - SetExpectedFlagUsed("--compiler-filter", "=extract"); - SetExpectedFlagUsed("-Xnorelocate", ""); - VerifyExpectedFlags(); -} - TEST_F(RunDex2OatTest, DalvikVmDex2oatFilter) { setSystemProperty("dalvik.vm.dex2oat-filter", "speed"); auto args = RunDex2OatArgs::MakeDefaultTestArgs(); -- GitLab From 9eab6c56aa88e1b6fe2c2eae5da84320875cb295 Mon Sep 17 00:00:00 2001 From: Ian Kasprzak Date: Fri, 11 Aug 2023 16:35:00 +0000 Subject: [PATCH 0450/1187] Revert "OMX: Add 64bit consumer usage flag parameter" This reverts commit c6b37fcda8eed1d0e8a82d966fb4f871727efd6a. Reason for revert: b/295498401- AOSP phones not booting Passing with revert: go/forrest-run/L01600000962534617 Change-Id: I4a17006ccc904433612faf65ad43b2ead33323a4 --- headers/media_plugin/media/openmax/OMX_AsString.h | 1 - headers/media_plugin/media/openmax/OMX_IndexExt.h | 1 - 2 files changed, 2 deletions(-) diff --git a/headers/media_plugin/media/openmax/OMX_AsString.h b/headers/media_plugin/media/openmax/OMX_AsString.h index 165a868d57..ce30b417e0 100644 --- a/headers/media_plugin/media/openmax/OMX_AsString.h +++ b/headers/media_plugin/media/openmax/OMX_AsString.h @@ -561,7 +561,6 @@ inline static const char *asString(OMX_INDEXEXTTYPE i, const char *def = "??") { case OMX_IndexConfigPriority: return "ConfigPriority"; case OMX_IndexConfigOperatingRate: return "ConfigOperatingRate"; case OMX_IndexParamConsumerUsageBits: return "ParamConsumerUsageBits"; - case OMX_IndexParamConsumerUsageBits64: return "ParamConsumerUsageBits64"; case OMX_IndexConfigLatency: return "ConfigLatency"; default: return asString((OMX_INDEXTYPE)i, def); } diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h index 5ddd719ba1..0af40dd28e 100644 --- a/headers/media_plugin/media/openmax/OMX_IndexExt.h +++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h @@ -105,7 +105,6 @@ typedef enum OMX_INDEXEXTTYPE { OMX_IndexConfigLowLatency, /**< reference: OMX_CONFIG_BOOLEANTYPE */ OMX_IndexConfigAndroidTunnelPeek, /**< reference: OMX_CONFIG_BOOLEANTYPE */ OMX_IndexConfigAndroidTunnelPeekLegacyMode, /**< reference: OMX_CONFIG_BOOLEANTYPE */ - OMX_IndexParamConsumerUsageBits64, /**< reference: OMX_PARAM_U64TYPE */ OMX_IndexExtOtherEndUnused, /* Time configurations */ -- GitLab From 7f019199c94d15923704bb0e2896c6147dc38998 Mon Sep 17 00:00:00 2001 From: Chavi Weingarten Date: Tue, 8 Aug 2023 20:39:01 +0000 Subject: [PATCH 0451/1187] Use rect instead of four int frame values for WindowInfo Test: Builds Bug: 290795410 Change-Id: Iff104ad14c5da792f32a68d25145b936f6ea71f6 --- libs/gui/WindowInfo.cpp | 25 ++++++------------- .../libgui_surfaceComposerClient_fuzzer.cpp | 6 ++--- libs/gui/include/gui/WindowInfo.h | 5 +--- libs/gui/tests/WindowInfo_test.cpp | 10 ++------ .../benchmarks/InputDispatcher_benchmarks.cpp | 5 +--- .../dispatcher/InputDispatcher.cpp | 10 ++++---- .../tests/InputDispatcher_test.cpp | 10 ++------ .../FrontEnd/LayerSnapshotBuilder.cpp | 7 +----- services/surfaceflinger/Layer.cpp | 6 +---- services/surfaceflinger/LayerProtoHelper.cpp | 4 +-- 10 files changed, 25 insertions(+), 63 deletions(-) diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 52af9d5114..2eb6bd670d 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -43,7 +43,7 @@ bool WindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { } bool WindowInfo::frameContainsPoint(int32_t x, int32_t y) const { - return x >= frameLeft && x < frameRight && y >= frameTop && y < frameBottom; + return x >= frame.left && x < frame.right && y >= frame.top && y < frame.bottom; } bool WindowInfo::supportsSplitTouch() const { @@ -59,18 +59,15 @@ bool WindowInfo::interceptsStylus() const { } bool WindowInfo::overlaps(const WindowInfo* other) const { - const bool nonEmpty = (frameRight - frameLeft > 0) || (frameBottom - frameTop > 0); - return nonEmpty && frameLeft < other->frameRight && frameRight > other->frameLeft && - frameTop < other->frameBottom && frameBottom > other->frameTop; + return !frame.isEmpty() && frame.left < other->frame.right && frame.right > other->frame.left && + frame.top < other->frame.bottom && frame.bottom > other->frame.top; } bool WindowInfo::operator==(const WindowInfo& info) const { return info.token == token && info.id == id && info.name == name && - info.dispatchingTimeout == dispatchingTimeout && info.frameLeft == frameLeft && - info.frameTop == frameTop && info.frameRight == frameRight && - info.frameBottom == frameBottom && info.surfaceInset == surfaceInset && - info.globalScaleFactor == globalScaleFactor && info.transform == transform && - info.touchableRegion.hasSameRects(touchableRegion) && + info.dispatchingTimeout == dispatchingTimeout && info.frame == frame && + info.surfaceInset == surfaceInset && info.globalScaleFactor == globalScaleFactor && + info.transform == transform && info.touchableRegion.hasSameRects(touchableRegion) && info.touchOcclusionMode == touchOcclusionMode && info.ownerPid == ownerPid && info.ownerUid == ownerUid && info.packageName == packageName && info.inputConfig == inputConfig && info.displayId == displayId && @@ -103,10 +100,7 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->writeInt32(layoutParamsFlags.get()) ?: parcel->writeInt32( static_cast>(layoutParamsType)) ?: - parcel->writeInt32(frameLeft) ?: - parcel->writeInt32(frameTop) ?: - parcel->writeInt32(frameRight) ?: - parcel->writeInt32(frameBottom) ?: + parcel->write(frame) ?: parcel->writeInt32(surfaceInset) ?: parcel->writeFloat(globalScaleFactor) ?: parcel->writeFloat(alpha) ?: @@ -155,10 +149,7 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { // clang-format off status = parcel->readInt32(&lpFlags) ?: parcel->readInt32(&lpType) ?: - parcel->readInt32(&frameLeft) ?: - parcel->readInt32(&frameTop) ?: - parcel->readInt32(&frameRight) ?: - parcel->readInt32(&frameBottom) ?: + parcel->read(frame) ?: parcel->readInt32(&surfaceInset) ?: parcel->readFloat(&globalScaleFactor) ?: parcel->readFloat(&alpha) ?: diff --git a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp index 3e37e4850e..4daa3be36f 100644 --- a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp +++ b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp @@ -178,10 +178,8 @@ void SurfaceComposerClientFuzzer::getWindowInfo(gui::WindowInfo* windowInfo) { windowInfo->name = mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes); windowInfo->layoutParamsFlags = mFdp.PickValueInArray(kFlags); windowInfo->layoutParamsType = mFdp.PickValueInArray(kType); - windowInfo->frameLeft = mFdp.ConsumeIntegral(); - windowInfo->frameTop = mFdp.ConsumeIntegral(); - windowInfo->frameRight = mFdp.ConsumeIntegral(); - windowInfo->frameBottom = mFdp.ConsumeIntegral(); + windowInfo->frame = Rect(mFdp.ConsumeIntegral(), mFdp.ConsumeIntegral(), + mFdp.ConsumeIntegral(), mFdp.ConsumeIntegral()); windowInfo->surfaceInset = mFdp.ConsumeIntegral(); windowInfo->alpha = mFdp.ConsumeFloatingPointInRange(0, 1); ui::Transform transform(mFdp.PickValueInArray(kOrientation)); diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 7ff73874ae..bd2eb7413b 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -194,10 +194,7 @@ struct WindowInfo : public Parcelable { std::chrono::nanoseconds dispatchingTimeout = std::chrono::seconds(5); /* These values are filled in by SurfaceFlinger. */ - int32_t frameLeft = -1; - int32_t frameTop = -1; - int32_t frameRight = -1; - int32_t frameBottom = -1; + Rect frame = Rect::INVALID_RECT; /* * SurfaceFlinger consumes this value to shrink the computed frame. This is diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index 461fe4a4ce..f2feaefa13 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -52,10 +52,7 @@ TEST(WindowInfo, Parcelling) { i.layoutParamsFlags = WindowInfo::Flag::SLIPPERY; i.layoutParamsType = WindowInfo::Type::INPUT_METHOD; i.dispatchingTimeout = 12s; - i.frameLeft = 93; - i.frameTop = 34; - i.frameRight = 16; - i.frameBottom = 19; + i.frame = Rect(93, 34, 16, 19); i.surfaceInset = 17; i.globalScaleFactor = 0.3; i.alpha = 0.7; @@ -85,10 +82,7 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.layoutParamsFlags, i2.layoutParamsFlags); ASSERT_EQ(i.layoutParamsType, i2.layoutParamsType); ASSERT_EQ(i.dispatchingTimeout, i2.dispatchingTimeout); - ASSERT_EQ(i.frameLeft, i2.frameLeft); - ASSERT_EQ(i.frameTop, i2.frameTop); - ASSERT_EQ(i.frameRight, i2.frameRight); - ASSERT_EQ(i.frameBottom, i2.frameBottom); + ASSERT_EQ(i.frame, i2.frame); ASSERT_EQ(i.surfaceInset, i2.surfaceInset); ASSERT_EQ(i.globalScaleFactor, i2.globalScaleFactor); ASSERT_EQ(i.alpha, i2.alpha); diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index 6dd785ae56..188d5f048d 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -185,10 +185,7 @@ public: mInfo.token = mClientChannel->getConnectionToken(); mInfo.name = "FakeWindowHandle"; mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; - mInfo.frameLeft = mFrame.left; - mInfo.frameTop = mFrame.top; - mInfo.frameRight = mFrame.right; - mInfo.frameBottom = mFrame.bottom; + mInfo.frame = mFrame; mInfo.globalScaleFactor = 1.0; mInfo.touchableRegion.clear(); mInfo.addTouchableRegion(mFrame); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 2923a3cfa7..630542fe47 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3011,8 +3011,8 @@ std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info, "hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n", isTouchedWindow ? "[TOUCHED] " : "", info->packageName.c_str(), info->ownerUid.toString().c_str(), info->id, - toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft, - info->frameTop, info->frameRight, info->frameBottom, + toString(info->touchOcclusionMode).c_str(), info->alpha, info->frame.left, + info->frame.top, info->frame.right, info->frame.bottom, dumpRegion(info->touchableRegion).c_str(), info->name.c_str(), info->inputConfig.string().c_str(), toString(info->token != nullptr), info->applicationInfo.name.c_str(), @@ -5644,9 +5644,9 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) const { i, windowInfo->name.c_str(), windowInfo->id, windowInfo->displayId, windowInfo->inputConfig.string().c_str(), - windowInfo->alpha, windowInfo->frameLeft, - windowInfo->frameTop, windowInfo->frameRight, - windowInfo->frameBottom, windowInfo->globalScaleFactor, + windowInfo->alpha, windowInfo->frame.left, + windowInfo->frame.top, windowInfo->frame.right, + windowInfo->frame.bottom, windowInfo->globalScaleFactor, windowInfo->applicationInfo.name.c_str(), binderToString(windowInfo->applicationInfo.token).c_str()); dump += dumpRegion(windowInfo->touchableRegion); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 6d9cd87c4f..4dd40cda80 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1131,10 +1131,7 @@ public: mInfo.name = name; mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT; mInfo.alpha = 1.0; - mInfo.frameLeft = 0; - mInfo.frameTop = 0; - mInfo.frameRight = WIDTH; - mInfo.frameBottom = HEIGHT; + mInfo.frame = Rect(0, 0, WIDTH, HEIGHT); mInfo.transform.set(0, 0); mInfo.globalScaleFactor = 1.0; mInfo.touchableRegion.clear(); @@ -1215,10 +1212,7 @@ public: void setApplicationToken(sp token) { mInfo.applicationInfo.token = token; } void setFrame(const Rect& frame, const ui::Transform& displayTransform = ui::Transform()) { - mInfo.frameLeft = frame.left; - mInfo.frameTop = frame.top; - mInfo.frameRight = frame.right; - mInfo.frameBottom = frame.bottom; + mInfo.frame = frame; mInfo.touchableRegion.clear(); mInfo.addTouchableRegion(frame); diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 159d0f028d..30a795f166 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -178,12 +178,7 @@ void fillInputFrameInfo(gui::WindowInfo& info, const ui::Transform& screenToDisp info.touchableRegion.clear(); } - const Rect roundedFrameInDisplay = - getInputBoundsInDisplaySpace(snapshot, inputBounds, screenToDisplay); - info.frameLeft = roundedFrameInDisplay.left; - info.frameTop = roundedFrameInDisplay.top; - info.frameRight = roundedFrameInDisplay.right; - info.frameBottom = roundedFrameInDisplay.bottom; + info.frame = getInputBoundsInDisplaySpace(snapshot, inputBounds, screenToDisplay); ui::Transform inputToLayer; inputToLayer.set(inputBounds.left, inputBounds.top); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 59a8825de5..377ebd4cd1 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2398,11 +2398,7 @@ void Layer::fillInputFrameInfo(WindowInfo& info, const ui::Transform& screenToDi info.touchableRegion.clear(); } - const Rect roundedFrameInDisplay = getInputBoundsInDisplaySpace(inputBounds, screenToDisplay); - info.frameLeft = roundedFrameInDisplay.left; - info.frameTop = roundedFrameInDisplay.top; - info.frameRight = roundedFrameInDisplay.right; - info.frameBottom = roundedFrameInDisplay.bottom; + info.frame = getInputBoundsInDisplaySpace(inputBounds, screenToDisplay); ui::Transform inputToLayer; inputToLayer.set(inputBounds.left, inputBounds.top); diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index 1c7581b093..341f041086 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -185,8 +185,8 @@ void LayerProtoHelper::writeToProto( static_assert(std::is_same_v); proto->set_layout_params_type(static_cast(inputInfo.layoutParamsType)); - LayerProtoHelper::writeToProto({inputInfo.frameLeft, inputInfo.frameTop, inputInfo.frameRight, - inputInfo.frameBottom}, + LayerProtoHelper::writeToProto({inputInfo.frame.left, inputInfo.frame.top, + inputInfo.frame.right, inputInfo.frame.bottom}, [&]() { return proto->mutable_frame(); }); LayerProtoHelper::writeToProto(inputInfo.touchableRegion, [&]() { return proto->mutable_touchable_region(); }); -- GitLab From 3d9f1e3b0a135b784b9ffa0e65d6a699c7ed1f8e Mon Sep 17 00:00:00 2001 From: Keith Mok Date: Fri, 4 Aug 2023 22:17:08 +0000 Subject: [PATCH 0452/1187] File size seal for memory mapped region When using memfd for cross process communication, we always need to seal the file size, otherwise remote process and shrink the size we memory mapped and thus crash the originate process causing a DoS Bug: 294609150 Test: Build Ignore-AOSP-First: security Change-Id: Ibc263c4f78df897e884378e3d984a188ca8772c7 --- libs/binder/MemoryHeapBase.cpp | 4 ++-- libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp index 3da06ba4db..fc273e0367 100644 --- a/libs/binder/MemoryHeapBase.cpp +++ b/libs/binder/MemoryHeapBase.cpp @@ -73,8 +73,8 @@ MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name) ALOGV("MemoryHeapBase: Attempting to force MemFD"); fd = memfd_create_region(name ? name : "MemoryHeapBase", size); if (fd < 0 || (mapfd(fd, true, size) != NO_ERROR)) return; - const int SEAL_FLAGS = ((mFlags & READ_ONLY) ? F_SEAL_FUTURE_WRITE : 0) | - ((mFlags & MEMFD_ALLOW_SEALING_FLAG) ? 0 : F_SEAL_SEAL); + const int SEAL_FLAGS = ((mFlags & READ_ONLY) ? F_SEAL_FUTURE_WRITE : 0) | F_SEAL_GROW | + F_SEAL_SHRINK | ((mFlags & MEMFD_ALLOW_SEALING_FLAG) ? 0 : F_SEAL_SEAL); if (SEAL_FLAGS && (fcntl(fd, F_ADD_SEALS, SEAL_FLAGS) == -1)) { ALOGE("MemoryHeapBase: MemFD %s sealing with flags %x failed with error %s", name, SEAL_FLAGS, strerror(errno)); diff --git a/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp index 278dd2bf81..140270f5a1 100644 --- a/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp +++ b/libs/binder/tests/binderMemoryHeapBaseUnitTest.cpp @@ -37,7 +37,8 @@ TEST(MemoryHeapBase, MemfdSealed) { ASSERT_NE(mHeap.get(), nullptr); int fd = mHeap->getHeapID(); EXPECT_NE(fd, -1); - EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL); + EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL); + EXPECT_EQ(ftruncate(fd, 4096), -1); } TEST(MemoryHeapBase, MemfdUnsealed) { @@ -48,7 +49,8 @@ TEST(MemoryHeapBase, MemfdUnsealed) { ASSERT_NE(mHeap.get(), nullptr); int fd = mHeap->getHeapID(); EXPECT_NE(fd, -1); - EXPECT_EQ(fcntl(fd, F_GET_SEALS), 0); + EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_GROW | F_SEAL_SHRINK); + EXPECT_EQ(ftruncate(fd, 4096), -1); } TEST(MemoryHeapBase, MemfdSealedProtected) { @@ -59,7 +61,9 @@ TEST(MemoryHeapBase, MemfdSealedProtected) { ASSERT_NE(mHeap.get(), nullptr); int fd = mHeap->getHeapID(); EXPECT_NE(fd, -1); - EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_SEAL | F_SEAL_FUTURE_WRITE); + EXPECT_EQ(fcntl(fd, F_GET_SEALS), + F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL | F_SEAL_FUTURE_WRITE); + EXPECT_EQ(ftruncate(fd, 4096), -1); } TEST(MemoryHeapBase, MemfdUnsealedProtected) { @@ -71,7 +75,8 @@ TEST(MemoryHeapBase, MemfdUnsealedProtected) { ASSERT_NE(mHeap.get(), nullptr); int fd = mHeap->getHeapID(); EXPECT_NE(fd, -1); - EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_FUTURE_WRITE); + EXPECT_EQ(fcntl(fd, F_GET_SEALS), F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_FUTURE_WRITE); + EXPECT_EQ(ftruncate(fd, 4096), -1); } #else -- GitLab From b08549f732063c9af9b84fc9ff3fd997f4f7d1ba Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Fri, 11 Aug 2023 22:06:19 +0530 Subject: [PATCH 0453/1187] ultrahdr: fix initialization in enc fuzzer Bug: 294709564 Test: ./ultrahdr_enc_fuzzer Change-Id: I67a5274bc69c9f7d7222faebca73127757ecab7f --- libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp index bf9b0318bd..c536c391b5 100644 --- a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp +++ b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp @@ -207,7 +207,7 @@ void UltraHdrEncFuzzer::process() { fill420Buffer(bufferYSdr.get(), width, height, yStride); size_t yuv420UVSize = uvStride * yuv420Img.height / 2 * 2; bufferUVSdr = std::make_unique(yuv420UVSize); - yuv420Img.chroma_data = bufferYSdr.get(); + yuv420Img.chroma_data = bufferUVSdr.get(); yuv420Img.chroma_stride = uvStride; fill420Buffer(bufferUVSdr.get(), width / 2, height / 2, uvStride); fill420Buffer(bufferUVSdr.get() + uvStride * height / 2, width / 2, height / 2, -- GitLab From 382956e36e2a1df889531ad6c1fd84d718f78836 Mon Sep 17 00:00:00 2001 From: Sungtak Lee Date: Sat, 12 Aug 2023 07:32:20 +0000 Subject: [PATCH 0454/1187] RELAND "OMX: Add 64bit consumer usage flag parameter" This reverts commit 9eab6c56aa88e1b6fe2c2eae5da84320875cb295. Bug: 295498401 Bug: 185896428 Test: forrest run https://android-build.googleplex.com/builds/forrest/run/L55400000962546914 Change-Id: I8aa0b217b7d5f379b3b069dfd6e1103abcc10453 --- headers/media_plugin/media/openmax/OMX_AsString.h | 1 + headers/media_plugin/media/openmax/OMX_IndexExt.h | 1 + 2 files changed, 2 insertions(+) diff --git a/headers/media_plugin/media/openmax/OMX_AsString.h b/headers/media_plugin/media/openmax/OMX_AsString.h index ce30b417e0..165a868d57 100644 --- a/headers/media_plugin/media/openmax/OMX_AsString.h +++ b/headers/media_plugin/media/openmax/OMX_AsString.h @@ -561,6 +561,7 @@ inline static const char *asString(OMX_INDEXEXTTYPE i, const char *def = "??") { case OMX_IndexConfigPriority: return "ConfigPriority"; case OMX_IndexConfigOperatingRate: return "ConfigOperatingRate"; case OMX_IndexParamConsumerUsageBits: return "ParamConsumerUsageBits"; + case OMX_IndexParamConsumerUsageBits64: return "ParamConsumerUsageBits64"; case OMX_IndexConfigLatency: return "ConfigLatency"; default: return asString((OMX_INDEXTYPE)i, def); } diff --git a/headers/media_plugin/media/openmax/OMX_IndexExt.h b/headers/media_plugin/media/openmax/OMX_IndexExt.h index 0af40dd28e..5ddd719ba1 100644 --- a/headers/media_plugin/media/openmax/OMX_IndexExt.h +++ b/headers/media_plugin/media/openmax/OMX_IndexExt.h @@ -105,6 +105,7 @@ typedef enum OMX_INDEXEXTTYPE { OMX_IndexConfigLowLatency, /**< reference: OMX_CONFIG_BOOLEANTYPE */ OMX_IndexConfigAndroidTunnelPeek, /**< reference: OMX_CONFIG_BOOLEANTYPE */ OMX_IndexConfigAndroidTunnelPeekLegacyMode, /**< reference: OMX_CONFIG_BOOLEANTYPE */ + OMX_IndexParamConsumerUsageBits64, /**< reference: OMX_PARAM_U64TYPE */ OMX_IndexExtOtherEndUnused, /* Time configurations */ -- GitLab From c0e3ed3cbb1edbc61a8d86494b90352ddec637aa Mon Sep 17 00:00:00 2001 From: Kiyoung Kim Date: Fri, 11 Aug 2023 11:22:15 +0900 Subject: [PATCH 0455/1187] Use llndk.libraries.txt from system if VNDK is deprecated llndk.libraries.txt will be relocated into system when VNDK is deprecated. This change sets a new location to load llndk.libraries.txt when VNDK is deprecated. Bug: 290160925 Test: aosp_cf build and boot succeeded with llndk.libraries.txt in the system image Change-Id: I3022910a4e2c9852e2dfe520e1a6e06a9de21f76 --- libs/graphicsenv/GraphicsEnv.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 5f5f85a2ad..64f8704094 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -60,6 +60,17 @@ typedef bool (*fpANGLEShouldBeUsedForApplication)(void* rulesHandle, int rulesVe typedef bool (*fpANGLEFreeRulesHandle)(void* handle); typedef bool (*fpANGLEFreeSystemInfoHandle)(void* handle); +namespace { +static bool isVndkEnabled() { +#ifdef __BIONIC__ + // TODO(b/290159430) Use ro.vndk.version to check if VNDK is enabled instead + static bool isVndkEnabled = !android::base::GetBoolProperty("ro.vndk.deprecate", false); + return isVndkEnabled; +#endif + return false; +} +} // namespace + namespace android { enum NativeLibrary { @@ -71,6 +82,8 @@ static constexpr const char* kNativeLibrariesSystemConfigPath[] = {"/apex/com.android.vndk.v{}/etc/llndk.libraries.{}.txt", "/apex/com.android.vndk.v{}/etc/vndksp.libraries.{}.txt"}; +static const char* kLlndkLibrariesTxtPath = "/system/etc/llndk.libraries.txt"; + static std::string vndkVersionStr() { #ifdef __BIONIC__ return base::GetProperty("ro.vndk.version", ""); @@ -108,8 +121,14 @@ static bool readConfig(const std::string& configFile, std::vector* } static const std::string getSystemNativeLibraries(NativeLibrary type) { - std::string nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type]; - insertVndkVersionStr(&nativeLibrariesSystemConfig); + std::string nativeLibrariesSystemConfig = ""; + + if (!isVndkEnabled() && type == NativeLibrary::LLNDK) { + nativeLibrariesSystemConfig = kLlndkLibrariesTxtPath; + } else { + nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type]; + insertVndkVersionStr(&nativeLibrariesSystemConfig); + } std::vector soNames; if (!readConfig(nativeLibrariesSystemConfig, &soNames)) { -- GitLab From 090ad06d47a8fec09252399f09d86ce4d063f5d1 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Tue, 8 Aug 2023 12:30:10 -0500 Subject: [PATCH 0456/1187] Add getStalledTransactionInfo method to SurfaceComposer Bug: 287577707 Test: presubmits Change-Id: I9c464ee302e7bafe8d45021063368fcd984e27ec --- libs/gui/Android.bp | 2 + libs/gui/SurfaceComposerClient.cpp | 7 +++ .../aidl/android/gui/ISurfaceComposer.aidl | 7 +++ .../android/gui/StalledTransactionInfo.aidl | 24 +++++++++ libs/gui/fuzzer/libgui_fuzzer_utils.h | 2 + libs/gui/include/gui/SurfaceComposerClient.h | 4 ++ libs/gui/tests/Surface_test.cpp | 5 ++ .../FrontEnd/TransactionHandler.cpp | 39 ++++++++++----- .../FrontEnd/TransactionHandler.h | 19 +++++-- services/surfaceflinger/SurfaceFlinger.cpp | 49 ++++++++++++++++--- services/surfaceflinger/SurfaceFlinger.h | 5 ++ 11 files changed, 142 insertions(+), 21 deletions(-) create mode 100644 libs/gui/android/gui/StalledTransactionInfo.aidl diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index d7e7eb8ea1..298838d816 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -62,6 +62,7 @@ filegroup { name: "guiconstants_aidl", srcs: [ "android/gui/DropInputMode.aidl", + "android/gui/StalledTransactionInfo.aidl", "android/**/TouchOcclusionMode.aidl", ], } @@ -140,6 +141,7 @@ aidl_library { "android/gui/IWindowInfosListener.aidl", "android/gui/IWindowInfosPublisher.aidl", "android/gui/IWindowInfosReportedListener.aidl", + "android/gui/StalledTransactionInfo.aidl", "android/gui/WindowInfo.aidl", "android/gui/WindowInfosUpdate.aidl", ], diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 6bc3324b7c..1a78b032aa 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1308,6 +1308,13 @@ sp SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId dis return status.isOk() ? display : nullptr; } +std::optional SurfaceComposerClient::getStalledTransactionInfo( + pid_t pid) { + std::optional result; + ComposerServiceAIDL::getComposerService()->getStalledTransactionInfo(pid, &result); + return result; +} + void SurfaceComposerClient::Transaction::setAnimationTransaction() { mAnimation = true; } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index 5e8e9043c1..f84a910bf8 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -46,6 +46,7 @@ import android.gui.LayerDebugInfo; import android.gui.OverlayProperties; import android.gui.PullAtomData; import android.gui.ARect; +import android.gui.StalledTransactionInfo; import android.gui.StaticDisplayInfo; import android.gui.WindowInfosListenerInfo; @@ -507,4 +508,10 @@ interface ISurfaceComposer { void removeWindowInfosListener(IWindowInfosListener windowInfosListener); OverlayProperties getOverlaySupport(); + + /** + * Returns an instance of StalledTransaction if a transaction from the passed pid has not been + * applied in SurfaceFlinger due to an unsignaled fence. Otherwise, null is returned. + */ + @nullable StalledTransactionInfo getStalledTransactionInfo(int pid); } diff --git a/libs/gui/android/gui/StalledTransactionInfo.aidl b/libs/gui/android/gui/StalledTransactionInfo.aidl new file mode 100644 index 0000000000..e6aa9bd1c7 --- /dev/null +++ b/libs/gui/android/gui/StalledTransactionInfo.aidl @@ -0,0 +1,24 @@ +/* + * Copyright 2023 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. + */ + +package android.gui; + +/** @hide */ +parcelable StalledTransactionInfo { + String layerName; + long bufferId; + long frameNumber; +} \ No newline at end of file diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index 4c7d0562af..c70197cb23 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -158,6 +158,8 @@ public: MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp&), (override)); MOCK_METHOD(binder::Status, getOverlaySupport, (gui::OverlayProperties*), (override)); + MOCK_METHOD(binder::Status, getStalledTransactionInfo, + (int32_t, std::optional*), (override)); }; class FakeBnSurfaceComposerClient : public gui::BnSurfaceComposerClient { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 3cf57b11e9..dbcbd3bd62 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -371,6 +371,10 @@ public: //! Get token for a physical display given its stable ID static sp getPhysicalDisplayToken(PhysicalDisplayId displayId); + // Returns StalledTransactionInfo if a transaction from the provided pid has not been applied + // due to an unsignaled fence. + static std::optional getStalledTransactionInfo(pid_t pid); + struct SCHash { std::size_t operator()(const sp& sc) const { return std::hash{}(sc.get()); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 567604dbec..d7910d26aa 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1016,6 +1016,11 @@ public: return binder::Status::ok(); } + binder::Status getStalledTransactionInfo( + int32_t /*pid*/, std::optional* /*result*/) override { + return binder::Status::ok(); + } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp index 0d3c6ebd47..ca7c3c25f7 100644 --- a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp +++ b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp @@ -188,21 +188,36 @@ bool TransactionHandler::hasPendingTransactions() { } void TransactionHandler::onTransactionQueueStalled(uint64_t transactionId, - sp& listener, - const std::string& reason) { - if (std::find(mStalledTransactions.begin(), mStalledTransactions.end(), transactionId) != - mStalledTransactions.end()) { - return; - } + StalledTransactionInfo stalledTransactionInfo) { + std::lock_guard lock{mStalledMutex}; + mStalledTransactions.emplace(transactionId, std::move(stalledTransactionInfo)); +} + +void TransactionHandler::removeFromStalledTransactions(uint64_t transactionId) { + std::lock_guard lock{mStalledMutex}; + mStalledTransactions.erase(transactionId); +} - mStalledTransactions.push_back(transactionId); - listener->onTransactionQueueStalled(String8(reason.c_str())); +std::optional +TransactionHandler::getStalledTransactionInfo(pid_t pid) { + std::lock_guard lock{mStalledMutex}; + for (auto [_, stalledTransactionInfo] : mStalledTransactions) { + if (pid == stalledTransactionInfo.pid) { + return stalledTransactionInfo; + } + } + return std::nullopt; } -void TransactionHandler::removeFromStalledTransactions(uint64_t id) { - auto it = std::find(mStalledTransactions.begin(), mStalledTransactions.end(), id); - if (it != mStalledTransactions.end()) { - mStalledTransactions.erase(it); +void TransactionHandler::onLayerDestroyed(uint32_t layerId) { + std::lock_guard lock{mStalledMutex}; + for (auto it = mStalledTransactions.begin(); it != mStalledTransactions.end();) { + if (it->second.layerId == layerId) { + it = mStalledTransactions.erase(it); + } else { + it++; + } } } + } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.h b/services/surfaceflinger/FrontEnd/TransactionHandler.h index 04183bcdb8..00f6bcebe6 100644 --- a/services/surfaceflinger/FrontEnd/TransactionHandler.h +++ b/services/surfaceflinger/FrontEnd/TransactionHandler.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -63,9 +64,18 @@ public: std::vector flushTransactions(); void addTransactionReadyFilter(TransactionFilter&&); void queueTransaction(TransactionState&&); - void onTransactionQueueStalled(uint64_t transactionId, sp&, - const std::string& reason); + + struct StalledTransactionInfo { + pid_t pid; + uint32_t layerId; + std::string layerName; + uint64_t bufferId; + uint64_t frameNumber; + }; + void onTransactionQueueStalled(uint64_t transactionId, StalledTransactionInfo); void removeFromStalledTransactions(uint64_t transactionId); + std::optional getStalledTransactionInfo(pid_t pid); + void onLayerDestroyed(uint32_t layerId); private: // For unit tests @@ -81,7 +91,10 @@ private: LocklessQueue mLocklessTransactionQueue; std::atomic mPendingTransactionCount = 0; ftl::SmallVector mTransactionReadyFilters; - std::vector mStalledTransactions; + + std::mutex mStalledMutex; + std::unordered_map mStalledTransactions + GUARDED_BY(mStalledMutex); }; } // namespace surfaceflinger::frontend } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e459f03f07..c943d0ac69 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4461,9 +4461,13 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC (flushState.queueProcessTime - transaction.postTime) > std::chrono::nanoseconds(4s).count()) { mTransactionHandler - .onTransactionQueueStalled(transaction.id, listener, - "Buffer processing hung up due to stuck " - "fence. Indicates GPU hang"); + .onTransactionQueueStalled(transaction.id, + {.pid = layer->getOwnerPid(), + .layerId = static_cast( + layer->getSequence()), + .layerName = layer->getDebugName(), + .bufferId = s.bufferData->getId(), + .frameNumber = s.bufferData->frameNumber}); } ATRACE_FORMAT("fence unsignaled %s", layer->getDebugName()); return TraverseBuffersReturnValues::STOP_TRAVERSAL; @@ -4556,9 +4560,12 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC (flushState.queueProcessTime - transaction.postTime) > std::chrono::nanoseconds(4s).count()) { mTransactionHandler - .onTransactionQueueStalled(transaction.id, listener, - "Buffer processing hung up due to stuck " - "fence. Indicates GPU hang"); + .onTransactionQueueStalled(transaction.id, + {.pid = layer->ownerPid.val(), + .layerId = layer->id, + .layerName = layer->name, + .bufferId = s.bufferData->getId(), + .frameNumber = s.bufferData->frameNumber}); } ATRACE_FORMAT("fence unsignaled %s", layer->name.c_str()); return TraverseBuffersReturnValues::STOP_TRAVERSAL; @@ -5585,6 +5592,8 @@ void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp& layer, uint32 mDestroyedHandles.emplace_back(layerId); } + mTransactionHandler.onLayerDestroyed(layerId); + Mutex::Autolock lock(mStateLock); markLayerPendingRemovalLocked(layer); layer->onHandleDestroyed(); @@ -8390,6 +8399,12 @@ status_t SurfaceFlinger::removeWindowInfosListener( return NO_ERROR; } +status_t SurfaceFlinger::getStalledTransactionInfo( + int pid, std::optional& result) { + result = mTransactionHandler.getStalledTransactionInfo(pid); + return NO_ERROR; +} + std::shared_ptr SurfaceFlinger::getExternalTextureFromBufferData( BufferData& bufferData, const char* layerName, uint64_t transactionId) { if (bufferData.buffer && @@ -9499,6 +9514,28 @@ binder::Status SurfaceComposerAIDL::removeWindowInfosListener( return binderStatusFromStatusT(status); } +binder::Status SurfaceComposerAIDL::getStalledTransactionInfo( + int pid, std::optional* outInfo) { + const int callingPid = IPCThreadState::self()->getCallingPid(); + const int callingUid = IPCThreadState::self()->getCallingUid(); + if (!checkPermission(sAccessSurfaceFlinger, callingPid, callingUid)) { + return binderStatusFromStatusT(PERMISSION_DENIED); + } + + std::optional stalledTransactionInfo; + status_t status = mFlinger->getStalledTransactionInfo(pid, stalledTransactionInfo); + if (stalledTransactionInfo) { + gui::StalledTransactionInfo result; + result.layerName = String16{stalledTransactionInfo->layerName.c_str()}, + result.bufferId = stalledTransactionInfo->bufferId, + result.frameNumber = stalledTransactionInfo->frameNumber, + outInfo->emplace(std::move(result)); + } else { + outInfo->reset(); + } + return binderStatusFromStatusT(status); +} + status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) { if (!mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) { IPCThreadState* ipc = IPCThreadState::self(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index d9c1101de8..3ba1bcba00 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -622,6 +622,9 @@ private: status_t removeWindowInfosListener( const sp& windowInfosListener) const; + status_t getStalledTransactionInfo( + int pid, std::optional& result); + // Implements IBinder::DeathRecipient. void binderDied(const wp& who) override; @@ -1560,6 +1563,8 @@ public: gui::WindowInfosListenerInfo* outInfo) override; binder::Status removeWindowInfosListener( const sp& windowInfosListener) override; + binder::Status getStalledTransactionInfo(int pid, + std::optional* outInfo); private: static const constexpr bool kUsePermissionCache = true; -- GitLab From 3996ee322e543383283e77c55f6ff9eefae55436 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 14 Aug 2023 04:32:31 +0000 Subject: [PATCH 0457/1187] [sf-newfe] translate dataspace correctly Also fix visible region flag to include geometry changes. Test: CtsCameraTestCases on cuttlefish Bug: 238781169 Change-Id: Iaa233f22cab61cd3c2b18be9777c855d5afa42ba --- services/surfaceflinger/FrontEnd/LayerSnapshot.cpp | 3 ++- services/surfaceflinger/Layer.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 6 +++++- .../tests/unittests/LayerHierarchyTest.h | 11 +++++++++++ .../tests/unittests/LayerSnapshotTest.cpp | 7 +++++++ 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index 5d41fddd98..d42bce6ed5 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -19,6 +19,7 @@ #define LOG_TAG "SurfaceFlinger" #include "LayerSnapshot.h" +#include "Layer.h" namespace android::surfaceflinger::frontend { @@ -363,7 +364,7 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate geomBufferUsesDisplayInverseTransform = requested.transformToDisplayInverse; } if (forceUpdate || requested.what & layer_state_t::eDataspaceChanged) { - dataspace = requested.dataspace; + dataspace = Layer::translateDataspace(requested.dataspace); } if (forceUpdate || requested.what & layer_state_t::eExtendedRangeBrightnessChanged) { currentHdrSdrRatio = requested.currentHdrSdrRatio; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 3eef277fa3..d1912e4c9c 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -427,7 +427,7 @@ public: bool needsFilteringForScreenshots(const DisplayDevice*, const ui::Transform&) const; // from graphics API - ui::Dataspace translateDataspace(ui::Dataspace dataspace); + static ui::Dataspace translateDataspace(ui::Dataspace dataspace); void updateCloneBufferInfo(); uint64_t mPreviousFrameNumber = 0; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 328a382e88..31cd6e5a01 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2322,7 +2322,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, mUpdateInputInfo = true; } if (mLayerLifecycleManager.getGlobalChanges().any(Changes::VisibleRegion | Changes::Hierarchy | - Changes::Visibility)) { + Changes::Visibility | Changes::Geometry)) { mVisibleRegionsDirty = true; } if (mLayerLifecycleManager.getGlobalChanges().any(Changes::Hierarchy | Changes::FrameRate)) { @@ -2363,6 +2363,7 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, } it->second->latchBufferImpl(unused, latchTime, bgColorOnly); newDataLatched = true; + mLayersWithQueuedFrames.emplace(it->second); mLayersIdsWithQueuedFrames.emplace(it->second->sequence); } @@ -5387,6 +5388,9 @@ uint32_t SurfaceFlinger::updateLayerCallbacksAndStats(const FrameTimelineInfo& f if (what & layer_state_t::eSidebandStreamChanged) { if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded; } + if (what & layer_state_t::eDataspaceChanged) { + if (layer->setDataspace(s.dataspace)) flags |= eTraversalNeeded; + } if (what & layer_state_t::eBufferChanged) { std::optional transformHint = std::nullopt; frontend::LayerSnapshot* snapshot = mLayerSnapshotBuilder.getSnapshot(layer->sequence); diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index 13805550aa..f64ba2a439 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -361,6 +361,17 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setDataspace(uint32_t id, ui::Dataspace dataspace) { + std::vector transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = layer_state_t::eDataspaceChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.dataspace = dataspace; + mLifecycleManager.applyTransactions(transactions); + } + LayerLifecycleManager mLifecycleManager; }; diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 65bac00461..84c37759ba 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -24,6 +24,7 @@ #include "FrontEnd/LayerSnapshotBuilder.h" #include "Layer.h" #include "LayerHierarchyTest.h" +#include "ui/GraphicTypes.h" #define UPDATE_AND_VERIFY(BUILDER, ...) \ ({ \ @@ -603,6 +604,12 @@ TEST_F(LayerSnapshotTest, framerate) { scheduler::LayerInfo::FrameRateCompatibility::Default); } +TEST_F(LayerSnapshotTest, translateDataspace) { + setDataspace(1, ui::Dataspace::UNKNOWN); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot({.id = 1})->dataspace, ui::Dataspace::V0_SRGB); +} + TEST_F(LayerSnapshotTest, skipRoundCornersWhenProtected) { setRoundedCorners(1, 42.f); setRoundedCorners(2, 42.f); -- GitLab From 440bf65fdc9c5fa2df7741ca93fb7b666d12e49f Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Wed, 9 Aug 2023 09:23:43 +0000 Subject: [PATCH 0458/1187] Test display associations in TouchIntegrationTest Added test for display linked via a input-port and via a unique id Bug: 285478143 Test: atest inputflinger_tests Change-Id: I12fb815eec20b345545899a20dc28110bfd321f0 --- .../inputflinger/tests/InputReader_test.cpp | 111 +++++++++++++----- services/inputflinger/tests/UinputDevice.cpp | 8 +- services/inputflinger/tests/UinputDevice.h | 3 +- 3 files changed, 92 insertions(+), 30 deletions(-) diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 02c2f650a1..1b1987095e 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1343,20 +1343,8 @@ protected: mFakePolicy = sp::make(); mFakePointerController = std::make_shared(); mFakePolicy->setPointerController(mFakePointerController); - mTestListener = std::make_unique(/*eventHappenedTimeout=*/2000ms, - /*eventDidNotHappenTimeout=*/30ms); - mReader = std::make_unique(std::make_shared(), mFakePolicy, - *mTestListener); - ASSERT_EQ(mReader->start(), OK); - - // Since this test is run on a real device, all the input devices connected - // to the test device will show up in mReader. We wait for those input devices to - // show up before beginning the tests. - ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); - ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyInputDevicesChangedWasCalled()); - ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled()); - mTestListener->clearNotifyDeviceResetCalls(); + setupInputReader(); } void TearDown() override { @@ -1377,6 +1365,22 @@ protected: }); return it != inputDevices.end() ? std::make_optional(*it) : std::nullopt; } + + void setupInputReader() { + mTestListener = std::make_unique(/*eventHappenedTimeout=*/2000ms, + /*eventDidNotHappenTimeout=*/30ms); + + mReader = std::make_unique(std::make_shared(), mFakePolicy, + *mTestListener); + ASSERT_EQ(mReader->start(), OK); + + // Since this test is run on a real device, all the input devices connected + // to the test device will show up in mReader. We wait for those input devices to + // show up before beginning the tests. + ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyInputDevicesChangedWasCalled()); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled()); + } }; TEST_F(InputReaderIntegrationTest, TestInvalidDevice) { @@ -1510,7 +1514,7 @@ TEST_F(InputReaderIntegrationTest, SendsGearDownAndUpToInputListener) { // --- TouchIntegrationTest --- -class TouchIntegrationTest : public InputReaderIntegrationTest { +class BaseTouchIntegrationTest : public InputReaderIntegrationTest { protected: const std::string UNIQUE_ID = "local:0"; @@ -1555,7 +1559,55 @@ protected: InputDeviceInfo mDeviceInfo; }; -TEST_F(TouchIntegrationTest, MultiTouchDeviceSource) { +enum class TouchIntegrationTestDisplays { DISPLAY_INTERNAL, DISPLAY_INPUT_PORT, DISPLAY_UNIQUE_ID }; + +class TouchIntegrationTest : public BaseTouchIntegrationTest, + public testing::WithParamInterface { +protected: + static constexpr std::optional DISPLAY_PORT = 0; + const std::string INPUT_PORT = "uinput_touch/input0"; + + void SetUp() override { +#if !defined(__ANDROID__) + GTEST_SKIP(); +#endif + if (GetParam() == TouchIntegrationTestDisplays::DISPLAY_INTERNAL) { + BaseTouchIntegrationTest::SetUp(); + return; + } + + // setup policy with a input-port or UniqueId association to the display + bool isInputPortAssociation = + GetParam() == TouchIntegrationTestDisplays::DISPLAY_INPUT_PORT; + + mFakePolicy = sp::make(); + if (isInputPortAssociation) { + mFakePolicy->addInputPortAssociation(INPUT_PORT, DISPLAY_PORT.value()); + } else { + mFakePolicy->addInputUniqueIdAssociation(INPUT_PORT, UNIQUE_ID); + } + mFakePointerController = std::make_shared(); + mFakePolicy->setPointerController(mFakePointerController); + + InputReaderIntegrationTest::setupInputReader(); + + mDevice = createUinputDevice(Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT), + INPUT_PORT); + ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); + + // Add a display linked to a physical port or UniqueId. + setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0, + UNIQUE_ID, isInputPortAssociation ? DISPLAY_PORT : NO_PORT, + ViewportType::INTERNAL); + ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled()); + const auto info = findDeviceByName(mDevice->getName()); + ASSERT_TRUE(info); + mDeviceInfo = *info; + } +}; + +TEST_P(TouchIntegrationTest, MultiTouchDeviceSource) { // The UinputTouchScreen is an MT device that supports MT_TOOL_TYPE and also supports stylus // buttons. It should show up as a touchscreen, stylus, and keyboard (for reporting button // presses). @@ -1563,7 +1615,7 @@ TEST_F(TouchIntegrationTest, MultiTouchDeviceSource) { mDeviceInfo.getSources()); } -TEST_F(TouchIntegrationTest, InputEvent_ProcessSingleTouch) { +TEST_P(TouchIntegrationTest, InputEvent_ProcessSingleTouch) { NotifyMotionArgs args; const Point centerPoint = mDevice->getCenterPoint(); @@ -1587,7 +1639,7 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessSingleTouch) { ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); } -TEST_F(TouchIntegrationTest, InputEvent_ProcessMultiTouch) { +TEST_P(TouchIntegrationTest, InputEvent_ProcessMultiTouch) { NotifyMotionArgs args; const Point centerPoint = mDevice->getCenterPoint(); @@ -1643,7 +1695,7 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessMultiTouch) { * palms, and wants to cancel Pointer 1, then it is safe to simply drop POINTER_1_UP event without * losing information about non-palm pointers. */ -TEST_F(TouchIntegrationTest, MultiTouch_PointerMoveAndSecondPointerUp) { +TEST_P(TouchIntegrationTest, MultiTouch_PointerMoveAndSecondPointerUp) { NotifyMotionArgs args; const Point centerPoint = mDevice->getCenterPoint(); @@ -1686,7 +1738,7 @@ TEST_F(TouchIntegrationTest, MultiTouch_PointerMoveAndSecondPointerUp) { * In this scenario, the movement of the second pointer just prior to liftoff is ignored, and never * gets sent to the listener. */ -TEST_F(TouchIntegrationTest, MultiTouch_PointerMoveAndSecondPointerMoveAndUp) { +TEST_P(TouchIntegrationTest, MultiTouch_PointerMoveAndSecondPointerMoveAndUp) { NotifyMotionArgs args; const Point centerPoint = mDevice->getCenterPoint(); @@ -1726,7 +1778,7 @@ TEST_F(TouchIntegrationTest, MultiTouch_PointerMoveAndSecondPointerMoveAndUp) { assertReceivedMotion(AMOTION_EVENT_ACTION_MOVE, {centerPoint + Point(5, 5)}); } -TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { +TEST_P(TouchIntegrationTest, InputEvent_ProcessPalm) { NotifyMotionArgs args; const Point centerPoint = mDevice->getCenterPoint(); @@ -1777,7 +1829,7 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); } -TEST_F(TouchIntegrationTest, NotifiesPolicyWhenStylusGestureStarted) { +TEST_P(TouchIntegrationTest, NotifiesPolicyWhenStylusGestureStarted) { const Point centerPoint = mDevice->getCenterPoint(); // Send down with the pen tool selected. The policy should be notified of the stylus presence. @@ -1829,7 +1881,7 @@ TEST_F(TouchIntegrationTest, NotifiesPolicyWhenStylusGestureStarted) { ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertStylusGestureNotified(mDeviceInfo.getId())); } -TEST_F(TouchIntegrationTest, ExternalStylusConnectedDuringTouchGesture) { +TEST_P(TouchIntegrationTest, ExternalStylusConnectedDuringTouchGesture) { const Point centerPoint = mDevice->getCenterPoint(); // Down @@ -1874,19 +1926,24 @@ TEST_F(TouchIntegrationTest, ExternalStylusConnectedDuringTouchGesture) { ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled()); } +INSTANTIATE_TEST_SUITE_P(TouchIntegrationTestDisplayVariants, TouchIntegrationTest, + testing::Values(TouchIntegrationTestDisplays::DISPLAY_INTERNAL, + TouchIntegrationTestDisplays::DISPLAY_INPUT_PORT, + TouchIntegrationTestDisplays::DISPLAY_UNIQUE_ID)); + // --- StylusButtonIntegrationTest --- // Verify the behavior of button presses reported by various kinds of styluses, including buttons // reported by the touchscreen's device, by a fused external stylus, and by an un-fused external // stylus. template -class StylusButtonIntegrationTest : public TouchIntegrationTest { +class StylusButtonIntegrationTest : public BaseTouchIntegrationTest { protected: void SetUp() override { #if !defined(__ANDROID__) GTEST_SKIP(); #endif - TouchIntegrationTest::SetUp(); + BaseTouchIntegrationTest::SetUp(); mTouchscreen = mDevice.get(); mTouchscreenInfo = mDeviceInfo; @@ -1924,8 +1981,8 @@ private: std::unique_ptr mStylusDeviceLifecycleTracker{}; // Hide the base class's device to expose it with a different name for readability. - using TouchIntegrationTest::mDevice; - using TouchIntegrationTest::mDeviceInfo; + using BaseTouchIntegrationTest::mDevice; + using BaseTouchIntegrationTest::mDeviceInfo; }; using StylusButtonIntegrationTestTypes = @@ -2177,7 +2234,7 @@ TYPED_TEST(StylusButtonIntegrationTest, StylusButtonMotionEventsDisabled) { // Verify the behavior of an external stylus. An external stylus can report pressure or button // data independently of the touchscreen, which is then sent as a MotionEvent as part of an // ongoing stylus gesture that is being emitted by the touchscreen. -using ExternalStylusIntegrationTest = TouchIntegrationTest; +using ExternalStylusIntegrationTest = BaseTouchIntegrationTest; TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureReported) { const Point centerPoint = mDevice->getCenterPoint(); diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp index 97a26141e0..7ceaccf0f3 100644 --- a/services/inputflinger/tests/UinputDevice.cpp +++ b/services/inputflinger/tests/UinputDevice.cpp @@ -159,10 +159,11 @@ void UinputExternalStylusWithPressure::setPressure(int32_t pressure) { // --- UinputTouchScreen --- -UinputTouchScreen::UinputTouchScreen(const Rect& size) +UinputTouchScreen::UinputTouchScreen(const Rect& size, const std::string& physicalPort) : UinputKeyboard(DEVICE_NAME, PRODUCT_ID, {BTN_TOUCH, BTN_TOOL_PEN, BTN_STYLUS, BTN_STYLUS2, BTN_STYLUS3}), - mSize(size) {} + mSize(size), + mPhysicalPort(physicalPort) {} void UinputTouchScreen::configureDevice(int fd, uinput_user_dev* device) { UinputKeyboard::configureDevice(fd, device); @@ -177,6 +178,9 @@ void UinputTouchScreen::configureDevice(int fd, uinput_user_dev* device) { ioctl(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID); ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOOL_TYPE); ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT); + if (!mPhysicalPort.empty()) { + ioctl(fd, UI_SET_PHYS, mPhysicalPort.c_str()); + } device->absmin[ABS_MT_SLOT] = RAW_SLOT_MIN; device->absmax[ABS_MT_SLOT] = RAW_SLOT_MAX; diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h index 51e331df8f..5b07465fda 100644 --- a/services/inputflinger/tests/UinputDevice.h +++ b/services/inputflinger/tests/UinputDevice.h @@ -197,11 +197,12 @@ public: const Point getCenterPoint(); protected: - explicit UinputTouchScreen(const Rect& size); + explicit UinputTouchScreen(const Rect& size, const std::string& physicalPort = ""); private: void configureDevice(int fd, uinput_user_dev* device) override; const Rect mSize; + const std::string mPhysicalPort; }; } // namespace android -- GitLab From f12ede5a0eb14da306baa8f265a34490f531a240 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Mon, 14 Aug 2023 17:40:06 +0000 Subject: [PATCH 0459/1187] Disable crashing fuzzer on infra This reverts commit 7ecae40568a745b4a331e04ea4532e78979044ef. Reason for revert: Disabling crashing fuzzer on infra. Waiting for b/295181193 Change-Id: I056aacfea5450b85f40be9f9a02484758013a3e2 --- libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp index 96092b10d3..690c39afc9 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp @@ -36,8 +36,8 @@ cc_fuzz { triage_assignee: "waghpawan@google.com", // This fuzzer should be used only test fuzzService locally - fuzz_on_haiku_host: true, - fuzz_on_haiku_device: true, + fuzz_on_haiku_host: false, + fuzz_on_haiku_device: false, }, } -- GitLab From cee446c2515b6e7cd7b359a67f4774713e62ac4e Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Tue, 8 Aug 2023 12:30:10 -0500 Subject: [PATCH 0460/1187] Add getStalledTransactionInfo method to SurfaceComposer Bug: 287577707 Test: presubmits Change-Id: I9c464ee302e7bafe8d45021063368fcd984e27ec Merged-In: I9c464ee302e7bafe8d45021063368fcd984e27ec --- libs/gui/Android.bp | 2 + libs/gui/SurfaceComposerClient.cpp | 7 ++++ .../aidl/android/gui/ISurfaceComposer.aidl | 7 ++++ .../android/gui/StalledTransactionInfo.aidl | 24 +++++++++++ libs/gui/fuzzer/libgui_fuzzer_utils.h | 2 + libs/gui/include/gui/SurfaceComposerClient.h | 4 ++ libs/gui/tests/Surface_test.cpp | 5 +++ .../FrontEnd/TransactionHandler.cpp | 39 ++++++++++++------ .../FrontEnd/TransactionHandler.h | 19 +++++++-- services/surfaceflinger/SurfaceFlinger.cpp | 40 +++++++++++++++++-- services/surfaceflinger/SurfaceFlinger.h | 5 +++ 11 files changed, 136 insertions(+), 18 deletions(-) create mode 100644 libs/gui/android/gui/StalledTransactionInfo.aidl diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index d7e7eb8ea1..298838d816 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -62,6 +62,7 @@ filegroup { name: "guiconstants_aidl", srcs: [ "android/gui/DropInputMode.aidl", + "android/gui/StalledTransactionInfo.aidl", "android/**/TouchOcclusionMode.aidl", ], } @@ -140,6 +141,7 @@ aidl_library { "android/gui/IWindowInfosListener.aidl", "android/gui/IWindowInfosPublisher.aidl", "android/gui/IWindowInfosReportedListener.aidl", + "android/gui/StalledTransactionInfo.aidl", "android/gui/WindowInfo.aidl", "android/gui/WindowInfosUpdate.aidl", ], diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 0b20186610..180ed095d8 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1302,6 +1302,13 @@ sp SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId dis return status.isOk() ? display : nullptr; } +std::optional SurfaceComposerClient::getStalledTransactionInfo( + pid_t pid) { + std::optional result; + ComposerServiceAIDL::getComposerService()->getStalledTransactionInfo(pid, &result); + return result; +} + void SurfaceComposerClient::Transaction::setAnimationTransaction() { mAnimation = true; } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index 539a1c140e..7e652ac0b2 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -46,6 +46,7 @@ import android.gui.LayerDebugInfo; import android.gui.OverlayProperties; import android.gui.PullAtomData; import android.gui.ARect; +import android.gui.StalledTransactionInfo; import android.gui.StaticDisplayInfo; import android.gui.WindowInfosListenerInfo; @@ -507,4 +508,10 @@ interface ISurfaceComposer { void removeWindowInfosListener(IWindowInfosListener windowInfosListener); OverlayProperties getOverlaySupport(); + + /** + * Returns an instance of StalledTransaction if a transaction from the passed pid has not been + * applied in SurfaceFlinger due to an unsignaled fence. Otherwise, null is returned. + */ + @nullable StalledTransactionInfo getStalledTransactionInfo(int pid); } diff --git a/libs/gui/android/gui/StalledTransactionInfo.aidl b/libs/gui/android/gui/StalledTransactionInfo.aidl new file mode 100644 index 0000000000..e6aa9bd1c7 --- /dev/null +++ b/libs/gui/android/gui/StalledTransactionInfo.aidl @@ -0,0 +1,24 @@ +/* + * Copyright 2023 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. + */ + +package android.gui; + +/** @hide */ +parcelable StalledTransactionInfo { + String layerName; + long bufferId; + long frameNumber; +} \ No newline at end of file diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index 4c7d0562af..c70197cb23 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -158,6 +158,8 @@ public: MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp&), (override)); MOCK_METHOD(binder::Status, getOverlaySupport, (gui::OverlayProperties*), (override)); + MOCK_METHOD(binder::Status, getStalledTransactionInfo, + (int32_t, std::optional*), (override)); }; class FakeBnSurfaceComposerClient : public gui::BnSurfaceComposerClient { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 3cf57b11e9..dbcbd3bd62 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -371,6 +371,10 @@ public: //! Get token for a physical display given its stable ID static sp getPhysicalDisplayToken(PhysicalDisplayId displayId); + // Returns StalledTransactionInfo if a transaction from the provided pid has not been applied + // due to an unsignaled fence. + static std::optional getStalledTransactionInfo(pid_t pid); + struct SCHash { std::size_t operator()(const sp& sc) const { return std::hash{}(sc.get()); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 567604dbec..d7910d26aa 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1016,6 +1016,11 @@ public: return binder::Status::ok(); } + binder::Status getStalledTransactionInfo( + int32_t /*pid*/, std::optional* /*result*/) override { + return binder::Status::ok(); + } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp index fa8eb3cf13..6e78e93650 100644 --- a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp +++ b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp @@ -186,21 +186,36 @@ bool TransactionHandler::hasPendingTransactions() { } void TransactionHandler::onTransactionQueueStalled(uint64_t transactionId, - sp& listener, - const std::string& reason) { - if (std::find(mStalledTransactions.begin(), mStalledTransactions.end(), transactionId) != - mStalledTransactions.end()) { - return; - } + StalledTransactionInfo stalledTransactionInfo) { + std::lock_guard lock{mStalledMutex}; + mStalledTransactions.emplace(transactionId, std::move(stalledTransactionInfo)); +} + +void TransactionHandler::removeFromStalledTransactions(uint64_t transactionId) { + std::lock_guard lock{mStalledMutex}; + mStalledTransactions.erase(transactionId); +} - mStalledTransactions.push_back(transactionId); - listener->onTransactionQueueStalled(String8(reason.c_str())); +std::optional +TransactionHandler::getStalledTransactionInfo(pid_t pid) { + std::lock_guard lock{mStalledMutex}; + for (auto [_, stalledTransactionInfo] : mStalledTransactions) { + if (pid == stalledTransactionInfo.pid) { + return stalledTransactionInfo; + } + } + return std::nullopt; } -void TransactionHandler::removeFromStalledTransactions(uint64_t id) { - auto it = std::find(mStalledTransactions.begin(), mStalledTransactions.end(), id); - if (it != mStalledTransactions.end()) { - mStalledTransactions.erase(it); +void TransactionHandler::onLayerDestroyed(uint32_t layerId) { + std::lock_guard lock{mStalledMutex}; + for (auto it = mStalledTransactions.begin(); it != mStalledTransactions.end();) { + if (it->second.layerId == layerId) { + it = mStalledTransactions.erase(it); + } else { + it++; + } } } + } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.h b/services/surfaceflinger/FrontEnd/TransactionHandler.h index 865835f92d..ff54dc5450 100644 --- a/services/surfaceflinger/FrontEnd/TransactionHandler.h +++ b/services/surfaceflinger/FrontEnd/TransactionHandler.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -61,9 +62,18 @@ public: std::vector flushTransactions(); void addTransactionReadyFilter(TransactionFilter&&); void queueTransaction(TransactionState&&); - void onTransactionQueueStalled(uint64_t transactionId, sp&, - const std::string& reason); + + struct StalledTransactionInfo { + pid_t pid; + uint32_t layerId; + std::string layerName; + uint64_t bufferId; + uint64_t frameNumber; + }; + void onTransactionQueueStalled(uint64_t transactionId, StalledTransactionInfo); void removeFromStalledTransactions(uint64_t transactionId); + std::optional getStalledTransactionInfo(pid_t pid); + void onLayerDestroyed(uint32_t layerId); private: // For unit tests @@ -79,7 +89,10 @@ private: LocklessQueue mLocklessTransactionQueue; std::atomic mPendingTransactionCount = 0; ftl::SmallVector mTransactionReadyFilters; - std::vector mStalledTransactions; + + std::mutex mStalledMutex; + std::unordered_map mStalledTransactions + GUARDED_BY(mStalledMutex); }; } // namespace surfaceflinger::frontend } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b832563201..39ea248ea6 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4369,9 +4369,13 @@ TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyBufferC (flushState.queueProcessTime - transaction.postTime) > std::chrono::nanoseconds(4s).count()) { mTransactionHandler - .onTransactionQueueStalled(transaction.id, listener, - "Buffer processing hung up due to stuck " - "fence. Indicates GPU hang"); + .onTransactionQueueStalled(transaction.id, + {.pid = layer->getOwnerPid(), + .layerId = static_cast( + layer->getSequence()), + .layerName = layer->getDebugName(), + .bufferId = s.bufferData->getId(), + .frameNumber = s.bufferData->frameNumber}); } ATRACE_FORMAT("fence unsignaled %s", layer->getDebugName()); return TraverseBuffersReturnValues::STOP_TRAVERSAL; @@ -5395,6 +5399,8 @@ void SurfaceFlinger::onHandleDestroyed(BBinder* handle, sp& layer, uint32 mDestroyedHandles.emplace_back(layerId); } + mTransactionHandler.onLayerDestroyed(layerId); + Mutex::Autolock lock(mStateLock); markLayerPendingRemovalLocked(layer); layer->onHandleDestroyed(); @@ -8017,6 +8023,12 @@ status_t SurfaceFlinger::removeWindowInfosListener( return NO_ERROR; } +status_t SurfaceFlinger::getStalledTransactionInfo( + int pid, std::optional& result) { + result = mTransactionHandler.getStalledTransactionInfo(pid); + return NO_ERROR; +} + std::shared_ptr SurfaceFlinger::getExternalTextureFromBufferData( BufferData& bufferData, const char* layerName, uint64_t transactionId) { if (bufferData.buffer && @@ -9121,6 +9133,28 @@ binder::Status SurfaceComposerAIDL::removeWindowInfosListener( return binderStatusFromStatusT(status); } +binder::Status SurfaceComposerAIDL::getStalledTransactionInfo( + int pid, std::optional* outInfo) { + const int callingPid = IPCThreadState::self()->getCallingPid(); + const int callingUid = IPCThreadState::self()->getCallingUid(); + if (!checkPermission(sAccessSurfaceFlinger, callingPid, callingUid)) { + return binderStatusFromStatusT(PERMISSION_DENIED); + } + + std::optional stalledTransactionInfo; + status_t status = mFlinger->getStalledTransactionInfo(pid, stalledTransactionInfo); + if (stalledTransactionInfo) { + gui::StalledTransactionInfo result; + result.layerName = String16{stalledTransactionInfo->layerName.c_str()}, + result.bufferId = stalledTransactionInfo->bufferId, + result.frameNumber = stalledTransactionInfo->frameNumber, + outInfo->emplace(std::move(result)); + } else { + outInfo->reset(); + } + return binderStatusFromStatusT(status); +} + status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) { if (!mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) { IPCThreadState* ipc = IPCThreadState::self(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index ee1e1f6865..e3e72ed224 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -618,6 +618,9 @@ private: status_t removeWindowInfosListener( const sp& windowInfosListener) const; + status_t getStalledTransactionInfo( + int pid, std::optional& result); + // Implements IBinder::DeathRecipient. void binderDied(const wp& who) override; @@ -1545,6 +1548,8 @@ public: gui::WindowInfosListenerInfo* outInfo) override; binder::Status removeWindowInfosListener( const sp& windowInfosListener) override; + binder::Status getStalledTransactionInfo(int pid, + std::optional* outInfo); private: static const constexpr bool kUsePermissionCache = true; -- GitLab From 84fbba9c304ef8f11c3a5f956f48bf04745eefc2 Mon Sep 17 00:00:00 2001 From: Robert Phillips Date: Mon, 14 Aug 2023 16:06:18 -0400 Subject: [PATCH 0461/1187] Create a Protected RenderTarget when blurring a Protected Image Test: manual - testing on Netflix app Bug: 242266174 Change-Id: I03c8f6159fdf6885bb55c1a14652234d4f3525e6 --- libs/renderengine/skia/filters/KawaseBlurFilter.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp index 7bf2b0c16f..5c9820cdc5 100644 --- a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp +++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp @@ -111,9 +111,9 @@ sk_sp KawaseBlurFilter::generate(GrRecordingContext* context, constexpr int kSampleCount = 1; constexpr bool kMipmapped = false; constexpr SkSurfaceProps* kProps = nullptr; - sk_sp surface = - SkSurfaces::RenderTarget(context, skgpu::Budgeted::kYes, scaledInfo, kSampleCount, - kTopLeft_GrSurfaceOrigin, kProps, kMipmapped); + sk_sp surface = SkSurfaces::RenderTarget(context, skgpu::Budgeted::kYes, scaledInfo, + kSampleCount, kTopLeft_GrSurfaceOrigin, + kProps, kMipmapped, input->isProtected()); LOG_ALWAYS_FATAL_IF(!surface, "%s: Failed to create surface for blurring!", __func__); sk_sp tmpBlur = makeImage(surface.get(), &blurBuilder); -- GitLab From c7ab564d8825f96103acec56684e5b0af1355073 Mon Sep 17 00:00:00 2001 From: Victor Hsieh Date: Fri, 28 Jul 2023 15:07:55 -0700 Subject: [PATCH 0462/1187] installd: allow enabling fs-verity to a given file The caller is allowed to request installd to enable fs-verity to a given file. Normally this is initiated by the app through an API, via system server. We must not allow an app to enable fs-verity to a file they don't own. In addition, the design also treat the less-privilged system server as untrusted and limit what it can do through the API. See code comments for more details. Bug: 285185747 Test: Call the API from a local client Test: atest installd_service_test Change-Id: I0782a9b23f3817898df0703cfdd9d8670f8fcdfb --- cmds/installd/InstalldNativeService.cpp | 126 ++++++++++++++++++ cmds/installd/InstalldNativeService.h | 26 ++++ .../installd/binder/android/os/IInstalld.aidl | 16 +++ cmds/installd/tests/installd_service_test.cpp | 101 ++++++++++++++ 4 files changed, 269 insertions(+) diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index b302f52f3e..e2a2927f2b 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -84,6 +86,8 @@ using android::base::ParseUint; using android::base::Split; using android::base::StringPrintf; +using android::base::unique_fd; +using android::os::ParcelFileDescriptor; using std::endl; namespace android { @@ -229,6 +233,14 @@ binder::Status checkArgumentFileName(const std::string& path) { return ok(); } +binder::Status checkUidInAppRange(int32_t appUid) { + if (FIRST_APPLICATION_UID <= appUid && appUid <= LAST_APPLICATION_UID) { + return ok(); + } + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("UID %d is outside of the range", appUid)); +} + #define ENFORCE_UID(uid) { \ binder::Status status = checkUid((uid)); \ if (!status.isOk()) { \ @@ -283,6 +295,14 @@ binder::Status checkArgumentFileName(const std::string& path) { } \ } +#define CHECK_ARGUMENT_UID_IN_APP_RANGE(uid) \ + { \ + binder::Status status = checkUidInAppRange((uid)); \ + if (!status.isOk()) { \ + return status; \ + } \ + } + #ifdef GRANULAR_LOCKS /** @@ -383,6 +403,33 @@ using PackageLockGuard = std::lock_guard; } // namespace +binder::Status InstalldNativeService::FsveritySetupAuthToken::authenticate( + const ParcelFileDescriptor& authFd, int32_t appUid, int32_t userId) { + int open_flags = fcntl(authFd.get(), F_GETFL); + if (open_flags < 0) { + return exception(binder::Status::EX_SERVICE_SPECIFIC, "fcntl failed"); + } + if ((open_flags & O_ACCMODE) != O_WRONLY && (open_flags & O_ACCMODE) != O_RDWR) { + return exception(binder::Status::EX_SECURITY, "Received FD with unexpected open flag"); + } + if (fstat(authFd.get(), &this->mStatFromAuthFd) < 0) { + return exception(binder::Status::EX_SERVICE_SPECIFIC, "fstat failed"); + } + if (!S_ISREG(this->mStatFromAuthFd.st_mode)) { + return exception(binder::Status::EX_SECURITY, "Not a regular file"); + } + // Don't accept a file owned by a different app. + uid_t uid = multiuser_get_uid(userId, appUid); + if (this->mStatFromAuthFd.st_uid != uid) { + return exception(binder::Status::EX_SERVICE_SPECIFIC, "File not owned by appUid"); + } + return ok(); +} + +bool InstalldNativeService::FsveritySetupAuthToken::isSameStat(const struct stat& st) const { + return memcmp(&st, &mStatFromAuthFd, sizeof(st)) == 0; +} + status_t InstalldNativeService::start() { IPCThreadState::self()->disableBackgroundScheduling(true); status_t ret = BinderService::publish(); @@ -3857,5 +3904,84 @@ binder::Status InstalldNativeService::getOdexVisibility( return *_aidl_return == -1 ? error() : ok(); } +// Creates an auth token to be used in enableFsverity. This token is really to store a proof that +// the caller can write to a file, represented by the authFd. Effectively, system_server as the +// attacker-in-the-middle cannot enable fs-verity on arbitrary app files. If the FD is not writable, +// return null. +// +// appUid and userId are passed for additional ownership check, such that one app can not be +// authenticated for another app's file. These parameters are assumed trusted for this purpose of +// consistency check. +// +// Notably, creating the token allows us to manage the writable FD easily during enableFsverity. +// Since enabling fs-verity to a file requires no outstanding writable FD, passing the authFd to the +// server allows the server to hold the only reference (as long as the client app doesn't). +binder::Status InstalldNativeService::createFsveritySetupAuthToken( + const ParcelFileDescriptor& authFd, int32_t appUid, int32_t userId, + sp* _aidl_return) { + CHECK_ARGUMENT_UID_IN_APP_RANGE(appUid); + ENFORCE_VALID_USER(userId); + + auto token = sp::make(); + binder::Status status = token->authenticate(authFd, appUid, userId); + if (!status.isOk()) { + return status; + } + *_aidl_return = token; + return ok(); +} + +// Enables fs-verity for filePath, which must be an absolute path and the same inode as in the auth +// token previously returned from createFsveritySetupAuthToken, and owned by the app uid. As +// installd is more privileged than its client / system server, we attempt to limit what a +// (compromised) client can do. +// +// The reason for this app request to go through installd is to avoid exposing a risky area (PKCS#7 +// signature verification) in the kernel to the app as an attack surface (it can't be system server +// because it can't override DAC and manipulate app files). Note that we should be able to drop +// these hops and simply the app calls the ioctl, once all upgrading devices run with a kernel +// without fs-verity built-in signature (https://r.android.com/2650402). +binder::Status InstalldNativeService::enableFsverity(const sp& authToken, + const std::string& filePath, + const std::string& packageName, + int32_t* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PATH(filePath); + CHECK_ARGUMENT_PACKAGE_NAME(packageName); + LOCK_PACKAGE(); + if (authToken == nullptr) { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Received a null auth token"); + } + + // Authenticate to check the targeting file is the same inode as the authFd. + sp authTokenBinder = IInterface::asBinder(authToken)->localBinder(); + if (authTokenBinder == nullptr) { + return exception(binder::Status::EX_SECURITY, "Received a non-local auth token"); + } + auto authTokenInstance = sp::cast(authTokenBinder); + unique_fd rfd(open(filePath.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW)); + struct stat stFromPath; + if (fstat(rfd.get(), &stFromPath) < 0) { + *_aidl_return = errno; + return ok(); + } + if (!authTokenInstance->isSameStat(stFromPath)) { + LOG(DEBUG) << "FD authentication failed"; + *_aidl_return = EPERM; + return ok(); + } + + fsverity_enable_arg arg = {}; + arg.version = 1; + arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; + arg.block_size = 4096; + if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, &arg) < 0) { + *_aidl_return = errno; + } else { + *_aidl_return = 0; + } + return ok(); +} + } // namespace installd } // namespace android diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 521afc3f97..0f28234422 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -19,6 +19,7 @@ #define COMMANDS_H_ #include +#include #include #include @@ -35,8 +36,26 @@ namespace android { namespace installd { +using IFsveritySetupAuthToken = android::os::IInstalld::IFsveritySetupAuthToken; + class InstalldNativeService : public BinderService, public os::BnInstalld { public: + class FsveritySetupAuthToken : public os::IInstalld::BnFsveritySetupAuthToken { + public: + FsveritySetupAuthToken() : mStatFromAuthFd() {} + + binder::Status authenticate(const android::os::ParcelFileDescriptor& authFd, int32_t appUid, + int32_t userId); + bool isSameStat(const struct stat& st) const; + + private: + // Not copyable or movable + FsveritySetupAuthToken(const FsveritySetupAuthToken&) = delete; + FsveritySetupAuthToken& operator=(const FsveritySetupAuthToken&) = delete; + + struct stat mStatFromAuthFd; + }; + static status_t start(); static char const* getServiceName() { return "installd"; } virtual status_t dump(int fd, const Vector &args) override; @@ -192,6 +211,13 @@ public: const std::optional& outputPath, int32_t* _aidl_return); + binder::Status createFsveritySetupAuthToken(const android::os::ParcelFileDescriptor& authFd, + int32_t appUid, int32_t userId, + android::sp* _aidl_return); + binder::Status enableFsverity(const android::sp& authToken, + const std::string& filePath, const std::string& packageName, + int32_t* _aidl_return); + private: std::recursive_mutex mLock; std::unordered_map> mUserIdLock; diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 9ad853b1df..8893e38c03 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -134,6 +134,22 @@ interface IInstalld { int getOdexVisibility(@utf8InCpp String packageName, @utf8InCpp String apkPath, @utf8InCpp String instructionSet, @nullable @utf8InCpp String outputPath); + interface IFsveritySetupAuthToken { + // Using an interface here is an easy way to create and maintain an IBinder object across + // the processes. When installd creates this binder object, it stores the file stat + // privately for later authentication, and only returns the reference to the caller process. + // Once the binder object has no reference count, it gets destructed automatically + // (alternatively, installd can maintain an internal mapping, but it is more error prone + // because the app may crash and not finish the fs-verity setup, keeping the memory unused + // forever). + // + // We don't necessarily need a method here, so it's left blank intentionally. + } + IFsveritySetupAuthToken createFsveritySetupAuthToken(in ParcelFileDescriptor authFd, int appUid, + int userId); + int enableFsverity(in IFsveritySetupAuthToken authToken, @utf8InCpp String filePath, + @utf8InCpp String packageName); + const int FLAG_STORAGE_DE = 0x1; const int FLAG_STORAGE_CE = 0x2; const int FLAG_STORAGE_EXTERNAL = 0x4; diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp index 858a92cc65..4bc92afa18 100644 --- a/cmds/installd/tests/installd_service_test.cpp +++ b/cmds/installd/tests/installd_service_test.cpp @@ -42,9 +42,12 @@ #include "binder_test_utils.h" #include "dexopt.h" #include "globals.h" +#include "unique_file.h" #include "utils.h" using android::base::StringPrintf; +using android::base::unique_fd; +using android::os::ParcelFileDescriptor; using std::filesystem::is_empty; namespace android { @@ -136,6 +139,16 @@ static int create(const std::string& path, uid_t owner, gid_t group, mode_t mode return fd; } +static void create_with_content(const std::string& path, uid_t owner, gid_t group, mode_t mode, + const std::string& content) { + int fd = ::open(path.c_str(), O_RDWR | O_CREAT, mode); + EXPECT_NE(fd, -1); + EXPECT_TRUE(android::base::WriteStringToFd(content, fd)); + EXPECT_EQ(::fchown(fd, owner, group), 0); + EXPECT_EQ(::fchmod(fd, mode), 0); + close(fd); +} + static void touch(const std::string& path, uid_t owner, gid_t group, mode_t mode) { EXPECT_EQ(::close(create(path.c_str(), owner, group, mode)), 0); } @@ -527,6 +540,94 @@ TEST_F(ServiceTest, GetAppSizeWrongSizes) { externalStorageAppId, ceDataInodes, codePaths, &externalStorageSize)); } + +class FsverityTest : public ServiceTest { +protected: + binder::Status createFsveritySetupAuthToken(const std::string& path, int open_mode, + sp* _aidl_return) { + unique_fd ufd(open(path.c_str(), open_mode)); + EXPECT_GE(ufd.get(), 0) << "open failed: " << strerror(errno); + ParcelFileDescriptor rfd(std::move(ufd)); + return service->createFsveritySetupAuthToken(std::move(rfd), kTestAppId, kTestUserId, + _aidl_return); + } +}; + +TEST_F(FsverityTest, enableFsverity) { + const std::string path = kTestPath + "/foo"; + create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content"); + UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); }); + + // Expect to fs-verity setup to succeed + sp authToken; + binder::Status status = createFsveritySetupAuthToken(path, O_RDWR, &authToken); + EXPECT_TRUE(status.isOk()); + EXPECT_TRUE(authToken != nullptr); + + // Verity auth token works to enable fs-verity + int32_t errno_local; + status = service->enableFsverity(authToken, path, "fake.package.name", &errno_local); + EXPECT_TRUE(status.isOk()); + EXPECT_EQ(errno_local, 0); +} + +TEST_F(FsverityTest, enableFsverity_nullAuthToken) { + const std::string path = kTestPath + "/foo"; + create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content"); + UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); }); + + // Verity null auth token fails + sp authToken; + int32_t errno_local; + binder::Status status = + service->enableFsverity(authToken, path, "fake.package.name", &errno_local); + EXPECT_FALSE(status.isOk()); +} + +TEST_F(FsverityTest, enableFsverity_differentFile) { + const std::string path = kTestPath + "/foo"; + create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content"); + UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); }); + + // Expect to fs-verity setup to succeed + sp authToken; + binder::Status status = createFsveritySetupAuthToken(path, O_RDWR, &authToken); + EXPECT_TRUE(status.isOk()); + EXPECT_TRUE(authToken != nullptr); + + // Verity auth token does not work for a different file + const std::string anotherPath = kTestPath + "/bar"; + ASSERT_TRUE(android::base::WriteStringToFile("content", anotherPath)); + UniqueFile raii2(/*fd=*/-1, anotherPath, [](const std::string& path) { unlink(path.c_str()); }); + int32_t errno_local; + status = service->enableFsverity(authToken, anotherPath, "fake.package.name", &errno_local); + EXPECT_TRUE(status.isOk()); + EXPECT_NE(errno_local, 0); +} + +TEST_F(FsverityTest, createFsveritySetupAuthToken_ReadonlyFdDoesNotAuthenticate) { + const std::string path = kTestPath + "/foo"; + create_with_content(path, kTestAppUid, kTestAppUid, 0600, "content"); + UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); }); + + // Expect the fs-verity setup to fail + sp authToken; + binder::Status status = createFsveritySetupAuthToken(path, O_RDONLY, &authToken); + EXPECT_FALSE(status.isOk()); +} + +TEST_F(FsverityTest, createFsveritySetupAuthToken_UnownedFile) { + const std::string path = kTestPath + "/foo"; + // Simulate world-writable file owned by another app + create_with_content(path, kTestAppUid + 1, kTestAppUid + 1, 0666, "content"); + UniqueFile raii(/*fd=*/-1, path, [](const std::string& path) { unlink(path.c_str()); }); + + // Expect the fs-verity setup to fail + sp authToken; + binder::Status status = createFsveritySetupAuthToken(path, O_RDWR, &authToken); + EXPECT_FALSE(status.isOk()); +} + static bool mkdirs(const std::string& path, mode_t mode) { struct stat sb; if (stat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode)) { -- GitLab From 04c90eb5cdfd0f4487dabc589defba5579ada09a Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Mon, 14 Aug 2023 21:31:43 +0000 Subject: [PATCH 0463/1187] Updating fuzzService with IBinder transact codes Using transaction codes defined in IBinder with B_PACK_CHARS so that these functions can be easily covered in fuzzing. Test: atest -c fuzz_service_test Test: atest -c binderRecordReplayTest Bug: 295191685 Change-Id: Ic6bd5b22d943c38343e177794bdff3b991f8103b --- libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp index 47d2a0a701..93ac1162ed 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp @@ -60,8 +60,15 @@ void fuzzService(const std::vector>& binders, FuzzedDataProvider&& p while (provider.remaining_bytes() > 0) { // Most of the AIDL services will have small set of transaction codes. - uint32_t code = provider.ConsumeBool() ? provider.ConsumeIntegral() - : provider.ConsumeIntegralInRange(0, 100); + // TODO(b/295942369) : Add remaining transact codes from IBinder.h + uint32_t code = provider.ConsumeBool() + ? provider.ConsumeIntegral() + : provider.PickValueInArray( + {provider.ConsumeIntegralInRange(0, 100), + 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 flags = provider.ConsumeIntegral(); Parcel data; // for increased fuzz coverage -- GitLab From 9b366602e3609575fdc0c33694c057740298deb7 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Mon, 14 Aug 2023 21:37:30 +0000 Subject: [PATCH 0464/1187] Tests for dump and shell cmd transactions Adding tests for Dump and Shell cmd transactions in TestServiceFuzzer by overriding onTrasact. Tests Verify that DUMP_TRANSACTION and SHELL_CMD_TRANSACTION codes are beinge hit. Test: atest -c fuzz_service_test Test: atest -c binderRecordReplayTest Bug: 295191685 Change-Id: I779ab49471fef3ac466e06f3e8a6b544087586b0 --- .../test_fuzzer/TestServiceFuzzer.cpp | 16 ++++++++++++++++ .../test_fuzzer/run_fuzz_service_test.sh | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp index 46205d7689..ba1a6a1ccd 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp @@ -33,6 +33,8 @@ enum class CrashType { ON_KNOWN_UID, ON_SYSTEM_AID, ON_ROOT_AID, + ON_DUMP_TRANSACT, + ON_SHELL_CMD_TRANSACT, }; // This service is to verify that fuzzService is functioning properly @@ -92,6 +94,16 @@ public: return Status::ok(); } + status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override { + if (mCrash == CrashType::ON_DUMP_TRANSACT && code == DUMP_TRANSACTION) { + LOG_ALWAYS_FATAL("Expected crash, DUMP."); + } else if (mCrash == CrashType::ON_SHELL_CMD_TRANSACT && + code == SHELL_COMMAND_TRANSACTION) { + LOG_ALWAYS_FATAL("Expected crash, SHELL_CMD."); + } + return BnTestService::onTransact(code, data, reply, flags); + } + private: CrashType mCrash; }; @@ -121,6 +133,10 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { gCrashType = CrashType::ON_ROOT_AID; } else if (arg == "BINDER") { gCrashType = CrashType::ON_BINDER; + } else if (arg == "DUMP") { + gCrashType = CrashType::ON_DUMP_TRANSACT; + } else if (arg == "SHELL_CMD") { + gCrashType = CrashType::ON_SHELL_CMD_TRANSACT; } else { printf("INVALID ARG\n"); exit(0); // success because this is a crash test diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh index 25906d8aeb..c447bffbfd 100755 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh @@ -27,7 +27,7 @@ then exit 1 fi -for CRASH_TYPE in PLAIN KNOWN_UID AID_SYSTEM AID_ROOT BINDER; do +for CRASH_TYPE in PLAIN KNOWN_UID AID_SYSTEM AID_ROOT BINDER DUMP SHELL_CMD; do echo "INFO: Running fuzzer : test_service_fuzzer_should_crash $CRASH_TYPE" ./test_service_fuzzer_should_crash "$CRASH_TYPE" -max_total_time=30 &>"$FUZZER_OUT" -- GitLab From 8a2e589e28329fd597dbb0d14f4f8f443fe9a4b0 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 14 Aug 2023 13:59:40 -0700 Subject: [PATCH 0465/1187] Override VelocityTracker strategy for non-differential axes only VelocityTracker may use different strategies, depending on the system flags. By default, the behaviour is like this: AXIS_X -> lsq2 AXIS_Y -> lsq2 AXIS_SCROLL -> impulse However, if we provide a specific strategy to VT, then things would change. The new map would look like this: AXIS_X -> provided strategy AXIS_Y -> provided strategy AXIS_SCROLL -> provided strategy This works fine if the user specifies "impulse" as the desired strategy, because impulse supports all of the axes. However, lsq2 only works in non-differential mode. The combination of "AXIS_SCROLL -> lsq2" is not allowed. To fix this, we only allow the specified strategy to affect non-differential axes. This is fine, because currently, impulse is the only strategy that can work in the differential mode. To reproduce the issue: 1. Run `atest VelocityTrackerTest`. Test should pass, because the default strategy is being used. 2. Connect the device to internet 3. Reboot the device 4. Run `atest VelocityTrackerTest` again. Test should fail because the device would pick up an "lsq2" strategy value and then try to run the axis_scroll tests with it. Bug: 295290374 Test: atest VelocityTrackerTest Change-Id: I702a2a3e58db3ce2e0ff0c33122839a527eebab2 --- include/input/VelocityTracker.h | 3 +-- libs/input/VelocityTracker.cpp | 32 +++++++++-------------- libs/input/tests/VelocityTracker_test.cpp | 5 ++++ 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index b58feac444..70d503d782 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -48,6 +48,7 @@ public: INT2 = 8, LEGACY = 9, MAX = LEGACY, + ftl_last = LEGACY, }; /* @@ -81,8 +82,6 @@ public: // TODO(b/32830165): support axis-specific strategies. VelocityTracker(const Strategy strategy = Strategy::DEFAULT); - ~VelocityTracker(); - /** Return true if the axis is supported for velocity tracking, false otherwise. */ static bool isAxisSupported(int32_t axis); diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index 8704eee73d..116b778608 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "VelocityTracker" #include +#include #include #include #include @@ -148,27 +149,19 @@ static std::string matrixToString(const float* a, uint32_t m, uint32_t n, bool r VelocityTracker::VelocityTracker(const Strategy strategy) : mLastEventTime(0), mCurrentPointerIdBits(0), mOverrideStrategy(strategy) {} -VelocityTracker::~VelocityTracker() { -} - bool VelocityTracker::isAxisSupported(int32_t axis) { return DEFAULT_STRATEGY_BY_AXIS.find(axis) != DEFAULT_STRATEGY_BY_AXIS.end(); } void VelocityTracker::configureStrategy(int32_t axis) { const bool isDifferentialAxis = DIFFERENTIAL_AXES.find(axis) != DIFFERENTIAL_AXES.end(); - - std::unique_ptr createdStrategy; - if (mOverrideStrategy != VelocityTracker::Strategy::DEFAULT) { - createdStrategy = createStrategy(mOverrideStrategy, /*deltaValues=*/isDifferentialAxis); + if (isDifferentialAxis || mOverrideStrategy == VelocityTracker::Strategy::DEFAULT) { + // Do not allow overrides of strategies for differential axes, for now. + mConfiguredStrategies[axis] = createStrategy(DEFAULT_STRATEGY_BY_AXIS.at(axis), + /*deltaValues=*/isDifferentialAxis); } else { - createdStrategy = createStrategy(DEFAULT_STRATEGY_BY_AXIS.at(axis), - /*deltaValues=*/isDifferentialAxis); + mConfiguredStrategies[axis] = createStrategy(mOverrideStrategy, /*deltaValues=*/false); } - - LOG_ALWAYS_FATAL_IF(createdStrategy == nullptr, - "Could not create velocity tracker strategy for axis '%" PRId32 "'!", axis); - mConfiguredStrategies[axis] = std::move(createdStrategy); } std::unique_ptr VelocityTracker::createStrategy( @@ -216,6 +209,9 @@ std::unique_ptr VelocityTracker::createStrategy( default: break; } + LOG(FATAL) << "Invalid strategy: " << ftl::enum_string(strategy) + << ", deltaValues = " << deltaValues; + return nullptr; } @@ -272,12 +268,10 @@ void VelocityTracker::addMovement(nsecs_t eventTime, int32_t pointerId, int32_t mConfiguredStrategies[axis]->addMovement(eventTime, pointerId, position); if (DEBUG_VELOCITY) { - ALOGD("VelocityTracker: addMovement eventTime=%" PRId64 ", pointerId=%" PRId32 - ", activePointerId=%s", - eventTime, pointerId, toString(mActivePointerId).c_str()); - - ALOGD(" %d: axis=%d, position=%0.3f, velocity=%s", pointerId, axis, position, - toString(getVelocity(axis, pointerId)).c_str()); + LOG(INFO) << "VelocityTracker: addMovement axis=" << MotionEvent::getLabel(axis) + << ", eventTime=" << eventTime << ", pointerId=" << pointerId + << ", activePointerId=" << toString(mActivePointerId) << ", position=" << position + << ", velocity=" << toString(getVelocity(axis, pointerId)); } } diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index ffebff1e65..1c8ec90373 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -278,6 +278,11 @@ static void computeAndCheckAxisScrollVelocity( const std::vector>& motions, std::optional targetVelocity) { checkVelocity(computeVelocity(strategy, motions, AMOTION_EVENT_AXIS_SCROLL), targetVelocity); + // The strategy LSQ2 is not compatible with AXIS_SCROLL. In those situations, we should fall + // back to a strategy that supports differential axes. + checkVelocity(computeVelocity(VelocityTracker::Strategy::LSQ2, motions, + AMOTION_EVENT_AXIS_SCROLL), + targetVelocity); } static void computeAndCheckQuadraticVelocity(const std::vector& motions, -- GitLab From f7436a190ede63eb75d10bea39de23120c20cbf3 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 14 Aug 2023 15:17:11 -0700 Subject: [PATCH 0466/1187] Move VelocityTracker strategy consts to aidl To ensure Java is in sync with native, move these consts to IInputConstants.aidl. Test: none Bug: 295290374 Change-Id: I616f4e969e5b7ec72263db62f225f85786f5e923 --- include/input/VelocityTracker.h | 25 +++---- libs/input/android/os/IInputConstants.aidl | 84 ++++++++++++++++++++++ 2 files changed, 97 insertions(+), 12 deletions(-) diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h index 70d503d782..2e9949578d 100644 --- a/include/input/VelocityTracker.h +++ b/include/input/VelocityTracker.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -35,18 +36,18 @@ public: static const size_t MAX_DEGREE = 4; enum class Strategy : int32_t { - DEFAULT = -1, - MIN = 0, - IMPULSE = 0, - LSQ1 = 1, - LSQ2 = 2, - LSQ3 = 3, - WLSQ2_DELTA = 4, - WLSQ2_CENTRAL = 5, - WLSQ2_RECENT = 6, - INT1 = 7, - INT2 = 8, - LEGACY = 9, + DEFAULT = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_DEFAULT, + IMPULSE = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_IMPULSE, + LSQ1 = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_LSQ1, + LSQ2 = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_LSQ2, + LSQ3 = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_LSQ3, + WLSQ2_DELTA = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_WLSQ2_DELTA, + WLSQ2_CENTRAL = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_WLSQ2_CENTRAL, + WLSQ2_RECENT = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_WLSQ2_RECENT, + INT1 = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_INT1, + INT2 = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_INT2, + LEGACY = android::os::IInputConstants::VELOCITY_TRACKER_STRATEGY_LEGACY, + MIN = IMPULSE, MAX = LEGACY, ftl_last = LEGACY, }; diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl index dab843b48f..8f6f95b7d1 100644 --- a/libs/input/android/os/IInputConstants.aidl +++ b/libs/input/android/os/IInputConstants.aidl @@ -57,4 +57,88 @@ interface IInputConstants /* The default pointer acceleration value. */ const int DEFAULT_POINTER_ACCELERATION = 3; + + /** + * Use the default Velocity Tracker Strategy. Different axes may use different default + * strategies. + */ + const int VELOCITY_TRACKER_STRATEGY_DEFAULT = -1; + + /** + * Velocity Tracker Strategy: Impulse. + * Physical model of pushing an object. Quality: VERY GOOD. + * Works with duplicate coordinates, unclean finger liftoff. + */ + const int VELOCITY_TRACKER_STRATEGY_IMPULSE = 0; + + /** + * Velocity Tracker Strategy: LSQ1. + * 1st order least squares. Quality: POOR. + * Frequently underfits the touch data especially when the finger accelerates + * or changes direction. Often underestimates velocity. The direction + * is overly influenced by historical touch points. + */ + const int VELOCITY_TRACKER_STRATEGY_LSQ1 = 1; + + /** + * Velocity Tracker Strategy: LSQ2. + * 2nd order least squares. Quality: VERY GOOD. + * Pretty much ideal, but can be confused by certain kinds of touch data, + * particularly if the panel has a tendency to generate delayed, + * duplicate or jittery touch coordinates when the finger is released. + */ + const int VELOCITY_TRACKER_STRATEGY_LSQ2 = 2; + + /** + * Velocity Tracker Strategy: LSQ3. + * 3rd order least squares. Quality: UNUSABLE. + * Frequently overfits the touch data yielding wildly divergent estimates + * of the velocity when the finger is released. + */ + const int VELOCITY_TRACKER_STRATEGY_LSQ3 = 3; + + /** + * Velocity Tracker Strategy: WLSQ2_DELTA. + * 2nd order weighted least squares, delta weighting. Quality: EXPERIMENTAL + */ + const int VELOCITY_TRACKER_STRATEGY_WLSQ2_DELTA = 4; + + /** + * Velocity Tracker Strategy: WLSQ2_CENTRAL. + * 2nd order weighted least squares, central weighting. Quality: EXPERIMENTALe + */ + const int VELOCITY_TRACKER_STRATEGY_WLSQ2_CENTRAL = 5; + + /** + * Velocity Tracker Strategy: WLSQ2_RECENT. + * 2nd order weighted least squares, recent weighting. Quality: EXPERIMENTAL + */ + const int VELOCITY_TRACKER_STRATEGY_WLSQ2_RECENT = 6; + + /** + * Velocity Tracker Strategy: INT1. + * 1st order integrating filter. Quality: GOOD. + * Not as good as 'lsq2' because it cannot estimate acceleration but it is + * more tolerant of errors. Like 'lsq1', this strategy tends to underestimate + * the velocity of a fling but this strategy tends to respond to changes in + * direction more quickly and accurately. + */ + const int VELOCITY_TRACKER_STRATEGY_INT1 = 7; + + /** + * Velocity Tracker Strategy: INT2. + * 2nd order integrating filter. Quality: EXPERIMENTAL. + * For comparison purposes only. Unlike 'int1' this strategy can compensate + * for acceleration but it typically overestimates the effect. + */ + const int VELOCITY_TRACKER_STRATEGY_INT2 = 8; + + /** + * Velocity Tracker Strategy: Legacy. + * Legacy velocity tracker algorithm. Quality: POOR. + * For comparison purposes only. This algorithm is strongly influenced by + * old data points, consistently underestimates velocity and takes a very long + * time to adjust to changes in direction. + */ + const int VELOCITY_TRACKER_STRATEGY_LEGACY = 9; } -- GitLab From 47bcb071be2a72b7854c36a38cf221dfd414bdde Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 15 Aug 2023 02:02:49 +0000 Subject: [PATCH 0467/1187] Delete non-colormanagement code Color management is mandatory now. Bug: 295966830 Test: builds Change-Id: I761cbd3967d1800cc74538f93f1b9c3ffe11ee6a --- .../aidl/android/gui/ISurfaceComposer.aidl | 2 - libs/gui/fuzzer/libgui_fuzzer_utils.h | 1 - libs/gui/tests/Surface_test.cpp | 4 - .../benchmark/RenderEngineBench.cpp | 1 - libs/renderengine/gl/GLESRenderEngine.cpp | 219 +++++++++--------- libs/renderengine/gl/GLESRenderEngine.h | 4 - libs/renderengine/gl/ProgramCache.cpp | 42 ++-- libs/renderengine/gl/ProgramCache.h | 2 +- .../include/renderengine/RenderEngine.h | 14 +- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 7 +- libs/renderengine/skia/SkiaRenderEngine.cpp | 14 +- libs/renderengine/skia/SkiaRenderEngine.h | 6 +- libs/renderengine/skia/SkiaVkRenderEngine.cpp | 2 +- libs/renderengine/tests/RenderEngineTest.cpp | 46 +--- services/surfaceflinger/SurfaceFlinger.cpp | 46 ++-- services/surfaceflinger/SurfaceFlinger.h | 5 - .../tests/LayerRenderTypeTransaction_test.cpp | 24 +- .../tests/LayerTransactionTest.h | 4 - 18 files changed, 170 insertions(+), 273 deletions(-) diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index 5e8e9043c1..81a8825515 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -280,8 +280,6 @@ interface ISurfaceComposer { */ List getLayerDebugInfo(); - boolean getColorManagement(); - /** * Gets the composition preference of the default data space and default pixel format, * as well as the wide color gamut data space and wide color gamut pixel format. diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index 4c7d0562af..c70c2d01cb 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -110,7 +110,6 @@ public: (override)); MOCK_METHOD(binder::Status, onPullAtom, (int32_t, gui::PullAtomData*), (override)); MOCK_METHOD(binder::Status, getLayerDebugInfo, (std::vector*), (override)); - MOCK_METHOD(binder::Status, getColorManagement, (bool*), (override)); MOCK_METHOD(binder::Status, getCompositionPreference, (gui::CompositionPreference*), (override)); MOCK_METHOD(binder::Status, getDisplayedContentSamplingAttributes, diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 567604dbec..1e3147eb42 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -879,10 +879,6 @@ public: return binder::Status::ok(); } - binder::Status getColorManagement(bool* /*outGetColorManagement*/) override { - return binder::Status::ok(); - } - binder::Status getCompositionPreference(gui::CompositionPreference* /*outPref*/) override { return binder::Status::ok(); } diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp index bd7b617ae7..791d4c94b4 100644 --- a/libs/renderengine/benchmark/RenderEngineBench.cpp +++ b/libs/renderengine/benchmark/RenderEngineBench.cpp @@ -121,7 +121,6 @@ static std::unique_ptr createRenderEngine(RenderEngine::RenderEngi .setSupportsBackgroundBlur(true) .setContextPriority(RenderEngine::ContextPriority::REALTIME) .setRenderEngineType(type) - .setUseColorManagerment(true) .build(); return RenderEngine::create(args); } diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index e7a2c7a411..a512b9aca1 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -389,7 +389,6 @@ GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisp mVpWidth(0), mVpHeight(0), mFramebufferImageCacheSize(args.imageCacheSize), - mUseColorManagement(args.useColorManagement), mPrecacheToneMapperShaderOnly(args.precacheToneMapperShaderOnly) { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); @@ -410,33 +409,31 @@ GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisp // mColorBlindnessCorrection = M; - if (mUseColorManagement) { - const ColorSpace srgb(ColorSpace::sRGB()); - const ColorSpace displayP3(ColorSpace::DisplayP3()); - const ColorSpace bt2020(ColorSpace::BT2020()); + const ColorSpace srgb(ColorSpace::sRGB()); + const ColorSpace displayP3(ColorSpace::DisplayP3()); + const ColorSpace bt2020(ColorSpace::BT2020()); - // no chromatic adaptation needed since all color spaces use D65 for their white points. - mSrgbToXyz = mat4(srgb.getRGBtoXYZ()); - mDisplayP3ToXyz = mat4(displayP3.getRGBtoXYZ()); - mBt2020ToXyz = mat4(bt2020.getRGBtoXYZ()); - mXyzToSrgb = mat4(srgb.getXYZtoRGB()); - mXyzToDisplayP3 = mat4(displayP3.getXYZtoRGB()); - mXyzToBt2020 = mat4(bt2020.getXYZtoRGB()); + // no chromatic adaptation needed since all color spaces use D65 for their white points. + mSrgbToXyz = mat4(srgb.getRGBtoXYZ()); + mDisplayP3ToXyz = mat4(displayP3.getRGBtoXYZ()); + mBt2020ToXyz = mat4(bt2020.getRGBtoXYZ()); + mXyzToSrgb = mat4(srgb.getXYZtoRGB()); + mXyzToDisplayP3 = mat4(displayP3.getXYZtoRGB()); + mXyzToBt2020 = mat4(bt2020.getXYZtoRGB()); - // Compute sRGB to Display P3 and BT2020 transform matrix. - // NOTE: For now, we are limiting output wide color space support to - // Display-P3 and BT2020 only. - mSrgbToDisplayP3 = mXyzToDisplayP3 * mSrgbToXyz; - mSrgbToBt2020 = mXyzToBt2020 * mSrgbToXyz; + // Compute sRGB to Display P3 and BT2020 transform matrix. + // NOTE: For now, we are limiting output wide color space support to + // Display-P3 and BT2020 only. + mSrgbToDisplayP3 = mXyzToDisplayP3 * mSrgbToXyz; + mSrgbToBt2020 = mXyzToBt2020 * mSrgbToXyz; - // Compute Display P3 to sRGB and BT2020 transform matrix. - mDisplayP3ToSrgb = mXyzToSrgb * mDisplayP3ToXyz; - mDisplayP3ToBt2020 = mXyzToBt2020 * mDisplayP3ToXyz; + // Compute Display P3 to sRGB and BT2020 transform matrix. + mDisplayP3ToSrgb = mXyzToSrgb * mDisplayP3ToXyz; + mDisplayP3ToBt2020 = mXyzToBt2020 * mDisplayP3ToXyz; - // Compute BT2020 to sRGB and Display P3 transform matrix - mBt2020ToSrgb = mXyzToSrgb * mBt2020ToXyz; - mBt2020ToDisplayP3 = mXyzToDisplayP3 * mBt2020ToXyz; - } + // Compute BT2020 to sRGB and Display P3 transform matrix + mBt2020ToSrgb = mXyzToSrgb * mBt2020ToXyz; + mBt2020ToDisplayP3 = mXyzToDisplayP3 * mBt2020ToXyz; char value[PROPERTY_VALUE_MAX]; property_get("debug.egl.traceGpuCompletion", value, "0"); @@ -518,7 +515,7 @@ Framebuffer* GLESRenderEngine::getFramebufferForDrawing() { std::future GLESRenderEngine::primeCache() { ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext, - mUseColorManagement, mPrecacheToneMapperShaderOnly); + mPrecacheToneMapperShaderOnly); return {}; } @@ -1444,99 +1441,95 @@ void GLESRenderEngine::drawMesh(const Mesh& mesh) { // BT2020 data space, in that case, the output data space is set to be // BT2020_HLG or BT2020_PQ respectively. In GPU fall back we need // to respect this and convert non-HDR content to HDR format. - if (mUseColorManagement) { - Dataspace inputStandard = static_cast(mDataSpace & Dataspace::STANDARD_MASK); - Dataspace inputTransfer = static_cast(mDataSpace & Dataspace::TRANSFER_MASK); - Dataspace outputStandard = - static_cast(mOutputDataSpace & Dataspace::STANDARD_MASK); - Dataspace outputTransfer = - static_cast(mOutputDataSpace & Dataspace::TRANSFER_MASK); - bool needsXYZConversion = needsXYZTransformMatrix(); - - // NOTE: if the input standard of the input dataspace is not STANDARD_DCI_P3 or - // STANDARD_BT2020, it will be treated as STANDARD_BT709 - if (inputStandard != Dataspace::STANDARD_DCI_P3 && - inputStandard != Dataspace::STANDARD_BT2020) { - inputStandard = Dataspace::STANDARD_BT709; + Dataspace inputStandard = static_cast(mDataSpace & Dataspace::STANDARD_MASK); + Dataspace inputTransfer = static_cast(mDataSpace & Dataspace::TRANSFER_MASK); + Dataspace outputStandard = static_cast(mOutputDataSpace & Dataspace::STANDARD_MASK); + Dataspace outputTransfer = static_cast(mOutputDataSpace & Dataspace::TRANSFER_MASK); + bool needsXYZConversion = needsXYZTransformMatrix(); + + // NOTE: if the input standard of the input dataspace is not STANDARD_DCI_P3 or + // STANDARD_BT2020, it will be treated as STANDARD_BT709 + if (inputStandard != Dataspace::STANDARD_DCI_P3 && + inputStandard != Dataspace::STANDARD_BT2020) { + inputStandard = Dataspace::STANDARD_BT709; + } + + if (needsXYZConversion) { + // The supported input color spaces are standard RGB, Display P3 and BT2020. + switch (inputStandard) { + case Dataspace::STANDARD_DCI_P3: + managedState.inputTransformMatrix = mDisplayP3ToXyz; + break; + case Dataspace::STANDARD_BT2020: + managedState.inputTransformMatrix = mBt2020ToXyz; + break; + default: + managedState.inputTransformMatrix = mSrgbToXyz; + break; } - if (needsXYZConversion) { - // The supported input color spaces are standard RGB, Display P3 and BT2020. - switch (inputStandard) { - case Dataspace::STANDARD_DCI_P3: - managedState.inputTransformMatrix = mDisplayP3ToXyz; - break; - case Dataspace::STANDARD_BT2020: - managedState.inputTransformMatrix = mBt2020ToXyz; - break; - default: - managedState.inputTransformMatrix = mSrgbToXyz; - break; - } - - // The supported output color spaces are BT2020, Display P3 and standard RGB. - switch (outputStandard) { - case Dataspace::STANDARD_BT2020: - managedState.outputTransformMatrix = mXyzToBt2020; - break; - case Dataspace::STANDARD_DCI_P3: - managedState.outputTransformMatrix = mXyzToDisplayP3; - break; - default: - managedState.outputTransformMatrix = mXyzToSrgb; - break; - } - } else if (inputStandard != outputStandard) { - // At this point, the input data space and output data space could be both - // HDR data spaces, but they match each other, we do nothing in this case. - // In addition to the case above, the input data space could be - // - scRGB linear - // - scRGB non-linear - // - sRGB - // - Display P3 - // - BT2020 - // The output data spaces could be - // - sRGB - // - Display P3 - // - BT2020 - switch (outputStandard) { - case Dataspace::STANDARD_BT2020: - if (inputStandard == Dataspace::STANDARD_BT709) { - managedState.outputTransformMatrix = mSrgbToBt2020; - } else if (inputStandard == Dataspace::STANDARD_DCI_P3) { - managedState.outputTransformMatrix = mDisplayP3ToBt2020; - } - break; - case Dataspace::STANDARD_DCI_P3: - if (inputStandard == Dataspace::STANDARD_BT709) { - managedState.outputTransformMatrix = mSrgbToDisplayP3; - } else if (inputStandard == Dataspace::STANDARD_BT2020) { - managedState.outputTransformMatrix = mBt2020ToDisplayP3; - } - break; - default: - if (inputStandard == Dataspace::STANDARD_DCI_P3) { - managedState.outputTransformMatrix = mDisplayP3ToSrgb; - } else if (inputStandard == Dataspace::STANDARD_BT2020) { - managedState.outputTransformMatrix = mBt2020ToSrgb; - } - break; - } + // The supported output color spaces are BT2020, Display P3 and standard RGB. + switch (outputStandard) { + case Dataspace::STANDARD_BT2020: + managedState.outputTransformMatrix = mXyzToBt2020; + break; + case Dataspace::STANDARD_DCI_P3: + managedState.outputTransformMatrix = mXyzToDisplayP3; + break; + default: + managedState.outputTransformMatrix = mXyzToSrgb; + break; } - - // we need to convert the RGB value to linear space and convert it back when: - // - there is a color matrix that is not an identity matrix, or - // - there is an output transform matrix that is not an identity matrix, or - // - the input transfer function doesn't match the output transfer function. - if (managedState.hasColorMatrix() || managedState.hasOutputTransformMatrix() || - inputTransfer != outputTransfer) { - managedState.inputTransferFunction = - Description::dataSpaceToTransferFunction(inputTransfer); - managedState.outputTransferFunction = - Description::dataSpaceToTransferFunction(outputTransfer); + } else if (inputStandard != outputStandard) { + // At this point, the input data space and output data space could be both + // HDR data spaces, but they match each other, we do nothing in this case. + // In addition to the case above, the input data space could be + // - scRGB linear + // - scRGB non-linear + // - sRGB + // - Display P3 + // - BT2020 + // The output data spaces could be + // - sRGB + // - Display P3 + // - BT2020 + switch (outputStandard) { + case Dataspace::STANDARD_BT2020: + if (inputStandard == Dataspace::STANDARD_BT709) { + managedState.outputTransformMatrix = mSrgbToBt2020; + } else if (inputStandard == Dataspace::STANDARD_DCI_P3) { + managedState.outputTransformMatrix = mDisplayP3ToBt2020; + } + break; + case Dataspace::STANDARD_DCI_P3: + if (inputStandard == Dataspace::STANDARD_BT709) { + managedState.outputTransformMatrix = mSrgbToDisplayP3; + } else if (inputStandard == Dataspace::STANDARD_BT2020) { + managedState.outputTransformMatrix = mBt2020ToDisplayP3; + } + break; + default: + if (inputStandard == Dataspace::STANDARD_DCI_P3) { + managedState.outputTransformMatrix = mDisplayP3ToSrgb; + } else if (inputStandard == Dataspace::STANDARD_BT2020) { + managedState.outputTransformMatrix = mBt2020ToSrgb; + } + break; } } + // we need to convert the RGB value to linear space and convert it back when: + // - there is a color matrix that is not an identity matrix, or + // - there is an output transform matrix that is not an identity matrix, or + // - the input transfer function doesn't match the output transfer function. + if (managedState.hasColorMatrix() || managedState.hasOutputTransformMatrix() || + inputTransfer != outputTransfer) { + managedState.inputTransferFunction = + Description::dataSpaceToTransferFunction(inputTransfer); + managedState.outputTransferFunction = + Description::dataSpaceToTransferFunction(outputTransfer); + } + ProgramCache::getInstance().useProgram(mInProtectedContext ? mProtectedEGLContext : mEGLContext, managedState); @@ -1547,7 +1540,7 @@ void GLESRenderEngine::drawMesh(const Mesh& mesh) { glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount()); } - if (mUseColorManagement && outputDebugPPMs) { + if (outputDebugPPMs) { static uint64_t managedColorFrameCount = 0; std::ostringstream out; out << "/data/texture_out" << managedColorFrameCount++; diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index ea75e215cd..f5368d4e9f 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -236,10 +236,6 @@ private: // Current output dataspace of the render engine ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN; - // Whether device supports color management, currently color management - // supports sRGB, DisplayP3 color spaces. - const bool mUseColorManagement = false; - // Whether only shaders performing tone mapping from HDR to SDR will be generated on // primeCache(). const bool mPrecacheToneMapperShaderOnly = false; diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp index 812dda04fa..96ccf5c512 100644 --- a/libs/renderengine/gl/ProgramCache.cpp +++ b/libs/renderengine/gl/ProgramCache.cpp @@ -77,8 +77,7 @@ Formatter& dedent(Formatter& f) { return f; } -void ProgramCache::primeCache( - EGLContext context, bool useColorManagement, bool toneMapperShaderOnly) { +void ProgramCache::primeCache(EGLContext context, bool toneMapperShaderOnly) { auto& cache = mCaches[context]; uint32_t shaderCount = 0; @@ -126,27 +125,24 @@ void ProgramCache::primeCache( } // Prime for sRGB->P3 conversion - if (useColorManagement) { - Key shaderKey; - shaderKey.set(Key::BLEND_MASK | Key::OUTPUT_TRANSFORM_MATRIX_MASK | Key::INPUT_TF_MASK | - Key::OUTPUT_TF_MASK, - Key::BLEND_PREMULT | Key::OUTPUT_TRANSFORM_MATRIX_ON | Key::INPUT_TF_SRGB | - Key::OUTPUT_TF_SRGB); - for (int i = 0; i < 16; i++) { - shaderKey.set(Key::OPACITY_MASK, - (i & 1) ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT); - shaderKey.set(Key::ALPHA_MASK, (i & 2) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE); - - // Cache rounded corners - shaderKey.set(Key::ROUNDED_CORNERS_MASK, - (i & 4) ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF); - - // Cache texture off option for window transition - shaderKey.set(Key::TEXTURE_MASK, (i & 8) ? Key::TEXTURE_EXT : Key::TEXTURE_OFF); - if (cache.count(shaderKey) == 0) { - cache.emplace(shaderKey, generateProgram(shaderKey)); - shaderCount++; - } + Key shaderKey; + shaderKey.set(Key::BLEND_MASK | Key::OUTPUT_TRANSFORM_MATRIX_MASK | Key::INPUT_TF_MASK | + Key::OUTPUT_TF_MASK, + Key::BLEND_PREMULT | Key::OUTPUT_TRANSFORM_MATRIX_ON | Key::INPUT_TF_SRGB | + Key::OUTPUT_TF_SRGB); + for (int i = 0; i < 16; i++) { + shaderKey.set(Key::OPACITY_MASK, (i & 1) ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT); + shaderKey.set(Key::ALPHA_MASK, (i & 2) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE); + + // Cache rounded corners + shaderKey.set(Key::ROUNDED_CORNERS_MASK, + (i & 4) ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF); + + // Cache texture off option for window transition + shaderKey.set(Key::TEXTURE_MASK, (i & 8) ? Key::TEXTURE_EXT : Key::TEXTURE_OFF); + if (cache.count(shaderKey) == 0) { + cache.emplace(shaderKey, generateProgram(shaderKey)); + shaderCount++; } } diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h index b18914fd5e..83fef8e1db 100644 --- a/libs/renderengine/gl/ProgramCache.h +++ b/libs/renderengine/gl/ProgramCache.h @@ -189,7 +189,7 @@ public: ~ProgramCache() = default; // Generate shaders to populate the cache - void primeCache(const EGLContext context, bool useColorManagement, bool toneMapperShaderOnly); + void primeCache(const EGLContext context, bool toneMapperShaderOnly); size_t getSize(const EGLContext context) { return mCaches[context].size(); } diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 0d910c9b29..83af252740 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -271,14 +271,13 @@ struct RenderEngineCreationArgs { private: // must be created by Builder via constructor with full argument list - RenderEngineCreationArgs(int _pixelFormat, uint32_t _imageCacheSize, bool _useColorManagement, + RenderEngineCreationArgs(int _pixelFormat, uint32_t _imageCacheSize, bool _enableProtectedContext, bool _precacheToneMapperShaderOnly, bool _supportsBackgroundBlur, RenderEngine::ContextPriority _contextPriority, RenderEngine::RenderEngineType _renderEngineType) : pixelFormat(_pixelFormat), imageCacheSize(_imageCacheSize), - useColorManagement(_useColorManagement), enableProtectedContext(_enableProtectedContext), precacheToneMapperShaderOnly(_precacheToneMapperShaderOnly), supportsBackgroundBlur(_supportsBackgroundBlur), @@ -298,10 +297,6 @@ struct RenderEngineCreationArgs::Builder { this->imageCacheSize = imageCacheSize; return *this; } - Builder& setUseColorManagerment(bool useColorManagement) { - this->useColorManagement = useColorManagement; - return *this; - } Builder& setEnableProtectedContext(bool enableProtectedContext) { this->enableProtectedContext = enableProtectedContext; return *this; @@ -323,16 +318,15 @@ struct RenderEngineCreationArgs::Builder { return *this; } RenderEngineCreationArgs build() const { - return RenderEngineCreationArgs(pixelFormat, imageCacheSize, useColorManagement, - enableProtectedContext, precacheToneMapperShaderOnly, - supportsBackgroundBlur, contextPriority, renderEngineType); + return RenderEngineCreationArgs(pixelFormat, imageCacheSize, enableProtectedContext, + precacheToneMapperShaderOnly, supportsBackgroundBlur, + contextPriority, renderEngineType); } private: // 1 means RGBA_8888 int pixelFormat = 1; uint32_t imageCacheSize = 0; - bool useColorManagement = true; bool enableProtectedContext = false; bool precacheToneMapperShaderOnly = false; bool supportsBackgroundBlur = false; diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index ff598e7ab5..92181d87c8 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -251,14 +251,13 @@ EGLConfig SkiaGLRenderEngine::chooseEglConfig(EGLDisplay display, int format, bo SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLContext ctxt, EGLSurface placeholder, EGLContext protectedContext, EGLSurface protectedPlaceholder) - : SkiaRenderEngine(args.renderEngineType, - static_cast(args.pixelFormat), - args.useColorManagement, args.supportsBackgroundBlur), + : SkiaRenderEngine(args.renderEngineType, static_cast(args.pixelFormat), + args.supportsBackgroundBlur), mEGLDisplay(display), mEGLContext(ctxt), mPlaceholderSurface(placeholder), mProtectedEGLContext(protectedContext), - mProtectedPlaceholderSurface(protectedPlaceholder) { } + mProtectedPlaceholderSurface(protectedPlaceholder) {} SkiaGLRenderEngine::~SkiaGLRenderEngine() { finishRenderingAndAbandonContext(); diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index 1f4c98963a..2225d5f818 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -269,10 +269,8 @@ void SkiaRenderEngine::setEnableTracing(bool tracingEnabled) { } SkiaRenderEngine::SkiaRenderEngine(RenderEngineType type, PixelFormat pixelFormat, - bool useColorManagement, bool supportsBackgroundBlur) - : RenderEngine(type), - mDefaultPixelFormat(pixelFormat), - mUseColorManagement(useColorManagement) { + bool supportsBackgroundBlur) + : RenderEngine(type), mDefaultPixelFormat(pixelFormat) { if (supportsBackgroundBlur) { ALOGD("Background Blurs Enabled"); mBlurFilter = new KawaseBlurFilter(); @@ -926,8 +924,7 @@ void SkiaRenderEngine::drawLayersInternal( // luminance in linear space, which color pipelines request GAMMA_OETF break // without a gamma 2.2 fixup. const bool requiresLinearEffect = layer.colorTransform != mat4() || - (mUseColorManagement && - needsToneMapping(layer.sourceDataspace, display.outputDataspace)) || + (needsToneMapping(layer.sourceDataspace, display.outputDataspace)) || (dimInLinearSpace && !equalsWithinMargin(1.f, layerDimmingRatio)) || (!dimInLinearSpace && isExtendedHdr); @@ -938,10 +935,7 @@ void SkiaRenderEngine::drawLayersInternal( continue; } - // If color management is disabled, then mark the source image with the same colorspace as - // the destination surface so that Skia's color management is a no-op. - const ui::Dataspace layerDataspace = - !mUseColorManagement ? display.outputDataspace : layer.sourceDataspace; + const ui::Dataspace layerDataspace = layer.sourceDataspace; SkPaint paint; if (layer.source.buffer.buffer) { diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 723e73c29e..7b4a0a0af2 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -59,10 +59,7 @@ class BlurFilter; class SkiaRenderEngine : public RenderEngine { public: static std::unique_ptr create(const RenderEngineCreationArgs& args); - SkiaRenderEngine(RenderEngineType type, - PixelFormat pixelFormat, - bool useColorManagement, - bool supportsBackgroundBlur); + SkiaRenderEngine(RenderEngineType type, PixelFormat pixelFormat, bool supportsBackgroundBlur); ~SkiaRenderEngine() override; std::future primeCache() override final; @@ -162,7 +159,6 @@ private: sk_sp createRuntimeEffectShader(const RuntimeEffectShaderParameters&); const PixelFormat mDefaultPixelFormat; - const bool mUseColorManagement; // Identifier used for various mappings of layers to various // textures or shaders diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp index c16586bb6b..6ecc6ab362 100644 --- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp @@ -592,7 +592,7 @@ std::unique_ptr SkiaVkRenderEngine::create( SkiaVkRenderEngine::SkiaVkRenderEngine(const RenderEngineCreationArgs& args) : SkiaRenderEngine(args.renderEngineType, static_cast(args.pixelFormat), - args.useColorManagement, args.supportsBackgroundBlur) {} + args.supportsBackgroundBlur) {} SkiaVkRenderEngine::~SkiaVkRenderEngine() { finishRenderingAndAbandonContext(); diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index f3f2da8a0e..1ad0fa6e70 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -109,7 +109,6 @@ public: virtual renderengine::RenderEngine::RenderEngineType type() = 0; virtual std::unique_ptr createRenderEngine() = 0; virtual bool typeSupported() = 0; - virtual bool useColorManagement() const = 0; }; class SkiaVkRenderEngineFactory : public RenderEngineFactory { @@ -130,13 +129,11 @@ public: renderengine::RenderEngineCreationArgs::Builder() .setPixelFormat(static_cast(ui::PixelFormat::RGBA_8888)) .setImageCacheSize(1) - .setUseColorManagerment(false) .setEnableProtectedContext(false) .setPrecacheToneMapperShaderOnly(false) .setSupportsBackgroundBlur(true) .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM) .setRenderEngineType(type()) - .setUseColorManagerment(useColorManagement()) .build(); return renderengine::skia::SkiaVkRenderEngine::create(reCreationArgs); } @@ -144,14 +141,9 @@ public: bool typeSupported() override { return skia::SkiaVkRenderEngine::canSupportSkiaVkRenderEngine(); } - bool useColorManagement() const override { return false; } void skip() { GTEST_SKIP(); } }; -class SkiaVkCMRenderEngineFactory : public SkiaVkRenderEngineFactory { -public: - bool useColorManagement() const override { return true; } -}; class SkiaGLESRenderEngineFactory : public RenderEngineFactory { public: std::string name() override { return "SkiaGLRenderEngineFactory"; } @@ -170,13 +162,11 @@ public: .setSupportsBackgroundBlur(true) .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM) .setRenderEngineType(type()) - .setUseColorManagerment(useColorManagement()) .build(); return renderengine::skia::SkiaGLRenderEngine::create(reCreationArgs); } bool typeSupported() override { return true; } - bool useColorManagement() const override { return false; } }; class SkiaGLESCMRenderEngineFactory : public RenderEngineFactory { @@ -197,13 +187,11 @@ public: .setSupportsBackgroundBlur(true) .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM) .setRenderEngineType(type()) - .setUseColorManagerment(useColorManagement()) .build(); return renderengine::skia::SkiaGLRenderEngine::create(reCreationArgs); } bool typeSupported() override { return true; } - bool useColorManagement() const override { return true; } }; class RenderEngineTest : public ::testing::TestWithParam> { @@ -1559,9 +1547,7 @@ void RenderEngineTest::tonemap(ui::Dataspace sourceDataspace, std::function(), - std::make_shared(), - std::make_shared(), - std::make_shared())); + std::make_shared())); TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) { if (!GetParam()->typeSupported()) { @@ -1745,7 +1731,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) { TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_sourceDataspace) { const auto& renderEngineFactory = GetParam(); // skip for non color management - if (!renderEngineFactory->typeSupported() || !renderEngineFactory->useColorManagement()) { + if (!renderEngineFactory->typeSupported()) { GTEST_SKIP(); } @@ -1756,7 +1742,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_sourceDataspace) { TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_outputDataspace) { const auto& renderEngineFactory = GetParam(); // skip for non color management - if (!renderEngineFactory->typeSupported() || !renderEngineFactory->useColorManagement()) { + if (!renderEngineFactory->typeSupported()) { GTEST_SKIP(); } @@ -1895,7 +1881,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_opaqueBufferSource) { const auto& renderEngineFactory = GetParam(); // skip for non color management - if (!renderEngineFactory->typeSupported() || !renderEngineFactory->useColorManagement()) { + if (!renderEngineFactory->typeSupported()) { GTEST_SKIP(); } @@ -1906,7 +1892,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_o TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_opaqueBufferSource) { const auto& renderEngineFactory = GetParam(); // skip for non color management - if (!renderEngineFactory->typeSupported() || !renderEngineFactory->useColorManagement()) { + if (!renderEngineFactory->typeSupported()) { GTEST_SKIP(); } @@ -2045,7 +2031,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) { TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_bufferSource) { const auto& renderEngineFactory = GetParam(); // skip for non color management - if (!renderEngineFactory->typeSupported() || !renderEngineFactory->useColorManagement()) { + if (!renderEngineFactory->typeSupported()) { GTEST_SKIP(); } @@ -2056,7 +2042,7 @@ TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndSourceDataspace_b TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformAndOutputDataspace_bufferSource) { const auto& renderEngineFactory = GetParam(); // skip for non color management - if (!renderEngineFactory->typeSupported() || !renderEngineFactory->useColorManagement()) { + if (!renderEngineFactory->typeSupported()) { GTEST_SKIP(); } @@ -2592,10 +2578,6 @@ TEST_P(RenderEngineTest, testBorder) { GTEST_SKIP(); } - if (!GetParam()->useColorManagement()) { - GTEST_SKIP(); - } - initializeRenderEngine(); const ui::Dataspace dataspace = ui::Dataspace::V0_SRGB; @@ -3017,15 +2999,11 @@ TEST_P(RenderEngineTest, test_isOpaque) { std::vector layers{greenLayer}; invokeDraw(display, layers); - if (GetParam()->useColorManagement()) { - expectBufferColor(rect, 117, 251, 76, 255); - } else { - expectBufferColor(rect, 0, 255, 0, 255); - } + expectBufferColor(rect, 117, 251, 76, 255); } TEST_P(RenderEngineTest, test_tonemapPQMatches) { - if (!GetParam()->typeSupported() || !GetParam()->useColorManagement()) { + if (!GetParam()->typeSupported()) { GTEST_SKIP(); } @@ -3042,7 +3020,7 @@ TEST_P(RenderEngineTest, test_tonemapPQMatches) { } TEST_P(RenderEngineTest, test_tonemapHLGMatches) { - if (!GetParam()->typeSupported() || !GetParam()->useColorManagement()) { + if (!GetParam()->typeSupported()) { GTEST_SKIP(); } @@ -3262,9 +3240,9 @@ TEST_P(RenderEngineTest, primeShaderCache) { fut.wait(); } - const int minimumExpectedShadersCompiled = GetParam()->useColorManagement() ? 60 : 30; + static constexpr int kMinimumExpectedShadersCompiled = 60; ASSERT_GT(static_cast(mRE.get())->reportShadersCompiled(), - minimumExpectedShadersCompiled); + kMinimumExpectedShadersCompiled); } } // namespace renderengine } // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7b37407ac6..f6f6ca6875 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -644,14 +644,6 @@ sp SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) return getPhysicalDisplayTokenLocked(displayId); } -status_t SurfaceFlinger::getColorManagement(bool* outGetColorManagement) const { - if (!outGetColorManagement) { - return BAD_VALUE; - } - *outGetColorManagement = useColorManagement; - return NO_ERROR; -} - HWComposer& SurfaceFlinger::getHwComposer() const { return mCompositionEngine->getHwComposer(); } @@ -812,7 +804,6 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { auto builder = renderengine::RenderEngineCreationArgs::Builder() .setPixelFormat(static_cast(defaultCompositionPixelFormat)) .setImageCacheSize(maxFrameBufferAcquiredBuffers) - .setUseColorManagerment(useColorManagement) .setEnableProtectedContext(enable_protected_contents(false)) .setPrecacheToneMapperShaderOnly(false) .setSupportsBackgroundBlur(mSupportsBlur) @@ -2618,9 +2609,7 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( refreshArgs.layersWithQueuedFrames.push_back(layerFE); } - refreshArgs.outputColorSetting = useColorManagement - ? mDisplayColorSetting - : compositionengine::OutputColorSetting::kUnmanaged; + refreshArgs.outputColorSetting = mDisplayColorSetting; refreshArgs.forceOutputColorMode = mForceColorMode; refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty; @@ -3391,18 +3380,16 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( creationArgs.isPrimary = physical->id == getPrimaryDisplayIdLocked(); - if (useColorManagement) { - mPhysicalDisplays.get(physical->id) - .transform(&PhysicalDisplay::snapshotRef) - .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) { - for (const auto mode : snapshot.colorModes()) { - creationArgs.hasWideColorGamut |= ui::isWideColorMode(mode); - creationArgs.hwcColorModes - .emplace(mode, - getHwComposer().getRenderIntents(physical->id, mode)); - } - })); - } + mPhysicalDisplays.get(physical->id) + .transform(&PhysicalDisplay::snapshotRef) + .transform(ftl::unit_fn([&](const display::DisplaySnapshot& snapshot) { + for (const auto mode : snapshot.colorModes()) { + creationArgs.hasWideColorGamut |= ui::isWideColorMode(mode); + creationArgs.hwcColorModes + .emplace(mode, + getHwComposer().getRenderIntents(physical->id, mode)); + } + })); } if (const auto id = HalDisplayId::tryCast(compositionDisplay->getId())) { @@ -6087,7 +6074,6 @@ void SurfaceFlinger::dumpRawDisplayIdentificationData(const DumpArgs& args, void SurfaceFlinger::dumpWideColorInfo(std::string& result) const { StringAppendF(&result, "Device supports wide color: %d\n", mSupportsWideColor); - StringAppendF(&result, "Device uses color management: %d\n", useColorManagement); StringAppendF(&result, "DisplayColorSetting: %s\n", decodeDisplayColorSetting(mDisplayColorSetting).c_str()); @@ -6762,8 +6748,6 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r DisplayColorSetting setting = static_cast(data.readInt32()); switch (setting) { case DisplayColorSetting::kManaged: - reply->writeBool(useColorManagement); - break; case DisplayColorSetting::kUnmanaged: reply->writeBool(true); break; @@ -6796,7 +6780,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } // Is device color managed? case 1030: { - reply->writeBool(useColorManagement); + // ColorDisplayManager stil calls this + reply->writeBool(true); return NO_ERROR; } // Override default composition data space @@ -9171,11 +9156,6 @@ binder::Status SurfaceComposerAIDL::getLayerDebugInfo(std::vectorgetColorManagement(outGetColorManagement); - return binderStatusFromStatusT(status); -} - binder::Status SurfaceComposerAIDL::getCompositionPreference(gui::CompositionPreference* outPref) { ui::Dataspace dataspace; ui::PixelFormat pixelFormat; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index d9c1101de8..869202f3d3 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -236,9 +236,6 @@ public: static uint32_t maxGraphicsWidth; static uint32_t maxGraphicsHeight; - // Indicate if device wants color management on its display. - static const constexpr bool useColorManagement = true; - static bool useContextPriority; // The data space and pixel format that SurfaceFlinger expects hardware composer @@ -567,7 +564,6 @@ private: const std::vector& hdrTypes); status_t onPullAtom(const int32_t atomId, std::vector* pulledData, bool* success); status_t getLayerDebugInfo(std::vector* outLayers); - status_t getColorManagement(bool* outGetColorManagement) const; status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat, ui::Dataspace* outWideColorGamutDataspace, ui::PixelFormat* outWideColorGamutPixelFormat) const; @@ -1508,7 +1504,6 @@ public: const std::vector& hdrTypes) override; binder::Status onPullAtom(int32_t atomId, gui::PullAtomData* outPullData) override; binder::Status getLayerDebugInfo(std::vector* outLayers) override; - binder::Status getColorManagement(bool* outGetColorManagement) override; binder::Status getCompositionPreference(gui::CompositionPreference* outPref) override; binder::Status getDisplayedContentSamplingAttributes( const sp& display, gui::ContentSamplingAttributes* outAttrs) override; diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp index b8068f79a4..2b1834d8e4 100644 --- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp @@ -1479,15 +1479,11 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) { matrix[2][2] = 0.11; // degamma before applying the matrix - if (mColorManagementUsed) { - ColorTransformHelper::DegammaColor(expected); - } + ColorTransformHelper::DegammaColor(expected); ColorTransformHelper::applyMatrix(expected, matrix); - if (mColorManagementUsed) { - ColorTransformHelper::GammaColor(expected); - } + ColorTransformHelper::GammaColor(expected); const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255), uint8_t(expected.b * 255), 255}; @@ -1537,15 +1533,11 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnParent) { matrix[2][2] = 0.11; // degamma before applying the matrix - if (mColorManagementUsed) { - ColorTransformHelper::DegammaColor(expected); - } + ColorTransformHelper::DegammaColor(expected); ColorTransformHelper::applyMatrix(expected, matrix); - if (mColorManagementUsed) { - ColorTransformHelper::GammaColor(expected); - } + ColorTransformHelper::GammaColor(expected); const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255), uint8_t(expected.b * 255), 255}; @@ -1608,16 +1600,12 @@ TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnChildAndParent) { matrixParent[2][2] = 0.10; // degamma before applying the matrix - if (mColorManagementUsed) { - ColorTransformHelper::DegammaColor(expected); - } + ColorTransformHelper::DegammaColor(expected); ColorTransformHelper::applyMatrix(expected, matrixChild); ColorTransformHelper::applyMatrix(expected, matrixParent); - if (mColorManagementUsed) { - ColorTransformHelper::GammaColor(expected); - } + ColorTransformHelper::GammaColor(expected); const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255), uint8_t(expected.b * 255), 255}; diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index badd5bebbc..2bdb8a452d 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -47,9 +47,6 @@ protected: ASSERT_NO_FATAL_FAILURE(SetUpDisplay()); sp sf(ComposerServiceAIDL::getComposerService()); - binder::Status status = sf->getColorManagement(&mColorManagementUsed); - ASSERT_NO_FATAL_FAILURE(gui::aidl_utils::statusTFromBinderStatus(status)); - mCaptureArgs.displayToken = mDisplay; } @@ -282,7 +279,6 @@ protected: const int32_t mLayerZBase = std::numeric_limits::max() - 256; sp mBlackBgSurface; - bool mColorManagementUsed; DisplayCaptureArgs mCaptureArgs; ScreenCaptureResults mCaptureResults; -- GitLab From 2c3d7fbcbb3d296b42a9646fd563a0993eb0cfd6 Mon Sep 17 00:00:00 2001 From: Ram Mohan Date: Sat, 12 Aug 2023 04:37:39 +0530 Subject: [PATCH 0468/1187] ultrahdr: revert gain map image dimension calculation Gain map resolution is 1 / kMapDimensionScaleFactor of primary image. Before computing the gain map image res, the primary image res is aligned to kMapDimensionScaleFactor and divided. This would require p010 and 420 to have additional bytes at each row end during access or clamp the reads to width. Currently neither is present. Until this is handled, adjust gain map res computations to avoid oob reads. Bug: 294709120 Bug: 294320724 Test: ./ultrahdr_enc_fuzzer Change-Id: I65daa5ac49255a8976cf929a5bd0ffe3e47afb6d --- libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp | 6 ++---- libs/ultrahdr/jpegr.cpp | 12 ++++-------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp index c536c391b5..2d59e8bb88 100644 --- a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp +++ b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp @@ -161,10 +161,8 @@ void UltraHdrEncFuzzer::process() { fillP010Buffer(bufferUVHdr.get(), width, height / 2, uvStride); } } else { - size_t map_width = static_cast( - floor((width + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); - size_t map_height = static_cast( - floor((height + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); + size_t map_width = width / kMapDimensionScaleFactor; + size_t map_height = height / kMapDimensionScaleFactor; // init 400 image grayImg.width = map_width; grayImg.height = map_height; diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp index dc439d785a..ae8184547a 100644 --- a/libs/ultrahdr/jpegr.cpp +++ b/libs/ultrahdr/jpegr.cpp @@ -801,10 +801,8 @@ status_t JpegR::generateGainMap(jr_uncompressed_ptr yuv420_image_ptr, size_t image_width = yuv420_image_ptr->width; size_t image_height = yuv420_image_ptr->height; - size_t map_width = static_cast( - floor((image_width + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); - size_t map_height = static_cast( - floor((image_height + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); + size_t map_width = image_width / kMapDimensionScaleFactor; + size_t map_height = image_height / kMapDimensionScaleFactor; dest->data = new uint8_t[map_width * map_height]; dest->width = map_width; @@ -984,10 +982,8 @@ status_t JpegR::applyGainMap(jr_uncompressed_ptr yuv420_image_ptr, // TODO: remove once map scaling factor is computed based on actual map dims size_t image_width = yuv420_image_ptr->width; size_t image_height = yuv420_image_ptr->height; - size_t map_width = static_cast( - floor((image_width + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); - size_t map_height = static_cast( - floor((image_height + kMapDimensionScaleFactor - 1) / kMapDimensionScaleFactor)); + size_t map_width = image_width / kMapDimensionScaleFactor; + size_t map_height = image_height / kMapDimensionScaleFactor; if (map_width != gainmap_image_ptr->width || map_height != gainmap_image_ptr->height) { ALOGE("gain map dimensions and primary image dimensions are not to scale, computed gain map " "resolution is %dx%d, received gain map resolution is %dx%d", -- GitLab From 83cc5ed010620ab8e9f0d53eb132a2b28650cc49 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Wed, 16 Aug 2023 10:08:14 +0900 Subject: [PATCH 0469/1187] libbinder_rs doesn't need libutils This has caused unused .so files in APEXes. Bug: 295593640 Test: m Change-Id: I5c3ea12a8de20e811f6628c3004393f75cb75bd6 --- libs/binder/rust/Android.bp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp index 672d6cf5d0..57a38dc480 100644 --- a/libs/binder/rust/Android.bp +++ b/libs/binder/rust/Android.bp @@ -11,9 +11,6 @@ rust_library { name: "libbinder_rs", crate_name: "binder", srcs: ["src/lib.rs"], - shared_libs: [ - "libutils", - ], rustlibs: [ "libbinder_ndk_sys", "libdowncast_rs", -- GitLab From f6918d4ab8c613302c3eda0b7be15674aceb8610 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Mon, 7 Aug 2023 15:28:30 -0700 Subject: [PATCH 0470/1187] Refactor `isHdrDataspace` function. - Rename it to `getHdrRenderType` and return a ternary enum. - return the hdr type that we want to treat based on the dataspace, format and hdr/sdr ratio. - pixelformat is optional, in case no source buffer but there is a source color. - hdr/sdr ratio is 1.0f by default, render rengine doesn't take care this param. - The ternary enum has 3 types: just SDR; generic hdr, namely those we need to tonemap; display hdr, namely those self-promoting to HDR by using extended brightness API. Bug: 261485283 Test: HdrRenderTypeUtils_test, TextureViewTest#testSDRFromSurfaceViewAndTextureView, OutputLayerUpdateCompositionStateTest Change-Id: I281687a010bbf5bff555f6fa893002c2a9b324d1 --- libs/renderengine/skia/SkiaRenderEngine.cpp | 9 ++- libs/ui/include_types/ui/DataspaceUtils.h | 29 --------- libs/ui/include_types/ui/HdrRenderTypeUtils.h | 64 ++++++++++++++++++ libs/ui/tests/Android.bp | 4 +- libs/ui/tests/DataspaceUtils_test.cpp | 53 --------------- libs/ui/tests/HdrRenderTypeUtils_test.cpp | 65 +++++++++++++++++++ .../CompositionEngine/src/OutputLayer.cpp | 21 ++++-- services/surfaceflinger/Layer.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 17 ++--- 9 files changed, 162 insertions(+), 102 deletions(-) delete mode 100644 libs/ui/include_types/ui/DataspaceUtils.h create mode 100644 libs/ui/include_types/ui/HdrRenderTypeUtils.h delete mode 100644 libs/ui/tests/DataspaceUtils_test.cpp create mode 100644 libs/ui/tests/HdrRenderTypeUtils_test.cpp diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index 29d8ba7267..8ea9ee7478 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -20,7 +20,6 @@ #include "SkiaRenderEngine.h" -#include #include #include #include @@ -55,13 +54,14 @@ #include #include #include +#include #include #include #include #include -#include #include #include +#include #include #include @@ -1027,7 +1027,10 @@ void SkiaRenderEngine::drawLayersInternal( // Most HDR standards require at least 10-bits of color depth for source content, so we // can just extract the transfer function rather than dig into precise gralloc layout. // Furthermore, we can assume that the only 8-bit target we support is RGBA8888. - const bool requiresDownsample = isHdrDataspace(layer.sourceDataspace) && + const bool requiresDownsample = + getHdrRenderType(layer.sourceDataspace, + std::optional(static_cast( + buffer->getPixelFormat()))) != HdrRenderType::SDR && buffer->getPixelFormat() == PIXEL_FORMAT_RGBA_8888; if (layerDimmingRatio <= kDimmingThreshold || requiresDownsample) { paint.setDither(true); diff --git a/libs/ui/include_types/ui/DataspaceUtils.h b/libs/ui/include_types/ui/DataspaceUtils.h deleted file mode 100644 index a461cb4e68..0000000000 --- a/libs/ui/include_types/ui/DataspaceUtils.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2021 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 - -namespace android { - -inline bool isHdrDataspace(ui::Dataspace dataspace) { - const auto transfer = dataspace & HAL_DATASPACE_TRANSFER_MASK; - - return transfer == HAL_DATASPACE_TRANSFER_ST2084 || transfer == HAL_DATASPACE_TRANSFER_HLG; -} - -} // namespace android \ No newline at end of file diff --git a/libs/ui/include_types/ui/HdrRenderTypeUtils.h b/libs/ui/include_types/ui/HdrRenderTypeUtils.h new file mode 100644 index 0000000000..b0af878cdb --- /dev/null +++ b/libs/ui/include_types/ui/HdrRenderTypeUtils.h @@ -0,0 +1,64 @@ +/* + * Copyright 2021 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 + +namespace android { + +enum class HdrRenderType { + SDR, // just render to SDR + DISPLAY_HDR, // HDR by extended brightness + GENERIC_HDR // tonemapped HDR +}; + +/*** + * A helper function to classify how we treat the result based on params. + * + * @param dataspace the dataspace + * @param pixelFormat optional, in case there is no source buffer. + * @param hdrSdrRatio default is 1.f, render engine side doesn't take care of it. + * @return HdrRenderType + */ +inline HdrRenderType getHdrRenderType(ui::Dataspace dataspace, + std::optional pixelFormat, + float hdrSdrRatio = 1.f) { + const auto transfer = dataspace & HAL_DATASPACE_TRANSFER_MASK; + const auto range = dataspace & HAL_DATASPACE_RANGE_MASK; + + if (transfer == HAL_DATASPACE_TRANSFER_ST2084 || transfer == HAL_DATASPACE_TRANSFER_HLG) { + return HdrRenderType::GENERIC_HDR; + } + + static const auto BT2020_LINEAR_EXT = static_cast(HAL_DATASPACE_STANDARD_BT2020 | + HAL_DATASPACE_TRANSFER_LINEAR | + HAL_DATASPACE_RANGE_EXTENDED); + + if ((dataspace == BT2020_LINEAR_EXT || dataspace == ui::Dataspace::V0_SCRGB) && + pixelFormat.has_value() && pixelFormat.value() == ui::PixelFormat::RGBA_FP16) { + return HdrRenderType::GENERIC_HDR; + } + + // Extended range layer with an hdr/sdr ratio of > 1.01f can "self-promote" to HDR. + if (range == HAL_DATASPACE_RANGE_EXTENDED && hdrSdrRatio > 1.01f) { + return HdrRenderType::DISPLAY_HDR; + } + + return HdrRenderType::SDR; +} + +} // namespace android \ No newline at end of file diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 831b64d877..8ce017d7a3 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -164,9 +164,9 @@ cc_test { } cc_test { - name: "DataspaceUtils_test", + name: "HdrRenderTypeUtils_test", shared_libs: ["libui"], - srcs: ["DataspaceUtils_test.cpp"], + srcs: ["HdrRenderTypeUtils_test.cpp"], cflags: [ "-Wall", "-Werror", diff --git a/libs/ui/tests/DataspaceUtils_test.cpp b/libs/ui/tests/DataspaceUtils_test.cpp deleted file mode 100644 index 3e0967182b..0000000000 --- a/libs/ui/tests/DataspaceUtils_test.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2021 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. - */ - -#undef LOG_TAG -#define LOG_TAG "DataspaceUtilsTest" - -#include -#include - -namespace android { - -class DataspaceUtilsTest : public testing::Test {}; - -TEST_F(DataspaceUtilsTest, isHdrDataspace) { - EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_ITU_HLG)); - EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_ITU_PQ)); - EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_PQ)); - EXPECT_TRUE(isHdrDataspace(ui::Dataspace::BT2020_HLG)); - - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SRGB_LINEAR)); - // scRGB defines a very wide gamut but not an expanded luminance range - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SCRGB_LINEAR)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SRGB)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_SCRGB)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_JFIF)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_BT601_625)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_BT601_525)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::V0_BT709)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DCI_P3_LINEAR)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DCI_P3)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DISPLAY_P3_LINEAR)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DISPLAY_P3)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::ADOBE_RGB)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::BT2020_LINEAR)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::BT2020)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::BT2020_ITU)); - EXPECT_FALSE(isHdrDataspace(ui::Dataspace::DISPLAY_BT2020)); -} - -} // namespace android diff --git a/libs/ui/tests/HdrRenderTypeUtils_test.cpp b/libs/ui/tests/HdrRenderTypeUtils_test.cpp new file mode 100644 index 0000000000..efe819db76 --- /dev/null +++ b/libs/ui/tests/HdrRenderTypeUtils_test.cpp @@ -0,0 +1,65 @@ +/* + * Copyright 2021 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. + */ + +#undef LOG_TAG +#define LOG_TAG "HdrRenderTypeUtilsTest" + +#include +#include + +namespace android { + +class HdrRenderTypeUtilsTest : public testing::Test {}; + +TEST_F(HdrRenderTypeUtilsTest, getHdrRenderType) { + EXPECT_EQ(getHdrRenderType(ui::Dataspace::BT2020_ITU_HLG, std::nullopt), + HdrRenderType::GENERIC_HDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::BT2020_ITU_PQ, std::nullopt), + HdrRenderType::GENERIC_HDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::BT2020_PQ, std::nullopt), HdrRenderType::GENERIC_HDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::BT2020_HLG, std::nullopt), + HdrRenderType::GENERIC_HDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::V0_SCRGB, + std::optional(ui::PixelFormat::RGBA_FP16)), + HdrRenderType::GENERIC_HDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::V0_SCRGB, + std::optional(ui::PixelFormat::RGBA_8888), 2.f), + HdrRenderType::DISPLAY_HDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::V0_SCRGB_LINEAR, + std::optional(ui::PixelFormat::RGBA_8888), 2.f), + HdrRenderType::DISPLAY_HDR); + + EXPECT_EQ(getHdrRenderType(ui::Dataspace::V0_SRGB_LINEAR, std::nullopt), HdrRenderType::SDR); + // scRGB defines a very wide gamut but not an expanded luminance range + EXPECT_EQ(getHdrRenderType(ui::Dataspace::V0_SCRGB_LINEAR, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::V0_SCRGB, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::V0_SRGB, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::V0_JFIF, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::V0_BT601_625, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::V0_BT601_525, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::V0_BT709, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::DCI_P3_LINEAR, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::DCI_P3, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::DISPLAY_P3_LINEAR, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::DISPLAY_P3, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::ADOBE_RGB, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::BT2020_LINEAR, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::BT2020, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::BT2020_ITU, std::nullopt), HdrRenderType::SDR); + EXPECT_EQ(getHdrRenderType(ui::Dataspace::DISPLAY_BT2020, std::nullopt), HdrRenderType::SDR); +} + +} // namespace android diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index b492b6a79e..4fe6927d80 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include #include #include @@ -26,7 +25,7 @@ #include #include "system/graphics-base-v1.0.h" -#include +#include // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push @@ -312,15 +311,26 @@ void OutputLayer::updateCompositionState( } } + auto pixelFormat = layerFEState->buffer ? std::make_optional(static_cast( + layerFEState->buffer->getPixelFormat())) + : std::nullopt; + + auto hdrRenderType = + getHdrRenderType(outputState.dataspace, pixelFormat, layerFEState->desiredHdrSdrRatio); + // Determine the output dependent dataspace for this layer. If it is // colorspace agnostic, it just uses the dataspace chosen for the output to // avoid the need for color conversion. // For now, also respect the colorspace agnostic flag if we're drawing to HDR, to avoid drastic // luminance shift. TODO(b/292162273): we should check if that's true though. - state.dataspace = layerFEState->isColorspaceAgnostic && !isHdrDataspace(outputState.dataspace) + state.dataspace = layerFEState->isColorspaceAgnostic && hdrRenderType == HdrRenderType::SDR ? outputState.dataspace : layerFEState->dataspace; + // re-get HdrRenderType after the dataspace gets changed. + hdrRenderType = + getHdrRenderType(state.dataspace, pixelFormat, layerFEState->desiredHdrSdrRatio); + // Override the dataspace transfer from 170M to sRGB if the device configuration requests this. // We do this here instead of in buffer info so that dumpsys can still report layers that are // using the 170M transfer. Also we only do this if the colorspace is not agnostic for the @@ -335,7 +345,7 @@ void OutputLayer::updateCompositionState( // For hdr content, treat the white point as the display brightness - HDR content should not be // boosted or dimmed. // If the layer explicitly requests to disable dimming, then don't dim either. - if (isHdrDataspace(state.dataspace) || + if (hdrRenderType == HdrRenderType::GENERIC_HDR || getOutput().getState().displayBrightnessNits == getOutput().getState().sdrWhitePointNits || getOutput().getState().displayBrightnessNits == 0.f || !layerFEState->dimmingEnabled) { state.dimmingRatio = 1.f; @@ -344,8 +354,7 @@ void OutputLayer::updateCompositionState( 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 - if ((state.dataspace & HAL_DATASPACE_RANGE_MASK) == HAL_DATASPACE_RANGE_EXTENDED && - layerFEState->currentHdrSdrRatio > 1.01f) { + if (hdrRenderType == HdrRenderType::DISPLAY_HDR) { layerBrightnessNits *= layerFEState->currentHdrSdrRatio; } state.dimmingRatio = diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 1a0517ac0d..38a36fc6bc 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -50,10 +50,10 @@ #include #include #include -#include #include #include #include +#include #include #include #include diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ef483f673d..13a457ed7d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -81,7 +81,6 @@ #include #include #include -#include #include #include #include @@ -89,6 +88,7 @@ #include #include #include +#include #include #include #include @@ -2796,7 +2796,14 @@ bool SurfaceFlinger::isHdrLayer(const frontend::LayerSnapshot& snapshot) const { return false; } } - if (isHdrDataspace(snapshot.dataspace)) { + // RANGE_EXTENDED layer may identify themselves as being "HDR" + // via a desired hdr/sdr ratio + auto pixelFormat = snapshot.buffer + ? std::make_optional(static_cast(snapshot.buffer->getPixelFormat())) + : std::nullopt; + + if (getHdrRenderType(snapshot.dataspace, pixelFormat, snapshot.desiredHdrSdrRatio) != + HdrRenderType::SDR) { return true; } // If the layer is not allowed to be dimmed, treat it as HDR. WindowManager may disable @@ -2806,12 +2813,6 @@ bool SurfaceFlinger::isHdrLayer(const frontend::LayerSnapshot& snapshot) const { if (!snapshot.dimmingEnabled) { return true; } - // RANGE_EXTENDED layers may identify themselves as being "HDR" via a desired sdr/hdr ratio - if ((snapshot.dataspace & (int32_t)Dataspace::RANGE_MASK) == - (int32_t)Dataspace::RANGE_EXTENDED && - snapshot.desiredHdrSdrRatio > 1.01f) { - return true; - } return false; } -- GitLab From 261ce7a3854d2a5a0153adad985c314073de3655 Mon Sep 17 00:00:00 2001 From: Lais Andrade Date: Wed, 16 Aug 2023 15:30:04 +0100 Subject: [PATCH 0471/1187] Fix flaky VibratorCallbackSchedulerTest The test is sometimes timing out while asserting the scheduled callbacks are triggered within the required test timeout. Update CallbackScheduler to use std::condition_variable_any::wait_for with calculated durations from using std::chrono::steady_clock, instead of relying on the timestamps via wait_until. Update the VibratorCallbackSchedulerTest to also use wait_for. Bug: 293603710 Test: VibratorCallbackSchedulerTest Change-Id: Ie84147a9ff686d666d8525a35914571f32d72719 --- .../vibratorservice/VibratorCallbackScheduler.cpp | 11 ++++++++--- .../vibratorservice/VibratorCallbackScheduler.h | 8 ++++---- .../test/VibratorCallbackSchedulerTest.cpp | 12 +++++++++--- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/services/vibratorservice/VibratorCallbackScheduler.cpp b/services/vibratorservice/VibratorCallbackScheduler.cpp index f2870b021d..7eda9ef0c7 100644 --- a/services/vibratorservice/VibratorCallbackScheduler.cpp +++ b/services/vibratorservice/VibratorCallbackScheduler.cpp @@ -29,8 +29,11 @@ bool DelayedCallback::isExpired() const { return mExpiration <= std::chrono::steady_clock::now(); } -DelayedCallback::Timestamp DelayedCallback::getExpiration() const { - return mExpiration; +std::chrono::milliseconds DelayedCallback::getWaitForExpirationDuration() const { + std::chrono::milliseconds delta = std::chrono::duration_cast( + mExpiration - std::chrono::steady_clock::now()); + // Return zero if this is already expired. + return delta > delta.zero() ? delta : delta.zero(); } void DelayedCallback::run() const { @@ -88,7 +91,9 @@ void CallbackScheduler::loop() { mCondition.wait(mMutex); } else { // Wait until next callback expires, or a new one is scheduled. - mCondition.wait_until(mMutex, mQueue.top().getExpiration()); + // Use the monotonic steady clock to wait for the measured delay interval via wait_for + // instead of using a wall clock via wait_until. + mCondition.wait_for(mMutex, mQueue.top().getWaitForExpirationDuration()); } } } diff --git a/services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h b/services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h index 2c194b5526..c8ec15d414 100644 --- a/services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h +++ b/services/vibratorservice/include/vibratorservice/VibratorCallbackScheduler.h @@ -30,15 +30,13 @@ namespace vibrator { // Wrapper for a callback to be executed after a delay. class DelayedCallback { public: - using Timestamp = std::chrono::time_point; - DelayedCallback(std::function callback, std::chrono::milliseconds delay) : mCallback(callback), mExpiration(std::chrono::steady_clock::now() + delay) {} ~DelayedCallback() = default; void run() const; bool isExpired() const; - Timestamp getExpiration() const; + std::chrono::milliseconds getWaitForExpirationDuration() const; // Compare by expiration time, where A < B when A expires first. bool operator<(const DelayedCallback& other) const; @@ -46,7 +44,9 @@ public: private: std::function mCallback; - Timestamp mExpiration; + // Use a steady monotonic clock to calculate the duration until expiration. + // This clock is not related to wall clock time and is most suitable for measuring intervals. + std::chrono::time_point mExpiration; }; // Schedules callbacks to be executed after a delay. diff --git a/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp index 106ab9e858..426cd426f7 100644 --- a/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp +++ b/services/vibratorservice/test/VibratorCallbackSchedulerTest.cpp @@ -71,15 +71,21 @@ protected: } int32_t waitForCallbacks(int32_t callbackCount, milliseconds timeout) { - time_point expiration = steady_clock::now() + timeout + TEST_TIMEOUT; + time_point expirationTime = steady_clock::now() + timeout + TEST_TIMEOUT; int32_t expiredCallbackCount = 0; - while (steady_clock::now() < expiration) { + while (steady_clock::now() < expirationTime) { std::lock_guard lock(mMutex); expiredCallbackCount = mExpiredCallbacks.size(); if (callbackCount <= expiredCallbackCount) { return expiredCallbackCount; } - mCondition.wait_until(mMutex, expiration); + auto currentTimeout = std::chrono::duration_cast( + expirationTime - steady_clock::now()); + if (currentTimeout > currentTimeout.zero()) { + // Use the monotonic steady clock to wait for the requested timeout via wait_for + // instead of using a wall clock via wait_until. + mCondition.wait_for(mMutex, currentTimeout); + } } return expiredCallbackCount; } -- GitLab From 00eac29d8c5e3ec07ff586edb99e7a06902379cb Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Wed, 16 Aug 2023 15:04:36 +0000 Subject: [PATCH 0472/1187] Use String8/16 c_str [input] Bug: 295394788 Test: make checkbuild Change-Id: Iffbcff6f58e30c0bd40e699ba6e1f917addc5ade --- libs/input/KeyCharacterMap.cpp | 123 +++++++++--------- libs/input/KeyLayoutMap.cpp | 119 +++++++++-------- libs/input/PropertyMap.cpp | 16 +-- libs/input/VirtualKeyMap.cpp | 17 ++- services/inputflinger/host/InputDriver.cpp | 6 +- services/inputflinger/host/InputFlinger.cpp | 2 +- .../VirtualTouchpadService.cpp | 2 +- 7 files changed, 138 insertions(+), 147 deletions(-) diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index 12c9e533c3..d571917ff9 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -140,7 +140,7 @@ status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) { #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); + tokenizer->getFilename().c_str(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (status != OK) { ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str()); @@ -297,7 +297,7 @@ bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t if (!findKey(ch, &keyCode, &metaState)) { #if DEBUG_MAPPING ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.", - deviceId, toString(chars, numChars).string(), ch); + deviceId, toString(chars, numChars).c_str(), ch); #endif return false; } @@ -309,8 +309,8 @@ bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t addMetaKeys(outEvents, deviceId, metaState, false, now, ¤tMetaState); } #if DEBUG_MAPPING - ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", - deviceId, toString(chars, numChars).string(), int32_t(outEvents.size())); + ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", deviceId, + toString(chars, numChars).c_str(), int32_t(outEvents.size())); for (size_t i = 0; i < outEvents.size(); i++) { ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.", outEvents[i].getKeyCode(), outEvents[i].getMetaState(), @@ -756,8 +756,8 @@ KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Form status_t KeyCharacterMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); #endif mTokenizer->skipDelimiters(WHITESPACE); @@ -779,8 +779,8 @@ status_t KeyCharacterMap::Parser::parse() { status_t status = parseKey(); if (status) return status; } else { - ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); + ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(), + keywordToken.c_str()); return BAD_VALUE; } break; @@ -795,10 +795,9 @@ status_t KeyCharacterMap::Parser::parse() { mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { - ALOGE("%s: Expected end of line or trailing comment, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); - return BAD_VALUE; + ALOGE("%s: Expected end of line or trailing comment, got '%s'.", + mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str()); + return BAD_VALUE; } } @@ -807,27 +806,27 @@ status_t KeyCharacterMap::Parser::parse() { if (mState != STATE_TOP) { ALOGE("%s: Unterminated key description at end of file.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (mMap->mType == KeyboardType::UNKNOWN) { ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (mFormat == Format::BASE) { if (mMap->mType == KeyboardType::OVERLAY) { ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } } else if (mFormat == Format::OVERLAY) { if (mMap->mType != KeyboardType::OVERLAY) { ALOGE("%s: Overlay keyboard layout missing required keyboard " - "'type OVERLAY' declaration.", - mTokenizer->getLocation().string()); + "'type OVERLAY' declaration.", + mTokenizer->getLocation().c_str()); return BAD_VALUE; } } @@ -837,8 +836,7 @@ status_t KeyCharacterMap::Parser::parse() { status_t KeyCharacterMap::Parser::parseType() { if (mMap->mType != KeyboardType::UNKNOWN) { - ALOGE("%s: Duplicate keyboard 'type' declaration.", - mTokenizer->getLocation().string()); + ALOGE("%s: Duplicate keyboard 'type' declaration.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -860,8 +858,8 @@ status_t KeyCharacterMap::Parser::parseType() { } else if (typeToken == "OVERLAY") { type = KeyboardType::OVERLAY; } else { - ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(), - typeToken.string()); + ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().c_str(), + typeToken.c_str()); return BAD_VALUE; } @@ -878,8 +876,8 @@ status_t KeyCharacterMap::Parser::parseMap() { mTokenizer->skipDelimiters(WHITESPACE); return parseMapKey(); } - ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); + ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().c_str(), + keywordToken.c_str()); return BAD_VALUE; } @@ -893,26 +891,26 @@ status_t KeyCharacterMap::Parser::parseMapKey() { } char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); + int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } std::map& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; const auto it = map.find(code); if (it != map.end()) { - ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - std::optional keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); + std::optional keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str()); if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); + ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(), + keyCodeToken.c_str()); return BAD_VALUE; } @@ -926,23 +924,23 @@ status_t KeyCharacterMap::Parser::parseMapKey() { status_t KeyCharacterMap::Parser::parseKey() { String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - std::optional keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); + std::optional keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str()); if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); + ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(), + keyCodeToken.c_str()); return BAD_VALUE; } if (mMap->mKeys.find(*keyCode) != mMap->mKeys.end()) { - ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); + ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().c_str(), + keyCodeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 openBraceToken = mTokenizer->nextToken(WHITESPACE); if (openBraceToken != "{") { - ALOGE("%s: Expected '{' after key code label, got '%s'.", - mTokenizer->getLocation().string(), openBraceToken.string()); + ALOGE("%s: Expected '{' after key code label, got '%s'.", mTokenizer->getLocation().c_str(), + openBraceToken.c_str()); return BAD_VALUE; } @@ -971,10 +969,10 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { properties.emplace_back(PROPERTY_NUMBER); } else { int32_t metaState; - status_t status = parseModifier(token.string(), &metaState); + status_t status = parseModifier(token.c_str(), &metaState); if (status) { ALOGE("%s: Expected a property name or modifier, got '%s'.", - mTokenizer->getLocation().string(), token.string()); + mTokenizer->getLocation().c_str(), token.c_str()); return status; } properties.emplace_back(PROPERTY_META, metaState); @@ -992,8 +990,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { } } - ALOGE("%s: Expected ',' or ':' after property name.", - mTokenizer->getLocation().string()); + ALOGE("%s: Expected ',' or ':' after property name.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -1011,18 +1008,17 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { char16_t character; status_t status = parseCharacterLiteral(&character); if (status || !character) { - ALOGE("%s: Invalid character literal for key.", - mTokenizer->getLocation().string()); + ALOGE("%s: Invalid character literal for key.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (haveCharacter) { ALOGE("%s: Cannot combine multiple character literals or 'none'.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (haveReplacement) { ALOGE("%s: Cannot combine character literal with replace action.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } behavior.character = character; @@ -1032,28 +1028,27 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { if (token == "none") { if (haveCharacter) { ALOGE("%s: Cannot combine multiple character literals or 'none'.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (haveReplacement) { ALOGE("%s: Cannot combine 'none' with replace action.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } haveCharacter = true; } else if (token == "fallback") { mTokenizer->skipDelimiters(WHITESPACE); token = mTokenizer->nextToken(WHITESPACE); - std::optional keyCode = InputEventLookup::getKeyCodeByLabel(token.string()); + std::optional keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str()); if (!keyCode) { ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.", - mTokenizer->getLocation().string(), - token.string()); + mTokenizer->getLocation().c_str(), token.c_str()); return BAD_VALUE; } if (haveFallback || haveReplacement) { ALOGE("%s: Cannot combine multiple fallback/replacement key codes.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } behavior.fallbackKeyCode = *keyCode; @@ -1061,29 +1056,27 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { } else if (token == "replace") { mTokenizer->skipDelimiters(WHITESPACE); token = mTokenizer->nextToken(WHITESPACE); - std::optional keyCode = InputEventLookup::getKeyCodeByLabel(token.string()); + std::optional keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str()); if (!keyCode) { ALOGE("%s: Invalid key code label for replace, got '%s'.", - mTokenizer->getLocation().string(), - token.string()); + mTokenizer->getLocation().c_str(), token.c_str()); return BAD_VALUE; } if (haveCharacter) { ALOGE("%s: Cannot combine character literal with replace action.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (haveFallback || haveReplacement) { ALOGE("%s: Cannot combine multiple fallback/replacement key codes.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } behavior.replacementKeyCode = *keyCode; haveReplacement = true; } else { - ALOGE("%s: Expected a key behavior after ':'.", - mTokenizer->getLocation().string()); + ALOGE("%s: Expected a key behavior after ':'.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } } @@ -1096,7 +1089,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { switch (property.property) { case PROPERTY_LABEL: if (key.label) { - ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().string()); + ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } key.label = behavior.character; @@ -1106,7 +1099,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { break; case PROPERTY_NUMBER: if (key.number) { - ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().string()); + ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } key.number = behavior.character; @@ -1118,7 +1111,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { for (const Behavior& b : key.behaviors) { if (b.metaState == property.metaState) { ALOGE("%s: Duplicate key behavior for modifier.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } } @@ -1185,8 +1178,8 @@ status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_ return BAD_VALUE; } if (combinedMeta & metaState) { - ALOGE("%s: Duplicate modifier combination '%s'.", - mTokenizer->getLocation().string(), token.c_str()); + ALOGE("%s: Duplicate modifier combination '%s'.", mTokenizer->getLocation().c_str(), + token.c_str()); return BAD_VALUE; } @@ -1259,7 +1252,7 @@ status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) } Error: - ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string()); + ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp index a194513953..ddc9ea457e 100644 --- a/libs/input/KeyLayoutMap.cpp +++ b/libs/input/KeyLayoutMap.cpp @@ -177,7 +177,7 @@ base::Result> KeyLayoutMap::load(Tokenizer* tokeni #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), + tokenizer->getFilename().c_str(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (!status) { @@ -306,8 +306,8 @@ KeyLayoutMap::Parser::~Parser() { status_t KeyLayoutMap::Parser::parse() { while (!mTokenizer->isEof()) { - ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); mTokenizer->skipDelimiters(WHITESPACE); @@ -334,16 +334,15 @@ status_t KeyLayoutMap::Parser::parse() { status_t status = parseRequiredKernelConfig(); if (status) return status; } else { - ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); + ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(), + keywordToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { ALOGE("%s: Expected end of line or trailing comment, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str()); return BAD_VALUE; } } @@ -362,26 +361,26 @@ status_t KeyLayoutMap::Parser::parseKey() { codeToken = mTokenizer->nextToken(WHITESPACE); } - std::optional code = parseInt(codeToken.string()); + std::optional code = parseInt(codeToken.c_str()); if (!code) { - ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } std::unordered_map& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; if (map.find(*code) != map.end()) { - ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - std::optional keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); + std::optional keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str()); if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); + ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(), + keyCodeToken.c_str()); return BAD_VALUE; } @@ -391,15 +390,15 @@ status_t KeyLayoutMap::Parser::parseKey() { if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break; String8 flagToken = mTokenizer->nextToken(WHITESPACE); - std::optional flag = InputEventLookup::getKeyFlagByLabel(flagToken.string()); + std::optional flag = InputEventLookup::getKeyFlagByLabel(flagToken.c_str()); if (!flag) { - ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(), - flagToken.string()); + ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().c_str(), + flagToken.c_str()); return BAD_VALUE; } if (flags & *flag) { - ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(), - flagToken.string()); + ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().c_str(), + flagToken.c_str()); return BAD_VALUE; } flags |= *flag; @@ -417,15 +416,15 @@ status_t KeyLayoutMap::Parser::parseKey() { status_t KeyLayoutMap::Parser::parseAxis() { String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); - std::optional scanCode = parseInt(scanCodeToken.string()); + std::optional scanCode = parseInt(scanCodeToken.c_str()); if (!scanCode) { - ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(), - scanCodeToken.string()); + ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().c_str(), + scanCodeToken.c_str()); return BAD_VALUE; } if (mMap->mAxes.find(*scanCode) != mMap->mAxes.end()) { - ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(), - scanCodeToken.string()); + ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().c_str(), + scanCodeToken.c_str()); return BAD_VALUE; } @@ -438,10 +437,10 @@ status_t KeyLayoutMap::Parser::parseAxis() { mTokenizer->skipDelimiters(WHITESPACE); String8 axisToken = mTokenizer->nextToken(WHITESPACE); - std::optional axis = InputEventLookup::getAxisByLabel(axisToken.string()); + std::optional axis = InputEventLookup::getAxisByLabel(axisToken.c_str()); if (!axis) { ALOGE("%s: Expected inverted axis label, got '%s'.", - mTokenizer->getLocation().string(), axisToken.string()); + mTokenizer->getLocation().c_str(), axisToken.c_str()); return BAD_VALUE; } axisInfo.axis = *axis; @@ -450,38 +449,38 @@ status_t KeyLayoutMap::Parser::parseAxis() { mTokenizer->skipDelimiters(WHITESPACE); String8 splitToken = mTokenizer->nextToken(WHITESPACE); - std::optional splitValue = parseInt(splitToken.string()); + std::optional splitValue = parseInt(splitToken.c_str()); if (!splitValue) { ALOGE("%s: Expected split value, got '%s'.", - mTokenizer->getLocation().string(), splitToken.string()); + mTokenizer->getLocation().c_str(), splitToken.c_str()); return BAD_VALUE; } axisInfo.splitValue = *splitValue; mTokenizer->skipDelimiters(WHITESPACE); String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE); - std::optional axis = InputEventLookup::getAxisByLabel(lowAxisToken.string()); + std::optional axis = InputEventLookup::getAxisByLabel(lowAxisToken.c_str()); if (!axis) { ALOGE("%s: Expected low axis label, got '%s'.", - mTokenizer->getLocation().string(), lowAxisToken.string()); + mTokenizer->getLocation().c_str(), lowAxisToken.c_str()); return BAD_VALUE; } axisInfo.axis = *axis; mTokenizer->skipDelimiters(WHITESPACE); String8 highAxisToken = mTokenizer->nextToken(WHITESPACE); - std::optional highAxis = InputEventLookup::getAxisByLabel(highAxisToken.string()); + std::optional highAxis = InputEventLookup::getAxisByLabel(highAxisToken.c_str()); if (!highAxis) { ALOGE("%s: Expected high axis label, got '%s'.", - mTokenizer->getLocation().string(), highAxisToken.string()); + mTokenizer->getLocation().c_str(), highAxisToken.c_str()); return BAD_VALUE; } axisInfo.highAxis = *highAxis; } else { - std::optional axis = InputEventLookup::getAxisByLabel(token.string()); + std::optional axis = InputEventLookup::getAxisByLabel(token.c_str()); if (!axis) { ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.", - mTokenizer->getLocation().string(), token.string()); + mTokenizer->getLocation().c_str(), token.c_str()); return BAD_VALUE; } axisInfo.axis = *axis; @@ -496,16 +495,16 @@ status_t KeyLayoutMap::Parser::parseAxis() { if (keywordToken == "flat") { mTokenizer->skipDelimiters(WHITESPACE); String8 flatToken = mTokenizer->nextToken(WHITESPACE); - std::optional flatOverride = parseInt(flatToken.string()); + std::optional flatOverride = parseInt(flatToken.c_str()); if (!flatOverride) { ALOGE("%s: Expected flat value, got '%s'.", - mTokenizer->getLocation().string(), flatToken.string()); + mTokenizer->getLocation().c_str(), flatToken.c_str()); return BAD_VALUE; } axisInfo.flatOverride = *flatOverride; } else { - ALOGE("%s: Expected keyword 'flat', got '%s'.", - mTokenizer->getLocation().string(), keywordToken.string()); + ALOGE("%s: Expected keyword 'flat', got '%s'.", mTokenizer->getLocation().c_str(), + keywordToken.c_str()); return BAD_VALUE; } } @@ -527,27 +526,27 @@ status_t KeyLayoutMap::Parser::parseLed() { mTokenizer->skipDelimiters(WHITESPACE); codeToken = mTokenizer->nextToken(WHITESPACE); } - std::optional code = parseInt(codeToken.string()); + std::optional code = parseInt(codeToken.c_str()); if (!code) { - ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } std::unordered_map& map = mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode; if (map.find(*code) != map.end()) { - ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE); - std::optional ledCode = InputEventLookup::getLedByLabel(ledCodeToken.string()); + std::optional ledCode = InputEventLookup::getLedByLabel(ledCodeToken.c_str()); if (!ledCode) { - ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(), - ledCodeToken.string()); + ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().c_str(), + ledCodeToken.c_str()); return BAD_VALUE; } @@ -569,7 +568,7 @@ static std::optional getSensorType(const char* token) { } static std::optional getSensorDataIndex(String8 token) { - std::string tokenStr(token.string()); + std::string tokenStr(token.c_str()); if (tokenStr == "X") { return 0; } else if (tokenStr == "Y") { @@ -594,26 +593,26 @@ static std::optional getSensorDataIndex(String8 token) { // sensor 0x05 GYROSCOPE Z status_t KeyLayoutMap::Parser::parseSensor() { String8 codeToken = mTokenizer->nextToken(WHITESPACE); - std::optional code = parseInt(codeToken.string()); + std::optional code = parseInt(codeToken.c_str()); if (!code) { - ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().string(), - "abs code", codeToken.string()); + ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().c_str(), + "abs code", codeToken.c_str()); return BAD_VALUE; } std::unordered_map& map = mMap->mSensorsByAbsCode; if (map.find(*code) != map.end()) { - ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().string(), - "abs code", codeToken.string()); + ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().c_str(), + "abs code", codeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 sensorTypeToken = mTokenizer->nextToken(WHITESPACE); - std::optional typeOpt = getSensorType(sensorTypeToken.string()); + std::optional typeOpt = getSensorType(sensorTypeToken.c_str()); if (!typeOpt) { - ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().string(), - sensorTypeToken.string()); + ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().c_str(), + sensorTypeToken.c_str()); return BAD_VALUE; } InputDeviceSensorType sensorType = typeOpt.value(); @@ -621,8 +620,8 @@ status_t KeyLayoutMap::Parser::parseSensor() { String8 sensorDataIndexToken = mTokenizer->nextToken(WHITESPACE); std::optional indexOpt = getSensorDataIndex(sensorDataIndexToken); if (!indexOpt) { - ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().string(), - sensorDataIndexToken.string()); + ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().c_str(), + sensorDataIndexToken.c_str()); return BAD_VALUE; } int32_t sensorDataIndex = indexOpt.value(); @@ -643,12 +642,12 @@ status_t KeyLayoutMap::Parser::parseSensor() { // requires_kernel_config CONFIG_HID_PLAYSTATION status_t KeyLayoutMap::Parser::parseRequiredKernelConfig() { String8 codeToken = mTokenizer->nextToken(WHITESPACE); - std::string configName = codeToken.string(); + std::string configName = codeToken.c_str(); const auto result = mMap->mRequiredKernelConfigs.emplace(configName); if (!result.second) { ALOGE("%s: Duplicate entry for required kernel config %s.", - mTokenizer->getLocation().string(), configName.c_str()); + mTokenizer->getLocation().c_str(), configName.c_str()); return BAD_VALUE; } diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp index 548f894d22..315f5a6d4f 100644 --- a/libs/input/PropertyMap.cpp +++ b/libs/input/PropertyMap.cpp @@ -163,8 +163,8 @@ PropertyMap::Parser::~Parser() {} status_t PropertyMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); #endif mTokenizer->skipDelimiters(WHITESPACE); @@ -172,7 +172,7 @@ status_t PropertyMap::Parser::parse() { if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); if (keyToken.isEmpty()) { - ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string()); + ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -180,7 +180,7 @@ status_t PropertyMap::Parser::parse() { if (mTokenizer->nextChar() != '=') { ALOGE("%s: Expected '=' between property key and value.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -189,20 +189,20 @@ status_t PropertyMap::Parser::parse() { String8 valueToken = mTokenizer->nextToken(WHITESPACE); if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) { ALOGE("%s: Found reserved character '\\' or '\"' in property value.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol()) { - ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); return BAD_VALUE; } if (mMap->hasProperty(keyToken.string())) { ALOGE("%s: Duplicate property value for key '%s'.", - mTokenizer->getLocation().string(), keyToken.string()); + mTokenizer->getLocation().c_str(), keyToken.c_str()); return BAD_VALUE; } diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp index 865366bcb2..de62c870ff 100644 --- a/libs/input/VirtualKeyMap.cpp +++ b/libs/input/VirtualKeyMap.cpp @@ -79,8 +79,8 @@ VirtualKeyMap::Parser::~Parser() { status_t VirtualKeyMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); #endif mTokenizer->skipDelimiters(WHITESPACE); @@ -91,7 +91,7 @@ status_t VirtualKeyMap::Parser::parse() { String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); if (token != "0x01") { ALOGE("%s: Unknown virtual key type, expected 0x01.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -103,7 +103,7 @@ status_t VirtualKeyMap::Parser::parse() { && parseNextIntField(&defn.height); if (!success) { ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -116,9 +116,8 @@ status_t VirtualKeyMap::Parser::parse() { } while (consumeFieldDelimiterAndSkipWhitespace()); if (!mTokenizer->isEol()) { - ALOGE("%s: Expected end of line, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); return BAD_VALUE; } } @@ -146,9 +145,9 @@ bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) { String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); char* end; - *outValue = strtol(token.string(), &end, 0); + *outValue = strtol(token.c_str(), &end, 0); if (token.isEmpty() || *end != '\0') { - ALOGE("Expected an integer, got '%s'.", token.string()); + ALOGE("Expected an integer, got '%s'.", token.c_str()); return false; } return true; diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp index ec0388d500..de99fc73ec 100644 --- a/services/inputflinger/host/InputDriver.cpp +++ b/services/inputflinger/host/InputDriver.cpp @@ -256,14 +256,14 @@ input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, const char* InputDriver::inputGetPropertyKey(input_property_t* property) { if (property != nullptr) { - return property->key.string(); + return property->key.c_str(); } return nullptr; } const char* InputDriver::inputGetPropertyValue(input_property_t* property) { if (property != nullptr) { - return property->value.string(); + return property->value.c_str(); } return nullptr; } @@ -281,7 +281,7 @@ void InputDriver::inputFreeDevicePropertyMap(input_property_map_t* map) { } void InputDriver::dump(String8& result) { - result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string()); + result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.c_str()); } } // namespace android diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp index 2da2a70c03..d974c43d78 100644 --- a/services/inputflinger/host/InputFlinger.cpp +++ b/services/inputflinger/host/InputFlinger.cpp @@ -57,7 +57,7 @@ status_t InputFlinger::dump(int fd, const Vector& args) { } else { dumpInternal(result); } - write(fd, result.string(), result.size()); + write(fd, result.c_str(), result.size()); return OK; } diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp index 523f890ce7..d0a9da1ff5 100644 --- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp +++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp @@ -113,7 +113,7 @@ status_t VirtualTouchpadService::dump( static_cast(client_pid_)); touchpad_->dumpInternal(result); } - write(fd, result.string(), result.size()); + write(fd, result.c_str(), result.size()); return OK; } -- GitLab From d5b677c78d9923dd8cb90d2e15cc0c9514d7269d Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Wed, 16 Aug 2023 15:04:36 +0000 Subject: [PATCH 0473/1187] Use String8/16 c_str [input] Bug: 295394788 Test: make checkbuild Change-Id: Iffbcff6f58e30c0bd40e699ba6e1f917addc5ade Merged-In: Iffbcff6f58e30c0bd40e699ba6e1f917addc5ade --- libs/input/KeyCharacterMap.cpp | 125 ++++++++--------- libs/input/KeyLayoutMap.cpp | 129 +++++++++--------- libs/input/Keyboard.cpp | 8 +- libs/input/PropertyMap.cpp | 30 ++-- libs/input/VirtualKeyMap.cpp | 17 ++- services/inputflinger/host/InputDriver.cpp | 6 +- services/inputflinger/host/InputFlinger.cpp | 2 +- .../reader/mapper/CursorInputMapper.cpp | 2 +- .../reader/mapper/TouchInputMapper.cpp | 16 +-- .../inputflinger/tests/InputReader_test.cpp | 2 +- .../VirtualTouchpadService.cpp | 2 +- 11 files changed, 164 insertions(+), 175 deletions(-) diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index 2039fa6553..7a379f530b 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -209,7 +209,7 @@ status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format) { #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); + tokenizer->getFilename().c_str(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (status != OK) { ALOGE("Loading KeyCharacterMap failed with status %s", statusToString(status).c_str()); @@ -363,8 +363,8 @@ char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_ ExactMatch: ; } #if DEBUG_MAPPING - ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.", - keyCode, toString(chars, numChars).string(), metaState, result); + ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.", keyCode, + toString(chars, numChars).c_str(), metaState, result); #endif return result; } @@ -379,7 +379,7 @@ bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t if (!findKey(ch, &keyCode, &metaState)) { #if DEBUG_MAPPING ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.", - deviceId, toString(chars, numChars).string(), ch); + deviceId, toString(chars, numChars).c_str(), ch); #endif return false; } @@ -391,8 +391,8 @@ bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t addMetaKeys(outEvents, deviceId, metaState, false, now, ¤tMetaState); } #if DEBUG_MAPPING - ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", - deviceId, toString(chars, numChars).string(), int32_t(outEvents.size())); + ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", deviceId, + toString(chars, numChars).c_str(), int32_t(outEvents.size())); for (size_t i = 0; i < outEvents.size(); i++) { ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.", outEvents[i].getKeyCode(), outEvents[i].getMetaState(), @@ -849,8 +849,8 @@ KeyCharacterMap::Parser::~Parser() { status_t KeyCharacterMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); #endif mTokenizer->skipDelimiters(WHITESPACE); @@ -872,8 +872,8 @@ status_t KeyCharacterMap::Parser::parse() { status_t status = parseKey(); if (status) return status; } else { - ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); + ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(), + keywordToken.c_str()); return BAD_VALUE; } break; @@ -889,8 +889,7 @@ status_t KeyCharacterMap::Parser::parse() { mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { ALOGE("%s: Expected end of line or trailing comment, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str()); return BAD_VALUE; } } @@ -900,27 +899,27 @@ status_t KeyCharacterMap::Parser::parse() { if (mState != STATE_TOP) { ALOGE("%s: Unterminated key description at end of file.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (mMap->mType == KeyboardType::UNKNOWN) { ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (mFormat == Format::BASE) { if (mMap->mType == KeyboardType::OVERLAY) { ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } } else if (mFormat == Format::OVERLAY) { if (mMap->mType != KeyboardType::OVERLAY) { ALOGE("%s: Overlay keyboard layout missing required keyboard " - "'type OVERLAY' declaration.", - mTokenizer->getLocation().string()); + "'type OVERLAY' declaration.", + mTokenizer->getLocation().c_str()); return BAD_VALUE; } } @@ -930,8 +929,7 @@ status_t KeyCharacterMap::Parser::parse() { status_t KeyCharacterMap::Parser::parseType() { if (mMap->mType != KeyboardType::UNKNOWN) { - ALOGE("%s: Duplicate keyboard 'type' declaration.", - mTokenizer->getLocation().string()); + ALOGE("%s: Duplicate keyboard 'type' declaration.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -953,8 +951,8 @@ status_t KeyCharacterMap::Parser::parseType() { } else if (typeToken == "OVERLAY") { type = KeyboardType::OVERLAY; } else { - ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(), - typeToken.string()); + ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().c_str(), + typeToken.c_str()); return BAD_VALUE; } @@ -971,8 +969,8 @@ status_t KeyCharacterMap::Parser::parseMap() { mTokenizer->skipDelimiters(WHITESPACE); return parseMapKey(); } - ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); + ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().c_str(), + keywordToken.c_str()); return BAD_VALUE; } @@ -986,26 +984,26 @@ status_t KeyCharacterMap::Parser::parseMapKey() { } char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); + int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } KeyedVector& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; if (map.indexOfKey(code) >= 0) { - ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); + int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str()); if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); + ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(), + keyCodeToken.c_str()); return BAD_VALUE; } @@ -1019,23 +1017,23 @@ status_t KeyCharacterMap::Parser::parseMapKey() { status_t KeyCharacterMap::Parser::parseKey() { String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); + int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str()); if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); + ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(), + keyCodeToken.c_str()); return BAD_VALUE; } if (mMap->mKeys.indexOfKey(keyCode) >= 0) { - ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); + ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().c_str(), + keyCodeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 openBraceToken = mTokenizer->nextToken(WHITESPACE); if (openBraceToken != "{") { - ALOGE("%s: Expected '{' after key code label, got '%s'.", - mTokenizer->getLocation().string(), openBraceToken.string()); + ALOGE("%s: Expected '{' after key code label, got '%s'.", mTokenizer->getLocation().c_str(), + openBraceToken.c_str()); return BAD_VALUE; } @@ -1066,10 +1064,10 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { properties.add(Property(PROPERTY_NUMBER)); } else { int32_t metaState; - status_t status = parseModifier(token.string(), &metaState); + status_t status = parseModifier(token.c_str(), &metaState); if (status) { ALOGE("%s: Expected a property name or modifier, got '%s'.", - mTokenizer->getLocation().string(), token.string()); + mTokenizer->getLocation().c_str(), token.c_str()); return status; } properties.add(Property(PROPERTY_META, metaState)); @@ -1087,8 +1085,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { } } - ALOGE("%s: Expected ',' or ':' after property name.", - mTokenizer->getLocation().string()); + ALOGE("%s: Expected ',' or ':' after property name.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -1106,18 +1103,17 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { char16_t character; status_t status = parseCharacterLiteral(&character); if (status || !character) { - ALOGE("%s: Invalid character literal for key.", - mTokenizer->getLocation().string()); + ALOGE("%s: Invalid character literal for key.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (haveCharacter) { ALOGE("%s: Cannot combine multiple character literals or 'none'.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (haveReplacement) { ALOGE("%s: Cannot combine character literal with replace action.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } behavior.character = character; @@ -1127,28 +1123,27 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { if (token == "none") { if (haveCharacter) { ALOGE("%s: Cannot combine multiple character literals or 'none'.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (haveReplacement) { ALOGE("%s: Cannot combine 'none' with replace action.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } haveCharacter = true; } else if (token == "fallback") { mTokenizer->skipDelimiters(WHITESPACE); token = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.string()); + int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str()); if (!keyCode) { ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.", - mTokenizer->getLocation().string(), - token.string()); + mTokenizer->getLocation().c_str(), token.c_str()); return BAD_VALUE; } if (haveFallback || haveReplacement) { ALOGE("%s: Cannot combine multiple fallback/replacement key codes.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } behavior.fallbackKeyCode = keyCode; @@ -1156,29 +1151,27 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { } else if (token == "replace") { mTokenizer->skipDelimiters(WHITESPACE); token = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.string()); + int32_t keyCode = InputEventLookup::getKeyCodeByLabel(token.c_str()); if (!keyCode) { ALOGE("%s: Invalid key code label for replace, got '%s'.", - mTokenizer->getLocation().string(), - token.string()); + mTokenizer->getLocation().c_str(), token.c_str()); return BAD_VALUE; } if (haveCharacter) { ALOGE("%s: Cannot combine character literal with replace action.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } if (haveFallback || haveReplacement) { ALOGE("%s: Cannot combine multiple fallback/replacement key codes.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } behavior.replacementKeyCode = keyCode; haveReplacement = true; } else { - ALOGE("%s: Expected a key behavior after ':'.", - mTokenizer->getLocation().string()); + ALOGE("%s: Expected a key behavior after ':'.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } } @@ -1192,8 +1185,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { switch (property.property) { case PROPERTY_LABEL: if (key->label) { - ALOGE("%s: Duplicate label for key.", - mTokenizer->getLocation().string()); + ALOGE("%s: Duplicate label for key.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } key->label = behavior.character; @@ -1203,8 +1195,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { break; case PROPERTY_NUMBER: if (key->number) { - ALOGE("%s: Duplicate number for key.", - mTokenizer->getLocation().string()); + ALOGE("%s: Duplicate number for key.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } key->number = behavior.character; @@ -1216,7 +1207,7 @@ status_t KeyCharacterMap::Parser::parseKeyProperty() { for (Behavior* b = key->firstBehavior; b; b = b->next) { if (b->metaState == property.metaState) { ALOGE("%s: Duplicate key behavior for modifier.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } } @@ -1285,8 +1276,8 @@ status_t KeyCharacterMap::Parser::parseModifier(const std::string& token, int32_ return BAD_VALUE; } if (combinedMeta & metaState) { - ALOGE("%s: Duplicate modifier combination '%s'.", - mTokenizer->getLocation().string(), token.c_str()); + ALOGE("%s: Duplicate modifier combination '%s'.", mTokenizer->getLocation().c_str(), + token.c_str()); return BAD_VALUE; } @@ -1359,7 +1350,7 @@ status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) } Error: - ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string()); + ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp index 250c0dd9a9..79b6cea292 100644 --- a/libs/input/KeyLayoutMap.cpp +++ b/libs/input/KeyLayoutMap.cpp @@ -161,7 +161,7 @@ base::Result> KeyLayoutMap::load(Tokenizer* tokeni #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), + tokenizer->getFilename().c_str(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (!status) { @@ -289,8 +289,8 @@ KeyLayoutMap::Parser::~Parser() { status_t KeyLayoutMap::Parser::parse() { while (!mTokenizer->isEof()) { - ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGD_IF(DEBUG_PARSER, "Parsing %s: '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); mTokenizer->skipDelimiters(WHITESPACE); @@ -317,16 +317,15 @@ status_t KeyLayoutMap::Parser::parse() { status_t status = parseRequiredKernelConfig(); if (status) return status; } else { - ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); + ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().c_str(), + keywordToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { ALOGE("%s: Expected end of line or trailing comment, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + mTokenizer->getLocation().c_str(), mTokenizer->peekRemainderOfLine().c_str()); return BAD_VALUE; } } @@ -346,26 +345,26 @@ status_t KeyLayoutMap::Parser::parseKey() { } char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); + int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } std::unordered_map& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; if (map.find(code) != map.end()) { - ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.string()); + int32_t keyCode = InputEventLookup::getKeyCodeByLabel(keyCodeToken.c_str()); if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); + ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().c_str(), + keyCodeToken.c_str()); return BAD_VALUE; } @@ -375,15 +374,15 @@ status_t KeyLayoutMap::Parser::parseKey() { if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break; String8 flagToken = mTokenizer->nextToken(WHITESPACE); - uint32_t flag = InputEventLookup::getKeyFlagByLabel(flagToken.string()); + uint32_t flag = InputEventLookup::getKeyFlagByLabel(flagToken.c_str()); if (!flag) { - ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(), - flagToken.string()); + ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().c_str(), + flagToken.c_str()); return BAD_VALUE; } if (flags & flag) { - ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(), - flagToken.string()); + ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().c_str(), + flagToken.c_str()); return BAD_VALUE; } flags |= flag; @@ -402,15 +401,15 @@ status_t KeyLayoutMap::Parser::parseKey() { status_t KeyLayoutMap::Parser::parseAxis() { String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); char* end; - int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); + int32_t scanCode = int32_t(strtol(scanCodeToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(), - scanCodeToken.string()); + ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().c_str(), + scanCodeToken.c_str()); return BAD_VALUE; } if (mMap->mAxes.find(scanCode) != mMap->mAxes.end()) { - ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(), - scanCodeToken.string()); + ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().c_str(), + scanCodeToken.c_str()); return BAD_VALUE; } @@ -423,10 +422,10 @@ status_t KeyLayoutMap::Parser::parseAxis() { mTokenizer->skipDelimiters(WHITESPACE); String8 axisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.axis = InputEventLookup::getAxisByLabel(axisToken.string()); + axisInfo.axis = InputEventLookup::getAxisByLabel(axisToken.c_str()); if (axisInfo.axis < 0) { - ALOGE("%s: Expected inverted axis label, got '%s'.", - mTokenizer->getLocation().string(), axisToken.string()); + ALOGE("%s: Expected inverted axis label, got '%s'.", mTokenizer->getLocation().c_str(), + axisToken.c_str()); return BAD_VALUE; } } else if (token == "split") { @@ -434,35 +433,35 @@ status_t KeyLayoutMap::Parser::parseAxis() { mTokenizer->skipDelimiters(WHITESPACE); String8 splitToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0)); + axisInfo.splitValue = int32_t(strtol(splitToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected split value, got '%s'.", - mTokenizer->getLocation().string(), splitToken.string()); + ALOGE("%s: Expected split value, got '%s'.", mTokenizer->getLocation().c_str(), + splitToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.axis = InputEventLookup::getAxisByLabel(lowAxisToken.string()); + axisInfo.axis = InputEventLookup::getAxisByLabel(lowAxisToken.c_str()); if (axisInfo.axis < 0) { - ALOGE("%s: Expected low axis label, got '%s'.", - mTokenizer->getLocation().string(), lowAxisToken.string()); + ALOGE("%s: Expected low axis label, got '%s'.", mTokenizer->getLocation().c_str(), + lowAxisToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 highAxisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.highAxis = InputEventLookup::getAxisByLabel(highAxisToken.string()); + axisInfo.highAxis = InputEventLookup::getAxisByLabel(highAxisToken.c_str()); if (axisInfo.highAxis < 0) { - ALOGE("%s: Expected high axis label, got '%s'.", - mTokenizer->getLocation().string(), highAxisToken.string()); + ALOGE("%s: Expected high axis label, got '%s'.", mTokenizer->getLocation().c_str(), + highAxisToken.c_str()); return BAD_VALUE; } } else { - axisInfo.axis = InputEventLookup::getAxisByLabel(token.string()); + axisInfo.axis = InputEventLookup::getAxisByLabel(token.c_str()); if (axisInfo.axis < 0) { ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.", - mTokenizer->getLocation().string(), token.string()); + mTokenizer->getLocation().c_str(), token.c_str()); return BAD_VALUE; } } @@ -476,15 +475,15 @@ status_t KeyLayoutMap::Parser::parseAxis() { if (keywordToken == "flat") { mTokenizer->skipDelimiters(WHITESPACE); String8 flatToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0)); + axisInfo.flatOverride = int32_t(strtol(flatToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected flat value, got '%s'.", - mTokenizer->getLocation().string(), flatToken.string()); + ALOGE("%s: Expected flat value, got '%s'.", mTokenizer->getLocation().c_str(), + flatToken.c_str()); return BAD_VALUE; } } else { - ALOGE("%s: Expected keyword 'flat', got '%s'.", - mTokenizer->getLocation().string(), keywordToken.string()); + ALOGE("%s: Expected keyword 'flat', got '%s'.", mTokenizer->getLocation().c_str(), + keywordToken.c_str()); return BAD_VALUE; } } @@ -507,27 +506,27 @@ status_t KeyLayoutMap::Parser::parseLed() { codeToken = mTokenizer->nextToken(WHITESPACE); } char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); + int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } std::unordered_map& map = mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode; if (map.find(code) != map.end()) { - ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); + ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().c_str(), + mapUsage ? "usage" : "scan code", codeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t ledCode = InputEventLookup::getLedByLabel(ledCodeToken.string()); + int32_t ledCode = InputEventLookup::getLedByLabel(ledCodeToken.c_str()); if (ledCode < 0) { - ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(), - ledCodeToken.string()); + ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().c_str(), + ledCodeToken.c_str()); return BAD_VALUE; } @@ -549,7 +548,7 @@ static std::optional getSensorType(const char* token) { } static std::optional getSensorDataIndex(String8 token) { - std::string tokenStr(token.string()); + std::string tokenStr(token.c_str()); if (tokenStr == "X") { return 0; } else if (tokenStr == "Y") { @@ -575,26 +574,26 @@ static std::optional getSensorDataIndex(String8 token) { status_t KeyLayoutMap::Parser::parseSensor() { String8 codeToken = mTokenizer->nextToken(WHITESPACE); char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); + int32_t code = int32_t(strtol(codeToken.c_str(), &end, 0)); if (*end) { - ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().string(), - "abs code", codeToken.string()); + ALOGE("%s: Expected sensor %s number, got '%s'.", mTokenizer->getLocation().c_str(), + "abs code", codeToken.c_str()); return BAD_VALUE; } std::unordered_map& map = mMap->mSensorsByAbsCode; if (map.find(code) != map.end()) { - ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().string(), - "abs code", codeToken.string()); + ALOGE("%s: Duplicate entry for sensor %s '%s'.", mTokenizer->getLocation().c_str(), + "abs code", codeToken.c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 sensorTypeToken = mTokenizer->nextToken(WHITESPACE); - std::optional typeOpt = getSensorType(sensorTypeToken.string()); + std::optional typeOpt = getSensorType(sensorTypeToken.c_str()); if (!typeOpt) { - ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().string(), - sensorTypeToken.string()); + ALOGE("%s: Expected sensor code label, got '%s'.", mTokenizer->getLocation().c_str(), + sensorTypeToken.c_str()); return BAD_VALUE; } InputDeviceSensorType sensorType = typeOpt.value(); @@ -602,8 +601,8 @@ status_t KeyLayoutMap::Parser::parseSensor() { String8 sensorDataIndexToken = mTokenizer->nextToken(WHITESPACE); std::optional indexOpt = getSensorDataIndex(sensorDataIndexToken); if (!indexOpt) { - ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().string(), - sensorDataIndexToken.string()); + ALOGE("%s: Expected sensor data index label, got '%s'.", mTokenizer->getLocation().c_str(), + sensorDataIndexToken.c_str()); return BAD_VALUE; } int32_t sensorDataIndex = indexOpt.value(); @@ -624,12 +623,12 @@ status_t KeyLayoutMap::Parser::parseSensor() { // requires_kernel_config CONFIG_HID_PLAYSTATION status_t KeyLayoutMap::Parser::parseRequiredKernelConfig() { String8 codeToken = mTokenizer->nextToken(WHITESPACE); - std::string configName = codeToken.string(); + std::string configName = codeToken.c_str(); const auto result = mMap->mRequiredKernelConfigs.emplace(configName); if (!result.second) { ALOGE("%s: Duplicate entry for required kernel config %s.", - mTokenizer->getLocation().string(), configName.c_str()); + mTokenizer->getLocation().c_str(), configName.c_str()); return BAD_VALUE; } diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp index c3f5151fd1..5f06efaf50 100644 --- a/libs/input/Keyboard.cpp +++ b/libs/input/Keyboard.cpp @@ -55,8 +55,8 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier, status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " - "it was not found.", - deviceIdentifier.name.c_str(), keyLayoutName.string()); + "it was not found.", + deviceIdentifier.name.c_str(), keyLayoutName.c_str()); } } @@ -66,8 +66,8 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier, status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard character " - "map '%s' but it was not found.", - deviceIdentifier.name.c_str(), keyCharacterMapName.string()); + "map '%s' but it was not found.", + deviceIdentifier.name.c_str(), keyCharacterMapName.c_str()); } } diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp index a842166761..fc020cae4a 100644 --- a/libs/input/PropertyMap.cpp +++ b/libs/input/PropertyMap.cpp @@ -74,10 +74,10 @@ bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const { } char* end; - int value = strtol(stringValue.string(), &end, 10); + int value = strtol(stringValue.c_str(), &end, 10); if (*end != '\0') { - ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.string(), - stringValue.string()); + ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.c_str(), + stringValue.c_str()); return false; } outValue = value; @@ -91,10 +91,10 @@ bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { } char* end; - float value = strtof(stringValue.string(), &end); + float value = strtof(stringValue.c_str(), &end); if (*end != '\0') { - ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.string(), - stringValue.string()); + ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.c_str(), + stringValue.c_str()); return false; } outValue = value; @@ -127,7 +127,7 @@ android::base::Result> PropertyMap::load(const char #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed property file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), + tokenizer->getFilename().c_str(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (status) { @@ -147,8 +147,8 @@ PropertyMap::Parser::~Parser() {} status_t PropertyMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); #endif mTokenizer->skipDelimiters(WHITESPACE); @@ -156,7 +156,7 @@ status_t PropertyMap::Parser::parse() { if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); if (keyToken.isEmpty()) { - ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string()); + ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -164,7 +164,7 @@ status_t PropertyMap::Parser::parse() { if (mTokenizer->nextChar() != '=') { ALOGE("%s: Expected '=' between property key and value.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -173,20 +173,20 @@ status_t PropertyMap::Parser::parse() { String8 valueToken = mTokenizer->nextToken(WHITESPACE); if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) { ALOGE("%s: Found reserved character '\\' or '\"' in property value.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol()) { - ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); return BAD_VALUE; } if (mMap->hasProperty(keyToken)) { ALOGE("%s: Duplicate property value for key '%s'.", - mTokenizer->getLocation().string(), keyToken.string()); + mTokenizer->getLocation().c_str(), keyToken.c_str()); return BAD_VALUE; } diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp index 865366bcb2..de62c870ff 100644 --- a/libs/input/VirtualKeyMap.cpp +++ b/libs/input/VirtualKeyMap.cpp @@ -79,8 +79,8 @@ VirtualKeyMap::Parser::~Parser() { status_t VirtualKeyMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); #endif mTokenizer->skipDelimiters(WHITESPACE); @@ -91,7 +91,7 @@ status_t VirtualKeyMap::Parser::parse() { String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); if (token != "0x01") { ALOGE("%s: Unknown virtual key type, expected 0x01.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -103,7 +103,7 @@ status_t VirtualKeyMap::Parser::parse() { && parseNextIntField(&defn.height); if (!success) { ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.", - mTokenizer->getLocation().string()); + mTokenizer->getLocation().c_str()); return BAD_VALUE; } @@ -116,9 +116,8 @@ status_t VirtualKeyMap::Parser::parse() { } while (consumeFieldDelimiterAndSkipWhitespace()); if (!mTokenizer->isEol()) { - ALOGE("%s: Expected end of line, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); + ALOGE("%s: Expected end of line, got '%s'.", mTokenizer->getLocation().c_str(), + mTokenizer->peekRemainderOfLine().c_str()); return BAD_VALUE; } } @@ -146,9 +145,9 @@ bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) { String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); char* end; - *outValue = strtol(token.string(), &end, 0); + *outValue = strtol(token.c_str(), &end, 0); if (token.isEmpty() || *end != '\0') { - ALOGE("Expected an integer, got '%s'.", token.string()); + ALOGE("Expected an integer, got '%s'.", token.c_str()); return false; } return true; diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp index 2ebdbcfcc4..94c839f761 100644 --- a/services/inputflinger/host/InputDriver.cpp +++ b/services/inputflinger/host/InputDriver.cpp @@ -259,14 +259,14 @@ input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, const char* InputDriver::inputGetPropertyKey(input_property_t* property) { if (property != nullptr) { - return property->key.string(); + return property->key.c_str(); } return nullptr; } const char* InputDriver::inputGetPropertyValue(input_property_t* property) { if (property != nullptr) { - return property->value.string(); + return property->value.c_str(); } return nullptr; } @@ -284,7 +284,7 @@ void InputDriver::inputFreeDevicePropertyMap(input_property_map_t* map) { } void InputDriver::dump(String8& result) { - result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string()); + result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.c_str()); } } // namespace android diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp index 2da2a70c03..d974c43d78 100644 --- a/services/inputflinger/host/InputFlinger.cpp +++ b/services/inputflinger/host/InputFlinger.cpp @@ -57,7 +57,7 @@ status_t InputFlinger::dump(int fd, const Vector& args) { } else { dumpInternal(result); } - write(fd, result.string(), result.size()); + write(fd, result.c_str(), result.size()); return OK; } diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index f4f3ae95a1..09b20fd8e1 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -251,7 +251,7 @@ void CursorInputMapper::configureParameters() { if (cursorModeString == "navigation") { mParameters.mode = Parameters::Mode::NAVIGATION; } else if (cursorModeString != "pointer" && cursorModeString != "default") { - ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); + ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.c_str()); } } diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index ed3b0eccf0..bc1add59d7 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -429,7 +429,7 @@ void TouchInputMapper::configureParameters() { } else if (gestureModeString == "multi-touch") { mParameters.gestureMode = Parameters::GestureMode::MULTI_TOUCH; } else if (gestureModeString != "default") { - ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string()); + ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.c_str()); } } @@ -463,7 +463,7 @@ void TouchInputMapper::configureParameters() { } else if (deviceTypeString == "pointer") { mParameters.deviceType = Parameters::DeviceType::POINTER; } else if (deviceTypeString != "default") { - ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); + ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.c_str()); } } @@ -484,7 +484,7 @@ void TouchInputMapper::configureParameters() { } else if (orientationString == "ORIENTATION_270") { mParameters.orientation = Parameters::Orientation::ORIENTATION_270; } else if (orientationString != "ORIENTATION_0") { - ALOGW("Invalid value for touch.orientation: '%s'", orientationString.string()); + ALOGW("Invalid value for touch.orientation: '%s'", orientationString.c_str()); } } @@ -1204,7 +1204,7 @@ void TouchInputMapper::parseCalibration() { } else if (sizeCalibrationString == "area") { out.sizeCalibration = Calibration::SizeCalibration::AREA; } else if (sizeCalibrationString != "default") { - ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.string()); + ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.c_str()); } } @@ -1224,7 +1224,7 @@ void TouchInputMapper::parseCalibration() { out.pressureCalibration = Calibration::PressureCalibration::AMPLITUDE; } else if (pressureCalibrationString != "default") { ALOGW("Invalid value for touch.pressure.calibration: '%s'", - pressureCalibrationString.string()); + pressureCalibrationString.c_str()); } } @@ -1242,7 +1242,7 @@ void TouchInputMapper::parseCalibration() { out.orientationCalibration = Calibration::OrientationCalibration::VECTOR; } else if (orientationCalibrationString != "default") { ALOGW("Invalid value for touch.orientation.calibration: '%s'", - orientationCalibrationString.string()); + orientationCalibrationString.c_str()); } } @@ -1256,7 +1256,7 @@ void TouchInputMapper::parseCalibration() { out.distanceCalibration = Calibration::DistanceCalibration::SCALED; } else if (distanceCalibrationString != "default") { ALOGW("Invalid value for touch.distance.calibration: '%s'", - distanceCalibrationString.string()); + distanceCalibrationString.c_str()); } } @@ -1271,7 +1271,7 @@ void TouchInputMapper::parseCalibration() { out.coverageCalibration = Calibration::CoverageCalibration::BOX; } else if (coverageCalibrationString != "default") { ALOGW("Invalid value for touch.coverage.calibration: '%s'", - coverageCalibrationString.string()); + coverageCalibrationString.c_str()); } } } diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 03fbf07b16..ad6cf01340 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -2784,7 +2784,7 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe String8 propertyValue; ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue)) << "Device should have read configuration during configuration phase."; - ASSERT_STREQ("value", propertyValue.string()); + ASSERT_STREQ("value", propertyValue.c_str()); ASSERT_NO_FATAL_FAILURE(mapper1.assertConfigureWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2.assertConfigureWasCalled()); diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp index 523f890ce7..d0a9da1ff5 100644 --- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp +++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp @@ -113,7 +113,7 @@ status_t VirtualTouchpadService::dump( static_cast(client_pid_)); touchpad_->dumpInternal(result); } - write(fd, result.string(), result.size()); + write(fd, result.c_str(), result.size()); return OK; } -- GitLab From 66b82f93d88ff360d40fcf6f3e366208529cb367 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 16 Aug 2023 14:42:06 -0700 Subject: [PATCH 0474/1187] Access mInputDevices with a lock Before this CL, 'mInputDevices' was GUARDED_BY mLock, but for some reason, those thread safety annotations weren't working. This only got noticed after I added a debug print to the body of the function 'getInputDevices'. This appears to be a bug with thread safety annotations. Still, the fix here is correct and needed. Bug: 296235458 Test: atest inputflinger_tests Change-Id: I0ae8cc7791e2042e47719ecd5a8ca00b4147be87 --- services/inputflinger/tests/FakeInputReaderPolicy.cpp | 7 ++++--- services/inputflinger/tests/FakeInputReaderPolicy.h | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp index 78420c0d67..41c98ef9e9 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp +++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp @@ -158,7 +158,8 @@ const InputReaderConfiguration& FakeInputReaderPolicy::getReaderConfiguration() return mConfig; } -const std::vector& FakeInputReaderPolicy::getInputDevices() const { +const std::vector FakeInputReaderPolicy::getInputDevices() const { + std::scoped_lock lock(mLock); return mInputDevices; } @@ -228,7 +229,7 @@ std::shared_ptr FakeInputReaderPolicy::obtainPointer void FakeInputReaderPolicy::notifyInputDevicesChanged( const std::vector& inputDevices) { - std::scoped_lock lock(mLock); + std::scoped_lock lock(mLock); mInputDevices = inputDevices; mInputDevicesChanged = true; mDevicesChangedCondition.notify_all(); @@ -256,7 +257,7 @@ void FakeInputReaderPolicy::waitForInputDevices(std::function proces } void FakeInputReaderPolicy::notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) { - std::scoped_lock lock(mLock); + std::scoped_lock lock(mLock); mStylusGestureNotified = deviceId; } diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h index e03d28d0ac..48912a6a28 100644 --- a/services/inputflinger/tests/FakeInputReaderPolicy.h +++ b/services/inputflinger/tests/FakeInputReaderPolicy.h @@ -64,7 +64,7 @@ public: void removeDisabledDevice(int32_t deviceId); void setPointerController(std::shared_ptr controller); const InputReaderConfiguration& getReaderConfiguration() const; - const std::vector& getInputDevices() const; + const std::vector getInputDevices() const; TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor, ui::Rotation surfaceRotation); void setTouchAffineTransformation(const TouchAffineTransformation t); @@ -91,7 +91,7 @@ private: void waitForInputDevices(std::function processDevicesChanged); void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) override; - std::mutex mLock; + mutable std::mutex mLock; std::condition_variable mDevicesChangedCondition; InputReaderConfiguration mConfig; -- GitLab From 23a98bf1478eb6b1509416a4734bcf38112255aa Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 15 Aug 2023 17:28:49 -0700 Subject: [PATCH 0475/1187] Accumulate NotifyArgs inside the lock before notifying Currently, mQueuedListener is used both with and without a lock inside InputReader. This is problematic because things like 'vibrate' could modify the collection inside QueuedInputListener while it's accessing it. This causes a crash. To avoid this, explicitly accumulate the events inside a lock, and then notify all args when the lock is released, but from a swapped variable. Bug: 293260512 Test: atest inputflinger_tests Change-Id: Ib9891b22e6c2632395ddfcec6af3aefe3151b4c4 --- services/inputflinger/reader/InputReader.cpp | 45 +++++++++---------- .../inputflinger/reader/include/InputReader.h | 11 +++-- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 08600b2db5..7f63355387 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -77,7 +77,7 @@ InputReader::InputReader(std::shared_ptr eventHub, : mContext(this), mEventHub(eventHub), mPolicy(policy), - mQueuedListener(listener), + mNextListener(listener), mGlobalMetaState(AMETA_NONE), mLedMetaState(AMETA_NONE), mGeneration(1), @@ -140,7 +140,7 @@ void InputReader::loopOnce() { mReaderIsAliveCondition.notify_all(); if (!events.empty()) { - notifyArgs += processEventsLocked(events.data(), events.size()); + mPendingArgs += processEventsLocked(events.data(), events.size()); } if (mNextTimeout != LLONG_MAX) { @@ -150,16 +150,18 @@ void InputReader::loopOnce() { ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); } mNextTimeout = LLONG_MAX; - notifyArgs += timeoutExpiredLocked(now); + mPendingArgs += timeoutExpiredLocked(now); } } if (oldGeneration != mGeneration) { inputDevicesChanged = true; inputDevices = getInputDevicesLocked(); - notifyArgs.emplace_back( + mPendingArgs.emplace_back( NotifyInputDevicesChangedArgs{mContext.getNextId(), inputDevices}); } + + std::swap(notifyArgs, mPendingArgs); } // release lock // Send out a message that the describes the changed input devices. @@ -175,8 +177,6 @@ void InputReader::loopOnce() { } } - notifyAll(std::move(notifyArgs)); - // Flush queued events out to the listener. // This must happen outside of the lock because the listener could potentially call // back into the InputReader's methods, such as getScanCodeState, or become blocked @@ -184,7 +184,9 @@ void InputReader::loopOnce() { // resulting in a deadlock. This situation is actually quite plausible because the // listener is actually the input dispatcher, which calls into the window manager, // which occasionally calls into the input reader. - mQueuedListener.flush(); + for (const NotifyArgs& args : notifyArgs) { + mNextListener.notify(args); + } } std::list InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { @@ -236,8 +238,8 @@ void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) { InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId); std::shared_ptr device = createDeviceLocked(eventHubId, identifier); - notifyAll(device->configure(when, mConfig, /*changes=*/{})); - notifyAll(device->reset(when)); + mPendingArgs += device->configure(when, mConfig, /*changes=*/{}); + mPendingArgs += device->reset(when); if (device->isIgnored()) { ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s' " @@ -310,12 +312,10 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t eventHubId) { notifyExternalStylusPresenceChangedLocked(); } - std::list resetEvents; if (device->hasEventHubDevices()) { - resetEvents += device->configure(when, mConfig, /*changes=*/{}); + mPendingArgs += device->configure(when, mConfig, /*changes=*/{}); } - resetEvents += device->reset(when); - notifyAll(std::move(resetEvents)); + mPendingArgs += device->reset(when); } std::shared_ptr InputReader::createDeviceLocked( @@ -387,7 +387,7 @@ void InputReader::handleConfigurationChangedLocked(nsecs_t when) { updateGlobalMetaStateLocked(); // Enqueue configuration changed. - mQueuedListener.notifyConfigurationChanged({mContext.getNextId(), when}); + mPendingArgs.emplace_back(NotifyConfigurationChangedArgs{mContext.getNextId(), when}); } void InputReader::refreshConfigurationLocked(ConfigurationChanges changes) { @@ -409,7 +409,7 @@ void InputReader::refreshConfigurationLocked(ConfigurationChanges changes) { } else { for (auto& devicePair : mDevices) { std::shared_ptr& device = devicePair.second; - notifyAll(device->configure(now, mConfig, changes)); + mPendingArgs += device->configure(now, mConfig, changes); } } @@ -419,18 +419,13 @@ void InputReader::refreshConfigurationLocked(ConfigurationChanges changes) { "There was no change in the pointer capture state."); } else { mCurrentPointerCaptureRequest = mConfig.pointerCaptureRequest; - mQueuedListener.notifyPointerCaptureChanged( - {mContext.getNextId(), now, mCurrentPointerCaptureRequest}); + mPendingArgs.emplace_back( + NotifyPointerCaptureChangedArgs{mContext.getNextId(), now, + mCurrentPointerCaptureRequest}); } } } -void InputReader::notifyAll(std::list&& argsList) { - for (const NotifyArgs& args : argsList) { - mQueuedListener.notify(args); - } -} - void InputReader::updateGlobalMetaStateLocked() { mGlobalMetaState = 0; @@ -690,7 +685,7 @@ void InputReader::vibrate(int32_t deviceId, const VibrationSequence& sequence, s InputDevice* device = findInputDeviceLocked(deviceId); if (device) { - notifyAll(device->vibrate(sequence, repeat, token)); + mPendingArgs += device->vibrate(sequence, repeat, token); } } @@ -699,7 +694,7 @@ void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { InputDevice* device = findInputDeviceLocked(deviceId); if (device) { - notifyAll(device->cancelVibrate(token)); + mPendingArgs += device->cancelVibrate(token); } } diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index 01ec7c1303..e21715eb27 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -174,7 +174,14 @@ private: // in parallel to passing it to the InputReader. std::shared_ptr mEventHub; sp mPolicy; - QueuedInputListener mQueuedListener; + + // The next stage that should receive the events generated inside InputReader. + InputListenerInterface& mNextListener; + // As various events are generated inside InputReader, they are stored inside this list. The + // list can only be accessed with the lock, so the events inside it are well-ordered. + // Once the reader is done working, these events will be swapped into a temporary storage and + // sent to the 'mNextListener' without holding the lock. + std::list mPendingArgs GUARDED_BY(mLock); InputReaderConfiguration mConfig GUARDED_BY(mLock); @@ -242,8 +249,6 @@ private: ConfigurationChanges mConfigurationChangesToRefresh GUARDED_BY(mLock); void refreshConfigurationLocked(ConfigurationChanges changes) REQUIRES(mLock); - void notifyAll(std::list&& argsList); - PointerCaptureRequest mCurrentPointerCaptureRequest GUARDED_BY(mLock); // state queries -- GitLab From c09ec6d46f9612a9c1e0c013638858205e7fed0b Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Mon, 14 Aug 2023 22:31:43 +0000 Subject: [PATCH 0476/1187] Add test to ensure values outside the abs axis range are accepted Although it is not explicitly mentioned in the evdev protocol docs, it may make sense to send values outside of the min and max range for absolute axes in some cases. For example, a positional axis value outside its range may indicate a touch point outside the min and max range that maps to the touchscreen's display. For the pressure axis, having a max may not make sense, as there is no theoretical maximum for pressure, outside of what the sensor can detect. We add a test to ensure that we accept these values that are outside of their range reported in input_abs_info. Bug: 295125932 Test: atest inputflinger_tests Change-Id: Ifa88bec96dea92a44be82d2c761bd30f5c5d5123 --- .../inputflinger/tests/InputReader_test.cpp | 32 +++++++++++++++++++ services/inputflinger/tests/UinputDevice.cpp | 8 +++++ services/inputflinger/tests/UinputDevice.h | 1 + 3 files changed, 41 insertions(+) diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 1b1987095e..72fe2af033 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1829,6 +1829,38 @@ TEST_P(TouchIntegrationTest, InputEvent_ProcessPalm) { ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); } +/** + * Some drivers historically have reported axis values outside of the range specified in the + * evdev axis info. Ensure we don't crash when this happens. For example, a driver may report a + * pressure value greater than the reported maximum, since it unclear what specific meaning the + * maximum value for pressure has (beyond the maximum value that can be produced by a sensor), + * and no units for pressure (resolution) is specified by the evdev documentation. + */ +TEST_P(TouchIntegrationTest, AcceptsAxisValuesOutsideReportedRange) { + const Point centerPoint = mDevice->getCenterPoint(); + + // Down with pressure outside the reported range + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendTrackingId(FIRST_TRACKING_ID); + mDevice->sendDown(centerPoint); + mDevice->sendPressure(UinputTouchScreen::RAW_PRESSURE_MAX + 2); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + WithMotionAction(AMOTION_EVENT_ACTION_DOWN))); + + // Move to a point outside the reported range + mDevice->sendMove(Point(DISPLAY_WIDTH, DISPLAY_HEIGHT) + Point(1, 1)); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( + WithMotionAction(AMOTION_EVENT_ACTION_MOVE))); + + // Up + mDevice->sendUp(); + mDevice->sendSync(); + ASSERT_NO_FATAL_FAILURE( + mTestListener->assertNotifyMotionWasCalled(WithMotionAction(AMOTION_EVENT_ACTION_UP))); +} + TEST_P(TouchIntegrationTest, NotifiesPolicyWhenStylusGestureStarted) { const Point centerPoint = mDevice->getCenterPoint(); diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp index 7ceaccf0f3..19f7bb4409 100644 --- a/services/inputflinger/tests/UinputDevice.cpp +++ b/services/inputflinger/tests/UinputDevice.cpp @@ -177,6 +177,7 @@ void UinputTouchScreen::configureDevice(int fd, uinput_user_dev* device) { ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y); ioctl(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID); ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOOL_TYPE); + ioctl(fd, UI_SET_ABSBIT, ABS_MT_PRESSURE); ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT); if (!mPhysicalPort.empty()) { ioctl(fd, UI_SET_PHYS, mPhysicalPort.c_str()); @@ -194,6 +195,8 @@ void UinputTouchScreen::configureDevice(int fd, uinput_user_dev* device) { device->absmax[ABS_MT_TRACKING_ID] = RAW_ID_MAX; device->absmin[ABS_MT_TOOL_TYPE] = MT_TOOL_FINGER; device->absmax[ABS_MT_TOOL_TYPE] = MT_TOOL_MAX; + device->absmin[ABS_MT_PRESSURE] = RAW_PRESSURE_MIN; + device->absmax[ABS_MT_PRESSURE] = RAW_PRESSURE_MAX; } void UinputTouchScreen::sendSlot(int32_t slot) { @@ -206,6 +209,7 @@ void UinputTouchScreen::sendTrackingId(int32_t trackingId) { void UinputTouchScreen::sendDown(const Point& point) { injectEvent(EV_KEY, BTN_TOUCH, 1); + injectEvent(EV_ABS, ABS_MT_PRESSURE, RAW_PRESSURE_MAX); injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x); injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y); } @@ -215,6 +219,10 @@ void UinputTouchScreen::sendMove(const Point& point) { injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y); } +void UinputTouchScreen::sendPressure(int32_t pressure) { + injectEvent(EV_ABS, ABS_MT_PRESSURE, pressure); +} + void UinputTouchScreen::sendPointerUp() { sendTrackingId(0xffffffff); } diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h index 5b07465fda..e7010c32a5 100644 --- a/services/inputflinger/tests/UinputDevice.h +++ b/services/inputflinger/tests/UinputDevice.h @@ -189,6 +189,7 @@ public: void sendTrackingId(int32_t trackingId); void sendDown(const Point& point); void sendMove(const Point& point); + void sendPressure(int32_t pressure); void sendPointerUp(); void sendUp(); void sendToolType(int32_t toolType); -- GitLab From e2b61c6265d4cda693daeb1313d0aaab48874452 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 15 Aug 2023 19:04:54 +0000 Subject: [PATCH 0477/1187] Delete GLESRenderEngine GLESRenderEngine was replaced by SkiaRenderEngine in Android 12. To avoid bitrotting an unsupported RenderEngine backend, let's just delete it. There is still some cleanup for texture creation and deletion which are no-ops in RenderEngine, but those changes are slightly less trivial so they will be done in a followup. Bug: 199918329 Test: builds Change-Id: I1ec4bd6520cd2e8dad1c30f8acef9f004f190806 --- libs/renderengine/Android.bp | 26 +- libs/renderengine/Description.cpp | 61 - libs/renderengine/ExternalTexture.cpp | 8 - libs/renderengine/Mesh.cpp | 146 -- libs/renderengine/RenderEngine.cpp | 10 - libs/renderengine/Texture.cpp | 77 - .../benchmark/RenderEngineBench.cpp | 4 - libs/renderengine/gl/GLESRenderEngine.cpp | 1853 ----------------- libs/renderengine/gl/GLESRenderEngine.h | 308 --- libs/renderengine/gl/GLFramebuffer.cpp | 115 - libs/renderengine/gl/GLFramebuffer.h | 68 - libs/renderengine/gl/GLImage.cpp | 83 - libs/renderengine/gl/GLImage.h | 54 - libs/renderengine/gl/GLShadowTexture.cpp | 52 - libs/renderengine/gl/GLShadowTexture.h | 44 - .../gl/GLShadowVertexGenerator.cpp | 98 - .../renderengine/gl/GLShadowVertexGenerator.h | 65 - libs/renderengine/gl/GLSkiaShadowPort.cpp | 656 ------ libs/renderengine/gl/GLSkiaShadowPort.h | 96 - libs/renderengine/gl/GLVertexBuffer.cpp | 55 - libs/renderengine/gl/GLVertexBuffer.h | 49 - libs/renderengine/gl/ImageManager.cpp | 148 -- libs/renderengine/gl/ImageManager.h | 74 - libs/renderengine/gl/Program.cpp | 175 -- libs/renderengine/gl/Program.h | 120 -- libs/renderengine/gl/ProgramCache.cpp | 802 ------- libs/renderengine/gl/ProgramCache.h | 233 --- libs/renderengine/gl/filters/BlurFilter.cpp | 268 --- libs/renderengine/gl/filters/BlurFilter.h | 95 - .../gl/filters/GenericProgram.cpp | 122 -- libs/renderengine/gl/filters/GenericProgram.h | 51 - .../include/renderengine/Framebuffer.h | 35 - .../renderengine/include/renderengine/Image.h | 31 - libs/renderengine/include/renderengine/Mesh.h | 205 -- .../include/renderengine/RenderEngine.h | 8 +- .../include/renderengine/Texture.h | 60 - .../include/renderengine/mock/Framebuffer.h | 36 - .../include/renderengine/mock/Image.h | 36 - .../include/renderengine/mock/RenderEngine.h | 2 - .../renderengine/private/Description.h | 92 - libs/renderengine/mock/Framebuffer.cpp | 30 - libs/renderengine/mock/Image.cpp | 30 - .../{gl => skia}/GLExtensions.cpp | 6 +- libs/renderengine/{gl => skia}/GLExtensions.h | 4 +- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 29 +- libs/renderengine/skia/SkiaRenderEngine.h | 1 - .../tests/RenderEngineThreadedTest.cpp | 14 +- .../threaded/RenderEngineThreaded.cpp | 48 +- .../threaded/RenderEngineThreaded.h | 1 - services/surfaceflinger/Layer.h | 2 - services/surfaceflinger/SurfaceFlinger.cpp | 12 +- .../tests/unittests/CompositionTest.cpp | 2 - 52 files changed, 32 insertions(+), 6668 deletions(-) delete mode 100644 libs/renderengine/Description.cpp delete mode 100644 libs/renderengine/Mesh.cpp delete mode 100644 libs/renderengine/Texture.cpp delete mode 100644 libs/renderengine/gl/GLESRenderEngine.cpp delete mode 100644 libs/renderengine/gl/GLESRenderEngine.h delete mode 100644 libs/renderengine/gl/GLFramebuffer.cpp delete mode 100644 libs/renderengine/gl/GLFramebuffer.h delete mode 100644 libs/renderengine/gl/GLImage.cpp delete mode 100644 libs/renderengine/gl/GLImage.h delete mode 100644 libs/renderengine/gl/GLShadowTexture.cpp delete mode 100644 libs/renderengine/gl/GLShadowTexture.h delete mode 100644 libs/renderengine/gl/GLShadowVertexGenerator.cpp delete mode 100644 libs/renderengine/gl/GLShadowVertexGenerator.h delete mode 100644 libs/renderengine/gl/GLSkiaShadowPort.cpp delete mode 100644 libs/renderengine/gl/GLSkiaShadowPort.h delete mode 100644 libs/renderengine/gl/GLVertexBuffer.cpp delete mode 100644 libs/renderengine/gl/GLVertexBuffer.h delete mode 100644 libs/renderengine/gl/ImageManager.cpp delete mode 100644 libs/renderengine/gl/ImageManager.h delete mode 100644 libs/renderengine/gl/Program.cpp delete mode 100644 libs/renderengine/gl/Program.h delete mode 100644 libs/renderengine/gl/ProgramCache.cpp delete mode 100644 libs/renderengine/gl/ProgramCache.h delete mode 100644 libs/renderengine/gl/filters/BlurFilter.cpp delete mode 100644 libs/renderengine/gl/filters/BlurFilter.h delete mode 100644 libs/renderengine/gl/filters/GenericProgram.cpp delete mode 100644 libs/renderengine/gl/filters/GenericProgram.h delete mode 100644 libs/renderengine/include/renderengine/Framebuffer.h delete mode 100644 libs/renderengine/include/renderengine/Image.h delete mode 100644 libs/renderengine/include/renderengine/Mesh.h delete mode 100644 libs/renderengine/include/renderengine/Texture.h delete mode 100644 libs/renderengine/include/renderengine/mock/Framebuffer.h delete mode 100644 libs/renderengine/include/renderengine/mock/Image.h delete mode 100644 libs/renderengine/include/renderengine/private/Description.h delete mode 100644 libs/renderengine/mock/Framebuffer.cpp delete mode 100644 libs/renderengine/mock/Image.cpp rename libs/renderengine/{gl => skia}/GLExtensions.cpp (97%) rename libs/renderengine/{gl => skia}/GLExtensions.h (98%) diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 8d19c45527..ba2eb7d224 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -56,30 +56,8 @@ cc_defaults { filegroup { name: "librenderengine_sources", srcs: [ - "Description.cpp", "ExternalTexture.cpp", - "Mesh.cpp", "RenderEngine.cpp", - "Texture.cpp", - ], -} - -filegroup { - name: "librenderengine_gl_sources", - srcs: [ - "gl/GLESRenderEngine.cpp", - "gl/GLExtensions.cpp", - "gl/GLFramebuffer.cpp", - "gl/GLImage.cpp", - "gl/GLShadowTexture.cpp", - "gl/GLShadowVertexGenerator.cpp", - "gl/GLSkiaShadowPort.cpp", - "gl/GLVertexBuffer.cpp", - "gl/ImageManager.cpp", - "gl/Program.cpp", - "gl/ProgramCache.cpp", - "gl/filters/BlurFilter.cpp", - "gl/filters/GenericProgram.cpp", ], } @@ -96,6 +74,7 @@ filegroup { "skia/AutoBackendTexture.cpp", "skia/Cache.cpp", "skia/ColorSpaces.cpp", + "skia/GLExtensions.cpp", "skia/SkiaRenderEngine.cpp", "skia/SkiaGLRenderEngine.cpp", "skia/SkiaVkRenderEngine.cpp", @@ -136,7 +115,6 @@ cc_library_static { ], srcs: [ ":librenderengine_sources", - ":librenderengine_gl_sources", ":librenderengine_threaded_sources", ":librenderengine_skia_sources", ], @@ -155,8 +133,6 @@ cc_library_static { name: "librenderengine_mocks", defaults: ["librenderengine_defaults"], srcs: [ - "mock/Framebuffer.cpp", - "mock/Image.cpp", "mock/RenderEngine.cpp", ], static_libs: [ diff --git a/libs/renderengine/Description.cpp b/libs/renderengine/Description.cpp deleted file mode 100644 index 245c9e1e30..0000000000 --- a/libs/renderengine/Description.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013 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 - -#include - -#include - -namespace android { -namespace renderengine { - -Description::TransferFunction Description::dataSpaceToTransferFunction(ui::Dataspace dataSpace) { - ui::Dataspace transfer = static_cast(dataSpace & ui::Dataspace::TRANSFER_MASK); - switch (transfer) { - case ui::Dataspace::TRANSFER_ST2084: - return Description::TransferFunction::ST2084; - case ui::Dataspace::TRANSFER_HLG: - return Description::TransferFunction::HLG; - case ui::Dataspace::TRANSFER_LINEAR: - return Description::TransferFunction::LINEAR; - default: - return Description::TransferFunction::SRGB; - } -} - -bool Description::hasInputTransformMatrix() const { - const mat4 identity; - return inputTransformMatrix != identity; -} - -bool Description::hasOutputTransformMatrix() const { - const mat4 identity; - return outputTransformMatrix != identity; -} - -bool Description::hasColorMatrix() const { - const mat4 identity; - return colorMatrix != identity; -} - -bool Description::hasDisplayColorMatrix() const { - const mat4 identity; - return displayColorMatrix != identity; -} - -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/ExternalTexture.cpp b/libs/renderengine/ExternalTexture.cpp index 9eb42cd8e1..6f2a96a87b 100644 --- a/libs/renderengine/ExternalTexture.cpp +++ b/libs/renderengine/ExternalTexture.cpp @@ -27,14 +27,6 @@ ExternalTexture::ExternalTexture(const sp& buffer, : mBuffer(buffer), mRenderEngine(renderEngine), mWritable(usage & WRITEABLE) { LOG_ALWAYS_FATAL_IF(buffer == nullptr, "Attempted to bind a null buffer to an external texture!"); - // GLESRenderEngine has a separate texture cache for output buffers, - if (usage == WRITEABLE && - (mRenderEngine.getRenderEngineType() == - renderengine::RenderEngine::RenderEngineType::GLES || - mRenderEngine.getRenderEngineType() == - renderengine::RenderEngine::RenderEngineType::THREADED)) { - return; - } mRenderEngine.mapExternalTextureBuffer(mBuffer, mWritable); } diff --git a/libs/renderengine/Mesh.cpp b/libs/renderengine/Mesh.cpp deleted file mode 100644 index ed2f45fdf5..0000000000 --- a/libs/renderengine/Mesh.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2013 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 - -#include - -namespace android { -namespace renderengine { - -Mesh::Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize, - size_t cropCoordsSize, size_t shadowColorSize, size_t shadowParamsSize, - size_t indexCount) - : mVertexCount(vertexCount), - mVertexSize(vertexSize), - mTexCoordsSize(texCoordSize), - mCropCoordsSize(cropCoordsSize), - mShadowColorSize(shadowColorSize), - mShadowParamsSize(shadowParamsSize), - mPrimitive(primitive), - mIndexCount(indexCount) { - if (vertexCount == 0) { - mVertices.resize(1); - mVertices[0] = 0.0f; - mStride = 0; - return; - } - size_t stride = vertexSize + texCoordSize + cropCoordsSize + shadowColorSize + shadowParamsSize; - size_t remainder = (stride * vertexCount) / vertexCount; - // Since all of the input parameters are unsigned, if stride is less than - // either vertexSize or texCoordSize, it must have overflowed. remainder - // will be equal to stride as long as stride * vertexCount doesn't overflow. - if ((stride < vertexSize) || (remainder != stride)) { - ALOGE("Overflow in Mesh(..., %zu, %zu, %zu, %zu, %zu, %zu)", vertexCount, vertexSize, - texCoordSize, cropCoordsSize, shadowColorSize, shadowParamsSize); - mVertices.resize(1); - mVertices[0] = 0.0f; - mVertexCount = 0; - mVertexSize = 0; - mTexCoordsSize = 0; - mCropCoordsSize = 0; - mShadowColorSize = 0; - mShadowParamsSize = 0; - mStride = 0; - return; - } - - mVertices.resize(stride * vertexCount); - mStride = stride; - mIndices.resize(indexCount); -} - -Mesh::Primitive Mesh::getPrimitive() const { - return mPrimitive; -} - -float const* Mesh::getPositions() const { - return mVertices.data(); -} -float* Mesh::getPositions() { - return mVertices.data(); -} - -float const* Mesh::getTexCoords() const { - return mVertices.data() + mVertexSize; -} -float* Mesh::getTexCoords() { - return mVertices.data() + mVertexSize; -} - -float const* Mesh::getCropCoords() const { - return mVertices.data() + mVertexSize + mTexCoordsSize; -} -float* Mesh::getCropCoords() { - return mVertices.data() + mVertexSize + mTexCoordsSize; -} - -float const* Mesh::getShadowColor() const { - return mVertices.data() + mVertexSize + mTexCoordsSize + mCropCoordsSize; -} -float* Mesh::getShadowColor() { - return mVertices.data() + mVertexSize + mTexCoordsSize + mCropCoordsSize; -} - -float const* Mesh::getShadowParams() const { - return mVertices.data() + mVertexSize + mTexCoordsSize + mCropCoordsSize + mShadowColorSize; -} -float* Mesh::getShadowParams() { - return mVertices.data() + mVertexSize + mTexCoordsSize + mCropCoordsSize + mShadowColorSize; -} - -uint16_t const* Mesh::getIndices() const { - return mIndices.data(); -} - -uint16_t* Mesh::getIndices() { - return mIndices.data(); -} - -size_t Mesh::getVertexCount() const { - return mVertexCount; -} - -size_t Mesh::getVertexSize() const { - return mVertexSize; -} - -size_t Mesh::getTexCoordsSize() const { - return mTexCoordsSize; -} - -size_t Mesh::getShadowColorSize() const { - return mShadowColorSize; -} - -size_t Mesh::getShadowParamsSize() const { - return mShadowParamsSize; -} - -size_t Mesh::getByteStride() const { - return mStride * sizeof(float); -} - -size_t Mesh::getStride() const { - return mStride; -} - -size_t Mesh::getIndexCount() const { - return mIndexCount; -} - -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index d08c2213ad..a8e92c6807 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -18,7 +18,6 @@ #include #include -#include "gl/GLESRenderEngine.h" #include "renderengine/ExternalTexture.h" #include "threaded/RenderEngineThreaded.h" @@ -30,11 +29,6 @@ namespace renderengine { std::unique_ptr RenderEngine::create(const RenderEngineCreationArgs& args) { switch (args.renderEngineType) { - case RenderEngineType::THREADED: - ALOGD("Threaded RenderEngine with GLES Backend"); - return renderengine::threaded::RenderEngineThreaded::create( - [args]() { return android::renderengine::gl::GLESRenderEngine::create(args); }, - args.renderEngineType); case RenderEngineType::SKIA_GL: ALOGD("RenderEngine with SkiaGL Backend"); return renderengine::skia::SkiaGLRenderEngine::create(args); @@ -56,10 +50,6 @@ std::unique_ptr RenderEngine::create(const RenderEngineCreationArg return android::renderengine::skia::SkiaVkRenderEngine::create(args); }, args.renderEngineType); - case RenderEngineType::GLES: - default: - ALOGD("RenderEngine with GLES Backend"); - return renderengine::gl::GLESRenderEngine::create(args); } } diff --git a/libs/renderengine/Texture.cpp b/libs/renderengine/Texture.cpp deleted file mode 100644 index 154cde80b9..0000000000 --- a/libs/renderengine/Texture.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2013 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 - -namespace android { -namespace renderengine { - -Texture::Texture() - : mTextureName(0), mTextureTarget(TEXTURE_2D), mWidth(0), mHeight(0), mFiltering(false) {} - -Texture::Texture(Target textureTarget, uint32_t textureName) - : mTextureName(textureName), - mTextureTarget(textureTarget), - mWidth(0), - mHeight(0), - mFiltering(false) {} - -void Texture::init(Target textureTarget, uint32_t textureName) { - mTextureName = textureName; - mTextureTarget = textureTarget; -} - -Texture::~Texture() {} - -void Texture::setMatrix(float const* matrix) { - mTextureMatrix = mat4(matrix); -} - -void Texture::setFiltering(bool enabled) { - mFiltering = enabled; -} - -void Texture::setDimensions(size_t width, size_t height) { - mWidth = width; - mHeight = height; -} - -uint32_t Texture::getTextureName() const { - return mTextureName; -} - -uint32_t Texture::getTextureTarget() const { - return mTextureTarget; -} - -const mat4& Texture::getMatrix() const { - return mTextureMatrix; -} - -bool Texture::getFiltering() const { - return mFiltering; -} - -size_t Texture::getWidth() const { - return mWidth; -} - -size_t Texture::getHeight() const { - return mHeight; -} - -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/benchmark/RenderEngineBench.cpp b/libs/renderengine/benchmark/RenderEngineBench.cpp index 791d4c94b4..ce2c7d7b6b 100644 --- a/libs/renderengine/benchmark/RenderEngineBench.cpp +++ b/libs/renderengine/benchmark/RenderEngineBench.cpp @@ -43,10 +43,6 @@ std::string RenderEngineTypeName(RenderEngine::RenderEngineType type) { return "skiavk"; case RenderEngine::RenderEngineType::SKIA_VK_THREADED: return "skiavkthreaded"; - case RenderEngine::RenderEngineType::GLES: - case RenderEngine::RenderEngineType::THREADED: - LOG_ALWAYS_FATAL("GLESRenderEngine is deprecated - why time it?"); - return "unused"; } } diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp deleted file mode 100644 index a512b9aca1..0000000000 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ /dev/null @@ -1,1853 +0,0 @@ -/* - * Copyright 2013 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_NDEBUG 0 -#include "EGL/egl.h" -#undef LOG_TAG -#define LOG_TAG "RenderEngine" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "GLESRenderEngine.h" -#include "GLExtensions.h" -#include "GLFramebuffer.h" -#include "GLImage.h" -#include "GLShadowVertexGenerator.h" -#include "Program.h" -#include "ProgramCache.h" -#include "filters/BlurFilter.h" - -bool checkGlError(const char* op, int lineNumber) { - bool errorFound = false; - GLint error = glGetError(); - while (error != GL_NO_ERROR) { - errorFound = true; - error = glGetError(); - ALOGV("after %s() (line # %d) glError (0x%x)\n", op, lineNumber, error); - } - return errorFound; -} - -static constexpr bool outputDebugPPMs = false; - -void writePPM(const char* basename, GLuint width, GLuint height) { - ALOGV("writePPM #%s: %d x %d", basename, width, height); - - std::vector pixels(width * height * 4); - std::vector outBuffer(width * height * 3); - - // TODO(courtneygo): We can now have float formats, need - // to remove this code or update to support. - // Make returned pixels fit in uint32_t, one byte per component - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data()); - if (checkGlError(__FUNCTION__, __LINE__)) { - return; - } - - std::string filename(basename); - filename.append(".ppm"); - std::ofstream file(filename.c_str(), std::ios::binary); - if (!file.is_open()) { - ALOGE("Unable to open file: %s", filename.c_str()); - ALOGE("You may need to do: \"adb shell setenforce 0\" to enable " - "surfaceflinger to write debug images"); - return; - } - - file << "P6\n"; - file << width << "\n"; - file << height << "\n"; - file << 255 << "\n"; - - auto ptr = reinterpret_cast(pixels.data()); - auto outPtr = reinterpret_cast(outBuffer.data()); - for (int y = height - 1; y >= 0; y--) { - char* data = ptr + y * width * sizeof(uint32_t); - - for (GLuint x = 0; x < width; x++) { - // Only copy R, G and B components - outPtr[0] = data[0]; - outPtr[1] = data[1]; - outPtr[2] = data[2]; - data += sizeof(uint32_t); - outPtr += 3; - } - } - file.write(reinterpret_cast(outBuffer.data()), outBuffer.size()); -} - -namespace android { -namespace renderengine { -namespace gl { - -class BindNativeBufferAsFramebuffer { -public: - BindNativeBufferAsFramebuffer(GLESRenderEngine& engine, ANativeWindowBuffer* buffer, - const bool useFramebufferCache) - : mEngine(engine), mFramebuffer(mEngine.getFramebufferForDrawing()), mStatus(NO_ERROR) { - mStatus = mFramebuffer->setNativeWindowBuffer(buffer, mEngine.isProtected(), - useFramebufferCache) - ? mEngine.bindFrameBuffer(mFramebuffer) - : NO_MEMORY; - } - ~BindNativeBufferAsFramebuffer() { - mFramebuffer->setNativeWindowBuffer(nullptr, false, /*arbitrary*/ true); - mEngine.unbindFrameBuffer(mFramebuffer); - } - status_t getStatus() const { return mStatus; } - -private: - GLESRenderEngine& mEngine; - Framebuffer* mFramebuffer; - status_t mStatus; -}; - -using base::StringAppendF; -using ui::Dataspace; - -static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute, - EGLint wanted, EGLConfig* outConfig) { - EGLint numConfigs = -1, n = 0; - eglGetConfigs(dpy, nullptr, 0, &numConfigs); - std::vector configs(numConfigs, EGL_NO_CONFIG_KHR); - eglChooseConfig(dpy, attrs, configs.data(), configs.size(), &n); - configs.resize(n); - - if (!configs.empty()) { - if (attribute != EGL_NONE) { - for (EGLConfig config : configs) { - EGLint value = 0; - eglGetConfigAttrib(dpy, config, attribute, &value); - if (wanted == value) { - *outConfig = config; - return NO_ERROR; - } - } - } else { - // just pick the first one - *outConfig = configs[0]; - return NO_ERROR; - } - } - - return NAME_NOT_FOUND; -} - -static status_t selectEGLConfig(EGLDisplay display, EGLint format, EGLint renderableType, - EGLConfig* config) { - // select our EGLConfig. It must support EGL_RECORDABLE_ANDROID if - // it is to be used with WIFI displays - status_t err; - EGLint wantedAttribute; - EGLint wantedAttributeValue; - - std::vector attribs; - if (renderableType) { - const ui::PixelFormat pixelFormat = static_cast(format); - const bool is1010102 = pixelFormat == ui::PixelFormat::RGBA_1010102; - - // Default to 8 bits per channel. - const EGLint tmpAttribs[] = { - EGL_RENDERABLE_TYPE, - renderableType, - EGL_RECORDABLE_ANDROID, - EGL_TRUE, - EGL_SURFACE_TYPE, - EGL_WINDOW_BIT | EGL_PBUFFER_BIT, - EGL_FRAMEBUFFER_TARGET_ANDROID, - EGL_TRUE, - EGL_RED_SIZE, - is1010102 ? 10 : 8, - EGL_GREEN_SIZE, - is1010102 ? 10 : 8, - EGL_BLUE_SIZE, - is1010102 ? 10 : 8, - EGL_ALPHA_SIZE, - is1010102 ? 2 : 8, - EGL_NONE, - }; - std::copy(tmpAttribs, tmpAttribs + (sizeof(tmpAttribs) / sizeof(EGLint)), - std::back_inserter(attribs)); - wantedAttribute = EGL_NONE; - wantedAttributeValue = EGL_NONE; - } else { - // if no renderable type specified, fallback to a simplified query - wantedAttribute = EGL_NATIVE_VISUAL_ID; - wantedAttributeValue = format; - } - - err = selectConfigForAttribute(display, attribs.data(), wantedAttribute, wantedAttributeValue, - config); - if (err == NO_ERROR) { - EGLint caveat; - if (eglGetConfigAttrib(display, *config, EGL_CONFIG_CAVEAT, &caveat)) - ALOGW_IF(caveat == EGL_SLOW_CONFIG, "EGL_SLOW_CONFIG selected!"); - } - - return err; -} - -std::optional GLESRenderEngine::createContextPriority( - const RenderEngineCreationArgs& args) { - if (!GLExtensions::getInstance().hasContextPriority()) { - return std::nullopt; - } - - switch (args.contextPriority) { - case RenderEngine::ContextPriority::REALTIME: - if (gl::GLExtensions::getInstance().hasRealtimePriority()) { - return RenderEngine::ContextPriority::REALTIME; - } else { - ALOGI("Realtime priority unsupported, degrading gracefully to high priority"); - return RenderEngine::ContextPriority::HIGH; - } - case RenderEngine::ContextPriority::HIGH: - case RenderEngine::ContextPriority::MEDIUM: - case RenderEngine::ContextPriority::LOW: - return args.contextPriority; - default: - return std::nullopt; - } -} - -std::unique_ptr GLESRenderEngine::create(const RenderEngineCreationArgs& args) { - // initialize EGL for the default display - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (!eglInitialize(display, nullptr, nullptr)) { - LOG_ALWAYS_FATAL("failed to initialize EGL. EGL error=0x%x", eglGetError()); - } - - const auto eglVersion = eglQueryString(display, EGL_VERSION); - if (!eglVersion) { - checkGlError(__FUNCTION__, __LINE__); - LOG_ALWAYS_FATAL("eglQueryString(EGL_VERSION) failed"); - } - - // Use the Android impl to grab EGL_NV_context_priority_realtime - const auto eglExtensions = eglQueryString(display, EGL_EXTENSIONS); - if (!eglExtensions) { - checkGlError(__FUNCTION__, __LINE__); - LOG_ALWAYS_FATAL("eglQueryString(EGL_EXTENSIONS) failed"); - } - - GLExtensions& extensions = GLExtensions::getInstance(); - extensions.initWithEGLStrings(eglVersion, eglExtensions); - - // The code assumes that ES2 or later is available if this extension is - // supported. - EGLConfig config = EGL_NO_CONFIG; - if (!extensions.hasNoConfigContext()) { - config = chooseEglConfig(display, args.pixelFormat, /*logConfig*/ true); - } - - const std::optional priority = createContextPriority(args); - EGLContext protectedContext = EGL_NO_CONTEXT; - if (args.enableProtectedContext && extensions.hasProtectedContent()) { - protectedContext = - createEglContext(display, config, nullptr, priority, Protection::PROTECTED); - ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context"); - } - - EGLContext ctxt = - createEglContext(display, config, protectedContext, priority, Protection::UNPROTECTED); - - // if can't create a GL context, we can only abort. - LOG_ALWAYS_FATAL_IF(ctxt == EGL_NO_CONTEXT, "EGLContext creation failed"); - - EGLSurface stub = EGL_NO_SURFACE; - if (!extensions.hasSurfacelessContext()) { - stub = createStubEglPbufferSurface(display, config, args.pixelFormat, - Protection::UNPROTECTED); - LOG_ALWAYS_FATAL_IF(stub == EGL_NO_SURFACE, "can't create stub pbuffer"); - } - EGLBoolean success = eglMakeCurrent(display, stub, stub, ctxt); - LOG_ALWAYS_FATAL_IF(!success, "can't make stub pbuffer current"); - extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER), - glGetString(GL_VERSION), glGetString(GL_EXTENSIONS)); - - EGLSurface protectedStub = EGL_NO_SURFACE; - if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) { - protectedStub = createStubEglPbufferSurface(display, config, args.pixelFormat, - Protection::PROTECTED); - ALOGE_IF(protectedStub == EGL_NO_SURFACE, "can't create protected stub pbuffer"); - } - - // now figure out what version of GL did we actually get - GlesVersion version = parseGlesVersion(extensions.getVersion()); - - LOG_ALWAYS_FATAL_IF(args.supportsBackgroundBlur && version < GLES_VERSION_3_0, - "Blurs require OpenGL ES 3.0. Please unset ro.surface_flinger.supports_background_blur"); - - // initialize the renderer while GL is current - std::unique_ptr engine; - switch (version) { - case GLES_VERSION_1_0: - case GLES_VERSION_1_1: - LOG_ALWAYS_FATAL("SurfaceFlinger requires OpenGL ES 2.0 minimum to run."); - break; - case GLES_VERSION_2_0: - case GLES_VERSION_3_0: - engine = std::make_unique(args, display, config, ctxt, stub, - protectedContext, protectedStub); - break; - } - - ALOGI("OpenGL ES informations:"); - ALOGI("vendor : %s", extensions.getVendor()); - ALOGI("renderer : %s", extensions.getRenderer()); - ALOGI("version : %s", extensions.getVersion()); - ALOGI("extensions: %s", extensions.getExtensions()); - ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize()); - ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims()); - return engine; -} - -EGLConfig GLESRenderEngine::chooseEglConfig(EGLDisplay display, int format, bool logConfig) { - status_t err; - EGLConfig config; - - // First try to get an ES3 config - err = selectEGLConfig(display, format, EGL_OPENGL_ES3_BIT, &config); - if (err != NO_ERROR) { - // If ES3 fails, try to get an ES2 config - err = selectEGLConfig(display, format, EGL_OPENGL_ES2_BIT, &config); - if (err != NO_ERROR) { - // If ES2 still doesn't work, probably because we're on the emulator. - // try a simplified query - ALOGW("no suitable EGLConfig found, trying a simpler query"); - err = selectEGLConfig(display, format, 0, &config); - if (err != NO_ERROR) { - // this EGL is too lame for android - LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up"); - } - } - } - - if (logConfig) { - // print some debugging info - EGLint r, g, b, a; - eglGetConfigAttrib(display, config, EGL_RED_SIZE, &r); - eglGetConfigAttrib(display, config, EGL_GREEN_SIZE, &g); - eglGetConfigAttrib(display, config, EGL_BLUE_SIZE, &b); - eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE, &a); - ALOGI("EGL information:"); - ALOGI("vendor : %s", eglQueryString(display, EGL_VENDOR)); - ALOGI("version : %s", eglQueryString(display, EGL_VERSION)); - ALOGI("extensions: %s", eglQueryString(display, EGL_EXTENSIONS)); - ALOGI("Client API: %s", eglQueryString(display, EGL_CLIENT_APIS) ?: "Not Supported"); - ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, config); - } - - return config; -} - -GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, - EGLConfig config, EGLContext ctxt, EGLSurface stub, - EGLContext protectedContext, EGLSurface protectedStub) - : RenderEngine(args.renderEngineType), - mEGLDisplay(display), - mEGLConfig(config), - mEGLContext(ctxt), - mStubSurface(stub), - mProtectedEGLContext(protectedContext), - mProtectedStubSurface(protectedStub), - mVpWidth(0), - mVpHeight(0), - mFramebufferImageCacheSize(args.imageCacheSize), - mPrecacheToneMapperShaderOnly(args.precacheToneMapperShaderOnly) { - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); - glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glPixelStorei(GL_PACK_ALIGNMENT, 4); - - // Initialize protected EGL Context. - if (mProtectedEGLContext != EGL_NO_CONTEXT) { - EGLBoolean success = eglMakeCurrent(display, mProtectedStubSurface, mProtectedStubSurface, - mProtectedEGLContext); - ALOGE_IF(!success, "can't make protected context current"); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glPixelStorei(GL_PACK_ALIGNMENT, 4); - success = eglMakeCurrent(display, mStubSurface, mStubSurface, mEGLContext); - LOG_ALWAYS_FATAL_IF(!success, "can't make default context current"); - } - - // mColorBlindnessCorrection = M; - - const ColorSpace srgb(ColorSpace::sRGB()); - const ColorSpace displayP3(ColorSpace::DisplayP3()); - const ColorSpace bt2020(ColorSpace::BT2020()); - - // no chromatic adaptation needed since all color spaces use D65 for their white points. - mSrgbToXyz = mat4(srgb.getRGBtoXYZ()); - mDisplayP3ToXyz = mat4(displayP3.getRGBtoXYZ()); - mBt2020ToXyz = mat4(bt2020.getRGBtoXYZ()); - mXyzToSrgb = mat4(srgb.getXYZtoRGB()); - mXyzToDisplayP3 = mat4(displayP3.getXYZtoRGB()); - mXyzToBt2020 = mat4(bt2020.getXYZtoRGB()); - - // Compute sRGB to Display P3 and BT2020 transform matrix. - // NOTE: For now, we are limiting output wide color space support to - // Display-P3 and BT2020 only. - mSrgbToDisplayP3 = mXyzToDisplayP3 * mSrgbToXyz; - mSrgbToBt2020 = mXyzToBt2020 * mSrgbToXyz; - - // Compute Display P3 to sRGB and BT2020 transform matrix. - mDisplayP3ToSrgb = mXyzToSrgb * mDisplayP3ToXyz; - mDisplayP3ToBt2020 = mXyzToBt2020 * mDisplayP3ToXyz; - - // Compute BT2020 to sRGB and Display P3 transform matrix - mBt2020ToSrgb = mXyzToSrgb * mBt2020ToXyz; - mBt2020ToDisplayP3 = mXyzToDisplayP3 * mBt2020ToXyz; - - char value[PROPERTY_VALUE_MAX]; - property_get("debug.egl.traceGpuCompletion", value, "0"); - if (atoi(value)) { - mTraceGpuCompletion = true; - mFlushTracer = std::make_unique(this); - } - - if (args.supportsBackgroundBlur) { - mBlurFilter = new BlurFilter(*this); - checkErrors("BlurFilter creation"); - } - - mImageManager = std::make_unique(this); - mImageManager->initThread(); - mDrawingBuffer = createFramebuffer(); - sp buf = - sp::make(1, 1, PIXEL_FORMAT_RGBA_8888, 1, - GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE, - "placeholder"); - - const status_t err = buf->initCheck(); - if (err != OK) { - ALOGE("Error allocating placeholder buffer: %d", err); - return; - } - mPlaceholderBuffer = buf.get(); - EGLint attributes[] = { - EGL_NONE, - }; - mPlaceholderImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, - mPlaceholderBuffer, attributes); - ALOGE_IF(mPlaceholderImage == EGL_NO_IMAGE_KHR, "Failed to create placeholder image: %#x", - eglGetError()); - - mShadowTexture = std::make_unique(); -} - -GLESRenderEngine::~GLESRenderEngine() { - // Destroy the image manager first. - mImageManager = nullptr; - mShadowTexture = nullptr; - cleanFramebufferCache(); - ProgramCache::getInstance().purgeCaches(); - std::lock_guard lock(mRenderingMutex); - glDisableVertexAttribArray(Program::position); - unbindFrameBuffer(mDrawingBuffer.get()); - mDrawingBuffer = nullptr; - eglDestroyImageKHR(mEGLDisplay, mPlaceholderImage); - mImageCache.clear(); - if (mStubSurface != EGL_NO_SURFACE) { - eglDestroySurface(mEGLDisplay, mStubSurface); - } - if (mProtectedStubSurface != EGL_NO_SURFACE) { - eglDestroySurface(mEGLDisplay, mProtectedStubSurface); - } - if (mEGLContext != EGL_NO_CONTEXT) { - eglDestroyContext(mEGLDisplay, mEGLContext); - } - if (mProtectedEGLContext != EGL_NO_CONTEXT) { - eglDestroyContext(mEGLDisplay, mProtectedEGLContext); - } - eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglTerminate(mEGLDisplay); - eglReleaseThread(); -} - -std::unique_ptr GLESRenderEngine::createFramebuffer() { - return std::make_unique(*this); -} - -std::unique_ptr GLESRenderEngine::createImage() { - return std::make_unique(*this); -} - -Framebuffer* GLESRenderEngine::getFramebufferForDrawing() { - return mDrawingBuffer.get(); -} - -std::future GLESRenderEngine::primeCache() { - ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext, - mPrecacheToneMapperShaderOnly); - return {}; -} - -base::unique_fd GLESRenderEngine::flush() { - ATRACE_CALL(); - if (!GLExtensions::getInstance().hasNativeFenceSync()) { - return base::unique_fd(); - } - - EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); - if (sync == EGL_NO_SYNC_KHR) { - ALOGW("failed to create EGL native fence sync: %#x", eglGetError()); - return base::unique_fd(); - } - - // native fence fd will not be populated until flush() is done. - glFlush(); - - // get the fence fd - base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync)); - eglDestroySyncKHR(mEGLDisplay, sync); - if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { - ALOGW("failed to dup EGL native fence sync: %#x", eglGetError()); - } - - // Only trace if we have a valid fence, as current usage falls back to - // calling finish() if the fence fd is invalid. - if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer) && fenceFd.get() >= 0) { - mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr)); - } - - return fenceFd; -} - -bool GLESRenderEngine::finish() { - ATRACE_CALL(); - if (!GLExtensions::getInstance().hasFenceSync()) { - ALOGW("no synchronization support"); - return false; - } - - EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr); - if (sync == EGL_NO_SYNC_KHR) { - ALOGW("failed to create EGL fence sync: %#x", eglGetError()); - return false; - } - - if (CC_UNLIKELY(mTraceGpuCompletion && mFlushTracer)) { - mFlushTracer->queueSync(eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, nullptr)); - } - - return waitSync(sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR); -} - -bool GLESRenderEngine::waitSync(EGLSyncKHR sync, EGLint flags) { - EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, flags, 2000000000 /*2 sec*/); - EGLint error = eglGetError(); - eglDestroySyncKHR(mEGLDisplay, sync); - if (result != EGL_CONDITION_SATISFIED_KHR) { - if (result == EGL_TIMEOUT_EXPIRED_KHR) { - ALOGW("fence wait timed out"); - } else { - ALOGW("error waiting on EGL fence: %#x", error); - } - return false; - } - - return true; -} - -bool GLESRenderEngine::waitFence(base::unique_fd fenceFd) { - if (!GLExtensions::getInstance().hasNativeFenceSync() || - !GLExtensions::getInstance().hasWaitSync()) { - return false; - } - - // release the fd and transfer the ownership to EGLSync - EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd.release(), EGL_NONE}; - EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); - if (sync == EGL_NO_SYNC_KHR) { - ALOGE("failed to create EGL native fence sync: %#x", eglGetError()); - return false; - } - - // XXX: The spec draft is inconsistent as to whether this should return an - // EGLint or void. Ignore the return value for now, as it's not strictly - // needed. - eglWaitSyncKHR(mEGLDisplay, sync, 0); - EGLint error = eglGetError(); - eglDestroySyncKHR(mEGLDisplay, sync); - if (error != EGL_SUCCESS) { - ALOGE("failed to wait for EGL native fence sync: %#x", error); - return false; - } - - return true; -} - -void GLESRenderEngine::clearWithColor(float red, float green, float blue, float alpha) { - ATRACE_CALL(); - glDisable(GL_BLEND); - glClearColor(red, green, blue, alpha); - glClear(GL_COLOR_BUFFER_BIT); -} - -void GLESRenderEngine::fillRegionWithColor(const Region& region, float red, float green, float blue, - float alpha) { - size_t c; - Rect const* r = region.getArray(&c); - Mesh mesh = Mesh::Builder() - .setPrimitive(Mesh::TRIANGLES) - .setVertices(c * 6 /* count */, 2 /* size */) - .build(); - Mesh::VertexArray position(mesh.getPositionArray()); - for (size_t i = 0; i < c; i++, r++) { - position[i * 6 + 0].x = r->left; - position[i * 6 + 0].y = r->top; - position[i * 6 + 1].x = r->left; - position[i * 6 + 1].y = r->bottom; - position[i * 6 + 2].x = r->right; - position[i * 6 + 2].y = r->bottom; - position[i * 6 + 3].x = r->left; - position[i * 6 + 3].y = r->top; - position[i * 6 + 4].x = r->right; - position[i * 6 + 4].y = r->bottom; - position[i * 6 + 5].x = r->right; - position[i * 6 + 5].y = r->top; - } - setupFillWithColor(red, green, blue, alpha); - drawMesh(mesh); -} - -void GLESRenderEngine::setScissor(const Rect& region) { - glScissor(region.left, region.top, region.getWidth(), region.getHeight()); - glEnable(GL_SCISSOR_TEST); -} - -void GLESRenderEngine::disableScissor() { - glDisable(GL_SCISSOR_TEST); -} - -void GLESRenderEngine::genTextures(size_t count, uint32_t* names) { - glGenTextures(count, names); -} - -void GLESRenderEngine::deleteTextures(size_t count, uint32_t const* names) { - for (int i = 0; i < count; ++i) { - mTextureView.erase(names[i]); - } - glDeleteTextures(count, names); -} - -void GLESRenderEngine::bindExternalTextureImage(uint32_t texName, const Image& image) { - ATRACE_CALL(); - const GLImage& glImage = static_cast(image); - const GLenum target = GL_TEXTURE_EXTERNAL_OES; - - glBindTexture(target, texName); - if (glImage.getEGLImage() != EGL_NO_IMAGE_KHR) { - glEGLImageTargetTexture2DOES(target, static_cast(glImage.getEGLImage())); - } -} - -void GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, const sp& buffer, - const sp& bufferFence) { - ATRACE_CALL(); - - bool found = false; - { - std::lock_guard lock(mRenderingMutex); - auto cachedImage = mImageCache.find(buffer->getId()); - found = (cachedImage != mImageCache.end()); - } - - // If we couldn't find the image in the cache at this time, then either - // SurfaceFlinger messed up registering the buffer ahead of time or we got - // backed up creating other EGLImages. - if (!found) { - status_t cacheResult = mImageManager->cache(buffer); - if (cacheResult != NO_ERROR) { - ALOGE("Error with caching buffer: %d", cacheResult); - return; - } - } - - // Whether or not we needed to cache, re-check mImageCache to make sure that - // there's an EGLImage. The current threading model guarantees that we don't - // destroy a cached image until it's really not needed anymore (i.e. this - // function should not be called), so the only possibility is that something - // terrible went wrong and we should just bind something and move on. - { - std::lock_guard lock(mRenderingMutex); - auto cachedImage = mImageCache.find(buffer->getId()); - - if (cachedImage == mImageCache.end()) { - // We failed creating the image if we got here, so bail out. - ALOGE("Failed to create an EGLImage when rendering"); - bindExternalTextureImage(texName, *createImage()); - return; - } - - bindExternalTextureImage(texName, *cachedImage->second); - mTextureView.insert_or_assign(texName, buffer->getId()); - } - - // Wait for the new buffer to be ready. - if (bufferFence != nullptr && bufferFence->isValid()) { - if (GLExtensions::getInstance().hasWaitSync()) { - base::unique_fd fenceFd(bufferFence->dup()); - if (fenceFd == -1) { - ALOGE("error dup'ing fence fd: %d", errno); - return; - } - if (!waitFence(std::move(fenceFd))) { - ALOGE("failed to wait on fence fd"); - return; - } - } else { - status_t err = bufferFence->waitForever("RenderEngine::bindExternalTextureBuffer"); - if (err != NO_ERROR) { - ALOGE("error waiting for fence: %d", err); - return; - } - } - } - - return; -} - -void GLESRenderEngine::mapExternalTextureBuffer(const sp& buffer, - bool /*isRenderable*/) { - ATRACE_CALL(); - mImageManager->cacheAsync(buffer, nullptr); -} - -std::shared_ptr GLESRenderEngine::cacheExternalTextureBufferForTesting( - const sp& buffer) { - auto barrier = std::make_shared(); - mImageManager->cacheAsync(buffer, barrier); - return barrier; -} - -status_t GLESRenderEngine::cacheExternalTextureBufferInternal(const sp& buffer) { - if (buffer == nullptr) { - return BAD_VALUE; - } - - { - std::lock_guard lock(mRenderingMutex); - if (mImageCache.count(buffer->getId()) > 0) { - // If there's already an image then fail fast here. - return NO_ERROR; - } - } - ATRACE_CALL(); - - // Create the image without holding a lock so that we don't block anything. - std::unique_ptr newImage = createImage(); - - bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(), - buffer->getUsage() & GRALLOC_USAGE_PROTECTED); - if (!created) { - ALOGE("Failed to create image. id=%" PRIx64 " size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d", - buffer->getId(), buffer->getWidth(), buffer->getHeight(), buffer->getStride(), - buffer->getUsage(), buffer->getPixelFormat()); - return NO_INIT; - } - - { - std::lock_guard lock(mRenderingMutex); - if (mImageCache.count(buffer->getId()) > 0) { - // In theory it's possible for another thread to recache the image, - // so bail out if another thread won. - return NO_ERROR; - } - mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage))); - } - - return NO_ERROR; -} - -void GLESRenderEngine::unmapExternalTextureBuffer(sp&& buffer) { - mImageManager->releaseAsync(buffer->getId(), nullptr); -} - -std::shared_ptr GLESRenderEngine::unbindExternalTextureBufferForTesting( - uint64_t bufferId) { - auto barrier = std::make_shared(); - mImageManager->releaseAsync(bufferId, barrier); - return barrier; -} - -void GLESRenderEngine::unbindExternalTextureBufferInternal(uint64_t bufferId) { - std::unique_ptr image; - { - std::lock_guard lock(mRenderingMutex); - const auto& cachedImage = mImageCache.find(bufferId); - - if (cachedImage != mImageCache.end()) { - ALOGV("Destroying image for buffer: %" PRIu64, bufferId); - // Move the buffer out of cache first, so that we can destroy - // without holding the cache's lock. - image = std::move(cachedImage->second); - mImageCache.erase(bufferId); - return; - } - } - ALOGV("Failed to find image for buffer: %" PRIu64, bufferId); -} - -int GLESRenderEngine::getContextPriority() { - int value; - eglQueryContext(mEGLDisplay, mEGLContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &value); - return value; -} - -FloatRect GLESRenderEngine::setupLayerCropping(const LayerSettings& layer, Mesh& mesh) { - // Translate win by the rounded corners rect coordinates, to have all values in - // layer coordinate space. - FloatRect cropWin = layer.geometry.boundaries; - const FloatRect& roundedCornersCrop = layer.geometry.roundedCornersCrop; - cropWin.left -= roundedCornersCrop.left; - cropWin.right -= roundedCornersCrop.left; - cropWin.top -= roundedCornersCrop.top; - cropWin.bottom -= roundedCornersCrop.top; - Mesh::VertexArray cropCoords(mesh.getCropCoordArray()); - cropCoords[0] = vec2(cropWin.left, cropWin.top); - cropCoords[1] = vec2(cropWin.left, cropWin.top + cropWin.getHeight()); - cropCoords[2] = vec2(cropWin.right, cropWin.top + cropWin.getHeight()); - cropCoords[3] = vec2(cropWin.right, cropWin.top); - - setupCornerRadiusCropSize(roundedCornersCrop.getWidth(), roundedCornersCrop.getHeight()); - return cropWin; -} - -void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display, - const LayerSettings& layer, const Mesh& mesh) { - // We separate the layer into 3 parts essentially, such that we only turn on blending for the - // top rectangle and the bottom rectangle, and turn off blending for the middle rectangle. - FloatRect bounds = layer.geometry.roundedCornersCrop; - - // Explicitly compute the transform from the clip rectangle to the physical - // display. Normally, this is done in glViewport but we explicitly compute - // it here so that we can get the scissor bounds correct. - const Rect& source = display.clip; - const Rect& destination = display.physicalDisplay; - // Here we compute the following transform: - // 1. Translate the top left corner of the source clip to (0, 0) - // 2. Rotate the clip rectangle about the origin in accordance with the - // orientation flag - // 3. Translate the top left corner back to the origin. - // 4. Scale the clip rectangle to the destination rectangle dimensions - // 5. Translate the top left corner to the destination rectangle's top left - // corner. - const mat4 translateSource = mat4::translate(vec4(-source.left, -source.top, 0, 1)); - mat4 rotation; - int displacementX = 0; - int displacementY = 0; - float destinationWidth = static_cast(destination.getWidth()); - float destinationHeight = static_cast(destination.getHeight()); - float sourceWidth = static_cast(source.getWidth()); - float sourceHeight = static_cast(source.getHeight()); - const float rot90InRadians = 2.0f * static_cast(M_PI) / 4.0f; - switch (display.orientation) { - case ui::Transform::ROT_90: - rotation = mat4::rotate(rot90InRadians, vec3(0, 0, 1)); - displacementX = source.getHeight(); - std::swap(sourceHeight, sourceWidth); - break; - case ui::Transform::ROT_180: - rotation = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)); - displacementY = source.getHeight(); - displacementX = source.getWidth(); - break; - case ui::Transform::ROT_270: - rotation = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)); - displacementY = source.getWidth(); - std::swap(sourceHeight, sourceWidth); - break; - default: - break; - } - - const mat4 intermediateTranslation = mat4::translate(vec4(displacementX, displacementY, 0, 1)); - const mat4 scale = mat4::scale( - vec4(destinationWidth / sourceWidth, destinationHeight / sourceHeight, 1, 1)); - const mat4 translateDestination = - mat4::translate(vec4(destination.left, destination.top, 0, 1)); - const mat4 globalTransform = - translateDestination * scale * intermediateTranslation * rotation * translateSource; - - const mat4 transformMatrix = globalTransform * layer.geometry.positionTransform; - const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0); - const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0); - const vec4 leftTopCoordinateInBuffer = transformMatrix * leftTopCoordinate; - const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate; - bounds = FloatRect(std::min(leftTopCoordinateInBuffer[0], rightBottomCoordinateInBuffer[0]), - std::min(leftTopCoordinateInBuffer[1], rightBottomCoordinateInBuffer[1]), - std::max(leftTopCoordinateInBuffer[0], rightBottomCoordinateInBuffer[0]), - std::max(leftTopCoordinateInBuffer[1], rightBottomCoordinateInBuffer[1])); - - // Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners - // and the middle part without rounded corners. - const int32_t radius = ceil( - (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) / 2.0); - const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius); - setScissor(topRect); - drawMesh(mesh); - const Rect bottomRect(bounds.left, bounds.bottom - radius, bounds.right, bounds.bottom); - setScissor(bottomRect); - drawMesh(mesh); - - // The middle part of the layer can turn off blending. - if (topRect.bottom < bottomRect.top) { - const Rect middleRect(bounds.left, bounds.top + radius, bounds.right, - bounds.bottom - radius); - setScissor(middleRect); - mState.cornerRadius = 0.0; - disableBlending(); - drawMesh(mesh); - } - disableScissor(); -} - -status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) { - ATRACE_CALL(); - GLFramebuffer* glFramebuffer = static_cast(framebuffer); - EGLImageKHR eglImage = glFramebuffer->getEGLImage(); - uint32_t textureName = glFramebuffer->getTextureName(); - uint32_t framebufferName = glFramebuffer->getFramebufferName(); - - // Bind the texture and turn our EGLImage into a texture - glBindTexture(GL_TEXTURE_2D, textureName); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)eglImage); - - // Bind the Framebuffer to render into - glBindFramebuffer(GL_FRAMEBUFFER, framebufferName); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0); - - uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d", - glStatus); - - return glStatus == GL_FRAMEBUFFER_COMPLETE_OES ? NO_ERROR : BAD_VALUE; -} - -void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /*framebuffer*/) { - ATRACE_CALL(); - - // back to main framebuffer - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -bool GLESRenderEngine::canSkipPostRenderCleanup() const { - return mPriorResourcesCleaned || - (mLastDrawFence != nullptr && mLastDrawFence->getStatus() != Fence::Status::Signaled); -} - -void GLESRenderEngine::cleanupPostRender() { - ATRACE_CALL(); - - if (canSkipPostRenderCleanup()) { - // If we don't have a prior frame needing cleanup, then don't do anything. - return; - } - - // Bind the texture to placeholder so that backing image data can be freed. - GLFramebuffer* glFramebuffer = static_cast(getFramebufferForDrawing()); - glFramebuffer->allocateBuffers(1, 1, mPlaceholderDrawBuffer); - - // Release the cached fence here, so that we don't churn reallocations when - // we could no-op repeated calls of this method instead. - mLastDrawFence = nullptr; - mPriorResourcesCleaned = true; -} - -void GLESRenderEngine::cleanFramebufferCache() { - std::lock_guard lock(mFramebufferImageCacheMutex); - // Bind the texture to placeholder so that backing image data can be freed. - GLFramebuffer* glFramebuffer = static_cast(getFramebufferForDrawing()); - glFramebuffer->allocateBuffers(1, 1, mPlaceholderDrawBuffer); - - while (!mFramebufferImageCache.empty()) { - EGLImageKHR expired = mFramebufferImageCache.front().second; - mFramebufferImageCache.pop_front(); - eglDestroyImageKHR(mEGLDisplay, expired); - DEBUG_EGL_IMAGE_TRACKER_DESTROY(); - } -} - -void GLESRenderEngine::checkErrors() const { - checkErrors(nullptr); -} - -void GLESRenderEngine::checkErrors(const char* tag) const { - do { - // there could be more than one error flag - GLenum error = glGetError(); - if (error == GL_NO_ERROR) break; - if (tag == nullptr) { - ALOGE("GL error 0x%04x", int(error)); - } else { - ALOGE("GL error: %s -> 0x%04x", tag, int(error)); - } - } while (true); -} - -bool GLESRenderEngine::supportsProtectedContent() const { - return mProtectedEGLContext != EGL_NO_CONTEXT; -} - -void GLESRenderEngine::useProtectedContext(bool useProtectedContext) { - if (useProtectedContext == mInProtectedContext || - (useProtectedContext && !supportsProtectedContent())) { - return; - } - - const EGLSurface surface = useProtectedContext ? mProtectedStubSurface : mStubSurface; - const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext; - if (eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE) { - mInProtectedContext = useProtectedContext; - } -} -EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, - bool isProtected, - bool useFramebufferCache) { - sp graphicBuffer = GraphicBuffer::from(nativeBuffer); - if (useFramebufferCache) { - std::lock_guard lock(mFramebufferImageCacheMutex); - for (const auto& image : mFramebufferImageCache) { - if (image.first == graphicBuffer->getId()) { - return image.second; - } - } - } - EGLint attributes[] = { - isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, - isProtected ? EGL_TRUE : EGL_NONE, - EGL_NONE, - }; - EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, - nativeBuffer, attributes); - if (useFramebufferCache) { - if (image != EGL_NO_IMAGE_KHR) { - std::lock_guard lock(mFramebufferImageCacheMutex); - if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) { - EGLImageKHR expired = mFramebufferImageCache.front().second; - mFramebufferImageCache.pop_front(); - eglDestroyImageKHR(mEGLDisplay, expired); - DEBUG_EGL_IMAGE_TRACKER_DESTROY(); - } - mFramebufferImageCache.push_back({graphicBuffer->getId(), image}); - } - } - - if (image != EGL_NO_IMAGE_KHR) { - DEBUG_EGL_IMAGE_TRACKER_CREATE(); - } - return image; -} - -void GLESRenderEngine::drawLayersInternal( - const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, const std::vector& layers, - const std::shared_ptr& buffer, const bool useFramebufferCache, - base::unique_fd&& bufferFence) { - ATRACE_CALL(); - if (layers.empty()) { - ALOGV("Drawing empty layer stack"); - resultPromise->set_value(Fence::NO_FENCE); - return; - } - - if (bufferFence.get() >= 0) { - // Duplicate the fence for passing to waitFence. - base::unique_fd bufferFenceDup(dup(bufferFence.get())); - if (bufferFenceDup < 0 || !waitFence(std::move(bufferFenceDup))) { - ATRACE_NAME("Waiting before draw"); - sync_wait(bufferFence.get(), -1); - } - } - - if (buffer == nullptr) { - ALOGE("No output buffer provided. Aborting GPU composition."); - resultPromise->set_value(base::unexpected(BAD_VALUE)); - return; - } - - validateOutputBufferUsage(buffer->getBuffer()); - - std::unique_ptr fbo; - // Gathering layers that requested blur, we'll need them to decide when to render to an - // offscreen buffer, and when to render to the native buffer. - std::deque blurLayers; - if (CC_LIKELY(mBlurFilter != nullptr)) { - for (const auto& layer : layers) { - if (layer.backgroundBlurRadius > 0) { - blurLayers.push_back(layer); - } - } - } - const auto blurLayersSize = blurLayers.size(); - - if (blurLayersSize == 0) { - fbo = std::make_unique(*this, - buffer->getBuffer() - .get() - ->getNativeBuffer(), - useFramebufferCache); - if (fbo->getStatus() != NO_ERROR) { - ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); - checkErrors(); - resultPromise->set_value(base::unexpected(fbo->getStatus())); - return; - } - setViewportAndProjection(display.physicalDisplay, display.clip); - } else { - setViewportAndProjection(display.physicalDisplay, display.clip); - auto status = - mBlurFilter->setAsDrawTarget(display, blurLayers.front().backgroundBlurRadius); - if (status != NO_ERROR) { - ALOGE("Failed to prepare blur filter! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); - checkErrors(); - resultPromise->set_value(base::unexpected(status)); - return; - } - } - - // clear the entire buffer, sometimes when we reuse buffers we'd persist - // ghost images otherwise. - // we also require a full transparent framebuffer for overlays. This is - // probably not quite efficient on all GPUs, since we could filter out - // opaque layers. - clearWithColor(0.0, 0.0, 0.0, 0.0); - - setOutputDataSpace(display.outputDataspace); - setDisplayMaxLuminance(display.maxLuminance); - setDisplayColorTransform(display.colorTransform); - - const mat4 projectionMatrix = - ui::Transform(display.orientation).asMatrix4() * mState.projectionMatrix; - - Mesh mesh = Mesh::Builder() - .setPrimitive(Mesh::TRIANGLE_FAN) - .setVertices(4 /* count */, 2 /* size */) - .setTexCoords(2 /* size */) - .setCropCoords(2 /* size */) - .build(); - for (const auto& layer : layers) { - if (blurLayers.size() > 0 && blurLayers.front() == layer) { - blurLayers.pop_front(); - - auto status = mBlurFilter->prepare(); - if (status != NO_ERROR) { - ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); - checkErrors("Can't render first blur pass"); - resultPromise->set_value(base::unexpected(status)); - return; - } - - if (blurLayers.size() == 0) { - // Done blurring, time to bind the native FBO and render our blur onto it. - fbo = std::make_unique(*this, - buffer.get() - ->getBuffer() - ->getNativeBuffer(), - useFramebufferCache); - status = fbo->getStatus(); - setViewportAndProjection(display.physicalDisplay, display.clip); - } else { - // There's still something else to blur, so let's keep rendering to our FBO - // instead of to the display. - status = mBlurFilter->setAsDrawTarget(display, - blurLayers.front().backgroundBlurRadius); - } - if (status != NO_ERROR) { - ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); - checkErrors("Can't bind native framebuffer"); - resultPromise->set_value(base::unexpected(status)); - return; - } - - status = mBlurFilter->render(blurLayersSize > 1); - if (status != NO_ERROR) { - ALOGE("Failed to render blur effect! Aborting GPU composition for buffer (%p).", - buffer->getBuffer()->handle); - checkErrors("Can't render blur filter"); - resultPromise->set_value(base::unexpected(status)); - return; - } - } - - // Ensure luminance is at least 100 nits to avoid div-by-zero - const float maxLuminance = std::max(100.f, layer.source.buffer.maxLuminanceNits); - mState.maxMasteringLuminance = maxLuminance; - mState.maxContentLuminance = maxLuminance; - mState.projectionMatrix = projectionMatrix * layer.geometry.positionTransform; - - const FloatRect bounds = layer.geometry.boundaries; - Mesh::VertexArray position(mesh.getPositionArray()); - position[0] = vec2(bounds.left, bounds.top); - position[1] = vec2(bounds.left, bounds.bottom); - position[2] = vec2(bounds.right, bounds.bottom); - position[3] = vec2(bounds.right, bounds.top); - - setupLayerCropping(layer, mesh); - setColorTransform(layer.colorTransform); - - bool usePremultipliedAlpha = true; - bool disableTexture = true; - bool isOpaque = false; - if (layer.source.buffer.buffer != nullptr) { - disableTexture = false; - isOpaque = layer.source.buffer.isOpaque; - - sp gBuf = layer.source.buffer.buffer->getBuffer(); - validateInputBufferUsage(gBuf); - bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf, - layer.source.buffer.fence); - - usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha; - Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName); - mat4 texMatrix = layer.source.buffer.textureTransform; - - texture.setMatrix(texMatrix.asArray()); - texture.setFiltering(layer.source.buffer.useTextureFiltering); - - texture.setDimensions(gBuf->getWidth(), gBuf->getHeight()); - - renderengine::Mesh::VertexArray texCoords(mesh.getTexCoordArray()); - texCoords[0] = vec2(0.0, 0.0); - texCoords[1] = vec2(0.0, 1.0); - texCoords[2] = vec2(1.0, 1.0); - texCoords[3] = vec2(1.0, 0.0); - setupLayerTexturing(texture); - - // Do not cache protected EGLImage, protected memory is limited. - if (gBuf->getUsage() & GRALLOC_USAGE_PROTECTED) { - unmapExternalTextureBuffer(std::move(gBuf)); - } - } - - const half3 solidColor = layer.source.solidColor; - const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha); - const float radius = - (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) / - 2.0f; - // Buffer sources will have a black solid color ignored in the shader, - // so in that scenario the solid color passed here is arbitrary. - setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, radius); - if (layer.disableBlending) { - glDisable(GL_BLEND); - } - setSourceDataSpace(layer.sourceDataspace); - - if (layer.shadow.length > 0.0f) { - handleShadow(layer.geometry.boundaries, radius, layer.shadow); - } - // We only want to do a special handling for rounded corners when having rounded corners - // is the only reason it needs to turn on blending, otherwise, we handle it like the - // usual way since it needs to turn on blending anyway. - else if (radius > 0.0 && color.a >= 1.0f && isOpaque) { - handleRoundedCorners(display, layer, mesh); - } else { - drawMesh(mesh); - } - - // Cleanup if there's a buffer source - if (layer.source.buffer.buffer != nullptr) { - disableBlending(); - disableTexturing(); - } - } - - base::unique_fd drawFence = flush(); - - // If flush failed or we don't support native fences, we need to force the - // gl command stream to be executed. - if (drawFence.get() < 0) { - bool success = finish(); - if (!success) { - ALOGE("Failed to flush RenderEngine commands"); - checkErrors(); - // Chances are, something illegal happened (either the caller passed - // us bad parameters, or we messed up our shader generation). - resultPromise->set_value(base::unexpected(INVALID_OPERATION)); - return; - } - mLastDrawFence = nullptr; - } else { - // The caller takes ownership of drawFence, so we need to duplicate the - // fd here. - mLastDrawFence = new Fence(dup(drawFence.get())); - } - mPriorResourcesCleaned = false; - - checkErrors(); - resultPromise->set_value(sp::make(std::move(drawFence))); -} - -void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) { - ATRACE_CALL(); - mVpWidth = viewport.getWidth(); - mVpHeight = viewport.getHeight(); - - // We pass the the top left corner instead of the bottom left corner, - // because since we're rendering off-screen first. - glViewport(viewport.left, viewport.top, mVpWidth, mVpHeight); - - mState.projectionMatrix = mat4::ortho(clip.left, clip.right, clip.top, clip.bottom, 0, 1); -} - -void GLESRenderEngine::setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, - const half4& color, float cornerRadius) { - mState.isPremultipliedAlpha = premultipliedAlpha; - mState.isOpaque = opaque; - mState.color = color; - mState.cornerRadius = cornerRadius; - - if (disableTexture) { - mState.textureEnabled = false; - } - - if (color.a < 1.0f || !opaque || cornerRadius > 0.0f) { - glEnable(GL_BLEND); - glBlendFuncSeparate(premultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, - GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glDisable(GL_BLEND); - } -} - -void GLESRenderEngine::setSourceDataSpace(Dataspace source) { - mDataSpace = source; -} - -void GLESRenderEngine::setOutputDataSpace(Dataspace dataspace) { - mOutputDataSpace = dataspace; -} - -void GLESRenderEngine::setDisplayMaxLuminance(const float maxLuminance) { - mState.displayMaxLuminance = maxLuminance; -} - -void GLESRenderEngine::setupLayerTexturing(const Texture& texture) { - GLuint target = texture.getTextureTarget(); - glBindTexture(target, texture.getTextureName()); - GLenum filter = GL_NEAREST; - if (texture.getFiltering()) { - filter = GL_LINEAR; - } - glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter); - glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter); - - mState.texture = texture; - mState.textureEnabled = true; -} - -void GLESRenderEngine::setColorTransform(const mat4& colorTransform) { - mState.colorMatrix = colorTransform; -} - -void GLESRenderEngine::setDisplayColorTransform(const mat4& colorTransform) { - mState.displayColorMatrix = colorTransform; -} - -void GLESRenderEngine::disableTexturing() { - mState.textureEnabled = false; -} - -void GLESRenderEngine::disableBlending() { - glDisable(GL_BLEND); -} - -void GLESRenderEngine::setupFillWithColor(float r, float g, float b, float a) { - mState.isPremultipliedAlpha = true; - mState.isOpaque = false; - mState.color = half4(r, g, b, a); - mState.textureEnabled = false; - glDisable(GL_BLEND); -} - -void GLESRenderEngine::setupCornerRadiusCropSize(float width, float height) { - mState.cropSize = half2(width, height); -} - -void GLESRenderEngine::drawMesh(const Mesh& mesh) { - ATRACE_CALL(); - if (mesh.getTexCoordsSize()) { - glEnableVertexAttribArray(Program::texCoords); - glVertexAttribPointer(Program::texCoords, mesh.getTexCoordsSize(), GL_FLOAT, GL_FALSE, - mesh.getByteStride(), mesh.getTexCoords()); - } - - glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE, - mesh.getByteStride(), mesh.getPositions()); - - if (mState.cornerRadius > 0.0f) { - glEnableVertexAttribArray(Program::cropCoords); - glVertexAttribPointer(Program::cropCoords, mesh.getVertexSize(), GL_FLOAT, GL_FALSE, - mesh.getByteStride(), mesh.getCropCoords()); - } - - if (mState.drawShadows) { - glEnableVertexAttribArray(Program::shadowColor); - glVertexAttribPointer(Program::shadowColor, mesh.getShadowColorSize(), GL_FLOAT, GL_FALSE, - mesh.getByteStride(), mesh.getShadowColor()); - - glEnableVertexAttribArray(Program::shadowParams); - glVertexAttribPointer(Program::shadowParams, mesh.getShadowParamsSize(), GL_FLOAT, GL_FALSE, - mesh.getByteStride(), mesh.getShadowParams()); - } - - Description managedState = mState; - // By default, DISPLAY_P3 is the only supported wide color output. However, - // when HDR content is present, hardware composer may be able to handle - // BT2020 data space, in that case, the output data space is set to be - // BT2020_HLG or BT2020_PQ respectively. In GPU fall back we need - // to respect this and convert non-HDR content to HDR format. - Dataspace inputStandard = static_cast(mDataSpace & Dataspace::STANDARD_MASK); - Dataspace inputTransfer = static_cast(mDataSpace & Dataspace::TRANSFER_MASK); - Dataspace outputStandard = static_cast(mOutputDataSpace & Dataspace::STANDARD_MASK); - Dataspace outputTransfer = static_cast(mOutputDataSpace & Dataspace::TRANSFER_MASK); - bool needsXYZConversion = needsXYZTransformMatrix(); - - // NOTE: if the input standard of the input dataspace is not STANDARD_DCI_P3 or - // STANDARD_BT2020, it will be treated as STANDARD_BT709 - if (inputStandard != Dataspace::STANDARD_DCI_P3 && - inputStandard != Dataspace::STANDARD_BT2020) { - inputStandard = Dataspace::STANDARD_BT709; - } - - if (needsXYZConversion) { - // The supported input color spaces are standard RGB, Display P3 and BT2020. - switch (inputStandard) { - case Dataspace::STANDARD_DCI_P3: - managedState.inputTransformMatrix = mDisplayP3ToXyz; - break; - case Dataspace::STANDARD_BT2020: - managedState.inputTransformMatrix = mBt2020ToXyz; - break; - default: - managedState.inputTransformMatrix = mSrgbToXyz; - break; - } - - // The supported output color spaces are BT2020, Display P3 and standard RGB. - switch (outputStandard) { - case Dataspace::STANDARD_BT2020: - managedState.outputTransformMatrix = mXyzToBt2020; - break; - case Dataspace::STANDARD_DCI_P3: - managedState.outputTransformMatrix = mXyzToDisplayP3; - break; - default: - managedState.outputTransformMatrix = mXyzToSrgb; - break; - } - } else if (inputStandard != outputStandard) { - // At this point, the input data space and output data space could be both - // HDR data spaces, but they match each other, we do nothing in this case. - // In addition to the case above, the input data space could be - // - scRGB linear - // - scRGB non-linear - // - sRGB - // - Display P3 - // - BT2020 - // The output data spaces could be - // - sRGB - // - Display P3 - // - BT2020 - switch (outputStandard) { - case Dataspace::STANDARD_BT2020: - if (inputStandard == Dataspace::STANDARD_BT709) { - managedState.outputTransformMatrix = mSrgbToBt2020; - } else if (inputStandard == Dataspace::STANDARD_DCI_P3) { - managedState.outputTransformMatrix = mDisplayP3ToBt2020; - } - break; - case Dataspace::STANDARD_DCI_P3: - if (inputStandard == Dataspace::STANDARD_BT709) { - managedState.outputTransformMatrix = mSrgbToDisplayP3; - } else if (inputStandard == Dataspace::STANDARD_BT2020) { - managedState.outputTransformMatrix = mBt2020ToDisplayP3; - } - break; - default: - if (inputStandard == Dataspace::STANDARD_DCI_P3) { - managedState.outputTransformMatrix = mDisplayP3ToSrgb; - } else if (inputStandard == Dataspace::STANDARD_BT2020) { - managedState.outputTransformMatrix = mBt2020ToSrgb; - } - break; - } - } - - // we need to convert the RGB value to linear space and convert it back when: - // - there is a color matrix that is not an identity matrix, or - // - there is an output transform matrix that is not an identity matrix, or - // - the input transfer function doesn't match the output transfer function. - if (managedState.hasColorMatrix() || managedState.hasOutputTransformMatrix() || - inputTransfer != outputTransfer) { - managedState.inputTransferFunction = - Description::dataSpaceToTransferFunction(inputTransfer); - managedState.outputTransferFunction = - Description::dataSpaceToTransferFunction(outputTransfer); - } - - ProgramCache::getInstance().useProgram(mInProtectedContext ? mProtectedEGLContext : mEGLContext, - managedState); - - if (mState.drawShadows) { - glDrawElements(mesh.getPrimitive(), mesh.getIndexCount(), GL_UNSIGNED_SHORT, - mesh.getIndices()); - } else { - glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount()); - } - - if (outputDebugPPMs) { - static uint64_t managedColorFrameCount = 0; - std::ostringstream out; - out << "/data/texture_out" << managedColorFrameCount++; - writePPM(out.str().c_str(), mVpWidth, mVpHeight); - } - - if (mesh.getTexCoordsSize()) { - glDisableVertexAttribArray(Program::texCoords); - } - - if (mState.cornerRadius > 0.0f) { - glDisableVertexAttribArray(Program::cropCoords); - } - - if (mState.drawShadows) { - glDisableVertexAttribArray(Program::shadowColor); - glDisableVertexAttribArray(Program::shadowParams); - } -} - -size_t GLESRenderEngine::getMaxTextureSize() const { - return mMaxTextureSize; -} - -size_t GLESRenderEngine::getMaxViewportDims() const { - return mMaxViewportDims[0] < mMaxViewportDims[1] ? mMaxViewportDims[0] : mMaxViewportDims[1]; -} - -void GLESRenderEngine::dump(std::string& result) { - const GLExtensions& extensions = GLExtensions::getInstance(); - ProgramCache& cache = ProgramCache::getInstance(); - - StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion()); - StringAppendF(&result, "%s\n", extensions.getEGLExtensions()); - StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(), - extensions.getVersion()); - StringAppendF(&result, "%s\n", extensions.getExtensions()); - StringAppendF(&result, "RenderEngine supports protected context: %d\n", - supportsProtectedContent()); - StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext); - StringAppendF(&result, "RenderEngine program cache size for unprotected context: %zu\n", - cache.getSize(mEGLContext)); - StringAppendF(&result, "RenderEngine program cache size for protected context: %zu\n", - cache.getSize(mProtectedEGLContext)); - StringAppendF(&result, "RenderEngine last dataspace conversion: (%s) to (%s)\n", - dataspaceDetails(static_cast(mDataSpace)).c_str(), - dataspaceDetails(static_cast(mOutputDataSpace)).c_str()); - { - std::lock_guard lock(mRenderingMutex); - StringAppendF(&result, "RenderEngine image cache size: %zu\n", mImageCache.size()); - StringAppendF(&result, "Dumping buffer ids...\n"); - for (const auto& [id, unused] : mImageCache) { - StringAppendF(&result, "0x%" PRIx64 "\n", id); - } - } - { - std::lock_guard lock(mFramebufferImageCacheMutex); - StringAppendF(&result, "RenderEngine framebuffer image cache size: %zu\n", - mFramebufferImageCache.size()); - StringAppendF(&result, "Dumping buffer ids...\n"); - for (const auto& [id, unused] : mFramebufferImageCache) { - StringAppendF(&result, "0x%" PRIx64 "\n", id); - } - } -} - -GLESRenderEngine::GlesVersion GLESRenderEngine::parseGlesVersion(const char* str) { - int major, minor; - if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) { - if (sscanf(str, "OpenGL ES %d.%d", &major, &minor) != 2) { - ALOGW("Unable to parse GL_VERSION string: \"%s\"", str); - return GLES_VERSION_1_0; - } - } - - if (major == 1 && minor == 0) return GLES_VERSION_1_0; - if (major == 1 && minor >= 1) return GLES_VERSION_1_1; - if (major == 2 && minor >= 0) return GLES_VERSION_2_0; - if (major == 3 && minor >= 0) return GLES_VERSION_3_0; - - ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor); - return GLES_VERSION_1_0; -} - -EGLContext GLESRenderEngine::createEglContext(EGLDisplay display, EGLConfig config, - EGLContext shareContext, - std::optional contextPriority, - Protection protection) { - EGLint renderableType = 0; - if (config == EGL_NO_CONFIG) { - renderableType = EGL_OPENGL_ES3_BIT; - } else if (!eglGetConfigAttrib(display, config, EGL_RENDERABLE_TYPE, &renderableType)) { - LOG_ALWAYS_FATAL("can't query EGLConfig RENDERABLE_TYPE"); - } - EGLint contextClientVersion = 0; - if (renderableType & EGL_OPENGL_ES3_BIT) { - contextClientVersion = 3; - } else if (renderableType & EGL_OPENGL_ES2_BIT) { - contextClientVersion = 2; - } else if (renderableType & EGL_OPENGL_ES_BIT) { - contextClientVersion = 1; - } else { - LOG_ALWAYS_FATAL("no supported EGL_RENDERABLE_TYPEs"); - } - - std::vector contextAttributes; - contextAttributes.reserve(7); - contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION); - contextAttributes.push_back(contextClientVersion); - if (contextPriority) { - contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG); - switch (*contextPriority) { - case ContextPriority::REALTIME: - contextAttributes.push_back(EGL_CONTEXT_PRIORITY_REALTIME_NV); - break; - case ContextPriority::MEDIUM: - contextAttributes.push_back(EGL_CONTEXT_PRIORITY_MEDIUM_IMG); - break; - case ContextPriority::LOW: - contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LOW_IMG); - break; - case ContextPriority::HIGH: - default: - contextAttributes.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG); - break; - } - } - if (protection == Protection::PROTECTED) { - contextAttributes.push_back(EGL_PROTECTED_CONTENT_EXT); - contextAttributes.push_back(EGL_TRUE); - } - contextAttributes.push_back(EGL_NONE); - - EGLContext context = eglCreateContext(display, config, shareContext, contextAttributes.data()); - - if (contextClientVersion == 3 && context == EGL_NO_CONTEXT) { - // eglGetConfigAttrib indicated we can create GLES 3 context, but we failed, thus - // EGL_NO_CONTEXT so that we can abort. - if (config != EGL_NO_CONFIG) { - return context; - } - // If |config| is EGL_NO_CONFIG, we speculatively try to create GLES 3 context, so we should - // try to fall back to GLES 2. - contextAttributes[1] = 2; - context = eglCreateContext(display, config, shareContext, contextAttributes.data()); - } - - return context; -} - -EGLSurface GLESRenderEngine::createStubEglPbufferSurface(EGLDisplay display, EGLConfig config, - int hwcFormat, Protection protection) { - EGLConfig stubConfig = config; - if (stubConfig == EGL_NO_CONFIG) { - stubConfig = chooseEglConfig(display, hwcFormat, /*logConfig*/ true); - } - std::vector attributes; - attributes.reserve(7); - attributes.push_back(EGL_WIDTH); - attributes.push_back(1); - attributes.push_back(EGL_HEIGHT); - attributes.push_back(1); - if (protection == Protection::PROTECTED) { - attributes.push_back(EGL_PROTECTED_CONTENT_EXT); - attributes.push_back(EGL_TRUE); - } - attributes.push_back(EGL_NONE); - - return eglCreatePbufferSurface(display, stubConfig, attributes.data()); -} - -bool GLESRenderEngine::isHdrDataSpace(const Dataspace dataSpace) const { - const Dataspace standard = static_cast(dataSpace & Dataspace::STANDARD_MASK); - const Dataspace transfer = static_cast(dataSpace & Dataspace::TRANSFER_MASK); - return standard == Dataspace::STANDARD_BT2020 && - (transfer == Dataspace::TRANSFER_ST2084 || transfer == Dataspace::TRANSFER_HLG); -} - -// For convenience, we want to convert the input color space to XYZ color space first, -// and then convert from XYZ color space to output color space when -// - SDR and HDR contents are mixed, either SDR content will be converted to HDR or -// HDR content will be tone-mapped to SDR; Or, -// - there are HDR PQ and HLG contents presented at the same time, where we want to convert -// HLG content to PQ content. -// In either case above, we need to operate the Y value in XYZ color space. Thus, when either -// input data space or output data space is HDR data space, and the input transfer function -// doesn't match the output transfer function, we would enable an intermediate transfrom to -// XYZ color space. -bool GLESRenderEngine::needsXYZTransformMatrix() const { - const bool isInputHdrDataSpace = isHdrDataSpace(mDataSpace); - const bool isOutputHdrDataSpace = isHdrDataSpace(mOutputDataSpace); - const Dataspace inputTransfer = static_cast(mDataSpace & Dataspace::TRANSFER_MASK); - const Dataspace outputTransfer = - static_cast(mOutputDataSpace & Dataspace::TRANSFER_MASK); - - return (isInputHdrDataSpace || isOutputHdrDataSpace) && inputTransfer != outputTransfer; -} - -bool GLESRenderEngine::isImageCachedForTesting(uint64_t bufferId) { - std::lock_guard lock(mRenderingMutex); - const auto& cachedImage = mImageCache.find(bufferId); - return cachedImage != mImageCache.end(); -} - -bool GLESRenderEngine::isTextureNameKnownForTesting(uint32_t texName) { - const auto& entry = mTextureView.find(texName); - return entry != mTextureView.end(); -} - -std::optional GLESRenderEngine::getBufferIdForTextureNameForTesting(uint32_t texName) { - const auto& entry = mTextureView.find(texName); - return entry != mTextureView.end() ? entry->second : std::nullopt; -} - -bool GLESRenderEngine::isFramebufferImageCachedForTesting(uint64_t bufferId) { - std::lock_guard lock(mFramebufferImageCacheMutex); - return std::any_of(mFramebufferImageCache.cbegin(), mFramebufferImageCache.cend(), - [=](std::pair image) { - return image.first == bufferId; - }); -} - -// FlushTracer implementation -GLESRenderEngine::FlushTracer::FlushTracer(GLESRenderEngine* engine) : mEngine(engine) { - mThread = std::thread(&GLESRenderEngine::FlushTracer::loop, this); -} - -GLESRenderEngine::FlushTracer::~FlushTracer() { - { - std::lock_guard lock(mMutex); - mRunning = false; - } - mCondition.notify_all(); - if (mThread.joinable()) { - mThread.join(); - } -} - -void GLESRenderEngine::FlushTracer::queueSync(EGLSyncKHR sync) { - std::lock_guard lock(mMutex); - char name[64]; - const uint64_t frameNum = mFramesQueued++; - snprintf(name, sizeof(name), "Queueing sync for frame: %lu", - static_cast(frameNum)); - ATRACE_NAME(name); - mQueue.push({sync, frameNum}); - ATRACE_INT("GPU Frames Outstanding", mQueue.size()); - mCondition.notify_one(); -} - -void GLESRenderEngine::FlushTracer::loop() { - while (mRunning) { - QueueEntry entry; - { - std::lock_guard lock(mMutex); - - mCondition.wait(mMutex, - [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; }); - - if (!mRunning) { - // if mRunning is false, then FlushTracer is being destroyed, so - // bail out now. - break; - } - entry = mQueue.front(); - mQueue.pop(); - } - { - char name[64]; - snprintf(name, sizeof(name), "waiting for frame %lu", - static_cast(entry.mFrameNum)); - ATRACE_NAME(name); - mEngine->waitSync(entry.mSync, 0); - } - } -} - -void GLESRenderEngine::handleShadow(const FloatRect& casterRect, float casterCornerRadius, - const ShadowSettings& settings) { - ATRACE_CALL(); - const float casterZ = settings.length / 2.0f; - const GLShadowVertexGenerator shadows(casterRect, casterCornerRadius, casterZ, - settings.casterIsTranslucent, settings.ambientColor, - settings.spotColor, settings.lightPos, - settings.lightRadius); - - // setup mesh for both shadows - Mesh mesh = Mesh::Builder() - .setPrimitive(Mesh::TRIANGLES) - .setVertices(shadows.getVertexCount(), 2 /* size */) - .setShadowAttrs() - .setIndices(shadows.getIndexCount()) - .build(); - - Mesh::VertexArray position = mesh.getPositionArray(); - Mesh::VertexArray shadowColor = mesh.getShadowColorArray(); - Mesh::VertexArray shadowParams = mesh.getShadowParamsArray(); - shadows.fillVertices(position, shadowColor, shadowParams); - shadows.fillIndices(mesh.getIndicesArray()); - - mState.cornerRadius = 0.0f; - mState.drawShadows = true; - setupLayerTexturing(mShadowTexture->getTexture()); - drawMesh(mesh); - mState.drawShadows = false; -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h deleted file mode 100644 index f5368d4e9f..0000000000 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SF_GLESRENDERENGINE_H_ -#define SF_GLESRENDERENGINE_H_ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include "GLShadowTexture.h" -#include "ImageManager.h" - -#define EGL_NO_CONFIG ((EGLConfig)0) - -namespace android { - -namespace renderengine { - -class Mesh; -class Texture; - -namespace gl { - -class GLImage; -class BlurFilter; - -class GLESRenderEngine : public RenderEngine { -public: - static std::unique_ptr create(const RenderEngineCreationArgs& args); - - GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLConfig config, - EGLContext ctxt, EGLSurface stub, EGLContext protectedContext, - EGLSurface protectedStub); - ~GLESRenderEngine() override EXCLUDES(mRenderingMutex); - - std::future primeCache() override; - void genTextures(size_t count, uint32_t* names) override; - void deleteTextures(size_t count, uint32_t const* names) override; - bool isProtected() const { return mInProtectedContext; } - bool supportsProtectedContent() const override; - void useProtectedContext(bool useProtectedContext) override; - void cleanupPostRender() override; - int getContextPriority() override; - bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } - void onActiveDisplaySizeChanged(ui::Size size) override {} - - EGLDisplay getEGLDisplay() const { return mEGLDisplay; } - // Creates an output image for rendering to - EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected, - bool useFramebufferCache) - EXCLUDES(mFramebufferImageCacheMutex); - - // Test-only methods - // Returns true iff mImageCache contains an image keyed by bufferId - bool isImageCachedForTesting(uint64_t bufferId) EXCLUDES(mRenderingMutex); - // Returns true iff texName was previously generated by RenderEngine and was - // not destroyed. - bool isTextureNameKnownForTesting(uint32_t texName); - // Returns the buffer ID of the content bound to texName, or nullopt if no - // such mapping exists. - std::optional getBufferIdForTextureNameForTesting(uint32_t texName); - // Returns true iff mFramebufferImageCache contains an image keyed by bufferId - bool isFramebufferImageCachedForTesting(uint64_t bufferId) - EXCLUDES(mFramebufferImageCacheMutex); - // These are wrappers around public methods above, but exposing Barrier - // objects so that tests can block. - std::shared_ptr cacheExternalTextureBufferForTesting( - const sp& buffer); - std::shared_ptr unbindExternalTextureBufferForTesting(uint64_t bufferId); - -protected: - Framebuffer* getFramebufferForDrawing(); - void dump(std::string& result) override EXCLUDES(mRenderingMutex) - EXCLUDES(mFramebufferImageCacheMutex); - size_t getMaxTextureSize() const override; - size_t getMaxViewportDims() const override; - void mapExternalTextureBuffer(const sp& buffer, bool isRenderable) - EXCLUDES(mRenderingMutex); - void unmapExternalTextureBuffer(sp&& buffer) EXCLUDES(mRenderingMutex); - bool canSkipPostRenderCleanup() const override; - void drawLayersInternal(const std::shared_ptr>&& resultPromise, - const DisplaySettings& display, - const std::vector& layers, - const std::shared_ptr& buffer, - const bool useFramebufferCache, base::unique_fd&& bufferFence) override; - -private: - friend class BindNativeBufferAsFramebuffer; - - enum GlesVersion { - GLES_VERSION_1_0 = 0x10000, - GLES_VERSION_1_1 = 0x10001, - GLES_VERSION_2_0 = 0x20000, - GLES_VERSION_3_0 = 0x30000, - }; - - static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); - static GlesVersion parseGlesVersion(const char* str); - static EGLContext createEglContext(EGLDisplay display, EGLConfig config, - EGLContext shareContext, - std::optional contextPriority, - Protection protection); - static std::optional createContextPriority( - const RenderEngineCreationArgs& args); - static EGLSurface createStubEglPbufferSurface(EGLDisplay display, EGLConfig config, - int hwcFormat, Protection protection); - std::unique_ptr createFramebuffer(); - std::unique_ptr createImage(); - void checkErrors() const; - void checkErrors(const char* tag) const; - void setScissor(const Rect& region); - void disableScissor(); - bool waitSync(EGLSyncKHR sync, EGLint flags); - status_t cacheExternalTextureBufferInternal(const sp& buffer) - EXCLUDES(mRenderingMutex); - void unbindExternalTextureBufferInternal(uint64_t bufferId) EXCLUDES(mRenderingMutex); - status_t bindFrameBuffer(Framebuffer* framebuffer); - void unbindFrameBuffer(Framebuffer* framebuffer); - void bindExternalTextureImage(uint32_t texName, const Image& image); - void bindExternalTextureBuffer(uint32_t texName, const sp& buffer, - const sp& fence) EXCLUDES(mRenderingMutex); - void cleanFramebufferCache() EXCLUDES(mFramebufferImageCacheMutex) override; - - // A data space is considered HDR data space if it has BT2020 color space - // with PQ or HLG transfer function. - bool isHdrDataSpace(const ui::Dataspace dataSpace) const; - bool needsXYZTransformMatrix() const; - // Defines the viewport, and sets the projection matrix to the projection - // defined by the clip. - void setViewportAndProjection(Rect viewport, Rect clip); - // Evicts stale images from the buffer cache. - void evictImages(const std::vector& layers); - // Computes the cropping window for the layer and sets up cropping - // coordinates for the mesh. - FloatRect setupLayerCropping(const LayerSettings& layer, Mesh& mesh); - - // We do a special handling for rounded corners when it's possible to turn off blending - // for the majority of the layer. The rounded corners needs to turn on blending such that - // we can set the alpha value correctly, however, only the corners need this, and since - // blending is an expensive operation, we want to turn off blending when it's not necessary. - void handleRoundedCorners(const DisplaySettings& display, const LayerSettings& layer, - const Mesh& mesh); - base::unique_fd flush(); - bool finish(); - bool waitFence(base::unique_fd fenceFd); - void clearWithColor(float red, float green, float blue, float alpha); - void fillRegionWithColor(const Region& region, float red, float green, float blue, float alpha); - void handleShadow(const FloatRect& casterRect, float casterCornerRadius, - const ShadowSettings& shadowSettings); - void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, - const half4& color, float cornerRadius); - void setupLayerTexturing(const Texture& texture); - void setupFillWithColor(float r, float g, float b, float a); - void setColorTransform(const mat4& colorTransform); - void setDisplayColorTransform(const mat4& colorTransform); - void disableTexturing(); - void disableBlending(); - void setupCornerRadiusCropSize(float width, float height); - - // HDR and color management related functions and state - void setSourceDataSpace(ui::Dataspace source); - void setOutputDataSpace(ui::Dataspace dataspace); - void setDisplayMaxLuminance(const float maxLuminance); - - // drawing - void drawMesh(const Mesh& mesh); - - EGLDisplay mEGLDisplay; - EGLConfig mEGLConfig; - EGLContext mEGLContext; - EGLSurface mStubSurface; - EGLContext mProtectedEGLContext; - EGLSurface mProtectedStubSurface; - GLint mMaxViewportDims[2]; - GLint mMaxTextureSize; - GLuint mVpWidth; - GLuint mVpHeight; - Description mState; - std::unique_ptr mShadowTexture = nullptr; - - mat4 mSrgbToXyz; - mat4 mDisplayP3ToXyz; - mat4 mBt2020ToXyz; - mat4 mXyzToSrgb; - mat4 mXyzToDisplayP3; - mat4 mXyzToBt2020; - mat4 mSrgbToDisplayP3; - mat4 mSrgbToBt2020; - mat4 mDisplayP3ToSrgb; - mat4 mDisplayP3ToBt2020; - mat4 mBt2020ToSrgb; - mat4 mBt2020ToDisplayP3; - - bool mInProtectedContext = false; - // If set to true, then enables tracing flush() and finish() to systrace. - bool mTraceGpuCompletion = false; - // Maximum size of mFramebufferImageCache. If more images would be cached, then (approximately) - // the last recently used buffer should be kicked out. - uint32_t mFramebufferImageCacheSize = 0; - - // Cache of output images, keyed by corresponding GraphicBuffer ID. - std::deque> mFramebufferImageCache - GUARDED_BY(mFramebufferImageCacheMutex); - // The only reason why we have this mutex is so that we don't segfault when - // dumping info. - std::mutex mFramebufferImageCacheMutex; - - // Current dataspace of layer being rendered - ui::Dataspace mDataSpace = ui::Dataspace::UNKNOWN; - - // Current output dataspace of the render engine - ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN; - - // Whether only shaders performing tone mapping from HDR to SDR will be generated on - // primeCache(). - const bool mPrecacheToneMapperShaderOnly = false; - - // Cache of GL images that we'll store per GraphicBuffer ID - std::unordered_map> mImageCache GUARDED_BY(mRenderingMutex); - std::unordered_map> mTextureView; - - // Mutex guarding rendering operations, so that: - // 1. GL operations aren't interleaved, and - // 2. Internal state related to rendering that is potentially modified by - // multiple threads is guaranteed thread-safe. - std::mutex mRenderingMutex; - - std::unique_ptr mDrawingBuffer; - // this is a 1x1 RGB buffer, but over-allocate in case a driver wants more - // memory or if it needs to satisfy alignment requirements. In this case: - // assume that each channel requires 4 bytes, and add 3 additional bytes to - // ensure that we align on a word. Allocating 16 bytes will provide a - // guarantee that we don't clobber memory. - uint32_t mPlaceholderDrawBuffer[4]; - // Placeholder buffer and image, similar to mPlaceholderDrawBuffer, but - // instead these are intended for cleaning up texture memory with the - // GL_TEXTURE_EXTERNAL_OES target. - ANativeWindowBuffer* mPlaceholderBuffer = nullptr; - EGLImage mPlaceholderImage = EGL_NO_IMAGE_KHR; - sp mLastDrawFence; - // Store a separate boolean checking if prior resources were cleaned up, as - // devices that don't support native sync fences can't rely on a last draw - // fence that doesn't exist. - bool mPriorResourcesCleaned = true; - - // Blur effect processor, only instantiated when a layer requests it. - BlurFilter* mBlurFilter = nullptr; - - class FlushTracer { - public: - FlushTracer(GLESRenderEngine* engine); - ~FlushTracer(); - void queueSync(EGLSyncKHR sync) EXCLUDES(mMutex); - - struct QueueEntry { - EGLSyncKHR mSync = nullptr; - uint64_t mFrameNum = 0; - }; - - private: - void loop(); - GLESRenderEngine* const mEngine; - std::thread mThread; - std::condition_variable_any mCondition; - std::mutex mMutex; - std::queue mQueue GUARDED_BY(mMutex); - uint64_t mFramesQueued GUARDED_BY(mMutex) = 0; - bool mRunning = true; - }; - friend class FlushTracer; - friend class ImageManager; - friend class GLFramebuffer; - friend class BlurFilter; - friend class GenericProgram; - std::unique_ptr mFlushTracer; - std::unique_ptr mImageManager; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android - -#endif /* SF_GLESRENDERENGINE_H_ */ diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp deleted file mode 100644 index 58d6caa48a..0000000000 --- a/libs/renderengine/gl/GLFramebuffer.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "GLFramebuffer.h" - -#include -#include -#include -#include -#include -#include -#include -#include "GLESRenderEngine.h" - -namespace android { -namespace renderengine { -namespace gl { - -GLFramebuffer::GLFramebuffer(GLESRenderEngine& engine) - : mEngine(engine), mEGLDisplay(engine.getEGLDisplay()), mEGLImage(EGL_NO_IMAGE_KHR) { - glGenTextures(1, &mTextureName); - glGenFramebuffers(1, &mFramebufferName); -} - -GLFramebuffer::~GLFramebuffer() { - setNativeWindowBuffer(nullptr, false, false); - glDeleteFramebuffers(1, &mFramebufferName); - glDeleteTextures(1, &mTextureName); -} - -bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected, - const bool useFramebufferCache) { - ATRACE_CALL(); - if (mEGLImage != EGL_NO_IMAGE_KHR) { - if (!usingFramebufferCache) { - eglDestroyImageKHR(mEGLDisplay, mEGLImage); - DEBUG_EGL_IMAGE_TRACKER_DESTROY(); - } - mEGLImage = EGL_NO_IMAGE_KHR; - mBufferWidth = 0; - mBufferHeight = 0; - } - - if (nativeBuffer) { - mEGLImage = mEngine.createFramebufferImageIfNeeded(nativeBuffer, isProtected, - useFramebufferCache); - if (mEGLImage == EGL_NO_IMAGE_KHR) { - return false; - } - usingFramebufferCache = useFramebufferCache; - mBufferWidth = nativeBuffer->width; - mBufferHeight = nativeBuffer->height; - } - return true; -} - -void GLFramebuffer::allocateBuffers(uint32_t width, uint32_t height, void* data) { - ATRACE_CALL(); - - glBindTexture(GL_TEXTURE_2D, mTextureName); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); - - mBufferHeight = height; - mBufferWidth = width; - mEngine.checkErrors("Allocating Fbo texture"); - - bind(); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTextureName, 0); - mStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); - unbind(); - glBindTexture(GL_TEXTURE_2D, 0); - - if (mStatus != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Frame buffer is not complete. Error %d", mStatus); - } -} - -void GLFramebuffer::bind() const { - glBindFramebuffer(GL_FRAMEBUFFER, mFramebufferName); -} - -void GLFramebuffer::bindAsReadBuffer() const { - glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebufferName); -} - -void GLFramebuffer::bindAsDrawBuffer() const { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferName); -} - -void GLFramebuffer::unbind() const { - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h deleted file mode 100644 index 6757695ddb..0000000000 --- a/libs/renderengine/gl/GLFramebuffer.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2018 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 - -#include -#include -#include -#include - -struct ANativeWindowBuffer; - -namespace android { -namespace renderengine { -namespace gl { - -class GLESRenderEngine; - -class GLFramebuffer : public renderengine::Framebuffer { -public: - explicit GLFramebuffer(GLESRenderEngine& engine); - explicit GLFramebuffer(GLESRenderEngine& engine, bool multiTarget); - ~GLFramebuffer() override; - - bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected, - const bool useFramebufferCache) override; - void allocateBuffers(uint32_t width, uint32_t height, void* data = nullptr); - EGLImageKHR getEGLImage() const { return mEGLImage; } - uint32_t getTextureName() const { return mTextureName; } - uint32_t getFramebufferName() const { return mFramebufferName; } - int32_t getBufferHeight() const { return mBufferHeight; } - int32_t getBufferWidth() const { return mBufferWidth; } - GLenum getStatus() const { return mStatus; } - void bind() const; - void bindAsReadBuffer() const; - void bindAsDrawBuffer() const; - void unbind() const; - -private: - GLESRenderEngine& mEngine; - EGLDisplay mEGLDisplay; - EGLImageKHR mEGLImage; - bool usingFramebufferCache = false; - GLenum mStatus = GL_FRAMEBUFFER_UNSUPPORTED; - uint32_t mTextureName, mFramebufferName; - - int32_t mBufferHeight = 0; - int32_t mBufferWidth = 0; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLImage.cpp b/libs/renderengine/gl/GLImage.cpp deleted file mode 100644 index 8497721956..0000000000 --- a/libs/renderengine/gl/GLImage.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "GLImage.h" - -#include - -#include -#include -#include -#include "GLESRenderEngine.h" -#include "GLExtensions.h" - -namespace android { -namespace renderengine { -namespace gl { - -static std::vector buildAttributeList(bool isProtected) { - std::vector attrs; - attrs.reserve(16); - - attrs.push_back(EGL_IMAGE_PRESERVED_KHR); - attrs.push_back(EGL_TRUE); - - if (isProtected && GLExtensions::getInstance().hasProtectedContent()) { - attrs.push_back(EGL_PROTECTED_CONTENT_EXT); - attrs.push_back(EGL_TRUE); - } - - attrs.push_back(EGL_NONE); - - return attrs; -} - -GLImage::GLImage(const GLESRenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {} - -GLImage::~GLImage() { - setNativeWindowBuffer(nullptr, false); -} - -bool GLImage::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) { - ATRACE_CALL(); - if (mEGLImage != EGL_NO_IMAGE_KHR) { - if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) { - ALOGE("failed to destroy image: %#x", eglGetError()); - } - DEBUG_EGL_IMAGE_TRACKER_DESTROY(); - mEGLImage = EGL_NO_IMAGE_KHR; - } - - if (buffer) { - std::vector attrs = buildAttributeList(isProtected); - mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, - static_cast(buffer), attrs.data()); - if (mEGLImage == EGL_NO_IMAGE_KHR) { - ALOGE("failed to create EGLImage: %#x", eglGetError()); - return false; - } - DEBUG_EGL_IMAGE_TRACKER_CREATE(); - mProtected = isProtected; - } - - return true; -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLImage.h b/libs/renderengine/gl/GLImage.h deleted file mode 100644 index 59d6ce3549..0000000000 --- a/libs/renderengine/gl/GLImage.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018 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 - -#include -#include -#include -#include - -struct ANativeWindowBuffer; - -namespace android { -namespace renderengine { -namespace gl { - -class GLESRenderEngine; - -class GLImage : public renderengine::Image { -public: - explicit GLImage(const GLESRenderEngine& engine); - ~GLImage() override; - - bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) override; - - EGLImageKHR getEGLImage() const { return mEGLImage; } - bool isProtected() const { return mProtected; } - -private: - EGLDisplay mEGLDisplay; - EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR; - bool mProtected = false; - - DISALLOW_COPY_AND_ASSIGN(GLImage); -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLShadowTexture.cpp b/libs/renderengine/gl/GLShadowTexture.cpp deleted file mode 100644 index 2423a3467e..0000000000 --- a/libs/renderengine/gl/GLShadowTexture.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 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. - */ - -#include -#include -#include -#include -#include - -#include "GLShadowTexture.h" -#include "GLSkiaShadowPort.h" - -namespace android { -namespace renderengine { -namespace gl { - -GLShadowTexture::GLShadowTexture() { - fillShadowTextureData(mTextureData, SHADOW_TEXTURE_WIDTH); - - glGenTextures(1, &mName); - glBindTexture(GL_TEXTURE_2D, mName); - glTexImage2D(GL_TEXTURE_2D, 0 /* base image level */, GL_ALPHA, SHADOW_TEXTURE_WIDTH, - SHADOW_TEXTURE_HEIGHT, 0 /* border */, GL_ALPHA, GL_UNSIGNED_BYTE, mTextureData); - mTexture.init(Texture::TEXTURE_2D, mName); - mTexture.setFiltering(true); - mTexture.setDimensions(SHADOW_TEXTURE_WIDTH, 1); -} - -GLShadowTexture::~GLShadowTexture() { - glDeleteTextures(1, &mName); -} - -const Texture& GLShadowTexture::getTexture() { - return mTexture; -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLShadowTexture.h b/libs/renderengine/gl/GLShadowTexture.h deleted file mode 100644 index 250a9d77d0..0000000000 --- a/libs/renderengine/gl/GLShadowTexture.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 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. - */ - -#pragma once - -#include -#include - -namespace android { -namespace renderengine { -namespace gl { - -class GLShadowTexture { -public: - GLShadowTexture(); - ~GLShadowTexture(); - - const Texture& getTexture(); - -private: - static constexpr int SHADOW_TEXTURE_WIDTH = 128; - static constexpr int SHADOW_TEXTURE_HEIGHT = 1; - - GLuint mName; - Texture mTexture; - uint8_t mTextureData[SHADOW_TEXTURE_WIDTH]; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLShadowVertexGenerator.cpp b/libs/renderengine/gl/GLShadowVertexGenerator.cpp deleted file mode 100644 index 3181f9bebb..0000000000 --- a/libs/renderengine/gl/GLShadowVertexGenerator.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2019 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 - -#include - -#include -#include - -#include "GLShadowVertexGenerator.h" - -namespace android { -namespace renderengine { -namespace gl { - -GLShadowVertexGenerator::GLShadowVertexGenerator(const FloatRect& casterRect, - float casterCornerRadius, float casterZ, - bool casterIsTranslucent, const vec4& ambientColor, - const vec4& spotColor, const vec3& lightPosition, - float lightRadius) { - mDrawAmbientShadow = ambientColor.a > 0.f; - mDrawSpotShadow = spotColor.a > 0.f; - - // Generate geometries and find number of vertices to generate - if (mDrawAmbientShadow) { - mAmbientShadowGeometry = getAmbientShadowGeometry(casterRect, casterCornerRadius, casterZ, - casterIsTranslucent, ambientColor); - mAmbientShadowVertexCount = getVertexCountForGeometry(*mAmbientShadowGeometry.get()); - mAmbientShadowIndexCount = getIndexCountForGeometry(*mAmbientShadowGeometry.get()); - } else { - mAmbientShadowVertexCount = 0; - mAmbientShadowIndexCount = 0; - } - - if (mDrawSpotShadow) { - mSpotShadowGeometry = - getSpotShadowGeometry(casterRect, casterCornerRadius, casterZ, casterIsTranslucent, - spotColor, lightPosition, lightRadius); - mSpotShadowVertexCount = getVertexCountForGeometry(*mSpotShadowGeometry.get()); - mSpotShadowIndexCount = getIndexCountForGeometry(*mSpotShadowGeometry.get()); - } else { - mSpotShadowVertexCount = 0; - mSpotShadowIndexCount = 0; - } -} - -size_t GLShadowVertexGenerator::getVertexCount() const { - return mAmbientShadowVertexCount + mSpotShadowVertexCount; -} - -size_t GLShadowVertexGenerator::getIndexCount() const { - return mAmbientShadowIndexCount + mSpotShadowIndexCount; -} - -void GLShadowVertexGenerator::fillVertices(Mesh::VertexArray& position, - Mesh::VertexArray& color, - Mesh::VertexArray& params) const { - if (mDrawAmbientShadow) { - fillVerticesForGeometry(*mAmbientShadowGeometry.get(), mAmbientShadowVertexCount, position, - color, params); - } - if (mDrawSpotShadow) { - fillVerticesForGeometry(*mSpotShadowGeometry.get(), mSpotShadowVertexCount, - Mesh::VertexArray(position, mAmbientShadowVertexCount), - Mesh::VertexArray(color, mAmbientShadowVertexCount), - Mesh::VertexArray(params, mAmbientShadowVertexCount)); - } -} - -void GLShadowVertexGenerator::fillIndices(uint16_t* indices) const { - if (mDrawAmbientShadow) { - fillIndicesForGeometry(*mAmbientShadowGeometry.get(), mAmbientShadowIndexCount, - 0 /* starting vertex offset */, indices); - } - if (mDrawSpotShadow) { - fillIndicesForGeometry(*mSpotShadowGeometry.get(), mSpotShadowIndexCount, - mAmbientShadowVertexCount /* starting vertex offset */, - &(indices[mAmbientShadowIndexCount])); - } -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLShadowVertexGenerator.h b/libs/renderengine/gl/GLShadowVertexGenerator.h deleted file mode 100644 index 112f97623b..0000000000 --- a/libs/renderengine/gl/GLShadowVertexGenerator.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2019 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 -#include - -#include "GLSkiaShadowPort.h" - -namespace android { -namespace renderengine { - -class Mesh; - -namespace gl { - -/** - * Generates gl attributes required to draw shadow spot and/or ambient shadows. - * - * Each shadow can support different colors. This class generates three vertex attributes for - * each shadow, its position, color and shadow params(offset and distance). These can be sent - * using a single glDrawElements call. - */ -class GLShadowVertexGenerator { -public: - GLShadowVertexGenerator(const FloatRect& casterRect, float casterCornerRadius, float casterZ, - bool casterIsTranslucent, const vec4& ambientColor, - const vec4& spotColor, const vec3& lightPosition, float lightRadius); - ~GLShadowVertexGenerator() = default; - - size_t getVertexCount() const; - size_t getIndexCount() const; - void fillVertices(Mesh::VertexArray& position, Mesh::VertexArray& color, - Mesh::VertexArray& params) const; - void fillIndices(uint16_t* indices) const; - -private: - bool mDrawAmbientShadow; - std::unique_ptr mAmbientShadowGeometry; - int mAmbientShadowVertexCount = 0; - int mAmbientShadowIndexCount = 0; - - bool mDrawSpotShadow; - std::unique_ptr mSpotShadowGeometry; - int mSpotShadowVertexCount = 0; - int mSpotShadowIndexCount = 0; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLSkiaShadowPort.cpp b/libs/renderengine/gl/GLSkiaShadowPort.cpp deleted file mode 100644 index da8b435854..0000000000 --- a/libs/renderengine/gl/GLSkiaShadowPort.cpp +++ /dev/null @@ -1,656 +0,0 @@ -/* - * Copyright 2019 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 - -#include - -#include -#include - -#include - -#include "GLSkiaShadowPort.h" - -namespace android { -namespace renderengine { -namespace gl { - -/** - * The shadow geometry logic and vertex generation code has been ported from skia shadow - * fast path OpenGL implementation to draw shadows around rects and rounded rects including - * circles. - * - * path: skia/src/gpu/GrRenderTargetContext.cpp GrRenderTargetContext::drawFastShadow - * - * Modifications made: - * - Switched to using std lib math functions - * - Fall off function is implemented in vertex shader rather than a shadow texture - * - Removed transformations applied on the caster rect since the caster will be in local - * coordinate space and will be transformed by the vertex shader. - */ - -static inline float divide_and_pin(float numer, float denom, float min, float max) { - if (denom == 0.0f) return min; - return std::clamp(numer / denom, min, max); -} - -static constexpr auto SK_ScalarSqrt2 = 1.41421356f; -static constexpr auto kAmbientHeightFactor = 1.0f / 128.0f; -static constexpr auto kAmbientGeomFactor = 64.0f; -// Assuming that we have a light height of 600 for the spot shadow, -// the spot values will reach their maximum at a height of approximately 292.3077. -// We'll round up to 300 to keep it simple. -static constexpr auto kMaxAmbientRadius = 300 * kAmbientHeightFactor * kAmbientGeomFactor; - -inline float AmbientBlurRadius(float height) { - return std::min(height * kAmbientHeightFactor * kAmbientGeomFactor, kMaxAmbientRadius); -} -inline float AmbientRecipAlpha(float height) { - return 1.0f + std::max(height * kAmbientHeightFactor, 0.0f); -} - -////////////////////////////////////////////////////////////////////////////// -// Circle Data -// -// We have two possible cases for geometry for a circle: - -// In the case of a normal fill, we draw geometry for the circle as an octagon. -static const uint16_t gFillCircleIndices[] = { - // enter the octagon - // clang-format off - 0, 1, 8, 1, 2, 8, - 2, 3, 8, 3, 4, 8, - 4, 5, 8, 5, 6, 8, - 6, 7, 8, 7, 0, 8, - // clang-format on -}; - -// For stroked circles, we use two nested octagons. -static const uint16_t gStrokeCircleIndices[] = { - // enter the octagon - // clang-format off - 0, 1, 9, 0, 9, 8, - 1, 2, 10, 1, 10, 9, - 2, 3, 11, 2, 11, 10, - 3, 4, 12, 3, 12, 11, - 4, 5, 13, 4, 13, 12, - 5, 6, 14, 5, 14, 13, - 6, 7, 15, 6, 15, 14, - 7, 0, 8, 7, 8, 15, - // clang-format on -}; - -#define SK_ARRAY_COUNT(a) (sizeof(a) / sizeof((a)[0])) -static const int kIndicesPerFillCircle = SK_ARRAY_COUNT(gFillCircleIndices); -static const int kIndicesPerStrokeCircle = SK_ARRAY_COUNT(gStrokeCircleIndices); -static const int kVertsPerStrokeCircle = 16; -static const int kVertsPerFillCircle = 9; - -static int circle_type_to_vert_count(bool stroked) { - return stroked ? kVertsPerStrokeCircle : kVertsPerFillCircle; -} - -static int circle_type_to_index_count(bool stroked) { - return stroked ? kIndicesPerStrokeCircle : kIndicesPerFillCircle; -} - -static const uint16_t* circle_type_to_indices(bool stroked) { - return stroked ? gStrokeCircleIndices : gFillCircleIndices; -} - -/////////////////////////////////////////////////////////////////////////////// -// RoundRect Data -// -// The geometry for a shadow roundrect is similar to a 9-patch: -// ____________ -// |_|________|_| -// | | | | -// | | | | -// | | | | -// |_|________|_| -// |_|________|_| -// -// However, each corner is rendered as a fan rather than a simple quad, as below. (The diagram -// shows the upper part of the upper left corner. The bottom triangle would similarly be split -// into two triangles.) -// ________ -// |\ \ | -// | \ \ | -// | \\ | -// | \| -// -------- -// -// The center of the fan handles the curve of the corner. For roundrects where the stroke width -// is greater than the corner radius, the outer triangles blend from the curve to the straight -// sides. Otherwise these triangles will be degenerate. -// -// In the case where the stroke width is greater than the corner radius and the -// blur radius (overstroke), we add additional geometry to mark out the rectangle in the center. -// This rectangle extends the coverage values of the center edges of the 9-patch. -// ____________ -// |_|________|_| -// | |\ ____ /| | -// | | | | | | -// | | |____| | | -// |_|/______\|_| -// |_|________|_| -// -// For filled rrects we reuse the stroke geometry but add an additional quad to the center. - -static const uint16_t gRRectIndices[] = { - // clang-format off - // overstroke quads - // we place this at the beginning so that we can skip these indices when rendering as filled - 0, 6, 25, 0, 25, 24, - 6, 18, 27, 6, 27, 25, - 18, 12, 26, 18, 26, 27, - 12, 0, 24, 12, 24, 26, - - // corners - 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, - 6, 11, 10, 6, 10, 9, 6, 9, 8, 6, 8, 7, - 12, 17, 16, 12, 16, 15, 12, 15, 14, 12, 14, 13, - 18, 19, 20, 18, 20, 21, 18, 21, 22, 18, 22, 23, - - // edges - 0, 5, 11, 0, 11, 6, - 6, 7, 19, 6, 19, 18, - 18, 23, 17, 18, 17, 12, - 12, 13, 1, 12, 1, 0, - - // fill quad - // we place this at the end so that we can skip these indices when rendering as stroked - 0, 6, 18, 0, 18, 12, - // clang-format on -}; - -// overstroke count -static const int kIndicesPerOverstrokeRRect = SK_ARRAY_COUNT(gRRectIndices) - 6; -// simple stroke count skips overstroke indices -static const int kIndicesPerStrokeRRect = kIndicesPerOverstrokeRRect - 6 * 4; -// fill count adds final quad to stroke count -static const int kIndicesPerFillRRect = kIndicesPerStrokeRRect + 6; -static const int kVertsPerStrokeRRect = 24; -static const int kVertsPerOverstrokeRRect = 28; -static const int kVertsPerFillRRect = 24; - -static int rrect_type_to_vert_count(RRectType type) { - switch (type) { - case kFill_RRectType: - return kVertsPerFillRRect; - case kStroke_RRectType: - return kVertsPerStrokeRRect; - case kOverstroke_RRectType: - return kVertsPerOverstrokeRRect; - } - ALOGE("Invalid rect type: %d", type); - return -1; -} - -static int rrect_type_to_index_count(RRectType type) { - switch (type) { - case kFill_RRectType: - return kIndicesPerFillRRect; - case kStroke_RRectType: - return kIndicesPerStrokeRRect; - case kOverstroke_RRectType: - return kIndicesPerOverstrokeRRect; - } - ALOGE("Invalid rect type: %d", type); - return -1; -} - -static const uint16_t* rrect_type_to_indices(RRectType type) { - switch (type) { - case kFill_RRectType: - case kStroke_RRectType: - return gRRectIndices + 6 * 4; - case kOverstroke_RRectType: - return gRRectIndices; - } - ALOGE("Invalid rect type: %d", type); - return nullptr; -} - -static void fillInCircleVerts(const Geometry& args, bool isStroked, - Mesh::VertexArray& position, - Mesh::VertexArray& shadowColor, - Mesh::VertexArray& shadowParams) { - vec4 color = args.fColor; - float outerRadius = args.fOuterRadius; - float innerRadius = args.fInnerRadius; - float blurRadius = args.fBlurRadius; - float distanceCorrection = outerRadius / blurRadius; - - const FloatRect& bounds = args.fDevBounds; - - // The inner radius in the vertex data must be specified in normalized space. - innerRadius = innerRadius / outerRadius; - - vec2 center = vec2(bounds.getWidth() / 2.0f, bounds.getHeight() / 2.0f); - float halfWidth = 0.5f * bounds.getWidth(); - float octOffset = 0.41421356237f; // sqrt(2) - 1 - int vertexCount = 0; - - position[vertexCount] = center + vec2(-octOffset * halfWidth, -halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-octOffset, -1, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(octOffset * halfWidth, -halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(octOffset, -1, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(halfWidth, -octOffset * halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(1, -octOffset, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(halfWidth, octOffset * halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(1, octOffset, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(octOffset * halfWidth, halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(octOffset, 1, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(-octOffset * halfWidth, halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-octOffset, 1, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(-halfWidth, octOffset * halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-1, octOffset, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(-halfWidth, -octOffset * halfWidth); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-1, -octOffset, distanceCorrection); - vertexCount++; - - if (isStroked) { - // compute the inner ring - - // cosine and sine of pi/8 - float c = 0.923579533f; - float s = 0.382683432f; - float r = args.fInnerRadius; - - position[vertexCount] = center + vec2(-s * r, -c * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-s * innerRadius, -c * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(s * r, -c * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(s * innerRadius, -c * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(c * r, -s * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(c * innerRadius, -s * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(c * r, s * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(c * innerRadius, s * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(s * r, c * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(s * innerRadius, c * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(-s * r, c * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-s * innerRadius, c * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(-c * r, s * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-c * innerRadius, s * innerRadius, distanceCorrection); - vertexCount++; - - position[vertexCount] = center + vec2(-c * r, -s * r); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(-c * innerRadius, -s * innerRadius, distanceCorrection); - vertexCount++; - } else { - // filled - position[vertexCount] = center; - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, 0, distanceCorrection); - vertexCount++; - } -} - -static void fillInRRectVerts(const Geometry& args, Mesh::VertexArray& position, - Mesh::VertexArray& shadowColor, - Mesh::VertexArray& shadowParams) { - vec4 color = args.fColor; - float outerRadius = args.fOuterRadius; - - const FloatRect& bounds = args.fDevBounds; - - float umbraInset = args.fUmbraInset; - float minDim = 0.5f * std::min(bounds.getWidth(), bounds.getHeight()); - if (umbraInset > minDim) { - umbraInset = minDim; - } - - float xInner[4] = {bounds.left + umbraInset, bounds.right - umbraInset, - bounds.left + umbraInset, bounds.right - umbraInset}; - float xMid[4] = {bounds.left + outerRadius, bounds.right - outerRadius, - bounds.left + outerRadius, bounds.right - outerRadius}; - float xOuter[4] = {bounds.left, bounds.right, bounds.left, bounds.right}; - float yInner[4] = {bounds.top + umbraInset, bounds.top + umbraInset, bounds.bottom - umbraInset, - bounds.bottom - umbraInset}; - float yMid[4] = {bounds.top + outerRadius, bounds.top + outerRadius, - bounds.bottom - outerRadius, bounds.bottom - outerRadius}; - float yOuter[4] = {bounds.top, bounds.top, bounds.bottom, bounds.bottom}; - - float blurRadius = args.fBlurRadius; - - // In the case where we have to inset more for the umbra, our two triangles in the - // corner get skewed to a diamond rather than a square. To correct for that, - // we also skew the vectors we send to the shader that help define the circle. - // By doing so, we end up with a quarter circle in the corner rather than the - // elliptical curve. - - // This is a bit magical, but it gives us the correct results at extrema: - // a) umbraInset == outerRadius produces an orthogonal vector - // b) outerRadius == 0 produces a diagonal vector - // And visually the corner looks correct. - vec2 outerVec = vec2(outerRadius - umbraInset, -outerRadius - umbraInset); - outerVec = normalize(outerVec); - // We want the circle edge to fall fractionally along the diagonal at - // (sqrt(2)*(umbraInset - outerRadius) + outerRadius)/sqrt(2)*umbraInset - // - // Setting the components of the diagonal offset to the following value will give us that. - float diagVal = umbraInset / (SK_ScalarSqrt2 * (outerRadius - umbraInset) - outerRadius); - vec2 diagVec = vec2(diagVal, diagVal); - float distanceCorrection = umbraInset / blurRadius; - - int vertexCount = 0; - // build corner by corner - for (int i = 0; i < 4; ++i) { - // inner point - position[vertexCount] = vec2(xInner[i], yInner[i]); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, 0, distanceCorrection); - vertexCount++; - - // outer points - position[vertexCount] = vec2(xOuter[i], yInner[i]); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, -1, distanceCorrection); - vertexCount++; - - position[vertexCount] = vec2(xOuter[i], yMid[i]); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(outerVec.x, outerVec.y, distanceCorrection); - vertexCount++; - - position[vertexCount] = vec2(xOuter[i], yOuter[i]); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(diagVec.x, diagVec.y, distanceCorrection); - vertexCount++; - - position[vertexCount] = vec2(xMid[i], yOuter[i]); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(outerVec.x, outerVec.y, distanceCorrection); - vertexCount++; - - position[vertexCount] = vec2(xInner[i], yOuter[i]); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, -1, distanceCorrection); - vertexCount++; - } - - // Add the additional vertices for overstroked rrects. - // Effectively this is an additional stroked rrect, with its - // parameters equal to those in the center of the 9-patch. This will - // give constant values across this inner ring. - if (kOverstroke_RRectType == args.fType) { - float inset = umbraInset + args.fInnerRadius; - - // TL - position[vertexCount] = vec2(bounds.left + inset, bounds.top + inset); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, 0, distanceCorrection); - vertexCount++; - - // TR - position[vertexCount] = vec2(bounds.right - inset, bounds.top + inset); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, 0, distanceCorrection); - vertexCount++; - - // BL - position[vertexCount] = vec2(bounds.left + inset, bounds.bottom - inset); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, 0, distanceCorrection); - vertexCount++; - - // BR - position[vertexCount] = vec2(bounds.right - inset, bounds.bottom - inset); - shadowColor[vertexCount] = color; - shadowParams[vertexCount] = vec3(0, 0, distanceCorrection); - vertexCount++; - } -} - -int getVertexCountForGeometry(const Geometry& shadowGeometry) { - if (shadowGeometry.fIsCircle) { - return circle_type_to_vert_count(shadowGeometry.fType); - } - - return rrect_type_to_vert_count(shadowGeometry.fType); -} - -int getIndexCountForGeometry(const Geometry& shadowGeometry) { - if (shadowGeometry.fIsCircle) { - return circle_type_to_index_count(kStroke_RRectType == shadowGeometry.fType); - } - - return rrect_type_to_index_count(shadowGeometry.fType); -} - -void fillVerticesForGeometry(const Geometry& shadowGeometry, int /* vertexCount */, - Mesh::VertexArray position, Mesh::VertexArray shadowColor, - Mesh::VertexArray shadowParams) { - if (shadowGeometry.fIsCircle) { - fillInCircleVerts(shadowGeometry, shadowGeometry.fIsStroked, position, shadowColor, - shadowParams); - } else { - fillInRRectVerts(shadowGeometry, position, shadowColor, shadowParams); - } -} - -void fillIndicesForGeometry(const Geometry& shadowGeometry, int indexCount, - int startingVertexOffset, uint16_t* indices) { - if (shadowGeometry.fIsCircle) { - const uint16_t* primIndices = circle_type_to_indices(shadowGeometry.fIsStroked); - for (int i = 0; i < indexCount; ++i) { - indices[i] = primIndices[i] + startingVertexOffset; - } - } else { - const uint16_t* primIndices = rrect_type_to_indices(shadowGeometry.fType); - for (int i = 0; i < indexCount; ++i) { - indices[i] = primIndices[i] + startingVertexOffset; - } - } -} - -inline void GetSpotParams(float occluderZ, float lightX, float lightY, float lightZ, - float lightRadius, float& blurRadius, float& scale, vec2& translate) { - float zRatio = divide_and_pin(occluderZ, lightZ - occluderZ, 0.0f, 0.95f); - blurRadius = lightRadius * zRatio; - scale = divide_and_pin(lightZ, lightZ - occluderZ, 1.0f, 1.95f); - translate.x = -zRatio * lightX; - translate.y = -zRatio * lightY; -} - -static std::unique_ptr getShadowGeometry(const vec4& color, const FloatRect& devRect, - float devRadius, float blurRadius, - float insetWidth) { - // An insetWidth > 1/2 rect width or height indicates a simple fill. - const bool isCircle = ((devRadius >= devRect.getWidth()) && (devRadius >= devRect.getHeight())); - - FloatRect bounds = devRect; - float innerRadius = 0.0f; - float outerRadius = devRadius; - float umbraInset; - - RRectType type = kFill_RRectType; - if (isCircle) { - umbraInset = 0; - } else { - umbraInset = std::max(outerRadius, blurRadius); - } - - // If stroke is greater than width or height, this is still a fill, - // otherwise we compute stroke params. - if (isCircle) { - innerRadius = devRadius - insetWidth; - type = innerRadius > 0 ? kStroke_RRectType : kFill_RRectType; - } else { - if (insetWidth <= 0.5f * std::min(devRect.getWidth(), devRect.getHeight())) { - // We don't worry about a real inner radius, we just need to know if we - // need to create overstroke vertices. - innerRadius = std::max(insetWidth - umbraInset, 0.0f); - type = innerRadius > 0 ? kOverstroke_RRectType : kStroke_RRectType; - } - } - const bool isStroked = (kStroke_RRectType == type); - return std::make_unique(Geometry{color, outerRadius, umbraInset, innerRadius, - blurRadius, bounds, type, isCircle, isStroked}); -} - -std::unique_ptr getAmbientShadowGeometry(const FloatRect& casterRect, - float casterCornerRadius, float casterZ, - bool casterIsTranslucent, - const vec4& ambientColor) { - float devSpaceInsetWidth = AmbientBlurRadius(casterZ); - const float umbraRecipAlpha = AmbientRecipAlpha(casterZ); - const float devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha; - - // Outset the shadow rrect to the border of the penumbra - float ambientPathOutset = devSpaceInsetWidth; - FloatRect outsetRect(casterRect); - outsetRect.left -= ambientPathOutset; - outsetRect.top -= ambientPathOutset; - outsetRect.right += ambientPathOutset; - outsetRect.bottom += ambientPathOutset; - - float outsetRad = casterCornerRadius + ambientPathOutset; - if (casterIsTranslucent) { - // set a large inset to force a fill - devSpaceInsetWidth = outsetRect.getWidth(); - } - - return getShadowGeometry(ambientColor, outsetRect, std::abs(outsetRad), devSpaceAmbientBlur, - std::abs(devSpaceInsetWidth)); -} - -std::unique_ptr getSpotShadowGeometry(const FloatRect& casterRect, - float casterCornerRadius, float casterZ, - bool casterIsTranslucent, const vec4& spotColor, - const vec3& lightPosition, float lightRadius) { - float devSpaceSpotBlur; - float spotScale; - vec2 spotOffset; - GetSpotParams(casterZ, lightPosition.x, lightPosition.y, lightPosition.z, lightRadius, - devSpaceSpotBlur, spotScale, spotOffset); - // handle scale of radius due to CTM - const float srcSpaceSpotBlur = devSpaceSpotBlur; - - // Adjust translate for the effect of the scale. - spotOffset.x += spotScale; - spotOffset.y += spotScale; - - // Compute the transformed shadow rect - ui::Transform shadowTransform; - shadowTransform.set(spotOffset.x, spotOffset.y); - shadowTransform.set(spotScale, 0, 0, spotScale); - FloatRect spotShadowRect = shadowTransform.transform(casterRect); - float spotShadowRadius = casterCornerRadius * spotScale; - - // Compute the insetWidth - float blurOutset = srcSpaceSpotBlur; - float insetWidth = blurOutset; - if (casterIsTranslucent) { - // If transparent, just do a fill - insetWidth += spotShadowRect.getWidth(); - } else { - // For shadows, instead of using a stroke we specify an inset from the penumbra - // border. We want to extend this inset area so that it meets up with the caster - // geometry. The inset geometry will by default already be inset by the blur width. - // - // We compare the min and max corners inset by the radius between the original - // rrect and the shadow rrect. The distance between the two plus the difference - // between the scaled radius and the original radius gives the distance from the - // transformed shadow shape to the original shape in that corner. The max - // of these gives the maximum distance we need to cover. - // - // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to - // that to get the full insetWidth. - float maxOffset; - if (casterCornerRadius <= 0.f) { - // Manhattan distance works better for rects - maxOffset = std::max(std::max(std::abs(spotShadowRect.left - casterRect.left), - std::abs(spotShadowRect.top - casterRect.top)), - std::max(std::abs(spotShadowRect.right - casterRect.right), - std::abs(spotShadowRect.bottom - casterRect.bottom))); - } else { - float dr = spotShadowRadius - casterCornerRadius; - vec2 upperLeftOffset = vec2(spotShadowRect.left - casterRect.left + dr, - spotShadowRect.top - casterRect.top + dr); - vec2 lowerRightOffset = vec2(spotShadowRect.right - casterRect.right - dr, - spotShadowRect.bottom - casterRect.bottom - dr); - maxOffset = sqrt(std::max(dot(upperLeftOffset, lowerRightOffset), - dot(lowerRightOffset, lowerRightOffset))) + - dr; - } - insetWidth += std::max(blurOutset, maxOffset); - } - - // Outset the shadow rrect to the border of the penumbra - spotShadowRadius += blurOutset; - spotShadowRect.left -= blurOutset; - spotShadowRect.top -= blurOutset; - spotShadowRect.right += blurOutset; - spotShadowRect.bottom += blurOutset; - - return getShadowGeometry(spotColor, spotShadowRect, std::abs(spotShadowRadius), - 2.0f * devSpaceSpotBlur, std::abs(insetWidth)); -} - -void fillShadowTextureData(uint8_t* data, size_t shadowTextureWidth) { - for (int i = 0; i < shadowTextureWidth; i++) { - const float d = 1 - i / ((shadowTextureWidth * 1.0f) - 1.0f); - data[i] = static_cast((exp(-4.0f * d * d) - 0.018f) * 255); - } -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLSkiaShadowPort.h b/libs/renderengine/gl/GLSkiaShadowPort.h deleted file mode 100644 index 912c8bb7b3..0000000000 --- a/libs/renderengine/gl/GLSkiaShadowPort.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2019 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 -#include -#include - -namespace android { -namespace renderengine { -namespace gl { - -/** - * The shadow geometry logic and vertex generation code has been ported from skia shadow - * fast path OpenGL implementation to draw shadows around rects and rounded rects including - * circles. - * - * path: skia/src/gpu/GrRenderTargetContext.cpp GrRenderTargetContext::drawFastShadow - * - * Modifications made: - * - Switched to using std lib math functions - * - Fall off function is implemented in vertex shader rather than a shadow texture - * - Removed transformations applied on the caster rect since the caster will be in local - * coordinate space and will be transformed by the vertex shader. - */ - -enum RRectType { - kFill_RRectType, - kStroke_RRectType, - kOverstroke_RRectType, -}; - -struct Geometry { - vec4 fColor; - float fOuterRadius; - float fUmbraInset; - float fInnerRadius; - float fBlurRadius; - FloatRect fDevBounds; - RRectType fType; - bool fIsCircle; - bool fIsStroked; -}; - -std::unique_ptr getSpotShadowGeometry(const FloatRect& casterRect, - float casterCornerRadius, float casterZ, - bool casterIsTranslucent, const vec4& spotColor, - const vec3& lightPosition, float lightRadius); - -std::unique_ptr getAmbientShadowGeometry(const FloatRect& casterRect, - float casterCornerRadius, float casterZ, - bool casterIsTranslucent, - const vec4& ambientColor); - -int getVertexCountForGeometry(const Geometry& shadowGeometry); - -int getIndexCountForGeometry(const Geometry& shadowGeometry); - -void fillVerticesForGeometry(const Geometry& shadowGeometry, int vertexCount, - Mesh::VertexArray position, Mesh::VertexArray shadowColor, - Mesh::VertexArray shadowParams); - -void fillIndicesForGeometry(const Geometry& shadowGeometry, int indexCount, - int startingVertexOffset, uint16_t* indices); - -/** - * Maps shadow geometry 'alpha' varying (1 for darkest, 0 for transparent) to - * darkness at that spot. Values are determined by an exponential falloff - * function provided by UX. - * - * The texture is used for quick lookup in theshadow shader. - * - * textureData - filled with shadow texture data that needs to be at least of - * size textureWidth - * - * textureWidth - width of the texture, height is always 1 - */ -void fillShadowTextureData(uint8_t* textureData, size_t textureWidth); - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLVertexBuffer.cpp b/libs/renderengine/gl/GLVertexBuffer.cpp deleted file mode 100644 index e50c471b6d..0000000000 --- a/libs/renderengine/gl/GLVertexBuffer.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 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 ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "GLVertexBuffer.h" - -#include -#include -#include -#include - -namespace android { -namespace renderengine { -namespace gl { - -GLVertexBuffer::GLVertexBuffer() { - glGenBuffers(1, &mBufferName); -} - -GLVertexBuffer::~GLVertexBuffer() { - glDeleteBuffers(1, &mBufferName); -} - -void GLVertexBuffer::allocateBuffers(const GLfloat data[], const GLuint size) { - ATRACE_CALL(); - bind(); - glBufferData(GL_ARRAY_BUFFER, size * sizeof(GLfloat), data, GL_STATIC_DRAW); - unbind(); -} - -void GLVertexBuffer::bind() const { - glBindBuffer(GL_ARRAY_BUFFER, mBufferName); -} - -void GLVertexBuffer::unbind() const { - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLVertexBuffer.h b/libs/renderengine/gl/GLVertexBuffer.h deleted file mode 100644 index c0fd0c1b04..0000000000 --- a/libs/renderengine/gl/GLVertexBuffer.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 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. - */ - -#pragma once - -#include - -#include -#include -#include - -struct ANativeWindowBuffer; - -namespace android { -namespace renderengine { -namespace gl { - -class GLESRenderEngine; - -class GLVertexBuffer { -public: - explicit GLVertexBuffer(); - ~GLVertexBuffer(); - - void allocateBuffers(const GLfloat data[], const GLuint size); - uint32_t getBufferName() const { return mBufferName; } - void bind() const; - void unbind() const; - -private: - uint32_t mBufferName; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/ImageManager.cpp b/libs/renderengine/gl/ImageManager.cpp deleted file mode 100644 index 62566494f0..0000000000 --- a/libs/renderengine/gl/ImageManager.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2019 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_NDEBUG 0 -#undef LOG_TAG -#define LOG_TAG "RenderEngine" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include - -#include -#include -#include "GLESRenderEngine.h" -#include "ImageManager.h" - -namespace android { -namespace renderengine { -namespace gl { - -ImageManager::ImageManager(GLESRenderEngine* engine) : mEngine(engine) {} - -void ImageManager::initThread() { - mThread = std::thread([this]() { threadMain(); }); - pthread_setname_np(mThread.native_handle(), "ImageManager"); - // Use SCHED_FIFO to minimize jitter - struct sched_param param = {0}; - param.sched_priority = 2; - if (pthread_setschedparam(mThread.native_handle(), SCHED_FIFO, ¶m) != 0) { - ALOGE("Couldn't set SCHED_FIFO for ImageManager"); - } -} - -ImageManager::~ImageManager() { - { - std::lock_guard lock(mMutex); - mRunning = false; - } - mCondition.notify_all(); - if (mThread.joinable()) { - mThread.join(); - } -} - -void ImageManager::cacheAsync(const sp& buffer, - const std::shared_ptr& barrier) { - if (buffer == nullptr) { - { - std::lock_guard lock(barrier->mutex); - barrier->isOpen = true; - barrier->result = BAD_VALUE; - } - barrier->condition.notify_one(); - return; - } - ATRACE_CALL(); - QueueEntry entry = {QueueEntry::Operation::Insert, buffer, buffer->getId(), barrier}; - queueOperation(std::move(entry)); -} - -status_t ImageManager::cache(const sp& buffer) { - ATRACE_CALL(); - auto barrier = std::make_shared(); - cacheAsync(buffer, barrier); - std::lock_guard lock(barrier->mutex); - barrier->condition.wait(barrier->mutex, - [&]() REQUIRES(barrier->mutex) { return barrier->isOpen; }); - return barrier->result; -} - -void ImageManager::releaseAsync(uint64_t bufferId, const std::shared_ptr& barrier) { - ATRACE_CALL(); - QueueEntry entry = {QueueEntry::Operation::Delete, nullptr, bufferId, barrier}; - queueOperation(std::move(entry)); -} - -void ImageManager::queueOperation(const QueueEntry&& entry) { - { - std::lock_guard lock(mMutex); - mQueue.emplace(entry); - ATRACE_INT("ImageManagerQueueDepth", mQueue.size()); - } - mCondition.notify_one(); -} - -void ImageManager::threadMain() { - set_sched_policy(0, SP_FOREGROUND); - bool run; - { - std::lock_guard lock(mMutex); - run = mRunning; - } - while (run) { - QueueEntry entry; - { - std::lock_guard lock(mMutex); - mCondition.wait(mMutex, - [&]() REQUIRES(mMutex) { return !mQueue.empty() || !mRunning; }); - run = mRunning; - - if (!mRunning) { - // if mRunning is false, then ImageManager is being destroyed, so - // bail out now. - break; - } - - entry = mQueue.front(); - mQueue.pop(); - ATRACE_INT("ImageManagerQueueDepth", mQueue.size()); - } - - status_t result = NO_ERROR; - switch (entry.op) { - case QueueEntry::Operation::Delete: - mEngine->unbindExternalTextureBufferInternal(entry.bufferId); - break; - case QueueEntry::Operation::Insert: - result = mEngine->cacheExternalTextureBufferInternal(entry.buffer); - break; - } - if (entry.barrier != nullptr) { - { - std::lock_guard entryLock(entry.barrier->mutex); - entry.barrier->result = result; - entry.barrier->isOpen = true; - } - entry.barrier->condition.notify_one(); - } - } - - ALOGD("Reached end of threadMain, terminating ImageManager thread!"); -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/ImageManager.h b/libs/renderengine/gl/ImageManager.h deleted file mode 100644 index be67de8367..0000000000 --- a/libs/renderengine/gl/ImageManager.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2019 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 -#include -#include -#include - -#include - -namespace android { -namespace renderengine { -namespace gl { - -class GLESRenderEngine; - -class ImageManager { -public: - struct Barrier { - std::mutex mutex; - std::condition_variable_any condition; - bool isOpen GUARDED_BY(mutex) = false; - status_t result GUARDED_BY(mutex) = NO_ERROR; - }; - ImageManager(GLESRenderEngine* engine); - ~ImageManager(); - // Starts the background thread for the ImageManager - // We need this to guarantee that the class is fully-constructed before the - // thread begins running. - void initThread(); - void cacheAsync(const sp& buffer, const std::shared_ptr& barrier) - EXCLUDES(mMutex); - status_t cache(const sp& buffer); - void releaseAsync(uint64_t bufferId, const std::shared_ptr& barrier) EXCLUDES(mMutex); - -private: - struct QueueEntry { - enum class Operation { Delete, Insert }; - - Operation op = Operation::Delete; - sp buffer = nullptr; - uint64_t bufferId = 0; - std::shared_ptr barrier = nullptr; - }; - - void queueOperation(const QueueEntry&& entry); - void threadMain(); - GLESRenderEngine* const mEngine; - std::thread mThread; - std::condition_variable_any mCondition; - std::mutex mMutex; - std::queue mQueue GUARDED_BY(mMutex); - - bool mRunning GUARDED_BY(mMutex) = true; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/Program.cpp b/libs/renderengine/gl/Program.cpp deleted file mode 100644 index 26f6166761..0000000000 --- a/libs/renderengine/gl/Program.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/*Gluint - * Copyright 2013 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 "Program.h" - -#include - -#include -#include -#include -#include "ProgramCache.h" - -namespace android { -namespace renderengine { -namespace gl { - -Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment) - : mInitialized(false) { - GLuint vertexId = buildShader(vertex, GL_VERTEX_SHADER); - GLuint fragmentId = buildShader(fragment, GL_FRAGMENT_SHADER); - GLuint programId = glCreateProgram(); - glAttachShader(programId, vertexId); - glAttachShader(programId, fragmentId); - glBindAttribLocation(programId, position, "position"); - glBindAttribLocation(programId, texCoords, "texCoords"); - glBindAttribLocation(programId, cropCoords, "cropCoords"); - glBindAttribLocation(programId, shadowColor, "shadowColor"); - glBindAttribLocation(programId, shadowParams, "shadowParams"); - glLinkProgram(programId); - - GLint status; - glGetProgramiv(programId, GL_LINK_STATUS, &status); - if (status != GL_TRUE) { - ALOGE("Error while linking shaders:"); - GLint infoLen = 0; - glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &infoLen); - if (infoLen > 1) { - GLchar log[infoLen]; - glGetProgramInfoLog(programId, infoLen, 0, &log[0]); - ALOGE("%s", log); - } - glDetachShader(programId, vertexId); - glDetachShader(programId, fragmentId); - glDeleteShader(vertexId); - glDeleteShader(fragmentId); - glDeleteProgram(programId); - } else { - mProgram = programId; - mVertexShader = vertexId; - mFragmentShader = fragmentId; - mInitialized = true; - mProjectionMatrixLoc = glGetUniformLocation(programId, "projection"); - mTextureMatrixLoc = glGetUniformLocation(programId, "texture"); - mSamplerLoc = glGetUniformLocation(programId, "sampler"); - mColorLoc = glGetUniformLocation(programId, "color"); - mDisplayColorMatrixLoc = glGetUniformLocation(programId, "displayColorMatrix"); - mDisplayMaxLuminanceLoc = glGetUniformLocation(programId, "displayMaxLuminance"); - mMaxMasteringLuminanceLoc = glGetUniformLocation(programId, "maxMasteringLuminance"); - mMaxContentLuminanceLoc = glGetUniformLocation(programId, "maxContentLuminance"); - mInputTransformMatrixLoc = glGetUniformLocation(programId, "inputTransformMatrix"); - mOutputTransformMatrixLoc = glGetUniformLocation(programId, "outputTransformMatrix"); - mCornerRadiusLoc = glGetUniformLocation(programId, "cornerRadius"); - mCropCenterLoc = glGetUniformLocation(programId, "cropCenter"); - - // set-up the default values for our uniforms - glUseProgram(programId); - glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, mat4().asArray()); - glEnableVertexAttribArray(0); - } -} - -Program::~Program() { - glDetachShader(mProgram, mVertexShader); - glDetachShader(mProgram, mFragmentShader); - glDeleteShader(mVertexShader); - glDeleteShader(mFragmentShader); - glDeleteProgram(mProgram); -} - -bool Program::isValid() const { - return mInitialized; -} - -void Program::use() { - glUseProgram(mProgram); -} - -GLuint Program::getAttrib(const char* name) const { - // TODO: maybe use a local cache - return glGetAttribLocation(mProgram, name); -} - -GLint Program::getUniform(const char* name) const { - // TODO: maybe use a local cache - return glGetUniformLocation(mProgram, name); -} - -GLuint Program::buildShader(const char* source, GLenum type) { - GLuint shader = glCreateShader(type); - glShaderSource(shader, 1, &source, 0); - glCompileShader(shader); - GLint status; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - if (status != GL_TRUE) { - // Some drivers return wrong values for GL_INFO_LOG_LENGTH - // use a fixed size instead - GLchar log[512]; - glGetShaderInfoLog(shader, sizeof(log), 0, log); - ALOGE("Error while compiling shader: \n%s\n%s", source, log); - glDeleteShader(shader); - return 0; - } - return shader; -} - -void Program::setUniforms(const Description& desc) { - // TODO: we should have a mechanism here to not always reset uniforms that - // didn't change for this program. - - if (mSamplerLoc >= 0) { - glUniform1i(mSamplerLoc, 0); - glUniformMatrix4fv(mTextureMatrixLoc, 1, GL_FALSE, desc.texture.getMatrix().asArray()); - } - if (mColorLoc >= 0) { - const float color[4] = {desc.color.r, desc.color.g, desc.color.b, desc.color.a}; - glUniform4fv(mColorLoc, 1, color); - } - if (mDisplayColorMatrixLoc >= 0) { - glUniformMatrix4fv(mDisplayColorMatrixLoc, 1, GL_FALSE, desc.displayColorMatrix.asArray()); - } - if (mInputTransformMatrixLoc >= 0) { - mat4 inputTransformMatrix = desc.inputTransformMatrix; - glUniformMatrix4fv(mInputTransformMatrixLoc, 1, GL_FALSE, inputTransformMatrix.asArray()); - } - if (mOutputTransformMatrixLoc >= 0) { - // The output transform matrix and color matrix can be combined as one matrix - // that is applied right before applying OETF. - mat4 outputTransformMatrix = desc.colorMatrix * desc.outputTransformMatrix; - glUniformMatrix4fv(mOutputTransformMatrixLoc, 1, GL_FALSE, outputTransformMatrix.asArray()); - } - if (mDisplayMaxLuminanceLoc >= 0) { - glUniform1f(mDisplayMaxLuminanceLoc, desc.displayMaxLuminance); - } - if (mMaxMasteringLuminanceLoc >= 0) { - glUniform1f(mMaxMasteringLuminanceLoc, desc.maxMasteringLuminance); - } - if (mMaxContentLuminanceLoc >= 0) { - glUniform1f(mMaxContentLuminanceLoc, desc.maxContentLuminance); - } - if (mCornerRadiusLoc >= 0) { - glUniform1f(mCornerRadiusLoc, desc.cornerRadius); - } - if (mCropCenterLoc >= 0) { - glUniform2f(mCropCenterLoc, desc.cropSize.x / 2.0f, desc.cropSize.y / 2.0f); - } - // these uniforms are always present - glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.projectionMatrix.asArray()); -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/Program.h b/libs/renderengine/gl/Program.h deleted file mode 100644 index 41f1bf865e..0000000000 --- a/libs/renderengine/gl/Program.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SF_RENDER_ENGINE_PROGRAM_H -#define SF_RENDER_ENGINE_PROGRAM_H - -#include - -#include -#include -#include "ProgramCache.h" - -namespace android { - -class String8; - -namespace renderengine { -namespace gl { - -/* - * Abstracts a GLSL program comprising a vertex and fragment shader - */ -class Program { -public: - // known locations for position and texture coordinates - enum { - /* position of each vertex for vertex shader */ - position = 0, - - /* UV coordinates for texture mapping */ - texCoords = 1, - - /* Crop coordinates, in pixels */ - cropCoords = 2, - - /* Shadow color */ - shadowColor = 3, - - /* Shadow params */ - shadowParams = 4, - }; - - Program(const ProgramCache::Key& needs, const char* vertex, const char* fragment); - ~Program(); - - /* whether this object is usable */ - bool isValid() const; - - /* Binds this program to the GLES context */ - void use(); - - /* Returns the location of the specified attribute */ - GLuint getAttrib(const char* name) const; - - /* Returns the location of the specified uniform */ - GLint getUniform(const char* name) const; - - /* set-up uniforms from the description */ - void setUniforms(const Description& desc); - -private: - GLuint buildShader(const char* source, GLenum type); - - // whether the initialization succeeded - bool mInitialized; - - // Name of the OpenGL program and shaders - GLuint mProgram; - GLuint mVertexShader; - GLuint mFragmentShader; - - /* location of the projection matrix uniform */ - GLint mProjectionMatrixLoc; - - /* location of the texture matrix uniform */ - GLint mTextureMatrixLoc; - - /* location of the sampler uniform */ - GLint mSamplerLoc; - - /* location of the color uniform */ - GLint mColorLoc; - - /* location of display luminance uniform */ - GLint mDisplayMaxLuminanceLoc; - /* location of max mastering luminance uniform */ - GLint mMaxMasteringLuminanceLoc; - /* location of max content luminance uniform */ - GLint mMaxContentLuminanceLoc; - - /* location of transform matrix */ - GLint mInputTransformMatrixLoc; - GLint mOutputTransformMatrixLoc; - GLint mDisplayColorMatrixLoc; - - /* location of corner radius uniform */ - GLint mCornerRadiusLoc; - - /* location of surface crop origin uniform, for rounded corner clipping */ - GLint mCropCenterLoc; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android - -#endif /* SF_RENDER_ENGINE_PROGRAM_H */ diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp deleted file mode 100644 index 96ccf5c512..0000000000 --- a/libs/renderengine/gl/ProgramCache.cpp +++ /dev/null @@ -1,802 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "ProgramCache.h" - -#include -#include -#include -#include -#include -#include -#include "Program.h" - -ANDROID_SINGLETON_STATIC_INSTANCE(android::renderengine::gl::ProgramCache) - -namespace android { -namespace renderengine { -namespace gl { - -/* - * A simple formatter class to automatically add the endl and - * manage the indentation. - */ - -class Formatter; -static Formatter& indent(Formatter& f); -static Formatter& dedent(Formatter& f); - -class Formatter { - String8 mString; - int mIndent; - typedef Formatter& (*FormaterManipFunc)(Formatter&); - friend Formatter& indent(Formatter& f); - friend Formatter& dedent(Formatter& f); - -public: - Formatter() : mIndent(0) {} - - String8 getString() const { return mString; } - - friend Formatter& operator<<(Formatter& out, const char* in) { - for (int i = 0; i < out.mIndent; i++) { - out.mString.append(" "); - } - out.mString.append(in); - out.mString.append("\n"); - return out; - } - friend inline Formatter& operator<<(Formatter& out, const String8& in) { - return operator<<(out, in.string()); - } - friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) { - return (*func)(to); - } -}; -Formatter& indent(Formatter& f) { - f.mIndent++; - return f; -} -Formatter& dedent(Formatter& f) { - f.mIndent--; - return f; -} - -void ProgramCache::primeCache(EGLContext context, bool toneMapperShaderOnly) { - auto& cache = mCaches[context]; - uint32_t shaderCount = 0; - - if (toneMapperShaderOnly) { - Key shaderKey; - // base settings used by HDR->SDR tonemap only - shaderKey.set(Key::BLEND_MASK | Key::INPUT_TRANSFORM_MATRIX_MASK | - Key::OUTPUT_TRANSFORM_MATRIX_MASK | Key::OUTPUT_TF_MASK | - Key::OPACITY_MASK | Key::ALPHA_MASK | - Key::ROUNDED_CORNERS_MASK | Key::TEXTURE_MASK, - Key::BLEND_NORMAL | Key::INPUT_TRANSFORM_MATRIX_ON | - Key::OUTPUT_TRANSFORM_MATRIX_ON | Key::OUTPUT_TF_SRGB | - Key::OPACITY_OPAQUE | Key::ALPHA_EQ_ONE | - Key::ROUNDED_CORNERS_OFF | Key::TEXTURE_EXT); - for (int i = 0; i < 4; i++) { - // Cache input transfer for HLG & ST2084 - shaderKey.set(Key::INPUT_TF_MASK, (i & 1) ? - Key::INPUT_TF_HLG : Key::INPUT_TF_ST2084); - - if (cache.count(shaderKey) == 0) { - cache.emplace(shaderKey, generateProgram(shaderKey)); - shaderCount++; - } - } - return; - } - - uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK - | Key::ROUNDED_CORNERS_MASK; - // Prime the cache for all combinations of the above masks, - // leaving off the experimental color matrix mask options. - - nsecs_t timeBefore = systemTime(); - for (uint32_t keyVal = 0; keyVal <= keyMask; keyVal++) { - Key shaderKey; - shaderKey.set(keyMask, keyVal); - uint32_t tex = shaderKey.getTextureTarget(); - if (tex != Key::TEXTURE_OFF && tex != Key::TEXTURE_EXT && tex != Key::TEXTURE_2D) { - continue; - } - if (cache.count(shaderKey) == 0) { - cache.emplace(shaderKey, generateProgram(shaderKey)); - shaderCount++; - } - } - - // Prime for sRGB->P3 conversion - Key shaderKey; - shaderKey.set(Key::BLEND_MASK | Key::OUTPUT_TRANSFORM_MATRIX_MASK | Key::INPUT_TF_MASK | - Key::OUTPUT_TF_MASK, - Key::BLEND_PREMULT | Key::OUTPUT_TRANSFORM_MATRIX_ON | Key::INPUT_TF_SRGB | - Key::OUTPUT_TF_SRGB); - for (int i = 0; i < 16; i++) { - shaderKey.set(Key::OPACITY_MASK, (i & 1) ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT); - shaderKey.set(Key::ALPHA_MASK, (i & 2) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE); - - // Cache rounded corners - shaderKey.set(Key::ROUNDED_CORNERS_MASK, - (i & 4) ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF); - - // Cache texture off option for window transition - shaderKey.set(Key::TEXTURE_MASK, (i & 8) ? Key::TEXTURE_EXT : Key::TEXTURE_OFF); - if (cache.count(shaderKey) == 0) { - cache.emplace(shaderKey, generateProgram(shaderKey)); - shaderCount++; - } - } - - nsecs_t timeAfter = systemTime(); - float compileTimeMs = static_cast(timeAfter - timeBefore) / 1.0E6; - ALOGD("shader cache generated - %u shaders in %f ms\n", shaderCount, compileTimeMs); -} - -ProgramCache::Key ProgramCache::computeKey(const Description& description) { - Key needs; - needs.set(Key::TEXTURE_MASK, - !description.textureEnabled ? Key::TEXTURE_OFF - : description.texture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES - ? Key::TEXTURE_EXT - : description.texture.getTextureTarget() == GL_TEXTURE_2D ? Key::TEXTURE_2D - : Key::TEXTURE_OFF) - .set(Key::ALPHA_MASK, (description.color.a < 1) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE) - .set(Key::BLEND_MASK, - description.isPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL) - .set(Key::OPACITY_MASK, - description.isOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT) - .set(Key::Key::INPUT_TRANSFORM_MATRIX_MASK, - description.hasInputTransformMatrix() ? Key::INPUT_TRANSFORM_MATRIX_ON - : Key::INPUT_TRANSFORM_MATRIX_OFF) - .set(Key::Key::OUTPUT_TRANSFORM_MATRIX_MASK, - description.hasOutputTransformMatrix() || description.hasColorMatrix() - ? Key::OUTPUT_TRANSFORM_MATRIX_ON - : Key::OUTPUT_TRANSFORM_MATRIX_OFF) - .set(Key::Key::DISPLAY_COLOR_TRANSFORM_MATRIX_MASK, - description.hasDisplayColorMatrix() ? Key::DISPLAY_COLOR_TRANSFORM_MATRIX_ON - : Key::DISPLAY_COLOR_TRANSFORM_MATRIX_OFF) - .set(Key::ROUNDED_CORNERS_MASK, - description.cornerRadius > 0 ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF) - .set(Key::SHADOW_MASK, description.drawShadows ? Key::SHADOW_ON : Key::SHADOW_OFF); - - if (needs.hasTransformMatrix() || - (description.inputTransferFunction != description.outputTransferFunction)) { - switch (description.inputTransferFunction) { - case Description::TransferFunction::LINEAR: - default: - needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_LINEAR); - break; - case Description::TransferFunction::SRGB: - needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_SRGB); - break; - case Description::TransferFunction::ST2084: - needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_ST2084); - break; - case Description::TransferFunction::HLG: - needs.set(Key::INPUT_TF_MASK, Key::INPUT_TF_HLG); - break; - } - - switch (description.outputTransferFunction) { - case Description::TransferFunction::LINEAR: - default: - needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_LINEAR); - break; - case Description::TransferFunction::SRGB: - needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_SRGB); - break; - case Description::TransferFunction::ST2084: - needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_ST2084); - break; - case Description::TransferFunction::HLG: - needs.set(Key::OUTPUT_TF_MASK, Key::OUTPUT_TF_HLG); - break; - } - } - - return needs; -} - -// Generate EOTF that converts signal values to relative display light, -// both normalized to [0, 1]. -void ProgramCache::generateEOTF(Formatter& fs, const Key& needs) { - switch (needs.getInputTF()) { - case Key::INPUT_TF_SRGB: - fs << R"__SHADER__( - float EOTF_sRGB(float srgb) { - return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4); - } - - vec3 EOTF_sRGB(const vec3 srgb) { - return vec3(EOTF_sRGB(srgb.r), EOTF_sRGB(srgb.g), EOTF_sRGB(srgb.b)); - } - - vec3 EOTF(const vec3 srgb) { - return sign(srgb.rgb) * EOTF_sRGB(abs(srgb.rgb)); - } - )__SHADER__"; - break; - case Key::INPUT_TF_ST2084: - fs << R"__SHADER__( - vec3 EOTF(const highp vec3 color) { - const highp float m1 = (2610.0 / 4096.0) / 4.0; - const highp float m2 = (2523.0 / 4096.0) * 128.0; - const highp float c1 = (3424.0 / 4096.0); - const highp float c2 = (2413.0 / 4096.0) * 32.0; - const highp float c3 = (2392.0 / 4096.0) * 32.0; - - highp vec3 tmp = pow(clamp(color, 0.0, 1.0), 1.0 / vec3(m2)); - tmp = max(tmp - c1, 0.0) / (c2 - c3 * tmp); - return pow(tmp, 1.0 / vec3(m1)); - } - )__SHADER__"; - break; - case Key::INPUT_TF_HLG: - fs << R"__SHADER__( - highp float EOTF_channel(const highp float channel) { - const highp float a = 0.17883277; - const highp float b = 0.28466892; - const highp float c = 0.55991073; - return channel <= 0.5 ? channel * channel / 3.0 : - (exp((channel - c) / a) + b) / 12.0; - } - - vec3 EOTF(const highp vec3 color) { - return vec3(EOTF_channel(color.r), EOTF_channel(color.g), - EOTF_channel(color.b)); - } - )__SHADER__"; - break; - default: - fs << R"__SHADER__( - vec3 EOTF(const vec3 linear) { - return linear; - } - )__SHADER__"; - break; - } -} - -void ProgramCache::generateToneMappingProcess(Formatter& fs, const Key& needs) { - // Convert relative light to absolute light. - switch (needs.getInputTF()) { - case Key::INPUT_TF_ST2084: - fs << R"__SHADER__( - highp vec3 ScaleLuminance(highp vec3 color) { - return color * 10000.0; - } - )__SHADER__"; - break; - case Key::INPUT_TF_HLG: - fs << R"__SHADER__( - highp vec3 ScaleLuminance(highp vec3 color) { - // The formula is: - // alpha * pow(Y, gamma - 1.0) * color + beta; - // where alpha is 1000.0, gamma is 1.2, beta is 0.0. - return color * 1000.0 * pow(color.y, 0.2); - } - )__SHADER__"; - break; - default: - fs << R"__SHADER__( - highp vec3 ScaleLuminance(highp vec3 color) { - return color * displayMaxLuminance; - } - )__SHADER__"; - break; - } - - // Tone map absolute light to display luminance range. - switch (needs.getInputTF()) { - case Key::INPUT_TF_ST2084: - case Key::INPUT_TF_HLG: - switch (needs.getOutputTF()) { - case Key::OUTPUT_TF_HLG: - // Right now when mixed PQ and HLG contents are presented, - // HLG content will always be converted to PQ. However, for - // completeness, we simply clamp the value to [0.0, 1000.0]. - fs << R"__SHADER__( - highp vec3 ToneMap(highp vec3 color) { - return clamp(color, 0.0, 1000.0); - } - )__SHADER__"; - break; - case Key::OUTPUT_TF_ST2084: - fs << R"__SHADER__( - highp vec3 ToneMap(highp vec3 color) { - return color; - } - )__SHADER__"; - break; - default: - fs << R"__SHADER__( - highp vec3 ToneMap(highp vec3 color) { - float maxMasteringLumi = maxMasteringLuminance; - float maxContentLumi = maxContentLuminance; - float maxInLumi = min(maxMasteringLumi, maxContentLumi); - float maxOutLumi = displayMaxLuminance; - - float nits = color.y; - - // clamp to max input luminance - nits = clamp(nits, 0.0, maxInLumi); - - // scale [0.0, maxInLumi] to [0.0, maxOutLumi] - if (maxInLumi <= maxOutLumi) { - return color * (maxOutLumi / maxInLumi); - } else { - // three control points - const float x0 = 10.0; - const float y0 = 17.0; - float x1 = maxOutLumi * 0.75; - float y1 = x1; - float x2 = x1 + (maxInLumi - x1) / 2.0; - float y2 = y1 + (maxOutLumi - y1) * 0.75; - - // horizontal distances between the last three control points - float h12 = x2 - x1; - float h23 = maxInLumi - x2; - // tangents at the last three control points - float m1 = (y2 - y1) / h12; - float m3 = (maxOutLumi - y2) / h23; - float m2 = (m1 + m3) / 2.0; - - if (nits < x0) { - // scale [0.0, x0] to [0.0, y0] linearly - float slope = y0 / x0; - return color * slope; - } else if (nits < x1) { - // scale [x0, x1] to [y0, y1] linearly - float slope = (y1 - y0) / (x1 - x0); - nits = y0 + (nits - x0) * slope; - } else if (nits < x2) { - // scale [x1, x2] to [y1, y2] using Hermite interp - float t = (nits - x1) / h12; - nits = (y1 * (1.0 + 2.0 * t) + h12 * m1 * t) * (1.0 - t) * (1.0 - t) + - (y2 * (3.0 - 2.0 * t) + h12 * m2 * (t - 1.0)) * t * t; - } else { - // scale [x2, maxInLumi] to [y2, maxOutLumi] using Hermite interp - float t = (nits - x2) / h23; - nits = (y2 * (1.0 + 2.0 * t) + h23 * m2 * t) * (1.0 - t) * (1.0 - t) + - (maxOutLumi * (3.0 - 2.0 * t) + h23 * m3 * (t - 1.0)) * t * t; - } - } - - // color.y is greater than x0 and is thus non-zero - return color * (nits / color.y); - } - )__SHADER__"; - break; - } - break; - default: - // inverse tone map; the output luminance can be up to maxOutLumi. - fs << R"__SHADER__( - highp vec3 ToneMap(highp vec3 color) { - const float maxOutLumi = 3000.0; - - const float x0 = 5.0; - const float y0 = 2.5; - float x1 = displayMaxLuminance * 0.7; - float y1 = maxOutLumi * 0.15; - float x2 = displayMaxLuminance * 0.9; - float y2 = maxOutLumi * 0.45; - float x3 = displayMaxLuminance; - float y3 = maxOutLumi; - - float c1 = y1 / 3.0; - float c2 = y2 / 2.0; - float c3 = y3 / 1.5; - - float nits = color.y; - - float scale; - if (nits <= x0) { - // scale [0.0, x0] to [0.0, y0] linearly - const float slope = y0 / x0; - return color * slope; - } else if (nits <= x1) { - // scale [x0, x1] to [y0, y1] using a curve - float t = (nits - x0) / (x1 - x0); - nits = (1.0 - t) * (1.0 - t) * y0 + 2.0 * (1.0 - t) * t * c1 + t * t * y1; - } else if (nits <= x2) { - // scale [x1, x2] to [y1, y2] using a curve - float t = (nits - x1) / (x2 - x1); - nits = (1.0 - t) * (1.0 - t) * y1 + 2.0 * (1.0 - t) * t * c2 + t * t * y2; - } else { - // scale [x2, x3] to [y2, y3] using a curve - float t = (nits - x2) / (x3 - x2); - nits = (1.0 - t) * (1.0 - t) * y2 + 2.0 * (1.0 - t) * t * c3 + t * t * y3; - } - - // color.y is greater than x0 and is thus non-zero - return color * (nits / color.y); - } - )__SHADER__"; - break; - } - - // convert absolute light to relative light. - switch (needs.getOutputTF()) { - case Key::OUTPUT_TF_ST2084: - fs << R"__SHADER__( - highp vec3 NormalizeLuminance(highp vec3 color) { - return color / 10000.0; - } - )__SHADER__"; - break; - case Key::OUTPUT_TF_HLG: - fs << R"__SHADER__( - highp vec3 NormalizeLuminance(highp vec3 color) { - return color / 1000.0 * pow(color.y / 1000.0, -0.2 / 1.2); - } - )__SHADER__"; - break; - default: - fs << R"__SHADER__( - highp vec3 NormalizeLuminance(highp vec3 color) { - return color / displayMaxLuminance; - } - )__SHADER__"; - break; - } -} - -// Generate OOTF that modifies the relative scence light to relative display light. -void ProgramCache::generateOOTF(Formatter& fs, const ProgramCache::Key& needs) { - if (!needs.needsToneMapping()) { - fs << R"__SHADER__( - highp vec3 OOTF(const highp vec3 color) { - return color; - } - )__SHADER__"; - } else { - generateToneMappingProcess(fs, needs); - fs << R"__SHADER__( - highp vec3 OOTF(const highp vec3 color) { - return NormalizeLuminance(ToneMap(ScaleLuminance(color))); - } - )__SHADER__"; - } -} - -// Generate OETF that converts relative display light to signal values, -// both normalized to [0, 1] -void ProgramCache::generateOETF(Formatter& fs, const Key& needs) { - switch (needs.getOutputTF()) { - case Key::OUTPUT_TF_SRGB: - fs << R"__SHADER__( - float OETF_sRGB(const float linear) { - return linear <= 0.0031308 ? - linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055; - } - - vec3 OETF_sRGB(const vec3 linear) { - return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b)); - } - - vec3 OETF(const vec3 linear) { - return sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)); - } - )__SHADER__"; - break; - case Key::OUTPUT_TF_ST2084: - fs << R"__SHADER__( - vec3 OETF(const vec3 linear) { - const highp float m1 = (2610.0 / 4096.0) / 4.0; - const highp float m2 = (2523.0 / 4096.0) * 128.0; - const highp float c1 = (3424.0 / 4096.0); - const highp float c2 = (2413.0 / 4096.0) * 32.0; - const highp float c3 = (2392.0 / 4096.0) * 32.0; - - highp vec3 tmp = pow(linear, vec3(m1)); - tmp = (c1 + c2 * tmp) / (1.0 + c3 * tmp); - return pow(tmp, vec3(m2)); - } - )__SHADER__"; - break; - case Key::OUTPUT_TF_HLG: - fs << R"__SHADER__( - highp float OETF_channel(const highp float channel) { - const highp float a = 0.17883277; - const highp float b = 0.28466892; - const highp float c = 0.55991073; - return channel <= 1.0 / 12.0 ? sqrt(3.0 * channel) : - a * log(12.0 * channel - b) + c; - } - - vec3 OETF(const highp vec3 color) { - return vec3(OETF_channel(color.r), OETF_channel(color.g), - OETF_channel(color.b)); - } - )__SHADER__"; - break; - default: - fs << R"__SHADER__( - vec3 OETF(const vec3 linear) { - return linear; - } - )__SHADER__"; - break; - } -} - -String8 ProgramCache::generateVertexShader(const Key& needs) { - Formatter vs; - if (needs.hasTextureCoords()) { - vs << "attribute vec4 texCoords;" - << "varying vec2 outTexCoords;"; - } - if (needs.hasRoundedCorners()) { - vs << "attribute lowp vec4 cropCoords;"; - vs << "varying lowp vec2 outCropCoords;"; - } - if (needs.drawShadows()) { - vs << "attribute lowp vec4 shadowColor;"; - vs << "varying lowp vec4 outShadowColor;"; - vs << "attribute lowp vec4 shadowParams;"; - vs << "varying lowp vec3 outShadowParams;"; - } - vs << "attribute vec4 position;" - << "uniform mat4 projection;" - << "uniform mat4 texture;" - << "void main(void) {" << indent << "gl_Position = projection * position;"; - if (needs.hasTextureCoords()) { - vs << "outTexCoords = (texture * texCoords).st;"; - } - if (needs.hasRoundedCorners()) { - vs << "outCropCoords = cropCoords.st;"; - } - if (needs.drawShadows()) { - vs << "outShadowColor = shadowColor;"; - vs << "outShadowParams = shadowParams.xyz;"; - } - vs << dedent << "}"; - return vs.getString(); -} - -String8 ProgramCache::generateFragmentShader(const Key& needs) { - Formatter fs; - if (needs.getTextureTarget() == Key::TEXTURE_EXT) { - fs << "#extension GL_OES_EGL_image_external : require"; - } - - // default precision is required-ish in fragment shaders - fs << "precision mediump float;"; - - if (needs.getTextureTarget() == Key::TEXTURE_EXT) { - fs << "uniform samplerExternalOES sampler;"; - } else if (needs.getTextureTarget() == Key::TEXTURE_2D) { - fs << "uniform sampler2D sampler;"; - } - - if (needs.hasTextureCoords()) { - fs << "varying highp vec2 outTexCoords;"; - } - - if (needs.hasRoundedCorners()) { - // Rounded corners implementation using a signed distance function. - fs << R"__SHADER__( - uniform float cornerRadius; - uniform vec2 cropCenter; - varying vec2 outCropCoords; - - /** - * This function takes the current crop coordinates and calculates an alpha value based - * on the corner radius and distance from the crop center. - */ - float applyCornerRadius(vec2 cropCoords) - { - vec2 position = cropCoords - cropCenter; - // Scale down the dist vector here, as otherwise large corner - // radii can cause floating point issues when computing the norm - vec2 dist = (abs(position) - cropCenter + vec2(cornerRadius)) / 16.0; - // Once we've found the norm, then scale back up. - float plane = length(max(dist, vec2(0.0))) * 16.0; - return 1.0 - clamp(plane - cornerRadius, 0.0, 1.0); - } - )__SHADER__"; - } - - if (needs.drawShadows()) { - fs << R"__SHADER__( - varying lowp vec4 outShadowColor; - varying lowp vec3 outShadowParams; - - /** - * Returns the shadow color. - */ - vec4 getShadowColor() - { - lowp float d = length(outShadowParams.xy); - vec2 uv = vec2(outShadowParams.z * (1.0 - d), 0.5); - lowp float factor = texture2D(sampler, uv).a; - return outShadowColor * factor; - } - )__SHADER__"; - } - - if (needs.getTextureTarget() == Key::TEXTURE_OFF || needs.hasAlpha()) { - fs << "uniform vec4 color;"; - } - - if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF()) || - needs.hasDisplayColorMatrix()) { - if (needs.needsToneMapping()) { - fs << "uniform float displayMaxLuminance;"; - fs << "uniform float maxMasteringLuminance;"; - fs << "uniform float maxContentLuminance;"; - } - - if (needs.hasInputTransformMatrix()) { - fs << "uniform mat4 inputTransformMatrix;"; - fs << R"__SHADER__( - highp vec3 InputTransform(const highp vec3 color) { - return clamp(vec3(inputTransformMatrix * vec4(color, 1.0)), 0.0, 1.0); - } - )__SHADER__"; - } else { - fs << R"__SHADER__( - highp vec3 InputTransform(const highp vec3 color) { - return color; - } - )__SHADER__"; - } - - // the transformation from a wider colorspace to a narrower one can - // result in >1.0 or <0.0 pixel values - if (needs.hasOutputTransformMatrix()) { - fs << "uniform mat4 outputTransformMatrix;"; - fs << R"__SHADER__( - highp vec3 OutputTransform(const highp vec3 color) { - return clamp(vec3(outputTransformMatrix * vec4(color, 1.0)), 0.0, 1.0); - } - )__SHADER__"; - } else { - fs << R"__SHADER__( - highp vec3 OutputTransform(const highp vec3 color) { - return clamp(color, 0.0, 1.0); - } - )__SHADER__"; - } - - if (needs.hasDisplayColorMatrix()) { - fs << "uniform mat4 displayColorMatrix;"; - fs << R"__SHADER__( - highp vec3 DisplayColorMatrix(const highp vec3 color) { - return clamp(vec3(displayColorMatrix * vec4(color, 1.0)), 0.0, 1.0); - } - )__SHADER__"; - } else { - fs << R"__SHADER__( - highp vec3 DisplayColorMatrix(const highp vec3 color) { - return color; - } - )__SHADER__"; - } - - generateEOTF(fs, needs); - generateOOTF(fs, needs); - generateOETF(fs, needs); - } - - fs << "void main(void) {" << indent; - if (needs.drawShadows()) { - fs << "gl_FragColor = getShadowColor();"; - } else { - if (needs.isTexturing()) { - fs << "gl_FragColor = texture2D(sampler, outTexCoords);"; - } else { - fs << "gl_FragColor.rgb = color.rgb;"; - fs << "gl_FragColor.a = 1.0;"; - } - if (needs.isOpaque()) { - fs << "gl_FragColor.a = 1.0;"; - } - } - - if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF()) || - needs.hasDisplayColorMatrix()) { - if (!needs.isOpaque() && needs.isPremultiplied()) { - // un-premultiply if needed before linearization - // avoid divide by 0 by adding 0.5/256 to the alpha channel - fs << "gl_FragColor.rgb = gl_FragColor.rgb / (gl_FragColor.a + 0.0019);"; - } - fs << "gl_FragColor.rgb = " - "DisplayColorMatrix(OETF(OutputTransform(OOTF(InputTransform(EOTF(gl_FragColor.rgb)))" - ")));"; - - if (!needs.isOpaque() && needs.isPremultiplied()) { - // and re-premultiply if needed after gamma correction - fs << "gl_FragColor.rgb = gl_FragColor.rgb * (gl_FragColor.a + 0.0019);"; - } - } - - /* - * Whether applying layer alpha before or after color transform doesn't matter, - * as long as we can undo premultiplication. But we cannot un-premultiply - * for color transform if the layer alpha = 0, e.g. 0 / (0 + 0.0019) = 0. - */ - if (!needs.drawShadows()) { - if (needs.hasAlpha()) { - // modulate the current alpha value with alpha set - if (needs.isPremultiplied()) { - // ... and the color too if we're premultiplied - fs << "gl_FragColor *= color.a;"; - } else { - fs << "gl_FragColor.a *= color.a;"; - } - } - } - - if (needs.hasRoundedCorners()) { - if (needs.isPremultiplied()) { - fs << "gl_FragColor *= vec4(applyCornerRadius(outCropCoords));"; - } else { - fs << "gl_FragColor.a *= applyCornerRadius(outCropCoords);"; - } - } - - fs << dedent << "}"; - return fs.getString(); -} - -std::unique_ptr ProgramCache::generateProgram(const Key& needs) { - ATRACE_CALL(); - - // vertex shader - String8 vs = generateVertexShader(needs); - - // fragment shader - String8 fs = generateFragmentShader(needs); - - return std::make_unique(needs, vs.string(), fs.string()); -} - -void ProgramCache::useProgram(EGLContext context, const Description& description) { - // generate the key for the shader based on the description - Key needs(computeKey(description)); - - // look-up the program in the cache - auto& cache = mCaches[context]; - auto it = cache.find(needs); - if (it == cache.end()) { - // we didn't find our program, so generate one... - nsecs_t time = systemTime(); - it = cache.emplace(needs, generateProgram(needs)).first; - time = systemTime() - time; - - ALOGV(">>> generated new program for context %p: needs=%08X, time=%u ms (%zu programs)", - context, needs.mKey, uint32_t(ns2ms(time)), cache.size()); - } - - // here we have a suitable program for this description - std::unique_ptr& program = it->second; - if (program->isValid()) { - program->use(); - program->setUniforms(description); - } -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h deleted file mode 100644 index 83fef8e1db..0000000000 --- a/libs/renderengine/gl/ProgramCache.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SF_RENDER_ENGINE_PROGRAMCACHE_H -#define SF_RENDER_ENGINE_PROGRAMCACHE_H - -#include -#include - -#include -#include -#include -#include -#include - -namespace android { - -class String8; - -namespace renderengine { - -struct Description; - -namespace gl { - -class Formatter; -class Program; - -/* - * This class generates GLSL programs suitable to handle a given - * Description. It's responsible for figuring out what to - * generate from a Description. - * It also maintains a cache of these Programs. - */ -class ProgramCache : public Singleton { -public: - /* - * Key is used to retrieve a Program in the cache. - * A Key is generated from a Description. - */ - class Key { - friend class ProgramCache; - typedef uint32_t key_t; - key_t mKey; - - public: - enum { - BLEND_SHIFT = 0, - BLEND_MASK = 1 << BLEND_SHIFT, - BLEND_PREMULT = 1 << BLEND_SHIFT, - BLEND_NORMAL = 0 << BLEND_SHIFT, - - OPACITY_SHIFT = 1, - OPACITY_MASK = 1 << OPACITY_SHIFT, - OPACITY_OPAQUE = 1 << OPACITY_SHIFT, - OPACITY_TRANSLUCENT = 0 << OPACITY_SHIFT, - - ALPHA_SHIFT = 2, - ALPHA_MASK = 1 << ALPHA_SHIFT, - ALPHA_LT_ONE = 1 << ALPHA_SHIFT, - ALPHA_EQ_ONE = 0 << ALPHA_SHIFT, - - TEXTURE_SHIFT = 3, - TEXTURE_MASK = 3 << TEXTURE_SHIFT, - TEXTURE_OFF = 0 << TEXTURE_SHIFT, - TEXTURE_EXT = 1 << TEXTURE_SHIFT, - TEXTURE_2D = 2 << TEXTURE_SHIFT, - - ROUNDED_CORNERS_SHIFT = 5, - ROUNDED_CORNERS_MASK = 1 << ROUNDED_CORNERS_SHIFT, - ROUNDED_CORNERS_OFF = 0 << ROUNDED_CORNERS_SHIFT, - ROUNDED_CORNERS_ON = 1 << ROUNDED_CORNERS_SHIFT, - - INPUT_TRANSFORM_MATRIX_SHIFT = 6, - INPUT_TRANSFORM_MATRIX_MASK = 1 << INPUT_TRANSFORM_MATRIX_SHIFT, - INPUT_TRANSFORM_MATRIX_OFF = 0 << INPUT_TRANSFORM_MATRIX_SHIFT, - INPUT_TRANSFORM_MATRIX_ON = 1 << INPUT_TRANSFORM_MATRIX_SHIFT, - - OUTPUT_TRANSFORM_MATRIX_SHIFT = 7, - OUTPUT_TRANSFORM_MATRIX_MASK = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT, - OUTPUT_TRANSFORM_MATRIX_OFF = 0 << OUTPUT_TRANSFORM_MATRIX_SHIFT, - OUTPUT_TRANSFORM_MATRIX_ON = 1 << OUTPUT_TRANSFORM_MATRIX_SHIFT, - - INPUT_TF_SHIFT = 8, - INPUT_TF_MASK = 3 << INPUT_TF_SHIFT, - INPUT_TF_LINEAR = 0 << INPUT_TF_SHIFT, - INPUT_TF_SRGB = 1 << INPUT_TF_SHIFT, - INPUT_TF_ST2084 = 2 << INPUT_TF_SHIFT, - INPUT_TF_HLG = 3 << INPUT_TF_SHIFT, - - OUTPUT_TF_SHIFT = 10, - OUTPUT_TF_MASK = 3 << OUTPUT_TF_SHIFT, - OUTPUT_TF_LINEAR = 0 << OUTPUT_TF_SHIFT, - OUTPUT_TF_SRGB = 1 << OUTPUT_TF_SHIFT, - OUTPUT_TF_ST2084 = 2 << OUTPUT_TF_SHIFT, - OUTPUT_TF_HLG = 3 << OUTPUT_TF_SHIFT, - - SHADOW_SHIFT = 13, - SHADOW_MASK = 1 << SHADOW_SHIFT, - SHADOW_OFF = 0 << SHADOW_SHIFT, - SHADOW_ON = 1 << SHADOW_SHIFT, - - DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT = 14, - DISPLAY_COLOR_TRANSFORM_MATRIX_MASK = 1 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT, - DISPLAY_COLOR_TRANSFORM_MATRIX_OFF = 0 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT, - DISPLAY_COLOR_TRANSFORM_MATRIX_ON = 1 << DISPLAY_COLOR_TRANSFORM_MATRIX_SHIFT, - }; - - inline Key() : mKey(0) {} - inline Key(const Key& rhs) : mKey(rhs.mKey) {} - - inline Key& set(key_t mask, key_t value) { - mKey = (mKey & ~mask) | value; - return *this; - } - - inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; } - inline bool hasTextureCoords() const { return isTexturing() && !drawShadows(); } - inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); } - inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; } - inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; } - inline bool hasAlpha() const { return (mKey & ALPHA_MASK) == ALPHA_LT_ONE; } - inline bool hasRoundedCorners() const { - return (mKey & ROUNDED_CORNERS_MASK) == ROUNDED_CORNERS_ON; - } - inline bool drawShadows() const { return (mKey & SHADOW_MASK) == SHADOW_ON; } - inline bool hasInputTransformMatrix() const { - return (mKey & INPUT_TRANSFORM_MATRIX_MASK) == INPUT_TRANSFORM_MATRIX_ON; - } - inline bool hasOutputTransformMatrix() const { - return (mKey & OUTPUT_TRANSFORM_MATRIX_MASK) == OUTPUT_TRANSFORM_MATRIX_ON; - } - inline bool hasDisplayColorMatrix() const { - return (mKey & DISPLAY_COLOR_TRANSFORM_MATRIX_MASK) == - DISPLAY_COLOR_TRANSFORM_MATRIX_ON; - } - inline bool hasTransformMatrix() const { - return hasInputTransformMatrix() || hasOutputTransformMatrix(); - } - inline int getInputTF() const { return (mKey & INPUT_TF_MASK); } - inline int getOutputTF() const { return (mKey & OUTPUT_TF_MASK); } - - // When HDR and non-HDR contents are mixed, or different types of HDR contents are - // mixed, we will do a tone mapping process to tone map the input content to output - // content. Currently, the following conversions handled, they are: - // * SDR -> HLG - // * SDR -> PQ - // * HLG -> PQ - inline bool needsToneMapping() const { - int inputTF = getInputTF(); - int outputTF = getOutputTF(); - - // Return false when converting from SDR to SDR. - if (inputTF == Key::INPUT_TF_SRGB && outputTF == Key::OUTPUT_TF_LINEAR) { - return false; - } - if (inputTF == Key::INPUT_TF_LINEAR && outputTF == Key::OUTPUT_TF_SRGB) { - return false; - } - - inputTF >>= Key::INPUT_TF_SHIFT; - outputTF >>= Key::OUTPUT_TF_SHIFT; - return inputTF != outputTF; - } - - // for use by std::unordered_map - - bool operator==(const Key& other) const { return mKey == other.mKey; } - - struct Hash { - size_t operator()(const Key& key) const { return static_cast(key.mKey); } - }; - }; - - ProgramCache() = default; - ~ProgramCache() = default; - - // Generate shaders to populate the cache - void primeCache(const EGLContext context, bool toneMapperShaderOnly); - - size_t getSize(const EGLContext context) { return mCaches[context].size(); } - - // useProgram lookup a suitable program in the cache or generates one - // if none can be found. - void useProgram(const EGLContext context, const Description& description); - - void purgeCaches() { mCaches.clear(); } - -private: - // compute a cache Key from a Description - static Key computeKey(const Description& description); - // Generate EOTF based from Key. - static void generateEOTF(Formatter& fs, const Key& needs); - // Generate necessary tone mapping methods for OOTF. - static void generateToneMappingProcess(Formatter& fs, const Key& needs); - // Generate OOTF based from Key. - static void generateOOTF(Formatter& fs, const Key& needs); - // Generate OETF based from Key. - static void generateOETF(Formatter& fs, const Key& needs); - // generates a program from the Key - static std::unique_ptr generateProgram(const Key& needs); - // generates the vertex shader from the Key - static String8 generateVertexShader(const Key& needs); - // generates the fragment shader from the Key - static String8 generateFragmentShader(const Key& needs); - - // Key/Value map used for caching Programs. Currently the cache - // is never shrunk (and the GL program objects are never deleted). - std::unordered_map, Key::Hash>> - mCaches; -}; - -} // namespace gl -} // namespace renderengine - -ANDROID_BASIC_TYPES_TRAITS(renderengine::gl::ProgramCache::Key) - -} // namespace android - -#endif /* SF_RENDER_ENGINE_PROGRAMCACHE_H */ diff --git a/libs/renderengine/gl/filters/BlurFilter.cpp b/libs/renderengine/gl/filters/BlurFilter.cpp deleted file mode 100644 index 3455e08cfe..0000000000 --- a/libs/renderengine/gl/filters/BlurFilter.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "BlurFilter.h" -#include -#include -#include -#include -#include -#include - -#include - -namespace android { -namespace renderengine { -namespace gl { - -BlurFilter::BlurFilter(GLESRenderEngine& engine) - : mEngine(engine), - mCompositionFbo(engine), - mPingFbo(engine), - mPongFbo(engine), - mMixProgram(engine), - mBlurProgram(engine) { - mMixProgram.compile(getVertexShader(), getMixFragShader()); - mMPosLoc = mMixProgram.getAttributeLocation("aPosition"); - mMUvLoc = mMixProgram.getAttributeLocation("aUV"); - mMTextureLoc = mMixProgram.getUniformLocation("uTexture"); - mMCompositionTextureLoc = mMixProgram.getUniformLocation("uCompositionTexture"); - mMMixLoc = mMixProgram.getUniformLocation("uMix"); - - mBlurProgram.compile(getVertexShader(), getFragmentShader()); - mBPosLoc = mBlurProgram.getAttributeLocation("aPosition"); - mBUvLoc = mBlurProgram.getAttributeLocation("aUV"); - mBTextureLoc = mBlurProgram.getUniformLocation("uTexture"); - mBOffsetLoc = mBlurProgram.getUniformLocation("uOffset"); - - static constexpr auto size = 2.0f; - static constexpr auto translation = 1.0f; - const GLfloat vboData[] = { - // Vertex data - translation - size, -translation - size, - translation - size, -translation + size, - translation + size, -translation + size, - // UV data - 0.0f, 0.0f - translation, - 0.0f, size - translation, - size, size - translation - }; - mMeshBuffer.allocateBuffers(vboData, 12 /* size */); -} - -status_t BlurFilter::setAsDrawTarget(const DisplaySettings& display, uint32_t radius) { - ATRACE_NAME("BlurFilter::setAsDrawTarget"); - mRadius = radius; - mDisplayX = display.physicalDisplay.left; - mDisplayY = display.physicalDisplay.top; - - if (mDisplayWidth < display.physicalDisplay.width() || - mDisplayHeight < display.physicalDisplay.height()) { - ATRACE_NAME("BlurFilter::allocatingTextures"); - - mDisplayWidth = display.physicalDisplay.width(); - mDisplayHeight = display.physicalDisplay.height(); - mCompositionFbo.allocateBuffers(mDisplayWidth, mDisplayHeight); - - const uint32_t fboWidth = floorf(mDisplayWidth * kFboScale); - const uint32_t fboHeight = floorf(mDisplayHeight * kFboScale); - mPingFbo.allocateBuffers(fboWidth, fboHeight); - mPongFbo.allocateBuffers(fboWidth, fboHeight); - - if (mPingFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid ping buffer"); - return mPingFbo.getStatus(); - } - if (mPongFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid pong buffer"); - return mPongFbo.getStatus(); - } - if (mCompositionFbo.getStatus() != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Invalid composition buffer"); - return mCompositionFbo.getStatus(); - } - if (!mBlurProgram.isValid()) { - ALOGE("Invalid shader"); - return GL_INVALID_OPERATION; - } - } - - mCompositionFbo.bind(); - glViewport(0, 0, mCompositionFbo.getBufferWidth(), mCompositionFbo.getBufferHeight()); - return NO_ERROR; -} - -void BlurFilter::drawMesh(GLuint uv, GLuint position) { - - glEnableVertexAttribArray(uv); - glEnableVertexAttribArray(position); - mMeshBuffer.bind(); - glVertexAttribPointer(position, 2 /* size */, GL_FLOAT, GL_FALSE, - 2 * sizeof(GLfloat) /* stride */, 0 /* offset */); - glVertexAttribPointer(uv, 2 /* size */, GL_FLOAT, GL_FALSE, 0 /* stride */, - (GLvoid*)(6 * sizeof(GLfloat)) /* offset */); - mMeshBuffer.unbind(); - - // draw mesh - glDrawArrays(GL_TRIANGLES, 0 /* first */, 3 /* count */); -} - -status_t BlurFilter::prepare() { - ATRACE_NAME("BlurFilter::prepare"); - - // Kawase is an approximation of Gaussian, but it behaves differently from it. - // A radius transformation is required for approximating them, and also to introduce - // non-integer steps, necessary to smoothly interpolate large radii. - const auto radius = mRadius / 6.0f; - - // Calculate how many passes we'll do, based on the radius. - // Too many passes will make the operation expensive. - const auto passes = min(kMaxPasses, (uint32_t)ceil(radius)); - - const float radiusByPasses = radius / (float)passes; - const float stepX = radiusByPasses / (float)mCompositionFbo.getBufferWidth(); - const float stepY = radiusByPasses / (float)mCompositionFbo.getBufferHeight(); - - // Let's start by downsampling and blurring the composited frame simultaneously. - mBlurProgram.useProgram(); - glActiveTexture(GL_TEXTURE0); - glUniform1i(mBTextureLoc, 0); - glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName()); - glUniform2f(mBOffsetLoc, stepX, stepY); - glViewport(0, 0, mPingFbo.getBufferWidth(), mPingFbo.getBufferHeight()); - mPingFbo.bind(); - drawMesh(mBUvLoc, mBPosLoc); - - // And now we'll ping pong between our textures, to accumulate the result of various offsets. - GLFramebuffer* read = &mPingFbo; - GLFramebuffer* draw = &mPongFbo; - glViewport(0, 0, draw->getBufferWidth(), draw->getBufferHeight()); - for (auto i = 1; i < passes; i++) { - ATRACE_NAME("BlurFilter::renderPass"); - draw->bind(); - - glBindTexture(GL_TEXTURE_2D, read->getTextureName()); - glUniform2f(mBOffsetLoc, stepX * i, stepY * i); - - drawMesh(mBUvLoc, mBPosLoc); - - // Swap buffers for next iteration - auto tmp = draw; - draw = read; - read = tmp; - } - mLastDrawTarget = read; - - return NO_ERROR; -} - -status_t BlurFilter::render(bool multiPass) { - ATRACE_NAME("BlurFilter::render"); - - // Now let's scale our blur up. It will be interpolated with the larger composited - // texture for the first frames, to hide downscaling artifacts. - GLfloat mix = fmin(1.0, mRadius / kMaxCrossFadeRadius); - - // When doing multiple passes, we cannot try to read mCompositionFbo, given that we'll - // be writing onto it. Let's disable the crossfade, otherwise we'd need 1 extra frame buffer, - // as large as the screen size. - if (mix >= 1 || multiPass) { - mLastDrawTarget->bindAsReadBuffer(); - glBlitFramebuffer(0, 0, mLastDrawTarget->getBufferWidth(), - mLastDrawTarget->getBufferHeight(), mDisplayX, mDisplayY, mDisplayWidth, - mDisplayHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR); - return NO_ERROR; - } - - mMixProgram.useProgram(); - glUniform1f(mMMixLoc, mix); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, mLastDrawTarget->getTextureName()); - glUniform1i(mMTextureLoc, 0); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, mCompositionFbo.getTextureName()); - glUniform1i(mMCompositionTextureLoc, 1); - - drawMesh(mMUvLoc, mMPosLoc); - - glUseProgram(0); - glActiveTexture(GL_TEXTURE0); - mEngine.checkErrors("Drawing blur mesh"); - return NO_ERROR; -} - -string BlurFilter::getVertexShader() const { - return R"SHADER(#version 300 es - precision mediump float; - - in vec2 aPosition; - in highp vec2 aUV; - out highp vec2 vUV; - - void main() { - vUV = aUV; - gl_Position = vec4(aPosition, 0.0, 1.0); - } - )SHADER"; -} - -string BlurFilter::getFragmentShader() const { - return R"SHADER(#version 300 es - precision mediump float; - - uniform sampler2D uTexture; - uniform vec2 uOffset; - - in highp vec2 vUV; - out vec4 fragColor; - - void main() { - fragColor = texture(uTexture, vUV, 0.0); - fragColor += texture(uTexture, vUV + vec2( uOffset.x, uOffset.y), 0.0); - fragColor += texture(uTexture, vUV + vec2( uOffset.x, -uOffset.y), 0.0); - fragColor += texture(uTexture, vUV + vec2(-uOffset.x, uOffset.y), 0.0); - fragColor += texture(uTexture, vUV + vec2(-uOffset.x, -uOffset.y), 0.0); - - fragColor = vec4(fragColor.rgb * 0.2, 1.0); - } - )SHADER"; -} - -string BlurFilter::getMixFragShader() const { - string shader = R"SHADER(#version 300 es - precision mediump float; - - in highp vec2 vUV; - out vec4 fragColor; - - uniform sampler2D uCompositionTexture; - uniform sampler2D uTexture; - uniform float uMix; - - void main() { - vec4 blurred = texture(uTexture, vUV); - vec4 composition = texture(uCompositionTexture, vUV); - fragColor = mix(composition, blurred, uMix); - } - )SHADER"; - return shader; -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/filters/BlurFilter.h b/libs/renderengine/gl/filters/BlurFilter.h deleted file mode 100644 index 593a8fd54e..0000000000 --- a/libs/renderengine/gl/filters/BlurFilter.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2019 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 -#include "../GLESRenderEngine.h" -#include "../GLFramebuffer.h" -#include "../GLVertexBuffer.h" -#include "GenericProgram.h" - -using namespace std; - -namespace android { -namespace renderengine { -namespace gl { - -/** - * This is an implementation of a Kawase blur, as described in here: - * https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/ - * 00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf - */ -class BlurFilter { -public: - // Downsample FBO to improve performance - static constexpr float kFboScale = 0.25f; - // Maximum number of render passes - static constexpr uint32_t kMaxPasses = 4; - // To avoid downscaling artifacts, we interpolate the blurred fbo with the full composited - // image, up to this radius. - static constexpr float kMaxCrossFadeRadius = 30.0f; - - explicit BlurFilter(GLESRenderEngine& engine); - virtual ~BlurFilter(){}; - - // Set up render targets, redirecting output to offscreen texture. - status_t setAsDrawTarget(const DisplaySettings&, uint32_t radius); - // Execute blur passes, rendering to offscreen texture. - status_t prepare(); - // Render blur to the bound framebuffer (screen). - status_t render(bool multiPass); - -private: - uint32_t mRadius; - void drawMesh(GLuint uv, GLuint position); - string getVertexShader() const; - string getFragmentShader() const; - string getMixFragShader() const; - - GLESRenderEngine& mEngine; - // Frame buffer holding the composited background. - GLFramebuffer mCompositionFbo; - // Frame buffers holding the blur passes. - GLFramebuffer mPingFbo; - GLFramebuffer mPongFbo; - uint32_t mDisplayWidth = 0; - uint32_t mDisplayHeight = 0; - uint32_t mDisplayX = 0; - uint32_t mDisplayY = 0; - // Buffer holding the final blur pass. - GLFramebuffer* mLastDrawTarget; - - // VBO containing vertex and uv data of a fullscreen triangle. - GLVertexBuffer mMeshBuffer; - - GenericProgram mMixProgram; - GLuint mMPosLoc; - GLuint mMUvLoc; - GLuint mMMixLoc; - GLuint mMTextureLoc; - GLuint mMCompositionTextureLoc; - - GenericProgram mBlurProgram; - GLuint mBPosLoc; - GLuint mBUvLoc; - GLuint mBTextureLoc; - GLuint mBOffsetLoc; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/filters/GenericProgram.cpp b/libs/renderengine/gl/filters/GenericProgram.cpp deleted file mode 100644 index bb35889665..0000000000 --- a/libs/renderengine/gl/filters/GenericProgram.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2019 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 "GenericProgram.h" - -#include -#include -#include -#include - -namespace android { -namespace renderengine { -namespace gl { - -GenericProgram::GenericProgram(GLESRenderEngine& engine) : mEngine(engine) {} - -GenericProgram::~GenericProgram() { - if (mVertexShaderHandle != 0) { - if (mProgramHandle != 0) { - glDetachShader(mProgramHandle, mVertexShaderHandle); - } - glDeleteShader(mVertexShaderHandle); - } - - if (mFragmentShaderHandle != 0) { - if (mProgramHandle != 0) { - glDetachShader(mProgramHandle, mFragmentShaderHandle); - } - glDeleteShader(mFragmentShaderHandle); - } - - if (mProgramHandle != 0) { - glDeleteProgram(mProgramHandle); - } -} - -void GenericProgram::compile(string vertexShader, string fragmentShader) { - mVertexShaderHandle = compileShader(GL_VERTEX_SHADER, vertexShader); - mFragmentShaderHandle = compileShader(GL_FRAGMENT_SHADER, fragmentShader); - if (mVertexShaderHandle == 0 || mFragmentShaderHandle == 0) { - ALOGE("Aborting program creation."); - return; - } - mProgramHandle = createAndLink(mVertexShaderHandle, mFragmentShaderHandle); - mEngine.checkErrors("Linking program"); -} - -void GenericProgram::useProgram() const { - glUseProgram(mProgramHandle); -} - -GLuint GenericProgram::compileShader(GLuint type, string src) const { - const GLuint shader = glCreateShader(type); - if (shader == 0) { - mEngine.checkErrors("Creating shader"); - return 0; - } - const GLchar* charSrc = (const GLchar*)src.c_str(); - glShaderSource(shader, 1, &charSrc, nullptr); - glCompileShader(shader); - - GLint isCompiled = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled); - if (isCompiled == GL_FALSE) { - GLint maxLength = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); - string errorLog; - errorLog.reserve(maxLength); - glGetShaderInfoLog(shader, maxLength, &maxLength, errorLog.data()); - glDeleteShader(shader); - ALOGE("Error compiling shader: %s", errorLog.c_str()); - return 0; - } - return shader; -} -GLuint GenericProgram::createAndLink(GLuint vertexShader, GLuint fragmentShader) const { - const GLuint program = glCreateProgram(); - mEngine.checkErrors("Creating program"); - - glAttachShader(program, vertexShader); - glAttachShader(program, fragmentShader); - glLinkProgram(program); - mEngine.checkErrors("Linking program"); - return program; -} - -GLuint GenericProgram::getUniformLocation(const string name) const { - if (mProgramHandle == 0) { - ALOGE("Can't get location of %s on an invalid program.", name.c_str()); - return -1; - } - return glGetUniformLocation(mProgramHandle, (const GLchar*)name.c_str()); -} - -GLuint GenericProgram::getAttributeLocation(const string name) const { - if (mProgramHandle == 0) { - ALOGE("Can't get location of %s on an invalid program.", name.c_str()); - return -1; - } - return glGetAttribLocation(mProgramHandle, (const GLchar*)name.c_str()); -} - -bool GenericProgram::isValid() const { - return mProgramHandle != 0; -} - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/filters/GenericProgram.h b/libs/renderengine/gl/filters/GenericProgram.h deleted file mode 100644 index 6da2a5af58..0000000000 --- a/libs/renderengine/gl/filters/GenericProgram.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2019 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 -#include "../GLESRenderEngine.h" -#include "../GLFramebuffer.h" - -using namespace std; - -namespace android { -namespace renderengine { -namespace gl { - -class GenericProgram { -public: - explicit GenericProgram(GLESRenderEngine& renderEngine); - ~GenericProgram(); - void compile(string vertexShader, string fragmentShader); - bool isValid() const; - void useProgram() const; - GLuint getAttributeLocation(const string name) const; - GLuint getUniformLocation(const string name) const; - -private: - GLuint compileShader(GLuint type, const string src) const; - GLuint createAndLink(GLuint vertexShader, GLuint fragmentShader) const; - - GLESRenderEngine& mEngine; - GLuint mVertexShaderHandle = 0; - GLuint mFragmentShaderHandle = 0; - GLuint mProgramHandle = 0; -}; - -} // namespace gl -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/include/renderengine/Framebuffer.h b/libs/renderengine/include/renderengine/Framebuffer.h deleted file mode 100644 index 65111278e0..0000000000 --- a/libs/renderengine/include/renderengine/Framebuffer.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2018 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 - -struct ANativeWindowBuffer; - -namespace android { -namespace renderengine { - -class Framebuffer { -public: - virtual ~Framebuffer() = default; - - virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected, - const bool useFramebufferCache) = 0; -}; - -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/include/renderengine/Image.h b/libs/renderengine/include/renderengine/Image.h deleted file mode 100644 index 3bb47318ef..0000000000 --- a/libs/renderengine/include/renderengine/Image.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2017 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 - -struct ANativeWindowBuffer; - -namespace android { -namespace renderengine { - -class Image { -public: - virtual ~Image() = default; - virtual bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) = 0; -}; - -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/include/renderengine/Mesh.h b/libs/renderengine/include/renderengine/Mesh.h deleted file mode 100644 index 167f13f1bc..0000000000 --- a/libs/renderengine/include/renderengine/Mesh.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SF_RENDER_ENGINE_MESH_H -#define SF_RENDER_ENGINE_MESH_H - -#include - -#include - -namespace android { -namespace renderengine { - -class Mesh { -public: - class Builder; - - enum Primitive { - TRIANGLES = 0x0004, // GL_TRIANGLES - TRIANGLE_STRIP = 0x0005, // GL_TRIANGLE_STRIP - TRIANGLE_FAN = 0x0006 // GL_TRIANGLE_FAN - }; - - ~Mesh() = default; - - /* - * VertexArray handles the stride automatically. - */ - template - class VertexArray { - friend class Mesh; - float* mData; - size_t mStride; - size_t mOffset = 0; - VertexArray(float* data, size_t stride) : mData(data), mStride(stride) {} - - public: - // Returns a vertex array at an offset so its easier to append attributes from - // multiple sources. - VertexArray(VertexArray& other, size_t offset) - : mData(other.mData), mStride(other.mStride), mOffset(offset) {} - - TYPE& operator[](size_t index) { - return *reinterpret_cast(&mData[(index + mOffset) * mStride]); - } - TYPE const& operator[](size_t index) const { - return *reinterpret_cast(&mData[(index + mOffset) * mStride]); - } - }; - - template - VertexArray getPositionArray() { - return VertexArray(getPositions(), mStride); - } - - template - VertexArray getTexCoordArray() { - return VertexArray(getTexCoords(), mStride); - } - - template - VertexArray getCropCoordArray() { - return VertexArray(getCropCoords(), mStride); - } - - template - VertexArray getShadowColorArray() { - return VertexArray(getShadowColor(), mStride); - } - - template - VertexArray getShadowParamsArray() { - return VertexArray(getShadowParams(), mStride); - } - - uint16_t* getIndicesArray() { return getIndices(); } - - Primitive getPrimitive() const; - - // returns a pointer to the vertices positions - float const* getPositions() const; - - // returns a pointer to the vertices texture coordinates - float const* getTexCoords() const; - - // returns a pointer to the vertices crop coordinates - float const* getCropCoords() const; - - // returns a pointer to colors - float const* getShadowColor() const; - - // returns a pointer to the shadow params - float const* getShadowParams() const; - - // returns a pointer to indices - uint16_t const* getIndices() const; - - // number of vertices in this mesh - size_t getVertexCount() const; - - // dimension of vertices - size_t getVertexSize() const; - - // dimension of texture coordinates - size_t getTexCoordsSize() const; - - size_t getShadowParamsSize() const; - - size_t getShadowColorSize() const; - - size_t getIndexCount() const; - - // return stride in bytes - size_t getByteStride() const; - - // return stride in floats - size_t getStride() const; - -private: - Mesh(Primitive primitive, size_t vertexCount, size_t vertexSize, size_t texCoordSize, - size_t cropCoordsSize, size_t shadowColorSize, size_t shadowParamsSize, size_t indexCount); - Mesh(const Mesh&); - Mesh& operator=(const Mesh&); - Mesh const& operator=(const Mesh&) const; - - float* getPositions(); - float* getTexCoords(); - float* getCropCoords(); - float* getShadowColor(); - float* getShadowParams(); - uint16_t* getIndices(); - - std::vector mVertices; - size_t mVertexCount; - size_t mVertexSize; - size_t mTexCoordsSize; - size_t mCropCoordsSize; - size_t mShadowColorSize; - size_t mShadowParamsSize; - size_t mStride; - Primitive mPrimitive; - std::vector mIndices; - size_t mIndexCount; -}; - -class Mesh::Builder { -public: - Builder& setPrimitive(Primitive primitive) { - mPrimitive = primitive; - return *this; - }; - Builder& setVertices(size_t vertexCount, size_t vertexSize) { - mVertexCount = vertexCount; - mVertexSize = vertexSize; - return *this; - }; - Builder& setTexCoords(size_t texCoordsSize) { - mTexCoordsSize = texCoordsSize; - return *this; - }; - Builder& setCropCoords(size_t cropCoordsSize) { - mCropCoordsSize = cropCoordsSize; - return *this; - }; - Builder& setShadowAttrs() { - mShadowParamsSize = 3; - mShadowColorSize = 4; - return *this; - }; - Builder& setIndices(size_t indexCount) { - mIndexCount = indexCount; - return *this; - }; - Mesh build() const { - return Mesh{mPrimitive, mVertexCount, mVertexSize, mTexCoordsSize, - mCropCoordsSize, mShadowColorSize, mShadowParamsSize, mIndexCount}; - } - -private: - size_t mVertexCount = 0; - size_t mVertexSize = 0; - size_t mTexCoordsSize = 0; - size_t mCropCoordsSize = 0; - size_t mShadowColorSize = 0; - size_t mShadowParamsSize = 0; - size_t mIndexCount = 0; - Primitive mPrimitive; -}; - -} // namespace renderengine -} // namespace android -#endif /* SF_RENDER_ENGINE_MESH_H */ diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 83af252740..72a6075ff1 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -22,8 +22,6 @@ #include #include #include -#include -#include #include #include #include @@ -95,8 +93,6 @@ public: }; enum class RenderEngineType { - GLES = 1, - THREADED = 2, SKIA_GL = 3, SKIA_GL_THREADED = 4, SKIA_VK = 5, @@ -171,8 +167,6 @@ public: // being drawn, then the implementation is free to silently ignore this call. virtual void cleanupPostRender() = 0; - virtual void cleanFramebufferCache() = 0; - // Returns the priority this context was actually created with. Note: this // may not be the same as specified at context creation time, due to // implementation limits on the number of contexts that can be created at a @@ -204,7 +198,7 @@ public: virtual void setEnableTracing(bool /*tracingEnabled*/) {} protected: - RenderEngine() : RenderEngine(RenderEngineType::GLES) {} + RenderEngine() : RenderEngine(RenderEngineType::SKIA_GL) {} RenderEngine(RenderEngineType type) : mRenderEngineType(type) {} diff --git a/libs/renderengine/include/renderengine/Texture.h b/libs/renderengine/include/renderengine/Texture.h deleted file mode 100644 index c69ace0603..0000000000 --- a/libs/renderengine/include/renderengine/Texture.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SF_RENDER_ENGINE_TEXTURE_H -#define SF_RENDER_ENGINE_TEXTURE_H - -#include - -#include - -namespace android { -namespace renderengine { - -class Texture { -public: - enum Target { TEXTURE_2D = 0x0DE1, TEXTURE_EXTERNAL = 0x8D65 }; - - Texture(); - Texture(Target textureTarget, uint32_t textureName); - ~Texture(); - - void init(Target textureTarget, uint32_t textureName); - - void setMatrix(float const* matrix); - void setFiltering(bool enabled); - void setDimensions(size_t width, size_t height); - - uint32_t getTextureName() const; - uint32_t getTextureTarget() const; - - const mat4& getMatrix() const; - bool getFiltering() const; - size_t getWidth() const; - size_t getHeight() const; - -private: - uint32_t mTextureName; - uint32_t mTextureTarget; - size_t mWidth; - size_t mHeight; - bool mFiltering; - mat4 mTextureMatrix; -}; - -} // namespace renderengine -} // namespace android -#endif /* SF_RENDER_ENGINE_TEXTURE_H */ diff --git a/libs/renderengine/include/renderengine/mock/Framebuffer.h b/libs/renderengine/include/renderengine/mock/Framebuffer.h deleted file mode 100644 index dfb6a4e41e..0000000000 --- a/libs/renderengine/include/renderengine/mock/Framebuffer.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018 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 -#include - -namespace android { -namespace renderengine { -namespace mock { - -class Framebuffer : public renderengine::Framebuffer { -public: - Framebuffer(); - ~Framebuffer() override; - - MOCK_METHOD3(setNativeWindowBuffer, bool(ANativeWindowBuffer*, bool, const bool)); -}; - -} // namespace mock -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/include/renderengine/mock/Image.h b/libs/renderengine/include/renderengine/mock/Image.h deleted file mode 100644 index 2b0eed1173..0000000000 --- a/libs/renderengine/include/renderengine/mock/Image.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018 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 -#include - -namespace android { -namespace renderengine { -namespace mock { - -class Image : public renderengine::Image { -public: - Image(); - ~Image() override; - - MOCK_METHOD2(setNativeWindowBuffer, bool(ANativeWindowBuffer* buffer, bool isProtected)); -}; - -} // namespace mock -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index d3035e24a5..571b52b787 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -19,9 +19,7 @@ #include #include #include -#include #include -#include #include #include #include diff --git a/libs/renderengine/include/renderengine/private/Description.h b/libs/renderengine/include/renderengine/private/Description.h deleted file mode 100644 index 2873ad7148..0000000000 --- a/libs/renderengine/include/renderengine/private/Description.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SF_RENDER_ENGINE_DESCRIPTION_H_ -#define SF_RENDER_ENGINE_DESCRIPTION_H_ - -#include -#include - -namespace android { -namespace renderengine { - -/* - * This is the structure that holds the state of the rendering engine. - * This class is used to generate a corresponding GLSL program and set the - * appropriate uniform. - */ -struct Description { - enum class TransferFunction : int { - LINEAR, - SRGB, - ST2084, - HLG, // Hybrid Log-Gamma for HDR. - }; - - static TransferFunction dataSpaceToTransferFunction(ui::Dataspace dataSpace); - - Description() = default; - ~Description() = default; - - bool hasInputTransformMatrix() const; - bool hasOutputTransformMatrix() const; - bool hasColorMatrix() const; - bool hasDisplayColorMatrix() const; - - // whether textures are premultiplied - bool isPremultipliedAlpha = false; - // whether this layer is marked as opaque - bool isOpaque = true; - - // corner radius of the layer - float cornerRadius = 0; - - // Size of the rounded rectangle we are cropping to - half2 cropSize; - - // Texture this layer uses - Texture texture; - bool textureEnabled = false; - - // color used when texturing is disabled or when setting alpha. - half4 color; - - // transfer functions for the input/output - TransferFunction inputTransferFunction = TransferFunction::LINEAR; - TransferFunction outputTransferFunction = TransferFunction::LINEAR; - - float displayMaxLuminance; - float maxMasteringLuminance; - float maxContentLuminance; - - // projection matrix - mat4 projectionMatrix; - - // The color matrix will be applied in linear space right before OETF. - mat4 colorMatrix; - // The display color matrix will be applied in gamma space after OETF - mat4 displayColorMatrix; - mat4 inputTransformMatrix; - mat4 outputTransformMatrix; - - // True if this layer will draw a shadow. - bool drawShadows = false; -}; - -} // namespace renderengine -} // namespace android - -#endif /* SF_RENDER_ENGINE_DESCRIPTION_H_ */ diff --git a/libs/renderengine/mock/Framebuffer.cpp b/libs/renderengine/mock/Framebuffer.cpp deleted file mode 100644 index fbdcaab697..0000000000 --- a/libs/renderengine/mock/Framebuffer.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2018 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 - -namespace android { -namespace renderengine { -namespace mock { - -// The Google Mock documentation recommends explicit non-header instantiations -// for better compile time performance. -Framebuffer::Framebuffer() = default; -Framebuffer::~Framebuffer() = default; - -} // namespace mock -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/mock/Image.cpp b/libs/renderengine/mock/Image.cpp deleted file mode 100644 index 57f4346f8f..0000000000 --- a/libs/renderengine/mock/Image.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2018 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 - -namespace android { -namespace renderengine { -namespace mock { - -// The Google Mock documentation recommends explicit non-header instantiations -// for better compile time performance. -Image::Image() = default; -Image::~Image() = default; - -} // namespace mock -} // namespace renderengine -} // namespace android diff --git a/libs/renderengine/gl/GLExtensions.cpp b/libs/renderengine/skia/GLExtensions.cpp similarity index 97% rename from libs/renderengine/gl/GLExtensions.cpp rename to libs/renderengine/skia/GLExtensions.cpp index 3dd534e602..32da303a92 100644 --- a/libs/renderengine/gl/GLExtensions.cpp +++ b/libs/renderengine/skia/GLExtensions.cpp @@ -23,11 +23,11 @@ #include #include -ANDROID_SINGLETON_STATIC_INSTANCE(android::renderengine::gl::GLExtensions) +ANDROID_SINGLETON_STATIC_INSTANCE(android::renderengine::skia::GLExtensions) namespace android { namespace renderengine { -namespace gl { +namespace skia { namespace { @@ -134,6 +134,6 @@ char const* GLExtensions::getEGLExtensions() const { return mEGLExtensions.string(); } -} // namespace gl +} // namespace skia } // namespace renderengine } // namespace android diff --git a/libs/renderengine/gl/GLExtensions.h b/libs/renderengine/skia/GLExtensions.h similarity index 98% rename from libs/renderengine/gl/GLExtensions.h rename to libs/renderengine/skia/GLExtensions.h index e415ff304a..0cb1bda0df 100644 --- a/libs/renderengine/gl/GLExtensions.h +++ b/libs/renderengine/skia/GLExtensions.h @@ -29,7 +29,7 @@ namespace android { namespace renderengine { -namespace gl { +namespace skia { class GLExtensions : public Singleton { public: @@ -81,7 +81,7 @@ private: GLExtensions& operator=(const GLExtensions&); }; -} // namespace gl +} // namespace skia } // namespace renderengine } // namespace android diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 92181d87c8..e253ad596e 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -36,17 +36,26 @@ #include #include -#include "../gl/GLExtensions.h" +#include "GLExtensions.h" #include "log/log_main.h" -bool checkGlError(const char* op, int lineNumber); - namespace android { namespace renderengine { namespace skia { using base::StringAppendF; +static bool checkGlError(const char* op, int lineNumber) { + bool errorFound = false; + GLint error = glGetError(); + while (error != GL_NO_ERROR) { + errorFound = true; + error = glGetError(); + ALOGV("after %s() (line # %d) glError (0x%x)\n", op, lineNumber, error); + } + return errorFound; +} + static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute, EGLint wanted, EGLConfig* outConfig) { EGLint numConfigs = -1, n = 0; @@ -149,7 +158,7 @@ std::unique_ptr SkiaGLRenderEngine::create( LOG_ALWAYS_FATAL("eglQueryString(EGL_EXTENSIONS) failed"); } - auto& extensions = gl::GLExtensions::getInstance(); + auto& extensions = GLExtensions::getInstance(); extensions.initWithEGLStrings(eglVersion, eglExtensions); // The code assumes that ES2 or later is available if this extension is @@ -342,8 +351,8 @@ base::unique_fd SkiaGLRenderEngine::flushAndSubmit(GrDirectContext* grContext) { } bool SkiaGLRenderEngine::waitGpuFence(base::borrowed_fd fenceFd) { - if (!gl::GLExtensions::getInstance().hasNativeFenceSync() || - !gl::GLExtensions::getInstance().hasWaitSync()) { + if (!GLExtensions::getInstance().hasNativeFenceSync() || + !GLExtensions::getInstance().hasWaitSync()) { return false; } @@ -378,7 +387,7 @@ bool SkiaGLRenderEngine::waitGpuFence(base::borrowed_fd fenceFd) { base::unique_fd SkiaGLRenderEngine::flush() { ATRACE_CALL(); - if (!gl::GLExtensions::getInstance().hasNativeFenceSync()) { + if (!GLExtensions::getInstance().hasNativeFenceSync()) { return base::unique_fd(); } @@ -469,13 +478,13 @@ EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig co std::optional SkiaGLRenderEngine::createContextPriority( const RenderEngineCreationArgs& args) { - if (!gl::GLExtensions::getInstance().hasContextPriority()) { + if (!GLExtensions::getInstance().hasContextPriority()) { return std::nullopt; } switch (args.contextPriority) { case RenderEngine::ContextPriority::REALTIME: - if (gl::GLExtensions::getInstance().hasRealtimePriority()) { + if (GLExtensions::getInstance().hasRealtimePriority()) { return RenderEngine::ContextPriority::REALTIME; } else { ALOGI("Realtime priority unsupported, degrading gracefully to high priority"); @@ -519,7 +528,7 @@ int SkiaGLRenderEngine::getContextPriority() { } void SkiaGLRenderEngine::appendBackendSpecificInfoToDump(std::string& result) { - const gl::GLExtensions& extensions = gl::GLExtensions::getInstance(); + const GLExtensions& extensions = GLExtensions::getInstance(); StringAppendF(&result, "\n ------------RE GLES------------\n"); StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion()); StringAppendF(&result, "%s\n", extensions.getEGLExtensions()); diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 7b4a0a0af2..011052102d 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -64,7 +64,6 @@ public: std::future primeCache() override final; void cleanupPostRender() override final; - void cleanFramebufferCache() override final{ } bool supportsBackgroundBlur() override final { return mBlurFilter != nullptr; } diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index fe3a16d4bf..281a502b06 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -36,7 +36,7 @@ struct RenderEngineThreadedTest : public ::testing::Test { void SetUp() override { mThreadedRE = renderengine::threaded::RenderEngineThreaded::create( [this]() { return std::unique_ptr(mRenderEngine); }, - renderengine::RenderEngine::RenderEngineType::THREADED); + renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED); } std::unique_ptr mThreadedRE; @@ -57,18 +57,6 @@ TEST_F(RenderEngineThreadedTest, primeCache) { mThreadedRE->getContextPriority(); } -TEST_F(RenderEngineThreadedTest, genTextures) { - uint32_t texName; - EXPECT_CALL(*mRenderEngine, genTextures(1, &texName)); - mThreadedRE->genTextures(1, &texName); -} - -TEST_F(RenderEngineThreadedTest, deleteTextures) { - uint32_t texName; - EXPECT_CALL(*mRenderEngine, deleteTextures(1, &texName)); - mThreadedRE->deleteTextures(1, &texName); -} - TEST_F(RenderEngineThreadedTest, getMaxTextureSize_returns20) { size_t size = 20; EXPECT_CALL(*mRenderEngine, getMaxTextureSize()).WillOnce(Return(size)); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index 6a1561abcd..57055bd9ac 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -27,8 +27,6 @@ #include #include -#include "gl/GLESRenderEngine.h" - using namespace std::chrono_literals; namespace android { @@ -178,41 +176,13 @@ void RenderEngineThreaded::dump(std::string& result) { void RenderEngineThreaded::genTextures(size_t count, uint32_t* names) { ATRACE_CALL(); // This is a no-op in SkiaRenderEngine. - if (getRenderEngineType() != RenderEngineType::THREADED) { - return; - } - std::promise resultPromise; - std::future resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise, count, names](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::genTextures"); - instance.genTextures(count, names); - resultPromise.set_value(); - }); - } - mCondition.notify_one(); - resultFuture.wait(); + return; } void RenderEngineThreaded::deleteTextures(size_t count, uint32_t const* names) { ATRACE_CALL(); // This is a no-op in SkiaRenderEngine. - if (getRenderEngineType() != RenderEngineType::THREADED) { - return; - } - std::promise resultPromise; - std::future resultFuture = resultPromise.get_future(); - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([&resultPromise, count, &names](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::deleteTextures"); - instance.deleteTextures(count, names); - resultPromise.set_value(); - }); - } - mCondition.notify_one(); - resultFuture.wait(); + return; } void RenderEngineThreaded::mapExternalTextureBuffer(const sp& buffer, @@ -313,20 +283,6 @@ ftl::Future RenderEngineThreaded::drawLayers( return resultFuture; } -void RenderEngineThreaded::cleanFramebufferCache() { - ATRACE_CALL(); - // This function is designed so it can run asynchronously, so we do not need to wait - // for the futures. - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::cleanFramebufferCache"); - instance.cleanFramebufferCache(); - }); - } - mCondition.notify_one(); -} - int RenderEngineThreaded::getContextPriority() { std::promise resultPromise; std::future resultFuture = resultPromise.get_future(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 6eb108e064..68e50625c8 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -60,7 +60,6 @@ public: const bool useFramebufferCache, base::unique_fd&& bufferFence) override; - void cleanFramebufferCache() override; int getContextPriority() override; bool supportsBackgroundBlur() override; void onActiveDisplaySizeChanged(ui::Size size) override; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index d1912e4c9c..faf0e3c117 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -23,8 +23,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 06adfec0d2..5dd1598299 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -769,13 +769,9 @@ void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { static std::optional chooseRenderEngineTypeViaSysProp() { char prop[PROPERTY_VALUE_MAX]; - property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, ""); + property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "skiaglthreaded"); - if (strcmp(prop, "gles") == 0) { - return renderengine::RenderEngine::RenderEngineType::GLES; - } else if (strcmp(prop, "threaded") == 0) { - return renderengine::RenderEngine::RenderEngineType::THREADED; - } else if (strcmp(prop, "skiagl") == 0) { + if (strcmp(prop, "skiagl") == 0) { return renderengine::RenderEngine::RenderEngineType::SKIA_GL; } else if (strcmp(prop, "skiaglthreaded") == 0) { return renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED; @@ -3578,8 +3574,6 @@ void SurfaceFlinger::processDisplayChanged(const wp& displayToken, // Recreate the DisplayDevice if the surface or sequence ID changed. if (currentBinder != drawingBinder || currentState.sequenceId != drawingState.sequenceId) { - getRenderEngine().cleanFramebufferCache(); - if (const auto display = getDisplayDeviceLocked(displayToken)) { display->disconnect(); if (display->isVirtual()) { @@ -7872,7 +7866,7 @@ ftl::SharedFuture SurfaceFlinger::renderScreenImpl( const bool renderEngineIsThreaded = [&]() { using Type = renderengine::RenderEngine::RenderEngineType; const auto type = mRenderEngine->getRenderEngineType(); - return type == Type::THREADED || type == Type::SKIA_GL_THREADED; + return type == Type::SKIA_GL_THREADED; }(); auto presentFuture = renderEngineIsThreaded ? ftl::defer(std::move(present)).share() : ftl::yield(present()).share(); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 14fa492576..14f71f28a2 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -31,8 +31,6 @@ #include #include #include -#include -#include #include #include #include -- GitLab From 7dd69fd635eed4abe3b119204c2ceabafc110ae9 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Wed, 16 Aug 2023 22:00:43 +0000 Subject: [PATCH 0478/1187] Setting up crash type in test fuzzer Setting up crash type in fuzzer as this test fuzzer should always find a crash in TestService. Exiting on incorrect number of args won't be catched by infra. Test: atest fuzz_service_test Test: m test_service_fuzzer_should_crash && ./test_service_fuzzer_should_crash Bug: N/A Change-Id: I48053bada6fe67cfa6f3b6d30fc27dbf6afe28f8 --- .../parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp index ba1a6a1ccd..d2fa581822 100644 --- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp +++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp @@ -35,6 +35,7 @@ enum class CrashType { ON_ROOT_AID, ON_DUMP_TRANSACT, ON_SHELL_CMD_TRANSACT, + CRASH_ALWAYS, }; // This service is to verify that fuzzService is functioning properly @@ -112,8 +113,10 @@ CrashType gCrashType = CrashType::NONE; extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { if (*argc < 2) { - printf("You must specify at least one argument\n"); - exit(0); // success because this is a crash test + // This fuzzer is also used as test fuzzer to check infra pipeline. + // It should always run and find a crash in TestService. + gCrashType = CrashType::CRASH_ALWAYS; + return 0; } std::string arg = std::string((*argv)[1]); @@ -146,6 +149,9 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (gCrashType == CrashType::CRASH_ALWAYS) { + LOG_ALWAYS_FATAL("Expected crash, This fuzzer will always crash."); + } auto service = sp::make(gCrashType); fuzzService(service, FuzzedDataProvider(data, size)); return 0; -- GitLab From 6f972e3416d1693bac3acff0620793f2b25e8bbf Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Thu, 17 Aug 2023 00:38:18 +0000 Subject: [PATCH 0479/1187] Adding defaults for AIDL rust fuzzers Adding rust_defaults for service fuzzers and using them in existing fuzzers. Test: m parcel_fuzzer_rs && adb sync data && adb shell data/fuzz/x86_64/parcel_fuzzer_rs/parcel_fuzzer_rs Bug: 261555016 Change-Id: I7b0a675e404dd49bf775d34c6900d22fbcd951be --- .../rust/tests/parcel_fuzzer/Android.bp | 26 ++++++++++++------- .../fuzz_service_test/Android.bp | 14 +++------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/libs/binder/rust/tests/parcel_fuzzer/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/Android.bp index ac968237a0..6eb707bcf7 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/Android.bp +++ b/libs/binder/rust/tests/parcel_fuzzer/Android.bp @@ -3,19 +3,12 @@ package { default_applicable_licenses: ["frameworks_native_license"], } -rust_fuzz { - name: "parcel_fuzzer_rs", - srcs: [ - "parcel_fuzzer.rs", - ], +rust_defaults { + name: "service_fuzzer_defaults_rs", rustlibs: [ - "libarbitrary", - "libnum_traits", "libbinder_rs", "libbinder_random_parcel_rs", - "binderReadParcelIface-rust", ], - fuzz_config: { cc: [ "waghpawan@google.com", @@ -26,3 +19,18 @@ rust_fuzz { hotlists: ["4637097"], }, } + +rust_fuzz { + name: "parcel_fuzzer_rs", + srcs: [ + "parcel_fuzzer.rs", + ], + defaults: [ + "service_fuzzer_defaults_rs", + ], + rustlibs: [ + "libarbitrary", + "libnum_traits", + "binderReadParcelIface-rust", + ], +} diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp index 2537ce0bcb..84130c17e1 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp +++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp @@ -19,18 +19,10 @@ rust_fuzz { srcs: [ "service_fuzzer.rs", ], + defaults: [ + "service_fuzzer_defaults_rs", + ], rustlibs: [ - "libbinder_rs", - "libbinder_random_parcel_rs", "testServiceInterface-rust", ], - fuzz_config: { - cc: [ - "waghpawan@google.com", - "smoreland@google.com", - ], - triage_assignee: "waghpawan@google.com", - // hotlist "AIDL fuzzers bugs" on buganizer - hotlists: ["4637097"], - }, } -- GitLab From c3a17824aed485229dba17819e5ee4e4ecf4db1e Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 16 Aug 2023 14:56:30 +0000 Subject: [PATCH 0480/1187] Delete genTextures and deleteTextures from RenderEngine These methods are no-ops with skia and cause thread bounces in practice so just remove these. Bug: 270628071 Test: builds Change-Id: I0dc549eb7c9a0d94def5a8727322ed49b010ef1f --- .../include/renderengine/LayerSettings.h | 6 --- .../include/renderengine/RenderEngine.h | 3 -- .../include/renderengine/mock/RenderEngine.h | 4 -- libs/renderengine/skia/SkiaRenderEngine.h | 2 - libs/renderengine/tests/RenderEngineTest.cpp | 21 -------- .../threaded/RenderEngineThreaded.cpp | 12 ----- .../threaded/RenderEngineThreaded.h | 2 - .../src/ClientCompositionRequestCache.cpp | 3 +- .../FrontEnd/LayerCreationArgs.h | 1 - .../surfaceflinger/FrontEnd/LayerSnapshot.cpp | 1 - .../surfaceflinger/FrontEnd/LayerSnapshot.h | 1 - .../FrontEnd/RequestedLayerState.cpp | 1 - .../FrontEnd/RequestedLayerState.h | 1 - services/surfaceflinger/Layer.cpp | 10 ---- services/surfaceflinger/Layer.h | 2 - services/surfaceflinger/LayerFE.cpp | 1 - services/surfaceflinger/SurfaceFlinger.cpp | 54 ------------------- services/surfaceflinger/SurfaceFlinger.h | 14 ----- .../fuzzer/surfaceflinger_fuzzer.cpp | 3 -- .../tests/unittests/CompositionTest.cpp | 15 ++---- .../tests/unittests/TestableSurfaceFlinger.h | 1 - 21 files changed, 6 insertions(+), 152 deletions(-) diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index b501c4074b..28aa4dd71d 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -46,10 +46,6 @@ struct Buffer { // Fence that will fire when the buffer is ready to be bound. sp fence = nullptr; - // Texture identifier to bind the external texture to. - // TODO(alecmouri): This is GL-specific...make the type backend-agnostic. - uint32_t textureName = 0; - // Whether to use filtering when rendering the texture. bool useTextureFiltering = false; @@ -182,7 +178,6 @@ struct LayerSettings { // compositionengine/impl/ClientCompositionRequestCache.cpp static inline bool operator==(const Buffer& lhs, const Buffer& rhs) { return lhs.buffer == rhs.buffer && lhs.fence == rhs.fence && - lhs.textureName == rhs.textureName && lhs.useTextureFiltering == rhs.useTextureFiltering && lhs.textureTransform == rhs.textureTransform && lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha && @@ -237,7 +232,6 @@ static inline void PrintTo(const Buffer& settings, ::std::ostream* os) { << (settings.buffer.get() ? decodePixelFormat(settings.buffer->getPixelFormat()).c_str() : ""); *os << "\n .fence = " << settings.fence.get(); - *os << "\n .textureName = " << settings.textureName; *os << "\n .useTextureFiltering = " << settings.useTextureFiltering; *os << "\n .textureTransform = "; PrintMatrix(settings.textureTransform, os); diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 72a6075ff1..80aa4c61e6 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -112,9 +112,6 @@ public: // dump the extension strings. always call the base class. virtual void dump(std::string& result) = 0; - virtual void genTextures(size_t count, uint32_t* names) = 0; - virtual void deleteTextures(size_t count, uint32_t const* names) = 0; - // queries that are required to be thread safe virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index 571b52b787..78811908d6 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -35,9 +35,6 @@ public: MOCK_METHOD0(primeCache, std::future()); MOCK_METHOD1(dump, void(std::string&)); - MOCK_METHOD2(genTextures, void(size_t, uint32_t*)); - MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*)); - MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&)); MOCK_CONST_METHOD0(getMaxTextureSize, size_t()); MOCK_CONST_METHOD0(getMaxViewportDims, size_t()); MOCK_CONST_METHOD0(isProtected, bool()); @@ -53,7 +50,6 @@ public: void(const std::shared_ptr>&&, const DisplaySettings&, const std::vector&, const std::shared_ptr&, const bool, base::unique_fd&&)); - MOCK_METHOD0(cleanFramebufferCache, void()); MOCK_METHOD0(getContextPriority, int()); MOCK_METHOD0(supportsBackgroundBlur, bool()); MOCK_METHOD1(onActiveDisplaySizeChanged, void(ui::Size)); diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 011052102d..d4fc959ba5 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -70,8 +70,6 @@ public: void onActiveDisplaySizeChanged(ui::Size size) override final; int reportShadersCompiled(); - virtual void genTextures(size_t /*count*/, uint32_t* /*names*/) override final{}; - virtual void deleteTextures(size_t /*count*/, uint32_t const* /*names*/) override final{}; virtual void setEnableTracing(bool tracingEnabled) override final; void useProtectedContext(bool useProtectedContext) override; diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 1ad0fa6e70..5eec305096 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -278,9 +278,6 @@ public: if (WRITE_BUFFER_TO_FILE_ON_FAILURE && ::testing::Test::HasFailure()) { writeBufferToFile("/data/texture_out_"); } - for (uint32_t texName : mTexNames) { - mRE->deleteTextures(1, &texName); - } const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); @@ -623,8 +620,6 @@ public: std::unique_ptr mRE; std::shared_ptr mBuffer; - - std::vector mTexNames; }; void RenderEngineTest::initializeRenderEngine() { @@ -668,9 +663,6 @@ struct BufferSourceVariant { static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b, RenderEngineTest* fixture) { const auto buf = fixture->allocateSourceBuffer(1, 1); - uint32_t texName; - fixture->mRE->genTextures(1, &texName); - fixture->mTexNames.push_back(texName); uint8_t* pixels; buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, @@ -690,7 +682,6 @@ struct BufferSourceVariant { buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; - layer.source.buffer.textureName = texName; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; OpaquenessVariant::setOpaqueBit(layer); } @@ -1239,9 +1230,6 @@ void RenderEngineTest::fillRedBufferTextureTransform() { // Here will allocate a checker board texture, but transform texture // coordinates so that only the upper left is applied. const auto buf = allocateSourceBuffer(2, 2); - uint32_t texName; - RenderEngineTest::mRE->genTextures(1, &texName); - this->mTexNames.push_back(texName); uint8_t* pixels; buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, @@ -1262,7 +1250,6 @@ void RenderEngineTest::fillRedBufferTextureTransform() { buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; - layer.source.buffer.textureName = texName; // Transform coordinates to only be inside the red quadrant. layer.source.buffer.textureTransform = mat4::scale(vec4(0.2f, 0.2f, 1.f, 1.f)); layer.alpha = 1.0f; @@ -1288,9 +1275,6 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() { renderengine::LayerSettings layer; const auto buf = allocateSourceBuffer(1, 1); - uint32_t texName; - RenderEngineTest::mRE->genTextures(1, &texName); - this->mTexNames.push_back(texName); uint8_t* pixels; buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, @@ -1302,7 +1286,6 @@ void RenderEngineTest::fillRedBufferWithPremultiplyAlpha() { buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; - layer.source.buffer.textureName = texName; layer.source.buffer.usePremultipliedAlpha = true; layer.alpha = 0.5f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); @@ -1327,9 +1310,6 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() { renderengine::LayerSettings layer; const auto buf = allocateSourceBuffer(1, 1); - uint32_t texName; - RenderEngineTest::mRE->genTextures(1, &texName); - this->mTexNames.push_back(texName); uint8_t* pixels; buf->getBuffer()->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, @@ -1341,7 +1321,6 @@ void RenderEngineTest::fillRedBufferWithoutPremultiplyAlpha() { buf->getBuffer()->unlock(); layer.source.buffer.buffer = buf; - layer.source.buffer.textureName = texName; layer.source.buffer.usePremultipliedAlpha = false; layer.alpha = 0.5f; layer.geometry.boundaries = Rect(1, 1).toFloatRect(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index 57055bd9ac..3bc9e6d7e0 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -173,18 +173,6 @@ void RenderEngineThreaded::dump(std::string& result) { result.assign(resultFuture.get()); } -void RenderEngineThreaded::genTextures(size_t count, uint32_t* names) { - ATRACE_CALL(); - // This is a no-op in SkiaRenderEngine. - return; -} - -void RenderEngineThreaded::deleteTextures(size_t count, uint32_t const* names) { - ATRACE_CALL(); - // This is a no-op in SkiaRenderEngine. - return; -} - void RenderEngineThreaded::mapExternalTextureBuffer(const sp& buffer, bool isRenderable) { ATRACE_CALL(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 68e50625c8..a7ecab2931 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -46,8 +46,6 @@ public: void dump(std::string& result) override; - void genTextures(size_t count, uint32_t* names) override; - void deleteTextures(size_t count, uint32_t const* names) override; size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp index 752257b810..bdaa1d0ae1 100644 --- a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp +++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp @@ -41,8 +41,7 @@ inline bool equalIgnoringSource(const renderengine::LayerSettings& lhs, } inline bool equalIgnoringBuffer(const renderengine::Buffer& lhs, const renderengine::Buffer& rhs) { - return lhs.textureName == rhs.textureName && - lhs.useTextureFiltering == rhs.useTextureFiltering && + return lhs.useTextureFiltering == rhs.useTextureFiltering && lhs.textureTransform == rhs.textureTransform && lhs.usePremultipliedAlpha == rhs.usePremultipliedAlpha && lhs.isOpaque == rhs.isOpaque && lhs.maxLuminanceNits == rhs.maxLuminanceNits; diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h index c26edb5d22..0788d1abce 100644 --- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h +++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h @@ -54,7 +54,6 @@ struct LayerCreationArgs { gui::LayerMetadata metadata; pid_t ownerPid; uid_t ownerUid; - uint32_t textureName; uint32_t sequence; bool addToRoot = true; wp parentHandle = nullptr; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index d42bce6ed5..80bedf4a39 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -118,7 +118,6 @@ LayerSnapshot::LayerSnapshot(const RequestedLayerState& state, sequence = static_cast(state.id); name = state.name; debugName = state.debugName; - textureName = state.textureName; premultipliedAlpha = state.premultipliedAlpha; inputInfo.name = state.name; inputInfo.id = static_cast(uniqueSequence); diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 92d23e2724..7537a39060 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -64,7 +64,6 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { int32_t sequence; std::string name; std::string debugName; - uint32_t textureName; bool contentOpaque; bool layerOpaqueFlagSet; RoundedCornerState roundedCorner; diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index d979c4662e..a5d556328d 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -51,7 +51,6 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) name(args.name + "#" + std::to_string(args.sequence)), canBeRoot(args.addToRoot), layerCreationFlags(args.flags), - textureName(args.textureName), ownerUid(args.ownerUid), ownerPid(args.ownerPid), parentId(args.parentId), diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h index 030930289d..8eff22bbe4 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h @@ -95,7 +95,6 @@ struct RequestedLayerState : layer_state_t { const std::string name; bool canBeRoot = false; const uint32_t layerCreationFlags; - const uint32_t textureName; // The owner of the layer. If created from a non system process, it will be the calling uid. // If created from a system process, the value can be passed in. const gui::Uid ownerUid; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 59a8825de5..af4b65bcbc 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -149,7 +149,6 @@ Layer::Layer(const LayerCreationArgs& args) args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))), mLayerCreationFlags(args.flags), mBorderEnabled(false), - mTextureName(args.textureName), mLegacyLayerFE(args.flinger->getFactory().createLayerFE(mName)) { ALOGV("Creating Layer %s", getDebugName()); @@ -214,7 +213,6 @@ Layer::Layer(const LayerCreationArgs& args) mSnapshot->sequence = sequence; mSnapshot->name = getDebugName(); - mSnapshot->textureName = mTextureName; mSnapshot->premultipliedAlpha = mPremultipliedAlpha; mSnapshot->parentTransform = {}; } @@ -236,13 +234,6 @@ Layer::~Layer() { mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber, mBufferInfo.mFence); } - if (!isClone()) { - // The original layer and the clone layer share the same texture. Therefore, only one of - // the layers, in this case the original layer, needs to handle the deletion. The original - // layer and the clone should be removed at the same time so there shouldn't be any issue - // with the clone layer trying to use the deleted texture. - mFlinger->deleteTextureAsync(mTextureName); - } const int32_t layerId = getSequence(); mFlinger->mTimeStats->onDestroy(layerId); mFlinger->mFrameTracer->onDestroy(layerId); @@ -3624,7 +3615,6 @@ Rect Layer::computeBufferCrop(const State& s) { sp Layer::createClone(uint32_t mirrorRootId) { LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()); - args.textureName = mTextureName; sp layer = mFlinger->getFactory().createBufferStateLayer(args); layer->setInitialValuesForClone(sp::fromExisting(this), mirrorRootId); return layer; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index faf0e3c117..8a65d9dba6 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -1191,8 +1191,6 @@ private: void setTransformHintLegacy(ui::Transform::RotationFlags); void resetDrawingStateBufferInfo(); - const uint32_t mTextureName; - // Transform hint provided to the producer. This must be accessed holding // the mStateLock. ui::Transform::RotationFlags mTransformHintLegacy = ui::Transform::ROT_0; diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index 5ae52abe7b..a0024d52d4 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -223,7 +223,6 @@ void LayerFE::prepareBufferStateClientComposition( layerSettings.source.buffer.buffer = mSnapshot->externalTexture; layerSettings.source.buffer.isOpaque = mSnapshot->contentOpaque; layerSettings.source.buffer.fence = mSnapshot->acquireFence; - layerSettings.source.buffer.textureName = mSnapshot->textureName; layerSettings.source.buffer.usePremultipliedAlpha = mSnapshot->premultipliedAlpha; bool hasSmpte2086 = mSnapshot->hdrMetadata.validTypes & HdrMetadata::SMPTE2086; bool hasCta861_3 = mSnapshot->hdrMetadata.validTypes & HdrMetadata::CTA861_3; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5dd1598299..9e6e934648 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -730,42 +730,6 @@ void SurfaceFlinger::bootFinished() { })); } -uint32_t SurfaceFlinger::getNewTexture() { - { - std::lock_guard lock(mTexturePoolMutex); - if (!mTexturePool.empty()) { - uint32_t name = mTexturePool.back(); - mTexturePool.pop_back(); - ATRACE_INT("TexturePoolSize", mTexturePool.size()); - return name; - } - - // The pool was too small, so increase it for the future - ++mTexturePoolSize; - } - - // The pool was empty, so we need to get a new texture name directly using a - // blocking call to the main thread - auto genTextures = [this] { - uint32_t name = 0; - getRenderEngine().genTextures(1, &name); - return name; - }; - if (std::this_thread::get_id() == mMainThreadId) { - return genTextures(); - } else { - return mScheduler->schedule(genTextures).get(); - } -} - -void SurfaceFlinger::deleteTextureAsync(uint32_t texture) { - std::lock_guard lock(mTexturePoolMutex); - // We don't change the pool size, so the fix-up logic in postComposition will decide whether - // to actually delete this or not based on mTexturePoolSize - mTexturePool.push_back(texture); - ATRACE_INT("TexturePoolSize", mTexturePool.size()); -} - static std::optional chooseRenderEngineTypeViaSysProp() { char prop[PROPERTY_VALUE_MAX]; @@ -3060,23 +3024,6 @@ void SurfaceFlinger::postComposition(PhysicalDisplayId pacesetterId, // Cleanup any outstanding resources due to rendering a prior frame. getRenderEngine().cleanupPostRender(); - { - std::lock_guard lock(mTexturePoolMutex); - if (mTexturePool.size() < mTexturePoolSize) { - const size_t refillCount = mTexturePoolSize - mTexturePool.size(); - const size_t offset = mTexturePool.size(); - mTexturePool.resize(mTexturePoolSize); - getRenderEngine().genTextures(refillCount, mTexturePool.data() + offset); - ATRACE_INT("TexturePoolSize", mTexturePool.size()); - } else if (mTexturePool.size() > mTexturePoolSize) { - const size_t deleteCount = mTexturePool.size() - mTexturePoolSize; - const size_t offset = mTexturePoolSize; - getRenderEngine().deleteTextures(deleteCount, mTexturePool.data() + offset); - mTexturePool.resize(mTexturePoolSize); - ATRACE_INT("TexturePoolSize", mTexturePool.size()); - } - } - if (mNumTrustedPresentationListeners > 0) { // We avoid any reverse traversal upwards so this shouldn't be too expensive traverseLegacyLayers([&](Layer* layer) { @@ -5553,7 +5500,6 @@ status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, gui::CreateSurface status_t SurfaceFlinger::createBufferStateLayer(LayerCreationArgs& args, sp* handle, sp* outLayer) { - args.textureName = getNewTexture(); *outLayer = getFactory().createBufferStateLayer(args); *handle = (*outLayer)->getHandle(); return NO_ERROR; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 5d2115c2fb..8ff11e2d1b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -277,13 +277,6 @@ public: // The CompositionEngine encapsulates all composition related interfaces and actions. compositionengine::CompositionEngine& getCompositionEngine() const; - // Obtains a name from the texture pool, or, if the pool is empty, posts a - // synchronous message to the main thread to obtain one on the fly - uint32_t getNewTexture(); - - // utility function to delete a texture on the main thread - void deleteTextureAsync(uint32_t texture); - renderengine::RenderEngine& getRenderEngine() const; void onLayerFirstRef(Layer*); @@ -1274,13 +1267,6 @@ private: TransactionCallbackInvoker mTransactionCallbackInvoker; - // We maintain a pool of pre-generated texture names to hand out to avoid - // layer creation needing to run on the main thread (which it would - // otherwise need to do to access RenderEngine). - std::mutex mTexturePoolMutex; - uint32_t mTexturePoolSize = 0; - std::vector mTexturePool; - std::atomic mNumLayers = 0; // to linkToDeath diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp index b2d4131b5d..ed8bb7fc93 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp @@ -144,9 +144,6 @@ void SurfaceFlingerFuzzer::invokeFlinger() { mFlinger->scheduleRepaint(); mFlinger->scheduleSample(); - uint32_t texture = mFlinger->getNewTexture(); - mFlinger->deleteTextureAsync(texture); - sp handle = defaultServiceManager()->checkService( String16(mFdp.ConsumeRandomLengthString().c_str())); LayerHandle::getLayer(handle); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 14f71f28a2..bdbf243dd4 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -597,7 +597,6 @@ struct BaseLayerProperties { const renderengine::LayerSettings layer = layerSettings.back(); EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull())); EXPECT_THAT(layer.source.buffer.fence, Not(IsNull())); - EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName); EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha); EXPECT_EQ(false, layer.source.buffer.isOpaque); EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.x); @@ -873,15 +872,11 @@ struct BufferLayerVariant : public BaseLayerVariant { using FlingerLayerType = sp; static FlingerLayerType createLayer(CompositionTest* test) { - test->mFlinger.mutableTexturePool().push_back(DEFAULT_TEXTURE_ID); - - FlingerLayerType layer = - Base::template createLayerWithFactory(test, [test]() { - LayerCreationArgs args(test->mFlinger.flinger(), sp(), "test-layer", - LayerProperties::LAYER_FLAGS, LayerMetadata()); - args.textureName = test->mFlinger.mutableTexturePool().back(); - return sp::make(args); - }); + FlingerLayerType layer = Base::template createLayerWithFactory(test, [test]() { + LayerCreationArgs args(test->mFlinger.flinger(), sp(), "test-layer", + LayerProperties::LAYER_FLAGS, LayerMetadata()); + return sp::make(args); + }); LayerProperties::setupLayerState(test, layer); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index e59d44d745..02fa4153ed 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -631,7 +631,6 @@ public: auto& mutableVisibleRegionsDirty() { return mFlinger->mVisibleRegionsDirty; } auto& mutableMainThreadId() { return mFlinger->mMainThreadId; } auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; } - auto& mutableTexturePool() { return mFlinger->mTexturePool; } auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; } auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; } auto& mutableMaxRenderTargetSize() { return mFlinger->mMaxRenderTargetSize; } -- GitLab From 9af38ba9d5f9de413d87a64165226a2b488059a8 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 16 Aug 2023 22:41:14 +0000 Subject: [PATCH 0481/1187] Dim correctly in screenshots on some devices Some devices are configured to dim in gamma space for non-colorimetric rendering intents. This configuration is a per-frame configuration on HWC, but that doesn't work for screenshots. Bug: 293560925 Test: HDR playback in youtube and rotate Change-Id: I3110de534d6ef1ad16f9f94d30874bca6f8838c9 --- .../surfaceflinger/ScreenCaptureOutput.cpp | 22 ++++++++++++++----- services/surfaceflinger/ScreenCaptureOutput.h | 4 +++- services/surfaceflinger/SurfaceFlinger.cpp | 7 +++++- services/surfaceflinger/SurfaceFlinger.h | 5 +++++ 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp index 01038432de..ef9b457fc9 100644 --- a/services/surfaceflinger/ScreenCaptureOutput.cpp +++ b/services/surfaceflinger/ScreenCaptureOutput.cpp @@ -45,10 +45,9 @@ Rect getOrientedDisplaySpaceRect(ui::Rotation orientation, int reqWidth, int req std::shared_ptr createScreenCaptureOutput(ScreenCaptureOutputArgs args) { std::shared_ptr output = compositionengine::impl::createOutputTemplated< ScreenCaptureOutput, compositionengine::CompositionEngine, const RenderArea&, - const compositionengine::Output::ColorProfile&, bool>(args.compositionEngine, - args.renderArea, - args.colorProfile, - args.regionSampling); + const compositionengine::Output::ColorProfile&, + bool>(args.compositionEngine, args.renderArea, args.colorProfile, args.regionSampling, + args.dimInGammaSpaceForEnhancedScreenshots); output->editState().isSecure = args.renderArea.isSecure(); output->setCompositionEnabled(true); output->setLayerFilter({args.layerStack}); @@ -81,8 +80,11 @@ std::shared_ptr createScreenCaptureOutput(ScreenCaptureOutp ScreenCaptureOutput::ScreenCaptureOutput( const RenderArea& renderArea, const compositionengine::Output::ColorProfile& colorProfile, - bool regionSampling) - : mRenderArea(renderArea), mColorProfile(colorProfile), mRegionSampling(regionSampling) {} + bool regionSampling, bool dimInGammaSpaceForEnhancedScreenshots) + : mRenderArea(renderArea), + mColorProfile(colorProfile), + mRegionSampling(regionSampling), + mDimInGammaSpaceForEnhancedScreenshots(dimInGammaSpaceForEnhancedScreenshots) {} void ScreenCaptureOutput::updateColorProfile(const compositionengine::CompositionRefreshArgs&) { auto& outputState = editState(); @@ -95,6 +97,14 @@ renderengine::DisplaySettings ScreenCaptureOutput::generateClientCompositionDisp auto clientCompositionDisplay = compositionengine::impl::Output::generateClientCompositionDisplaySettings(); clientCompositionDisplay.clip = mRenderArea.getSourceCrop(); + + auto renderIntent = static_cast(clientCompositionDisplay.renderIntent); + if (mDimInGammaSpaceForEnhancedScreenshots && renderIntent != ui::RenderIntent::COLORIMETRIC && + renderIntent != ui::RenderIntent::TONE_MAP_COLORIMETRIC) { + clientCompositionDisplay.dimmingStage = + aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF; + } + return clientCompositionDisplay; } diff --git a/services/surfaceflinger/ScreenCaptureOutput.h b/services/surfaceflinger/ScreenCaptureOutput.h index 159c2bf903..fc095def99 100644 --- a/services/surfaceflinger/ScreenCaptureOutput.h +++ b/services/surfaceflinger/ScreenCaptureOutput.h @@ -37,6 +37,7 @@ struct ScreenCaptureOutputArgs { float targetBrightness; bool regionSampling; bool treat170mAsSrgb; + bool dimInGammaSpaceForEnhancedScreenshots; }; // ScreenCaptureOutput is used to compose a set of layers into a preallocated buffer. @@ -47,7 +48,7 @@ class ScreenCaptureOutput : public compositionengine::impl::Output { public: ScreenCaptureOutput(const RenderArea& renderArea, const compositionengine::Output::ColorProfile& colorProfile, - bool regionSampling); + bool regionSampling, bool dimInGammaSpaceForEnhancedScreenshots); void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override; @@ -63,6 +64,7 @@ private: const RenderArea& mRenderArea; const compositionengine::Output::ColorProfile& mColorProfile; const bool mRegionSampling; + const bool mDimInGammaSpaceForEnhancedScreenshots; }; std::shared_ptr createScreenCaptureOutput(ScreenCaptureOutputArgs); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9e6e934648..5c000ed8f5 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -452,6 +452,9 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("debug.sf.treat_170m_as_sRGB", value, "0"); mTreat170mAsSrgb = atoi(value); + property_get("debug.sf.dim_in_gamma_in_enhanced_screenshots", value, 0); + mDimInGammaSpaceForEnhancedScreenshots = atoi(value); + mIgnoreHwcPhysicalDisplayOrientation = base::GetBoolProperty("debug.sf.ignore_hwc_physical_display_orientation"s, false); @@ -7787,7 +7790,9 @@ ftl::SharedFuture SurfaceFlinger::renderScreenImpl( .displayBrightnessNits = displayBrightnessNits, .targetBrightness = targetBrightness, .regionSampling = regionSampling, - .treat170mAsSrgb = mTreat170mAsSrgb}); + .treat170mAsSrgb = mTreat170mAsSrgb, + .dimInGammaSpaceForEnhancedScreenshots = + mDimInGammaSpaceForEnhancedScreenshots}); const float colorSaturation = grayscale ? 0 : 1; compositionengine::CompositionRefreshArgs refreshArgs{ diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8ff11e2d1b..81c3f2f9d2 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -317,6 +317,11 @@ public: // on this behavior to increase contrast for some media sources. bool mTreat170mAsSrgb = false; + // If true, then screenshots with an enhanced render intent will dim in gamma space. + // The purpose is to ensure that screenshots appear correct during system animations for devices + // that require that dimming must occur in gamma space. + bool mDimInGammaSpaceForEnhancedScreenshots = false; + // Allows to ignore physical orientation provided through hwc API in favour of // 'ro.surface_flinger.primary_display_orientation'. // TODO(b/246793311): Clean up a temporary property -- GitLab From 90f7fd29d616222a63d9021799186adea3636c93 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 16 Aug 2023 11:02:00 -0700 Subject: [PATCH 0482/1187] SF: use frame rate override even when the physical range is single When the physical range is a single rate (e.g. 120Hz), render rates where discarded if they could be run at a lower physical rate (e.g. 30fps of 60Hz). This CL enables these frame rates to be able to save power by running on a slower rate. Bug: 296079213 Test: play 30fps video while the device policy has a single physical refresh rate Test: atest libsurfaceflinger_unittest Change-Id: I4d6d6ddffd6004022d02329148709204ff9d57db --- .../Scheduler/RefreshRateSelector.cpp | 45 ++++++++----- .../Scheduler/RefreshRateSelector.h | 9 ++- .../DisplayDevice_InitiateModeChange.cpp | 10 +-- .../unittests/RefreshRateSelectorTest.cpp | 64 +++++++++++++++++++ .../tests/unittests/mock/MockFrameRateMode.h | 6 +- 5 files changed, 110 insertions(+), 24 deletions(-) diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index fb985f7c5b..2bb8c3ff41 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -148,8 +148,8 @@ std::string toString(const RefreshRateSelector::PolicyVariant& policy) { } // namespace auto RefreshRateSelector::createFrameRateModes( - std::function&& filterModes, const FpsRange& renderRange) const - -> std::vector { + const Policy& policy, std::function&& filterModes, + const FpsRange& renderRange) const -> std::vector { struct Key { Fps fps; int32_t group; @@ -202,11 +202,25 @@ auto RefreshRateSelector::createFrameRateModes( ALOGV("%s: including %s (%s)", __func__, to_string(fps).c_str(), to_string(mode->getFps()).c_str()); } else { - // We might need to update the map as we found a lower refresh rate - if (isStrictlyLess(mode->getFps(), existingIter->second->second->getFps())) { + // If the primary physical range is a single rate, prefer to stay in that rate + // even if there is a lower physical refresh rate available. This would cause more + // cases to stay within the primary physical range + const Fps existingModeFps = existingIter->second->second->getFps(); + const bool existingModeIsPrimaryRange = policy.primaryRangeIsSingleRate() && + policy.primaryRanges.physical.includes(existingModeFps); + const bool newModeIsPrimaryRange = policy.primaryRangeIsSingleRate() && + policy.primaryRanges.physical.includes(mode->getFps()); + if (newModeIsPrimaryRange == existingModeIsPrimaryRange) { + // We might need to update the map as we found a lower refresh rate + if (isStrictlyLess(mode->getFps(), existingModeFps)) { + existingIter->second = it; + ALOGV("%s: changing %s (%s) as we found a lower physical rate", __func__, + to_string(fps).c_str(), to_string(mode->getFps()).c_str()); + } + } else if (newModeIsPrimaryRange) { existingIter->second = it; - ALOGV("%s: changing %s (%s)", __func__, to_string(fps).c_str(), - to_string(mode->getFps()).c_str()); + ALOGV("%s: changing %s (%s) to stay in the primary range", __func__, + to_string(fps).c_str(), to_string(mode->getFps()).c_str()); } } } @@ -500,10 +514,8 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vectorprimaryRanges.physical.min, policy->primaryRanges.physical.max); - - if (!signals.touch && signals.idle && !(primaryRangeIsSingleRate && hasExplicitVoteLayers)) { + if (!signals.touch && signals.idle && + !(policy->primaryRangeIsSingleRate() && hasExplicitVoteLayers)) { ALOGV("Idle"); const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Ascending); ATRACE_FORMAT_INSTANT("%s (Idle)", to_string(ranking.front().frameRateMode.fps).c_str()); @@ -577,8 +589,11 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vectorprimaryRanges.render.includes(fps); - if ((primaryRangeIsSingleRate || !inPrimaryRange) && + const bool inPrimaryPhysicalRange = + policy->primaryRanges.physical.includes(modePtr->getFps()); + const bool inPrimaryRenderRange = policy->primaryRanges.render.includes(fps); + if (((policy->primaryRangeIsSingleRate() && !inPrimaryPhysicalRange) || + !inPrimaryRenderRange) && !(layer.focused && (layer.vote == LayerVoteType::ExplicitDefault || layer.vote == LayerVoteType::ExplicitExact))) { @@ -689,7 +704,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vectorprimaryRangeIsSingleRate()) { // If we never scored any layers, then choose the rate from the primary // range instead of picking a random score from the app range. if (noLayerScore) { @@ -1236,14 +1251,14 @@ void RefreshRateSelector::constructAvailableRefreshRates() { (supportsFrameRateOverride() || ranges.render.includes(mode.getFps())); }; - auto frameRateModes = createFrameRateModes(filterModes, ranges.render); + auto frameRateModes = createFrameRateModes(*policy, filterModes, ranges.render); if (frameRateModes.empty()) { ALOGW("No matching frame rate modes for %s range. policy: %s", rangeName, policy->toString().c_str()); // TODO(b/292105422): Ideally DisplayManager should not send render ranges smaller than // the min supported. See b/292047939. // For not we just ignore the render ranges. - frameRateModes = createFrameRateModes(filterModes, {}); + frameRateModes = createFrameRateModes(*policy, filterModes, {}); } LOG_ALWAYS_FATAL_IF(frameRateModes.empty(), "No matching frame rate modes for %s range even after ignoring the " diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h index 7af8d0397f..b25919e7a0 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -101,6 +101,11 @@ public: } bool operator!=(const Policy& other) const { return !(*this == other); } + + bool primaryRangeIsSingleRate() const { + return isApproxEqual(primaryRanges.physical.min, primaryRanges.physical.max); + } + std::string toString() const; }; @@ -468,8 +473,8 @@ private: } std::vector createFrameRateModes( - std::function&& filterModes, const FpsRange&) const - REQUIRES(mLock); + const Policy&, std::function&& filterModes, + const FpsRange&) const REQUIRES(mLock); // The display modes of the active display. The DisplayModeIterators below are pointers into // this container, so must be invalidated whenever the DisplayModes change. The Policy below diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp index 60ad7a3a03..2d87ddd488 100644 --- a/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayDevice_InitiateModeChange.cpp @@ -78,7 +78,7 @@ TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setNewMode) { mDisplay->setDesiredActiveMode( {scheduler::FrameRateMode{90_Hz, kMode90}, Event::None})); ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, mDisplay->getDesiredActiveMode()->modeOpt); + EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getDesiredActiveMode()->modeOpt); EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); // Setting another mode should be cached but return None @@ -86,7 +86,7 @@ TEST_F(InitiateModeChangeTest, setDesiredActiveMode_setNewMode) { mDisplay->setDesiredActiveMode( {scheduler::FrameRateMode{120_Hz, kMode120}, Event::None})); ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, mDisplay->getDesiredActiveMode()->modeOpt); + EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, *mDisplay->getDesiredActiveMode()->modeOpt); EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); } @@ -105,7 +105,7 @@ TEST_F(InitiateModeChangeTest, initiateModeChange) NO_THREAD_SAFETY_ANALYSIS { mDisplay->setDesiredActiveMode( {scheduler::FrameRateMode{90_Hz, kMode90}, Event::None})); ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, mDisplay->getDesiredActiveMode()->modeOpt); + EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getDesiredActiveMode()->modeOpt); EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); hal::VsyncPeriodChangeConstraints constraints{ @@ -136,7 +136,7 @@ NO_THREAD_SAFETY_ANALYSIS { mDisplay->setDesiredActiveMode( {scheduler::FrameRateMode{90_Hz, kMode90}, Event::None})); ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, mDisplay->getDesiredActiveMode()->modeOpt); + EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getDesiredActiveMode()->modeOpt); EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); hal::VsyncPeriodChangeConstraints constraints{ @@ -154,7 +154,7 @@ NO_THREAD_SAFETY_ANALYSIS { mDisplay->setDesiredActiveMode( {scheduler::FrameRateMode{120_Hz, kMode120}, Event::None})); ASSERT_NE(std::nullopt, mDisplay->getDesiredActiveMode()); - EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, mDisplay->getDesiredActiveMode()->modeOpt); + EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, *mDisplay->getDesiredActiveMode()->modeOpt); EXPECT_EQ(Event::None, mDisplay->getDesiredActiveMode()->event); EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, *mDisplay->getUpcomingActiveMode().modeOpt); diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index aaf55fbeae..0397b9936f 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -3125,5 +3125,69 @@ TEST_P(RefreshRateSelectorTest, frameRateIsLowerThanMinSupported) { {DisplayModeId(kModeId60), kLowerThanMin, kLowerThanMin})); } +// b/296079213 +TEST_P(RefreshRateSelectorTest, frameRateOverrideInBlockingZone60_120) { + auto selector = createSelector(kModes_60_120, kModeId120); + + const FpsRange only120 = {120_Hz, 120_Hz}; + const FpsRange allRange = {0_Hz, 120_Hz}; + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy( + {kModeId120, {only120, allRange}, {allRange, allRange}})); + + std::vector layers = {{.weight = 1.f}}; + layers[0].name = "30Hz ExplicitExactOrMultiple"; + layers[0].desiredRefreshRate = 30_Hz; + layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; + + if (GetParam() != Config::FrameRateOverride::Enabled) { + EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, + selector.getBestScoredFrameRate(layers).frameRateMode); + } else { + EXPECT_FRAME_RATE_MODE(kMode120, 30_Hz, + selector.getBestScoredFrameRate(layers).frameRateMode); + } +} + +TEST_P(RefreshRateSelectorTest, frameRateOverrideInBlockingZone60_90) { + auto selector = createSelector(kModes_60_90, kModeId90); + + const FpsRange only90 = {90_Hz, 90_Hz}; + const FpsRange allRange = {0_Hz, 90_Hz}; + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy( + {kModeId90, {only90, allRange}, {allRange, allRange}})); + + std::vector layers = {{.weight = 1.f}}; + layers[0].name = "30Hz ExplicitExactOrMultiple"; + layers[0].desiredRefreshRate = 30_Hz; + layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; + + if (GetParam() != Config::FrameRateOverride::Enabled) { + EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, + selector.getBestScoredFrameRate(layers).frameRateMode); + } else { + EXPECT_FRAME_RATE_MODE(kMode90, 30_Hz, + selector.getBestScoredFrameRate(layers).frameRateMode); + } +} + +TEST_P(RefreshRateSelectorTest, frameRateOverrideInBlockingZone60_90_NonDivisor) { + auto selector = createSelector(kModes_60_90, kModeId90); + + const FpsRange only90 = {90_Hz, 90_Hz}; + const FpsRange allRange = {0_Hz, 90_Hz}; + EXPECT_EQ(SetPolicyResult::Changed, + selector.setDisplayManagerPolicy( + {kModeId90, {only90, allRange}, {allRange, allRange}})); + + std::vector layers = {{.weight = 1.f}}; + layers[0].name = "60Hz ExplicitExactOrMultiple"; + layers[0].desiredRefreshRate = 60_Hz; + layers[0].vote = LayerVoteType::ExplicitExactOrMultiple; + + EXPECT_FRAME_RATE_MODE(kMode90, 90_Hz, selector.getBestScoredFrameRate(layers).frameRateMode); +} + } // namespace } // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameRateMode.h b/services/surfaceflinger/tests/unittests/mock/MockFrameRateMode.h index ef9cd9bc43..4cfdd58c70 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockFrameRateMode.h +++ b/services/surfaceflinger/tests/unittests/mock/MockFrameRateMode.h @@ -19,5 +19,7 @@ #include // Use a C style macro to keep the line numbers printed in gtest -#define EXPECT_FRAME_RATE_MODE(modePtr, fps, mode) \ - EXPECT_EQ((scheduler::FrameRateMode{(fps), (modePtr)}), (mode)) +#define EXPECT_FRAME_RATE_MODE(_modePtr, _fps, _mode) \ + EXPECT_EQ((scheduler::FrameRateMode{(_fps), (_modePtr)}), (_mode)) \ + << "Expected " << (_fps) << " (" << (_modePtr)->getFps() << ") but was " \ + << (_mode).fps << " (" << (_mode).modePtr->getFps() << ")" -- GitLab From 44e6e832e93ab37ed29b08b462a3a0bf3aa6f4f1 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 6 Jun 2023 00:03:25 +0000 Subject: [PATCH 0483/1187] Bootstrap IInputFlingerRust - the Rust component of inputflinger When inputflinger boots, we create the Rust component of inputflinger, which we interact with from C++ through the local AIDL interface IInputFlingerRust. After we have access to the IInputFlingerRust binder object in C++, all communication between C++ and Rust can take place purely through AIDL interfaces. To initialize the interface, we must first pass a raw pointer to an AIDL implementation across the language barrier through some other means. In this CL, we use cxxbridge to bootstrap the local AIDL interface for IInputFlingerRust. Bug: 278783893 Test: manual, boot Change-Id: Ifbd0168ae4fadaa5b357f6064113f1691e6cf5a7 --- services/inputflinger/Android.bp | 9 ++ services/inputflinger/InputManager.cpp | 70 +++++++++++-- services/inputflinger/InputManager.h | 5 + services/inputflinger/aidl/Android.bp | 31 ++++++ .../inputflinger/IInputFlingerRust.aidl | 34 +++++++ services/inputflinger/rust/Android.bp | 52 ++++++++++ .../rust/ffi/InputFlingerBootstrap.h | 21 ++++ services/inputflinger/rust/lib.rs | 99 +++++++++++++++++++ 8 files changed, 313 insertions(+), 8 deletions(-) create mode 100644 services/inputflinger/aidl/Android.bp create mode 100644 services/inputflinger/aidl/com/android/server/inputflinger/IInputFlingerRust.aidl create mode 100644 services/inputflinger/rust/Android.bp create mode 100644 services/inputflinger/rust/ffi/InputFlingerBootstrap.h create mode 100644 services/inputflinger/rust/lib.rs diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 18f6dbc1e1..d5512132be 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -87,6 +87,7 @@ cc_defaults { srcs: [":libinputflinger_sources"], shared_libs: [ "android.hardware.input.processor-V1-ndk", + "com.android.server.inputflinger-ndk", "libbase", "libbinder", "libbinder_ndk", @@ -107,6 +108,14 @@ cc_defaults { "libpalmrejection", "libui-types", ], + generated_headers: [ + "cxx-bridge-header", + "inputflinger_rs_bootstrap_bridge_header", + ], + header_libs: ["inputflinger_rs_bootstrap_cxx_headers"], + generated_sources: ["inputflinger_rs_bootstrap_bridge_code"], + whole_static_libs: ["libinputflinger_rs"], + export_shared_lib_headers: ["com.android.server.inputflinger-ndk"], target: { android: { shared_libs: [ diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index c90356459f..da79ae3a48 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -23,22 +23,22 @@ #include "InputReaderFactory.h" #include "UnwantedInteractionBlocker.h" +#include +#include #include #include - +#include #include -#include - #include namespace android { -static const bool ENABLE_INPUT_DEVICE_USAGE_METRICS = - sysprop::InputProperties::enable_input_device_usage_metrics().value_or(true); +namespace { -using gui::FocusRequest; +const bool ENABLE_INPUT_DEVICE_USAGE_METRICS = + sysprop::InputProperties::enable_input_device_usage_metrics().value_or(true); -static int32_t exceptionCodeFromStatusT(status_t status) { +int32_t exceptionCodeFromStatusT(status_t status) { switch (status) { case OK: return binder::Status::EX_NONE; @@ -57,6 +57,58 @@ static int32_t exceptionCodeFromStatusT(status_t status) { } } +// Convert a binder interface into a raw pointer to an AIBinder. +using IInputFlingerRustBootstrapCallback = aidl::com::android::server::inputflinger:: + IInputFlingerRust::IInputFlingerRustBootstrapCallback; +IInputFlingerRustBootstrapCallbackAIBinder* binderToPointer( + IInputFlingerRustBootstrapCallback& interface) { + ndk::SpAIBinder spAIBinder = interface.asBinder(); + auto* ptr = spAIBinder.get(); + AIBinder_incStrong(ptr); + return ptr; +} + +// Create the Rust component of InputFlinger that uses AIDL interfaces as a the foreign function +// interface (FFI). The bootstraping process for IInputFlingerRust is as follows: +// - Create BnInputFlingerRustBootstrapCallback in C++. +// - Use the cxxbridge ffi interface to call the Rust function `create_inputflinger_rust()`, and +// pass the callback binder object as a raw pointer. +// - The Rust implementation will create the implementation of IInputFlingerRust, and pass it +// to C++ through the callback. +// - After the Rust function returns, the binder interface provided to the callback will be the +// only strong reference to the IInputFlingerRust. +std::shared_ptr createInputFlingerRust() { + using namespace aidl::com::android::server::inputflinger; + + class Callback : public IInputFlingerRust::BnInputFlingerRustBootstrapCallback { + ndk::ScopedAStatus onProvideInputFlingerRust( + const std::shared_ptr& inputFlingerRust) override { + mService = inputFlingerRust; + return ndk::ScopedAStatus::ok(); + } + + public: + std::shared_ptr consumeInputFlingerRust() { + auto service = mService; + mService.reset(); + return service; + } + + private: + std::shared_ptr mService; + }; + + auto callback = ndk::SharedRefBase::make(); + create_inputflinger_rust(binderToPointer(*callback)); + auto service = callback->consumeInputFlingerRust(); + LOG_ALWAYS_FATAL_IF(!service, + "create_inputflinger_rust did not provide the IInputFlingerRust " + "implementation through the callback."); + return service; +} + +} // namespace + /** * The event flow is via the "InputListener" interface, as follows: * InputReader @@ -67,6 +119,8 @@ static int32_t exceptionCodeFromStatusT(status_t status) { */ InputManager::InputManager(const sp& readerPolicy, InputDispatcherPolicyInterface& dispatcherPolicy) { + mInputFlingerRust = createInputFlingerRust(); + mDispatcher = createInputDispatcher(dispatcherPolicy); if (ENABLE_INPUT_DEVICE_USAGE_METRICS) { @@ -190,7 +244,7 @@ status_t InputManager::dump(int fd, const Vector& args) { return NO_ERROR; } -binder::Status InputManager::setFocusedWindow(const FocusRequest& request) { +binder::Status InputManager::setFocusedWindow(const gui::FocusRequest& request) { mDispatcher->setFocusedWindow(request); return binder::Status::ok(); } diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index 9dc285f2c0..528d2aa5ca 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -30,6 +30,7 @@ #include { + /// Create a new wrapper around a [BufferSubscriber]. + pub fn new(subscriber: S) -> Self { + Self(Arc::new(Mutex::new(SharedSubscriberInner { subscriber, is_subscribed: false }))) + } + + /// Provides access to an immutable reference to the wrapped [BufferSubscriber]. + pub fn map_inner R>(&self, f: F) -> R { + let inner = self.0.lock().unwrap(); + f(&inner.subscriber) + } + + /// Provides access to a mutable reference to the wrapped [BufferSubscriber]. + pub fn map_inner_mut R>(&self, f: F) -> R { + let mut inner = self.0.lock().unwrap(); + f(&mut inner.subscriber) + } +} + +impl Clone for SharedSubscriber { + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } +} + +impl BufferSubscriber for SharedSubscriber { + fn get_subscriber_stream_config(&self) -> StreamConfig { + let inner = self.0.lock().unwrap(); + inner.subscriber.get_subscriber_stream_config() + } + + fn on_subscribe(&mut self, subscription: Box) { + let mut inner = self.0.lock().unwrap(); + assert!( + !inner.is_subscribed, + "A SharedSubscriber can not be shared between two BufferPublishers" + ); + inner.is_subscribed = true; + + inner.subscriber.on_subscribe(subscription); + } + + fn on_next(&mut self, frame: Frame) { + let mut inner = self.0.lock().unwrap(); + inner.subscriber.on_next(frame); + } + + fn on_error(&mut self, error: BufferError) { + let mut inner = self.0.lock().unwrap(); + inner.subscriber.on_error(error); + } + + fn on_complete(&mut self) { + let mut inner = self.0.lock().unwrap(); + inner.subscriber.on_complete(); + } +} diff --git a/libs/bufferstreams/rust/src/subscribers/testing.rs b/libs/bufferstreams/rust/src/subscribers/testing.rs new file mode 100644 index 0000000000..b7e970579e --- /dev/null +++ b/libs/bufferstreams/rust/src/subscribers/testing.rs @@ -0,0 +1,106 @@ +// Copyright (C) 2023 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. + +//! Provides useful subscribers for testing specifically. These should not be used in normal code. + +use crate::*; + +/// Represents a callback called by a [BufferPublisher] on a [BufferSubscriber]. +pub enum TestingSubscriberEvent { + /// Represents a call to [BufferSubscriber::on_subscribe]. + Subscribe, + /// Represents a call to [BufferSubscriber::on_next]. + Next(Frame), + /// Represents a call to [BufferSubscriber::on_error]. + Error(BufferError), + /// Represents a call to [BufferSubscriber::on_complete]. + Complete, +} + +/// A [BufferSubscriber] specifically for testing. Logs events as they happen which can be retrieved +/// by the test to ensure appropriate behavior. +pub struct TestSubscriber { + config: StreamConfig, + subscription: Option>, + events: Vec, +} + +impl TestSubscriber { + /// Create a new [TestSubscriber]. + pub fn new(config: StreamConfig) -> Self { + Self { config, subscription: None, events: Vec::new() } + } + + /// Returns true if this [BufferSubscriber] has an active subscription. + pub fn has_subscription(&self) -> bool { + self.subscription.is_some() + } + + /// Make a request on behalf of this test subscriber. + /// + /// This will panic if there is no owned subscription. + pub fn request(&self, n: u64) { + let subscription = self + .subscription + .as_deref() + .expect("Tried to request on a TestSubscriber with no subscription"); + subscription.request(n); + } + + /// Cancel on behalf of this test subscriber. + /// + /// # Panics + /// + /// This will panic if there is no owned subscription. + pub fn cancel(&self) { + let subscription = self + .subscription + .as_deref() + .expect("Tried to cancel a TestSubscriber with no subscription"); + subscription.cancel(); + } + + /// Gets all of the events that have happened to this [BufferSubscriber] since the last call + /// to this function or it was created. + pub fn take_events(&mut self) -> Vec { + let mut out = Vec::new(); + out.append(&mut self.events); + out + } +} + +impl BufferSubscriber for TestSubscriber { + fn get_subscriber_stream_config(&self) -> StreamConfig { + self.config + } + + fn on_subscribe(&mut self, subscription: Box) { + assert!(self.subscription.is_none(), "TestSubscriber must only be subscribed to once"); + self.subscription = Some(subscription); + + self.events.push(TestingSubscriberEvent::Subscribe); + } + + fn on_next(&mut self, frame: Frame) { + self.events.push(TestingSubscriberEvent::Next(frame)); + } + + fn on_error(&mut self, error: BufferError) { + self.events.push(TestingSubscriberEvent::Error(error)); + } + + fn on_complete(&mut self) { + self.events.push(TestingSubscriberEvent::Complete); + } +} diff --git a/libs/bufferstreams/rust/src/subscriptions/mod.rs b/libs/bufferstreams/rust/src/subscriptions/mod.rs new file mode 100644 index 0000000000..e046dbbda3 --- /dev/null +++ b/libs/bufferstreams/rust/src/subscriptions/mod.rs @@ -0,0 +1,19 @@ +// Copyright (C) 2023 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. + +//! This module provides [BufferSubscription] implementations and helpers. + +mod shared_buffer_subscription; + +pub use shared_buffer_subscription::*; diff --git a/libs/bufferstreams/rust/src/subscriptions/shared_buffer_subscription.rs b/libs/bufferstreams/rust/src/subscriptions/shared_buffer_subscription.rs new file mode 100644 index 0000000000..90275c7320 --- /dev/null +++ b/libs/bufferstreams/rust/src/subscriptions/shared_buffer_subscription.rs @@ -0,0 +1,84 @@ +// Copyright (C) 2023 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. + +use std::sync::{Arc, Mutex}; + +use crate::*; + +/// A simple sharable helper that can be used as a [BufferSubscription] by a [BufferSubscriber] and +/// as a state tracker by a [BufferPublisher]. +#[derive(Clone, Debug)] +pub struct SharedBufferSubscription(Arc>); + +#[derive(Debug, Default)] +struct BufferSubscriptionData { + requests: u64, + is_cancelled: bool, +} + +impl SharedBufferSubscription { + /// Create a new [SharedBufferSubscription]. + pub fn new() -> Self { + SharedBufferSubscription::default() + } + + /// Clone this [SharedBufferSubscription] so it can be passed into + /// [BufferSubscriber::on_subscribe]. + pub fn clone_for_subscriber(&self) -> Box { + Box::new(self.clone()) as Box + } + + /// If possible (not cancelled and with requests pending), take + pub fn take_request(&self) -> bool { + let mut data = self.0.lock().unwrap(); + + if data.is_cancelled || data.requests == 0 { + false + } else { + data.requests -= 1; + true + } + } + + /// Get the number of pending requests made by the [BufferSubscriber] via + /// [BufferSubscription::request]. + pub fn pending_requests(&self) -> u64 { + self.0.lock().unwrap().requests + } + + /// Get get whether the [BufferSubscriber] has called [BufferSubscription::cancel]. + pub fn is_cancelled(&self) -> bool { + self.0.lock().unwrap().is_cancelled + } +} + +impl Default for SharedBufferSubscription { + fn default() -> Self { + Self(Arc::new(Mutex::new(BufferSubscriptionData::default()))) + } +} + +impl BufferSubscription for SharedBufferSubscription { + fn request(&self, n: u64) { + let mut data = self.0.lock().unwrap(); + if !data.is_cancelled { + data.requests = data.requests.saturating_add(n); + } + } + + fn cancel(&self) { + let mut data = self.0.lock().unwrap(); + data.is_cancelled = true; + } +} -- GitLab From 9b08532c0e28a9c5b5b7478c80448110d0e5cec8 Mon Sep 17 00:00:00 2001 From: ramindani Date: Tue, 19 Sep 2023 17:18:37 -0700 Subject: [PATCH 0671/1187] [SF] Add sysprop to enable vrr config Test: manual with adb shell setprop ro.surface_flinger.enable_vrr_config true BUG: 284845445 Change-Id: I36e2e132021e9ac17e1d928e754c6df54bdc29d3 --- .../DisplayHardware/DisplayMode.h | 5 ++- .../Scheduler/RefreshRateSelector.cpp | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 5 +-- services/surfaceflinger/SurfaceFlinger.h | 1 - services/surfaceflinger/Utils/FlagUtils.h | 33 +++++++++++++++++++ 5 files changed, 40 insertions(+), 7 deletions(-) create mode 100644 services/surfaceflinger/Utils/FlagUtils.h diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h index 422513be9b..1775a7a4a6 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayMode.h +++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h @@ -31,8 +31,7 @@ #include "DisplayHardware/Hal.h" #include "Scheduler/StrongTyping.h" - -#include +#include "Utils/FlagUtils.h" namespace android { @@ -141,7 +140,7 @@ public: // Peak refresh rate represents the highest refresh rate that can be used // for the presentation. Fps getPeakFps() const { - return flags::vrr_config() && mVrrConfig + return flagutils::vrrConfigEnabled() && mVrrConfig ? Fps::fromPeriodNsecs(mVrrConfig->minFrameIntervalNs) : mVsyncRate; } diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index e378946f1b..b06723ddab 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -38,6 +38,7 @@ #include "../SurfaceFlingerProperties.h" #include "RefreshRateSelector.h" +#include "Utils/FlagUtils.h" #include @@ -114,7 +115,7 @@ std::pair divisorRange(Fps vsyncRate, Fps peakFps, FpsRange using fps_approx_ops::operator/; // use signed type as `fps / range.max` might be 0 auto start = std::max(1, static_cast(peakFps / range.max) - 1); - if (flags::vrr_config()) { + if (flagutils::vrrConfigEnabled()) { start = std::max(1, static_cast(vsyncRate / std::min(range.max, peakFps, fps_approx_ops::operator<)) - diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index fadde51a33..1a24332d22 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -155,6 +155,7 @@ #include "TimeStats/TimeStats.h" #include "TunnelModeEnabledReporter.h" #include "Utils/Dumper.h" +#include "Utils/FlagUtils.h" #include "WindowInfosListenerInvoker.h" #include @@ -498,7 +499,6 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI mMiscFlagValue = flags::misc1(); mConnectedDisplayFlagValue = flags::connected_display(); mMisc2FlagEarlyBootValue = flags::late_boot_misc2(); - mVrrConfigFlagValue = flags::vrr_config(); } LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { @@ -6418,7 +6418,8 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp StringAppendF(&result, "Misc2FlagValue: %s (%s after boot)\n", mMisc2FlagLateBootValue ? "true" : "false", mMisc2FlagEarlyBootValue == mMisc2FlagLateBootValue ? "stable" : "modified"); - StringAppendF(&result, "VrrConfigFlagValue: %s\n", mVrrConfigFlagValue ? "true" : "false"); + StringAppendF(&result, "VrrConfigFlagValue: %s\n", + flagutils::vrrConfigEnabled() ? "true" : "false"); getRenderEngine().dump(result); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index ef6b8159e4..e22dd5680f 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1457,7 +1457,6 @@ private: bool mConnectedDisplayFlagValue; bool mMisc2FlagEarlyBootValue; bool mMisc2FlagLateBootValue; - bool mVrrConfigFlagValue; }; class SurfaceComposerAIDL : public gui::BnSurfaceComposer { diff --git a/services/surfaceflinger/Utils/FlagUtils.h b/services/surfaceflinger/Utils/FlagUtils.h new file mode 100644 index 0000000000..8435f04573 --- /dev/null +++ b/services/surfaceflinger/Utils/FlagUtils.h @@ -0,0 +1,33 @@ +/** + * Copyright 2023 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 +#include +#include + +namespace android::flagutils { + +using namespace std::literals::string_literals; +using namespace com::android::graphics::surfaceflinger; + +inline bool vrrConfigEnabled() { + static const bool enable_vrr_config = + base::GetBoolProperty("debug.sf.enable_vrr_config"s, false); + return flags::vrr_config() || enable_vrr_config; +} +} // namespace android::flagutils -- GitLab From 529fa06fa0088abfd916e932ad2fe82acc94ea81 Mon Sep 17 00:00:00 2001 From: Carlos Martinez Romero Date: Fri, 15 Sep 2023 18:34:06 +0000 Subject: [PATCH 0672/1187] Bufferstreams test app. Used to test out BufferQueues and BufferStreams. Test: Ran the app. Bug: 296272152 Change-Id: Ie1192658bf7db49b2ccc216433585fbd1cd1bff7 --- libs/bufferstreams/examples/app/Android.bp | 27 +++ .../examples/app/AndroidManifest.xml | 25 +++ .../bufferstreamsdemoapp/MainActivity.java | 39 ++++ .../bufferstreams/examples/app/jni/Android.bp | 28 +++ libs/bufferstreams/examples/app/jni/main.cpp | 37 ++++ .../res/drawable/ic_launcher_background.xml | 170 ++++++++++++++++++ .../res/drawable/ic_launcher_foreground.xml | 30 ++++ .../examples/app/res/layout/activity_main.xml | 18 ++ .../app/res/mipmap-anydpi/ic_launcher.xml | 6 + .../res/mipmap-anydpi/ic_launcher_round.xml | 6 + .../app/res/mipmap-hdpi/ic_launcher.webp | Bin 0 -> 1404 bytes .../res/mipmap-hdpi/ic_launcher_round.webp | Bin 0 -> 2898 bytes .../app/res/mipmap-mdpi/ic_launcher.webp | Bin 0 -> 982 bytes .../res/mipmap-mdpi/ic_launcher_round.webp | Bin 0 -> 1772 bytes .../app/res/mipmap-xhdpi/ic_launcher.webp | Bin 0 -> 1900 bytes .../res/mipmap-xhdpi/ic_launcher_round.webp | Bin 0 -> 3918 bytes .../app/res/mipmap-xxhdpi/ic_launcher.webp | Bin 0 -> 2884 bytes .../res/mipmap-xxhdpi/ic_launcher_round.webp | Bin 0 -> 5914 bytes .../app/res/mipmap-xxxhdpi/ic_launcher.webp | Bin 0 -> 3844 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.webp | Bin 0 -> 7778 bytes .../examples/app/res/values/colors.xml | 10 ++ .../examples/app/res/values/strings.xml | 3 + 22 files changed, 399 insertions(+) create mode 100644 libs/bufferstreams/examples/app/Android.bp create mode 100644 libs/bufferstreams/examples/app/AndroidManifest.xml create mode 100644 libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.java create mode 100644 libs/bufferstreams/examples/app/jni/Android.bp create mode 100644 libs/bufferstreams/examples/app/jni/main.cpp create mode 100644 libs/bufferstreams/examples/app/res/drawable/ic_launcher_background.xml create mode 100644 libs/bufferstreams/examples/app/res/drawable/ic_launcher_foreground.xml create mode 100644 libs/bufferstreams/examples/app/res/layout/activity_main.xml create mode 100644 libs/bufferstreams/examples/app/res/mipmap-anydpi/ic_launcher.xml create mode 100644 libs/bufferstreams/examples/app/res/mipmap-anydpi/ic_launcher_round.xml create mode 100644 libs/bufferstreams/examples/app/res/mipmap-hdpi/ic_launcher.webp create mode 100644 libs/bufferstreams/examples/app/res/mipmap-hdpi/ic_launcher_round.webp create mode 100644 libs/bufferstreams/examples/app/res/mipmap-mdpi/ic_launcher.webp create mode 100644 libs/bufferstreams/examples/app/res/mipmap-mdpi/ic_launcher_round.webp create mode 100644 libs/bufferstreams/examples/app/res/mipmap-xhdpi/ic_launcher.webp create mode 100644 libs/bufferstreams/examples/app/res/mipmap-xhdpi/ic_launcher_round.webp create mode 100644 libs/bufferstreams/examples/app/res/mipmap-xxhdpi/ic_launcher.webp create mode 100644 libs/bufferstreams/examples/app/res/mipmap-xxhdpi/ic_launcher_round.webp create mode 100644 libs/bufferstreams/examples/app/res/mipmap-xxxhdpi/ic_launcher.webp create mode 100644 libs/bufferstreams/examples/app/res/mipmap-xxxhdpi/ic_launcher_round.webp create mode 100644 libs/bufferstreams/examples/app/res/values/colors.xml create mode 100644 libs/bufferstreams/examples/app/res/values/strings.xml diff --git a/libs/bufferstreams/examples/app/Android.bp b/libs/bufferstreams/examples/app/Android.bp new file mode 100644 index 0000000000..0ecf94c48d --- /dev/null +++ b/libs/bufferstreams/examples/app/Android.bp @@ -0,0 +1,27 @@ +// Copyright (C) 2023 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. + +android_app { + name: "BufferStreamsDemoApp", + srcs: ["java/**/*.java"], + sdk_version: "current", + + jni_uses_platform_apis: true, + jni_libs: ["libbufferstreamdemoapp"], + use_embedded_native_libs: true, + + static_libs: [ + "androidx.appcompat_appcompat", + ], +} diff --git a/libs/bufferstreams/examples/app/AndroidManifest.xml b/libs/bufferstreams/examples/app/AndroidManifest.xml new file mode 100644 index 0000000000..872193c4e6 --- /dev/null +++ b/libs/bufferstreams/examples/app/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.java b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.java new file mode 100644 index 0000000000..67b95a5349 --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.java @@ -0,0 +1,39 @@ +// Copyright (C) 2023 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. + +package com.android.graphics.bufferstreamsdemoapp; + +import android.os.Bundle; +import android.widget.TextView; +import androidx.appcompat.app.AppCompatActivity; + +public class MainActivity extends AppCompatActivity { + // Used to load the 'bufferstreamsdemoapp' library on application startup. + static { System.loadLibrary("bufferstreamdemoapp"); } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + RunBufferQueue(); + System.out.println("stringFromJNI: " + stringFromJNI()); + } + + /** + * A native method that is implemented by the 'bufferstreamsdemoapp' native + * library, which is packaged with this application. + */ + public native String stringFromJNI(); + public native void RunBufferQueue(); +} \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/jni/Android.bp b/libs/bufferstreams/examples/app/jni/Android.bp new file mode 100644 index 0000000000..67910a1c4d --- /dev/null +++ b/libs/bufferstreams/examples/app/jni/Android.bp @@ -0,0 +1,28 @@ +// Copyright (C) 2023 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. + +cc_library_shared { + name: "libbufferstreamdemoapp", + cflags: [ + "-Werror", + "-Wno-error=unused-parameter", + ], + shared_libs: [ + "libgui", + "libbase", + "libutils", + ], + header_libs: ["jni_headers"], + srcs: ["*.cpp"], +} diff --git a/libs/bufferstreams/examples/app/jni/main.cpp b/libs/bufferstreams/examples/app/jni/main.cpp new file mode 100644 index 0000000000..34e0eb451c --- /dev/null +++ b/libs/bufferstreams/examples/app/jni/main.cpp @@ -0,0 +1,37 @@ +// Copyright (C) 2023 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 + +#include + +extern "C" +{ + JNIEXPORT jstring JNICALL + Java_com_android_graphics_bufferstreamsdemoapp_MainActivity_stringFromJNI( + JNIEnv *env, + jobject /* this */) { + const char* hello = "Hello from C++"; + return env->NewStringUTF(hello); + } + + JNIEXPORT void JNICALL + Java_com_android_graphics_bufferstreamsdemoapp_MainActivity_RunBufferQueue( + JNIEnv *env, + jobject /* this */) { + android::sp producer; + android::sp consumer; + android::BufferQueue::createBufferQueue(&producer, &consumer); + } +} \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/res/drawable/ic_launcher_background.xml b/libs/bufferstreams/examples/app/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000000..07d5da9cbf --- /dev/null +++ b/libs/bufferstreams/examples/app/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/bufferstreams/examples/app/res/drawable/ic_launcher_foreground.xml b/libs/bufferstreams/examples/app/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000000..2b068d1146 --- /dev/null +++ b/libs/bufferstreams/examples/app/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/res/layout/activity_main.xml b/libs/bufferstreams/examples/app/res/layout/activity_main.xml new file mode 100644 index 0000000000..79fb331f09 --- /dev/null +++ b/libs/bufferstreams/examples/app/res/layout/activity_main.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/res/mipmap-anydpi/ic_launcher.xml b/libs/bufferstreams/examples/app/res/mipmap-anydpi/ic_launcher.xml new file mode 100644 index 0000000000..6f3b755bf5 --- /dev/null +++ b/libs/bufferstreams/examples/app/res/mipmap-anydpi/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/res/mipmap-anydpi/ic_launcher_round.xml b/libs/bufferstreams/examples/app/res/mipmap-anydpi/ic_launcher_round.xml new file mode 100644 index 0000000000..6f3b755bf5 --- /dev/null +++ b/libs/bufferstreams/examples/app/res/mipmap-anydpi/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/res/mipmap-hdpi/ic_launcher.webp b/libs/bufferstreams/examples/app/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..c209e78ecd372343283f4157dcfd918ec5165bb3 GIT binary patch literal 1404 zcmWIYbaN|VWnc(*bqWXzu!!JdU|xt`5!v_jjvkEam13D%HG@k-IMc zNLB6Ts|;5bzSwJe>ULbl1cvf&ZkhaCoSq2>@AZ5-D>jj1lIT2H&dag$gn7N+e4L{u z^V=qU9`n4<|KGj+Jg1Vc;+*Ym8}@ms^PajGxhz`fUcGqB^ot%&0-(G6 ztJqa}H}n3HU3Yip`SGVeoN_0jHpk{$^4G>a6%8p%x7&Z)J5^*02Bzg(emT zh6~~ha~ZWf7(5v43`IJe7AY!6)06s|5LTRZ~a|9(#3-?A(9e&YZ4?>X2s?GW>o|33SDelz`B z`+wn|Q;!w?=CKR)$n9qK&JB=|i?B8=Za(_yby{8ahEC_FQc?|fX6jq-S#{;T*P>@x z_ZT?env#-TMm+56J zYxbSv3`wunSg8L0QM8}=O*rp?-VOhM|NEg<)7%*xHvh-siA*kcCjMS>GB?P(>_@}3 z)Ft&xoDRNt&3eFh)jsaGt6V1Y-utsGX3D{BPrGiMe#bFC=cA;8JMEoLi`oHXxI)DE^oHMbkaEEw% z-9tKtyZ;ro&wXg4x@O8`m1O~q z?MexGg12&nX4y|S@pnFV^V}u9giQ-GT$3$KnU6R18RkeC3%K&!v-YvBIofAmw>PFs zIdS)#VNole5AMDC;{Wfgucb?`mgwZOH*=)K)xFxh zvAbsbOYcV^yis0yb^(2L-iLG^EU>@ZcYlA->$iWR*2l$qNu~2Y6n&DlA@j?-eeQ>s z$tnK&Z05FhmCbjTD+dy9O%PYyrL7Vlbht#oNZ2QS;ASZ@?QSi@KIA`)Q{Plar-EBMn zOue{8S#RsoI9{I8-1%wjYL3ra-WXN>myuB|k`TLaRw0(}Q{v*)neU%|Uf=%kE$@XZ zhG9pKE&f~)a@RGze*OGS1~2BsylnCL*)X3i|99J|eC4QK#}-~?>BH&Aafd zWjZOh{NVc@|Mx8WeQ&M$PqIskKh9jN|JQv<&;0)q`yZ~E&-DGzd;15MW#|73p4FDw z7Oym+LiWGhsn`4Zdv7t_;1XiVJF+=y-{rn5k2YR9d}BwU-%Zx7^dl3uQO%=KtB6@_8OJ`?s99PuHc(Wv{Uvn57cQnzH^! z4YT&W4>v_49d0g>;5}1QsqLw*bguIK-eRRko_V#EY72aobT&L-pQO|$YAra)UWXy) z?H0HH>?%h$pNjLSyTHFTTZD1@o5kYirK&#Ospl5Bs^WBcdditu$Df4zc4P@8o+&!k z$5~=Hz27y&v^)8mahg-|JA1KhUV`UTT02EQ$+(1e7MN)IY?yFdc~#TV8Gl98qIT3X z<+w`qp4Rl)QQ*p5k{WN6_9(e-vDU^NGYy%0D%Eo$*=nm_Iu+cp7Fo9EyM*zH8S<-( zbe>%_4mh8j;GJ3H&*}PO^CeZDWfSd0{LeLOrhQauJ;-&xL3dH%i?m$@GTTcW#Uo<; zjyK5WH|QF?3ik3iw0R4K4powOB8I2&<4clQ^(Uj_3W$DXcxV zjR)uF>MkgGAGK?O%ys_DTn)LunuI2O_?_0>^yO@cqUF8WeOw_XMar=jeY4eFRxzx+ zX0Gv&!#=}z;R?_B9=`%?D${O>ImiC?pAyhg|KwG`rL=QOwG#98Xb4Yrsy&|GbGYMY zsk`kdlbM#*pzy1VI5w^M*Ee@fMUMHI`3^U=Cjaj%{FL<1WJ2K6gWG!I4_RayPWQ{} z49K*qKIG@Msb#m{$z_3+$=9FuO;TC7d)e;5P)F16cb`b8t1sKVcD?JuS-Vv0pYk2^ z?A-ZzR?TX+($eVvC%s?B2+etX>GH4JCacy)S1+&gKejK-POW~zQ&92b*Z1)zdh>m?RW6x4`?Q$9`o-?6Ybw5O=a)6J znxAdrvF2pT?)Lt<)la$Q|86dLJ5APl+nU%P=iT*VEX(hFn3r=*;o`1!s<%xIlFl4i zS=?{;ZpY&1elso7jyQyGTk5C$(`ss_?45b9U%h<$_T{Oq{CQ`Wm^6jnax4A%wRGZD zE>kv!umB5%GX|4H8{Z@_=K|4QA)x&-@h`_S6Qf2Dsh)QA3idd>WW^{=-t z8-KfgX#H*dd;SOcKdXQF|C@c;|3t~WUrT=WpZoB8>;4~njC{d|%8TTG+k4fYt629} z`$G7y{eSuc-+!+;Su6Tm{R8ix`M=ix@qbr4*FLkh&)(F)Ap{?{NBv@`t@kSAS1B$~ybiwY(%|)}H4jSI%v=Qr@Kb`cGWAVur)+zV()i z4?A6W@j#!K@m+50(S5dCwQWzj|JbP4>YvFS6mr$y>y5yEP4n*)KXi85vDBuw8+)!4 zIjeehEpxeZftfr@;e;aal}OP<_kN? z8H{ULme&3EZhY!uu;D>YX!zaP=dUD)?5tnSEBwE5$LCktf9xI-v&s*Ozst5$IQ ztz6E$SS?<0^Oel!de8Uk-&y&8nqNTNN&Tt+Zu}Bi&*pc0mW1hw3qg@P8K2jzKfCzw zHwEtaOZf}R?W9-jP1LO2u-f?4frw)m@uOwudWAd#cu zuQEC>WPX%+vnGjgrr~jxtOx%pBYz+J^#AaG;q$9E&IwJm|GvUqUxGzG_5e4xXEvv6 zUG??f*A4cxJX`Ph{MWt5;i?784E{zroM3h>eb|uf@u>gLnbODXYbvw2O_xZse|c(u z{@?5UpX+y+b=}`LwM!vR@9)Xk%}PSkq$=wz3t2gzT#1vK$a^#WIQv~K*X{jr5`vA4 zk}IoYntV?^VNM;4_Wtk=Dw1> zU>nNDXITF309S16?5P2*0cZIdFI}(TnK${}flpU|+W*b$I?TVL`}AF|KU=RT$2+{M z@x5zt%k8c5RqGdKzp4zL-c{E;J2SyAWbSN#%N)P`n}0tJxXw6%tL0fnyWefC^;4sF z=${nIn6pMYeVf3BCvCqk&AGa7L*L4RBX?!D-25h+IA>X7_2<=3{N)~Ls;5j@V)#yj z`|9^pJ;^pHU-6p9OXHSlZp_p7o7i^ZvgKXR34(E222)?wGG6+d{`Y|L)!s>5SvPJq z9*V6fURC|MuVF>KzT|!p=Gexx`XzH*t}NXqZtE~9F6@)v(j|NkXLH-zX}46JOMT#* zlol>^bI1PcT{3F25#f7R%wXAfO>A0)vBJF8O9lRu*6&J{Sl5;>B;LL<&f|~5f$NKe zy8WNXDcD6eO~KY~l{Xv%)=37U*G z9@e=QE!yR(DL-y_ZvWj^|G(Z?>DZ%9&#cqV_P<#iGf%`!AZcZQ_~U-r8|lRfslT&% ztGiT|PYZfe)F5*2<;?VuC+=%)f^IuKDr&ydqI)rT+M4}e-Rsil9K0Ho5%Nm@pTH&A zDfbM@=gFL!TbX}-(VL%(gU;7n5|PbnUbihsL;pX2v4Ct&tU9ly((2#k_7AF;7oL2w zNrK(x&6L;gcDZI&SEy_G?N2s^h4ZJGuJJYgE!XzPEm_U+_5;h^ ovnzgd{?9o4BIu2n{`8h0i$C!PvP=E;mwU3J$(bU=hK^z`!8Dz`&pnMvguK9;+A_7#JI(Z(rN=;?q9<^78W4 zOhLCk^T{mJia8V*b8oxYO%_2z#)|1qo4Sv8EKs<}%(5dn@YxLM1=cLV#rqQHoBJ-P ze!F;*?O9#M^PhhFJpHdShE;K$%BJ0q-%tGeeTTl|y;HfOn)Vxlmwf8K7&h_K-a~#9 zU+FfU_ytybXGvZo&)>z9l9eA$(>TAa{cmGw{f)Yiqp}kWBeOSLpX_$1_R`GUH)*mD z6IZ5Aub3VdV4?7jiGkq)Kf_!`EdvGv20LA$Hm8LP`AoMn@GvGtGw6Ca@MSlLe+-`; ze#LtKr2nUDCw-f7JN{AcugUL?&of?Ye8Kp%@=fJ$`4W==$ltZ?P1l7gjK3~&UA6o}nD~qHWos?In)WT!`}J%WM{B$gv&7cr z9t{6}uUyYksmO6E;}~}hpZb%x*-NJElJdTPV@q6u%I+_+UM1SU(>5(EUT@*rD7ER9 z!i-9Jp$n_!U%S@F1=rvCkXB^V`}>Fg+d9q<^Y^*jtQX#p|3Bc?>VF{}hf0%v7@hoQ z7jWJ1lTgsqcM{d=yw%ZOQkUW{trmUN$(mIuyN508vZCzSJ@*uK&i|axyTxhpl!EE< zU!KgkwY>7vLA9lgJNhhEdyC!_JY_C&lJ`oU_M-E@-Y&Q@XZMqxM`iOKJnj!)6aT2} zAE=0ka6FprVae3f|#zmTubOVOLtZ&wu@K77-HXRq>!IX3ez%vm)R&GJ*) zB65nqE9~*Sf1lU=>FAXGvhl-=-AQk=ew>{B=b>4zH_zLO!^;zWI#Vv_&S=hFIw>YT zYWkfrsL6LkpRU-vVbkwrC70)2oYC3j)SZ-{m9Yo5yqn zH>ff&&3ON_z$0Tld#k&{wfYYMZ~xvqF~z0o|Fbz^|K6$fn`y*~)=pfiz^nW2LBQF2 z;RlQ!$I3VT-G4G(`1>c#TjoFKd%y6P+R1sja{W24fB!XDH8qaz{BLU>d-UT5c46~? zxn)r@h3o&z{I~t`TKD3s3D17#=if}2zdUBonLMqZZc(f&x0EUh7Cw8>?vR!=(XF;t z##)$tR_v$8yXKhA&YNu%8Tc!XJ6I*2TgUn0V-rFVlVx3UmpLJ$(bU=hK^z`!8Dz`&pnMvguK9x+S|42%o1Z*R-I{VKRR_O_X_ z^vvAbVQHV4bMD_b_PMm~oSu2zw)-*3-E@E^|?El(}TXJtN zGyM?1dh-P_hvly7^Pcbj^Y6F*=kxwLuUHPe+GM%l*dBKK%`fK5pIObfZ z2U@NXWrA_R2Cf+Sf=lfF*^|Zcp*zy130q&}_cR#(H z{~u3cRZS6Z$xdX<2w9zQiX%AeS`(Yjvp|WZ1)Mq}9~$iV&L5XLwczpjDHbjEA4Nx?jQY9E50B(=5AwH{IM^g z)eG|MmVNJSc=C8gTuAfQ=gGSstqIPSbdpgl=q_Tjty^+L@y|;8HBPRm7IQirE~Qf8v3vi0~2iPiN<(SvFq^U6*%# z?^G2{*GVZ)_vMuqbETGgPL_+d|Iz6B|HHv+a=t?CMcUz83!fWW=j}OB|L?5%{O9p^ zZWu1}e!R+0**Q0M?Xlcl-=xfHer$+~y=}7Y=^D3Vr=At9%lbOYbai;CWxA*rTUdaF zLJ|uD!vt}Lxr|x{3@iF-{w*N3)rWHzi~e}|LyY)>~F&V|2`$Z_lwQ1w@URY zKVomi|GM{+UH+l|Hs&jJ|My+}yz^i4<>PZeDyUx1xb;~UI40Ekc=EzRTi2rzh;?hed#*(i;e?0N%CC}4Tma95H)sm;qe&@*} zD!$3}+5(1u|Edjp--bH%*G4?OS>B#lEOCxiZQ5TBlklv!dyE5$YggNz^mz4t(_wyo z#*aMxFB7iJH#}A!KH(L^;(4>4Zrb|%@K^Omf0pYs@BRNPbjOc*<(lT3ZvLNtZt>#_ zub2OK4WIpbYVU=Fd;d_d@dXc8-pPonn6G~m%;FhlXNTA%$6a5TIyKQ)@`nWf(tT?l zFZeg-|D*N)6t?egI(ciKrI@miq+>?eYq7wCY_^ltndD6`GG31le%>X%CZuii7R^6O zvnNWv_`?6dX7T%qub%@%P2OF39QRBvYlRkzJIl(s{}%1M{q~L2vaj84e9bFY9;o@T z=WXDQck??9p0`i?P`qc>?AkPz>n4YGrVA}DTe|qk*?HTmUsbz^vZ-ZOY@aT#UhlQ_ z)1^<^mo~NJ^F39pacW+**GyA{>$k%cwrAmU{v0Tn=)a>vc!}`qLtm#e1aJGDn37?- z=IJ5RLW5N-9ZhlDf|sqZ-S|G;a?yrllfzzXMU9_5JJqo@`Ga^JhoF~;_1z{}#+Vyn zr|x-edok^Y`~SoKH}W5;*G+X&h!T*CD_iqv<>bxs@0R(mx7_x;!X`UDcJDotYN14*kn_7jwr}zihOj{bNGVOcxxf%|EtzTbQJuki$dZvwg z)ozC9>*v1LZdYB+oBj37)5Y6Z>_yvzxZBhIGTo~d3tFj{QJu%;yiv1dvh#i)rRp=*JjrimCi=5XTmE|Hjnx}7p7$-#5c+FYu^^z!B0Vn-KqJ`V;40Lb8F AkN^Mx literal 0 HcmV?d00001 diff --git a/libs/bufferstreams/examples/app/res/mipmap-xhdpi/ic_launcher.webp b/libs/bufferstreams/examples/app/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 0000000000000000000000000000000000000000..948a3070fe34c611c42c0d3ad3013a0dce358be0 GIT binary patch literal 1900 zcmWIYbaP8#XJ80-bqWXzu!!JdU|mW5E>Nv^7ASo zZU;%H6C7*q?%lWN*RQ8v^K>ULX1F+BRy3@6&1zg4lvmz9%-E@xS zM42ck)-}f@U0OOEa~Y4VR{$==&(JIn(kk)7~lbj5o>lJ04%w-FU^q zc4ClCt)oxeIq~IOwgHx=i?x^QFHAUb{osYyFJDFYu48Ie+P7j^ZbePnt>?y%m2*v9 zKOSN^(emfitz&BU&98+$Q}-~?Ui0Kl(;=n#;$kW4(M&zuA=BQAa{Y+n3Jb7M;A3N8 z_#nqHmr*N$A%VfpP^jH$ks@zsGlKwQQq{XV_oq zuUhZH{%U>X|Ih1#`E}Q)zP~yD#`}!-|0>VO-}xN-L2}>knDEMT0@fXSRX=+7^2J4N z{5s_e!{0onO zPIgGY$msfbhyN@-AK~|pr|iDFJAU($&r`2Ny^D04c+G@g_)|+|ER*T`2~%FaSRTez zT^IPS>$>#$T;YWpD^6bEW3DSwx^4)h8+Xdw{x4ByXO22JA}NsMCUUecx->e{nd(7W;gb} zHM$|7!@m3vTf_ULSA7dMeEswM|Frx+GnBt)-a2^qx8aJXDi>{z-D3;kSBX7y%FA>0 z{axbuqHYT3miwlgulLxJSikybP1OYsy`t)+o~~7IAG)vE!X|Ql3D2ui@Bgdg51wS$ zt@?1AjIQcz!+v4uPp>7Y8OS^A(Bx|EHI?WL*vC zE-{<0eP?nuWUCry>{U2?a9!toqwCSJ9>%QyU*EU5@}w?!)9U?7ean9TX7#P-+r@0(4Q zFm18BWcT`4QU1pk7wK%N$8xuATvzNpr@woLZn|rwv&;lxQ+er)!bin6zS3(u7jE>x zr>Jq&Pqk&*N>Ni)raNrgW~BXD?eal^4c;Mz`#juEZF!URP5it65$>hQ?d|jb-~Y#P z@OR6L5D5jA6leA6`Kzu>`ue1B{f@q}2siQbVz*OvxXzOF=JGJoF%Vtqtv^lAl`X@Z zv+31p#dmtQOUh)IYHvTz@nsILSy}0!iyjrrey`76G=-37|$ zDeaA~*xTtVoWxeD@ML;#&*8Z7u5X9!#S`D_Km5P3gMD7^YI!;LCFK{dcr&&L_?`Q* z?c7G&F8V`GlbFUxh^!Kd`^l(L@J|GnnJ^7Q>S@#RnB)r+2;SjfF)k&OP{ zo`#<4_Y=%2&U0B^HYiH^Q@lm&XJ=wxYslTTlI!j@Z%VQ9ZQUkeQtR0Pg`~6<;Wk;yuB?Kgr4s#xv_2I?+sSR>i>utNuROYR&1%H*6^=BW$Bk?UWGYR z3};zgIkqBV!?syM+{urNy}gScC$oB82`m1#B~j^=uFb>P`@g@tn!nxueBbYPH|rm} z{{MGx_q+`gl$Fe^qTPfqURz%GcF*pMM|Yq9dnbb7cM-m(}IxD)p5f z?JYjHxb(UIya=^RR?<OIEmHgiuDWldRj>wE*R zV^%8jkI3FFUY%-HM|>NcSIHJUR_-X#;<>oHvA1DLJMRNqA2rstFZ>McJXR0d+kDRJ zO#RO%m=eVDUqa=!va|E@!>lPL7IOksFAFcwdb&r+vM1{bf{*viBwmbqUaSg{OyzN?etGA$I!ExW)CrcV<)^oLM zSpD%bEKhr}(xJndVV?6cW#8uTgUXZSuJ=rM*J01lpHWrQWPQtgbW>Q#uo5HT9_Zo8-oR}xN{4>{* zXrA+T<(6AtyQyX?S9oai%`F*U%RD;#1!_Dpm6FWvx4F02*5%CX6nXkjaP@yt4?#`6 zx$>*KSFhw>u(N~+hq zv#`i4OJ7sAUNv_=pPieWxlgw9l8~=|B4T60XLVdXV4wVT|EeID9IyMmSI?hn>pUTL zuUX)cFq2*2hAWr8mpD99KG6NUNLQ`=!aj?;bw1~|ZIHFq_7l(9ysGun)b+<-9-nHX zI&~g*%MF$Xp-cCv+}&THtYX#_&G*LKbBg?L&6pgSy71GNm+f5moIz2KvEpce^sWng zKtUI-BXTA!MB=xG$`KWgeFk9*%!--Y-?bcZ+3@>DV~usptzTPj)YNBp-d3cS#>TFp>(M#9sOnR|=JKinzo_u)P%I`Vs>SBHW zWEJde;~MN`b{iO`%)E4B*N)`0ue{Tll@xg$S#~_~U2SaLHA{2ps`b}mZ2ov#H$GSz z{)lc@=J>HzADb& z&%)s1;-v2A!or~U^U&e2=W6c1O@dF|6v+-Q)^6YTZM(TbV9n}|d{LFS|F^HpZ8I_t z)s|YuqZPfz_l(ZkxgXl(=Wcetu;K*Vyl!9W^?Q4F=k5Hp=l{Pqm)BQ*QOrJF9DKW-J1np*^11io-e+I_e0ufEv0b+M z)MEMHH{9nJok?V0yI$|Szq$0{rF+s&S!hqz4|`>;wrrMh@#oLn+}xjwjnA&^l>O>u zm@g765;-%bzHoz8(CX{2zuxjF-Ed>RahK+*GhUgwJ%&-*M}1bZGK2+KC^T_0Fl^9e zn9Hb@z>vUTXDHI)v`A4=qHkFej{uVA}Q>;1L=jCC*SXS`}Kie2?@ z^}FVW?yKz$_%H8&zc=vDp?}BfF8$v3%j*ln-?Z0Ce-C_P_}lhn=ieDW%>J(ayZHzA z-_HLRuQ484{WpBu{4e$s_O|{D{dQXO{R?}YeNJWKTg`u*{c7|0VD#(wcY9R73cg=I zrCnnlgWW;<&i^I<$N`I1Ux8AS*!FSGo-hZwCPX9jt?)i_g|MnOB?fxHi$6rKj z^)io1C&OnSW(iz;Vci=?ubs_Xe)!ivnzHf9CY@DBTk|xouWS0HwmN9b$J5iEsx8$5Y*39!=*^U38=Sxv&2!(a%3$eyuoRdic3-h=b+bH>*_j&v)vcnPX{uR=%mA z<8x1_PRy*PxDEB;+@B1hF3A=xzq{z6t)i8Z%LN98fB)~a*Z=<{-x&XPWxCwqN0VP) z|9*0=vD>OJtD>gkDoa1=|D5wP?&34EBPKf~EJZ6_Iv5Kd>TmwYp%mA%jxW__%3rRu z966?`pX<1%nEa594i~*rTl;Nw&)Q@ErgqNh(%bs3E_!ZhlE)K%;o`cxUs*CAZ+>P} z&wYfcN;bXP?juvv z4fBc?th%2c_V>|)F!OW5Z3V02OY48Rq$-#!mJLW{5ct+8G_zpFGIIf0k1V%3o4E=r z=ji!p^M7*w@yGAqgJWd}lo!Xe91q$&>*?ePzs@gxe`K4w!u97f_Ias1Uu|{f+k;2G z%UGXiGdz5CSRw0XRZNdO!(yRgRpcaH5>*TP)Zf7;q#cAY%< z-?czl@=(b!;ZtiG6SOXNOt@m!q-pW_lGV)vHn!UzhKQ7|D7^SDURmux-K(Ug$p_JGwqQ+*80FCGG_nn3n@L0wx7a%jFeeJpS8HYPq6pTR1=VYXL%s)oW zQ(acf7FzUUN5!IhHg^~WXY~F}@M1W&$M}Q6{Ftw8|2r4WH3>Ypu-aBA?nj%Fp!f6% zMSN?v*G>%LetqC-^Yp_3rPX)OUd-B;HGB6(#~t2MJ32~v;yzq>VRnDrr)i(tE=B#} zTJb!KA>~xk55{YAx@*=y%>6fE_p7H7b~6f;7#4mxsTghlGVAC3i6`uoPkEI5NxLJE zDxRcn`u9Cw(>|9E$@ALHbQKF%mH(`{&TwXCbJg_;#!dIlU!T76gy-dNr*#?S2Q=oN z=-dC$yYtTab<@8sxh4H$Uigf+D*Hdgto(odk8rtW`N}oA|E2Wfjwa=I-Rj$=TL1kb zYfUj{b*$Kt>t~J{WFKXg-v8i#qV3WG^Cz*Ea3XbG>7fb1irhkrtop^oPE*l$v)SJ&40b$v7hRAv#0O;b4%;zduQqF zezJCjc!DA8?I*jM_-n6+amy_~Yi_yhy=v}l{my#{k88r;gv~hlF?e!j+g|6pJq2rC z*Z2y~GGEHybI$IEU#hc&-;Q*;XO- zaenPwtkahLtaIEi`*O#e|Mx%NiEMN#+`ZJ_ZEc+&{Oyx)wd1^w!p%aewH+ zWUb=a|NnP2pJen8zO>$QLT8=Fp~dAab)Uks8>X|Qgm-;#j}w&+7GE$;a#ehwzTItU zE{$*7!>8#@_u2O(w8HWJ?%328^UT;8$~VLNK7F(QC^_S$%nMF+QAz)k>L$(0GNa$U zUHyOmFA1rzlb&Zor*B*9cX7?Pz|$LrPduq^j99xjdgC9qlSf)a&oFQQygQE}!nfd2 z?d9h!Ya%ztC7%8MD2ws$jD$-j919)u?v%1TIp{JgQ7U^^cBE5?>iuK0O=HdU*Pp)2 zqP(uxId;i*#oWtP=eE|Ij4nO%U)_&=Joc|Wad^R>KY#lKSMOCB zpL|T7G5@`D$fDP8zumqXZ*?%N`Td8YH;N|t%FIu_!$0zKN@_gZzVvsW^r_vEQ+?-% zxwEIfy?w8sQg+AP?EWii75Ce7_iL|cis(pBzVh|jS<4?BIdeq*%@KJP&*T1G&GmD& zzPaQKXTF2=!N0v9AKZR+!q3K**q+e@5n^|k8ukOo=yv}>%n?=;CVkPA@`Uf-rILQ6|KJ#J5D&yBpO7{>M{EAZndjhLh+QA14)YyhSx29 zKiOUN|D_vS4yX$Et=YVAou4=_O<3Yon8w=+dRhi23{Cdk6PsJRu~zoI5}V##&m~GW zJ-=)exQ?%V8S3BoaKX|g$6i~nS}YK?W#0zI|G`d2R!v+{CFZ$lpH!u8yu%e4-dP8) z-0y$!{BZZ?r#3D-!*8to^Od`Br%BM}%3g=9DetWRNv#fTss7AoWfJs2A}s4tqVANH zzS@UB94dY_^+Mg6pxWwwQ;I|bhytJ(0e=>_K;y>P~fqK zi9s&yjoCs5?jjQmnHPx)LfNufz8J&KC7jknY3_i+_}x_F3XMjr9^|8-|+F6=$U$~KJPL)Y+hfTuy1Yf&9qJb zf4|@V|KIQT;oXd>3o>O7y}N62{#uLf=HqX>%0*_XF7o%?c0#UL=(Wf!)g`+<+cQ51 zO+Qm?`Y_vJ^^Tvsnv*qt-H6Ls%rt*s4wMv7``<|jq9*R@&OH=&b)0Q zznz#3tS{cEe5Ne<`SQ_o$6C%hD0}T+v$p!rwZ-diFYNkR@cZ@R+roEqQ}?;Z9$2&J z)VFo}8e6aa-MBwJal`u6dpDg(S|GYJHss=!tCugQADB09-LfvF*^A{I^2C>{dKG

      ( zLK6-19F7SnwqI=cuskR%z(T=+lYv1%pJ6Ve)&zzL40eVh?M{mnc}f-)2{1NA%nsT# z_04Iv{=mAQzl$Fn-CUh{rQsv^iLRus-Nz_cQ6A z@?Yg|{4e|eU2bD7gMEP2tNO+D2fi`*hWwgZiK-*NWd2QBrm3eYwJT&vs$uSBhilme`B$s{c82kGXRmPh-MF>9 zd-1E*kC*OVIw*5#?fDYsW}UZ|zXG#QujQ_I{;&V{f@QV4F3A7;{G#jTbv1>L4v`)E z?_F{DZdvc6y!G$2M`n+4A0EBar?d5c+zUw_=)Q1bPamk0}UBwvBu9M|d3_mpTC&JMeOF0bC{ z%MIhR*4eN3pX8Wfvg1um&*@63MNuo)?bVt4v7VXt`Wx`z` ztc{GTi`kZEKZB_`;sXQ2zyApmumAs>wdacWv-sxt9(Er$@ju(I-JB;AKd*7&z15tN zhdlzni*~4VTZ!5+y`#EuZrli z?Mry19C~3v^}HpfcZ5?qKD@53^jW}^UpdQa#`CoYeFc)|@A_``E_HK_`bweIKd#3v zEKO?95?>U?X7kZ1YJ)EC-LIkrfhMZn&rdbm2a4+d)#xu|Rs8&*e6sp`-px&}H`(?b z`@6lmKV#Od0>;#zRplQ4A8%U}u=*dTd(L?s#)V?eQcIuCJaFgj$$dSItNqizEU?dd z+5W`&^Sz~68$Z4MDADuGe8s$K@9TZ3(dz$WW}jem+ZVRr!^30F?EloKFTJjjbGh{IR}1Q%e?IZua;cf3+2{M$?e<>VWOS!y#S-1i_Db8X zxjkJiayQdPw651N*Hhg|IQ)~;k=)d%XHhLjOzX>CLdEP9ls1)eGdu~_xgD`L*Dk!| z;*I0X6Hm)W*49i;*)SvWbD+PW!}9KwwYhv7e=jResy1r)H5?LzTa$-IDP3Emq$Nl zJt|+hVa3CJAuK0l-?tyw&~+#zETw)w!{*(mo88S3mzEq>mLlK*J-ph9!b-X%n>D^?f?|0n4PfAzukUgDP5?tz1x2^uom$*wg@snpn z73A$cc5F?*&aNjKmv!Fv*Ikf_E|xzZYanO#ZEnLI>5E4?w%lOd@yfHs@2DG7*t1r* zMI}$x-7P))$HMaHz14p6uS`h(k((i?B$#_bblFFhTe~bDZ!(*(!|nH7BUbi#d)Yd& zckqXOZhyBfli4%rO7?m=@dGEVUW%?-_B3Pd8HV?DPwZY@dgL%C#QBfMvcFOdUUDne zZWR#tm-~N1wQG&sse;LNf9hwZ_Fuee{oZWN&W>4Sl}6W$w;#3>bbPf&RP^$*BR7<* zoB~B}2s<6$W4*yL>~3vE)w<6cibHD6|BG6Evw5le`?+Xg=yP8ExPFmk$M`m%J+*s9 z@bgV~u~T zvzhA6zvsSMrTs}%B29T}+fvE*i>7NG{mL%Yy`ZH$>HQg3=OUHW>J@gYe&1aoyUYHF z&&@T5y?Y%^o!N5gmp{|!?JC-ya+~cyN}q++yqlZP7fuWwPR`%?HLm50CTRn(lu3T;789 zB39+Mjkg^mZJLusQV#w7wCkVU-0gFN`TkyLpLp%U--Ln+CFV_kzM4hs^xR$dw?=>8 zzr0p6|Fo*V#$9^W!Pm7y#Q1fp&t6Kp%*G^8ef>1cmCI2E&V1|MDz?b0ZS;FA^f!E6 z<%)`9+dr)cQTfidNK*RVp^gQ!xK9*4&i(9pyX#Zy)T_7ibnET^&v+qx(QZeFeEP0k zf4{q(_~0sTC9bT~ICs^Qg36Rj%B6esn4=D9r)X={b5E^1+=lDz2UFQQ`NqG> zd(X{^3^lm1h;7pO?neP^hOExIE=Sw`X}^wrxp3Wmr+Yf<7(R!`w11e)HoYbJ{^xD3 z`}hBOH_b(=N=U`~^{v3t{|npeKV{l&U-0}Nb5Orjc#jA zwdFrv*DT=7UQ+HTJ}0;5&69?I)kP8(^L;BF_WOUAy_CM1pLd4#^6Drt-u>B17b31O z6{hA1?k{($Njo1N72i6=>6XPOUxhDvoi58e_U#M(Y+(9zLRtvZEQQdz{nqPFwfZe( zw%MtzKixg@?1nx2PBhQr+7-8Rc4z(msUo=}h17R!;xJ@ih~!u4j=uS#|oy z47;4RcSarN7PD=RuivyKpw!JQwdVQC<}DM7mcHW;xBAkU5q^SmYcl7*+@m2Zr(PF3 zaEh1lK-%m|{m*;?ijHkfg|@Swnll}2N^^Sgf-!T>gC(}sQRSYgk6s`D h)!-feYx=u=W`83jCzS3vu;p{;zO&Xh3m6y}7yxx!zL5X` literal 0 HcmV?d00001 diff --git a/libs/bufferstreams/examples/app/res/mipmap-xxhdpi/ic_launcher_round.webp b/libs/bufferstreams/examples/app/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..9287f5083623b375139afb391af71cc533a7dd37 GIT binary patch literal 5914 zcmWIYbaN9DXJ80-bqWXzu!!JdU|J<7_Jf5|s~ za~9p8x_okrvVg~}_?nguk6ibyxwXXoxs;ALRhQRLvv^kzb^pZ&Xr*bDEjezyDhy*}Mq;6Z4*SmVm{ zn5uIVYZ)H!H6;i;3Y=j`sJInh|M|SG!v?O!iVH2Cx1Hu=ncy-hW4($Y!;J5*=l|uM z*eEI*bL0ED+x<*aGLBT77UihrQF5ln9)Y16jhk#PS$KrH_iBkhz-h4lJH$dycT%AP) zN0Wamwq+%B)ciclxTHZ(PiDtAF{U*Q6AF%9_jBQKDUUvKVC{0{sOvMmYCf1PlH4^< ztng53L+SK~{J-n}%N${vn!#}HuKYPYqdyD2o;@hhv5H6V_`Ieg>kJvD@+38KsTx!; z9n>>C5ZZJiV66z>OUB)Y8X_3&*%oE#CVpR;AkGnF*}*94lepV)#b<$&2?yEL7GLHS zU>Dolp5V@zcW=Xo-n9YjoN3BB|CXH%IL?um7I9EFdLf@+4bO%y?NqSN?IiqxQt>(>#w8p4xpsJRwv+&Q2rpcgJ?Y z>Q7Af-`Q@;U1;+(gC!+w$6FcwTdLK(8>dOTRA1fWt2l4_-mDXO3s38XUzEG~x!^Rv z%=uZ{RgX+AZ&p0q)_pGUBHstcB}(o-6&+d4M{UouOiX=rirHq1<94O1pHebE=-rwj z(H%YUqjZ(h@gytJ4Kb2^cKwMt*Of$fCLJn$A`#(d$?vkQ^E110wDDY)hdZysU!YyG<^BMRp7yDbbE);E@tniHI(8*`I z7Y<)M@lUYz#;F5&3HLhwmggMZQa*G4T>g{{w>SKe&q8Ee%$j8x4D$u}j7-$O&Ej}- zQtZyRLo5Z~ADlgK_rM)NYxV*YXTt{02UGT?9a*9&+~^scu()yZFLkEc$(?DodlTMu z%!}I+p>4pZQ+4BrM2?a`kC~K%4@>JaCokc~Cl@jtdIH|HNL);cJkGM=Vul(Izc0(H z!xu6RY+Ebbm^*uR=PeV#8$vgEqFA5$Ma;f%XN!#Rfvb60O1iAY?mFU8SDHEx{0WQc zZdp|*WRUgcSLHD2L!v6$w zu}!Kf)9M|r{oi<2C~9ib&)sdB;hR2fPn{CgD3y84{e<|k|Mpi~r%9@Pzgssedftk= zY!{t-E>?BVo$t8psPpu0iQtR(|9{ClS>!T*PxW54zSe8e)_?S#oaBq-PkIyf`hE2t zbwm3v8$RD+=K#vy)LdWdeDF4FRPWZ) z4=f8~Y|c);b$rqKvJ0LYY9#vXoE+aWuYIw4?#=hpxIgdPoUO?D_&|Wc9G<667KR%{ zj!j*7osHkwjQ`HbUoleh+Ev|$%h-z@-c*HLjOKXk-L{CseMUs>6j?bZ!DHMDSa0kr z2$PllE!DJ9c#T528(TTYnwf%++1qBdGOoDQ(s-!Lp@hL<^MQXWSNu5nmnY37eNx&R z?Nw`EBpV3L^%8R73=<7(QtCX%=xMTzX_XRV{53}*S(XNscC&*awnjNpN}eSmjsl-b z7p!tSvP(t4<@xEQM>(g?p0*?Ag;%A~*$BR>Qj3j6Y-ik8JZACaoMp-WEc9X9&dYNH zg*wiuFPIo@|3~QH>I2OC{$xycTjZ^JGI+_qkDMCs&BQ<6ynobaCrc?igC^_igVSy~ zGCxZZ_hdX>zyH8h4^N?8H_tk8MC^O~Z|}4NdLKnLJUw4ua75zn#ivSVZ!{Mj{q|e* zS%UZut}Fk4T|T?+;fzUFN*T_c$-1>C>(xBd=E<_E?gzHn|1C&NQa<+NUM+*;g@o2? zx(E80O*r2OaI)$AKDvFmrS#WLJ$fN(j*?qnUe^D;ef`9uhQ}(MY&o;PHLpMKe@|kS zc~Vg*o8hEQ3oNqFJ-e0QxLAhiwvwX>!{N>U|4xsL7CyDmZE=rY$QlOD#(nP|TV|iS zcXGkRq6S^g1&L2ySeTF95CjOWixy`TBa z-g)h5$Kl&;uX>GkwP;N{{ZvzOVQ#nmpU?L8e`@aeS@Za;`pVM0+$}ld^RKPi({v+4 zr?VWbik$YfN_l6?s%cM7+PVpT+L3wEAHn^3R@7%58cw&XZ&gBxGLPtCtl@%QYjC35C7#kQ^7?>1FOc}xgEEG=g zF)(bfXPC>VHGyFQgPoyRr_&-uMX^_{OB9${HZ!FCd9gq3Ps1CZXaAHxxqs4r#&+eO z_;2$U>yPWzI?uiN{^h@yc7^|!eD!|D_^a|?_R9A&>|fMB`k!KZul~xfyI&aoPX7P@ zt^cc~fA{}=zJdMI`*;8M|GQEDqyA!z>c7kXPW|Efx99)M*9;F!{~i3Y`sw~3{j2vq zzVAKX{I`Cb{Dtzz+tj{pxA}MV{=(J$HT%!}TKRA1zsVEr(&X>dU;KNrX6FBc-;>{Y zzx@BV?xFnI`j!9J{dxTE>hJP5{=atI+9ZCy_sW+I>{5}pKFS}Omt*nyjnuUdxl2A8 z>^XfxK;fv^&&9<}X|a2*d0r6OV7JZi)XDU<`l+C9Xa%?aTu3WX;T}$MX?8ZRWM1GEm zPF=0CR+IL-GDOZP>FVFRBf@LOe9c)eeZMVMFL-9@aHymD{fSf8+E18IofF;c$MRd+ ztdiwHX+w>N^{h{=n>~vJ7pb#*UhPVD&ddv&ZMk?=%0tPZ>~j^~;#8o}(Md zX*8E5p#toTBes@Q{BKiT{{5OgPlDm!|NcFK@h_Oz8vULa&b+!R zQ(P*r)U9vJzF*At5eMHFN;0rTw3SI5`ExJe>)S+yDcTip#YHL>J^odH`rNJXtFM-I zuwSzM?D;3aIpti1Tk6{rY0JEpmj$wVnIy+{uQT7z`~HEK_vM{t#V;3@ZaBQ_$Bd7A ztSauO_J>QS{qNWw`7}VzVB?L&zUhivpN04TvRVA&ZQbwxcRJ1Mgd-P7cPK2=P-iU!%FgzYBi03)B5p`{{q5zzgHK|Jm8EFAWzo`B#0n?{Ve%KQnFB{#7h7u3r^? zJiqr}KJ#f+m!^H<+Y1a2eNi{PR>{72%d*C87u1V(1(&fo?JPYsA#qP+&Lkyik-Ooa z^g?e|wmtqIswjWdFl68Trm)`?v-f!a-K=$C=K1MAlWLlBH5fGQ7jSOgy8rH;MO6Vu zpDi!^WdA9oNjCYm&JI=o_IUOp!SdMamBMp>O`0*|@!c{9waC1_?8Fvft;UzX;}4bl zrkM*I@Z{r)ds+14`@gu4$B%7(^Lx?F&m5bsZ@tfV{#OjASb(ie-i~RTwyb&Z?B@mF zjMD!FQHNyP{x1z+WR=+(5WC!deTxFe!{dLsmi11vdoR2A;np*gcx_+#>(3Wi6IUz0 z%jDJCDZ7_wI|d}S^X-lJC^6;Jq^TEHe=srmu`?jlUh>k91wF!ZQ&SD2HYP1#-Mz}> zuYhyV8c9{pl4MKwhfEz&Z#|iA%9bA4_9DMtB-&8z)1DPCpTA~$Q>A)G?Ea+*_x`Q1 z>F=4Em}fLEM|A4>9TABlRg-w%P2?(=l9KXu`U7ijEpLG+v0p~t`57;o|1F;(rfz@n zt>FKRHammW*ZgW?ye~>-{nR`>t+l`K;Il_o2``zWU${8`5&38#^;KJL@$5eNvsS5R zj!MY?KJvI^-X9x-{o)1hKR!99yS(_w5#DQeW`3CdQ}DvoPiI9Ef9^~CwxqU0$-6nk z+N(PFxV6QGWLK&1Rg-kj^YHeX1;@nP<>BTGdB)T`;ncPa$*?2xUQH8H?HN~0xi0sm zq})9z{MnXf@sOL|bz45~2{oM_(&2PDCN+EWMeiw`E0t6m*3D?T`y(gYm+PjbWi{vI zoFAXJ`1f|4b6Xlv^FG2e;V|n}3--D-hYeqw9{+Hr>FKirKTo>EH4t6^%@r8ub~Q#bBNw=4bcB_5Vlt{;@VHS##va^Z9R0V%Ayje-~I|x$W-i67&Dg(`;|be^UKd7brH} zS(dl*$+WVa$s1DKMRO;A`}2C`)5^U^Ykmq%*d%i7o7T}D?bqAiRv9jRa7ujIEtln& zyly*}9QbqL>}*qGZP%*8Yj0CoFa6v4O4HT#_Py0FBY&q1WVTOEGmmUdgK<~cHT)x)T(e{m>EKYRI(?2q$UzEl8 zK(0K)*4M8M>T-mo*&JW`3wC`8o*An7ZibS@2k*p;jR}4BcjW|Nrd*qvMooZ??Og*wf$z037WywZ! z79FmYraI022i{FT5&7RLte#!tooZ+65A9E@*S@t~_i_07%)=S;0F^=90=!(6e*xcj`SwR*_^yzn(gKV0c_@9u9q z)H;3lEC!L|OZ&P`d7nL#{&B`+Wr=sOS_$hr;@6sMUy!&k`&UOX*X=ToskgQV)MsYw zDJqXFV7L}gadh_XI4ym#vgeEa84Z_jn{eV;19L$7l;(#w^5Z_wIhgx=j=t#>-@6MJ z&9U2f{QDOlK|MqBa zCDXd42R3)l$p1Tem(9ToDOpqBNGh)o(_g#odIVE}MDA+ueS+O3zpkhLGC#%4#;Rwi zmy+(TqRi{}%DH#v7Uem-m6nYTCj!-@XT6<&xV>SG#=4qy4{9>F^phA58Z+u{e#f%j z}R)L@cpN?2WSIdK10lLwN% zf&cFAS^DQ!-26>5V@_&cUA6bkKCiXkdP~G2eqRxMVyb?A`ll89zrWIb6~|!6t)ka) z<%R3Ki4V@q`X`aF>)E7b++j=X_XQNouPb4TmMpsEzC0ixq3Z6}2W+qPjSqJ!{&Vb( z5aTRNF1I{&Phtr(rOLG%_OCymqWk^4-W-DqskOLgZXycyAOnXxbR=%^UU2kIXo{4Ui$I8JJF+g^ShKthOk;(*V|iu z8xLN}e!Pn3H1qB+IY-0K-Mg%Ac`24X<(Hz$^E0PEE^XR2abA4&9K-mfWpfXlEjh(e zDg1o-w1}eR)|pBss}?PkzqNc}z>#|w1edm0w)1^^{D0@H*UJ|38TuaRzxQVL46T*6 z6B{c|;#O}IlX(_Fl6EIM`IieZw)mO8W7Z>lz5o1(t$1+QIO&(`wa{L^V0b)`dW=YhzE&MhWg7Ya^QMt=D`vs29G z>8<#eH&uQwbMfe%bm!OO8qM@;A_`Y#=O)+{vvwRl(|hq_D4Tjnc)>;OXQgVUFW2ZU zEL~HmuHAfJJ>Xz-w$`MZMbXVqQuc~OM(VOGw>Ty8=h*cp0*j|5OxZEff35PXS@zM# zzIH`NU+{Q)QK$C7B1Kcff|#gs!>I**U1@XkwqM+Ly8E6%%RjSwtovRzonbZ!j1my% z=6fLFl;-mC#&VD4limsaeR-_%>B|>OW%~5lv&|FF*WcvWb*jUWwTaIrxn|nS8Qlso z(Pj0&WXrF_daVxNn`h*p*IeQG_2Zdv>zgsk1v8Fz3B|k0q&x&qPO<=YQ^Z8mE9{3ZsBR!P<}5hHh7k&N~5z+p>X2UVw%sqz!{@)L9U%$Dbsw%*F(GMH%i zW)oA;cB_P3HQ7@oF`?NjQ;vlNUyXR76&z5v)br!?w#(-K6J;OdvjtQ<5aSPHIQQ+F zTf)IPm(DK@J8|rHbwY9O^ozI$<2jBas9DB&+eE0pV>h*1R*u^_$d=0!Q_C!V6i0|m}`F`I|9$mWN z+~c~SuO4%!<(^pQ8R)80_9Jx11?Dwj$?|)5&nsAcTResFkkC=dRA*Pts`qUPC(p22 zWE^DwX6$^od&aABS+?Id55#Y`&1zMDtH~0RqFcu|;|I5OpGxa`_oVw@lJzQgITl~J zskZxAbt8{Um}X2Q+uTUSLmfXkLp;+C9h|*l_s{2@Uh#h2ihs^mcoeYg`doeg#r`;F zhk{98Egc%KrKGyE^xmIzCQRg)%(aWFr*SImn$^T~_3hms%{(fPY|?wnjd#dy(Ajs= zE9~&Xrwe%1C(c?kVWY6bIgvcoqbI-iS$F^aDto^AglJ2NJ$(bU=hK^z`!8Dz`(E{j2wLeJldHU7(>b%bUDJ3u)$aAX7!}(6$UFx zSAJ(;QR8K7Q)4t%i+=x8TwYyK?P*%phS&RMFPd4^=k>ODyUiUb+w~U`j$i(`{EcNx zX0h4Z?B#Y{6Nv6&-#EViZ?%=zb_mtm-8m%igMtLg>q%5EcXXQvfLM45im!z zY(`Of&gO=bPjM`(1aJ!@ERx-wv2=J6*7Qs!s4Ev)(YIAf+&bNI{FtF51YU75I5 z(fL)Qt&a{LtBt``nY-P&6-8H`nTfee$JbPQb-m&X%F(l5Riw=$-{<|jZ%wbHL+;lb z*6bJ7YS=tzGc11H^&)OU!{_jKC)GAdT;V&;d|qdfM;ZHx%Nw3;+4?*DLlTFex$W*f zzf`5BHmc;iEi2w{QPL{P9Je#;%&H&3sVYSc-e);%O8(A?74wskzEb=pe}C2Qi{;nX zA3ZOcc_OGNT)O=_zx}U=Cpf;z*!(pqe*Ej<{w)*J&bYpt#LxfZ=i>FkRdI!f&Isnz z8(!);arN#~p_~~L-&pT_<#MS==!vJ$422cXIf4Z|*pxSkK6y7OpiAX!&xwep)3TT3 zZzTU><}?G|1tc; zUa6ju_Wer#t9@_(mDV5rs{7CR3iDUzKkuK0XPJAOwzZ~e{s8}&E7CjUQJ&HY<SKKvfO^VCzn)BnFqJ08klIC19l-HvVN zpM?F^sku~cr)z1v!81)nS()_(pW}`*=9!a1QorARTqkZA-X8j9YwJq6LvLeM*B2l8 zykVxX&>EE%F^?B-ULQ6Uu83EZe=g@{;{8R<(Z%$afR1d{!g5b|H(~LryO|DtHt$i*Jp!Yu7CejS27u&h}|Nnnt^m()?X0BW3$>8FpLR0E4`fr*xYyYh2 zo~|;Ai+`2e&R67=uj5uU*Im24W6zVRMy$D#6B-!)eR#>hz#x48{}uUoJ*{XFroj83 zuIL3Fc`otwut8|9=6lY1v11vdv`KF~?!yPSv*m+|PD>zHx&2)!qFcWL2^cglSw@ zIluXVfpX}s!1#GOi{k!DEPe5P@g|k%$KT{XDSIAq?by9Qz_f1PJ>Q;rK^;}!+xF

      0vl^(ubK57i3$j`RXVdItc2Zu zTjP%3T{qqDyHu$1wf>en`}f$lI?l)hfy+`aCTxu8`Mp4Wt8~lzsk7fIKUzdbU&D@u>@#|8JoKt2mbv8|~*&2E%ct_*EIJ>)7o&PKE5_$1H zYTdgu^~m!0A4{%YZ`c&qZ)$yr|AXm!sqXjcKR?_Pn|Ao^jNS9)1$Q|wns@3F%fsvg zwSO(SHf}Wd&gY@5dZETG=E3!B4m$1-}j)^|n6tq;mOd3k8c0DH_GHdj+bC#}?wC!#j7mQS#vf_fXiT$x+$0-Ud(~5MTubmb>WqqsT;k{xpsIQhc5wmzv^leMXZ>rUpkvod!E z%4X!{CT@DfUb}1l9;OF%&cZj$=~`?izExW$`!W#MmrU&bU9x zY4?Y|ihvD`aVe?!Jd*bn>a_Ljw%A+cxQM63#5tgD>7pvIfk zXZB`A(+B?|xK;mhgAxy6j8m5a|tYYQtz-&)`wciH>w!z4Jl6EbdLNgW&t4n&Z^`r` zg&vWF3I>a?I;mM9pQdx?h+g`4^#9q@#m5&cUv`wUW67(N(f8cqnde#^*{|z4`#8&% z$(*MTuC#KwaPVof`>D`&U$yg@H74@YWB+XNzOk9HzHI)?S*96(9jadGnl+RhV?HYU zTPymOU!2^Y9Y;SYsn1QEpStG70rM^O4*D71J+(bX{#n9KLDg&XW+cq#d%E33PUWv_ zkfOTshO5hBt#1C8*W^yL{vnXQVRqiLErQMrj6U1<_5@j|Em*A4E4-te^ZzpYDI0B` zXg;x>w9{g(u&mK%{^Fz8n{xBlOZuI;!E!86S+BwIO2Xl&Fh%#ZoBUQU_O0g4%ANk> z0Jmq=?VG;}VuQcWs7ieBJAdXY(fhi`7ADvReRQ>AUivA=PwM}&`iLJJJJZ{_&k3Y2 zUvhnu->Tx7bEg!!9%6moQp;o7lU20XJ=QDEK<4}Dx`6F-nzAlROmUdnwpX%JBgyHE&EJd_^1F8lZE|Tb`4Z9o=_5<>!KzQ} zGZoDj*B>l-_{cMi-TF`Qmi1X-=QLK8d3<{luV|^Id8CphQgh85osBxngzXY9@84_h z%f`4XHqy%Sk8jJOIRCXp`#HYZ9tjb8r7sFp_47S~Y8LMZ0|ACD*T9*?vNtsq>c#FZ;4AF83!N-}7Zh7R+l= zw!4tMaFcX!P3Els8SK9LLhRyJK z+&t%0aQM50`k&8S%~Uwp?rm21|LFNWlV+G(ACydR-+6qUWz*kv3iZ{C%If{&>euW) z@@W5$w|~FeitEW*v$L+4y5z_58%Bq(G3{FX-GAnci|2Se?q;?>GnLW&F(+=#|9Z#w z-#_o;-&VrrqOwwO%B-^WHLF&}EjZj>w|%nOHqFIdHlY~LM|@kt^cB?v?aRN!JSJaHjLeW zb$GNz$NM?U8z(oNo3`r8e%lS3CEre$zVUyZ&{wym*PqV*QMTjIf~G4kJUQ0C+9_cC zLSfq{(=7&@u0G04(^)DtZ};(To{cq(j|-+htN*jEpuxFk0?Ru8XP3^z-&SNkURt^2 zTSfZcN5x^>ML|ky1rH}oViJ7+@cetDleV!hBksSwEn~4q@Xz`GmCrjHOK)GEd0p-B z(Y6SS8poDMuE(=E|4rGmcvp9MsGHU9V8)Ek>HE*irk%F9rK7RU-2N}yiz$uUO57Qx zXRAv!tdNVQd!7^~xNg;>=ojmFGC8tun)m$oP3PKhc*onS@K5?rr^}yu zUmUrRUESJJ=>F0}m;TMP>i;SjwwR~)_nQ*mc_z*-WwSXs6&fs_bqPz9s|2|0xg0$2 t@u$Pda=rYAtrOikX7%&GRsG&;Z1Lh{&yL;Ao6ROYUN$pxVgmyL003>zdZqvX literal 0 HcmV?d00001 diff --git a/libs/bufferstreams/examples/app/res/mipmap-xxxhdpi/ic_launcher_round.webp b/libs/bufferstreams/examples/app/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 0000000000000000000000000000000000000000..9126ae37cbc3587421d6889eadd1d91fbf1994d4 GIT binary patch literal 7778 zcmWIYbaRW6V_*n(bqWXzu!!JdU|~fj$$Xu^|Mi2edtS{o z3zt<=OJK4|yuEEt?zY_9b#taO@tJ$hoLOybY}_OF?BQpgnQeb;7N=LHojG&Hf9A}c zrI*?+D!T7Fmn?syG$+#PxS%1U)_-9yCvT%|w>`KopDb!S#C_XU$WKf@=gx+_zrRXT z53D#h-_p4L)sv2+&NuS+7paLN;IC()Hr()%!obv0rzJ5_+5y&6qC#>-XwH zdBff=tzT#K|D5?5AbT+DOi1JWpRMORRvG0wO`ZAv=TCVX`Rg2E`DqXT$p88Ie&#~0 zWu7b2KlA_jv3y}#$JMuMKD?Cwe^B>JSLVVMIX~vf?`HlUcw|+0=e;{07vJC8C^d^K z@S=JBleC!b856Xw-ua_^U%*steu~{c=J!VGQhnwz6hFa(Vi!pCRcH_m2y@S7sPA-Cnm$-{T?E9+&5Z&FTHg zQWwwIp51XF8R^9|31&J6&&B6`rPp0x#=rS(w}bqpJJS|38JC z6gye;OJ6oQpz=w*=PZ+*-{pRZ7JqOr$rCRB6WJDi=KnW_scvg+zLm$Vd~@y}-`wb< zvh_7t6SRZ>hWk%2$^LXle&;%mvgP&NkID)kmiLvHs;>I~#!-tmy7E!^TbY*>=rW?H)aeL2fYUep<9n1K@xyd9@ZTqdd znOyr)*w60C<(*{oF)u*caak-=*OaHWDc9Z9CI_oIdtUh@x5i9Jz1?cZ5|5AH47c3PD(t7x#Dy?TvP=>3%#T_G{Y?Ac-p zPcFrHDhV>?=`vTT>s-IKYFgx?6*r^aT?|Sv$yu9te$v?&IoZ8!6`BV2_oLF!Z%8q& z-?jDJoMYaee)DtISr%#DC|+Bdl%ao+k8jI0!S=s?3h#5*Hj8<0-NV0i%8l0_f;`^4 z=Bb~qo~v`SF1v5qqbGUQo__DGeS*)Qwc5)vdEV@!Z&SX>6+S9w(vDxeGX1<(Jz|_VI&%omZXRX_dYAe?ydq`@1zW zpT*>U|NF+-AH2ExpZUbKlMnvyO`7s-jw);Wx?@?=GgtFjsLYk_Sa*NZ z;@WL-72BM3)^oY%O}Kq*S5}{&&T5ufxA(1El^SwAu7YF2H0FSdCto)$>(zFDb)?99 zL%#cxTdpg)%ak)`vXoerre4@k=z0FYf~Slv<@xGYwYT4cZT)zC* zmWvjRZ{JAXtDUs6{?)t6ubHz8%hSGDm0qv1IeTW;?q@HIFZayfd~ISMA6KyLHMzdP zwVB7_Q?6Mx@tLe`VQPyk4sD3dmURsKU}ALT$l`rrv#(}0q_XL2b^_m+9XvSLe>)@eowqbxE`4^3PS5Sc=&;_ew=|XcS{tA3TfL}} zMPY*IqaUB;|9+7bXXLyjaZ}*Hz2)!zG)ErJxY6%c8-Lm0r5Kk(gL2TWAI|doUMe+g zSz@?hEyIo9hn)HMJq_V&Uwkp+%JnU|%N9gjNigbC)vG=Kd;R_jHU-@Y(@wH!Gx)u) z{JHV?y-jQD>P%#K-D~5G&u+QGbf9gWbc?Fl{fgJU;V~OJUEiiojQDco-_7asYCl?R z+a%xHcKG3n_u0#4$}K22h`l~_o%XgRzTt7TZ&k(f=0~0{nr~TKasT%EeIJjV+_Kba z)zt1_>Ck0G#I`S)bdhCwBf7Z@6TN4|+ODX2J)f{`<@;47A z?#-9Aoh#A)S|dCD_dfaFUv`&gywpCRw{*(7DeGKbDzPXybZs@xzUDH)Qf8jrY_kN0 z^lzrw@!9d&Z-4tFFWcrUnEFv;G7uFl_U)ldH{%ZZU-4|#=6+Q zm-jCYxzF))N&U93kN0m&m%n0v@$cc9b$^{-B)`1>$L^v1nf+`3@BGjB`{FnM@>%8T!K87bYr%qW{Eb;kt|L?J%8caWD^Gws>7o5ns zJy!M35sw~)7gCQ6xfJ9*X3R)#n;opp!@nTO(01y_o7bvbi@Q$f?fSTFmc2!A{@m0R zp}AW6hc_47|G&KcE(g2AhwCf9UEjt$$vQE~RP{HUsZP~pD*vP&t0AUt7Kw-c7|MLV}E`$-TXk|vWfS2gw7eR-BcHJhTUyS^|R0W z*e@Hdp1ImPYkrG`()84b&vJ8<!-md1-1~>C(AfXExT|GN>xsuXB34_^wwgGWZ0=J(IQeX>cUQC5iKu z{YYvQT>tK*$*#67&#u z5!!WYN0d~T_ZuVbj_gVSDW%6V7bNh>|9`giqi)f=#cnP;wmjLD)um{TVSb zW*Ein90X!KZ2wwLQxMQ!~1JdLv?=-7)K{_|6iAZVPp;Y|P7yu$lHhDHAa4aAirVHQIAMw=65ffmkG>@m=uo-9ruW1qo~uon;&N}nuEOPqW=I^|&^f%{!$IR{5PsE`ltN>8neY&0hQw7$W&eZuciktXEd8_bZ3JiezNxAFc5UB< zIP6+KH#zRk+#}I7*~ew>=QpfLZtfMmS1wL_>fN-zR#KknztNoA+?r0)_RG$h{UUIc z4~Nq7!=VQ8&vtG4=N`YJvv+adCjP@-S%r)q+HanGW;uF$*Qp%_%kRY0u2o(7-P($M zn~vnt)`mz~-AYA^k1wK+mVfqsCN$gps`EcpArI$S>v`nYWQhPF4p^5uQ_iZ>!3d2L)euumAUd+3jTCNN#I^ z%`-QfZhgErtw;Osudi2IZ!v<7C~UGn zdg|kYniTIR(yQuJw$zjf*G@VT@MDKX2cO)#7YFnLPK#YDI-k02v-$bgyK+^n&YYOw z-Pk^B#rfoy+_U1RRkB~cIoagsh6zu?BywN-B>UQ%Zrt|&zt_z-ua$)!EA3To;NLCR z@>Od7%k!!4XZ-ct;{I*>nP1+L=Gn7PmIlrJ^y(S+nrELCH7cAKv)q<7rg$6(GOqd8 zdsxN=#v`xO?ai&N38usn>#v=Q(1qJ;aQvV-`H`q1L;OhC= zr&pUvP0ClPbiAp;wP63O9)`V#k9SY_x@Gf({i*%ov%ZE%SING7>(&r&z?rAcX;Zyz zd-gjY?!IL8ld@^ce|4~3+N;-fZ*$^muSfdYTwB;4vS=w(Uw*Uw{n|f&)iyB&B>jIo z_2<8P6+4?=Zhy1V@6?SA3p?KQrO!}*;If!)OGCwiULxPi>;nqB)*-B5XAh+V-q^TAjFc z{d(a~??Nm7FR;%F_;E!;*ni%4vB(1tMDDhDg*^SqV0`u5@43Y+2TprU@X762CgC6O z^*HOEC(rN9JN`O^?e}?$+T;_?!Uw)wz9h@ltSaP}cAC>{uD182&D(q?FTQELW?tcp z;NN?{zADODo!4ja&}YfY|Ar=PpN{_5kxLaYtPD)qWB>pEGtC$-qZd1OxLvOJy5VP; zm+B7DsFlULv^V62DXbKbkL#YWJ)(B`n*wR!f-B4S@BcXIX~^#S3kN64eOT(cTKDkg zmpfxmFIoF>{?@0bB^=kTnf7_UK~#3xjg9Y?@}AtX+s0*P^{0C?ttK{n^>{OL4paT{ zy_=8a3;W;D_7J~axGha7{Bh8s`;3zd-(0`FsqkXMM+k6=N85=GsfkYIg=I? z)@3I6&P>@G%D!WgtK#NB{RaWX%MbLJu8RM+;p<(y(mO`x0lcNlPkejK!0!0|_#`cX z*Gq1fiWEn+|C5zmW?l?!(5oK%;$rP@1oXV{%M#t;{YHG(;%>!hC^D?R-3Y*gQG zJM($(PPpt~Uth6h)d8F3t=^$b+>;a-76&Z*ANXyu|0lbK6}sO=*0Bg(=iBmhWzLkW zmACjC{&|Hbc3wN2dAnP>-rwt~`5e2y*Ju4bu>GRy|GBr;9Q;|eD$nz3{PEskkNcjB z_Q^fTXe!oKyeP3Z(S6tBJ>Sifd@uSqC|4bfEaL zb#MD)&d-pc%eG;D&Eo4HrmI|?xF-IB!|4YT9ta8ZWmh>BmZg5#cW~CrgIWzT6K%~! zj=lT!KYRWMD%YUuVefwa;3%Z78kle|MS{R#{&8{2FpXKOE(p zlu|ypPEgy%^X}aLC2KETso7t0pnA^N^`g(>1b^N0-?nzmlCljwM&>s*%j^~Q&72pm z&9SL=z3Nxh-G%#kFI@G1+M_;2<)!H{KE`~ONe+uSwluuGSF`DJ^x390-Qj7Mq91Lj z{rmFJ$^A0lE5eW6eOLPEzD`%zS?!U-`2o{n$-J#jYN#>Tzd(riU$lYj~z89e8|xtH_7P zTwmUv){`;+-1JAi_=I%so~NppmaJ2Fb|K)SjsA|l3$;$iKfStpFgdHUza@tKZSz)f zqbJg3i|$TIapN!B%c`%y(0jY0eahG0eI?&4Up;x#6|*b0LrJ~E&23S!kFuL>yPKNU z!i?=_xaTXL7HQqQY3fd;?pL_)HiD#@nbXzFy!q)tcYknU3DKXJ+sln>~d$u}n z@tU(c$ZT?Om`vhs*K;dp@T`0NC*YGFi~0EpiIV&pXHID98aVx|pR~y8(!-|UQor`g zZr9E#_s8gSR-C&&Dcm-;vo7%51+D*kOxS(Z!k@6b3HWL;D|b=xu}7c(6wZCZ zBKqvO{>J3yNTV~p^QAfz?3zOlJ%8-O-Z)> zD>`dc)1GU;$*YUb3)Y!Y%FM+1zj6Q053ZJbr~Lc%Jb%BuUTu@$I;Z%miX%%(+)R;DJkz{4{m6{`4u8Az+j$f?&MO;ecYWt0!nMbbpPuuV# z?cCH9g~`V5PPG%xN*N1e{#o*Z_*{KefBxBq9wyhv4;fE!@tLi!^1Qfy52HlAnxV>V=4_q^ zT7G^V8(zF%V7M^VLbtWPt?C*7`nZtooA!5Zp5JyM@obgMOS_$#()HVSOn2C4weZlH z^!zjX7Z;~oJ7S@IdF%JPvE`R7y(BH&*qQshvO|P&1$&Xr5&(*^x z?&2$R@w(^CS#Lb2D_o7S>XB_aUn5f+In#$-Mep#MtQARlI|ZkQ8Hl%SHQYD%Wv|J5 z9)`PH*tZ%=t$OMkyF+-zm-LOE(mN{6A~q!NzfkdDmUvm7+tCNVx8^?EB=6(N>UN{^ zql{v2cTu#ey1?1KZyOvZT#LMVHv0X4(WFAf@1lM6fl>By+#fcEw(4moW;GmJ8K-W( zZqjD%6-skge|5%77e2)&D{F4{qA_b88B-_1;gPPB+@C xnhRWv`IUK*^+E0R8{Q5smc^CM&d>M1G5EHH$7b>Dkbv658Y;W>pIu-80{{_~QQ!ao literal 0 HcmV?d00001 diff --git a/libs/bufferstreams/examples/app/res/values/colors.xml b/libs/bufferstreams/examples/app/res/values/colors.xml new file mode 100644 index 0000000000..f8c6127d32 --- /dev/null +++ b/libs/bufferstreams/examples/app/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/res/values/strings.xml b/libs/bufferstreams/examples/app/res/values/strings.xml new file mode 100644 index 0000000000..e652102cb3 --- /dev/null +++ b/libs/bufferstreams/examples/app/res/values/strings.xml @@ -0,0 +1,3 @@ + + Buffer Demos + \ No newline at end of file -- GitLab From 3faf574466854576f79f5798f9350bc2cb0fb6f5 Mon Sep 17 00:00:00 2001 From: ramindani Date: Thu, 21 Sep 2023 13:45:12 -0700 Subject: [PATCH 0673/1187] [SF] Update only the render rate on the refresh rate indicator Test: manual BUG: 284845445 Change-Id: I30c34f1363bd7b3a21741c6b3ee70b67b1938fc0 --- services/surfaceflinger/DisplayDevice.cpp | 8 ++++++-- services/surfaceflinger/RefreshRateOverlay.cpp | 9 +++++++++ services/surfaceflinger/RefreshRateOverlay.h | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 252ba8e753..1faf6a1bcb 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -477,8 +477,12 @@ void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc, bool sh void DisplayDevice::updateRefreshRateOverlayRate(Fps vsyncRate, Fps renderFps, bool setByHwc) { ATRACE_CALL(); - if (mRefreshRateOverlay && (!mRefreshRateOverlay->isSetByHwc() || setByHwc)) { - mRefreshRateOverlay->changeRefreshRate(vsyncRate, renderFps); + if (mRefreshRateOverlay) { + if (!mRefreshRateOverlay->isSetByHwc() || setByHwc) { + mRefreshRateOverlay->changeRefreshRate(vsyncRate, renderFps); + } else { + mRefreshRateOverlay->changeRenderRate(renderFps); + } } } diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index e918dc9045..be04c09fa3 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -19,6 +19,7 @@ #include "Client.h" #include "Layer.h" #include "RefreshRateOverlay.h" +#include "Utils/FlagUtils.h" #include @@ -249,6 +250,14 @@ void RefreshRateOverlay::changeRefreshRate(Fps vsyncRate, Fps renderFps) { createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply(); } +void RefreshRateOverlay::changeRenderRate(Fps renderFps) { + if (mFeatures.test(Features::RenderRate) && mVsyncRate && flagutils::vrrConfigEnabled()) { + mRenderFps = renderFps; + const auto buffer = getOrCreateBuffers(*mVsyncRate, renderFps)[mFrame]; + createTransaction().setBuffer(mSurfaceControl->get(), buffer).apply(); + } +} + void RefreshRateOverlay::animate() { if (!mFeatures.test(Features::Spinner) || !mVsyncRate) return; diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index c0fc79b0ba..ae334e54ef 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -50,6 +50,7 @@ public: void setLayerStack(ui::LayerStack); void setViewport(ui::Size); void changeRefreshRate(Fps, Fps); + void changeRenderRate(Fps); void animate(); bool isSetByHwc() const { return mFeatures.test(RefreshRateOverlay::Features::SetByHwc); } -- GitLab From aa68d0a1bafebd3e09f5cdd404b70e74b580578d Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 22 Sep 2023 17:28:07 -0700 Subject: [PATCH 0674/1187] ftl: add enum_string_full which includes the enum class name Bug: 300701739 Test: presubmit Change-Id: I235275b5d299efea779851434c392ca4e07ca4fd --- include/ftl/enum.h | 79 ++++++++++++++++++++++++++++++++++++++---- libs/ftl/enum_test.cpp | 38 ++++++++++++++++++++ 2 files changed, 110 insertions(+), 7 deletions(-) diff --git a/include/ftl/enum.h b/include/ftl/enum.h index 075d12bd17..2c86e2e4c9 100644 --- a/include/ftl/enum.h +++ b/include/ftl/enum.h @@ -25,12 +25,12 @@ #include -// Returns the name of enumerator E::V (i.e. "V") as std::optional by parsing the -// compiler-generated string literal for the signature of this function. The function is defined in -// the global namespace with a short name and inferred return type to reduce bloat in the read-only -// data segment. -template -constexpr auto ftl_enum() { +// Returns the name of enumerator E::V and optionally the class (i.e. "E::V" or "V") as +// std::optional by parsing the compiler-generated string literal for the +// signature of this function. The function is defined in the global namespace with a short name +// and inferred return type to reduce bloat in the read-only data segment. +template +constexpr auto ftl_enum_builder() { static_assert(std::is_enum_v); using R = std::optional; @@ -58,7 +58,9 @@ constexpr auto ftl_enum() { // V = android::test::Enum::kValue // view = view.substr(value_begin); - const auto name_begin = view.rfind("::"sv); + const auto pos = S ? view.rfind("::"sv) - 2 : view.npos; + + const auto name_begin = view.rfind("::"sv, pos); if (name_begin == view.npos) return R{}; // Chop off the leading "::". @@ -68,6 +70,18 @@ constexpr auto ftl_enum() { return name.find(')') == view.npos ? R{name} : R{}; } +// Returns the name of enumerator E::V (i.e. "V") as std::optional +template +constexpr auto ftl_enum() { + return ftl_enum_builder(); +} + +// Returns the name of enumerator and class E::V (i.e. "E::V") as std::optional +template +constexpr auto ftl_enum_full() { + return ftl_enum_builder(); +} + namespace android::ftl { // Trait for determining whether a type is specifically a scoped enum or not. By definition, a @@ -191,6 +205,11 @@ struct EnumName { static constexpr auto value = ftl_enum(); }; +template +struct EnumNameFull { + static constexpr auto value = ftl_enum_full(); +}; + template struct FlagName { using E = decltype(I); @@ -230,6 +249,18 @@ constexpr std::string_view enum_name() { return *kName; } +// Returns a stringified enumerator with class at compile time. +// +// enum class E { A, B, C }; +// static_assert(ftl::enum_name() == "E::B"); +// +template +constexpr std::string_view enum_name_full() { + constexpr auto kName = ftl_enum_full(); + static_assert(kName, "Unknown enumerator"); + return *kName; +} + // Returns a stringified enumerator, possibly at compile time. // // enum class E { A, B, C, F = 5, ftl_last = F }; @@ -249,6 +280,25 @@ constexpr std::optional enum_name(E v) { return kRange.values[value - kBegin]; } +// Returns a stringified enumerator with class, possibly at compile time. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// static_assert(ftl::enum_name(E::C).value_or("?") == "E::C"); +// static_assert(ftl::enum_name(E{3}).value_or("?") == "?"); +// +template +constexpr std::optional enum_name_full(E v) { + const auto value = to_underlying(v); + + constexpr auto kBegin = to_underlying(enum_begin_v); + constexpr auto kLast = to_underlying(enum_last_v); + if (value < kBegin || value > kLast) return {}; + + constexpr auto kRange = details::EnumRange{}; + return kRange.values[value - kBegin]; +} + // Returns a stringified flag enumerator, possibly at compile time. // // enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; @@ -282,6 +332,21 @@ inline std::string enum_string(E v) { return to_string(to_underlying(v)); } +// Returns a stringified enumerator with class, or its integral value if not named. +// +// enum class E { A, B, C, F = 5, ftl_last = F }; +// +// assert(ftl::enum_string(E::C) == "E::C"); +// assert(ftl::enum_string(E{3}) == "3"); +// +template +inline std::string enum_string_full(E v) { + if (const auto name = enum_name_full(v)) { + return std::string(*name); + } + return to_string(to_underlying(v)); +} + // Returns a stringified flag enumerator, or its integral value if not named. // // enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; diff --git a/libs/ftl/enum_test.cpp b/libs/ftl/enum_test.cpp index 5592a01fde..b68c2c3d02 100644 --- a/libs/ftl/enum_test.cpp +++ b/libs/ftl/enum_test.cpp @@ -33,6 +33,11 @@ static_assert(ftl::enum_name() == "F"); static_assert(ftl::enum_name(E::C).value_or("?") == "C"); static_assert(ftl::enum_name(E{3}).value_or("?") == "?"); +static_assert(ftl::enum_name_full() == "E::B"); +static_assert(ftl::enum_name_full() == "E::F"); +static_assert(ftl::enum_name_full(E::C).value_or("?") == "E::C"); +static_assert(ftl::enum_name_full(E{3}).value_or("?") == "?"); + enum class F : std::uint16_t { X = 0b1, Y = 0b10, Z = 0b100 }; static_assert(ftl::enum_begin_v == F{0}); @@ -60,6 +65,10 @@ static_assert(ftl::enum_name() == "kNone"); static_assert(ftl::enum_name() == "kFlag4"); static_assert(ftl::enum_name() == "kFlag7"); +static_assert(ftl::enum_name_full() == "Flags::kNone"); +static_assert(ftl::enum_name_full() == "Flags::kFlag4"); +static_assert(ftl::enum_name_full() == "Flags::kFlag7"); + // Though not flags, the enumerators are within the implicit range of bit indices. enum class Planet : std::uint8_t { kMercury, @@ -81,6 +90,9 @@ static_assert(ftl::enum_size_v == 8); static_assert(ftl::enum_name() == "kMercury"); static_assert(ftl::enum_name() == "kSaturn"); +static_assert(ftl::enum_name_full() == "Planet::kMercury"); +static_assert(ftl::enum_name_full() == "Planet::kSaturn"); + // Unscoped enum must define explicit range, even if the underlying type is fixed. enum Temperature : int { kRoom = 20, @@ -122,16 +134,28 @@ TEST(Enum, Name) { EXPECT_EQ(ftl::enum_name(Planet::kEarth), "kEarth"); EXPECT_EQ(ftl::enum_name(Planet::kNeptune), "kNeptune"); + EXPECT_EQ(ftl::enum_name_full(Planet::kEarth), "Planet::kEarth"); + EXPECT_EQ(ftl::enum_name_full(Planet::kNeptune), "Planet::kNeptune"); + EXPECT_EQ(ftl::enum_name(kPluto), std::nullopt); + EXPECT_EQ(ftl::enum_name_full(kPluto), std::nullopt); } { EXPECT_EQ(ftl::enum_name(kRoom), "kRoom"); EXPECT_EQ(ftl::enum_name(kFridge), "kFridge"); EXPECT_EQ(ftl::enum_name(kFreezer), "kFreezer"); + EXPECT_EQ(ftl::enum_name(kRoom), "kRoom"); + EXPECT_EQ(ftl::enum_name(kFridge), "kFridge"); + EXPECT_EQ(ftl::enum_name(kFreezer), "kFreezer"); + EXPECT_EQ(ftl::enum_name(static_cast(-30)), std::nullopt); EXPECT_EQ(ftl::enum_name(static_cast(0)), std::nullopt); EXPECT_EQ(ftl::enum_name(static_cast(100)), std::nullopt); + + EXPECT_EQ(ftl::enum_name_full(static_cast(-30)), std::nullopt); + EXPECT_EQ(ftl::enum_name_full(static_cast(0)), std::nullopt); + EXPECT_EQ(ftl::enum_name_full(static_cast(100)), std::nullopt); } } @@ -158,16 +182,30 @@ TEST(Enum, String) { EXPECT_EQ(ftl::enum_string(Planet::kEarth), "kEarth"); EXPECT_EQ(ftl::enum_string(Planet::kNeptune), "kNeptune"); + EXPECT_EQ(ftl::enum_string_full(Planet::kEarth), "Planet::kEarth"); + EXPECT_EQ(ftl::enum_string_full(Planet::kNeptune), "Planet::kNeptune"); + EXPECT_EQ(ftl::enum_string(kPluto), "8"); + + EXPECT_EQ(ftl::enum_string_full(kPluto), "8"); + } { EXPECT_EQ(ftl::enum_string(kRoom), "kRoom"); EXPECT_EQ(ftl::enum_string(kFridge), "kFridge"); EXPECT_EQ(ftl::enum_string(kFreezer), "kFreezer"); + EXPECT_EQ(ftl::enum_string_full(kRoom), "20"); + EXPECT_EQ(ftl::enum_string_full(kFridge), "4"); + EXPECT_EQ(ftl::enum_string_full(kFreezer), "-18"); + EXPECT_EQ(ftl::enum_string(static_cast(-30)), "-30"); EXPECT_EQ(ftl::enum_string(static_cast(0)), "0"); EXPECT_EQ(ftl::enum_string(static_cast(100)), "100"); + + EXPECT_EQ(ftl::enum_string_full(static_cast(-30)), "-30"); + EXPECT_EQ(ftl::enum_string_full(static_cast(0)), "0"); + EXPECT_EQ(ftl::enum_string_full(static_cast(100)), "100"); } } -- GitLab From 4cb525bc5c72e93c76c02659472c499767a2a809 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 22 Sep 2023 17:34:45 -0700 Subject: [PATCH 0675/1187] SF: add requestedLaterState to Hierarchy dump Test: presubmit Bug: 300701739 Change-Id: I6d24998c50eeaaedc5f7ec5a4b9e5ad5e0555745 --- services/surfaceflinger/FrontEnd/RequestedLayerState.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index fcc1e61c95..dc8694c930 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -405,10 +405,19 @@ std::string RequestedLayerState::getDebugString() const { return debug.str(); } +std::ostream& operator<<(std::ostream& out, const scheduler::LayerInfo::FrameRate& obj) { + out << obj.vote.rate; + out << " " << ftl::enum_string_full(obj.vote.type); + out << " " << ftl::enum_string_full(obj.category); + return out; +} + std::ostream& operator<<(std::ostream& out, const RequestedLayerState& obj) { out << obj.debugName; if (obj.relativeParentId != UNASSIGNED_LAYER_ID) out << " parent=" << obj.parentId; if (!obj.handleAlive) out << " handleNotAlive"; + if (obj.requestedFrameRate.isValid()) + out << " requestedFrameRate: {" << obj.requestedFrameRate << "}"; return out; } -- GitLab From 771a769d6a9aa6eeea72dc821ee4c0a706942302 Mon Sep 17 00:00:00 2001 From: Hu Guo Date: Sun, 17 Sep 2023 20:51:08 +0800 Subject: [PATCH 0676/1187] Dispatch cancel event to the correct target display When screen recording is enabled, a virtual screen will be generated, and the cancel event will be incorrectly sent to the virtual screen. The coordinates of the cancel event are the wrong logical coordinates after being transformed by the transform of the windows of the virtual screen. Bug: 301020008 Test: atest inputflinger_tests Change-Id: Icf1301e5174ac61eeedda326545f2b68ef7b8af0 --- .../dispatcher/InputDispatcher.cpp | 9 +++- .../tests/InputDispatcher_test.cpp | 54 +++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index d98641ec1d..0a143e8d3b 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3940,8 +3940,13 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS; InputTarget target; - sp windowHandle = - getWindowHandleLocked(connection->inputChannel->getConnectionToken()); + sp windowHandle; + if (options.displayId) { + windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken(), + options.displayId.value()); + } else { + windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken()); + } if (windowHandle != nullptr) { const WindowInfo* windowInfo = windowHandle->getInfo(); target.setDefaultPointerTransform(windowInfo->transform); diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index dc281a3d5f..443b037673 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -3977,6 +3977,60 @@ TEST_F(InputDispatcherTest, MultiplePointersWithRotatingWindow) { window->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); } +/** + * When there are multiple screens, such as screen projection to TV or screen recording, if the + * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and + * its coordinates should be converted by the transform of the windows of target screen. + */ +TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) { + // This case will create a window and a spy window on the default display and mirror + // window on the second display. cancel event is sent through spy window pilferPointers + std::shared_ptr application = std::make_shared(); + + sp spyWindowDefaultDisplay = + sp::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); + spyWindowDefaultDisplay->setTrustedOverlay(true); + spyWindowDefaultDisplay->setSpy(true); + + sp windowDefaultDisplay = + sp::make(application, mDispatcher, "DefaultDisplay", + ADISPLAY_ID_DEFAULT); + windowDefaultDisplay->setWindowTransform(1, 0, 0, 1); + + sp windowSecondDisplay = windowDefaultDisplay->clone(SECOND_DISPLAY_ID); + windowSecondDisplay->setWindowTransform(2, 0, 0, 2); + + // Add the windows to the dispatcher + mDispatcher->onWindowInfosChanged( + {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(), + *windowSecondDisplay->getInfo()}, + {}, + 0, + 0}); + + // Send down to ADISPLAY_ID_DEFAULT + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 100})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + spyWindowDefaultDisplay->consumeMotionDown(); + windowDefaultDisplay->consumeMotionDown(); + + EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken())); + + // windowDefaultDisplay gets cancel + MotionEvent* event = windowDefaultDisplay->consumeMotion(); + EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction()); + + // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the + // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y + // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of + // SECOND_DISPLAY_ID, the x and y coordinates are 200 + EXPECT_EQ(100, event->getX(0)); + EXPECT_EQ(100, event->getY(0)); +} + /** * Ensure the correct coordinate spaces are used by InputDispatcher. * -- GitLab From 4c5b25e5e9967366bfe7df7219ca4c469eab5375 Mon Sep 17 00:00:00 2001 From: Daniele Di Proietto Date: Mon, 25 Sep 2023 09:20:18 +0000 Subject: [PATCH 0677/1187] tracing: Allow access to a couple more binder events Bug: 295124679 Change-Id: I6a03e56d992c6d0d4e5e8137ceebe93e312e0640 --- cmds/atrace/atrace.rc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index fc0801cce8..3e6d2e01f8 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -93,6 +93,10 @@ on late-init chmod 0666 /sys/kernel/tracing/events/binder/binder_unlock/enable chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_set_priority/enable chmod 0666 /sys/kernel/tracing/events/binder/binder_set_priority/enable + chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_command/enable + chmod 0666 /sys/kernel/tracing/events/binder/binder_command/enable + chmod 0666 /sys/kernel/debug/tracing/events/binder/binder_return/enable + chmod 0666 /sys/kernel/tracing/events/binder/binder_return/enable chmod 0666 /sys/kernel/debug/tracing/events/i2c/enable chmod 0666 /sys/kernel/tracing/events/i2c/enable chmod 0666 /sys/kernel/debug/tracing/events/i2c/i2c_read/enable -- GitLab From 0f3fb962e1bbe2df09831c6c65afbbaf7bc29511 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 25 Sep 2023 19:10:16 +0000 Subject: [PATCH 0678/1187] Add CoGS team as OWNERS of ftl Change-Id: I6dedab758f2a6b50e07f2c9bf5fed8fcc37a8d52 --- libs/ftl/OWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 libs/ftl/OWNERS diff --git a/libs/ftl/OWNERS b/libs/ftl/OWNERS new file mode 100644 index 0000000000..3f6129226a --- /dev/null +++ b/libs/ftl/OWNERS @@ -0,0 +1 @@ +include platform/frameworks/native:/services/surfaceflinger/OWNERS \ No newline at end of file -- GitLab From b7d57bb3f9060bb5b3ad532bf5ea8218470b5b22 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 25 Sep 2023 19:15:39 +0000 Subject: [PATCH 0679/1187] Add jreck to SF owners Change-Id: I73bcf6c5a0733993fdd0a24826e2936cb6f7c33c --- services/surfaceflinger/OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS index 3270e4c95c..0aee7d497c 100644 --- a/services/surfaceflinger/OWNERS +++ b/services/surfaceflinger/OWNERS @@ -4,6 +4,7 @@ adyabr@google.com alecmouri@google.com chaviw@google.com domlaskowski@google.com +jreck@google.com lpy@google.com pdwilliams@google.com racarr@google.com -- GitLab From eb44a9cf3836848862214b61c964a823beb86558 Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Mon, 25 Sep 2023 19:42:56 +0000 Subject: [PATCH 0680/1187] Add CoGS team as OWNERS of ftl Change-Id: I3a0c6b46197debe5985d386b56bb1178e24d85f9 --- include/ftl/OWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 include/ftl/OWNERS diff --git a/include/ftl/OWNERS b/include/ftl/OWNERS new file mode 100644 index 0000000000..3f6129226a --- /dev/null +++ b/include/ftl/OWNERS @@ -0,0 +1 @@ +include platform/frameworks/native:/services/surfaceflinger/OWNERS \ No newline at end of file -- GitLab From 0f64d57d1c66b2a11a4040910ac58e3652aaf3a9 Mon Sep 17 00:00:00 2001 From: Jing Ji Date: Fri, 22 Sep 2023 15:01:48 -0700 Subject: [PATCH 0681/1187] Add test to the BpBinder::getBinderProxyCount Ignore-AOSP-First: Will merge along with the previous CL Bug: 298314844 Test: atest BinderLibTest#BinderProxyCount Change-Id: I97bbb5b7560f36294718ce22015079bc4f96ba22 --- libs/binder/tests/binderLibTest.cpp | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index e021af0264..0396869167 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -1441,6 +1441,36 @@ TEST_F(BinderLibTest, HangingServices) { EXPECT_GE(epochMsAfter, epochMsBefore + delay); } +TEST_F(BinderLibTest, BinderProxyCount) { + Parcel data, reply; + sp server = addServer(); + ASSERT_NE(server, nullptr); + + uint32_t initialCount = BpBinder::getBinderProxyCount(); + size_t iterations = 100; + { + uint32_t count = initialCount; + std::vector > proxies; + sp proxy; + // Create binder proxies and verify the count. + for (size_t i = 0; i < iterations; i++) { + ASSERT_THAT(server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, data, &reply), + StatusEq(NO_ERROR)); + proxies.push_back(reply.readStrongBinder()); + EXPECT_EQ(BpBinder::getBinderProxyCount(), ++count); + } + // Remove every other one and verify the count. + auto it = proxies.begin(); + for (size_t i = 0; it != proxies.end(); i++) { + if (i % 2 == 0) { + it = proxies.erase(it); + EXPECT_EQ(BpBinder::getBinderProxyCount(), --count); + } + } + } + EXPECT_EQ(BpBinder::getBinderProxyCount(), initialCount); +} + class BinderLibRpcTestBase : public BinderLibTest { public: void SetUp() override { -- GitLab From d7479506dcbf82d9fc01c512fbe18c8c5d979254 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Mon, 25 Sep 2023 17:02:35 -0700 Subject: [PATCH 0682/1187] Propagate tree on setting selection strategy Otherwise there is an order dependency on calling setFrameRate, setFrameRateCategory, and setFrameRateSelectionStrategy. Bug: 297418260 Test: atest FrameRateSelectionStrategyTest Change-Id: I9fb345a1632c5a18fe445d1637b6bb22984fe24e --- services/surfaceflinger/Layer.cpp | 2 ++ .../unittests/FrameRateSelectionStrategyTest.cpp | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index e780a1e8f7..a73c5115b1 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1352,6 +1352,8 @@ bool Layer::setFrameRateSelectionStrategy(FrameRateSelectionStrategy strategy) { mDrawingState.frameRateSelectionStrategy = strategy; mDrawingState.sequence++; mDrawingState.modified = true; + + updateTreeHasFrameRateVote(); setTransactionFlags(eTransactionNeeded); return true; } diff --git a/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp index ffe6f245b5..20ea0c080a 100644 --- a/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp @@ -153,6 +153,19 @@ TEST_P(FrameRateSelectionStrategyTest, SetParentAndGet) { EXPECT_EQ(FRAME_RATE_VOTE1, layer3->getFrameRateForLayerTree()); EXPECT_EQ(FrameRateSelectionStrategy::Self, layer3->getDrawingState().frameRateSelectionStrategy); + + layer1->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::Self); + commitTransaction(); + + EXPECT_EQ(FRAME_RATE_VOTE1, layer1->getFrameRateForLayerTree()); + EXPECT_EQ(FrameRateSelectionStrategy::Self, + layer1->getDrawingState().frameRateSelectionStrategy); + EXPECT_EQ(FRAME_RATE_VOTE2, layer2->getFrameRateForLayerTree()); + EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren, + layer2->getDrawingState().frameRateSelectionStrategy); + EXPECT_EQ(FRAME_RATE_VOTE2, layer3->getFrameRateForLayerTree()); + EXPECT_EQ(FrameRateSelectionStrategy::Self, + layer3->getDrawingState().frameRateSelectionStrategy); } } // namespace -- GitLab From 77f370977a53dddc5a9b5d77968c404fd93fa2e6 Mon Sep 17 00:00:00 2001 From: Kiyoung Kim Date: Tue, 26 Sep 2023 10:41:47 +0900 Subject: [PATCH 0683/1187] Use ro.vndk.version to check if VNDK is deprecated ro.vndk.version will not be set if VNDK is deprecated. This change reads ro.vndk.version instead of temp property to check if the device is VNDK deprecated. Bug: 290159430 Test: Cuttlefish build and run succeeded Change-Id: I7ef2341872fb8dcd1a2ca5e0c853ada06d6726ac --- libs/graphicsenv/GraphicsEnv.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 64f8704094..701a3b2f77 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -63,8 +63,7 @@ typedef bool (*fpANGLEFreeSystemInfoHandle)(void* handle); namespace { static bool isVndkEnabled() { #ifdef __BIONIC__ - // TODO(b/290159430) Use ro.vndk.version to check if VNDK is enabled instead - static bool isVndkEnabled = !android::base::GetBoolProperty("ro.vndk.deprecate", false); + static bool isVndkEnabled = android::base::GetProperty("ro.vndk.version", "") != ""; return isVndkEnabled; #endif return false; -- GitLab From 2389f167dfad030c2f013fd38b83989685620adf Mon Sep 17 00:00:00 2001 From: Atharva_Deshpande Date: Tue, 1 Aug 2023 16:19:09 +0530 Subject: [PATCH 0684/1187] inputflinger_input_classifier_fuzzer: Bug Fix Resolved signed integer overflow. A range for eventTime has been set to prevent integer overflow in the readTime variable exec/sec: 7000 Test: ./inputflinger_input_classifier_fuzzer clusterfuzz-testcase-minimized-inputflinger_input_classifier_fuzzer-5773122447933440 Bug: 289471463 Change-Id: I5cff2468b81ac8dc2f0773638d13a0d7e25f7038 (cherry picked from commit 6f6c88f12f57633047b32ce98498367c40a4b891) --- .../inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp index f8ebc97ccd..3b3ed9ba0d 100644 --- a/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/InputClassifierFuzzer.cpp @@ -73,9 +73,11 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { }, [&]() -> void { // SendToNextStage_NotifyKeyArgs - const nsecs_t eventTime = fdp.ConsumeIntegral(); - const nsecs_t readTime = - eventTime + fdp.ConsumeIntegralInRange(0, 1E8); + const nsecs_t eventTime = + fdp.ConsumeIntegralInRange(0, + systemTime(SYSTEM_TIME_MONOTONIC)); + const nsecs_t readTime = fdp.ConsumeIntegralInRange< + nsecs_t>(eventTime, std::numeric_limits::max()); mClassifier->notifyKey({/*sequenceNum=*/fdp.ConsumeIntegral(), eventTime, readTime, /*deviceId=*/fdp.ConsumeIntegral(), -- GitLab From f0f258882ea0f26338bfc984685db32e98bf70fb Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Tue, 26 Sep 2023 09:37:52 +0000 Subject: [PATCH 0685/1187] Fix output stream creation in layertracegenerator layertracegenerator creates the output layers trace file specifying std::ios::app (append mode). Meaning, if an output file already exists layertracegenerator appends the new layers trace to it. This commit solves the issue replacing std::ios::app with std::ios::out. Bug: 301539901 Test: execute multiple times \ adb shell layertracegenerator transaction.winscope test.winscope and make sure the size of test.winscope remains constant \ and doesn't increase after each execution of layertracegenerator Change-Id: I23bf4e689cee450b055a0451aa0301ce34131739 --- services/surfaceflinger/Tracing/tools/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/Tracing/tools/main.cpp b/services/surfaceflinger/Tracing/tools/main.cpp index 65e8479358..698ef06534 100644 --- a/services/surfaceflinger/Tracing/tools/main.cpp +++ b/services/surfaceflinger/Tracing/tools/main.cpp @@ -50,7 +50,7 @@ int main(int argc, char** argv) { const auto* outputLayersTracePath = (argc == 3) ? argv[2] : "/data/misc/wmtrace/layers_trace.winscope"; - auto outStream = std::ofstream{outputLayersTracePath, std::ios::binary | std::ios::app}; + auto outStream = std::ofstream{outputLayersTracePath, std::ios::binary | std::ios::out}; auto layerTracing = LayerTracing{outStream}; -- GitLab From 8bbfca38d61b2691ba356f147bcdf8912ea45d9e Mon Sep 17 00:00:00 2001 From: Khyber Sen Date: Sat, 2 Sep 2023 00:24:05 +0000 Subject: [PATCH 0686/1187] rpc_fuzzer: Add new trusty binder rpc fuzzers that use multiple connections Test: Build and run in trusty emulator Change-Id: I17906f6323723c4799b25432651137c7bb9ca16a --- libs/binder/trusty/fuzzer/Android.bp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/libs/binder/trusty/fuzzer/Android.bp b/libs/binder/trusty/fuzzer/Android.bp index 2f1f54b0a6..4f9b5c4d9d 100644 --- a/libs/binder/trusty/fuzzer/Android.bp +++ b/libs/binder/trusty/fuzzer/Android.bp @@ -24,6 +24,7 @@ cc_fuzz { "-DTRUSTY_APP_PORT=\"com.android.trusty.binder.test.service\"", "-DTRUSTY_APP_UUID=\"d42f06c5-9dc5-455b-9914-cf094116cfa8\"", "-DTRUSTY_APP_FILENAME=\"binder-test-service.syms.elf\"", + "-DTRUSTY_APP_MAX_CONNECTIONS=1", ], } @@ -35,5 +36,30 @@ cc_fuzz { "-DTRUSTY_APP_PORT=\"com.android.trusty.binderRpcTestService.V0\"", "-DTRUSTY_APP_UUID=\"87e424e5-69d7-4bbd-8b7c-7e24812cbc94\"", "-DTRUSTY_APP_FILENAME=\"binderRpcTestService.syms.elf\"", + "-DTRUSTY_APP_MAX_CONNECTIONS=1", + ], +} + +cc_fuzz { + name: "trusty_binder_fuzzer_multi_connection", + defaults: ["trusty_fuzzer_defaults"], + srcs: [":trusty_tipc_fuzzer"], + cflags: [ + "-DTRUSTY_APP_PORT=\"com.android.trusty.binder.test.service\"", + "-DTRUSTY_APP_UUID=\"d42f06c5-9dc5-455b-9914-cf094116cfa8\"", + "-DTRUSTY_APP_FILENAME=\"binder-test-service.syms.elf\"", + "-DTRUSTY_APP_MAX_CONNECTIONS=10", + ], +} + +cc_fuzz { + name: "trusty_binder_rpc_fuzzer_multi_connection", + defaults: ["trusty_fuzzer_defaults"], + srcs: [":trusty_tipc_fuzzer"], + cflags: [ + "-DTRUSTY_APP_PORT=\"com.android.trusty.binderRpcTestService.V0\"", + "-DTRUSTY_APP_UUID=\"87e424e5-69d7-4bbd-8b7c-7e24812cbc94\"", + "-DTRUSTY_APP_FILENAME=\"binderRpcTestService.syms.elf\"", + "-DTRUSTY_APP_MAX_CONNECTIONS=10", ], } -- GitLab From e4d23b9ce68f221cb9750b49d62d8c1ac35a1a14 Mon Sep 17 00:00:00 2001 From: Trevor David Black Date: Tue, 26 Sep 2023 20:30:42 +0000 Subject: [PATCH 0687/1187] Clarified value of 2 for default buffers in vulkan swapchain Bug: 296019634 Test: atest CtsDeqpTestCases -- --module-arg 'CtsDeqpTestCases:include-filter:dEQP-VK.wsi.*' Change-Id: Ie690fdb87c42d1000550d3f92fb7d0527cba3ca9 --- vulkan/libvulkan/swapchain.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index c5870d4de2..dcef54dc38 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -944,6 +944,11 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( return VK_ERROR_SURFACE_LOST_KHR; } + // Additional buffer count over min_undequeued_buffers in vulkan came from 2 total + // being technically enough for fifo (although a poor experience) vs 3 being the + // absolute minimum for mailbox to be useful. So min_undequeued_buffers + 2 is sensible + static constexpr int default_additional_buffers = 2; + if(pPresentMode != nullptr) { switch (pPresentMode->presentMode) { case VK_PRESENT_MODE_IMMEDIATE_KHR: @@ -951,8 +956,8 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( break; case VK_PRESENT_MODE_MAILBOX_KHR: case VK_PRESENT_MODE_FIFO_KHR: - capabilities->minImageCount = - std::min(max_buffer_count, min_undequeued_buffers + 2); + capabilities->minImageCount = std::min(max_buffer_count, + min_undequeued_buffers + default_additional_buffers); capabilities->maxImageCount = static_cast(max_buffer_count); break; case VK_PRESENT_MODE_FIFO_RELAXED_KHR: @@ -971,7 +976,8 @@ VkResult GetPhysicalDeviceSurfaceCapabilities2KHR( break; } } else { - capabilities->minImageCount = std::min(max_buffer_count, min_undequeued_buffers + 2); + capabilities->minImageCount = std::min(max_buffer_count, + min_undequeued_buffers + default_additional_buffers); capabilities->maxImageCount = static_cast(max_buffer_count); } } -- GitLab From 1926052eb752a8a7d10d9b7bd12fde8291f1f1d7 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 22 Sep 2023 12:18:53 -0700 Subject: [PATCH 0688/1187] libnativedisplay: Introduce SurfaceTextureListener This is a tiny refactoting needed for the next CL. Bug: 281695725 Test: manual using a test app Change-Id: I0635325717073b528dadb712a843aabb4efddd3b --- libs/gui/Android.bp | 1 + libs/nativedisplay/Android.bp | 2 ++ .../include/surfacetexture/SurfaceTexture.h | 34 +++++++++++++++++++ .../surfacetexture/SurfaceTexture.cpp | 24 +++++++++++++ 4 files changed, 61 insertions(+) diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 9a27d2321b..f17a6547f7 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -200,6 +200,7 @@ aconfig_declarations { cc_aconfig_library { name: "libguiflags", + host_supported: true, vendor_available: true, aconfig_declarations: "libgui_flags", } diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp index 8d8a2bc244..342f5de337 100644 --- a/libs/nativedisplay/Android.bp +++ b/libs/nativedisplay/Android.bp @@ -73,6 +73,8 @@ cc_library_shared { "libGLESv2", ], + static_libs: ["libguiflags"], + export_header_lib_headers: ["jni_headers"], header_libs: [ diff --git a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h index 0f119f3fc1..46727055bb 100644 --- a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h +++ b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h @@ -290,6 +290,18 @@ public: */ void releaseConsumerOwnership(); + /** + * Interface for SurfaceTexture callback(s). + */ + struct SurfaceTextureListener : public RefBase { + virtual void onFrameAvailable(const BufferItem& item) = 0; + }; + + /** + * setSurfaceTextureListener registers a SurfaceTextureListener. + */ + void setSurfaceTextureListener(const sp&); + protected: /** * abandonLocked overrides the ConsumerBase method to clear @@ -465,8 +477,30 @@ protected: */ ImageConsumer mImageConsumer; + /** + * mSurfaceTextureListener holds the registered SurfaceTextureListener. + * Note that SurfaceTexture holds the lister with an sp<>, which means that the listener + * must only hold a wp<> to SurfaceTexture and not an sp<>. + */ + sp mSurfaceTextureListener; + friend class ImageConsumer; friend class EGLConsumer; + +private: + // Proxy listener to avoid having SurfaceTexture directly implement FrameAvailableListener as it + // is extending ConsumerBase which also implements FrameAvailableListener. + class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener { + public: + FrameAvailableListenerProxy(const wp& listener) + : mSurfaceTextureListener(listener) {} + + private: + void onFrameAvailable(const BufferItem& item) override; + + const wp mSurfaceTextureListener; + }; + sp mFrameAvailableListenerProxy; }; // ---------------------------------------------------------------------------- diff --git a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp index 9f610e1a50..11482ecc36 100644 --- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp +++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp @@ -23,6 +23,8 @@ #include #include +#include + namespace android { // Macros for including the SurfaceTexture name in log messages @@ -491,4 +493,26 @@ sp SurfaceTexture::dequeueBuffer(int* outSlotid, android_dataspac return buffer; } +void SurfaceTexture::setSurfaceTextureListener( + const sp& listener) { + SFT_LOGV("setSurfaceTextureListener"); + + Mutex::Autolock _l(mMutex); + mSurfaceTextureListener = listener; + if (mSurfaceTextureListener != nullptr) { + mFrameAvailableListenerProxy = + sp::make(mSurfaceTextureListener); + setFrameAvailableListener(mFrameAvailableListenerProxy); + } else { + mFrameAvailableListenerProxy.clear(); + } +} + +void SurfaceTexture::FrameAvailableListenerProxy::onFrameAvailable(const BufferItem& item) { + const auto listener = mSurfaceTextureListener.promote(); + if (listener) { + listener->onFrameAvailable(item); + } +} + } // namespace android -- GitLab From d5e8e27630b869153c1db7d718b01d99749cdc3c Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 21 Sep 2023 18:06:54 -0700 Subject: [PATCH 0689/1187] libnativedisplay: plumb setFrameRate to SurfaceTexure Bug: 281695725 Test: manual using a test app Change-Id: I2d18c843d9e0771cef4378f58f1197f974163fa0 --- .../include/surfacetexture/SurfaceTexture.h | 11 +++++++++++ .../surfacetexture/SurfaceTexture.cpp | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h index 46727055bb..32fb3508ff 100644 --- a/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h +++ b/libs/nativedisplay/include/surfacetexture/SurfaceTexture.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -295,6 +296,8 @@ public: */ struct SurfaceTextureListener : public RefBase { virtual void onFrameAvailable(const BufferItem& item) = 0; + virtual void onSetFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) = 0; }; /** @@ -346,6 +349,14 @@ protected: */ void computeCurrentTransformMatrixLocked(); + /** + * onSetFrameRate Notifies the consumer of a setFrameRate call from the producer side. + */ +#if FLAG_BQ_SET_FRAME_RATE + void onSetFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) override; +#endif + /** * The default consumer usage flags that SurfaceTexture always sets on its * BufferQueue instance; these will be OR:d with any additional flags passed diff --git a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp index 11482ecc36..c2535e0bf6 100644 --- a/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp +++ b/libs/nativedisplay/surfacetexture/SurfaceTexture.cpp @@ -515,4 +515,20 @@ void SurfaceTexture::FrameAvailableListenerProxy::onFrameAvailable(const BufferI } } +#if FLAG_BQ_SET_FRAME_RATE +void SurfaceTexture::onSetFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) { + SFT_LOGV("onSetFrameRate: %.2f", frameRate); + + auto listener = [&] { + Mutex::Autolock _l(mMutex); + return mSurfaceTextureListener; + }(); + + if (listener) { + listener->onSetFrameRate(frameRate, compatibility, changeFrameRateStrategy); + } +} +#endif + } // namespace android -- GitLab From 42407bc5607b1169accb306d301e3899f6925863 Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Tue, 26 Sep 2023 21:30:39 +0000 Subject: [PATCH 0690/1187] Add additional instance info to log When an instance can't be found, we now log the available instances. This can help debugging when the instance name is misspelled or the manifest fragment file wasn't included. Test: launch_cvd && and logcat | grep "Could not find" Test: atest servicemanager_test Bug: 302147119 Change-Id: Iad85903d82bbd45c012b007ba1fcf059c5cd5c4a --- cmds/servicemanager/ServiceManager.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index cae9684cc4..facb8b133b 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -112,10 +113,26 @@ static bool isVintfDeclared(const std::string& name) { }); if (!found) { + std::set instances; + forEachManifest([&](const ManifestWithDescription& mwd) { + std::set res = mwd.manifest->getAidlInstances(aname.package, aname.iface); + instances.insert(res.begin(), res.end()); + return true; + }); + + std::string available; + if (instances.empty()) { + available = "No alternative instances declared in VINTF"; + } else { + // for logging only. We can't return this information to the client + // because they may not have permissions to find or list those + // instances + available = "VINTF declared instances: " + base::Join(instances, ", "); + } // Although it is tested, explicitly rebuilding qualified name, in case it // becomes something unexpected. - ALOGI("Could not find %s.%s/%s in the VINTF manifest.", aname.package.c_str(), - aname.iface.c_str(), aname.instance.c_str()); + ALOGI("Could not find %s.%s/%s in the VINTF manifest. %s.", aname.package.c_str(), + aname.iface.c_str(), aname.instance.c_str(), available.c_str()); } return found; -- GitLab From 2aef464f72f415a03d0bc47aa7c7ed4c5db57009 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Tue, 26 Sep 2023 16:49:22 -0700 Subject: [PATCH 0691/1187] inputflinger: add missing include Bug: 175635923 Test: treehugger Change-Id: Ieb7828b26613c3b5470c9b76f31ad1b6b09d9445 --- services/inputflinger/BlockingQueue.h | 1 + 1 file changed, 1 insertion(+) diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h index 56938480f0..f848c82c42 100644 --- a/services/inputflinger/BlockingQueue.h +++ b/services/inputflinger/BlockingQueue.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include #include -- GitLab From bba43428f314582e9b628b79aa13b357f0fa29fd Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Tue, 19 Sep 2023 23:54:04 -0700 Subject: [PATCH 0692/1187] inputflinger: add missing include Bug: 175635923 Test: treehugger Change-Id: Ieb7828b26613c3b5470c9b76f31ad1b6b09d9445 Merged-In: Ieb7828b26613c3b5470c9b76f31ad1b6b09d9445 --- services/inputflinger/BlockingQueue.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h index 8300e8a3da..032cb6dea3 100644 --- a/services/inputflinger/BlockingQueue.h +++ b/services/inputflinger/BlockingQueue.h @@ -17,10 +17,11 @@ #ifndef _UI_INPUT_BLOCKING_QUEUE_H #define _UI_INPUT_BLOCKING_QUEUE_H -#include "android-base/thread_annotations.h" #include +#include #include #include +#include "android-base/thread_annotations.h" namespace android { -- GitLab From 5197ce6de3b0bce9de795f4cbd8605de08946bb3 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 19 Sep 2023 08:27:05 -0700 Subject: [PATCH 0693/1187] Move Process_PointerCapture to CursorInputMapper_test This test will now be using the new test infra set up in CursorInputMapper_test instead of the one in InputReader_test. This specific test documents the behaviour of pointer capture - the generation of ACTION_MOVE events during pointer capture, and the use of SOURCE_MOUSE_RELATIVE. Bug: 283812079 Test: atest inputflinger_tests Change-Id: I87d707dfd418ab7d6203571a4acf7a090d247304 --- .../tests/CursorInputMapper_test.cpp | 98 ++++++++++++++++++- .../inputflinger/tests/InputMapperTest.cpp | 2 +- services/inputflinger/tests/InputMapperTest.h | 2 + .../inputflinger/tests/InputReader_test.cpp | 86 ---------------- services/inputflinger/tests/InterfaceMocks.h | 5 +- .../tests/TestInputListenerMatchers.h | 8 ++ 6 files changed, 111 insertions(+), 90 deletions(-) diff --git a/services/inputflinger/tests/CursorInputMapper_test.cpp b/services/inputflinger/tests/CursorInputMapper_test.cpp index 6774b1793f..e630915116 100644 --- a/services/inputflinger/tests/CursorInputMapper_test.cpp +++ b/services/inputflinger/tests/CursorInputMapper_test.cpp @@ -28,6 +28,7 @@ namespace android { +using testing::AllOf; using testing::Return; using testing::VariantWith; constexpr auto ACTION_DOWN = AMOTION_EVENT_ACTION_DOWN; @@ -36,6 +37,7 @@ constexpr auto ACTION_UP = AMOTION_EVENT_ACTION_UP; constexpr auto BUTTON_PRESS = AMOTION_EVENT_ACTION_BUTTON_PRESS; constexpr auto BUTTON_RELEASE = AMOTION_EVENT_ACTION_BUTTON_RELEASE; constexpr auto HOVER_MOVE = AMOTION_EVENT_ACTION_HOVER_MOVE; +constexpr auto INVALID_CURSOR_POSITION = AMOTION_EVENT_INVALID_CURSOR_POSITION; /** * Unit tests for CursorInputMapper. @@ -58,10 +60,23 @@ protected: EXPECT_CALL(mMockEventHub, hasRelativeAxis(EVENTHUB_ID, REL_HWHEEL)) .WillRepeatedly(Return(false)); - EXPECT_CALL(mMockInputReaderContext, bumpGeneration()).WillRepeatedly(Return(1)); - mMapper = createInputMapper(*mDeviceContext, mReaderConfiguration); } + + void setPointerCapture(bool enabled) { + mReaderConfiguration.pointerCaptureRequest.enable = enabled; + mReaderConfiguration.pointerCaptureRequest.seq = 1; + int32_t generation = mDevice->getGeneration(); + std::list args = + mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration, + InputReaderConfiguration::Change::POINTER_CAPTURE); + ASSERT_THAT(args, + ElementsAre( + VariantWith(AllOf(WithDeviceId(DEVICE_ID))))); + + // Check that generation also got bumped + ASSERT_GT(mDevice->getGeneration(), generation); + } }; /** @@ -102,4 +117,83 @@ TEST_F(CursorInputMapperUnitTest, HoverAndLeftButtonPress) { VariantWith(WithMotionAction(HOVER_MOVE)))); } +/** + * Set pointer capture and check that ACTION_MOVE events are emitted from CursorInputMapper. + * During pointer capture, source should be set to MOUSE_RELATIVE. When the capture is disabled, + * the events should be generated normally: + * 1) The source should return to SOURCE_MOUSE + * 2) Cursor position should be incremented by the relative device movements + * 3) Cursor position of NotifyMotionArgs should now be getting populated. + * When it's not SOURCE_MOUSE, CursorInputMapper doesn't populate cursor position values. + */ +TEST_F(CursorInputMapperUnitTest, ProcessPointerCapture) { + setPointerCapture(true); + std::list args; + + // Move. + args += process(EV_REL, REL_X, 10); + args += process(EV_REL, REL_Y, 20); + args += process(EV_SYN, SYN_REPORT, 0); + + ASSERT_THAT(args, + ElementsAre(VariantWith( + AllOf(WithMotionAction(ACTION_MOVE), + WithSource(AINPUT_SOURCE_MOUSE_RELATIVE), WithCoords(10.0f, 20.0f), + WithCursorPosition(INVALID_CURSOR_POSITION, + INVALID_CURSOR_POSITION))))); + + // Button press. + args.clear(); + args += process(EV_KEY, BTN_MOUSE, 1); + args += process(EV_SYN, SYN_REPORT, 0); + ASSERT_THAT(args, + ElementsAre(VariantWith( + AllOf(WithMotionAction(ACTION_DOWN), + WithSource(AINPUT_SOURCE_MOUSE_RELATIVE), + WithCoords(0.0f, 0.0f), WithPressure(1.0f))), + VariantWith( + AllOf(WithMotionAction(BUTTON_PRESS), + WithSource(AINPUT_SOURCE_MOUSE_RELATIVE), + WithCoords(0.0f, 0.0f), WithPressure(1.0f))))); + + // Button release. + args.clear(); + args += process(EV_KEY, BTN_MOUSE, 0); + args += process(EV_SYN, SYN_REPORT, 0); + ASSERT_THAT(args, + ElementsAre(VariantWith( + AllOf(WithMotionAction(BUTTON_RELEASE), + WithSource(AINPUT_SOURCE_MOUSE_RELATIVE), + WithCoords(0.0f, 0.0f), WithPressure(0.0f))), + VariantWith( + AllOf(WithMotionAction(ACTION_UP), + WithSource(AINPUT_SOURCE_MOUSE_RELATIVE), + WithCoords(0.0f, 0.0f), WithPressure(0.0f))))); + + // Another move. + args.clear(); + args += process(EV_REL, REL_X, 30); + args += process(EV_REL, REL_Y, 40); + args += process(EV_SYN, SYN_REPORT, 0); + ASSERT_THAT(args, + ElementsAre(VariantWith( + AllOf(WithMotionAction(ACTION_MOVE), + WithSource(AINPUT_SOURCE_MOUSE_RELATIVE), + WithCoords(30.0f, 40.0f))))); + + // Disable pointer capture. Afterwards, events should be generated the usual way. + setPointerCapture(false); + + args.clear(); + args += process(EV_REL, REL_X, 10); + args += process(EV_REL, REL_Y, 20); + args += process(EV_SYN, SYN_REPORT, 0); + ASSERT_THAT(args, + ElementsAre(VariantWith( + AllOf(WithMotionAction(HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE), + WithCoords(INITIAL_CURSOR_X + 10.0f, INITIAL_CURSOR_Y + 20.0f), + WithCursorPosition(INITIAL_CURSOR_X + 10.0f, + INITIAL_CURSOR_Y + 20.0f))))); +} + } // namespace android diff --git a/services/inputflinger/tests/InputMapperTest.cpp b/services/inputflinger/tests/InputMapperTest.cpp index 0eee2b9be4..dac4ea02c4 100644 --- a/services/inputflinger/tests/InputMapperTest.cpp +++ b/services/inputflinger/tests/InputMapperTest.cpp @@ -27,7 +27,7 @@ using testing::Return; void InputMapperUnitTest::SetUp() { mFakePointerController = std::make_shared(); mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1); - mFakePointerController->setPosition(400, 240); + mFakePointerController->setPosition(INITIAL_CURSOR_X, INITIAL_CURSOR_Y); EXPECT_CALL(mMockInputReaderContext, getPointerController(DEVICE_ID)) .WillRepeatedly(Return(mFakePointerController)); diff --git a/services/inputflinger/tests/InputMapperTest.h b/services/inputflinger/tests/InputMapperTest.h index 909bd9c056..c2ac258765 100644 --- a/services/inputflinger/tests/InputMapperTest.h +++ b/services/inputflinger/tests/InputMapperTest.h @@ -39,6 +39,8 @@ class InputMapperUnitTest : public testing::Test { protected: static constexpr int32_t EVENTHUB_ID = 1; static constexpr int32_t DEVICE_ID = END_RESERVED_ID + 1000; + static constexpr float INITIAL_CURSOR_X = 400; + static constexpr float INITIAL_CURSOR_Y = 240; virtual void SetUp() override; void setupAxis(int axis, bool valid, int32_t min, int32_t max, int32_t resolution); diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 6539593217..6032e3037a 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -4744,92 +4744,6 @@ TEST_F(CursorInputMapperTest, Process_WhenModeIsPointer_ShouldMoveThePointerArou ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(110.0f, 220.0f)); } -TEST_F(CursorInputMapperTest, Process_PointerCapture) { - addConfigurationProperty("cursor.mode", "pointer"); - mFakePolicy->setPointerCapture(true); - CursorInputMapper& mapper = constructAndAddMapper(); - - NotifyDeviceResetArgs resetArgs; - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); - ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); - ASSERT_EQ(DEVICE_ID, resetArgs.deviceId); - - mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1); - mFakePointerController->setPosition(100, 200); - - NotifyMotionArgs args; - - // Move. - process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10); - process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20); - process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 10.0f, 20.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(100.0f, 200.0f)); - - // Button press. - process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_MOUSE, 1); - process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source); - ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source); - ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_PRESS, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - // Button release. - process(mapper, ARBITRARY_TIME + 2, READ_TIME, EV_KEY, BTN_MOUSE, 0); - process(mapper, ARBITRARY_TIME + 2, READ_TIME, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source); - ASSERT_EQ(AMOTION_EVENT_ACTION_BUTTON_RELEASE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source); - ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - - // Another move. - process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 30); - process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 40); - process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AINPUT_SOURCE_MOUSE_RELATIVE, args.source); - ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 30.0f, 40.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(100.0f, 200.0f)); - - // Disable pointer capture and check that the device generation got bumped - // and events are generated the usual way. - const uint32_t generation = mReader->getContext()->getGeneration(); - mFakePolicy->setPointerCapture(false); - configureDevice(InputReaderConfiguration::Change::POINTER_CAPTURE); - ASSERT_TRUE(mReader->getContext()->getGeneration() != generation); - - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); - ASSERT_EQ(DEVICE_ID, resetArgs.deviceId); - - process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_X, 10); - process(mapper, ARBITRARY_TIME, READ_TIME, EV_REL, REL_Y, 20); - process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0); - ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); - ASSERT_EQ(AINPUT_SOURCE_MOUSE, args.source); - ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action); - ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], - 110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); - ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(110.0f, 220.0f)); -} - /** * When Pointer Capture is enabled, we expect to report unprocessed relative movements, so any * pointer acceleration or speed processing should not be applied. diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h index 5d50b94a62..05823cd9de 100644 --- a/services/inputflinger/tests/InterfaceMocks.h +++ b/services/inputflinger/tests/InterfaceMocks.h @@ -59,7 +59,7 @@ public: (int32_t deviceId), (override)); MOCK_METHOD(void, requestTimeoutAtTime, (nsecs_t when), (override)); - MOCK_METHOD(int32_t, bumpGeneration, (), (override)); + int32_t bumpGeneration() override { return ++mGeneration; } MOCK_METHOD(void, getExternalStylusDevices, (std::vector & outDevices), (override)); @@ -76,6 +76,9 @@ public: MOCK_METHOD(void, setPreventingTouchpadTaps, (bool prevent), (override)); MOCK_METHOD(bool, isPreventingTouchpadTaps, (), (override)); + +private: + int32_t mGeneration = 0; }; class MockEventHubInterface : public EventHubInterface { diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h index 183383f57d..31ad569c27 100644 --- a/services/inputflinger/tests/TestInputListenerMatchers.h +++ b/services/inputflinger/tests/TestInputListenerMatchers.h @@ -185,6 +185,14 @@ MATCHER_P2(WithCoords, x, y, "InputEvent with specified coords") { return argX == x && argY == y; } +MATCHER_P2(WithCursorPosition, x, y, "InputEvent with specified cursor position") { + const auto argX = arg.xCursorPosition; + const auto argY = arg.yCursorPosition; + *result_listener << "expected cursor position (" << x << ", " << y << "), but got (" << argX + << ", " << argY << ")"; + return (isnan(x) ? isnan(argX) : x == argX) && (isnan(y) ? isnan(argY) : y == argY); +} + MATCHER_P3(WithPointerCoords, pointer, x, y, "InputEvent with specified coords for pointer") { const auto argX = arg.pointerCoords[pointer].getX(); const auto argY = arg.pointerCoords[pointer].getY(); -- GitLab From b1230625406d438fa248fd7be2fcaf1684833f06 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 19 Sep 2023 09:06:56 -0700 Subject: [PATCH 0694/1187] Add flag for multi-device input For now, this flag will simply bypass the PreferStylusOverTouchBlocker. In the future, we can look into possibly turning on/off parts of the dispatcher with this flag, as well. Test: atest inputflinger_tests Bug: 211379801 Change-Id: I9ec6a42bf2cb9671cf3ca179995698dbae1dcc34 --- libs/input/input_flags.aconfig | 7 +++++++ .../inputflinger/UnwantedInteractionBlocker.cpp | 15 +++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index a0563f916d..e8575a6103 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -27,3 +27,10 @@ flag { description: "Set to true to enable timer support for the touchpad Gestures library" bug: "297192727" } + +flag { + name: "enable_multi_device_input" + namespace: "input" + description: "Set to true to enable multi-device input: touch and stylus can be active at the same time, but in different windows" + bug: "211379801" +} diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp index f889de58b8..0f6232477e 100644 --- a/services/inputflinger/UnwantedInteractionBlocker.cpp +++ b/services/inputflinger/UnwantedInteractionBlocker.cpp @@ -18,6 +18,7 @@ #include "UnwantedInteractionBlocker.h" #include +#include #include #include #include @@ -28,6 +29,8 @@ #include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter.h" #include "ui/events/ozone/evdev/touch_filter/palm_model/onedevice_train_palm_detection_filter_model.h" +namespace input_flags = com::android::input::flags; + using android::base::StringPrintf; /** @@ -344,10 +347,14 @@ void UnwantedInteractionBlocker::notifyMotion(const NotifyMotionArgs& args) { ALOGD_IF(DEBUG_INBOUND_MOTION, "%s: %s", __func__, args.dump().c_str()); { // acquire lock std::scoped_lock lock(mLock); - const std::vector processedArgs = - mPreferStylusOverTouchBlocker.processMotion(args); - for (const NotifyMotionArgs& loopArgs : processedArgs) { - notifyMotionLocked(loopArgs); + if (input_flags::enable_multi_device_input()) { + notifyMotionLocked(args); + } else { + const std::vector processedArgs = + mPreferStylusOverTouchBlocker.processMotion(args); + for (const NotifyMotionArgs& loopArgs : processedArgs) { + notifyMotionLocked(loopArgs); + } } } // release lock -- GitLab From 4e955a2d5a1b61ce501354e2b341fc58dcdba1dd Mon Sep 17 00:00:00 2001 From: Philip Quinn Date: Tue, 26 Sep 2023 12:09:40 -0700 Subject: [PATCH 0695/1187] Mark all pointers in a resampled event as resampled. Even if the coordinates for a pointer are not resampled, they will be added to an event with a timestamp that doesn't match what the device is reporting. Algorithms that care about the consistency of pointer coordinates will want to handle these events in the same manner as resampled coordinates -- otherwise it may appear as though the pointer has suddenly stopped moving. Bug: 301277887 Test: atest --host libinput_tests Change-Id: Idc833e9844856172ff749a90ee584292536524dc --- libs/input/InputTransport.cpp | 2 +- libs/input/tests/TouchResampling_test.cpp | 45 ++++++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 16000139f7..5450ad075c 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -1276,13 +1276,13 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, PointerCoords& resampledCoords = touchState.lastResample.pointers[i]; const PointerCoords& currentCoords = current->getPointerById(id); resampledCoords = currentCoords; + resampledCoords.isResampled = true; if (other->idBits.hasBit(id) && shouldResampleTool(event->getToolType(i))) { const PointerCoords& otherCoords = other->getPointerById(id); resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X, lerp(currentCoords.getX(), otherCoords.getX(), alpha)); resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, lerp(currentCoords.getY(), otherCoords.getY(), alpha)); - resampledCoords.isResampled = true; ALOGD_IF(debugResampling(), "[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f), " "other (%0.3f, %0.3f), alpha %0.3f", diff --git a/libs/input/tests/TouchResampling_test.cpp b/libs/input/tests/TouchResampling_test.cpp index 655de803ae..106d78a469 100644 --- a/libs/input/tests/TouchResampling_test.cpp +++ b/libs/input/tests/TouchResampling_test.cpp @@ -31,6 +31,7 @@ struct Pointer { int32_t id; float x; float y; + ToolType toolType = ToolType::FINGER; bool isResampled = false; }; @@ -99,7 +100,7 @@ void TouchResamplingTest::publishSimpleMotionEvent(int32_t action, nsecs_t event properties.push_back({}); properties.back().clear(); properties.back().id = pointer.id; - properties.back().toolType = ToolType::FINGER; + properties.back().toolType = pointer.toolType; coords.push_back({}); coords.back().clear(); @@ -291,6 +292,48 @@ TEST_F(TouchResamplingTest, EventIsResampledWithDifferentId) { consumeInputEventEntries(expectedEntries, frameTime); } +/** + * Stylus pointer coordinates are not resampled, but an event is still generated for the batch with + * a resampled timestamp and should be marked as such. + */ +TEST_F(TouchResamplingTest, StylusCoordinatesNotResampledFor) { + std::chrono::nanoseconds frameTime; + std::vector entries, expectedEntries; + + // Initial ACTION_DOWN should be separate, because the first consume event will only return + // InputEvent with a single action. + entries = { + // id x y + {0ms, {{0, 10, 20, .toolType = ToolType::STYLUS}}, AMOTION_EVENT_ACTION_DOWN}, + }; + publishInputEventEntries(entries); + frameTime = 5ms; + expectedEntries = { + // id x y + {0ms, {{0, 10, 20, .toolType = ToolType::STYLUS}}, AMOTION_EVENT_ACTION_DOWN}, + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y + entries = { + // id x y + {10ms, {{0, 20, 30, .toolType = ToolType::STYLUS}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30, .toolType = ToolType::STYLUS}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 35ms; + expectedEntries = { + // id x y + {10ms, {{0, 20, 30, .toolType = ToolType::STYLUS}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30, .toolType = ToolType::STYLUS}}, AMOTION_EVENT_ACTION_MOVE}, + // A resampled event is generated, but the stylus coordinates are not resampled. + {25ms, + {{0, 30, 30, .toolType = ToolType::STYLUS, .isResampled = true}}, + AMOTION_EVENT_ACTION_MOVE}, + }; + consumeInputEventEntries(expectedEntries, frameTime); +} + /** * Event should not be resampled when sample time is equal to event time. */ -- GitLab From c00f5e92cb9aa89044ef03b7444f83be286cde44 Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Tue, 19 Sep 2023 13:11:05 +0000 Subject: [PATCH 0696/1187] Keep mouse pointer hidden while typing An optimisation causes mouse pointer to remain visible while user is typing. As Mouse pointer may reappear while user is typing and may not hide again if IME connection remains active and touchpad is used. This leads to an incosistent state where toucpad-pad is disabled but cursor is visible while user is actively typing on PK. Bug: 301055381 Test: atest KeyboardInputMapperUnitTest Change-Id: Id37d57d924e4f1f1b8875b078c48762a5d523acc --- .../inputflinger/reader/mapper/KeyboardInputMapper.cpp | 3 ++- services/inputflinger/tests/KeyboardInputMapper_test.cpp | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp index 58b29b82f9..531fc6766d 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp @@ -451,7 +451,8 @@ std::list KeyboardInputMapper::cancelAllDownKeys(nsecs_t when) { void KeyboardInputMapper::onKeyDownProcessed() { InputReaderContext& context = *getContext(); if (context.isPreventingTouchpadTaps()) { - // avoid pinging java service unnecessarily + // avoid pinging java service unnecessarily, just fade pointer again if it became visible + context.fadePointer(); return; } // Ignore meta keys or multiple simultaneous down keys as they are likely to be keyboard diff --git a/services/inputflinger/tests/KeyboardInputMapper_test.cpp b/services/inputflinger/tests/KeyboardInputMapper_test.cpp index 08a5559de4..48f5673c51 100644 --- a/services/inputflinger/tests/KeyboardInputMapper_test.cpp +++ b/services/inputflinger/tests/KeyboardInputMapper_test.cpp @@ -111,6 +111,15 @@ TEST_F(KeyboardInputMapperUnitTest, AlphanumericKeystrokesWithIMeConnectionHideP testPointerVisibilityForKeys({KEY_0, KEY_A}, /* expectVisible= */ false); } +/** + * Pointer should still hide if touchpad taps are already disabled + */ +TEST_F(KeyboardInputMapperUnitTest, AlphanumericKeystrokesWithTouchpadTapDisabledHidePointer) { + mFakePolicy->setIsInputMethodConnectionActive(true); + EXPECT_CALL(mMockInputReaderContext, isPreventingTouchpadTaps).WillRepeatedly(Return(true)); + testPointerVisibilityForKeys({KEY_0, KEY_A}, /* expectVisible= */ false); +} + /** * Pointer visibility should remain unaffected by meta keys even if Input Method Connection is * active -- GitLab From 66ed1c48f6a9a152576edb98472bfe1cae1324df Mon Sep 17 00:00:00 2001 From: Dorin Drimus Date: Wed, 27 Sep 2023 13:10:16 +0000 Subject: [PATCH 0697/1187] Properly release the sideband stream when setting a buffer Bug: 301910615 Change-Id: I0dfdb5bb6816be5227a7d6b720654bd722438ffd Test: Netflix playback changing streams --- services/surfaceflinger/Layer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index a73c5115b1..5890050caa 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -3183,8 +3183,7 @@ bool Layer::setBuffer(std::shared_ptr& buffer, } else { // release sideband stream if it exists and a non null buffer is being set if (mDrawingState.sidebandStream != nullptr) { - mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount(); - mDrawingState.sidebandStream = nullptr; + setSidebandStream(nullptr, info, postTime); } } -- GitLab From 2d151ac3e2f6280f541fd75a9578ee1ab13ea405 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 19 Sep 2023 13:30:24 -0700 Subject: [PATCH 0698/1187] InputVerifier: only check pointer sources Check for the source inside InputVerifier. Sources like MOUSE_RELATIVE could send ACTION_MOVE events without a prior DOWN event. Verifying such streams is tricky, so let's simply skip such events for now. Also in this CL, add some verifications to the number of pointers inside the event. Bug: 211379801 Test: enable event verification and run native tests Test: atest inputflinger_tests libinput_tests Change-Id: I3703ba57af7ede77712b91b7429ac46c0624a616 --- include/input/InputVerifier.h | 2 +- libs/input/Android.bp | 22 ++++++ libs/input/InputTransport.cpp | 4 +- libs/input/InputVerifier.cpp | 6 +- libs/input/rust/input.rs | 56 ++++++++++++++ libs/input/rust/input_verifier.rs | 76 +++++++++++++++++-- libs/input/rust/lib.rs | 5 +- .../dispatcher/InputDispatcher.cpp | 6 +- 8 files changed, 161 insertions(+), 16 deletions(-) diff --git a/include/input/InputVerifier.h b/include/input/InputVerifier.h index b8574829f3..14dd463425 100644 --- a/include/input/InputVerifier.h +++ b/include/input/InputVerifier.h @@ -46,7 +46,7 @@ class InputVerifier { public: InputVerifier(const std::string& name); - android::base::Result processMovement(int32_t deviceId, int32_t action, + android::base::Result processMovement(int32_t deviceId, int32_t source, int32_t action, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, int32_t flags); diff --git a/libs/input/Android.bp b/libs/input/Android.bp index 36a01d37a5..ab4af1a7b6 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -90,6 +90,28 @@ rust_bindgen { "--allowlist-var=AMOTION_EVENT_ACTION_DOWN", "--allowlist-var=AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT", "--allowlist-var=MAX_POINTER_ID", + "--allowlist-var=AINPUT_SOURCE_CLASS_NONE", + "--allowlist-var=AINPUT_SOURCE_CLASS_BUTTON", + "--allowlist-var=AINPUT_SOURCE_CLASS_POINTER", + "--allowlist-var=AINPUT_SOURCE_CLASS_NAVIGATION", + "--allowlist-var=AINPUT_SOURCE_CLASS_POSITION", + "--allowlist-var=AINPUT_SOURCE_CLASS_JOYSTICK", + "--allowlist-var=AINPUT_SOURCE_UNKNOWN", + "--allowlist-var=AINPUT_SOURCE_KEYBOARD", + "--allowlist-var=AINPUT_SOURCE_DPAD", + "--allowlist-var=AINPUT_SOURCE_GAMEPAD", + "--allowlist-var=AINPUT_SOURCE_TOUCHSCREEN", + "--allowlist-var=AINPUT_SOURCE_MOUSE", + "--allowlist-var=AINPUT_SOURCE_STYLUS", + "--allowlist-var=AINPUT_SOURCE_BLUETOOTH_STYLUS", + "--allowlist-var=AINPUT_SOURCE_TRACKBALL", + "--allowlist-var=AINPUT_SOURCE_MOUSE_RELATIVE", + "--allowlist-var=AINPUT_SOURCE_TOUCHPAD", + "--allowlist-var=AINPUT_SOURCE_TOUCH_NAVIGATION", + "--allowlist-var=AINPUT_SOURCE_JOYSTICK", + "--allowlist-var=AINPUT_SOURCE_HDMI", + "--allowlist-var=AINPUT_SOURCE_SENSOR", + "--allowlist-var=AINPUT_SOURCE_ROTARY_ENCODER", ], static_libs: [ diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 16000139f7..b5a823d76a 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -632,8 +632,8 @@ status_t InputPublisher::publishMotionEvent( MotionEvent::actionToString(action).c_str())); if (verifyEvents()) { Result result = - mInputVerifier.processMovement(deviceId, action, pointerCount, pointerProperties, - pointerCoords, flags); + mInputVerifier.processMovement(deviceId, source, action, pointerCount, + pointerProperties, pointerCoords, flags); if (!result.ok()) { LOG(FATAL) << "Bad stream: " << result.error(); } diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp index 6c602e031d..cec244539e 100644 --- a/libs/input/InputVerifier.cpp +++ b/libs/input/InputVerifier.cpp @@ -33,7 +33,7 @@ namespace android { InputVerifier::InputVerifier(const std::string& name) : mVerifier(android::input::verifier::create(rust::String::lossy(name))){}; -Result InputVerifier::processMovement(DeviceId deviceId, int32_t action, +Result InputVerifier::processMovement(DeviceId deviceId, int32_t source, int32_t action, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, int32_t flags) { @@ -43,8 +43,8 @@ Result InputVerifier::processMovement(DeviceId deviceId, int32_t action, } rust::Slice properties{rpp.data(), rpp.size()}; rust::String errorMessage = - android::input::verifier::process_movement(*mVerifier, deviceId, action, properties, - static_cast(flags)); + android::input::verifier::process_movement(*mVerifier, deviceId, source, action, + properties, static_cast(flags)); if (errorMessage.empty()) { return {}; } else { diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs index 9d3b38693a..9725b00212 100644 --- a/libs/input/rust/input.rs +++ b/libs/input/rust/input.rs @@ -23,6 +23,54 @@ use std::fmt; #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct DeviceId(pub i32); +#[repr(u32)] +pub enum SourceClass { + None = input_bindgen::AINPUT_SOURCE_CLASS_NONE, + Button = input_bindgen::AINPUT_SOURCE_CLASS_BUTTON, + Pointer = input_bindgen::AINPUT_SOURCE_CLASS_POINTER, + Navigation = input_bindgen::AINPUT_SOURCE_CLASS_NAVIGATION, + Position = input_bindgen::AINPUT_SOURCE_CLASS_POSITION, + Joystick = input_bindgen::AINPUT_SOURCE_CLASS_JOYSTICK, +} + +bitflags! { + /// Source of the input device or input events. + pub struct Source: u32 { + /// SOURCE_UNKNOWN + const Unknown = input_bindgen::AINPUT_SOURCE_UNKNOWN; + /// SOURCE_KEYBOARD + const Keyboard = input_bindgen::AINPUT_SOURCE_KEYBOARD; + /// SOURCE_DPAD + const Dpad = input_bindgen::AINPUT_SOURCE_DPAD; + /// SOURCE_GAMEPAD + const Gamepad = input_bindgen::AINPUT_SOURCE_GAMEPAD; + /// SOURCE_TOUCHSCREEN + const Touchscreen = input_bindgen::AINPUT_SOURCE_TOUCHSCREEN; + /// SOURCE_MOUSE + const Mouse = input_bindgen::AINPUT_SOURCE_MOUSE; + /// SOURCE_STYLUS + const Stylus = input_bindgen::AINPUT_SOURCE_STYLUS; + /// SOURCE_BLUETOOTH_STYLUS + const BluetoothStylus = input_bindgen::AINPUT_SOURCE_BLUETOOTH_STYLUS; + /// SOURCE_TRACKBALL + const Trackball = input_bindgen::AINPUT_SOURCE_TRACKBALL; + /// SOURCE_MOUSE_RELATIVE + const MouseRelative = input_bindgen::AINPUT_SOURCE_MOUSE_RELATIVE; + /// SOURCE_TOUCHPAD + const Touchpad = input_bindgen::AINPUT_SOURCE_TOUCHPAD; + /// SOURCE_TOUCH_NAVIGATION + const TouchNavigation = input_bindgen::AINPUT_SOURCE_TOUCH_NAVIGATION; + /// SOURCE_JOYSTICK + const Joystick = input_bindgen::AINPUT_SOURCE_JOYSTICK; + /// SOURCE_HDMI + const HDMI = input_bindgen::AINPUT_SOURCE_HDMI; + /// SOURCE_SENSOR + const Sensor = input_bindgen::AINPUT_SOURCE_SENSOR; + /// SOURCE_ROTARY_ENCODER + const RotaryEncoder = input_bindgen::AINPUT_SOURCE_ROTARY_ENCODER; + } +} + /// A rust enum representation of a MotionEvent action. #[repr(u32)] pub enum MotionAction { @@ -134,3 +182,11 @@ bitflags! { const NO_FOCUS_CHANGE = input_bindgen::AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE; } } + +impl Source { + /// Return true if this source is from the provided class + pub fn is_from_class(&self, source_class: SourceClass) -> bool { + let class_bits = source_class as u32; + self.bits() & class_bits == class_bits + } +} diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs index 64c0466687..2d94e70309 100644 --- a/libs/input/rust/input_verifier.rs +++ b/libs/input/rust/input_verifier.rs @@ -17,7 +17,7 @@ //! Contains the InputVerifier, used to validate a stream of input events. use crate::ffi::RustPointerProperties; -use crate::input::{DeviceId, MotionAction, MotionFlags}; +use crate::input::{DeviceId, MotionAction, MotionFlags, Source, SourceClass}; use log::info; use std::collections::HashMap; use std::collections::HashSet; @@ -51,10 +51,15 @@ impl InputVerifier { pub fn process_movement( &mut self, device_id: DeviceId, + source: Source, action: u32, pointer_properties: &[RustPointerProperties], flags: MotionFlags, ) -> Result<(), String> { + if !source.is_from_class(SourceClass::Pointer) { + // Skip non-pointer sources like MOUSE_RELATIVE for now + return Ok(()); + } if self.should_log { info!( "Processing {} for device {:?} ({} pointer{}) on {}", @@ -68,6 +73,13 @@ impl InputVerifier { match action.into() { MotionAction::Down => { + if pointer_properties.len() != 1 { + return Err(format!( + "{}: Invalid DOWN event: there are {} pointers in the event", + self.name, + pointer_properties.len() + )); + } let it = self .touching_pointer_ids_by_device .entry(device_id) @@ -90,10 +102,19 @@ impl InputVerifier { )); } let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap(); + if it.len() != pointer_properties.len() - 1 { + return Err(format!( + "{}: There are currently {} touching pointers, but the incoming \ + POINTER_DOWN event has {}", + self.name, + it.len(), + pointer_properties.len() + )); + } let pointer_id = pointer_properties[action_index].id; if it.contains(&pointer_id) { return Err(format!( - "{}: Pointer with id={} not found in the properties", + "{}: Pointer with id={} already present found in the properties", self.name, pointer_id )); } @@ -108,11 +129,10 @@ impl InputVerifier { } } MotionAction::PointerUp { action_index } => { - if !self.touching_pointer_ids_by_device.contains_key(&device_id) { + if !self.ensure_touching_pointers_match(device_id, pointer_properties) { return Err(format!( - "{}: Received POINTER_UP but no pointers are currently down for device \ - {:?}", - self.name, device_id + "{}: ACTION_POINTER_UP touching pointers don't match", + self.name )); } let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap(); @@ -120,6 +140,13 @@ impl InputVerifier { it.remove(&pointer_id); } MotionAction::Up => { + if pointer_properties.len() != 1 { + return Err(format!( + "{}: Invalid UP event: there are {} pointers in the event", + self.name, + pointer_properties.len() + )); + } if !self.touching_pointer_ids_by_device.contains_key(&device_id) { return Err(format!( "{} Received ACTION_UP but no pointers are currently down for device {:?}", @@ -246,6 +273,7 @@ mod tests { use crate::DeviceId; use crate::MotionFlags; use crate::RustPointerProperties; + use crate::Source; #[test] fn single_pointer_stream() { let mut verifier = InputVerifier::new("Test", /*should_log*/ false); @@ -253,6 +281,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, &pointer_properties, MotionFlags::empty(), @@ -261,6 +290,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_MOVE, &pointer_properties, MotionFlags::empty(), @@ -269,6 +299,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_UP, &pointer_properties, MotionFlags::empty(), @@ -283,6 +314,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, &pointer_properties, MotionFlags::empty(), @@ -291,6 +323,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_MOVE, &pointer_properties, MotionFlags::empty(), @@ -299,6 +332,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(2), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, &pointer_properties, MotionFlags::empty(), @@ -307,6 +341,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(2), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_MOVE, &pointer_properties, MotionFlags::empty(), @@ -315,6 +350,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_UP, &pointer_properties, MotionFlags::empty(), @@ -329,6 +365,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, &pointer_properties, MotionFlags::empty(), @@ -337,6 +374,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_CANCEL, &pointer_properties, MotionFlags::CANCELED, @@ -351,6 +389,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_DOWN, &pointer_properties, MotionFlags::empty(), @@ -359,6 +398,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_CANCEL, &pointer_properties, MotionFlags::empty(), // forgot to set FLAG_CANCELED @@ -373,6 +413,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_UP, &pointer_properties, MotionFlags::empty(), @@ -387,6 +428,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, &pointer_properties, MotionFlags::empty(), @@ -396,6 +438,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE, &pointer_properties, MotionFlags::empty(), @@ -405,6 +448,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT, &pointer_properties, MotionFlags::empty(), @@ -414,6 +458,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, &pointer_properties, MotionFlags::empty(), @@ -428,6 +473,7 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, &pointer_properties, MotionFlags::empty(), @@ -437,10 +483,28 @@ mod tests { assert!(verifier .process_movement( DeviceId(1), + Source::Touchscreen, input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, &pointer_properties, MotionFlags::empty(), ) .is_err()); } + + // Send a MOVE without a preceding DOWN event. This is OK because it's from source + // MOUSE_RELATIVE, which is used during pointer capture. The verifier should allow such event. + #[test] + fn relative_mouse_move() { + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(2), + Source::MouseRelative, + input_bindgen::AMOTION_EVENT_ACTION_MOVE, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + } } diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs index 1d3c434f76..01d959942c 100644 --- a/libs/input/rust/lib.rs +++ b/libs/input/rust/lib.rs @@ -19,7 +19,7 @@ mod input; mod input_verifier; -pub use input::{DeviceId, MotionAction, MotionFlags}; +pub use input::{DeviceId, MotionAction, MotionFlags, Source}; pub use input_verifier::InputVerifier; #[cxx::bridge(namespace = "android::input")] @@ -51,6 +51,7 @@ mod ffi { fn process_movement( verifier: &mut InputVerifier, device_id: i32, + source: u32, action: u32, pointer_properties: &[RustPointerProperties], flags: u32, @@ -73,12 +74,14 @@ fn create(name: String) -> Box { fn process_movement( verifier: &mut InputVerifier, device_id: i32, + source: u32, action: u32, pointer_properties: &[RustPointerProperties], flags: u32, ) -> String { let result = verifier.process_movement( DeviceId(device_id), + Source::from_bits(source).unwrap(), action, pointer_properties, MotionFlags::from_bits(flags).unwrap(), diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 9cd1e0903d..4657c011f6 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4324,9 +4324,9 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) { mVerifiersByDisplay.try_emplace(args.displayId, StringPrintf("display %" PRId32, args.displayId)); Result result = - it->second.processMovement(args.deviceId, args.action, args.getPointerCount(), - args.pointerProperties.data(), args.pointerCoords.data(), - args.flags); + it->second.processMovement(args.deviceId, args.source, args.action, + args.getPointerCount(), args.pointerProperties.data(), + args.pointerCoords.data(), args.flags); if (!result.ok()) { LOG(FATAL) << "Bad stream: " << result.error() << " caused by " << args.dump(); } -- GitLab From 70f3d8c37d2a0eab012f4787527253c5f5d3b546 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 19 Sep 2023 15:36:52 -0700 Subject: [PATCH 0699/1187] Specify pointer id when creating outside targets For outside targets that are owned by the same uid, we don't obscure the coordinates. As part of the effort to always have the correct pointer id specified, add the pointer id to the outside window targets. In future CLs, we will introduce a strict requirement to have correct pointers when adding pointer-based targets. Bug: 211379801 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: Ibeb80bc7545344fde63a8b4e8ddae4c0d20cb465 --- .../inputflinger/dispatcher/InputDispatcher.cpp | 16 ++++++++-------- .../inputflinger/dispatcher/InputDispatcher.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 9cd1e0903d..6f940e5a8e 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -1293,7 +1293,7 @@ sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayI } std::vector InputDispatcher::findOutsideTargetsLocked( - int32_t displayId, const sp& touchedWindow) const { + int32_t displayId, const sp& touchedWindow, int32_t pointerId) const { if (touchedWindow == nullptr) { return {}; } @@ -1309,9 +1309,10 @@ std::vector InputDispatcher::findOutsideTargetsLocked( const WindowInfo& info = *windowHandle->getInfo(); if (info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) { - addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_OUTSIDE, - /*pointerIds=*/{}, /*firstDownTimeInTarget=*/std::nullopt, - outsideTargets); + std::bitset pointerIds; + pointerIds.set(pointerId); + addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_OUTSIDE, pointerIds, + /*firstDownTimeInTarget=*/std::nullopt, outsideTargets); } } return outsideTargets; @@ -2333,6 +2334,7 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ const auto [x, y] = resolveTouchedPosition(entry); const int32_t pointerIndex = MotionEvent::getActionIndex(action); + const int32_t pointerId = entry.pointerProperties[pointerIndex].id; // Outside targets should be added upon first dispatched DOWN event. That means, this should // be a pointer that would generate ACTION_DOWN, *and* touch should not already be down. const bool isStylus = isPointerFromStylus(entry, pointerIndex); @@ -2340,7 +2342,7 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( findTouchedWindowAtLocked(displayId, x, y, isStylus); if (isDown) { - targets += findOutsideTargetsLocked(displayId, newTouchedWindowHandle); + targets += findOutsideTargetsLocked(displayId, newTouchedWindowHandle, pointerId); } // Handle the case where we did not find a window. if (newTouchedWindowHandle == nullptr) { @@ -2398,7 +2400,6 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { - const int32_t pointerId = entry.pointerProperties[0].id; // The "windowHandle" is the target of this hovering pointer. tempTouchState.addHoveringPointerToWindow(windowHandle, entry.deviceId, pointerId); } @@ -2423,7 +2424,7 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( // Update the temporary touch state. std::bitset pointerIds; if (!isHoverAction) { - pointerIds.set(entry.pointerProperties[pointerIndex].id); + pointerIds.set(pointerId); } const bool isDownOrPointerDown = maskedAction == AMOTION_EVENT_ACTION_DOWN || @@ -2467,7 +2468,6 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( // If a window is already pilfering some pointers, give it this new pointer as well and // make it pilfering. This will prevent other non-spy windows from getting this pointer, // which is a specific behaviour that we want. - const int32_t pointerId = entry.pointerProperties[pointerIndex].id; for (TouchedWindow& touchedWindow : tempTouchState.windows) { if (touchedWindow.hasTouchingPointer(entry.deviceId, pointerId) && touchedWindow.hasPilferingPointers(entry.deviceId)) { diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 4d145c68f6..67705b9392 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -242,8 +242,8 @@ private: int32_t displayId, float x, float y, bool isStylus = false, bool ignoreDragWindow = false) const REQUIRES(mLock); std::vector findOutsideTargetsLocked( - int32_t displayId, const sp& touchedWindow) const - REQUIRES(mLock); + int32_t displayId, const sp& touchedWindow, + int32_t pointerId) const REQUIRES(mLock); std::vector> findTouchedSpyWindowsAtLocked( int32_t displayId, float x, float y, bool isStylus) const REQUIRES(mLock); -- GitLab From d19875ff379935a2ac1f93c2b2e0ce675195f257 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Wed, 27 Sep 2023 15:02:47 +0000 Subject: [PATCH 0700/1187] [native] Use newer GrDirectContexts::MakeGL This was added in https://skia-review.googlesource.com/c/skia/+/760017 and the old versions were deprecated. Change-Id: I41ec95164e623e53451bcf050c55a136a2630ee8 Bug: b/293490566 --- libs/renderengine/skia/SkiaGLRenderEngine.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index cc1d12bc5c..2053c6a34f 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -299,10 +300,10 @@ SkiaRenderEngine::Contexts SkiaGLRenderEngine::createDirectContexts( LOG_ALWAYS_FATAL_IF(!glInterface.get(), "GrGLMakeNativeInterface() failed"); SkiaRenderEngine::Contexts contexts; - contexts.first = GrDirectContext::MakeGL(glInterface, options); + contexts.first = GrDirectContexts::MakeGL(glInterface, options); if (supportsProtectedContentImpl()) { useProtectedContextImpl(GrProtected::kYes); - contexts.second = GrDirectContext::MakeGL(glInterface, options); + contexts.second = GrDirectContexts::MakeGL(glInterface, options); useProtectedContextImpl(GrProtected::kNo); } -- GitLab From 6252af728d99cb2cb9f83fc15f2144b09b38e90f Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 20 Sep 2023 09:00:38 -0700 Subject: [PATCH 0701/1187] Provide a consistent motion event stream in libinput_tests When the InputVerifier is enabled, some of the input tests fail because they provide an inconsistent motion event stream to the InputPublisher. In this CL, those are fixed. This should help us enable event verification in the future. There are still some failures remaining due to zero pointer tests that will be addressed separately. Bug: 211379801 Bug: 271455682 Test: enable InputVerifier in the code Test: TEST=libinput_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: If19ea9bc50d2191ba2bdce3aad35390889db7f95 --- .../tests/InputPublisherAndConsumer_test.cpp | 187 +++++++++++++----- libs/input/tests/TouchResampling_test.cpp | 8 +- 2 files changed, 144 insertions(+), 51 deletions(-) diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 3ecf8eed50..06b841be0d 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -25,7 +25,22 @@ using android::base::Result; namespace android { -constexpr static float EPSILON = MotionEvent::ROUNDING_PRECISION; +namespace { + +static constexpr float EPSILON = MotionEvent::ROUNDING_PRECISION; +static constexpr int32_t POINTER_1_DOWN = + AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); +static constexpr int32_t POINTER_2_DOWN = + AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + +struct Pointer { + int32_t id; + float x; + float y; + bool isResampled = false; +}; + +} // namespace class InputPublisherAndConsumerTest : public testing::Test { protected: @@ -46,12 +61,28 @@ protected: mConsumer = std::make_unique(mClientChannel); } - void PublishAndConsumeKeyEvent(); - void PublishAndConsumeMotionEvent(); - void PublishAndConsumeFocusEvent(); - void PublishAndConsumeCaptureEvent(); - void PublishAndConsumeDragEvent(); - void PublishAndConsumeTouchModeEvent(); + void publishAndConsumeKeyEvent(); + void publishAndConsumeMotionStream(); + void publishAndConsumeFocusEvent(); + void publishAndConsumeCaptureEvent(); + void publishAndConsumeDragEvent(); + void publishAndConsumeTouchModeEvent(); + void publishAndConsumeMotionEvent(int32_t action, nsecs_t downTime, + const std::vector& pointers); + +private: + // The sequence number to use when publishing the next event + uint32_t mSeq = 1; + + void publishAndConsumeMotionEvent( + int32_t deviceId, uint32_t source, int32_t displayId, std::array hmac, + int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, + int32_t metaState, int32_t buttonState, MotionClassification classification, + float xScale, float yScale, float xOffset, float yOffset, float xPrecision, + float yPrecision, float xCursorPosition, float yCursorPosition, float rawXScale, + float rawYScale, float rawXOffset, float rawYOffset, nsecs_t downTime, + nsecs_t eventTime, const std::vector& pointerProperties, + const std::vector& pointerCoords); }; TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) { @@ -63,10 +94,10 @@ TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) { mConsumer->getChannel()->getConnectionToken()); } -void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { +void InputPublisherAndConsumerTest::publishAndConsumeKeyEvent() { status_t status; - constexpr uint32_t seq = 15; + const uint32_t seq = mSeq++; int32_t eventId = InputEvent::nextId(); constexpr int32_t deviceId = 1; constexpr uint32_t source = AINPUT_SOURCE_KEYBOARD; @@ -132,20 +163,43 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() { << "finished signal's consume time should be greater than publish time"; } -void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { - status_t status; +void InputPublisherAndConsumerTest::publishAndConsumeMotionStream() { + const nsecs_t downTime = systemTime(SYSTEM_TIME_MONOTONIC); - constexpr uint32_t seq = 15; - int32_t eventId = InputEvent::nextId(); + publishAndConsumeMotionEvent(AMOTION_EVENT_ACTION_DOWN, downTime, + {Pointer{.id = 0, .x = 20, .y = 30}}); + + publishAndConsumeMotionEvent(POINTER_1_DOWN, downTime, + {Pointer{.id = 0, .x = 20, .y = 30}, + Pointer{.id = 1, .x = 200, .y = 300}}); + + publishAndConsumeMotionEvent(POINTER_2_DOWN, downTime, + {Pointer{.id = 0, .x = 20, .y = 30}, + Pointer{.id = 1, .x = 200, .y = 300}, + Pointer{.id = 2, .x = 300, .y = 400}}); + + // Provide a consistent input stream - cancel the gesture that was started above + publishAndConsumeMotionEvent(AMOTION_EVENT_ACTION_CANCEL, downTime, + {Pointer{.id = 0, .x = 20, .y = 30}, + Pointer{.id = 1, .x = 200, .y = 300}, + Pointer{.id = 2, .x = 300, .y = 400}}); +} + +void InputPublisherAndConsumerTest::publishAndConsumeMotionEvent( + int32_t action, nsecs_t downTime, const std::vector& pointers) { constexpr int32_t deviceId = 1; constexpr uint32_t source = AINPUT_SOURCE_TOUCHSCREEN; constexpr int32_t displayId = ADISPLAY_ID_DEFAULT; constexpr std::array hmac = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; - constexpr int32_t action = AMOTION_EVENT_ACTION_MOVE; constexpr int32_t actionButton = 0; - constexpr int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; + int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; + + if (action == AMOTION_EVENT_ACTION_CANCEL) { + flags |= AMOTION_EVENT_FLAG_CANCELED; + } + const size_t pointerCount = pointers.size(); constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP; constexpr int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON; constexpr int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY; @@ -162,20 +216,21 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { constexpr float yPrecision = 0.5; constexpr float xCursorPosition = 1.3; constexpr float yCursorPosition = 50.6; - constexpr nsecs_t downTime = 3; - constexpr size_t pointerCount = 3; - constexpr nsecs_t eventTime = 4; - const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC); - PointerProperties pointerProperties[pointerCount]; - PointerCoords pointerCoords[pointerCount]; + + const nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC); + std::vector pointerProperties; + std::vector pointerCoords; for (size_t i = 0; i < pointerCount; i++) { + pointerProperties.push_back({}); pointerProperties[i].clear(); - pointerProperties[i].id = (i + 2) % pointerCount; + pointerProperties[i].id = pointers[i].id; pointerProperties[i].toolType = ToolType::FINGER; + pointerCoords.push_back({}); pointerCoords[i].clear(); - pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i); - pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i); + pointerCoords[i].isResampled = pointers[i].isResampled; + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, pointers[i].x); + pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, pointers[i].y); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i); pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i); @@ -185,18 +240,40 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i); } + publishAndConsumeMotionEvent(deviceId, source, displayId, hmac, action, actionButton, flags, + edgeFlags, metaState, buttonState, classification, xScale, yScale, + xOffset, yOffset, xPrecision, yPrecision, xCursorPosition, + yCursorPosition, rawXScale, rawYScale, rawXOffset, rawYOffset, + downTime, eventTime, pointerProperties, pointerCoords); +} + +void InputPublisherAndConsumerTest::publishAndConsumeMotionEvent( + int32_t deviceId, uint32_t source, int32_t displayId, std::array hmac, + int32_t action, int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState, + int32_t buttonState, MotionClassification classification, float xScale, float yScale, + float xOffset, float yOffset, float xPrecision, float yPrecision, float xCursorPosition, + float yCursorPosition, float rawXScale, float rawYScale, float rawXOffset, float rawYOffset, + nsecs_t downTime, nsecs_t eventTime, + const std::vector& pointerProperties, + const std::vector& pointerCoords) { + const uint32_t seq = mSeq++; + const int32_t eventId = InputEvent::nextId(); ui::Transform transform; transform.set({xScale, 0, xOffset, 0, yScale, yOffset, 0, 0, 1}); ui::Transform rawTransform; rawTransform.set({rawXScale, 0, rawXOffset, 0, rawYScale, rawYOffset, 0, 0, 1}); + + status_t status; + ASSERT_EQ(pointerProperties.size(), pointerCoords.size()); + const size_t pointerCount = pointerProperties.size(); + const nsecs_t publishTime = systemTime(SYSTEM_TIME_MONOTONIC); status = mPublisher->publishMotionEvent(seq, eventId, deviceId, source, displayId, hmac, action, actionButton, flags, edgeFlags, metaState, buttonState, classification, transform, xPrecision, yPrecision, xCursorPosition, yCursorPosition, rawTransform, - downTime, eventTime, pointerCount, pointerProperties, - pointerCoords); - ASSERT_EQ(OK, status) - << "publisher publishMotionEvent should return OK"; + downTime, eventTime, pointerCount, + pointerProperties.data(), pointerCoords.data()); + ASSERT_EQ(OK, status) << "publisher publishMotionEvent should return OK"; uint32_t consumeSeq; InputEvent* event; @@ -280,7 +357,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() { << "finished signal's consume time should be greater than publish time"; } -void InputPublisherAndConsumerTest::PublishAndConsumeFocusEvent() { +void InputPublisherAndConsumerTest::publishAndConsumeFocusEvent() { status_t status; constexpr uint32_t seq = 15; @@ -321,7 +398,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeFocusEvent() { << "finished signal's consume time should be greater than publish time"; } -void InputPublisherAndConsumerTest::PublishAndConsumeCaptureEvent() { +void InputPublisherAndConsumerTest::publishAndConsumeCaptureEvent() { status_t status; constexpr uint32_t seq = 42; @@ -361,7 +438,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeCaptureEvent() { << "finished signal's consume time should be greater than publish time"; } -void InputPublisherAndConsumerTest::PublishAndConsumeDragEvent() { +void InputPublisherAndConsumerTest::publishAndConsumeDragEvent() { status_t status; constexpr uint32_t seq = 15; @@ -405,7 +482,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeDragEvent() { << "finished signal's consume time should be greater than publish time"; } -void InputPublisherAndConsumerTest::PublishAndConsumeTouchModeEvent() { +void InputPublisherAndConsumerTest::publishAndConsumeTouchModeEvent() { status_t status; constexpr uint32_t seq = 15; @@ -462,27 +539,27 @@ TEST_F(InputPublisherAndConsumerTest, SendTimeline) { } TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) { - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent()); + ASSERT_NO_FATAL_FAILURE(publishAndConsumeKeyEvent()); } TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) { - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); + ASSERT_NO_FATAL_FAILURE(publishAndConsumeMotionStream()); } TEST_F(InputPublisherAndConsumerTest, PublishFocusEvent_EndToEnd) { - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeFocusEvent()); + ASSERT_NO_FATAL_FAILURE(publishAndConsumeFocusEvent()); } TEST_F(InputPublisherAndConsumerTest, PublishCaptureEvent_EndToEnd) { - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeCaptureEvent()); + ASSERT_NO_FATAL_FAILURE(publishAndConsumeCaptureEvent()); } TEST_F(InputPublisherAndConsumerTest, PublishDragEvent_EndToEnd) { - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeDragEvent()); + ASSERT_NO_FATAL_FAILURE(publishAndConsumeDragEvent()); } TEST_F(InputPublisherAndConsumerTest, PublishTouchModeEvent_EndToEnd) { - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeTouchModeEvent()); + ASSERT_NO_FATAL_FAILURE(publishAndConsumeTouchModeEvent()); } TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenSequenceNumberIsZero_ReturnsError) { @@ -546,17 +623,29 @@ TEST_F(InputPublisherAndConsumerTest, } TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) { - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent()); - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeFocusEvent()); - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent()); - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeCaptureEvent()); - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeDragEvent()); - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent()); - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent()); - ASSERT_NO_FATAL_FAILURE(PublishAndConsumeTouchModeEvent()); + const nsecs_t downTime = systemTime(SYSTEM_TIME_MONOTONIC); + + publishAndConsumeMotionEvent(AMOTION_EVENT_ACTION_DOWN, downTime, + {Pointer{.id = 0, .x = 20, .y = 30}}); + ASSERT_NO_FATAL_FAILURE(publishAndConsumeKeyEvent()); + publishAndConsumeMotionEvent(POINTER_1_DOWN, downTime, + {Pointer{.id = 0, .x = 20, .y = 30}, + Pointer{.id = 1, .x = 200, .y = 300}}); + ASSERT_NO_FATAL_FAILURE(publishAndConsumeFocusEvent()); + publishAndConsumeMotionEvent(POINTER_2_DOWN, downTime, + {Pointer{.id = 0, .x = 20, .y = 30}, + Pointer{.id = 1, .x = 200, .y = 300}, + Pointer{.id = 2, .x = 200, .y = 300}}); + ASSERT_NO_FATAL_FAILURE(publishAndConsumeKeyEvent()); + ASSERT_NO_FATAL_FAILURE(publishAndConsumeCaptureEvent()); + ASSERT_NO_FATAL_FAILURE(publishAndConsumeDragEvent()); + // Provide a consistent input stream - cancel the gesture that was started above + publishAndConsumeMotionEvent(AMOTION_EVENT_ACTION_CANCEL, downTime, + {Pointer{.id = 0, .x = 20, .y = 30}, + Pointer{.id = 1, .x = 200, .y = 300}, + Pointer{.id = 2, .x = 200, .y = 300}}); + ASSERT_NO_FATAL_FAILURE(publishAndConsumeKeyEvent()); + ASSERT_NO_FATAL_FAILURE(publishAndConsumeTouchModeEvent()); } } // namespace android diff --git a/libs/input/tests/TouchResampling_test.cpp b/libs/input/tests/TouchResampling_test.cpp index 106d78a469..1cb7f7ba8c 100644 --- a/libs/input/tests/TouchResampling_test.cpp +++ b/libs/input/tests/TouchResampling_test.cpp @@ -27,6 +27,8 @@ using namespace std::chrono_literals; namespace android { +namespace { + struct Pointer { int32_t id; float x; @@ -41,6 +43,8 @@ struct InputEventEntry { int32_t action; }; +} // namespace + class TouchResamplingTest : public testing::Test { protected: std::unique_ptr mPublisher; @@ -587,13 +591,13 @@ TEST_F(TouchResamplingTest, TwoPointersAreResampledIndependently) { // First pointer id=0 leaves the screen entries = { // id x y - {80ms, {{1, 600, 600}}, actionPointer0Up}, + {80ms, {{0, 120, 120}, {1, 600, 600}}, actionPointer0Up}, }; publishInputEventEntries(entries); frameTime = 90ms; expectedEntries = { // id x y - {80ms, {{1, 600, 600}}, actionPointer0Up}, + {80ms, {{0, 120, 120}, {1, 600, 600}}, actionPointer0Up}, // no resampled event for ACTION_POINTER_UP }; consumeInputEventEntries(expectedEntries, frameTime); -- GitLab From 5f8117acd45348704629a8aa7bd2169a5ad6a547 Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Tue, 26 Sep 2023 20:48:59 -0600 Subject: [PATCH 0702/1187] EGL: Close Multifile Blobcache files after mapping When loading entries from disk, we don't need to keep the files open after mapping their contents. Per mmap documentation: After the mmap() call has returned, the file descriptor, fd, can be closed immediately without invalidating the mapping. https://man7.org/linux/man-pages/man2/mmap.2.html This will prevent consuming excessive file descriptors, which are a limited resource. Added new test that ensures file descriptors do not remain open. Test: libEGL_test, EGL_test, restricted_trace_perf.py Bug: b/286809755 Change-Id: I6317fdbce340a8e7cbf3020ad41386cf9915dd2d --- opengl/libs/EGL/MultifileBlobCache.cpp | 16 ++++-- opengl/libs/EGL/MultifileBlobCache_test.cpp | 54 +++++++++++++++++++++ 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/opengl/libs/EGL/MultifileBlobCache.cpp b/opengl/libs/EGL/MultifileBlobCache.cpp index 7ffdac7ea7..ed3c616b92 100644 --- a/opengl/libs/EGL/MultifileBlobCache.cpp +++ b/opengl/libs/EGL/MultifileBlobCache.cpp @@ -48,9 +48,8 @@ namespace { void freeHotCacheEntry(android::MultifileHotCache& entry) { if (entry.entryFd != -1) { // If we have an fd, then this entry was added to hot cache via INIT or GET - // We need to unmap and close the entry + // We need to unmap the entry munmap(entry.entryBuffer, entry.entrySize); - close(entry.entryFd); } else { // Otherwise, this was added to hot cache during SET, so it was never mapped // and fd was only on the deferred thread. @@ -143,6 +142,7 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s if (result != sizeof(MultifileHeader)) { ALOGE("Error reading MultifileHeader from cache entry (%s): %s", fullPath.c_str(), std::strerror(errno)); + close(fd); return; } @@ -152,6 +152,7 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s if (remove(fullPath.c_str()) != 0) { ALOGE("Error removing %s: %s", fullPath.c_str(), std::strerror(errno)); } + close(fd); continue; } @@ -161,6 +162,10 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s // Memory map the file uint8_t* mappedEntry = reinterpret_cast( mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fd, 0)); + + // We can close the file now and the mmap will remain + close(fd); + if (mappedEntry == MAP_FAILED) { ALOGE("Failed to mmap cacheEntry, error: %s", std::strerror(errno)); return; @@ -206,13 +211,11 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s if (!addToHotCache(entryHash, fd, mappedEntry, fileSize)) { ALOGE("INIT Failed to add %u to hot cache", entryHash); munmap(mappedEntry, fileSize); - close(fd); return; } } else { // If we're not keeping it in hot cache, unmap it now munmap(mappedEntry, fileSize); - close(fd); } } closedir(dir); @@ -401,9 +404,12 @@ EGLsizeiANDROID MultifileBlobCache::get(const void* key, EGLsizeiANDROID keySize // Memory map the file cacheEntry = reinterpret_cast(mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fd, 0)); + + // We can close the file now and the mmap will remain + close(fd); + if (cacheEntry == MAP_FAILED) { ALOGE("Failed to mmap cacheEntry, error: %s", std::strerror(errno)); - close(fd); return 0; } diff --git a/opengl/libs/EGL/MultifileBlobCache_test.cpp b/opengl/libs/EGL/MultifileBlobCache_test.cpp index dbee13bb2e..1639be6480 100644 --- a/opengl/libs/EGL/MultifileBlobCache_test.cpp +++ b/opengl/libs/EGL/MultifileBlobCache_test.cpp @@ -42,6 +42,8 @@ protected: virtual void TearDown() { mMBC.reset(); } + int getFileDescriptorCount(); + std::unique_ptr mTempFile; std::unique_ptr mMBC; }; @@ -216,4 +218,56 @@ TEST_F(MultifileBlobCacheTest, CacheMinKeyAndValueSizeSucceeds) { ASSERT_EQ('y', buf[0]); } +int MultifileBlobCacheTest::getFileDescriptorCount() { + DIR* directory = opendir("/proc/self/fd"); + + int fileCount = 0; + struct dirent* entry; + while ((entry = readdir(directory)) != NULL) { + fileCount++; + // printf("File: %s\n", entry->d_name); + } + + closedir(directory); + return fileCount; +} + +TEST_F(MultifileBlobCacheTest, EnsureFileDescriptorsClosed) { + // Populate the cache with a bunch of entries + size_t kLargeNumberOfEntries = 1024; + for (int i = 0; i < kLargeNumberOfEntries; i++) { + // printf("Caching: %i", i); + + // Use the index as the key and value + mMBC->set(&i, sizeof(i), &i, sizeof(i)); + + int result = 0; + ASSERT_EQ(sizeof(i), mMBC->get(&i, sizeof(i), &result, sizeof(result))); + ASSERT_EQ(i, result); + } + + // Ensure we don't have a bunch of open fds + ASSERT_LT(getFileDescriptorCount(), kLargeNumberOfEntries / 2); + + // Close the cache so everything writes out + mMBC->finish(); + mMBC.reset(); + + // Now open it again and ensure we still don't have a bunch of open fds + mMBC.reset( + new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, &mTempFile->path[0])); + + // Check after initialization + ASSERT_LT(getFileDescriptorCount(), kLargeNumberOfEntries / 2); + + for (int i = 0; i < kLargeNumberOfEntries; i++) { + int result = 0; + ASSERT_EQ(sizeof(i), mMBC->get(&i, sizeof(i), &result, sizeof(result))); + ASSERT_EQ(i, result); + } + + // And again after we've actually used it + ASSERT_LT(getFileDescriptorCount(), kLargeNumberOfEntries / 2); +} + } // namespace android -- GitLab From 432179388d29847ff7e84a0533c71d46977d7221 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 27 Sep 2023 10:27:57 -0700 Subject: [PATCH 0703/1187] Add input tests to surfaceflinger presubmit One of the input tests was breaking a test from SurfaceFlinger_test. The breakage only happened when it was executed before the SF test. This only ended up affecting input presubmit, where the tests are executed in this specific order. Meanwhile, input postsubmit and surfaceflinger presubmit / postsubmit were fine. The help catch these issues sooner in the future, add input tests to SF presubmit. Bug: 301657737 Test: (cd frameworks/native/services/surfaceflinger && atest) Test output (as of 2023-09-27): Finding Tests... Found 'libgui_test' as MODULE Found 'FrameworksCoreTests' as MODULE Found 'libnativewindow_bindgen_test' as MODULE Found 'libscheduler_test' as MODULE Found 'libcompositionengine_test' as MODULE Found 'SurfaceFlinger_test' as CACHE Found 'libnativewindow_rs-internal_test' as MODULE Found 'inputflinger_tests' as CACHE Found 'libgui_test' as MODULE Found 'FrameworksServicesTests' as MODULE Found 'CtsViewTestCases' as MODULE Found 'libsurfaceflinger_unittest' as MODULE Found 'CtsGraphicsTestCases' as MODULE Found 'FrameworksCoreTests' as MODULE Found 'CtsHardwareTestCases' as MODULE Found 'libinputservice_test' as CACHE Found 'CtsGraphicsTestCases' as MODULE Found 'CtsInputTestCases' as MODULE Found 'libinput_tests' as CACHE Found 'InputTests' as MODULE Found 'CtsSecurityBulletinHostTestCases' as MODULE Found 'CtsSecurityTestCases' as MODULE Found 'CtsWidgetTestCases' as MODULE Found 'libnativewindow_test' as MODULE Found 'libchrome-gestures_test' as MODULE Found 'CtsWindowManagerDeviceWindow' as MODULE Found 'CtsViewTestCases' as MODULE Found 'libpalmrejection_test' as MODULE Found 'CtsSurfaceControlTests' as MODULE Found 'CtsAppTestCases' as MODULE Change-Id: Ib518d77f495f3a037c0af5d28bff91fe0fde42ff --- services/surfaceflinger/TEST_MAPPING | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/surfaceflinger/TEST_MAPPING b/services/surfaceflinger/TEST_MAPPING index 55127349eb..6f53d620ba 100644 --- a/services/surfaceflinger/TEST_MAPPING +++ b/services/surfaceflinger/TEST_MAPPING @@ -2,6 +2,9 @@ "imports": [ { "path": "frameworks/native/libs/gui" + }, + { + "path": "frameworks/native/services/inputflinger" } ], "presubmit": [ -- GitLab From 8c90d78b7ce147e7a4e728e77f8700d5923ea744 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 15 Sep 2023 21:16:44 +0000 Subject: [PATCH 0704/1187] Use std::unique_ptr for DispatchEntry Bug: 210460522 Test: atest inputflinger_tests Change-Id: I2e7073493cbd31df0d7073a5f5f44fe64d7be0b3 --- .../inputflinger/dispatcher/Connection.cpp | 9 -- services/inputflinger/dispatcher/Connection.h | 6 +- services/inputflinger/dispatcher/Entry.h | 4 +- .../dispatcher/InputDispatcher.cpp | 116 +++++++++--------- .../inputflinger/dispatcher/InputDispatcher.h | 8 +- 5 files changed, 70 insertions(+), 73 deletions(-) diff --git a/services/inputflinger/dispatcher/Connection.cpp b/services/inputflinger/dispatcher/Connection.cpp index ed95de787c..f304712e8c 100644 --- a/services/inputflinger/dispatcher/Connection.cpp +++ b/services/inputflinger/dispatcher/Connection.cpp @@ -38,13 +38,4 @@ const std::string Connection::getWindowName() const { return "?"; } -std::deque::iterator Connection::findWaitQueueEntry(uint32_t seq) { - for (std::deque::iterator it = waitQueue.begin(); it != waitQueue.end(); it++) { - if ((*it)->seq == seq) { - return it; - } - } - return waitQueue.end(); -} - } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h index 2929d61871..c17baea0e5 100644 --- a/services/inputflinger/dispatcher/Connection.h +++ b/services/inputflinger/dispatcher/Connection.h @@ -53,11 +53,11 @@ public: bool responsive = true; // Queue of events that need to be published to the connection. - std::deque outboundQueue; + std::deque> outboundQueue; // Queue of events that have been published to the connection but that have not // yet received a "finished" response from the application. - std::deque waitQueue; + std::deque> waitQueue; Connection(const std::shared_ptr& inputChannel, bool monitor, const IdGenerator& idGenerator); @@ -65,8 +65,6 @@ public: inline const std::string getInputChannelName() const { return inputChannel->getName(); } const std::string getWindowName() const; - - std::deque::iterator findWaitQueueEntry(uint32_t seq); }; } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index dd4aab85f5..98e2507a94 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -226,7 +226,7 @@ struct DispatchEntry { const uint32_t seq; // unique sequence number, never 0 std::shared_ptr eventEntry; // the event to dispatch - ftl::Flags targetFlags; + const ftl::Flags targetFlags; ui::Transform transform; ui::Transform rawTransform; float globalScaleFactor; @@ -244,6 +244,8 @@ struct DispatchEntry { DispatchEntry(std::shared_ptr eventEntry, ftl::Flags targetFlags, const ui::Transform& transform, const ui::Transform& rawTransform, float globalScaleFactor); + DispatchEntry(const DispatchEntry&) = delete; + DispatchEntry& operator=(const DispatchEntry&) = delete; inline bool hasForegroundTarget() const { return targetFlags.test(InputTarget::Flags::FOREGROUND); diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 9cd1e0903d..f037b87070 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -271,7 +271,8 @@ std::string dumpRegion(const Region& region) { return dump; } -std::string dumpQueue(const std::deque& queue, nsecs_t currentTime) { +std::string dumpQueue(const std::deque>& queue, + nsecs_t currentTime) { constexpr size_t maxEntries = 50; // max events to print constexpr size_t skipBegin = maxEntries / 2; const size_t skipEnd = queue.size() - maxEntries / 2; @@ -492,8 +493,8 @@ bool shouldReportFinishedEvent(const DispatchEntry& dispatchEntry, const Connect */ bool isConnectionResponsive(const Connection& connection) { const nsecs_t currentTime = now(); - for (const DispatchEntry* entry : connection.waitQueue) { - if (entry->timeoutTime < currentTime) { + for (const auto& dispatchEntry : connection.waitQueue) { + if (dispatchEntry->timeoutTime < currentTime) { return false; } } @@ -3415,7 +3416,7 @@ void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptroutboundQueue.push_back(dispatchEntry.release()); + connection->outboundQueue.emplace_back(std::move(dispatchEntry)); traceOutboundQueueLength(*connection); } @@ -3584,7 +3585,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, } while (connection->status == Connection::Status::NORMAL && !connection->outboundQueue.empty()) { - DispatchEntry* dispatchEntry = connection->outboundQueue.front(); + std::unique_ptr& dispatchEntry = connection->outboundQueue.front(); dispatchEntry->deliveryTime = currentTime; const std::chrono::nanoseconds timeout = getDispatchingTimeoutLocked(connection); dispatchEntry->timeoutTime = currentTime + timeout.count(); @@ -3699,14 +3700,12 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, } // Re-enqueue the event on the wait queue. - connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(), - connection->outboundQueue.end(), - dispatchEntry)); + const nsecs_t timeoutTime = dispatchEntry->timeoutTime; + connection->waitQueue.emplace_back(std::move(dispatchEntry)); + connection->outboundQueue.erase(connection->outboundQueue.begin()); traceOutboundQueueLength(*connection); - connection->waitQueue.push_back(dispatchEntry); if (connection->responsive) { - mAnrTracker.insert(dispatchEntry->timeoutTime, - connection->inputChannel->getConnectionToken()); + mAnrTracker.insert(timeoutTime, connection->inputChannel->getConnectionToken()); } traceWaitQueueLength(*connection); } @@ -3805,19 +3804,17 @@ void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, } } -void InputDispatcher::drainDispatchQueue(std::deque& queue) { +void InputDispatcher::drainDispatchQueue(std::deque>& queue) { while (!queue.empty()) { - DispatchEntry* dispatchEntry = queue.front(); + releaseDispatchEntry(std::move(queue.front())); queue.pop_front(); - releaseDispatchEntry(dispatchEntry); } } -void InputDispatcher::releaseDispatchEntry(DispatchEntry* dispatchEntry) { +void InputDispatcher::releaseDispatchEntry(std::unique_ptr dispatchEntry) { if (dispatchEntry->hasForegroundTarget()) { decrementPendingForegroundDispatches(*(dispatchEntry->eventEntry)); } - delete dispatchEntry; } int InputDispatcher::handleReceiveCallback(int events, sp connectionToken) { @@ -6061,43 +6058,52 @@ void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime, uint32_t seq, bool handled, nsecs_t consumeTime) { // Handle post-event policy actions. - std::deque::iterator dispatchEntryIt = connection->findWaitQueueEntry(seq); - if (dispatchEntryIt == connection->waitQueue.end()) { - return; - } - DispatchEntry* dispatchEntry = *dispatchEntryIt; - const nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime; - if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) { - ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(), - ns2ms(eventDuration), dispatchEntry->eventEntry->getDescription().c_str()); - } - if (shouldReportFinishedEvent(*dispatchEntry, *connection)) { - mLatencyTracker.trackFinishedEvent(dispatchEntry->eventEntry->id, - connection->inputChannel->getConnectionToken(), - dispatchEntry->deliveryTime, consumeTime, finishTime); - } - bool restartEvent; - if (dispatchEntry->eventEntry->type == EventEntry::Type::KEY) { - KeyEntry& keyEntry = static_cast(*(dispatchEntry->eventEntry)); - restartEvent = - afterKeyEventLockedInterruptable(connection, dispatchEntry, keyEntry, handled); - } else if (dispatchEntry->eventEntry->type == EventEntry::Type::MOTION) { - MotionEntry& motionEntry = static_cast(*(dispatchEntry->eventEntry)); - restartEvent = afterMotionEventLockedInterruptable(connection, dispatchEntry, motionEntry, - handled); - } else { - restartEvent = false; - } + + { // Start critical section + auto dispatchEntryIt = + std::find_if(connection->waitQueue.begin(), connection->waitQueue.end(), + [seq](auto& e) { return e->seq == seq; }); + if (dispatchEntryIt == connection->waitQueue.end()) { + return; + } + + DispatchEntry& dispatchEntry = **dispatchEntryIt; + + const nsecs_t eventDuration = finishTime - dispatchEntry.deliveryTime; + if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) { + ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(), + ns2ms(eventDuration), dispatchEntry.eventEntry->getDescription().c_str()); + } + if (shouldReportFinishedEvent(dispatchEntry, *connection)) { + mLatencyTracker.trackFinishedEvent(dispatchEntry.eventEntry->id, + connection->inputChannel->getConnectionToken(), + dispatchEntry.deliveryTime, consumeTime, finishTime); + } + + if (dispatchEntry.eventEntry->type == EventEntry::Type::KEY) { + KeyEntry& keyEntry = static_cast(*(dispatchEntry.eventEntry)); + restartEvent = + afterKeyEventLockedInterruptable(connection, dispatchEntry, keyEntry, handled); + } else if (dispatchEntry.eventEntry->type == EventEntry::Type::MOTION) { + MotionEntry& motionEntry = static_cast(*(dispatchEntry.eventEntry)); + restartEvent = afterMotionEventLockedInterruptable(connection, dispatchEntry, + motionEntry, handled); + } else { + restartEvent = false; + } + } // End critical section: The -LockedInterruptable methods may have released the lock. // Dequeue the event and start the next cycle. // Because the lock might have been released, it is possible that the // contents of the wait queue to have been drained, so we need to double-check // a few things. - dispatchEntryIt = connection->findWaitQueueEntry(seq); - if (dispatchEntryIt != connection->waitQueue.end()) { - dispatchEntry = *dispatchEntryIt; - connection->waitQueue.erase(dispatchEntryIt); + auto entryIt = std::find_if(connection->waitQueue.begin(), connection->waitQueue.end(), + [seq](auto& e) { return e->seq == seq; }); + if (entryIt != connection->waitQueue.end()) { + std::unique_ptr dispatchEntry = std::move(*entryIt); + connection->waitQueue.erase(entryIt); + const sp& connectionToken = connection->inputChannel->getConnectionToken(); mAnrTracker.erase(dispatchEntry->timeoutTime, connectionToken); if (!connection->responsive) { @@ -6109,10 +6115,10 @@ void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime, } traceWaitQueueLength(*connection); if (restartEvent && connection->status == Connection::Status::NORMAL) { - connection->outboundQueue.push_front(dispatchEntry); + connection->outboundQueue.emplace_front(std::move(dispatchEntry)); traceOutboundQueueLength(*connection); } else { - releaseDispatchEntry(dispatchEntry); + releaseDispatchEntry(std::move(dispatchEntry)); } } @@ -6156,13 +6162,13 @@ void InputDispatcher::onAnrLocked(const std::shared_ptr& connection) * processes the events linearly. So providing information about the oldest entry seems to be * most useful. */ - DispatchEntry* oldestEntry = *connection->waitQueue.begin(); - const nsecs_t currentWait = now() - oldestEntry->deliveryTime; + DispatchEntry& oldestEntry = *connection->waitQueue.front(); + const nsecs_t currentWait = now() - oldestEntry.deliveryTime; std::string reason = android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s", connection->inputChannel->getName().c_str(), ns2ms(currentWait), - oldestEntry->eventEntry->getDescription().c_str()); + oldestEntry.eventEntry->getDescription().c_str()); sp connectionToken = connection->inputChannel->getConnectionToken(); updateLastAnrStateLocked(getWindowHandleLocked(connectionToken), reason); @@ -6299,7 +6305,7 @@ void InputDispatcher::processConnectionResponsiveLocked(const Connection& connec } bool InputDispatcher::afterKeyEventLockedInterruptable( - const std::shared_ptr& connection, DispatchEntry* dispatchEntry, + const std::shared_ptr& connection, DispatchEntry& dispatchEntry, KeyEntry& keyEntry, bool handled) { if (keyEntry.flags & AKEY_EVENT_FLAG_FALLBACK) { if (!handled) { @@ -6317,7 +6323,7 @@ bool InputDispatcher::afterKeyEventLockedInterruptable( connection->inputState.removeFallbackKey(originalKeyCode); } - if (handled || !dispatchEntry->hasForegroundTarget()) { + if (handled || !dispatchEntry.hasForegroundTarget()) { // If the application handles the original key for which we previously // generated a fallback or if the window is not a foreground window, // then cancel the associated fallback key, if any. @@ -6484,7 +6490,7 @@ bool InputDispatcher::afterKeyEventLockedInterruptable( } bool InputDispatcher::afterMotionEventLockedInterruptable( - const std::shared_ptr& connection, DispatchEntry* dispatchEntry, + const std::shared_ptr& connection, DispatchEntry& dispatchEntry, MotionEntry& motionEntry, bool handled) { return false; } diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 4d145c68f6..00c2acb842 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -598,8 +598,8 @@ private: void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const std::shared_ptr& connection, bool notify) REQUIRES(mLock); - void drainDispatchQueue(std::deque& queue); - void releaseDispatchEntry(DispatchEntry* dispatchEntry); + void drainDispatchQueue(std::deque>& queue); + void releaseDispatchEntry(std::unique_ptr dispatchEntry); int handleReceiveCallback(int events, sp connectionToken); // The action sent should only be of type AMOTION_EVENT_* void dispatchPointerDownOutsideFocus(uint32_t source, int32_t action, @@ -664,10 +664,10 @@ private: REQUIRES(mLock); std::map mVerifiersByDisplay; bool afterKeyEventLockedInterruptable(const std::shared_ptr& connection, - DispatchEntry* dispatchEntry, KeyEntry& keyEntry, + DispatchEntry& dispatchEntry, KeyEntry& keyEntry, bool handled) REQUIRES(mLock); bool afterMotionEventLockedInterruptable(const std::shared_ptr& connection, - DispatchEntry* dispatchEntry, MotionEntry& motionEntry, + DispatchEntry& dispatchEntry, MotionEntry& motionEntry, bool handled) REQUIRES(mLock); // Find touched state and touched window by token. -- GitLab From ed234c620bee72bf0bfc603642ea42a3004e5145 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Wed, 27 Sep 2023 16:53:40 -0500 Subject: [PATCH 0705/1187] Ack messages when WindowInfosListeners are removed This fix updates WindowInfosListenersInvoker::removeWindowInfosListener to automatically ack any unacked messages associated with the listener being removed. This fixes a race where the invoker may send the listener a message while the client is removing the listener and terminating its process. Bug: 300644295 Test: WindowInfosListenerInvokerTest Change-Id: I93a5fbecb03bb8eeea8d8385bdf906051d595ae2 --- .../WindowInfosListenerInvoker.cpp | 34 +++++++++-------- .../WindowInfosListenerInvoker.h | 1 + .../WindowInfosListenerInvokerTest.cpp | 38 +++++++++++++++++++ 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index 7062a4e3a7..effbfdb896 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -56,29 +56,33 @@ void WindowInfosListenerInvoker::removeWindowInfosListener( ATRACE_NAME("WindowInfosListenerInvoker::removeWindowInfosListener"); sp asBinder = IInterface::asBinder(listener); asBinder->unlinkToDeath(sp::fromExisting(this)); - mWindowInfosListeners.erase(asBinder); + eraseListenerAndAckMessages(asBinder); }}); } void WindowInfosListenerInvoker::binderDied(const wp& who) { BackgroundExecutor::getInstance().sendCallbacks({[this, who]() { ATRACE_NAME("WindowInfosListenerInvoker::binderDied"); - auto it = mWindowInfosListeners.find(who); - int64_t listenerId = it->second.first; - mWindowInfosListeners.erase(who); - - std::vector vsyncIds; - for (auto& [vsyncId, state] : mUnackedState) { - if (std::find(state.unackedListenerIds.begin(), state.unackedListenerIds.end(), - listenerId) != state.unackedListenerIds.end()) { - vsyncIds.push_back(vsyncId); - } - } + eraseListenerAndAckMessages(who); + }}); +} + +void WindowInfosListenerInvoker::eraseListenerAndAckMessages(const wp& binder) { + auto it = mWindowInfosListeners.find(binder); + int64_t listenerId = it->second.first; + mWindowInfosListeners.erase(binder); - for (int64_t vsyncId : vsyncIds) { - ackWindowInfosReceived(vsyncId, listenerId); + std::vector vsyncIds; + for (auto& [vsyncId, state] : mUnackedState) { + if (std::find(state.unackedListenerIds.begin(), state.unackedListenerIds.end(), + listenerId) != state.unackedListenerIds.end()) { + vsyncIds.push_back(vsyncId); } - }}); + } + + for (int64_t vsyncId : vsyncIds) { + ackWindowInfosReceived(vsyncId, listenerId); + } } void WindowInfosListenerInvoker::windowInfosChanged( diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index f36b0edd7d..261fd0ff3b 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -67,6 +67,7 @@ private: std::optional mDelayedUpdate; WindowInfosReportedListenerSet mReportedListeners; + void eraseListenerAndAckMessages(const wp&); struct UnackedState { ftl::SmallVector unackedListenerIds; diff --git a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp index c7b845e668..cfb047c877 100644 --- a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp +++ b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp @@ -245,4 +245,42 @@ TEST_F(WindowInfosListenerInvokerTest, noListeners) { EXPECT_EQ(callCount, 1); } +// Test that WindowInfosListenerInvoker#removeWindowInfosListener acks any unacked messages for +// the removed listener. +TEST_F(WindowInfosListenerInvokerTest, removeListenerAcks) { + // Don't ack in this listener to ensure there's an unacked message when the listener is later + // removed. + gui::WindowInfosListenerInfo listenerToBeRemovedInfo; + auto listenerToBeRemoved = sp::make([](const gui::WindowInfosUpdate&) {}); + mInvoker->addWindowInfosListener(listenerToBeRemoved, &listenerToBeRemovedInfo); + + std::mutex mutex; + std::condition_variable cv; + int callCount = 0; + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp::make([&](const gui::WindowInfosUpdate& update) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); + listenerInfo.windowInfosPublisher + ->ackWindowInfosReceived(update.vsyncId, + listenerInfo.listenerId); + }), + &listenerInfo); + + BackgroundExecutor::getInstance().sendCallbacks( + {[&]() { mInvoker->windowInfosChanged({}, {}, false); }}); + mInvoker->removeWindowInfosListener(listenerToBeRemoved); + BackgroundExecutor::getInstance().sendCallbacks( + {[&]() { mInvoker->windowInfosChanged({}, {}, false); }}); + + // Verify that the second listener is called twice. If unacked messages aren't removed when the + // first listener is removed, this will fail. + { + std::unique_lock lock{mutex}; + cv.wait(lock, [&]() { return callCount == 2; }); + } + EXPECT_EQ(callCount, 2); +} + } // namespace android -- GitLab From f2851617f677795e5cc7bcded4b5ee9ea635333e Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 25 Sep 2023 17:19:00 -0700 Subject: [PATCH 0706/1187] SF: add IEventThreadCallback to EventThread .. so it will be easier to add more callbacks to EventThread Bug: 299378819 Test: presubmit Change-Id: I3787be9ad8162b059b4d59255581cd14cbcf1cd8 --- .../surfaceflinger/Scheduler/EventThread.cpp | 44 +++---- .../surfaceflinger/Scheduler/EventThread.h | 26 ++--- .../surfaceflinger/Scheduler/Scheduler.cpp | 58 +++++----- services/surfaceflinger/Scheduler/Scheduler.h | 9 +- .../surfaceflinger_scheduler_fuzzer.cpp | 13 ++- .../unittests/DisplayTransactionTest.cpp | 8 +- .../tests/unittests/EventThreadTest.cpp | 108 ++++++++++-------- .../tests/unittests/SchedulerTest.cpp | 3 +- .../SurfaceFlinger_DisplayModeSwitching.cpp | 6 +- .../tests/unittests/TestableSurfaceFlinger.h | 6 +- .../tests/unittests/mock/MockEventThread.h | 12 +- 11 files changed, 147 insertions(+), 146 deletions(-) diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 21714da0ac..edab7ecee1 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -171,10 +171,8 @@ DisplayEventReceiver::Event makeFrameRateOverrideFlushEvent(PhysicalDisplayId di } // namespace EventThreadConnection::EventThreadConnection(EventThread* eventThread, uid_t callingUid, - ResyncCallback resyncCallback, EventRegistrationFlags eventRegistration) - : resyncCallback(std::move(resyncCallback)), - mOwnerUid(callingUid), + : mOwnerUid(callingUid), mEventRegistration(eventRegistration), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {} @@ -250,9 +248,7 @@ namespace impl { EventThread::EventThread(const char* name, std::shared_ptr vsyncSchedule, android::frametimeline::TokenManager* tokenManager, - ThrottleVsyncCallback throttleVsyncCallback, - GetVsyncPeriodFunction getVsyncPeriodFunction, - std::chrono::nanoseconds workDuration, + IEventThreadCallback& callback, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) : mThreadName(name), mVsyncTracer(base::StringPrintf("VSYNC-%s", name), 0), @@ -261,11 +257,7 @@ EventThread::EventThread(const char* name, std::shared_ptrgetDispatch(), createDispatchCallback(), name), mTokenManager(tokenManager), - mThrottleVsyncCallback(std::move(throttleVsyncCallback)), - mGetVsyncPeriodFunction(std::move(getVsyncPeriodFunction)) { - LOG_ALWAYS_FATAL_IF(getVsyncPeriodFunction == nullptr, - "getVsyncPeriodFunction must not be null"); - + mCallback(callback) { mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS { std::unique_lock lock(mMutex); threadMain(lock); @@ -307,10 +299,10 @@ void EventThread::setDuration(std::chrono::nanoseconds workDuration, } sp EventThread::createEventConnection( - ResyncCallback resyncCallback, EventRegistrationFlags eventRegistration) const { + EventRegistrationFlags eventRegistration) const { return sp::make(const_cast(this), IPCThreadState::self()->getCallingUid(), - std::move(resyncCallback), eventRegistration); + eventRegistration); } status_t EventThread::registerDisplayEventConnection(const sp& connection) { @@ -353,9 +345,7 @@ void EventThread::setVsyncRate(uint32_t rate, const sp& c } void EventThread::requestNextVsync(const sp& connection) { - if (connection->resyncCallback) { - connection->resyncCallback(); - } + mCallback.resync(); std::lock_guard lock(mMutex); @@ -371,20 +361,18 @@ VsyncEventData EventThread::getLatestVsyncEventData( const sp& connection) const { // Resync so that the vsync is accurate with hardware. getLatestVsyncEventData is an alternate // way to get vsync data (instead of posting callbacks to Choreographer). - if (connection->resyncCallback) { - connection->resyncCallback(); - } + mCallback.resync(); VsyncEventData vsyncEventData; - nsecs_t frameInterval = mGetVsyncPeriodFunction(connection->mOwnerUid); - vsyncEventData.frameInterval = frameInterval; + const Period frameInterval = mCallback.getVsyncPeriod(connection->mOwnerUid); + vsyncEventData.frameInterval = frameInterval.ns(); const auto [presentTime, deadline] = [&]() -> std::pair { std::lock_guard lock(mMutex); const auto vsyncTime = mVsyncSchedule->getTracker().nextAnticipatedVSyncTimeFrom( systemTime() + mWorkDuration.get().count() + mReadyDuration.count()); return {vsyncTime, vsyncTime - mReadyDuration.count()}; }(); - generateFrameTimeline(vsyncEventData, frameInterval, systemTime(SYSTEM_TIME_MONOTONIC), + generateFrameTimeline(vsyncEventData, frameInterval.ns(), systemTime(SYSTEM_TIME_MONOTONIC), presentTime, deadline); return vsyncEventData; } @@ -549,9 +537,9 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, connection->frameRate); } - return mThrottleVsyncCallback && - mThrottleVsyncCallback(event.vsync.vsyncData.preferredExpectedPresentationTime(), - connection->mOwnerUid); + const auto expectedPresentTime = + TimePoint::fromNs(event.vsync.vsyncData.preferredExpectedPresentationTime()); + return mCallback.throttleVsync(expectedPresentTime, connection->mOwnerUid); }; switch (event.header.type) { @@ -671,9 +659,9 @@ void EventThread::dispatchEvent(const DisplayEventReceiver::Event& event, for (const auto& consumer : consumers) { DisplayEventReceiver::Event copy = event; if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) { - const int64_t frameInterval = mGetVsyncPeriodFunction(consumer->mOwnerUid); - copy.vsync.vsyncData.frameInterval = frameInterval; - generateFrameTimeline(copy.vsync.vsyncData, frameInterval, copy.header.timestamp, + const Period frameInterval = mCallback.getVsyncPeriod(consumer->mOwnerUid); + copy.vsync.vsyncData.frameInterval = frameInterval.ns(); + generateFrameTimeline(copy.vsync.vsyncData, frameInterval.ns(), copy.header.timestamp, event.vsync.vsyncData.preferredExpectedPresentationTime(), event.vsync.vsyncData.preferredDeadlineTimestamp()); } diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 576910ed6a..a7c8b74b91 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -54,7 +54,6 @@ using gui::VsyncEventData; // --------------------------------------------------------------------------- -using ResyncCallback = std::function; using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; enum class VSyncRequest { @@ -69,7 +68,7 @@ enum class VSyncRequest { class EventThreadConnection : public gui::BnDisplayEventConnection { public: - EventThreadConnection(EventThread*, uid_t callingUid, ResyncCallback, + EventThreadConnection(EventThread*, uid_t callingUid, EventRegistrationFlags eventRegistration = {}); virtual ~EventThreadConnection(); @@ -80,9 +79,6 @@ public: binder::Status requestNextVsync() override; // asynchronous binder::Status getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) override; - // Called in response to requestNextVsync. - const ResyncCallback resyncCallback; - VSyncRequest vsyncRequest = VSyncRequest::None; const uid_t mOwnerUid; const EventRegistrationFlags mEventRegistration; @@ -104,7 +100,7 @@ public: virtual ~EventThread(); virtual sp createEventConnection( - ResyncCallback, EventRegistrationFlags eventRegistration = {}) const = 0; + EventRegistrationFlags eventRegistration = {}) const = 0; // Feed clients with fake VSYNC, e.g. while the display is off. virtual void enableSyntheticVsync(bool) = 0; @@ -136,20 +132,25 @@ public: virtual void onNewVsyncSchedule(std::shared_ptr) = 0; }; +struct IEventThreadCallback { + virtual ~IEventThreadCallback() = default; + + virtual bool throttleVsync(TimePoint, uid_t) = 0; + virtual Period getVsyncPeriod(uid_t) = 0; + virtual void resync() = 0; +}; + namespace impl { class EventThread : public android::EventThread { public: - using ThrottleVsyncCallback = std::function; - using GetVsyncPeriodFunction = std::function; - EventThread(const char* name, std::shared_ptr, - frametimeline::TokenManager*, ThrottleVsyncCallback, GetVsyncPeriodFunction, + frametimeline::TokenManager*, IEventThreadCallback& callback, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration); ~EventThread(); sp createEventConnection( - ResyncCallback, EventRegistrationFlags eventRegistration = {}) const override; + EventRegistrationFlags eventRegistration = {}) const override; status_t registerDisplayEventConnection(const sp& connection) override; void setVsyncRate(uint32_t rate, const sp& connection) override; @@ -214,8 +215,7 @@ private: scheduler::VSyncCallbackRegistration mVsyncRegistration GUARDED_BY(mMutex); frametimeline::TokenManager* const mTokenManager; - const ThrottleVsyncCallback mThrottleVsyncCallback; - const GetVsyncPeriodFunction mGetVsyncPeriodFunction; + IEventThreadCallback& mCallback; std::thread mThread; mutable std::mutex mMutex; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index aa24f565f5..d72ae1f03e 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -242,36 +242,35 @@ bool Scheduler::isVsyncInPhase(TimePoint expectedVsyncTime, Fps frameRate) const return getVsyncSchedule()->getTracker().isVSyncInPhase(expectedVsyncTime.ns(), frameRate); } -impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const { - return [this](nsecs_t expectedVsyncTime, uid_t uid) { - return !isVsyncValid(TimePoint::fromNs(expectedVsyncTime), uid); - }; +bool Scheduler::throttleVsync(android::TimePoint expectedPresentTime, uid_t uid) { + return !isVsyncValid(expectedPresentTime, uid); } -impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const { - return [this](uid_t uid) { - const auto [refreshRate, period] = [this] { - std::scoped_lock lock(mDisplayLock); - const auto pacesetterOpt = pacesetterDisplayLocked(); - LOG_ALWAYS_FATAL_IF(!pacesetterOpt); - const Display& pacesetter = *pacesetterOpt; - return std::make_pair(pacesetter.selectorPtr->getActiveMode().fps, - pacesetter.schedulePtr->period()); - }(); +Period Scheduler::getVsyncPeriod(uid_t uid) { + const auto [refreshRate, period] = [this] { + std::scoped_lock lock(mDisplayLock); + const auto pacesetterOpt = pacesetterDisplayLocked(); + LOG_ALWAYS_FATAL_IF(!pacesetterOpt); + const Display& pacesetter = *pacesetterOpt; + return std::make_pair(pacesetter.selectorPtr->getActiveMode().fps, + pacesetter.schedulePtr->period()); + }(); - const Period currentPeriod = period != Period::zero() ? period : refreshRate.getPeriod(); + const Period currentPeriod = period != Period::zero() ? period : refreshRate.getPeriod(); - const auto frameRate = getFrameRateOverride(uid); - if (!frameRate.has_value()) { - return currentPeriod.ns(); - } + const auto frameRate = getFrameRateOverride(uid); + if (!frameRate.has_value()) { + return currentPeriod; + } - const auto divisor = RefreshRateSelector::getFrameRateDivisor(refreshRate, *frameRate); - if (divisor <= 1) { - return currentPeriod.ns(); - } - return currentPeriod.ns() * divisor; - }; + const auto divisor = RefreshRateSelector::getFrameRateDivisor(refreshRate, *frameRate); + if (divisor <= 1) { + return currentPeriod; + } + + // TODO(b/299378819): the casting is not needed, but we need a flag as it might change + // behaviour. + return Period::fromNs(currentPeriod.ns() * divisor); } ConnectionHandle Scheduler::createEventThread(Cycle cycle, @@ -279,9 +278,7 @@ ConnectionHandle Scheduler::createEventThread(Cycle cycle, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration) { auto eventThread = std::make_unique(cycle == Cycle::Render ? "app" : "appSf", - getVsyncSchedule(), tokenManager, - makeThrottleVsyncCallback(), - makeGetVsyncPeriodFunction(), + getVsyncSchedule(), tokenManager, *this, workDuration, readyDuration); auto& handle = cycle == Cycle::Render ? mAppConnectionHandle : mSfConnectionHandle; @@ -293,7 +290,7 @@ ConnectionHandle Scheduler::createConnection(std::unique_ptr eventT const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++}; ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id); - auto connection = eventThread->createEventConnection([&] { resync(); }); + auto connection = eventThread->createEventConnection(); std::lock_guard lock(mConnectionsLock); mConnections.emplace(handle, Connection{connection, std::move(eventThread)}); @@ -307,8 +304,7 @@ sp Scheduler::createDisplayEventConnection( std::scoped_lock lock(mConnectionsLock); RETURN_IF_INVALID_HANDLE(handle, nullptr); - return mConnections[handle].thread->createEventConnection([&] { resync(); }, - eventRegistration); + return mConnections[handle].thread->createEventConnection(eventRegistration); }(); const auto layerId = static_cast(LayerHandle::getLayerId(layerHandle)); diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 822f7cc299..5796d5966e 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -98,7 +98,7 @@ using GlobalSignals = RefreshRateSelector::GlobalSignals; class VsyncSchedule; -class Scheduler : android::impl::MessageQueue { +class Scheduler : public IEventThreadCallback, android::impl::MessageQueue { using Impl = android::impl::MessageQueue; public: @@ -217,7 +217,6 @@ public: ftl::FakeGuard guard(kMainThreadContext); resyncToHardwareVsyncLocked(id, allowToEnable, refreshRate); } - void resync() EXCLUDES(mDisplayLock); void forceNextResync() { mLastResyncTime = 0; } // Passes a vsync sample to VsyncController. Returns true if @@ -420,8 +419,10 @@ private: void dispatchCachedReportedMode() REQUIRES(mPolicyLock) EXCLUDES(mDisplayLock); - android::impl::EventThread::ThrottleVsyncCallback makeThrottleVsyncCallback() const; - android::impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const; + // IEventThreadCallback overrides + bool throttleVsync(TimePoint, uid_t) override; + Period getVsyncPeriod(uid_t) override EXCLUDES(mDisplayLock); + void resync() override EXCLUDES(mDisplayLock); // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection. struct Connection { diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp index cbbfa1695c..2f5a36009c 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp @@ -97,21 +97,26 @@ PhysicalDisplayId SchedulerFuzzer::getPhysicalDisplayId() { return displayId; } +struct EventThreadCallback : public IEventThreadCallback { + bool throttleVsync(TimePoint, uid_t) override { return false; } + Period getVsyncPeriod(uid_t) override { return kSyncPeriod; } + void resync() override {} +}; + void SchedulerFuzzer::fuzzEventThread() { mVsyncSchedule = std::shared_ptr( new scheduler::VsyncSchedule(getPhysicalDisplayId(), std::make_shared(), std::make_shared(), nullptr)); - const auto getVsyncPeriod = [](uid_t /* uid */) { return kSyncPeriod.count(); }; + EventThreadCallback callback; std::unique_ptr thread = std::make_unique< - android::impl::EventThread>("fuzzer", mVsyncSchedule, nullptr, nullptr, getVsyncPeriod, + android::impl::EventThread>("fuzzer", mVsyncSchedule, nullptr, callback, (std::chrono::nanoseconds)mFdp.ConsumeIntegral(), (std::chrono::nanoseconds)mFdp.ConsumeIntegral()); thread->onHotplugReceived(getPhysicalDisplayId(), mFdp.ConsumeBool()); sp connection = - sp::make(thread.get(), mFdp.ConsumeIntegral(), - nullptr); + sp::make(thread.get(), mFdp.ConsumeIntegral()); thread->requestNextVsync(connection); thread->setVsyncRate(mFdp.ConsumeIntegral() /*rate*/, connection); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index e32cf8863b..fa31643df1 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -67,15 +67,13 @@ void DisplayTransactionTest::injectMockScheduler(PhysicalDisplayId displayId) { EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*mEventThread, createEventConnection(_, _)) - .WillOnce(Return(sp::make(mEventThread, - mock::EventThread::kCallingUid, - ResyncCallback()))); + .WillOnce(Return( + sp::make(mEventThread, mock::EventThread::kCallingUid))); EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*mSFEventThread, createEventConnection(_, _)) .WillOnce(Return(sp::make(mSFEventThread, - mock::EventThread::kCallingUid, - ResyncCallback()))); + mock::EventThread::kCallingUid))); mFlinger.setupScheduler(std::make_unique(), std::make_shared(), diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 9b46009704..8891c06c75 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -57,7 +57,7 @@ constexpr std::chrono::duration VSYNC_PERIOD(16ms); } // namespace -class EventThreadTest : public testing::Test { +class EventThreadTest : public testing::Test, public IEventThreadCallback { protected: static constexpr std::chrono::nanoseconds kWorkDuration = 0ms; static constexpr std::chrono::nanoseconds kReadyDuration = 3ms; @@ -65,10 +65,8 @@ protected: class MockEventThreadConnection : public EventThreadConnection { public: MockEventThreadConnection(impl::EventThread* eventThread, uid_t callingUid, - ResyncCallback&& resyncCallback, EventRegistrationFlags eventRegistration) - : EventThreadConnection(eventThread, callingUid, std::move(resyncCallback), - eventRegistration) {} + : EventThreadConnection(eventThread, callingUid, eventRegistration) {} MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event)); }; @@ -78,7 +76,14 @@ protected: EventThreadTest(); ~EventThreadTest() override; - void setupEventThread(std::chrono::nanoseconds vsyncPeriod); + void SetUp() override { mVsyncPeriod = VSYNC_PERIOD; } + + // IEventThreadCallback overrides + bool throttleVsync(TimePoint, uid_t) override; + Period getVsyncPeriod(uid_t) override; + void resync() override; + + void setupEventThread(); sp createConnection(ConnectionEventRecorder& recorder, EventRegistrationFlags eventRegistration = {}, uid_t ownerUid = mConnectionUid); @@ -92,8 +97,7 @@ protected: void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount); void expectVsyncEventFrameTimelinesCorrect( nsecs_t expectedTimestamp, gui::VsyncEventData::FrameTimeline preferredVsyncData); - void expectVsyncEventDataFrameTimelinesValidLength(VsyncEventData vsyncEventData, - std::chrono::nanoseconds vsyncPeriod); + void expectVsyncEventDataFrameTimelinesValidLength(VsyncEventData vsyncEventData); void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected); void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, @@ -133,6 +137,8 @@ protected: sp mThrottledConnection; std::unique_ptr mTokenManager; + std::chrono::nanoseconds mVsyncPeriod; + static constexpr uid_t mConnectionUid = 443; static constexpr uid_t mThrottledConnectionUid = 177; }; @@ -168,17 +174,24 @@ EventThreadTest::~EventThreadTest() { EXPECT_TRUE(mVSyncCallbackUnregisterRecorder.waitForCall().has_value()); } -void EventThreadTest::setupEventThread(std::chrono::nanoseconds vsyncPeriod) { - const auto throttleVsync = [&](nsecs_t expectedVsyncTimestamp, uid_t uid) { - mThrottleVsyncCallRecorder.getInvocable()(expectedVsyncTimestamp, uid); - return (uid == mThrottledConnectionUid); - }; - const auto getVsyncPeriod = [vsyncPeriod](uid_t uid) { return vsyncPeriod.count(); }; +bool EventThreadTest::throttleVsync(android::TimePoint expectedVsyncTimestamp, uid_t uid) { + mThrottleVsyncCallRecorder.recordCall(expectedVsyncTimestamp.ns(), uid); + return (uid == mThrottledConnectionUid); +} + +Period EventThreadTest::getVsyncPeriod(uid_t) { + return mVsyncPeriod; +} + +void EventThreadTest::resync() { + mResyncCallRecorder.recordCall(); +} +void EventThreadTest::setupEventThread() { mTokenManager = std::make_unique(); mThread = std::make_unique("EventThreadTest", mVsyncSchedule, - mTokenManager.get(), throttleVsync, - getVsyncPeriod, kWorkDuration, kReadyDuration); + mTokenManager.get(), *this, kWorkDuration, + kReadyDuration); // EventThread should register itself as VSyncSource callback. EXPECT_TRUE(mVSyncCallbackRegisterRecorder.waitForCall().has_value()); @@ -200,9 +213,7 @@ sp EventThreadTest::createConnection ConnectionEventRecorder& recorder, EventRegistrationFlags eventRegistration, uid_t ownerUid) { sp connection = - sp::make(mThread.get(), ownerUid, - mResyncCallRecorder.getInvocable(), - eventRegistration); + sp::make(mThread.get(), ownerUid, eventRegistration); EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable())); return connection; } @@ -292,10 +303,9 @@ void EventThreadTest::expectVsyncEventFrameTimelinesCorrect( } } -void EventThreadTest::expectVsyncEventDataFrameTimelinesValidLength( - VsyncEventData vsyncEventData, std::chrono::nanoseconds vsyncPeriod) { +void EventThreadTest::expectVsyncEventDataFrameTimelinesValidLength(VsyncEventData vsyncEventData) { float nonPreferredTimelinesAmount = - scheduler::VsyncConfig::kEarlyLatchMaxThreshold / vsyncPeriod; + scheduler::VsyncConfig::kEarlyLatchMaxThreshold / mVsyncPeriod; EXPECT_LE(vsyncEventData.frameTimelinesLength, nonPreferredTimelinesAmount + 1) << "Amount of non-preferred frame timelines too many;" << " expected presentation time will be over threshold"; @@ -357,7 +367,7 @@ using namespace testing; */ TEST_F(EventThreadTest, canCreateAndDestroyThreadWithNoEventsSent) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); EXPECT_FALSE(mVSyncCallbackRegisterRecorder.waitForCall(0us).has_value()); EXPECT_FALSE(mVSyncCallbackScheduleRecorder.waitForCall(0us).has_value()); @@ -368,7 +378,7 @@ TEST_F(EventThreadTest, canCreateAndDestroyThreadWithNoEventsSent) { } TEST_F(EventThreadTest, vsyncRequestIsIgnoredIfDisplayIsDisconnected) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, false); expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, false); @@ -381,7 +391,7 @@ TEST_F(EventThreadTest, vsyncRequestIsIgnoredIfDisplayIsDisconnected) { } TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); // Signal that we want the next vsync event to be posted to the connection mThread->requestNextVsync(mConnection); @@ -414,7 +424,7 @@ TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) { } TEST_F(EventThreadTest, requestNextVsyncEventFrameTimelinesCorrect) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); // Signal that we want the next vsync event to be posted to the connection mThread->requestNextVsync(mConnection); @@ -428,12 +438,12 @@ TEST_F(EventThreadTest, requestNextVsyncEventFrameTimelinesCorrect) { } TEST_F(EventThreadTest, requestNextVsyncEventFrameTimelinesValidLength) { + setupEventThread(); // The VsyncEventData should not have kFrameTimelinesCapacity amount of valid frame timelines, // due to longer vsync period and kEarlyLatchMaxThreshold. Use length-2 to avoid decimal // truncation (e.g. 60Hz has 16.6... ms vsync period). - std::chrono::nanoseconds vsyncPeriod(scheduler::VsyncConfig::kEarlyLatchMaxThreshold / - (VsyncEventData::kFrameTimelinesCapacity - 2)); - setupEventThread(vsyncPeriod); + mVsyncPeriod = (scheduler::VsyncConfig::kEarlyLatchMaxThreshold / + (VsyncEventData::kFrameTimelinesCapacity - 2)); // Signal that we want the next vsync event to be posted to the connection mThread->requestNextVsync(mConnection); @@ -449,11 +459,11 @@ TEST_F(EventThreadTest, requestNextVsyncEventFrameTimelinesValidLength) { ASSERT_TRUE(args.has_value()) << " did not receive an event for timestamp " << expectedTimestamp; const VsyncEventData vsyncEventData = std::get<0>(args.value()).vsync.vsyncData; - expectVsyncEventDataFrameTimelinesValidLength(vsyncEventData, vsyncPeriod); + expectVsyncEventDataFrameTimelinesValidLength(vsyncEventData); } TEST_F(EventThreadTest, getLatestVsyncEventData) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); const nsecs_t now = systemTime(); const nsecs_t preferredExpectedPresentationTime = now + 20000000; @@ -469,7 +479,7 @@ TEST_F(EventThreadTest, getLatestVsyncEventData) { // Check EventThread immediately requested a resync. EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value()); - expectVsyncEventDataFrameTimelinesValidLength(vsyncEventData, VSYNC_PERIOD); + expectVsyncEventDataFrameTimelinesValidLength(vsyncEventData); EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now) << "Deadline timestamp should be greater than frame time"; for (size_t i = 0; i < vsyncEventData.frameTimelinesLength; i++) { @@ -508,7 +518,7 @@ TEST_F(EventThreadTest, getLatestVsyncEventData) { } TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); // Create a first connection, register it, and request a vsync rate of zero. ConnectionEventRecorder firstConnectionEventRecorder{0}; @@ -537,7 +547,7 @@ TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) { } TEST_F(EventThreadTest, setVsyncRateOnePostsAllEventsToThatConnection) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); mThread->setVsyncRate(1, mConnection); @@ -562,7 +572,7 @@ TEST_F(EventThreadTest, setVsyncRateOnePostsAllEventsToThatConnection) { } TEST_F(EventThreadTest, setVsyncRateTwoPostsEveryOtherEventToThatConnection) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); mThread->setVsyncRate(2, mConnection); @@ -590,7 +600,7 @@ TEST_F(EventThreadTest, setVsyncRateTwoPostsEveryOtherEventToThatConnection) { } TEST_F(EventThreadTest, connectionsRemovedIfInstanceDestroyed) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); mThread->setVsyncRate(1, mConnection); @@ -609,7 +619,7 @@ TEST_F(EventThreadTest, connectionsRemovedIfInstanceDestroyed) { } TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY}; sp errorConnection = createConnection(errorConnectionEventRecorder); @@ -635,7 +645,7 @@ TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) { } TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK}; sp errorConnection = createConnection(errorConnectionEventRecorder); @@ -661,42 +671,42 @@ TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) { } TEST_F(EventThreadTest, setPhaseOffsetForwardsToVSyncSource) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); mThread->setDuration(321ns, 456ns); expectVSyncSetDurationCallReceived(321ns, 456ns); } TEST_F(EventThreadTest, postHotplugInternalDisconnect) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, false); expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, false); } TEST_F(EventThreadTest, postHotplugInternalConnect) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true); expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, true); } TEST_F(EventThreadTest, postHotplugExternalDisconnect) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); mThread->onHotplugReceived(EXTERNAL_DISPLAY_ID, false); expectHotplugEventReceivedByConnection(EXTERNAL_DISPLAY_ID, false); } TEST_F(EventThreadTest, postHotplugExternalConnect) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); mThread->onHotplugReceived(EXTERNAL_DISPLAY_ID, true); expectHotplugEventReceivedByConnection(EXTERNAL_DISPLAY_ID, true); } TEST_F(EventThreadTest, postConfigChangedPrimary) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) .setPhysicalDisplayId(INTERNAL_DISPLAY_ID) @@ -710,7 +720,7 @@ TEST_F(EventThreadTest, postConfigChangedPrimary) { } TEST_F(EventThreadTest, postConfigChangedExternal) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) .setPhysicalDisplayId(EXTERNAL_DISPLAY_ID) @@ -724,7 +734,7 @@ TEST_F(EventThreadTest, postConfigChangedExternal) { } TEST_F(EventThreadTest, postConfigChangedPrimary64bit) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); const auto mode = DisplayMode::Builder(hal::HWConfigId(0)) .setPhysicalDisplayId(DISPLAY_ID_64BIT) @@ -737,7 +747,7 @@ TEST_F(EventThreadTest, postConfigChangedPrimary64bit) { } TEST_F(EventThreadTest, suppressConfigChanged) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); ConnectionEventRecorder suppressConnectionEventRecorder{0}; sp suppressConnection = @@ -758,7 +768,7 @@ TEST_F(EventThreadTest, suppressConfigChanged) { } TEST_F(EventThreadTest, postUidFrameRateMapping) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); const std::vector overrides = { {.uid = 1, .frameRateHz = 20}, @@ -771,7 +781,7 @@ TEST_F(EventThreadTest, postUidFrameRateMapping) { } TEST_F(EventThreadTest, suppressUidFrameRateMapping) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); const std::vector overrides = { {.uid = 1, .frameRateHz = 20}, @@ -791,7 +801,7 @@ TEST_F(EventThreadTest, suppressUidFrameRateMapping) { } TEST_F(EventThreadTest, requestNextVsyncWithThrottleVsyncDoesntPostVSync) { - setupEventThread(VSYNC_PERIOD); + setupEventThread(); // Signal that we want the next vsync event to be posted to the throttled connection mThread->requestNextVsync(mThrottledConnection); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 3200003eda..173f9417b9 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -55,8 +55,7 @@ protected: class MockEventThreadConnection : public android::EventThreadConnection { public: explicit MockEventThreadConnection(EventThread* eventThread) - : EventThreadConnection(eventThread, /*callingUid*/ static_cast(0), - ResyncCallback()) {} + : EventThreadConnection(eventThread, /*callingUid*/ static_cast(0)) {} ~MockEventThreadConnection() = default; MOCK_METHOD1(stealReceiveChannel, binder::Status(gui::BitTube* outChannel)); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index 3a5fdf98de..aeac80dc62 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -124,14 +124,12 @@ void DisplayModeSwitchingTest::setupScheduler( EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) .WillOnce(Return(sp::make(eventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); + mock::EventThread::kCallingUid))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) .WillOnce(Return(sp::make(sfEventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); + mock::EventThread::kCallingUid))); auto vsyncController = std::make_unique(); auto vsyncTracker = std::make_shared(); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 908c9abc03..dd998ba629 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -281,14 +281,12 @@ public: EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) .WillOnce(Return(sp::make(eventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); + mock::EventThread::kCallingUid))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) .WillOnce(Return(sp::make(sfEventThread.get(), - mock::EventThread::kCallingUid, - ResyncCallback()))); + mock::EventThread::kCallingUid))); auto vsyncController = makeMock(options.useNiceMock); auto vsyncTracker = makeSharedMock(options.useNiceMock); diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 8e782ebbb1..866af3bbd0 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -29,8 +29,16 @@ public: EventThread(); ~EventThread() override; - MOCK_METHOD(sp, createEventConnection, - (ResyncCallback, EventRegistrationFlags), (const, override)); + // TODO(b/302035909): workaround otherwise gtest complains about + // error: no viable conversion from + // 'tuple &&>' to 'const + // tuple>' + sp createEventConnection(EventRegistrationFlags flags) const override { + return createEventConnection(false, flags); + } + MOCK_METHOD(sp, createEventConnection, (bool, EventRegistrationFlags), + (const)); + MOCK_METHOD(void, enableSyntheticVsync, (bool), (override)); MOCK_METHOD(void, onHotplugReceived, (PhysicalDisplayId, bool), (override)); MOCK_METHOD(void, onHotplugConnectionError, (int32_t), (override)); -- GitLab From c969fb8902d183660de32cbb0a8d66d4819055e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 28 Sep 2023 05:30:24 +0000 Subject: [PATCH 0707/1187] use BpfMap's resetMap() for creating new maps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Å»enczykowski Change-Id: I0f837dd358e8bbcb601b2d5e7e2757f60154c1cb --- services/gpuservice/tests/unittests/GpuMemTest.cpp | 4 +--- services/gpuservice/tests/unittests/GpuMemTracerTest.cpp | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp index 8dabe4fbdb..1f5b2889d1 100644 --- a/services/gpuservice/tests/unittests/GpuMemTest.cpp +++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp @@ -66,9 +66,7 @@ public: mTestableGpuMem = TestableGpuMem(mGpuMem.get()); mTestableGpuMem.setInitialized(); errno = 0; - mTestMap = std::move(bpf::BpfMap(BPF_MAP_TYPE_HASH, - TEST_MAP_SIZE, - BPF_F_NO_PREALLOC)); + mTestMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); EXPECT_EQ(0, errno); EXPECT_TRUE(mTestMap.isValid()); diff --git a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp index 5c042102b2..6550df9e58 100644 --- a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp +++ b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp @@ -65,9 +65,7 @@ public: mTestableGpuMem = TestableGpuMem(mGpuMem.get()); errno = 0; - mTestMap = std::move(bpf::BpfMap(BPF_MAP_TYPE_HASH, - TEST_MAP_SIZE, - BPF_F_NO_PREALLOC)); + mTestMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); EXPECT_EQ(0, errno); EXPECT_TRUE(mTestMap.isValid()); -- GitLab From af8d3a709b93cb2a857ff783840b3b3f1d83d16b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 28 Sep 2023 05:12:28 +0000 Subject: [PATCH 0708/1187] make it clear mGpuMemTotalMap is R/O MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Å»enczykowski Change-Id: I0484c629a02b84b59ca19b35e24a6496fbfd0990 --- services/gpuservice/gpumem/GpuMem.cpp | 2 +- services/gpuservice/gpumem/include/gpumem/GpuMem.h | 4 ++-- services/gpuservice/tests/unittests/TestableGpuMem.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/services/gpuservice/gpumem/GpuMem.cpp b/services/gpuservice/gpumem/GpuMem.cpp index dd3cc3bd86..141fe021ee 100644 --- a/services/gpuservice/gpumem/GpuMem.cpp +++ b/services/gpuservice/gpumem/GpuMem.cpp @@ -77,7 +77,7 @@ void GpuMem::initialize() { mInitialized.store(true); } -void GpuMem::setGpuMemTotalMap(bpf::BpfMap& map) { +void GpuMem::setGpuMemTotalMap(bpf::BpfMapRO& map) { mGpuMemTotalMap = std::move(map); } diff --git a/services/gpuservice/gpumem/include/gpumem/GpuMem.h b/services/gpuservice/gpumem/include/gpumem/GpuMem.h index 7588b54818..9aa74d6863 100644 --- a/services/gpuservice/gpumem/include/gpumem/GpuMem.h +++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h @@ -44,12 +44,12 @@ private: friend class TestableGpuMem; // set gpu memory total map - void setGpuMemTotalMap(bpf::BpfMap& map); + void setGpuMemTotalMap(bpf::BpfMapRO& map); // indicate whether ebpf has been initialized std::atomic mInitialized = false; // bpf map for GPU memory total data - android::bpf::BpfMap mGpuMemTotalMap; + android::bpf::BpfMapRO mGpuMemTotalMap; // gpu memory tracepoint event category static constexpr char kGpuMemTraceGroup[] = "gpu_mem"; diff --git a/services/gpuservice/tests/unittests/TestableGpuMem.h b/services/gpuservice/tests/unittests/TestableGpuMem.h index 6c8becb075..f21843fe1a 100644 --- a/services/gpuservice/tests/unittests/TestableGpuMem.h +++ b/services/gpuservice/tests/unittests/TestableGpuMem.h @@ -28,7 +28,7 @@ public: void setInitialized() { mGpuMem->mInitialized.store(true); } - void setGpuMemTotalMap(bpf::BpfMap& map) { + void setGpuMemTotalMap(bpf::BpfMapRO& map) { mGpuMem->setGpuMemTotalMap(map); } -- GitLab From 5ad813f5a7615d9d9c945dd0d101c2aa11793699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Kongstad?= Date: Thu, 28 Sep 2023 10:09:18 +0200 Subject: [PATCH 0709/1187] dumpstate: call printflags instead of reading flag files explicitly Now that the printflags device tool exists, dumpstate no longer needs to read the aconfig files itself. Teach dumpstate to call printflags instead. As a bonus, printflags will also include the current flag values as defined by device_config. Bug: 302452801 Test: adb bugreport /tmp/bugreport.zip && unzip -c /tmp/bugreport.zip bugreport*.txt | grep --text -A20 -e 'ACONFIG FLAGS' Change-Id: I6be4aab8dad6e08d2bc0e646224b3682927e34a2 --- cmds/dumpstate/dumpstate.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 9444729a6c..e18c8e380d 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -186,6 +186,7 @@ void add_mountinfo(); #define CGROUPFS_DIR "/sys/fs/cgroup" #define SDK_EXT_INFO "/apex/com.android.sdkext/bin/derive_sdk" #define DROPBOX_DIR "/data/system/dropbox" +#define PRINT_FLAGS "/system/bin/printflags" // TODO(narayan): Since this information has to be kept in sync // with tombstoned, we should just put it in a common header. @@ -1759,14 +1760,8 @@ static Dumpstate::RunStatus dumpstate() { DumpFile("PRODUCT BUILD-TIME RELEASE FLAGS", "/product/etc/build_flags.json"); DumpFile("VENDOR BUILD-TIME RELEASE FLAGS", "/vendor/etc/build_flags.json"); - DumpFile("SYSTEM BUILD-TIME ACONFIG FLAGS (check dumpstate build_config for runtime values)", - "/system/etc/aconfig_flags.textproto"); - DumpFile("SYSTEM_EXT BUILD-TIME ACONFIG FLAGS (check dumpstate build_config for runtime" - " values)", "/system_ext/etc/aconfig_flags.textproto"); - DumpFile("PRODUCT BUILD-TIME ACONFIG FLAGS (check dumpstate build_config for runtime values)", - "/product/etc/aconfig_flags.textproto"); - DumpFile("VENDOR BUILD-TIME ACONFIG FLAGS (check dumpstate build_config for runtime values)", - "/vendor/etc/aconfig_flags.textproto"); + RunCommand("ACONFIG FLAGS", {PRINT_FLAGS}, + CommandOptions::WithTimeout(10).Always().DropRoot().Build()); RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"}); -- GitLab From 5bd19edcdd63f36c145301e454dfd15371254769 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Tue, 26 Sep 2023 16:49:22 -0700 Subject: [PATCH 0710/1187] inputflinger: add missing include Bug: 175635923 Test: treehugger Change-Id: Ieb7828b26613c3b5470c9b76f31ad1b6b09d9445 Merged-In: Ieb7828b26613c3b5470c9b76f31ad1b6b09d9445 --- services/inputflinger/BlockingQueue.h | 1 + 1 file changed, 1 insertion(+) diff --git a/services/inputflinger/BlockingQueue.h b/services/inputflinger/BlockingQueue.h index 56938480f0..f848c82c42 100644 --- a/services/inputflinger/BlockingQueue.h +++ b/services/inputflinger/BlockingQueue.h @@ -17,6 +17,7 @@ #pragma once #include +#include #include #include #include -- GitLab From 9489a0cce79799b1fb546ca3765875a7718f749f Mon Sep 17 00:00:00 2001 From: Brian Johnson Date: Thu, 28 Sep 2023 12:16:07 -0700 Subject: [PATCH 0711/1187] SF: Update the trunk-stable bugid for 24Q1 multidisplay feature Bug: 299486625 Test: adb shell dumpsys SurfaceFlinger -- check for "ConnectedDisplayFlagValue" Change-Id: I0a67509645392736876def705a06fa52e7ca5840 --- services/surfaceflinger/surfaceflinger_flags.aconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig index bfc03aae09..d4ab7869a0 100644 --- a/services/surfaceflinger/surfaceflinger_flags.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags.aconfig @@ -11,8 +11,8 @@ flag { flag { name: "connected_display" namespace: "core_graphics" - description: "Controls SurfaceFlinger support for Connected Displays" - bug: "278199093" + description: "Controls SurfaceFlinger support for Connected Displays in 24Q1" + bug: "299486625" is_fixed_read_only: true } -- GitLab From 1c7938ecd30c0938f63fb84fe279892ff6a20e47 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Fri, 22 Sep 2023 04:17:23 +0000 Subject: [PATCH 0712/1187] Support injecting jank into Scheduler for testing purposes Injects a fraction of a frame's expected present time as a jank. This is mainly to avoid thinking about hard-coding milliseconds. Also supports delaying this jank injection, since the Perfetto UI currently steals any ADB session Bug: 296636083 Test: TouchLatency + perfetto Change-Id: If08616e68c3e7b3d6eaed6f6ff5cbc6ad444481e --- .../surfaceflinger/Scheduler/Scheduler.cpp | 11 ++++++ services/surfaceflinger/Scheduler/Scheduler.h | 8 ++++ services/surfaceflinger/SurfaceFlinger.cpp | 37 ++++++++++++++++++- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index d72ae1f03e..68e2ce9b98 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -211,6 +211,17 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, targeters.try_emplace(id, &targeter); } + if (flagutils::vrrConfigEnabled() && + CC_UNLIKELY(mPacesetterFrameDurationFractionToSkip > 0.f)) { + const auto period = pacesetterTargeter.target().expectedFrameDuration(); + const auto skipDuration = Duration::fromNs( + static_cast(period.ns() * mPacesetterFrameDurationFractionToSkip)); + ATRACE_FORMAT("Injecting jank for %f%% of the frame (%" PRId64 " ns)", + mPacesetterFrameDurationFractionToSkip * 100, skipDuration.ns()); + std::this_thread::sleep_for(skipDuration); + mPacesetterFrameDurationFractionToSkip = 0.f; + } + const auto resultsPerDisplay = compositor.composite(pacesetterId, targeters); compositor.sample(); diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 5796d5966e..f652bb2627 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -323,6 +323,11 @@ public: return mFeatures.test(Feature::kSmallDirtyContentDetection); } + // Injects a delay that is a fraction of the predicted frame duration for the next frame. + void injectPacesetterDelay(float frameDurationFraction) REQUIRES(kMainThreadContext) { + mPacesetterFrameDurationFractionToSkip = frameDurationFraction; + } + private: friend class TestableScheduler; @@ -452,6 +457,9 @@ private: // Timer used to monitor display power mode. ftl::Optional mDisplayPowerTimer; + // Injected delay prior to compositing, for simulating jank. + float mPacesetterFrameDurationFractionToSkip GUARDED_BY(kMainThreadContext) = 0.f; + ISchedulerCallback& mSchedulerCallback; // mDisplayLock may be locked while under mPolicyLock. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b7d2f9a053..12aacad64c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -6660,9 +6660,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { code == IBinder::SYSPROPS_TRANSACTION) { return OK; } - // Numbers from 1000 to 1044 are currently used for backdoors. The code + // Numbers from 1000 to 1045 are currently used for backdoors. The code // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1044) { + if (code >= 1000 && code <= 1045) { ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); return OK; } @@ -7151,6 +7151,39 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } return NO_ERROR; } + // Inject jank + // First argument is a float that describes the fraction of frame duration to jank by. + // Second argument is a delay in ms for triggering the jank. This is useful for working + // with tools that steal the adb connection. This argument is optional. + case 1045: { + if (flagutils::vrrConfigEnabled()) { + float jankAmount = data.readFloat(); + int32_t jankDelayMs = 0; + if (data.readInt32(&jankDelayMs) != NO_ERROR) { + jankDelayMs = 0; + } + + const auto jankDelayDuration = Duration(std::chrono::milliseconds(jankDelayMs)); + + const bool jankAmountValid = jankAmount > 0.0 && jankAmount < 100.0; + + if (!jankAmountValid) { + ALOGD("Ignoring invalid jank amount: %f", jankAmount); + reply->writeInt32(BAD_VALUE); + return BAD_VALUE; + } + + (void)mScheduler->scheduleDelayed( + [&, jankAmount]() FTL_FAKE_GUARD(kMainThreadContext) { + mScheduler->injectPacesetterDelay(jankAmount); + scheduleComposite(FrameHint::kActive); + }, + jankDelayDuration.ns()); + reply->writeInt32(NO_ERROR); + return NO_ERROR; + } + return err; + } } } return err; -- GitLab From 06405fc71796aa5e5ec8ca61fcd7dacdd3513136 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Fri, 22 Sep 2023 13:40:51 -0700 Subject: [PATCH 0713/1187] Fix NoFocusedWindow_DoesNotSendDuplicateAnr test This test requires that the application timeout be larger than the "no focused window" timeout. But after a recent refactor, this became false - both values were at 100ms. The test should've failed close to 50% of the time, but due to bad luck, failure rate was less, so it wasn't caught earlier. Furthermore, for some reason this failure was not reproducing on host. In this CL, refactor the test to always use half of the app timeout. This will avoid such mistakes in the future. At the same time, we bump up the timeout to have a 100 ms buffer, which was empirically found to be sufficient for most host environments. I also found that we were waiting for the incorrect amount of time. Since the "no focused window" timer starts immediately, this should have been accounted for when asserting the ANR timeout receipt. One negative consequence of this CL is that the test now takes 800 ms to run, but at least it should no longer be flaky. Test: TEST=inputflinger_tests; m $TEST && adb sync data && adb shell -t data/nativetest64/$TEST/$TEST --gtest_filter="*NoFocusedWindow_DoesNotSendDuplicateAnr*" --gtest_repeat=200 --gtest_break_on_failure Bug: 293179353 Change-Id: I00526a0172e14746e77c871182d08c4c3de2e518 --- .../tests/InputDispatcher_test.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 38970f261a..79f4d1ec64 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -6848,6 +6848,10 @@ TEST_F(InputDispatcherSingleWindowAnr, StaleKeyEventDoesNotAnr) { // We have a focused application, but no focused window // Make sure that we don't notify policy twice about the same ANR. TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) { + const std::chrono::duration appTimeout = 400ms; + mApplication->setDispatchingTimeout(appTimeout); + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApplication); + mWindow->setFocusable(false); mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); mWindow->consumeFocusEvent(false); @@ -6855,13 +6859,18 @@ TEST_F(InputDispatcherSingleWindowAnr, NoFocusedWindow_DoesNotSendDuplicateAnr) // Once a focused event arrives, we get an ANR for this application // We specify the injection timeout to be smaller than the application timeout, to ensure that // injection times out (instead of failing). + const std::chrono::duration eventInjectionTimeout = 100ms; + ASSERT_LT(eventInjectionTimeout, appTimeout); const InputEventInjectionResult result = injectKey(*mDispatcher, AKEY_EVENT_ACTION_DOWN, /*repeatCount=*/0, ADISPLAY_ID_DEFAULT, - InputEventInjectionSync::WAIT_FOR_RESULT, 100ms, /*allowKeyRepeat=*/false); - ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result); - const std::chrono::duration appTimeout = - mApplication->getDispatchingTimeout(DISPATCHING_TIMEOUT); - mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(appTimeout, mApplication); + InputEventInjectionSync::WAIT_FOR_RESULT, eventInjectionTimeout, + /*allowKeyRepeat=*/false); + ASSERT_EQ(InputEventInjectionResult::TIMED_OUT, result) + << "result=" << ftl::enum_string(result); + // We already waited for 'eventInjectionTimeout`, because the countdown started when the event + // was first injected. So now we have (appTimeout - eventInjectionTimeout) left to wait. + std::chrono::duration remainingWaitTime = appTimeout - eventInjectionTimeout; + mFakePolicy->assertNotifyNoFocusedWindowAnrWasCalled(remainingWaitTime, mApplication); std::this_thread::sleep_for(appTimeout); // ANR should not be raised again. It is up to policy to do that if it desires. -- GitLab From 8384e0d7658295ccb2b724d96fb4b46292ecb81f Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 18 Sep 2023 18:48:27 -0700 Subject: [PATCH 0714/1187] Iterate over vector in pilferPointersLocked No behaviour change in this CL. We are currently returning early from the function where there isn't exactly one device active. To future-proof this code, iterate over the entire vector of devices, knowing that currently, only 1 iteration will occur. This will simplify the future CL for multi-device support. Bug: 211379801 Test: atest inputflinger_tests Change-Id: Ie58ecde47f6dccd4cb45e1d8264af59376c27683 --- .../dispatcher/InputDispatcher.cpp | 70 ++++++++++--------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 51582203fa..005e5b6c5a 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -5918,14 +5918,16 @@ status_t InputDispatcher::pilferPointers(const sp& token) { status_t InputDispatcher::pilferPointersLocked(const sp& token) { const std::shared_ptr requestingChannel = getInputChannelLocked(token); if (!requestingChannel) { - ALOGW("Attempted to pilfer pointers from an un-registered channel or invalid token"); + LOG(WARNING) + << "Attempted to pilfer pointers from an un-registered channel or invalid token"; return BAD_VALUE; } auto [statePtr, windowPtr, displayId] = findTouchStateWindowAndDisplayLocked(token); if (statePtr == nullptr || windowPtr == nullptr) { - ALOGW("Attempted to pilfer points from a channel without any on-going pointer streams." - " Ignoring."); + LOG(WARNING) + << "Attempted to pilfer points from a channel without any on-going pointer streams." + " Ignoring."; return BAD_VALUE; } std::set deviceIds = windowPtr->getTouchingDeviceIds(); @@ -5934,36 +5936,38 @@ status_t InputDispatcher::pilferPointersLocked(const sp& token) { << " in window: " << windowPtr->dump(); return BAD_VALUE; } - const int32_t deviceId = *deviceIds.begin(); - - TouchState& state = *statePtr; - TouchedWindow& window = *windowPtr; - // Send cancel events to all the input channels we're stealing from. - CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, - "input channel stole pointer stream"); - options.deviceId = deviceId; - options.displayId = displayId; - std::bitset pointerIds = window.getTouchingPointers(deviceId); - options.pointerIds = pointerIds; - std::string canceledWindows; - for (const TouchedWindow& w : state.windows) { - const std::shared_ptr channel = - getInputChannelLocked(w.windowHandle->getToken()); - if (channel != nullptr && channel->getConnectionToken() != token) { - synthesizeCancelationEventsForInputChannelLocked(channel, options); - canceledWindows += canceledWindows.empty() ? "[" : ", "; - canceledWindows += channel->getName(); - } - } - canceledWindows += canceledWindows.empty() ? "[]" : "]"; - ALOGI("Channel %s is stealing touch from %s", requestingChannel->getName().c_str(), - canceledWindows.c_str()); - - // Prevent the gesture from being sent to any other windows. - // This only blocks relevant pointers to be sent to other windows - window.addPilferingPointers(deviceId, pointerIds); - - state.cancelPointersForWindowsExcept(deviceId, pointerIds, token); + + for (const DeviceId deviceId : deviceIds) { + TouchState& state = *statePtr; + TouchedWindow& window = *windowPtr; + // Send cancel events to all the input channels we're stealing from. + CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, + "input channel stole pointer stream"); + options.deviceId = deviceId; + options.displayId = displayId; + std::bitset pointerIds = window.getTouchingPointers(deviceId); + options.pointerIds = pointerIds; + std::string canceledWindows; + for (const TouchedWindow& w : state.windows) { + const std::shared_ptr channel = + getInputChannelLocked(w.windowHandle->getToken()); + if (channel != nullptr && channel->getConnectionToken() != token) { + synthesizeCancelationEventsForInputChannelLocked(channel, options); + canceledWindows += canceledWindows.empty() ? "[" : ", "; + canceledWindows += channel->getName(); + } + } + canceledWindows += canceledWindows.empty() ? "[]" : "]"; + LOG(INFO) << "Channel " << requestingChannel->getName() + << " is stealing input gesture for device " << deviceId << " from " + << canceledWindows; + + // Prevent the gesture from being sent to any other windows. + // This only blocks relevant pointers to be sent to other windows + window.addPilferingPointers(deviceId, pointerIds); + + state.cancelPointersForWindowsExcept(deviceId, pointerIds, token); + } return OK; } -- GitLab From f404321f17faad494142aa4afa2bb1be29660d20 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 18 Sep 2023 19:33:03 -0700 Subject: [PATCH 0715/1187] Misc fixes in InputDispatcher Minor refactors to reduce the diff in the upcoming CLs Bug: 211379801 Test: atest inputflinger_tests Change-Id: I1f0fd663ba3b49fba4727a4e1a144f65ae3ad6f5 --- .../dispatcher/InputDispatcher.cpp | 2 +- .../inputflinger/dispatcher/InputState.cpp | 9 +++-- .../inputflinger/dispatcher/InputTarget.cpp | 7 +++- .../tests/InputDispatcher_test.cpp | 33 ++++++++++++------- 4 files changed, 36 insertions(+), 15 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 005e5b6c5a..8e20eaf954 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4531,7 +4531,7 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev // the injected event, it is responsible for setting POLICY_FLAG_INJECTED_FROM_ACCESSIBILITY. // For those events, we will set FLAG_IS_ACCESSIBILITY_EVENT to allow apps to distinguish them // from events that originate from actual hardware. - int32_t resolvedDeviceId = VIRTUAL_KEYBOARD_ID; + DeviceId resolvedDeviceId = VIRTUAL_KEYBOARD_ID; if (policyFlags & POLICY_FLAG_FILTERED) { resolvedDeviceId = event->getDeviceId(); } diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index ccffe26d57..b21427dad8 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -83,6 +83,11 @@ bool InputState::trackKey(const KeyEntry& entry, int32_t action, int32_t flags) } } +/** + * Return: + * true if the incoming event was correctly tracked, + * false if the incoming event should be dropped. + */ bool InputState::trackMotion(const MotionEntry& entry, int32_t action, int32_t flags) { int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK; switch (actionMasked) { @@ -310,7 +315,7 @@ std::vector> InputState::synthesizePointerDownEvents nsecs_t currentTime) { std::vector> events; for (MotionMemento& memento : mMotionMementos) { - if (!(memento.source & AINPUT_SOURCE_CLASS_POINTER)) { + if (!isFromSource(memento.source, AINPUT_SOURCE_CLASS_POINTER)) { continue; } @@ -443,7 +448,7 @@ void InputState::mergePointerStateTo(InputState& other) { MotionMemento& memento = mMotionMementos[i]; // Since we support split pointers we need to merge touch events // from the same source + device + screen. - if (memento.source & AINPUT_SOURCE_CLASS_POINTER) { + if (isFromSource(memento.source, AINPUT_SOURCE_CLASS_POINTER)) { bool merged = false; for (size_t j = 0; j < other.mMotionMementos.size(); j++) { MotionMemento& otherMemento = other.mMotionMementos[j]; diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp index 11f3413df8..343630c0da 100644 --- a/services/inputflinger/dispatcher/InputTarget.cpp +++ b/services/inputflinger/dispatcher/InputTarget.cpp @@ -16,7 +16,9 @@ #include "InputTarget.h" +#include #include +#include #include #include @@ -34,7 +36,10 @@ void InputTarget::addPointers(std::bitset newPointerIds, } // Ensure that the new set of pointers doesn't overlap with the current set of pointers. - LOG_ALWAYS_FATAL_IF((pointerIds & newPointerIds).any()); + if ((pointerIds & newPointerIds).any()) { + LOG(FATAL) << __func__ << " - overlap with incoming pointers " + << bitsetToString(newPointerIds) << " in " << *this; + } pointerIds |= newPointerIds; for (size_t i = 0; i < newPointerIds.size(); i++) { diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 79f4d1ec64..f0602dfbad 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -50,6 +51,8 @@ namespace android::inputdispatcher { using namespace ftl::flag_operators; using testing::AllOf; +namespace { + // An arbitrary time value. static constexpr nsecs_t ARBITRARY_TIME = 1234; @@ -136,6 +139,10 @@ struct PointF { auto operator<=>(const PointF&) const = default; }; +inline std::string pointFToString(const PointF& p) { + return std::string("(") + std::to_string(p.x) + ", " + std::to_string(p.y) + ")"; +} + /** * Return a DOWN key event with KEYCODE_A. */ @@ -148,13 +155,8 @@ static KeyEvent getTestKeyEvent() { return event; } -static void assertMotionAction(int32_t expectedAction, int32_t receivedAction) { - ASSERT_EQ(expectedAction, receivedAction) - << "expected " << MotionEvent::actionToString(expectedAction) << ", got " - << MotionEvent::actionToString(receivedAction); -} - MATCHER_P(WithDownTime, downTime, "InputEvent with specified downTime") { + *result_listener << "expected downTime " << downTime << ", but got " << arg.getDownTime(); return arg.getDownTime() == downTime; } @@ -165,6 +167,7 @@ MATCHER_P(WithSource, source, "InputEvent with specified source") { } MATCHER_P(WithFlags, flags, "InputEvent with specified flags") { + *result_listener << "expected flags " << std::hex << flags << ", but got " << arg.getFlags(); return arg.getFlags() == flags; } @@ -173,10 +176,16 @@ MATCHER_P2(WithCoords, x, y, "MotionEvent with specified coordinates") { *result_listener << "Expected 1 pointer, got " << arg.getPointerCount(); return false; } - return arg.getX(/*pointerIndex=*/0) == x && arg.getY(/*pointerIndex=*/0) == y; + const float receivedX = arg.getX(/*pointerIndex=*/0); + const float receivedY = arg.getY(/*pointerIndex=*/0); + *result_listener << "expected coords (" << x << ", " << y << "), but got (" << receivedX << ", " + << receivedY << ")"; + return receivedX == x && receivedY == y; } MATCHER_P(WithPointerCount, pointerCount, "MotionEvent with specified number of pointers") { + *result_listener << "expected pointerCount " << pointerCount << ", but got " + << arg.getPointerCount(); return arg.getPointerCount() == pointerCount; } @@ -187,6 +196,8 @@ MATCHER_P(WithPointers, pointers, "MotionEvent with specified pointers") { const int32_t pointerId = arg.getPointerId(pointerIndex); actualPointers[pointerId] = {arg.getX(pointerIndex), arg.getY(pointerIndex)}; } + *result_listener << "expected pointers " << dumpMap(pointers, constToString, pointFToString) + << ", but got " << dumpMap(actualPointers, constToString, pointFToString); return pointers == actualPointers; } @@ -617,6 +628,7 @@ private: mFilteredEvent = nullptr; } }; +} // namespace // --- InputDispatcherTest --- @@ -959,7 +971,7 @@ public: switch (expectedEventType) { case InputEventType::KEY: { const KeyEvent& keyEvent = static_cast(*event); - EXPECT_EQ(expectedAction, keyEvent.getAction()); + ASSERT_THAT(keyEvent, WithKeyAction(expectedAction)); if (expectedFlags.has_value()) { EXPECT_EQ(expectedFlags.value(), keyEvent.getFlags()); } @@ -967,8 +979,7 @@ public: } case InputEventType::MOTION: { const MotionEvent& motionEvent = static_cast(*event); - assertMotionAction(expectedAction, motionEvent.getAction()); - + ASSERT_THAT(motionEvent, WithMotionAction(expectedAction)); if (expectedFlags.has_value()) { EXPECT_EQ(expectedFlags.value(), motionEvent.getFlags()); } @@ -6467,7 +6478,7 @@ protected: ASSERT_NE(nullptr, motionEvent) << name.c_str() << ": consumer should have returned non-NULL event."; - assertMotionAction(expectedAction, motionEvent->getAction()); + ASSERT_THAT(*motionEvent, WithMotionAction(expectedAction)); ASSERT_EQ(points.size(), motionEvent->getPointerCount()); for (size_t i = 0; i < points.size(); i++) { -- GitLab From 7e6446c3da42c774ff702fc1dd202b3986bcebe7 Mon Sep 17 00:00:00 2001 From: Akhilesh C Sanikop Date: Thu, 28 Sep 2023 13:52:13 +0530 Subject: [PATCH 0716/1187] Refactored surfaceflinger_frametracer_fuzzer The following are the updates to the fuzzer: 1. Randomized APIs 2. Randomized 'signalTime' parameter 3. Coverage improved from 62% to 85% Test: ./surfaceflinger_frametracer_fuzzer Bug: 302634417 exec/s: 500 Change-Id: I920dce897d2834cb1f156c39c82c358a0ceb8699 --- .../surfaceflinger_frametracer_fuzzer.cpp | 78 ++++++++++++------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp index a22a778989..8978971539 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp @@ -23,12 +23,19 @@ namespace android::fuzz { using namespace google::protobuf; -constexpr size_t kMaxStringSize = 100; +constexpr size_t kMaxStringSize = 256; constexpr size_t kMinLayerIds = 1; constexpr size_t kMaxLayerIds = 10; +constexpr int32_t kMinRange = 0; constexpr int32_t kConfigDuration = 500; constexpr int32_t kBufferSize = 1024; constexpr int32_t kTimeOffset = 100000; +constexpr perfetto::BackendType backendTypes[] = { + perfetto::kUnspecifiedBackend, + perfetto::kInProcessBackend, + perfetto::kSystemBackend, + perfetto::kCustomBackend, +}; class FrameTracerFuzzer { public: @@ -47,24 +54,25 @@ public: void process(); private: - std::unique_ptr getTracingSessionForTest(); void traceTimestamp(); - std::vector generateLayerIds(size_t numLayerIds); void traceTimestamp(std::vector layerIds, size_t numLayerIds); void traceFence(std::vector layerIds, size_t numLayerIds); + std::unique_ptr getTracingSessionForTest(); std::unique_ptr mFrameTracer = nullptr; - FuzzedDataProvider mFdp; + std::vector generateLayerIds(size_t numLayerIds); android::FenceToFenceTimeMap mFenceFactory; + FuzzedDataProvider mFdp; }; std::unique_ptr FrameTracerFuzzer::getTracingSessionForTest() { perfetto::TraceConfig cfg; - cfg.set_duration_ms(kConfigDuration); - cfg.add_buffers()->set_size_kb(kBufferSize); + cfg.set_duration_ms(mFdp.ConsumeIntegralInRange(kMinRange, kConfigDuration)); + cfg.add_buffers()->set_size_kb(mFdp.ConsumeIntegralInRange(kMinRange, kBufferSize)); auto* dsCfg = cfg.add_data_sources()->mutable_config(); dsCfg->set_name(android::FrameTracer::kFrameTracerDataSource); - auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend); + auto tracingSession = + perfetto::Tracing::NewTrace(mFdp.PickValueInArray(backendTypes)); tracingSession->Setup(cfg); return tracingSession; } @@ -78,17 +86,23 @@ std::vector FrameTracerFuzzer::generateLayerIds(size_t numLayerIds) { } void FrameTracerFuzzer::traceTimestamp(std::vector layerIds, size_t numLayerIds) { - int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange(0, numLayerIds - 1)); + uint32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange(0, numLayerIds - 1)); + android::FrameTracer::FrameEvent::BufferEventType type = static_cast< + android::FrameTracer::FrameEvent::BufferEventType>( + mFdp.ConsumeIntegralInRange(android::FrameTracer::FrameEvent::UNSPECIFIED, + android::FrameTracer::FrameEvent::CANCEL)); mFrameTracer->traceTimestamp(layerId, mFdp.ConsumeIntegral() /*bufferID*/, mFdp.ConsumeIntegral() /*frameNumber*/, - mFdp.ConsumeIntegral() /*timestamp*/, - android::FrameTracer::FrameEvent::UNSPECIFIED, + mFdp.ConsumeIntegral() /*timestamp*/, type, mFdp.ConsumeIntegral() /*duration*/); } void FrameTracerFuzzer::traceFence(std::vector layerIds, size_t numLayerIds) { - const nsecs_t signalTime = systemTime(); - const nsecs_t startTime = signalTime + kTimeOffset; + const nsecs_t signalTime = + mFdp.ConsumeBool() ? android::Fence::SIGNAL_TIME_PENDING : systemTime(); + const nsecs_t startTime = (signalTime == android::Fence::SIGNAL_TIME_PENDING) + ? signalTime - kTimeOffset + : signalTime + kTimeOffset; auto fence = mFenceFactory.createFenceTimeForTest(android::Fence::NO_FENCE); mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, signalTime); int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange(0, numLayerIds - 1)); @@ -98,26 +112,30 @@ void FrameTracerFuzzer::traceFence(std::vector layerIds, size_t numLaye } void FrameTracerFuzzer::process() { - mFrameTracer->registerDataSource(); - - auto tracingSession = getTracingSessionForTest(); - tracingSession->StartBlocking(); - - size_t numLayerIds = mFdp.ConsumeIntegralInRange(kMinLayerIds, kMaxLayerIds); - std::vector layerIds = generateLayerIds(numLayerIds); - - for (auto it = layerIds.begin(); it != layerIds.end(); ++it) { - mFrameTracer->traceNewLayer(*it /*layerId*/, - mFdp.ConsumeRandomLengthString(kMaxStringSize) /*layerName*/); + std::vector layerIds = + generateLayerIds(mFdp.ConsumeIntegralInRange(kMinLayerIds, kMaxLayerIds)); + + while (mFdp.remaining_bytes()) { + auto invokeFrametracerAPI = mFdp.PickValueInArray>({ + [&]() { mFrameTracer->registerDataSource(); }, + [&]() { + auto tracingSession = getTracingSessionForTest(); + tracingSession->StartBlocking(); + }, + [&]() { traceTimestamp(layerIds, layerIds.size()); }, + [&]() { traceFence(layerIds, layerIds.size()); }, + [&]() { + for (auto it = layerIds.begin(); it != layerIds.end(); ++it) { + mFrameTracer->traceNewLayer(*it /*layerId*/, + mFdp.ConsumeRandomLengthString( + kMaxStringSize) /*layerName*/); + } + }, + [&]() { mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, systemTime()); }, + }); + invokeFrametracerAPI(); } - traceTimestamp(layerIds, numLayerIds); - traceFence(layerIds, numLayerIds); - - mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, systemTime()); - - tracingSession->StopBlocking(); - for (auto it = layerIds.begin(); it != layerIds.end(); ++it) { mFrameTracer->onDestroy(*it); } -- GitLab From a119a69b066f7bb03d51665a35bef17cecacbe95 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Fri, 29 Sep 2023 03:22:22 -0700 Subject: [PATCH 0717/1187] TFLite: Accommodate change in std::span size type The WIP version of std::span in external/libcxx uses a ptrdiff_t size, but the finalized C++20 std::span uses a size_t size instead. Comparing the size_t size() against a signed integer causes a -Werror,-Wsign-compare build error. Cast the size() expression so that the code compiles with both the old and the new libc++. Bug: 175635923 Test: m MODULES-IN-frameworks-native Change-Id: I50cc5354b6205b62918157b69df6cf1aa7bad6cc --- .../tests/TfLiteMotionPredictor_test.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libs/input/tests/TfLiteMotionPredictor_test.cpp b/libs/input/tests/TfLiteMotionPredictor_test.cpp index b5ed9e4430..c3ac0b7cfb 100644 --- a/libs/input/tests/TfLiteMotionPredictor_test.cpp +++ b/libs/input/tests/TfLiteMotionPredictor_test.cpp @@ -130,19 +130,19 @@ TEST(TfLiteMotionPredictorTest, ModelInputOutputLength) { std::unique_ptr model = TfLiteMotionPredictorModel::create(); ASSERT_GT(model->inputLength(), 0u); - const int inputLength = model->inputLength(); - ASSERT_EQ(inputLength, model->inputR().size()); - ASSERT_EQ(inputLength, model->inputPhi().size()); - ASSERT_EQ(inputLength, model->inputPressure().size()); - ASSERT_EQ(inputLength, model->inputOrientation().size()); - ASSERT_EQ(inputLength, model->inputTilt().size()); + const size_t inputLength = model->inputLength(); + ASSERT_EQ(inputLength, static_cast(model->inputR().size())); + ASSERT_EQ(inputLength, static_cast(model->inputPhi().size())); + ASSERT_EQ(inputLength, static_cast(model->inputPressure().size())); + ASSERT_EQ(inputLength, static_cast(model->inputOrientation().size())); + ASSERT_EQ(inputLength, static_cast(model->inputTilt().size())); ASSERT_TRUE(model->invoke()); - const int outputLength = model->outputLength(); - ASSERT_EQ(outputLength, model->outputR().size()); - ASSERT_EQ(outputLength, model->outputPhi().size()); - ASSERT_EQ(outputLength, model->outputPressure().size()); + const size_t outputLength = model->outputLength(); + ASSERT_EQ(outputLength, static_cast(model->outputR().size())); + ASSERT_EQ(outputLength, static_cast(model->outputPhi().size())); + ASSERT_EQ(outputLength, static_cast(model->outputPressure().size())); } TEST(TfLiteMotionPredictorTest, ModelOutput) { -- GitLab From ec8cc07d8ae214453c83cbe00404b9adf73d49c1 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Fri, 29 Sep 2023 03:46:39 -0700 Subject: [PATCH 0718/1187] [sf] Stop inheriting from std::unary_function std::unary_function was deprecated in C++11 and removed in C++17. Its function is to provide two typedefs, `argument_type` and `result_type`, but these are not needed for std::find_if's Predicate, so stop using std::unary_function. Bug: 175635923 Test: m MODULES-IN-frameworks-native Change-Id: Ie16ada6f76bee7d9f248dc8349a095b50777c92d --- .../surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp index 2fcb9e0b48..3c09422e42 100644 --- a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp +++ b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp @@ -126,7 +126,7 @@ inline void PrintTo(const LayerInfo& info, ::std::ostream* os) { << info.touchableRegionBounds.right << "," << info.touchableRegionBounds.bottom << "}"; } -struct find_id : std::unary_function { +struct find_id { uint64_t id; find_id(uint64_t id) : id(id) {} bool operator()(LayerInfo const& m) const { return m.id == id; } -- GitLab From 5b7855f224cc048fe8c765ad760bca6fd77ae89f Mon Sep 17 00:00:00 2001 From: Alex Careja Date: Wed, 27 Sep 2023 11:11:22 +0000 Subject: [PATCH 0719/1187] Remove contention from Render Engine early return An early return optimization path to skip post render cleanup in some cases was resulting in lock contention so remove it and replace it with an atomic boolean. Bug: 273708680 Test: boot device, observe boot animation is smooth Change-Id: Idd989a2e91a8ef1b71aef4e1c439eb0576511c79 --- .../tests/RenderEngineThreadedTest.cpp | 20 +++++++++++++++++-- .../threaded/RenderEngineThreaded.cpp | 5 +++-- .../threaded/RenderEngineThreaded.h | 1 + 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index 475dc15788..7289fe721d 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -98,7 +98,6 @@ TEST_F(RenderEngineThreadedTest, supportsProtectedContent_returnsTrue) { } TEST_F(RenderEngineThreadedTest, PostRenderCleanup_skipped) { - EXPECT_CALL(*mRenderEngine, canSkipPostRenderCleanup()).WillOnce(Return(true)); EXPECT_CALL(*mRenderEngine, cleanupPostRender()).Times(0); mThreadedRE->cleanupPostRender(); @@ -107,8 +106,25 @@ TEST_F(RenderEngineThreadedTest, PostRenderCleanup_skipped) { } TEST_F(RenderEngineThreadedTest, PostRenderCleanup_notSkipped) { - EXPECT_CALL(*mRenderEngine, canSkipPostRenderCleanup()).WillOnce(Return(false)); + renderengine::DisplaySettings settings; + std::vector layers; + std::shared_ptr buffer = std::make_shared< + renderengine::impl:: + ExternalTexture>(sp::make(), *mRenderEngine, + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage::WRITEABLE); + base::unique_fd bufferFence; + + EXPECT_CALL(*mRenderEngine, useProtectedContext(false)); + EXPECT_CALL(*mRenderEngine, drawLayersInternal) + .WillOnce([&](const std::shared_ptr>&& resultPromise, + const renderengine::DisplaySettings&, + const std::vector&, + const std::shared_ptr&, + base::unique_fd&&) { resultPromise->set_value(Fence::NO_FENCE); }); EXPECT_CALL(*mRenderEngine, cleanupPostRender()).WillOnce(Return()); + ftl::Future future = + mThreadedRE->drawLayers(settings, layers, buffer, std::move(bufferFence)); mThreadedRE->cleanupPostRender(); // call ANY synchronous function to ensure that cleanupPostRender has completed. diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index 2cb66cbebc..786a6fef12 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -231,13 +231,13 @@ void RenderEngineThreaded::cleanupPostRender() { ATRACE_NAME("REThreaded::cleanupPostRender"); instance.cleanupPostRender(); }); + mNeedsPostRenderCleanup = false; } mCondition.notify_one(); } bool RenderEngineThreaded::canSkipPostRenderCleanup() const { - waitUntilInitialized(); - return mRenderEngine->canSkipPostRenderCleanup(); + return !mNeedsPostRenderCleanup; } void RenderEngineThreaded::drawLayersInternal( @@ -257,6 +257,7 @@ ftl::Future RenderEngineThreaded::drawLayers( int fd = bufferFence.release(); { std::lock_guard lock(mThreadMutex); + mNeedsPostRenderCleanup = true; mFunctionCalls.push( [resultPromise, display, layers, buffer, fd](renderengine::RenderEngine& instance) { ATRACE_NAME("REThreaded::drawLayers"); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 43ec011b73..1093f5fad3 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -89,6 +89,7 @@ private: mutable std::mutex mThreadMutex; std::thread mThread GUARDED_BY(mThreadMutex); std::atomic mRunning = true; + std::atomic mNeedsPostRenderCleanup = false; using Work = std::function; mutable std::queue mFunctionCalls GUARDED_BY(mThreadMutex); -- GitLab From 84541d153da755916306ec1181c623cb3c64cb09 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Fri, 29 Sep 2023 11:00:23 -0500 Subject: [PATCH 0720/1187] Synchronize access to Transaction::sApplyToken Speculative fix for flaky test AddWidgetTest#testDragIcon. Bug: 301158583 Test: presubmits Change-Id: Idc2e37d8b8e596e4a729621ecc5b7d5c8d7299a5 --- libs/gui/SurfaceComposerClient.cpp | 6 +++++- libs/gui/include/gui/SurfaceComposerClient.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 038764b800..8a57f925ec 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1227,7 +1227,7 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay flags |= ISurfaceComposer::eEarlyWakeupEnd; } - sp applyToken = mApplyToken ? mApplyToken : sApplyToken; + sp applyToken = mApplyToken ? mApplyToken : getDefaultApplyToken(); sp sf(ComposerService::getComposerService()); sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken, @@ -1249,11 +1249,15 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay sp SurfaceComposerClient::Transaction::sApplyToken = new BBinder(); +std::mutex SurfaceComposerClient::Transaction::sApplyTokenMutex; + sp SurfaceComposerClient::Transaction::getDefaultApplyToken() { + std::scoped_lock lock{sApplyTokenMutex}; return sApplyToken; } void SurfaceComposerClient::Transaction::setDefaultApplyToken(sp applyToken) { + std::scoped_lock lock{sApplyTokenMutex}; sApplyToken = applyToken; } diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 42e3c164ed..26b1fbd2ba 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -422,6 +422,7 @@ public: class Transaction : public Parcelable { private: static sp sApplyToken; + static std::mutex sApplyTokenMutex; void releaseBufferIfOverwriting(const layer_state_t& state); static void mergeFrameTimelineInfo(FrameTimelineInfo& t, const FrameTimelineInfo& other); -- GitLab From 7da995f39ed09db6b81aaab9534dec9615f314ff Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Wed, 27 Sep 2023 16:53:40 -0500 Subject: [PATCH 0721/1187] Ack messages when WindowInfosListeners are removed This fix updates WindowInfosListenersInvoker::removeWindowInfosListener to automatically ack any unacked messages associated with the listener being removed. This fixes a race where the invoker may send the listener a message while the client is removing the listener and terminating its process. Bug: 300644295 Test: WindowInfosListenerInvokerTest Change-Id: I93a5fbecb03bb8eeea8d8385bdf906051d595ae2 (cherry picked from commit ed234c620bee72bf0bfc603642ea42a3004e5145) Merged-In: I93a5fbecb03bb8eeea8d8385bdf906051d595ae2 --- .../WindowInfosListenerInvoker.cpp | 34 +++++++++-------- .../WindowInfosListenerInvoker.h | 1 + .../WindowInfosListenerInvokerTest.cpp | 38 +++++++++++++++++++ 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index 7062a4e3a7..effbfdb896 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -56,29 +56,33 @@ void WindowInfosListenerInvoker::removeWindowInfosListener( ATRACE_NAME("WindowInfosListenerInvoker::removeWindowInfosListener"); sp asBinder = IInterface::asBinder(listener); asBinder->unlinkToDeath(sp::fromExisting(this)); - mWindowInfosListeners.erase(asBinder); + eraseListenerAndAckMessages(asBinder); }}); } void WindowInfosListenerInvoker::binderDied(const wp& who) { BackgroundExecutor::getInstance().sendCallbacks({[this, who]() { ATRACE_NAME("WindowInfosListenerInvoker::binderDied"); - auto it = mWindowInfosListeners.find(who); - int64_t listenerId = it->second.first; - mWindowInfosListeners.erase(who); - - std::vector vsyncIds; - for (auto& [vsyncId, state] : mUnackedState) { - if (std::find(state.unackedListenerIds.begin(), state.unackedListenerIds.end(), - listenerId) != state.unackedListenerIds.end()) { - vsyncIds.push_back(vsyncId); - } - } + eraseListenerAndAckMessages(who); + }}); +} + +void WindowInfosListenerInvoker::eraseListenerAndAckMessages(const wp& binder) { + auto it = mWindowInfosListeners.find(binder); + int64_t listenerId = it->second.first; + mWindowInfosListeners.erase(binder); - for (int64_t vsyncId : vsyncIds) { - ackWindowInfosReceived(vsyncId, listenerId); + std::vector vsyncIds; + for (auto& [vsyncId, state] : mUnackedState) { + if (std::find(state.unackedListenerIds.begin(), state.unackedListenerIds.end(), + listenerId) != state.unackedListenerIds.end()) { + vsyncIds.push_back(vsyncId); } - }}); + } + + for (int64_t vsyncId : vsyncIds) { + ackWindowInfosReceived(vsyncId, listenerId); + } } void WindowInfosListenerInvoker::windowInfosChanged( diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index f36b0edd7d..261fd0ff3b 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -67,6 +67,7 @@ private: std::optional mDelayedUpdate; WindowInfosReportedListenerSet mReportedListeners; + void eraseListenerAndAckMessages(const wp&); struct UnackedState { ftl::SmallVector unackedListenerIds; diff --git a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp index c7b845e668..cfb047c877 100644 --- a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp +++ b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp @@ -245,4 +245,42 @@ TEST_F(WindowInfosListenerInvokerTest, noListeners) { EXPECT_EQ(callCount, 1); } +// Test that WindowInfosListenerInvoker#removeWindowInfosListener acks any unacked messages for +// the removed listener. +TEST_F(WindowInfosListenerInvokerTest, removeListenerAcks) { + // Don't ack in this listener to ensure there's an unacked message when the listener is later + // removed. + gui::WindowInfosListenerInfo listenerToBeRemovedInfo; + auto listenerToBeRemoved = sp::make([](const gui::WindowInfosUpdate&) {}); + mInvoker->addWindowInfosListener(listenerToBeRemoved, &listenerToBeRemovedInfo); + + std::mutex mutex; + std::condition_variable cv; + int callCount = 0; + gui::WindowInfosListenerInfo listenerInfo; + mInvoker->addWindowInfosListener(sp::make([&](const gui::WindowInfosUpdate& update) { + std::scoped_lock lock{mutex}; + callCount++; + cv.notify_one(); + listenerInfo.windowInfosPublisher + ->ackWindowInfosReceived(update.vsyncId, + listenerInfo.listenerId); + }), + &listenerInfo); + + BackgroundExecutor::getInstance().sendCallbacks( + {[&]() { mInvoker->windowInfosChanged({}, {}, false); }}); + mInvoker->removeWindowInfosListener(listenerToBeRemoved); + BackgroundExecutor::getInstance().sendCallbacks( + {[&]() { mInvoker->windowInfosChanged({}, {}, false); }}); + + // Verify that the second listener is called twice. If unacked messages aren't removed when the + // first listener is removed, this will fail. + { + std::unique_lock lock{mutex}; + cv.wait(lock, [&]() { return callCount == 2; }); + } + EXPECT_EQ(callCount, 2); +} + } // namespace android -- GitLab From 3fbe326861bc22e40847b9edf3e905f4bd41d645 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 29 Sep 2023 17:07:00 -0700 Subject: [PATCH 0722/1187] Pull out FrameRateCompatibility definition to avoid circular dependencies Test: presubmit Bug: 300701739 Change-Id: I7a1cc64a786fca5a7a273522dc4735439b44fd13 --- .../FrontEnd/LayerSnapshotBuilder.cpp | 2 +- .../FrontEnd/RequestedLayerState.cpp | 3 +- services/surfaceflinger/Layer.cpp | 2 +- services/surfaceflinger/Layer.h | 2 +- .../Scheduler/FrameRateCompatibility.h | 38 +++++++++++++ .../surfaceflinger/Scheduler/LayerHistory.cpp | 6 +- .../surfaceflinger/Scheduler/LayerInfo.cpp | 2 +- services/surfaceflinger/Scheduler/LayerInfo.h | 19 +------ .../tests/unittests/LayerHistoryTest.cpp | 4 +- .../tests/unittests/LayerSnapshotTest.cpp | 57 +++++++++---------- .../tests/unittests/mock/MockLayer.h | 5 +- 11 files changed, 78 insertions(+), 62 deletions(-) create mode 100644 services/surfaceflinger/Scheduler/FrameRateCompatibility.h diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 4c9fb0655b..55be398bd0 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -666,7 +666,7 @@ void LayerSnapshotBuilder::updateFrameRateFromChildSnapshot(LayerSnapshot& snaps return; } - using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; + using FrameRateCompatibility = scheduler::FrameRateCompatibility; if (snapshot.frameRate.isValid()) { // we already have a valid framerate. return; diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index fcc1e61c95..a4c7852801 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -122,8 +122,7 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) isTrustedOverlay = false; dropInputMode = gui::DropInputMode::NONE; dimmingEnabled = true; - defaultFrameRateCompatibility = - static_cast(scheduler::LayerInfo::FrameRateCompatibility::Default); + defaultFrameRateCompatibility = static_cast(scheduler::FrameRateCompatibility::Default); frameRateCategory = static_cast(FrameRateCategory::Default); frameRateSelectionStrategy = static_cast(scheduler::LayerInfo::FrameRateSelectionStrategy::Self); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 31b5e28e4e..cbed0e7a98 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1160,7 +1160,7 @@ bool Layer::setDefaultFrameRateCompatibility(FrameRateCompatibility compatibilit return true; } -scheduler::LayerInfo::FrameRateCompatibility Layer::getDefaultFrameRateCompatibility() const { +scheduler::FrameRateCompatibility Layer::getDefaultFrameRateCompatibility() const { return mDrawingState.defaultFrameRateCompatibility; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index d5e2185a5e..dbde96f115 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -111,7 +111,7 @@ public: }; using FrameRate = scheduler::LayerInfo::FrameRate; - using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; + using FrameRateCompatibility = scheduler::FrameRateCompatibility; using FrameRateSelectionStrategy = scheduler::LayerInfo::FrameRateSelectionStrategy; struct State { diff --git a/services/surfaceflinger/Scheduler/FrameRateCompatibility.h b/services/surfaceflinger/Scheduler/FrameRateCompatibility.h new file mode 100644 index 0000000000..405c982494 --- /dev/null +++ b/services/surfaceflinger/Scheduler/FrameRateCompatibility.h @@ -0,0 +1,38 @@ +/* + * Copyright 2023 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 + +namespace android::scheduler { +// FrameRateCompatibility specifies how we should interpret the frame rate associated with +// the layer. +enum class FrameRateCompatibility { + Default, // Layer didn't specify any specific handling strategy + + Min, // Layer needs the minimum frame rate. + + Exact, // Layer needs the exact frame rate. + + ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the + // content properly. Any other value will result in a pull down. + + NoVote, // Layer doesn't have any requirements for the refresh rate and + // should not be considered when the display refresh rate is determined. + + ftl_last = NoVote +}; + +} // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 6b5327aa64..b98b8007ac 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -76,12 +76,12 @@ void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) { ALOGD("%s: %s @ %d Hz", __FUNCTION__, info.getName().c_str(), fps); } -LayerHistory::LayerVoteType getVoteType(LayerInfo::FrameRateCompatibility compatibility, +LayerHistory::LayerVoteType getVoteType(FrameRateCompatibility compatibility, bool contentDetectionEnabled) { LayerHistory::LayerVoteType voteType; - if (!contentDetectionEnabled || compatibility == LayerInfo::FrameRateCompatibility::NoVote) { + if (!contentDetectionEnabled || compatibility == FrameRateCompatibility::NoVote) { voteType = LayerHistory::LayerVoteType::NoVote; - } else if (compatibility == LayerInfo::FrameRateCompatibility::Min) { + } else if (compatibility == FrameRateCompatibility::Min) { voteType = LayerHistory::LayerVoteType::Min; } else { voteType = LayerHistory::LayerVoteType::Heuristic; diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 875bdc84f5..dd96930a06 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -455,7 +455,7 @@ bool LayerInfo::RefreshRateHistory::isConsistent() const { return consistent; } -LayerInfo::FrameRateCompatibility LayerInfo::FrameRate::convertCompatibility(int8_t compatibility) { +FrameRateCompatibility LayerInfo::FrameRate::convertCompatibility(int8_t compatibility) { switch (compatibility) { case ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT: return FrameRateCompatibility::Default; diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 129b4c44d4..6286b285cf 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -28,6 +28,7 @@ #include #include +#include "FrameRateCompatibility.h" #include "LayerHistory.h" #include "RefreshRateSelector.h" @@ -78,24 +79,6 @@ public: using RefreshRateVotes = ftl::SmallVector; - // FrameRateCompatibility specifies how we should interpret the frame rate associated with - // the layer. - enum class FrameRateCompatibility { - Default, // Layer didn't specify any specific handling strategy - - Min, // Layer needs the minimum frame rate. - - Exact, // Layer needs the exact frame rate. - - ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the - // content properly. Any other value will result in a pull down. - - NoVote, // Layer doesn't have any requirements for the refresh rate and - // should not be considered when the display refresh rate is determined. - - ftl_last = NoVote - }; - enum class FrameRateSelectionStrategy { Self, OverrideChildren, diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 7e3e61f6fb..cc7a45c78f 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -152,7 +152,7 @@ TEST_F(LayerHistoryTest, singleLayerNoVoteDefaultCompatibility) { EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer, getDefaultFrameRateCompatibility()) - .WillOnce(Return(LayerInfo::FrameRateCompatibility::NoVote)); + .WillOnce(Return(FrameRateCompatibility::NoVote)); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); @@ -176,7 +176,7 @@ TEST_F(LayerHistoryTest, singleLayerMinVoteDefaultCompatibility) { EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); EXPECT_CALL(*layer, getDefaultFrameRateCompatibility()) - .WillOnce(Return(LayerInfo::FrameRateCompatibility::Min)); + .WillOnce(Return(FrameRateCompatibility::Min)); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 1a9233d12c..69316bf4e5 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -315,14 +315,11 @@ TEST_F(LayerSnapshotTest, NoLayerVoteForParentWithChildVotes) { UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); EXPECT_EQ(getSnapshot(11)->frameRate.vote.rate.getIntValue(), 90); - EXPECT_EQ(getSnapshot(11)->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Exact); + EXPECT_EQ(getSnapshot(11)->frameRate.vote.type, scheduler::FrameRateCompatibility::Exact); EXPECT_EQ(getSnapshot(111)->frameRate.vote.rate.getIntValue(), 90); - EXPECT_EQ(getSnapshot(111)->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Exact); + EXPECT_EQ(getSnapshot(111)->frameRate.vote.type, scheduler::FrameRateCompatibility::Exact); EXPECT_EQ(getSnapshot(1)->frameRate.vote.rate.getIntValue(), 0); - EXPECT_EQ(getSnapshot(1)->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::NoVote); + EXPECT_EQ(getSnapshot(1)->frameRate.vote.type, scheduler::FrameRateCompatibility::NoVote); } TEST_F(LayerSnapshotTest, CanCropTouchableRegion) { @@ -550,20 +547,20 @@ TEST_F(LayerSnapshotTest, framerate) { // verify parent is gets no vote EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::NoVote); + scheduler::FrameRateCompatibility::NoVote); EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate)); // verify layer and children get the requested votes EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 11})->changes.test(RequestedLayerState::Changes::FrameRate)); EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 111})->changes.test(RequestedLayerState::Changes::FrameRate)); // reparent and verify the child gets the new parent's framerate @@ -574,23 +571,23 @@ TEST_F(LayerSnapshotTest, framerate) { // verify parent is gets no vote EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::NoVote); + scheduler::FrameRateCompatibility::NoVote); // verify layer and children get the requested votes EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.rate.getValue(), 244.f); EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate)); // reparent and verify the new parent gets no vote @@ -601,30 +598,30 @@ TEST_F(LayerSnapshotTest, framerate) { // verify old parent has invalid framerate (default) EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate)); // verify new parent get no vote EXPECT_FALSE(getSnapshot({.id = 2})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 2})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::NoVote); + scheduler::FrameRateCompatibility::NoVote); EXPECT_TRUE(getSnapshot({.id = 2})->changes.test(RequestedLayerState::Changes::FrameRate)); // verify layer and children get the requested votes (unchanged) EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.rate.getValue(), 244.f); EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); } TEST_F(LayerSnapshotTest, translateDataspace) { @@ -653,33 +650,33 @@ TEST_F(LayerSnapshotTest, frameRateWithCategory) { // verify parent 1 gets no vote EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::NoVote); + scheduler::FrameRateCompatibility::NoVote); EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate)); // verify layer 11 and children 111 get the requested votes EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 11})->changes.test(RequestedLayerState::Changes::FrameRate)); EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 111})->changes.test(RequestedLayerState::Changes::FrameRate)); // verify parent 12 gets no vote EXPECT_FALSE(getSnapshot({.id = 12})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 12})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::NoVote); + scheduler::FrameRateCompatibility::NoVote); EXPECT_TRUE(getSnapshot({.id = 12})->changes.test(RequestedLayerState::Changes::FrameRate)); // verify layer 122 and children 1221 get the requested votes EXPECT_FALSE(getSnapshot({.id = 122})->frameRate.vote.rate.isValid()); EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.isValid()); EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_EQ(getSnapshot({.id = 122})->frameRate.category, FrameRateCategory::Normal); EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate)); EXPECT_TRUE( @@ -688,7 +685,7 @@ TEST_F(LayerSnapshotTest, frameRateWithCategory) { EXPECT_FALSE(getSnapshot({.id = 1221})->frameRate.vote.rate.isValid()); EXPECT_TRUE(getSnapshot({.id = 1221})->frameRate.isValid()); EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.category, FrameRateCategory::Normal); EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate)); EXPECT_TRUE( @@ -713,32 +710,32 @@ TEST_F(LayerSnapshotTest, frameRateWithCategory) { // verify parent is gets no vote EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::NoVote); + scheduler::FrameRateCompatibility::NoVote); // verify layer 11 and children 111 get the requested votes EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.rate.getValue(), 244.f); EXPECT_EQ(getSnapshot({.id = 11})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.rate.getValue(), 244.f); EXPECT_EQ(getSnapshot({.id = 111})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); // verify layer 122 and children 1221 get the requested category vote (unchanged from // reparenting) EXPECT_FALSE(getSnapshot({.id = 122})->frameRate.vote.rate.isValid()); EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.isValid()); EXPECT_EQ(getSnapshot({.id = 122})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_EQ(getSnapshot({.id = 122})->frameRate.category, FrameRateCategory::Normal); EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate)); EXPECT_FALSE(getSnapshot({.id = 1221})->frameRate.vote.rate.isValid()); EXPECT_TRUE(getSnapshot({.id = 1221})->frameRate.isValid()); EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::Default); + scheduler::FrameRateCompatibility::Default); EXPECT_EQ(getSnapshot({.id = 1221})->frameRate.category, FrameRateCategory::Normal); EXPECT_TRUE(getSnapshot({.id = 1221})->changes.test(RequestedLayerState::Changes::FrameRate)); } @@ -762,7 +759,7 @@ TEST_F(LayerSnapshotTest, frameRateSelectionStrategy) { // verify parent 1 gets no vote EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid()); EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type, - scheduler::LayerInfo::FrameRateCompatibility::NoVote); + scheduler::FrameRateCompatibility::NoVote); EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate)); // verify layer 12 and all descendants (121, 122, 1221) get the requested vote diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h index 50e07fc92c..4cc78febee 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -25,7 +25,7 @@ public: MockLayer(SurfaceFlinger* flinger, std::string name) : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) { EXPECT_CALL(*this, getDefaultFrameRateCompatibility()) - .WillOnce(testing::Return(scheduler::LayerInfo::FrameRateCompatibility::Default)); + .WillOnce(testing::Return(scheduler::FrameRateCompatibility::Default)); } explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {} @@ -34,8 +34,7 @@ public: MOCK_CONST_METHOD0(isVisible, bool()); MOCK_METHOD1(createClone, sp(uint32_t)); MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate()); - MOCK_CONST_METHOD0(getDefaultFrameRateCompatibility, - scheduler::LayerInfo::FrameRateCompatibility()); + MOCK_CONST_METHOD0(getDefaultFrameRateCompatibility, scheduler::FrameRateCompatibility()); MOCK_CONST_METHOD0(getOwnerUid, uid_t()); MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace()); }; -- GitLab From 0dfa358c79fc8047dd622d82020c37559871c8e7 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Sat, 30 Sep 2023 00:50:06 -0700 Subject: [PATCH 0723/1187] [sf] HdrOutputControlTest: fix strategy arguments The code was previously passing an aidl::[...]::common::HdrConversionStrategy* argument to gui::ISurfaceComposer::setHdrConversionStrategy, which accepts a const gui::HdrConversionStrategy& parameter. Converting between these two kinds of HdrConversionStrategy is laborious -- see SurfaceFlinger::setHdrConversionStrategy. This code was previously avoiding the conversion difficulty by passing a pointer to HdrConversionStrategy, which is wrong because the function actually accepts a const reference. It worked, though, because gui::HdrConversionStrategy's _value has type: std::variant, int32_t> ... and aidl::[...]::common::HdrConversionStrategy* can be coerced to bool. The pointer is always non-nullptr, so each sf->setHdrConversionStrategy was actually passing a {passthrough==true} strategy. The C++ standard tightened the rules around variant conversion (P0608R3, P1957R2), and after upgrading libc++, this code no longer compiles. Fix the compile error by using gui::HdrConversionStrategy for the type of the strategy vector elements. Bug: 175635923 Test: m MODULES-IN-frameworks-native-services-surfaceflinger Change-Id: I820ac945113da0317d0eaa44f581fd6ab1b61645 --- .../SurfaceFlinger_HdrOutputControlTest.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp index a2c54ac621..db6df229d5 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp @@ -26,8 +26,6 @@ namespace android { -using aidl::android::hardware::graphics::common::HdrConversionCapability; -using aidl::android::hardware::graphics::common::HdrConversionStrategy; using GuiHdrConversionStrategyTag = gui::HdrConversionStrategy::Tag; using gui::aidl_utils::statusTFromBinderStatus; @@ -66,17 +64,15 @@ TEST(HdrOutputControlTest, testSetHdrConversionStrategy) { sf->getHdrOutputConversionSupport(&hdrOutputConversionSupport); ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(getSupportStatus)); - std::vector strategies = - {HdrConversionStrategy(std::in_place_index( - GuiHdrConversionStrategyTag::passthrough)>), - HdrConversionStrategy(std::in_place_index( - GuiHdrConversionStrategyTag::autoAllowedHdrTypes)>), - HdrConversionStrategy(std::in_place_index( - GuiHdrConversionStrategyTag::forceHdrConversion)>)}; + std::vector strategies = { + gui::HdrConversionStrategy::make(), + gui::HdrConversionStrategy::make(), + gui::HdrConversionStrategy::make(), + }; int32_t outPreferredHdrOutputType = 0; - for (HdrConversionStrategy strategy : strategies) { - binder::Status status = sf->setHdrConversionStrategy(&strategy, &outPreferredHdrOutputType); + for (const gui::HdrConversionStrategy& strategy : strategies) { + binder::Status status = sf->setHdrConversionStrategy(strategy, &outPreferredHdrOutputType); if (hdrOutputConversionSupport) { ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); -- GitLab From b2aff84fcf453b4524bbd4c628d00ae0f0d93f4c Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Tue, 26 Sep 2023 10:11:34 +0000 Subject: [PATCH 0724/1187] Add flag to mark key usage code as a fallback mapping We don't yet have a way to determine if a device can actually report a usage code. Adding a flag to mark usage code as fallback only mapping. Bug: 297094448 Test: atest inputflinger_tests Change-Id: I137113d0dc9a1c8abf523b96942486be176d0240 --- include/input/Input.h | 10 ++++++ libs/input/InputEventLabels.cpp | 3 +- libs/input/KeyLayoutMap.cpp | 2 +- libs/input/tests/InputDevice_test.cpp | 35 +++++++++++++++++++ libs/input/tests/data/hid_fallback_mapping.kl | 32 +++++++++++++++++ 5 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 libs/input/tests/data/hid_fallback_mapping.kl diff --git a/include/input/Input.h b/include/input/Input.h index 64ee47342d..567361d679 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -285,6 +285,16 @@ enum { // This policy flag prevents key events from changing touch mode state. POLICY_FLAG_GESTURE = 0x00000008, + // Indicates that key usage mapping represents a fallback mapping. + // Fallback mappings cannot be used to definitively determine whether a device + // supports a key code. For example, a HID device can report a key press + // as a HID usage code if it is not mapped to any linux key code in the kernel. + // However, we cannot know which HID usage codes that device supports from + // userspace through the evdev. We can use fallback mappings to convert HID + // usage codes to Android key codes without needing to know if a device can + // actually report the usage code. + POLICY_FLAG_FALLBACK_USAGE_MAPPING = 0x00000010, + POLICY_FLAG_RAW_MASK = 0x0000ffff, #ifdef __linux__ diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp index c218e1e858..0e627e56fd 100644 --- a/libs/input/InputEventLabels.cpp +++ b/libs/input/InputEventLabels.cpp @@ -430,7 +430,8 @@ namespace android { DEFINE_FLAG(VIRTUAL), \ DEFINE_FLAG(FUNCTION), \ DEFINE_FLAG(GESTURE), \ - DEFINE_FLAG(WAKE) + DEFINE_FLAG(WAKE), \ + DEFINE_FLAG(FALLBACK_USAGE_MAPPING) // clang-format on diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp index ddc9ea457e..3c1ae3e41b 100644 --- a/libs/input/KeyLayoutMap.cpp +++ b/libs/input/KeyLayoutMap.cpp @@ -250,7 +250,7 @@ std::vector KeyLayoutMap::findScanCodesForKey(int32_t keyCode) const { std::vector KeyLayoutMap::findUsageCodesForKey(int32_t keyCode) const { std::vector usageCodes; for (const auto& [usageCode, key] : mKeysByUsageCode) { - if (keyCode == key.keyCode) { + if (keyCode == key.keyCode && !(key.flags & POLICY_FLAG_FALLBACK_USAGE_MAPPING)) { usageCodes.push_back(usageCode); } } diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp index a0ec6adc65..fe5490caf5 100644 --- a/libs/input/tests/InputDevice_test.cpp +++ b/libs/input/tests/InputDevice_test.cpp @@ -167,6 +167,41 @@ TEST_F(InputDeviceKeyMapTest, keyCharacterMapBadLedLabel) { ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath; } +TEST(InputDeviceKeyLayoutTest, HidUsageCodesFallbackMapping) { + std::string klPath = base::GetExecutableDirectory() + "/data/hid_fallback_mapping.kl"; + base::Result> ret = KeyLayoutMap::load(klPath); + ASSERT_TRUE(ret.ok()) << "Unable to load KeyLayout at " << klPath; + const std::shared_ptr& keyLayoutMap = *ret; + + static constexpr std::array hidUsageCodesWithoutFallback = {0x0c0067, 0x0c0070, + 0x0c006F, 0x0c0079, + 0x0c007A}; + for (int32_t hidUsageCode : hidUsageCodesWithoutFallback) { + int32_t outKeyCode; + uint32_t outFlags; + keyLayoutMap->mapKey(0, hidUsageCode, &outKeyCode, &outFlags); + ASSERT_FALSE(outFlags & POLICY_FLAG_FALLBACK_USAGE_MAPPING) + << "HID usage code should not be marked as fallback"; + std::vector usageCodes = keyLayoutMap->findUsageCodesForKey(outKeyCode); + ASSERT_NE(std::find(usageCodes.begin(), usageCodes.end(), hidUsageCode), usageCodes.end()) + << "Fallback usage code should be mapped to key"; + } + + static constexpr std::array hidUsageCodesWithFallback = {0x0c007C, 0x0c0173, + 0x0c019C, 0x0c01A2, + 0x0d0044, 0x0d005a}; + for (int32_t hidUsageCode : hidUsageCodesWithFallback) { + int32_t outKeyCode; + uint32_t outFlags; + keyLayoutMap->mapKey(0, hidUsageCode, &outKeyCode, &outFlags); + ASSERT_TRUE(outFlags & POLICY_FLAG_FALLBACK_USAGE_MAPPING) + << "HID usage code should be marked as fallback"; + std::vector usageCodes = keyLayoutMap->findUsageCodesForKey(outKeyCode); + ASSERT_EQ(std::find(usageCodes.begin(), usageCodes.end(), hidUsageCode), usageCodes.end()) + << "Fallback usage code should not be mapped to key"; + } +} + TEST(InputDeviceKeyLayoutTest, DoesNotLoadWhenRequiredKernelConfigIsMissing) { #if !defined(__ANDROID__) GTEST_SKIP() << "Can't check kernel configs on host"; diff --git a/libs/input/tests/data/hid_fallback_mapping.kl b/libs/input/tests/data/hid_fallback_mapping.kl new file mode 100644 index 0000000000..b4ca9ef355 --- /dev/null +++ b/libs/input/tests/data/hid_fallback_mapping.kl @@ -0,0 +1,32 @@ +# Copyright 2023 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. + +# +# test key layout file for InputDeviceKeyMapTest#HidUsageCodesUseFallbackMapping +# + +# Keys defined by HID usages without fallback mapping flag +key usage 0x0c0067 WINDOW +key usage 0x0c006F BRIGHTNESS_UP +key usage 0x0c0070 BRIGHTNESS_DOWN +key usage 0x0c0079 KEYBOARD_BACKLIGHT_UP +key usage 0x0c007A KEYBOARD_BACKLIGHT_DOWN + +# Keys defined by HID usages with fallback mapping flag +key usage 0x0c007C KEYBOARD_BACKLIGHT_TOGGLE FALLBACK_USAGE_MAPPING +key usage 0x0c0173 MEDIA_AUDIO_TRACK FALLBACK_USAGE_MAPPING +key usage 0x0c019C PROFILE_SWITCH FALLBACK_USAGE_MAPPING +key usage 0x0c01A2 ALL_APPS FALLBACK_USAGE_MAPPING +key usage 0x0d0044 STYLUS_BUTTON_PRIMARY FALLBACK_USAGE_MAPPING +key usage 0x0d005a STYLUS_BUTTON_SECONDARY FALLBACK_USAGE_MAPPING \ No newline at end of file -- GitLab From 0b251a3f0b1b7c1a59904474657d680742a39e10 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 20 Sep 2023 16:24:42 -0700 Subject: [PATCH 0725/1187] Add multi-device tests to dispatcher In this CL, several multi-device tests are added to InputDispatcher. This is done for the following reasons: 1. Increase test coverage of dispatcher 2. Reduce the diff in the upcoming "multi-device input" CL 3. Show the difference in behaviour from the old code to the new one This should simplify the review of future CLs because the difference in behaviour will be easy to spot. Bug: 211379801 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: Ifadfc35eee43297305387e2cb79bc671259fd0bf --- .../tests/InputDispatcher_test.cpp | 635 ++++++++++++++++-- 1 file changed, 594 insertions(+), 41 deletions(-) diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index f0602dfbad..215989d0c4 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -73,6 +73,7 @@ static constexpr int32_t ACTION_UP = AMOTION_EVENT_ACTION_UP; static constexpr int32_t ACTION_HOVER_ENTER = AMOTION_EVENT_ACTION_HOVER_ENTER; static constexpr int32_t ACTION_HOVER_MOVE = AMOTION_EVENT_ACTION_HOVER_MOVE; static constexpr int32_t ACTION_HOVER_EXIT = AMOTION_EVENT_ACTION_HOVER_EXIT; +static constexpr int32_t ACTION_SCROLL = AMOTION_EVENT_ACTION_SCROLL; static constexpr int32_t ACTION_OUTSIDE = AMOTION_EVENT_ACTION_OUTSIDE; static constexpr int32_t ACTION_CANCEL = AMOTION_EVENT_ACTION_CANCEL; /** @@ -2368,6 +2369,189 @@ TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) { window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE)); } +/** + * Hover mouse over a window, and then send ACTION_SCROLL. Ensure both the hover and the scroll + * events are delivered to the window. + */ +TEST_F(InputDispatcherTest, HoverMoveAndScroll) { + std::shared_ptr application = std::make_shared(); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 200, 200)); + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); + + // Start hovering in the window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_MOVE)); + + // Scroll with the mouse + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_SCROLL, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120)) + .build()); + window->consumeMotionEvent(WithMotionAction(ACTION_SCROLL)); +} + +using InputDispatcherMultiDeviceTest = InputDispatcherTest; + +/** + * One window. Stylus down on the window. Next, touch from another device goes down. + */ +TEST_F(InputDispatcherMultiDeviceTest, StylusDownAndTouchDown) { + std::shared_ptr application = std::make_shared(); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 200, 200)); + + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); + + constexpr int32_t touchDeviceId = 4; + constexpr int32_t stylusDeviceId = 2; + + // Stylus down + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) + .build()); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); + + // Touch down + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) + .build()); + // Touch cancels stylus + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId), + WithCoords(100, 110))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId), + WithCoords(140, 145))); + + // Touch move + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) + .build()); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId), + WithCoords(141, 146))); + + // Subsequent stylus movements are dropped + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) + .build()); + window->assertNoEvents(); +} + +/** + * One window and one spy window. Stylus down on the window. Next, touch from another device goes + * down. + * Similar test as above, but with added SPY window. + */ +TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyAndTouchDown) { + std::shared_ptr application = std::make_shared(); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + sp spyWindow = + sp::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); + spyWindow->setFrame(Rect(0, 0, 200, 200)); + spyWindow->setTrustedOverlay(true); + spyWindow->setSpy(true); + window->setFrame(Rect(0, 0, 200, 200)); + + mDispatcher->onWindowInfosChanged({{*spyWindow->getInfo(), *window->getInfo()}, {}, 0, 0}); + + constexpr int32_t touchDeviceId = 4; + constexpr int32_t stylusDeviceId = 2; + + // Stylus down + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) + .build()); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); + + // Touch down + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) + .build()); + + // Touch move + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) + .build()); + window->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); + // Subsequent stylus movements are dropped + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) + .build()); + + window->assertNoEvents(); + spyWindow->assertNoEvents(); +} + +/** + * One window. Stylus hover on the window. Next, touch from another device goes down. + */ +TEST_F(InputDispatcherMultiDeviceTest, StylusHoverAndTouchDown) { + std::shared_ptr application = std::make_shared(); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 200, 200)); + + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); + + constexpr int32_t touchDeviceId = 4; + constexpr int32_t stylusDeviceId = 2; + + // Stylus down on the window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) + .build()); + window->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); + + // Touch down on window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) + .build()); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) + .build()); + window->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); + // Subsequent stylus movements are ignored + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) + .build()); + window->assertNoEvents(); +} + /** * Two windows: a window on the left and a window on the right. * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains @@ -2375,7 +2559,7 @@ TEST_F(InputDispatcherTest, HoverMoveWhileWindowAppears) { * This test tries to reproduce a crash. * In the buggy implementation, second pointer down on the left window would cause a crash. */ -TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { +TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch) { std::shared_ptr application = std::make_shared(); sp leftWindow = sp::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); @@ -2425,8 +2609,8 @@ TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { .deviceId(touchDeviceId) .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .build()); - leftWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); - + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(mouseDeviceId))); rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Second touch pointer down on left window @@ -2447,6 +2631,215 @@ TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { rightWindow->assertNoEvents(); } +/** + * Two windows: a window on the left and a window on the right. + * Mouse is hovered on the left window and stylus is hovered on the right window. + */ +TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHover) { + std::shared_ptr application = std::make_shared(); + sp leftWindow = + sp::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + leftWindow->setFrame(Rect(0, 0, 200, 200)); + + sp rightWindow = + sp::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + rightWindow->setFrame(Rect(200, 0, 400, 200)); + + mDispatcher->onWindowInfosChanged( + {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); + + const int32_t stylusDeviceId = 3; + const int32_t mouseDeviceId = 6; + + // Start hovering over the left window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110)) + .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); + + // Stylus hovered on right window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(300).y(100)) + .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId))); + rightWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); + + // Subsequent HOVER_MOVE events are dispatched correctly. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120)) + .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); + rightWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId))); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(310).y(110)) + .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId))); + rightWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); + + leftWindow->assertNoEvents(); + rightWindow->assertNoEvents(); +} + +/** + * Three windows: a window on the left and a window on the right. + * And a spy window that's positioned above all of them. + * Stylus down on the left window and remains down. Touch goes down on the right and remains down. + * Check the stream that's received by the spy. + */ +TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy) { + std::shared_ptr application = std::make_shared(); + + sp spyWindow = + sp::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); + spyWindow->setFrame(Rect(0, 0, 400, 400)); + spyWindow->setTrustedOverlay(true); + spyWindow->setSpy(true); + + sp leftWindow = + sp::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + leftWindow->setFrame(Rect(0, 0, 200, 200)); + + sp rightWindow = + sp::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + + rightWindow->setFrame(Rect(200, 0, 400, 200)); + + mDispatcher->onWindowInfosChanged( + {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); + + const int32_t stylusDeviceId = 1; + const int32_t touchDeviceId = 2; + + // Stylus down on the left window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100)) + .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); + + // Touch down on the right window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); + rightWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); + + // Stylus movements continue, but are ignored because the touch went down more recently. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110)) + .build()); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110)) + .build()); + rightWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); + + spyWindow->assertNoEvents(); + leftWindow->assertNoEvents(); + rightWindow->assertNoEvents(); +} + +/** + * Three windows: a window on the left, a window on the right, and a spy window positioned above + * both. + * Check hover in left window and touch down in the right window. + * At first, spy should receive hover, but the touch down should cancel hovering inside spy. + */ +TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverAndTouchWithSpy) { + std::shared_ptr application = std::make_shared(); + + sp spyWindow = + sp::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT); + spyWindow->setFrame(Rect(0, 0, 400, 400)); + spyWindow->setTrustedOverlay(true); + spyWindow->setSpy(true); + + sp leftWindow = + sp::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); + leftWindow->setFrame(Rect(0, 0, 200, 200)); + + sp rightWindow = + sp::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); + rightWindow->setFrame(Rect(200, 0, 400, 200)); + + mDispatcher->onWindowInfosChanged( + {{*spyWindow->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); + + const int32_t stylusDeviceId = 1; + const int32_t touchDeviceId = 2; + + // Stylus hover on the left window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(100)) + .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); + + // Touch down on the right window. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) + .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId))); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId))); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); + rightWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); + + // Stylus movements continue, but are ignored because the touch is down. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110)) + .build()); + + // Touch movements continue. They should be delivered to the right window and to the spy + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(301).y(101)) + .build()); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); + rightWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); + + spyWindow->assertNoEvents(); + leftWindow->assertNoEvents(); + rightWindow->assertNoEvents(); +} + /** * On a single window, use two different devices: mouse and touch. * Touch happens first, with two pointers going down, and then the first pointer leaving. @@ -2455,7 +2848,7 @@ TEST_F(InputDispatcherTest, MultiDeviceSplitTouch) { * because the mouse is currently down, and a POINTER_DOWN event from the touchscreen does not * represent a new gesture. */ -TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { +TEST_F(InputDispatcherMultiDeviceTest, MixedTouchAndMouseWithPointerDown) { std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); @@ -2513,7 +2906,17 @@ TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .pointer(PointerBuilder(1, ToolType::FINGER).x(350).y(100)) .build()); - // The pointer_down event should be ignored + // Since we already canceled this touch gesture, it will be ignored until a completely new + // gesture is started. This is easier to implement than trying to keep track of the new pointer + // and generating an ACTION_DOWN instead of ACTION_POINTER_DOWN. + // However, mouse movements should continue to work. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE) + .deviceId(mouseDeviceId) + .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(330).y(110)) + .build()); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(mouseDeviceId))); + window->assertNoEvents(); } @@ -2521,7 +2924,7 @@ TEST_F(InputDispatcherTest, MixedTouchAndMouseWithPointerDown) { * Inject a touch down and then send a new event via 'notifyMotion'. Ensure the new event cancels * the injected event. */ -TEST_F(InputDispatcherTest, UnfinishedInjectedEvent) { +TEST_F(InputDispatcherMultiDeviceTest, UnfinishedInjectedEvent) { std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); @@ -2567,7 +2970,7 @@ TEST_F(InputDispatcherTest, UnfinishedInjectedEvent) { * This test reproduces a crash where there is a mismatch between the downTime and eventTime. * In the buggy implementation, second finger down on the left window would cause a crash. */ -TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { +TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch) { std::shared_ptr application = std::make_shared(); sp leftWindow = sp::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); @@ -2643,7 +3046,7 @@ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { * While the touch is down, new hover events from the stylus device should be ignored. After the * touch is gone, stylus hovering should start working again. */ -TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { +TEST_F(InputDispatcherMultiDeviceTest, StylusHoverAndTouchTap) { std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); @@ -2656,25 +3059,24 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { // Start hovering with stylus ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, - MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, - AINPUT_SOURCE_STYLUS) + MotionEventBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) .build())); - window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); + window->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER)); // Finger down on the window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, - MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, - AINPUT_SOURCE_TOUCHSCREEN) + MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); - window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); - window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); + window->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); - // Try to continue hovering with stylus. Since we are already down, injection should fail + // Continue hovering with stylus. Injection will fail because touch is already down. ASSERT_EQ(InputEventInjectionResult::FAILED, injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, @@ -2693,7 +3095,7 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { .deviceId(touchDeviceId) .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); - window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(touchDeviceId))); // Now that the touch is gone, stylus hovering should start working again ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -2703,8 +3105,8 @@ TEST_F(InputDispatcherTest, StylusHoverAndTouchTap) { .deviceId(stylusDeviceId) .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70)) .build())); - window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); - // No more events + window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), + WithDeviceId(stylusDeviceId))); window->assertNoEvents(); } @@ -3429,22 +3831,17 @@ TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) { window->setFrame(Rect(0, 0, 100, 100)); mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); - - // Inject a hover_move from mouse. - NotifyMotionArgs motionArgs = - generateMotionArgs(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE, - ADISPLAY_ID_DEFAULT, {{50, 50}}); - motionArgs.xCursorPosition = 50; - motionArgs.yCursorPosition = 50; - mDispatcher->notifyMotion(motionArgs); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(50).y(50)) + .build()); ASSERT_NO_FATAL_FAILURE( window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER), WithSource(AINPUT_SOURCE_MOUSE)))); // Tap on the window - mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, - AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {{10, 10}})); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10)) + .build()); ASSERT_NO_FATAL_FAILURE( window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT), WithSource(AINPUT_SOURCE_MOUSE)))); @@ -3453,8 +3850,9 @@ TEST_F(InputDispatcherTest, MouseHoverAndTouchTap) { window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithSource(AINPUT_SOURCE_TOUCHSCREEN)))); - mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {{10, 10}})); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(10).y(10)) + .build()); ASSERT_NO_FATAL_FAILURE( window->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(AINPUT_SOURCE_TOUCHSCREEN)))); @@ -3655,12 +4053,12 @@ TEST_F(InputDispatcherTest, InterceptKeyIfKeyUp) { */ TEST_F(InputDispatcherTest, ActionOutsideForOwnedWindowHasValidCoordinates) { std::shared_ptr application = std::make_shared(); - sp window = sp::make(application, mDispatcher, - "First Window", ADISPLAY_ID_DEFAULT); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); window->setFrame(Rect{0, 0, 100, 100}); sp outsideWindow = - sp::make(application, mDispatcher, "Second Window", + sp::make(application, mDispatcher, "Outside Window", ADISPLAY_ID_DEFAULT); outsideWindow->setFrame(Rect{100, 100, 200, 200}); outsideWindow->setWatchOutsideTouch(true); @@ -5665,6 +6063,53 @@ TEST_F(InputDispatcherTest, TouchSlippingIntoWindowThatDropsTouches) { rightDropTouchesWindow->assertNoEvents(); } +/** + * A single window is on screen first. Touch is injected into that window. Next, a second window + * appears. Since the first window is slippery, touch will move from the first window to the second. + */ +TEST_F(InputDispatcherTest, InjectedTouchSlips) { + std::shared_ptr application = std::make_shared(); + sp originalWindow = + sp::make(application, mDispatcher, "Original", ADISPLAY_ID_DEFAULT); + originalWindow->setFrame(Rect(0, 0, 200, 200)); + originalWindow->setSlippery(true); + + sp appearingWindow = + sp::make(application, mDispatcher, "Appearing", ADISPLAY_ID_DEFAULT); + appearingWindow->setFrame(Rect(0, 0, 200, 200)); + + mDispatcher->onWindowInfosChanged({{*originalWindow->getInfo()}, {}, 0, 0}); + + // Touch down on the original window + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(*mDispatcher, + MotionEventBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100)) + .build())); + originalWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + + // Now, a new window appears. This could be, for example, a notification shade that appears + // after user starts to drag down on the launcher window. + mDispatcher->onWindowInfosChanged( + {{*appearingWindow->getInfo(), *originalWindow->getInfo()}, {}, 0, 0}); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(*mDispatcher, + MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(1, ToolType::FINGER).x(110).y(110)) + .build())); + originalWindow->consumeMotionEvent(WithMotionAction(ACTION_CANCEL)); + appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(*mDispatcher, + MotionEventBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120)) + .build())); + appearingWindow->consumeMotionEvent(WithMotionAction(ACTION_MOVE)); + + originalWindow->assertNoEvents(); + appearingWindow->assertNoEvents(); +} + TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) { using Uid = gui::Uid; std::shared_ptr application = std::make_shared(); @@ -6663,15 +7108,15 @@ TEST_F(InputDispatcherMultiWindowSameTokenTests, HoverIntoClone) { mDispatcher->onWindowInfosChanged({{*mWindow1->getInfo(), *mWindow2->getInfo()}, {}, 0, 0}); // Start hover in window 1 - mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {{50, 50}})); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50)) + .build()); consumeMotionEvent(mWindow1, ACTION_HOVER_ENTER, {getPointInWindow(mWindow1->getInfo(), PointF{50, 50})}); - // Move hover to window 2. - mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_TOUCHSCREEN, - ADISPLAY_ID_DEFAULT, {{150, 150}})); - + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(150)) + .build()); consumeMotionEvent(mWindow1, ACTION_HOVER_EXIT, {{50, 50}}); consumeMotionEvent(mWindow1, ACTION_HOVER_ENTER, {getPointInWindow(mWindow2->getInfo(), PointF{150, 150})}); @@ -7958,6 +8403,47 @@ TEST_F(InputDispatcherPointerCaptureTests, RapidToggleRequests) { mWindow->assertNoEvents(); } +/** + * One window. Hover mouse in the window, and then start capture. Make sure that the relative + * mouse movements don't affect the previous mouse hovering state. + * When pointer capture is enabled, the incoming events are always ACTION_MOVE (there are no + * HOVER_MOVE events). + */ +TEST_F(InputDispatcherPointerCaptureTests, MouseHoverAndPointerCapture) { + // Mouse hover on the window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110)) + .build()); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(100).y(110)) + .build()); + + mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER))); + mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_MOVE))); + + // Start pointer capture + requestAndVerifyPointerCapture(mWindow, true); + + // Send some relative mouse movements and receive them in the window. + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE_RELATIVE) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(10).y(11)) + .build()); + mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithCoords(10, 11), + WithSource(AINPUT_SOURCE_MOUSE_RELATIVE))); + + // Stop pointer capture + requestAndVerifyPointerCapture(mWindow, false); + + // Continue hovering on the window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(105).y(115)) + .build()); + mWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithSource(AINPUT_SOURCE_MOUSE))); + + mWindow->assertNoEvents(); +} + class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest { protected: constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8; @@ -9664,6 +10150,73 @@ TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) { spy->assertNoEvents(); } +/** + * A window on the left and a window on the right. Also, a spy window that's above all of the + * windows, and spanning both left and right windows. + * Send simultaneous motion streams from two different devices, one to the left window, and another + * to the right window. + * Pilfer from spy window. + * Check that the pilfering only affects the pointers that are actually being received by the spy. + */ +TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) { + sp spy = createSpy(); + spy->setFrame(Rect(0, 0, 200, 200)); + sp leftWindow = createForeground(); + leftWindow->setFrame(Rect(0, 0, 100, 100)); + + sp rightWindow = createForeground(); + rightWindow->setFrame(Rect(100, 0, 200, 100)); + + constexpr int32_t stylusDeviceId = 1; + constexpr int32_t touchDeviceId = 2; + + mDispatcher->onWindowInfosChanged( + {{*spy->getInfo(), *leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0}); + + // Stylus down on left window and spy + mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(50).y(50)) + .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); + spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); + + // Finger down on right window and spy - but spy already has stylus + mDispatcher->notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50)) + .build()); + rightWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); + spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); + spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); + + // Act: pilfer from spy. Spy is currently receiving touch events. + EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); + rightWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId))); + + // Continue movements from both stylus and touch. Touch will be delivered to spy, but not stylus + mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(51).y(52)) + .build()); + mDispatcher->notifyMotion( + MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52)) + .build()); + spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); + + spy->assertNoEvents(); + leftWindow->assertNoEvents(); + rightWindow->assertNoEvents(); +} + class InputDispatcherStylusInterceptorTest : public InputDispatcherTest { public: std::pair, sp> setupStylusOverlayScenario() { -- GitLab From 07d03c4d260b804c07f7ac927515b26c84c9a4ea Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 27 Sep 2023 19:15:08 -0700 Subject: [PATCH 0726/1187] SF: fix binder thread priority Add setMinSchedulerPolicy to all binder interfaces SF exposes. It was missing from gui::ISurfaceComposer and gui::IDisplayEventConnection. Test: presubmit Bug: 299378819 Change-Id: Ia0d99efa5a3bc58625c320d4df3c08bb597d2e38 --- libs/gui/ISurfaceComposer.cpp | 13 + .../android/gui/IDisplayEventConnection.aidl | 6 + .../aidl/android/gui/ISurfaceComposer.aidl | 3 + .../android/gui/ISurfaceComposerClient.aidl | 3 + .../aidl/android/gui/SchedulingPolicy.aidl | 23 ++ libs/gui/fuzzer/libgui_fuzzer_utils.h | 3 + libs/gui/include/gui/ISurfaceComposer.h | 1 + libs/gui/include/gui/SchedulingPolicy.h | 40 ++++ libs/gui/tests/Surface_test.cpp | 4 + services/surfaceflinger/Client.cpp | 5 + services/surfaceflinger/Client.h | 2 + .../surfaceflinger/Scheduler/EventThread.cpp | 16 +- .../surfaceflinger/Scheduler/EventThread.h | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 10 + services/surfaceflinger/SurfaceFlinger.h | 5 +- .../fuzzer/surfaceflinger_fuzzer.cpp | 1 + .../surfaceflinger/main_surfaceflinger.cpp | 3 + services/surfaceflinger/tests/Android.bp | 1 + services/surfaceflinger/tests/Binder_test.cpp | 225 ++++++++++++++++++ 19 files changed, 360 insertions(+), 5 deletions(-) create mode 100644 libs/gui/aidl/android/gui/SchedulingPolicy.aidl create mode 100644 libs/gui/include/gui/SchedulingPolicy.h create mode 100644 services/surfaceflinger/tests/Binder_test.cpp diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index b526a6c92c..ff6b558d41 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -201,6 +202,18 @@ status_t BnSurfaceComposer::onTransact( isAutoTimestamp, uncacheBuffers, hasListenerCallbacks, listenerCallbacks, transactionId, mergedTransactions); } + case GET_SCHEDULING_POLICY: { + gui::SchedulingPolicy policy; + const auto status = gui::getSchedulingPolicy(&policy); + if (!status.isOk()) { + return status.exceptionCode(); + } + + SAFE_PARCEL(reply->writeInt32, policy.policy); + SAFE_PARCEL(reply->writeInt32, policy.priority); + return NO_ERROR; + } + default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl index 9781ca96f4..008ef19244 100644 --- a/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl +++ b/libs/gui/aidl/android/gui/IDisplayEventConnection.aidl @@ -18,6 +18,7 @@ package android.gui; import android.gui.BitTube; import android.gui.ParcelableVsyncEventData; +import android.gui.SchedulingPolicy; /** @hide */ interface IDisplayEventConnection { @@ -44,4 +45,9 @@ interface IDisplayEventConnection { * getLatestVsyncEventData() gets the latest vsync event data. */ ParcelableVsyncEventData getLatestVsyncEventData(); + + /* + * getSchedulingPolicy() used in tests to validate the binder thread pririty + */ + SchedulingPolicy getSchedulingPolicy(); } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index 1c604a1f8b..507e0868d7 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -46,6 +46,7 @@ import android.gui.LayerDebugInfo; import android.gui.OverlayProperties; import android.gui.PullAtomData; import android.gui.ARect; +import android.gui.SchedulingPolicy; import android.gui.StalledTransactionInfo; import android.gui.StaticDisplayInfo; import android.gui.WindowInfosListenerInfo; @@ -545,4 +546,6 @@ interface ISurfaceComposer { * applied in SurfaceFlinger due to an unsignaled fence. Otherwise, null is returned. */ @nullable StalledTransactionInfo getStalledTransactionInfo(int pid); + + SchedulingPolicy getSchedulingPolicy(); } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl index 68781ce953..920257c449 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl @@ -19,6 +19,7 @@ package android.gui; import android.gui.CreateSurfaceResult; import android.gui.FrameStats; import android.gui.LayerMetadata; +import android.gui.SchedulingPolicy; /** @hide */ interface ISurfaceComposerClient { @@ -60,4 +61,6 @@ interface ISurfaceComposerClient { CreateSurfaceResult mirrorSurface(IBinder mirrorFromHandle); CreateSurfaceResult mirrorDisplay(long displayId); + + SchedulingPolicy getSchedulingPolicy(); } diff --git a/libs/gui/aidl/android/gui/SchedulingPolicy.aidl b/libs/gui/aidl/android/gui/SchedulingPolicy.aidl new file mode 100644 index 0000000000..4f7cf0a493 --- /dev/null +++ b/libs/gui/aidl/android/gui/SchedulingPolicy.aidl @@ -0,0 +1,23 @@ +/* + * Copyright 2023 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. + */ + +package android.gui; + +/** @hide */ +parcelable SchedulingPolicy { + int policy; + int priority; +} diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h index bdf8856a75..3142103d17 100644 --- a/libs/gui/fuzzer/libgui_fuzzer_utils.h +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -166,6 +166,7 @@ public: MOCK_METHOD(binder::Status, getOverlaySupport, (gui::OverlayProperties*), (override)); MOCK_METHOD(binder::Status, getStalledTransactionInfo, (int32_t, std::optional*), (override)); + MOCK_METHOD(binder::Status, getSchedulingPolicy, (gui::SchedulingPolicy*), (override)); }; class FakeBnSurfaceComposerClient : public gui::BnSurfaceComposerClient { @@ -186,6 +187,8 @@ public: MOCK_METHOD(binder::Status, mirrorDisplay, (int64_t displayId, gui::CreateSurfaceResult* outResult), (override)); + + MOCK_METHOD(binder::Status, getSchedulingPolicy, (gui::SchedulingPolicy*), (override)); }; class FakeDisplayEventDispatcher : public DisplayEventDispatcher { diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 3ff6735926..a836f4642a 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -199,6 +199,7 @@ public: SET_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now. CLEAR_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now. SET_OVERRIDE_FRAME_RATE, // Deprecated. Autogenerated by .aidl now. + GET_SCHEDULING_POLICY, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/SchedulingPolicy.h b/libs/gui/include/gui/SchedulingPolicy.h new file mode 100644 index 0000000000..48c9f0c7bf --- /dev/null +++ b/libs/gui/include/gui/SchedulingPolicy.h @@ -0,0 +1,40 @@ +/* + * Copyright 2023 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 + +#include +#include + +namespace android::gui { + +static binder::Status getSchedulingPolicy(gui::SchedulingPolicy* outPolicy) { + outPolicy->policy = sched_getscheduler(0); + if (outPolicy->policy < 0) { + return binder::Status::fromExceptionCode(EX_ILLEGAL_STATE); + } + + struct sched_param param; + if (sched_getparam(0, ¶m) < 0) { + return binder::Status::fromExceptionCode(EX_ILLEGAL_STATE); + } + outPolicy->priority = param.sched_priority; + return binder::Status::ok(); +} + +} // namespace android::gui \ No newline at end of file diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index daed764cd6..9eee699f23 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1036,6 +1036,10 @@ public: return binder::Status::ok(); } + binder::Status getSchedulingPolicy(gui::SchedulingPolicy*) override { + return binder::Status::ok(); + } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index bdbc79b8e1..6b4215e2f4 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "Client.h" #include "FrontEnd/LayerCreationArgs.h" @@ -117,5 +118,9 @@ binder::Status Client::mirrorDisplay(int64_t displayId, gui::CreateSurfaceResult return binderStatusFromStatusT(status); } +binder::Status Client::getSchedulingPolicy(gui::SchedulingPolicy* outPolicy) { + return gui::getSchedulingPolicy(outPolicy); +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h index af410ea19c..77916e0a78 100644 --- a/services/surfaceflinger/Client.h +++ b/services/surfaceflinger/Client.h @@ -55,6 +55,8 @@ private: binder::Status mirrorDisplay(int64_t displayId, gui::CreateSurfaceResult* outResult) override; + binder::Status getSchedulingPolicy(gui::SchedulingPolicy* outPolicy) override; + // constant sp mFlinger; diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index edab7ecee1..9a55c94424 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -218,6 +219,10 @@ binder::Status EventThreadConnection::getLatestVsyncEventData( return binder::Status::ok(); } +binder::Status EventThreadConnection::getSchedulingPolicy(gui::SchedulingPolicy* outPolicy) { + return gui::getSchedulingPolicy(outPolicy); +} + status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) { constexpr auto toStatus = [](ssize_t size) { return size < 0 ? status_t(size) : status_t(NO_ERROR); @@ -300,9 +305,14 @@ void EventThread::setDuration(std::chrono::nanoseconds workDuration, sp EventThread::createEventConnection( EventRegistrationFlags eventRegistration) const { - return sp::make(const_cast(this), - IPCThreadState::self()->getCallingUid(), - eventRegistration); + auto connection = sp::make(const_cast(this), + IPCThreadState::self()->getCallingUid(), + eventRegistration); + if (flags::misc1()) { + const int policy = SCHED_FIFO; + connection->setMinSchedulerPolicy(policy, sched_get_priority_min(policy)); + } + return connection; } status_t EventThread::registerDisplayEventConnection(const sp& connection) { diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index a7c8b74b91..7842318e2e 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -78,6 +78,7 @@ public: binder::Status setVsyncRate(int rate) override; binder::Status requestNextVsync() override; // asynchronous binder::Status getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) override; + binder::Status getSchedulingPolicy(gui::SchedulingPolicy* outPolicy) override; VSyncRequest vsyncRequest = VSyncRequest::None; const uid_t mOwnerUid; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 12aacad64c..3f52444c40 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -113,6 +113,7 @@ #include #include +#include #include #include "BackgroundExecutor.h" #include "Client.h" @@ -6579,6 +6580,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case GET_ACTIVE_DISPLAY_MODE: case GET_DISPLAY_COLOR_MODES: case GET_DISPLAY_MODES: + case GET_SCHEDULING_POLICY: // Calling setTransactionState is safe, because you need to have been // granted a reference to Client* and Handle* to do anything with it. case SET_TRANSACTION_STATE: { @@ -9016,6 +9018,10 @@ binder::Status SurfaceComposerAIDL::createConnection(sp client = sp::make(mFlinger); if (client->initCheck() == NO_ERROR) { *outClient = client; + if (flags::misc1()) { + const int policy = SCHED_FIFO; + client->setMinSchedulerPolicy(policy, sched_get_priority_min(policy)); + } return binder::Status::ok(); } else { *outClient = nullptr; @@ -9797,6 +9803,10 @@ binder::Status SurfaceComposerAIDL::getStalledTransactionInfo( return binderStatusFromStatusT(status); } +binder::Status SurfaceComposerAIDL::getSchedulingPolicy(gui::SchedulingPolicy* outPolicy) { + return gui::getSchedulingPolicy(outPolicy); +} + status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) { if (!mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(usePermissionCache)) { IPCThreadState* ipc = IPCThreadState::self(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 42825f77fc..a5a2341b14 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1581,8 +1581,9 @@ public: gui::WindowInfosListenerInfo* outInfo) override; binder::Status removeWindowInfosListener( const sp& windowInfosListener) override; - binder::Status getStalledTransactionInfo(int pid, - std::optional* outInfo); + binder::Status getStalledTransactionInfo( + int pid, std::optional* outInfo) override; + binder::Status getSchedulingPolicy(gui::SchedulingPolicy* outPolicy) override; private: static const constexpr bool kUsePermissionCache = true; diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp index ed8bb7fc93..d13189e439 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp @@ -94,6 +94,7 @@ static constexpr BnSurfaceComposer::ISurfaceComposerTag kSurfaceComposerTags[]{ BnSurfaceComposer::REMOVE_TUNNEL_MODE_ENABLED_LISTENER, BnSurfaceComposer::ADD_WINDOW_INFOS_LISTENER, BnSurfaceComposer::REMOVE_WINDOW_INFOS_LISTENER, + BnSurfaceComposer::GET_SCHEDULING_POLICY, }; static constexpr uint32_t kMinCode = 1000; diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp index cf23169eae..959945230d 100644 --- a/services/surfaceflinger/main_surfaceflinger.cpp +++ b/services/surfaceflinger/main_surfaceflinger.cpp @@ -149,6 +149,9 @@ int main(int, char**) { // publish gui::ISurfaceComposer, the new AIDL interface sp composerAIDL = sp::make(flinger); + if (flags::misc1()) { + composerAIDL->setMinSchedulerPolicy(SCHED_FIFO, newPriority); + } sm->addService(String16("SurfaceFlingerAIDL"), composerAIDL, false, IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO); diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index b5168b0f01..36b197234a 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -30,6 +30,7 @@ cc_test { test_suites: ["device-tests"], srcs: [ "BootDisplayMode_test.cpp", + "Binder_test.cpp", "BufferGenerator.cpp", "CommonTypes_test.cpp", "Credentials_test.cpp", diff --git a/services/surfaceflinger/tests/Binder_test.cpp b/services/surfaceflinger/tests/Binder_test.cpp new file mode 100644 index 0000000000..3152973da6 --- /dev/null +++ b/services/surfaceflinger/tests/Binder_test.cpp @@ -0,0 +1,225 @@ +/* + * Copyright 2023 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 +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace android::test { +using namespace com::android::graphics::surfaceflinger; + +class BinderTest : public ::testing::Test { +protected: + BinderTest(); + + void SetUp() override; + + void getSchedulingPolicy(gui::SchedulingPolicy* outPolicy); + void getNonAidlSchedulingPolicy(gui::SchedulingPolicy* outPolicy); + void getClientSchedulingPolicy(gui::SchedulingPolicy* outPolicy); + void getDisplayEventConnectionSchedulingPolicy(gui::SchedulingPolicy* outPolicy); + +private: + sp mISurfaceComposerAidl; + sp mISurfaceComposer; + sp mISurfaceComposerClient; + sp mConnection; +}; + +BinderTest::BinderTest() { + const String16 name("SurfaceFlingerAIDL"); + mISurfaceComposerAidl = waitForService(String16("SurfaceFlingerAIDL")); + mISurfaceComposer = waitForService(String16("SurfaceFlinger")); + mISurfaceComposerAidl->createConnection(&mISurfaceComposerClient); + mISurfaceComposerAidl + ->createDisplayEventConnection(gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, + gui::ISurfaceComposer::EventRegistration(0), {}, + &mConnection); +} + +void BinderTest::SetUp() { + ASSERT_TRUE(mISurfaceComposerAidl); + ASSERT_TRUE(mISurfaceComposer); + ASSERT_TRUE(mISurfaceComposerClient); + ASSERT_TRUE(mConnection); +} + +void BinderTest::getSchedulingPolicy(gui::SchedulingPolicy* outPolicy) { + const auto status = mISurfaceComposerAidl->getSchedulingPolicy(outPolicy); + ASSERT_TRUE(status.isOk()); +} + +void BinderTest::getNonAidlSchedulingPolicy(gui::SchedulingPolicy* outPolicy) { + Parcel data, reply; + const status_t status = + IInterface::asBinder(mISurfaceComposer) + ->transact(BnSurfaceComposer::GET_SCHEDULING_POLICY, data, &reply); + ASSERT_EQ(OK, status); + + outPolicy->policy = reply.readInt32(); + outPolicy->priority = reply.readInt32(); +} + +void BinderTest::getClientSchedulingPolicy(gui::SchedulingPolicy* outPolicy) { + const auto status = mISurfaceComposerClient->getSchedulingPolicy(outPolicy); + ASSERT_TRUE(status.isOk()); +} + +void BinderTest::getDisplayEventConnectionSchedulingPolicy(gui::SchedulingPolicy* outPolicy) { + const auto status = mConnection->getSchedulingPolicy(outPolicy); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(BinderTest, SchedulingPolicy) { + if (!flags::misc1()) GTEST_SKIP(); + + const int policy = SCHED_FIFO; + const int priority = sched_get_priority_min(policy); + + gui::SchedulingPolicy sfPolicy; + ASSERT_NO_FATAL_FAILURE(getSchedulingPolicy(&sfPolicy)); + + ASSERT_EQ(policy, sfPolicy.policy & (~SCHED_RESET_ON_FORK)); + ASSERT_EQ(priority, sfPolicy.priority); +} + +TEST_F(BinderTest, NonAidlSchedulingPolicy) { + const int policy = SCHED_FIFO; + const int priority = sched_get_priority_min(policy); + + gui::SchedulingPolicy sfPolicy; + ASSERT_NO_FATAL_FAILURE(getNonAidlSchedulingPolicy(&sfPolicy)); + + ASSERT_EQ(policy, sfPolicy.policy & (~SCHED_RESET_ON_FORK)); + ASSERT_EQ(priority, sfPolicy.priority); +} + +TEST_F(BinderTest, ClientSchedulingPolicy) { + if (!flags::misc1()) GTEST_SKIP(); + + const int policy = SCHED_FIFO; + const int priority = sched_get_priority_min(policy); + + gui::SchedulingPolicy sfPolicy; + ASSERT_NO_FATAL_FAILURE(getClientSchedulingPolicy(&sfPolicy)); + + ASSERT_EQ(policy, sfPolicy.policy & (~SCHED_RESET_ON_FORK)); + ASSERT_EQ(priority, sfPolicy.priority); +} + +TEST_F(BinderTest, DisplayEventConnectionSchedulingPolicy) { + if (!flags::misc1()) GTEST_SKIP(); + + const int policy = SCHED_FIFO; + const int priority = sched_get_priority_min(policy); + + gui::SchedulingPolicy sfPolicy; + ASSERT_NO_FATAL_FAILURE(getDisplayEventConnectionSchedulingPolicy(&sfPolicy)); + + ASSERT_EQ(policy, sfPolicy.policy & (~SCHED_RESET_ON_FORK)); + ASSERT_EQ(priority, sfPolicy.priority); +} + +class BinderTestRtCaller : public BinderTest { +protected: + void SetUp() override; + void TearDown() override; + +private: + int mOrigPolicy; + int mOrigPriority; +}; + +void BinderTestRtCaller::SetUp() { + const int policy = SCHED_FIFO; + const int priority = sched_get_priority_min(policy); + + mOrigPolicy = sched_getscheduler(0); + struct sched_param origSchedParam; + ASSERT_GE(0, sched_getparam(0, &origSchedParam)) << "errno: " << strerror(errno); + mOrigPriority = origSchedParam.sched_priority; + + struct sched_param param; + param.sched_priority = priority; + ASSERT_GE(0, sched_setscheduler(0, policy, ¶m)) << "errno: " << strerror(errno); +} + +void BinderTestRtCaller::TearDown() { + struct sched_param origSchedParam; + origSchedParam.sched_priority = mOrigPriority; + ASSERT_GE(0, sched_setscheduler(0, mOrigPolicy, &origSchedParam)) + << "errno: " << strerror(errno); +} + +TEST_F(BinderTestRtCaller, SchedulingPolicy) { + if (!flags::misc1()) GTEST_SKIP(); + + const int policy = SCHED_FIFO; + const int priority = sched_get_priority_min(policy); + + gui::SchedulingPolicy sfPolicy; + ASSERT_NO_FATAL_FAILURE(getSchedulingPolicy(&sfPolicy)); + + ASSERT_EQ(policy, sfPolicy.policy & (~SCHED_RESET_ON_FORK)); + ASSERT_EQ(priority, sfPolicy.priority); +} + +TEST_F(BinderTestRtCaller, NonAidlSchedulingPolicy) { + const int policy = SCHED_FIFO; + const int priority = sched_get_priority_min(policy); + + gui::SchedulingPolicy sfPolicy; + ASSERT_NO_FATAL_FAILURE(getNonAidlSchedulingPolicy(&sfPolicy)); + + ASSERT_EQ(policy, sfPolicy.policy & (~SCHED_RESET_ON_FORK)); + ASSERT_EQ(priority, sfPolicy.priority); +} + +TEST_F(BinderTestRtCaller, ClientSchedulingPolicy) { + if (!flags::misc1()) GTEST_SKIP(); + + const int policy = SCHED_FIFO; + const int priority = sched_get_priority_min(policy); + + gui::SchedulingPolicy sfPolicy; + ASSERT_NO_FATAL_FAILURE(getClientSchedulingPolicy(&sfPolicy)); + + ASSERT_EQ(policy, sfPolicy.policy & (~SCHED_RESET_ON_FORK)); + ASSERT_EQ(priority, sfPolicy.priority); +} + +TEST_F(BinderTestRtCaller, DisplayEventConnectionSchedulingPolicy) { + if (!flags::misc1()) GTEST_SKIP(); + + const int policy = SCHED_FIFO; + const int priority = sched_get_priority_min(policy); + + gui::SchedulingPolicy sfPolicy; + ASSERT_NO_FATAL_FAILURE(getDisplayEventConnectionSchedulingPolicy(&sfPolicy)); + + ASSERT_EQ(policy, sfPolicy.policy & (~SCHED_RESET_ON_FORK)); + ASSERT_EQ(priority, sfPolicy.priority); +} + +} // namespace android::test -- GitLab From ddba9342cf79ea67328a845bb1b99635b2cbd00e Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 2 Oct 2023 16:28:03 -0700 Subject: [PATCH 0727/1187] SF: avoid a nullptr access in RefreshRateOverlay / HDR overlay Bug: 302312658 Test: presubmit + manual Change-Id: I3a69e4520be7f52779e1f92e5621a6138de08797 --- services/surfaceflinger/DisplayDevice.cpp | 22 +++++++++++-------- .../surfaceflinger/HdrSdrRatioOverlay.cpp | 17 +++++++++++++- services/surfaceflinger/HdrSdrRatioOverlay.h | 12 ++++++++-- .../surfaceflinger/RefreshRateOverlay.cpp | 19 +++++++++++++++- services/surfaceflinger/RefreshRateOverlay.h | 10 ++++++++- 5 files changed, 66 insertions(+), 14 deletions(-) diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 1faf6a1bcb..5b6591aeac 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -428,10 +428,12 @@ void DisplayDevice::enableHdrSdrRatioOverlay(bool enable) { return; } - mHdrSdrRatioOverlay = std::make_unique(); - mHdrSdrRatioOverlay->setLayerStack(getLayerStack()); - mHdrSdrRatioOverlay->setViewport(getSize()); - updateHdrSdrRatioOverlayRatio(mHdrSdrRatio); + mHdrSdrRatioOverlay = HdrSdrRatioOverlay::create(); + if (mHdrSdrRatioOverlay) { + mHdrSdrRatioOverlay->setLayerStack(getLayerStack()); + mHdrSdrRatioOverlay->setViewport(getSize()); + updateHdrSdrRatioOverlayRatio(mHdrSdrRatio); + } } void DisplayDevice::updateHdrSdrRatioOverlayRatio(float currentHdrSdrRatio) { @@ -468,11 +470,13 @@ void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc, bool sh // TODO(b/296636258) Update to use the render rate range in VRR mode. const auto fpsRange = mRefreshRateSelector->getSupportedRefreshRateRange(); - mRefreshRateOverlay = std::make_unique(fpsRange, features); - mRefreshRateOverlay->setLayerStack(getLayerStack()); - mRefreshRateOverlay->setViewport(getSize()); - updateRefreshRateOverlayRate(getActiveMode().modePtr->getVsyncRate(), getActiveMode().fps, - setByHwc); + mRefreshRateOverlay = RefreshRateOverlay::create(fpsRange, features); + if (mRefreshRateOverlay) { + mRefreshRateOverlay->setLayerStack(getLayerStack()); + mRefreshRateOverlay->setViewport(getSize()); + updateRefreshRateOverlayRate(getActiveMode().modePtr->getVsyncRate(), getActiveMode().fps, + setByHwc); + } } void DisplayDevice::updateRefreshRateOverlayRate(Fps vsyncRate, Fps renderFps, bool setByHwc) { diff --git a/services/surfaceflinger/HdrSdrRatioOverlay.cpp b/services/surfaceflinger/HdrSdrRatioOverlay.cpp index 186e8784c5..dfb1c1e251 100644 --- a/services/surfaceflinger/HdrSdrRatioOverlay.cpp +++ b/services/surfaceflinger/HdrSdrRatioOverlay.cpp @@ -96,7 +96,18 @@ sp HdrSdrRatioOverlay::draw(float currentHdrSdrRatio, SkColor col return buffer; } -HdrSdrRatioOverlay::HdrSdrRatioOverlay() +std::unique_ptr HdrSdrRatioOverlay::create() { + std::unique_ptr overlay = + std::make_unique(ConstructorTag{}); + if (overlay->initCheck()) { + return overlay; + } + + ALOGE("%s: Failed to create HdrSdrRatioOverlay", __func__); + return {}; +} + +HdrSdrRatioOverlay::HdrSdrRatioOverlay(ConstructorTag) : mSurfaceControl( SurfaceControlHolder::createSurfaceControlHolder(String8("HdrSdrRatioOverlay"))) { if (!mSurfaceControl) { @@ -109,6 +120,10 @@ HdrSdrRatioOverlay::HdrSdrRatioOverlay() .apply(); } +bool HdrSdrRatioOverlay::initCheck() const { + return mSurfaceControl != nullptr; +} + void HdrSdrRatioOverlay::changeHdrSdrRatio(float currentHdrSdrRatio) { mCurrentHdrSdrRatio = currentHdrSdrRatio; animate(); diff --git a/services/surfaceflinger/HdrSdrRatioOverlay.h b/services/surfaceflinger/HdrSdrRatioOverlay.h index 69f95ecf7a..72d401d444 100644 --- a/services/surfaceflinger/HdrSdrRatioOverlay.h +++ b/services/surfaceflinger/HdrSdrRatioOverlay.h @@ -25,15 +25,22 @@ class SkCanvas; namespace android { class HdrSdrRatioOverlay { +private: + // Effectively making the constructor private, while keeping std::make_unique work + struct ConstructorTag {}; + public: - HdrSdrRatioOverlay(); + static std::unique_ptr create(); + void setLayerStack(ui::LayerStack); void setViewport(ui::Size); void animate(); void changeHdrSdrRatio(float currentRatio); + HdrSdrRatioOverlay(ConstructorTag); + private: - float mCurrentHdrSdrRatio = 1.f; + bool initCheck() const; static sp draw(float currentHdrSdrRatio, SkColor, ui::Transform::RotationFlags, sp& ringBufer); @@ -41,6 +48,7 @@ private: const sp getOrCreateBuffers(float currentHdrSdrRatio); + float mCurrentHdrSdrRatio = 1.f; const std::unique_ptr mSurfaceControl; size_t mIndex = 0; diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp index be04c09fa3..42676c6936 100644 --- a/services/surfaceflinger/RefreshRateOverlay.cpp +++ b/services/surfaceflinger/RefreshRateOverlay.cpp @@ -138,7 +138,20 @@ void RefreshRateOverlay::drawNumber(int number, int left, SkColor color, SkCanva SegmentDrawer::drawDigit(number % 10, left, color, canvas); } -RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, ftl::Flags features) +std::unique_ptr RefreshRateOverlay::create(FpsRange range, + ftl::Flags features) { + std::unique_ptr overlay = + std::make_unique(ConstructorTag{}, range, features); + if (overlay->initCheck()) { + return overlay; + } + + ALOGE("%s: Failed to create RefreshRateOverlay", __func__); + return {}; +} + +RefreshRateOverlay::RefreshRateOverlay(ConstructorTag, FpsRange fpsRange, + ftl::Flags features) : mFpsRange(fpsRange), mFeatures(features), mSurfaceControl( @@ -154,6 +167,10 @@ RefreshRateOverlay::RefreshRateOverlay(FpsRange fpsRange, ftl::Flags f .apply(); } +bool RefreshRateOverlay::initCheck() const { + return mSurfaceControl != nullptr; +} + auto RefreshRateOverlay::getOrCreateBuffers(Fps vsyncRate, Fps renderFps) -> const Buffers& { static const Buffers kNoBuffers; if (!mSurfaceControl) return kNoBuffers; diff --git a/services/surfaceflinger/RefreshRateOverlay.h b/services/surfaceflinger/RefreshRateOverlay.h index ae334e54ef..0fec470edc 100644 --- a/services/surfaceflinger/RefreshRateOverlay.h +++ b/services/surfaceflinger/RefreshRateOverlay.h @@ -37,6 +37,10 @@ class GraphicBuffer; class SurfaceFlinger; class RefreshRateOverlay { +private: + // Effectively making the constructor private, while keeping std::make_unique work + struct ConstructorTag {}; + public: enum class Features { Spinner = 1 << 0, @@ -45,7 +49,7 @@ public: SetByHwc = 1 << 3, }; - RefreshRateOverlay(FpsRange, ftl::Flags); + static std::unique_ptr create(FpsRange, ftl::Flags); void setLayerStack(ui::LayerStack); void setViewport(ui::Size); @@ -54,7 +58,11 @@ public: void animate(); bool isSetByHwc() const { return mFeatures.test(RefreshRateOverlay::Features::SetByHwc); } + RefreshRateOverlay(ConstructorTag, FpsRange, ftl::Flags); + private: + bool initCheck() const; + using Buffers = std::vector>; static Buffers draw(int vsyncRate, int renderFps, SkColor, ui::Transform::RotationFlags, -- GitLab From c99303bbd4907ea69862bf970e6b98dc3a03d72e Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Mon, 2 Oct 2023 07:25:24 +0000 Subject: [PATCH 0728/1187] Add a flag for the VRR small dirty detection Test: presubmit Bug: 283055450 Change-Id: Iea2b2edc65e2b5d702f380c655c37327f0aa1308 --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- services/surfaceflinger/surfaceflinger_flags.aconfig | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 12aacad64c..d0e39597fd 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4015,7 +4015,7 @@ void SurfaceFlinger::initScheduler(const sp& display) { if (sysprop::use_content_detection_for_refresh_rate(false)) { features |= Feature::kContentDetection; - if (base::GetBoolProperty("debug.sf.enable_small_dirty_detection"s, false)) { + if (flags::vrr_small_dirty_detection()) { features |= Feature::kSmallDirtyContentDetection; } } diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig index d4ab7869a0..fedf08bae8 100644 --- a/services/surfaceflinger/surfaceflinger_flags.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags.aconfig @@ -30,3 +30,11 @@ flag { bug: "284845445" is_fixed_read_only: true } + +flag { + name: "vrr_small_dirty_detection" + namespace: "core_graphics" + description: "Controls small dirty detection for VRR" + bug: "283055450" + is_fixed_read_only: true +} -- GitLab From 80e8cfe3d73baecc749dba0de0bd7f96c17a5eec Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 29 Sep 2023 17:03:45 -0700 Subject: [PATCH 0729/1187] [sf-newfe] update default frame rate compatibility Bug: 300701739 Test: presubmit Change-Id: I3dbfd8d7ef6fe801d4d750c1828d09da511ce283 --- services/surfaceflinger/FrontEnd/LayerSnapshot.cpp | 9 +++++++++ services/surfaceflinger/FrontEnd/LayerSnapshot.h | 2 ++ services/surfaceflinger/Layer.cpp | 2 +- services/surfaceflinger/Scheduler/LayerHistory.cpp | 10 +++++----- services/surfaceflinger/Scheduler/LayerHistory.h | 4 +++- services/surfaceflinger/Scheduler/Scheduler.cpp | 5 +++-- services/surfaceflinger/Scheduler/Scheduler.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 13 +++++++++++-- .../tests/unittests/LayerHistoryTest.cpp | 9 +++++++-- 9 files changed, 42 insertions(+), 14 deletions(-) diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index 899d2dedaf..f9c8e812dd 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -398,6 +398,15 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate geomCrop = requested.crop; } + if (forceUpdate || requested.what & layer_state_t::eDefaultFrameRateCompatibilityChanged) { + const auto compatibility = + Layer::FrameRate::convertCompatibility(requested.defaultFrameRateCompatibility); + if (defaultFrameRateCompatibility != compatibility) { + clientChanges |= layer_state_t::eDefaultFrameRateCompatibilityChanged; + } + defaultFrameRateCompatibility = compatibility; + } + if (forceUpdate || requested.what & (layer_state_t::eFlagsChanged | layer_state_t::eBufferChanged | diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index a5e9368565..a1c72a94e0 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -86,6 +86,8 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { gui::GameMode gameMode; scheduler::LayerInfo::FrameRate frameRate; scheduler::LayerInfo::FrameRateSelectionStrategy frameRateSelectionStrategy; + scheduler::FrameRateCompatibility defaultFrameRateCompatibility = + scheduler::FrameRateCompatibility::Default; ui::Transform::RotationFlags fixedTransformHint; std::optional transformHint; bool handleSkipScreenshotFlag = false; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 415f55ae66..5ae29990dc 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1155,7 +1155,7 @@ bool Layer::setDefaultFrameRateCompatibility(FrameRateCompatibility compatibilit if (mDrawingState.defaultFrameRateCompatibility == compatibility) return false; mDrawingState.defaultFrameRateCompatibility = compatibility; mDrawingState.modified = true; - mFlinger->mScheduler->setDefaultFrameRateCompatibility(this); + mFlinger->mScheduler->setDefaultFrameRateCompatibility(sequence, compatibility); setTransactionFlags(eTransactionNeeded); return true; } diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index b98b8007ac..4e5659ec5a 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -141,20 +141,20 @@ void LayerHistory::record(int32_t id, const LayerProps& layerProps, nsecs_t pres } } -void LayerHistory::setDefaultFrameRateCompatibility(Layer* layer, bool contentDetectionEnabled) { +void LayerHistory::setDefaultFrameRateCompatibility(int32_t id, + FrameRateCompatibility frameRateCompatibility, + bool contentDetectionEnabled) { std::lock_guard lock(mLock); - auto id = layer->getSequence(); auto [found, layerPair] = findLayer(id); if (found == LayerStatus::NotFound) { // Offscreen layer - ALOGV("%s: %s not registered", __func__, layer->getName().c_str()); + ALOGV("%s: %d not registered", __func__, id); return; } const auto& info = layerPair->second; - info->setDefaultLayerVote( - getVoteType(layer->getDefaultFrameRateCompatibility(), contentDetectionEnabled)); + info->setDefaultLayerVote(getVoteType(frameRateCompatibility, contentDetectionEnabled)); } auto LayerHistory::summarize(const RefreshRateSelector& selector, nsecs_t now) -> Summary { diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 5750ea7898..40bda83e62 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -29,6 +29,7 @@ #include "EventThread.h" +#include "FrameRateCompatibility.h" #include "RefreshRateSelector.h" namespace android { @@ -70,7 +71,8 @@ public: // Updates the default frame rate compatibility which takes effect when the app // does not set a preference for refresh rate. - void setDefaultFrameRateCompatibility(Layer*, bool contentDetectionEnabled); + void setDefaultFrameRateCompatibility(int32_t id, FrameRateCompatibility frameRateCompatibility, + bool contentDetectionEnabled); using Summary = std::vector; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 68e2ce9b98..76f1af9f56 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -635,8 +635,9 @@ void Scheduler::setModeChangePending(bool pending) { mLayerHistory.setModeChangePending(pending); } -void Scheduler::setDefaultFrameRateCompatibility(Layer* layer) { - mLayerHistory.setDefaultFrameRateCompatibility(layer, +void Scheduler::setDefaultFrameRateCompatibility( + int32_t id, scheduler::FrameRateCompatibility frameRateCompatibility) { + mLayerHistory.setDefaultFrameRateCompatibility(id, frameRateCompatibility, mFeatures.test(Feature::kContentDetection)); } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index f652bb2627..e6db654637 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -232,7 +232,7 @@ public: void recordLayerHistory(int32_t id, const LayerProps& layerProps, nsecs_t presentTime, LayerHistory::LayerUpdateType) EXCLUDES(mDisplayLock); void setModeChangePending(bool pending); - void setDefaultFrameRateCompatibility(Layer*); + void setDefaultFrameRateCompatibility(int32_t id, scheduler::FrameRateCompatibility); void deregisterLayer(Layer*); void onLayerDestroyed(Layer*) EXCLUDES(mChoreographerLock); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 3f52444c40..4d8dc94db5 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2205,8 +2205,12 @@ bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, nsecs_t frameTi void SurfaceFlinger::updateLayerHistory(const frontend::LayerSnapshot& snapshot) { using Changes = frontend::RequestedLayerState::Changes; - if (snapshot.path.isClone() || - !snapshot.changes.any(Changes::FrameRate | Changes::Buffer | Changes::Animation)) { + if (snapshot.path.isClone()) { + return; + } + + if (!snapshot.changes.any(Changes::FrameRate | Changes::Buffer | Changes::Animation) && + (snapshot.clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) == 0) { return; } @@ -2226,6 +2230,11 @@ void SurfaceFlinger::updateLayerHistory(const frontend::LayerSnapshot& snapshot) it->second->recordLayerHistoryAnimationTx(layerProps); } + if (snapshot.clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) { + mScheduler->setDefaultFrameRateCompatibility(snapshot.sequence, + snapshot.defaultFrameRateCompatibility); + } + if (snapshot.changes.test(Changes::FrameRate)) { it->second->setFrameRateForLayerTree(snapshot.frameRate, layerProps); } diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index cc7a45c78f..549a362af3 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -165,7 +165,10 @@ TEST_F(LayerHistoryTest, singleLayerNoVoteDefaultCompatibility) { history().record(layer->getSequence(), layer->getLayerProps(), 0, time, LayerHistory::LayerUpdateType::Buffer); - history().setDefaultFrameRateCompatibility(layer.get(), true /* contentDetectionEnabled */); + history().setDefaultFrameRateCompatibility(layer->getSequence(), + + layer->getDefaultFrameRateCompatibility(), + true /* contentDetectionEnabled */); EXPECT_TRUE(summarizeLayerHistory(time).empty()); EXPECT_EQ(1, activeLayerCount()); @@ -188,7 +191,9 @@ TEST_F(LayerHistoryTest, singleLayerMinVoteDefaultCompatibility) { history().record(layer->getSequence(), layer->getLayerProps(), 0, time, LayerHistory::LayerUpdateType::Buffer); - history().setDefaultFrameRateCompatibility(layer.get(), true /* contentDetectionEnabled */); + history().setDefaultFrameRateCompatibility(layer->getSequence(), + layer->getDefaultFrameRateCompatibility(), + true /* contentDetectionEnabled */); auto summary = summarizeLayerHistory(time); ASSERT_EQ(1, summarizeLayerHistory(time).size()); -- GitLab From f3425fab505e8b86c39e510bd549b0a6f1e9f843 Mon Sep 17 00:00:00 2001 From: sergiuferentz Date: Thu, 28 Sep 2023 12:49:25 +0000 Subject: [PATCH 0730/1187] Bump android.hardware.graphics.common V4->V5 Test: Build Bug: 291142745 Change-Id: I0d35038b1183db5530a36132e4f6452d7f778cfa --- libs/gralloc/types/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp index 6d1dfe8124..aab1276b47 100644 --- a/libs/gralloc/types/Android.bp +++ b/libs/gralloc/types/Android.bp @@ -58,7 +58,7 @@ cc_library { ], export_shared_lib_headers: [ - "android.hardware.graphics.common-V4-ndk", + "android.hardware.graphics.common-V5-ndk", "android.hardware.graphics.mapper@4.0", "libhidlbase", ], -- GitLab From 47989334c20a2ff97716d279e1343208c00034a8 Mon Sep 17 00:00:00 2001 From: sergiuferentz Date: Tue, 26 Sep 2023 10:24:36 +0000 Subject: [PATCH 0731/1187] Refactoring HAL Dataspace to AIDL Dataspace Bug: 291142745 Test: Build Change-Id: Icfa9562f03d58c4cb8d90151c3c5a4617c404375 --- libs/gralloc/types/Gralloc4.cpp | 4 +++ vulkan/libvulkan/swapchain.cpp | 59 +++++++++++++++------------------ 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp index 61e6657621..ce35906949 100644 --- a/libs/gralloc/types/Gralloc4.cpp +++ b/libs/gralloc/types/Gralloc4.cpp @@ -1307,6 +1307,10 @@ std::string getChromaSitingName(const ExtendableType& chromaSiting) { return "SitedInterstitial"; case ChromaSiting::COSITED_HORIZONTAL: return "CositedHorizontal"; + case ChromaSiting::COSITED_VERTICAL: + return "CositedVertical"; + case ChromaSiting::COSITED_BOTH: + return "CositedBoth"; } } diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index dcef54dc38..483863db2e 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -16,6 +16,7 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include #include #include #include @@ -37,6 +38,7 @@ #include "driver.h" using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat; +using DataSpace = aidl::android::hardware::graphics::common::Dataspace; using android::hardware::graphics::common::V1_0::BufferUsage; namespace vulkan { @@ -532,61 +534,51 @@ PixelFormat GetNativePixelFormat(VkFormat format) { return native_format; } -android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace, - PixelFormat pixelFormat) { +DataSpace GetNativeDataspace(VkColorSpaceKHR colorspace, + PixelFormat pixelFormat) { switch (colorspace) { case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR: - return HAL_DATASPACE_V0_SRGB; + return DataSpace::SRGB; case VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT: - return HAL_DATASPACE_DISPLAY_P3; + return DataSpace::DISPLAY_P3; case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT: - return HAL_DATASPACE_V0_SCRGB_LINEAR; + return DataSpace::SCRGB_LINEAR; case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT: - return HAL_DATASPACE_V0_SCRGB; + return DataSpace::SCRGB; case VK_COLOR_SPACE_DCI_P3_LINEAR_EXT: - return HAL_DATASPACE_DCI_P3_LINEAR; + return DataSpace::DCI_P3_LINEAR; case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT: - return HAL_DATASPACE_DCI_P3; + return DataSpace::DCI_P3; case VK_COLOR_SPACE_BT709_LINEAR_EXT: - return HAL_DATASPACE_V0_SRGB_LINEAR; + return DataSpace::SRGB_LINEAR; case VK_COLOR_SPACE_BT709_NONLINEAR_EXT: - return HAL_DATASPACE_V0_SRGB; + return DataSpace::SRGB; case VK_COLOR_SPACE_BT2020_LINEAR_EXT: if (pixelFormat == PixelFormat::RGBA_FP16) { - return static_cast( - HAL_DATASPACE_STANDARD_BT2020 | - HAL_DATASPACE_TRANSFER_LINEAR | - HAL_DATASPACE_RANGE_EXTENDED); + return DataSpace::BT2020_LINEAR_EXTENDED; } else { - return HAL_DATASPACE_BT2020_LINEAR; + return DataSpace::BT2020_LINEAR; } case VK_COLOR_SPACE_HDR10_ST2084_EXT: - return static_cast( - HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 | - HAL_DATASPACE_RANGE_FULL); + return DataSpace::BT2020_PQ; case VK_COLOR_SPACE_DOLBYVISION_EXT: - return static_cast( - HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 | - HAL_DATASPACE_RANGE_FULL); + return DataSpace::BT2020_PQ; case VK_COLOR_SPACE_HDR10_HLG_EXT: - return static_cast(HAL_DATASPACE_BT2020_HLG); + return DataSpace::BT2020_HLG; case VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT: - return static_cast( - HAL_DATASPACE_STANDARD_ADOBE_RGB | - HAL_DATASPACE_TRANSFER_LINEAR | HAL_DATASPACE_RANGE_FULL); + return DataSpace::ADOBE_RGB_LINEAR; case VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT: - return HAL_DATASPACE_ADOBE_RGB; - + return DataSpace::ADOBE_RGB; // Pass through is intended to allow app to provide data that is passed // to the display system without modification. case VK_COLOR_SPACE_PASS_THROUGH_EXT: - return HAL_DATASPACE_ARBITRARY; + return DataSpace::ARBITRARY; default: // This indicates that we don't know about the // dataspace specified and we should indicate that // it's unsupported - return HAL_DATASPACE_UNKNOWN; + return DataSpace::UNKNOWN; } } @@ -1393,9 +1385,9 @@ VkResult CreateSwapchainKHR(VkDevice device, PixelFormat native_pixel_format = GetNativePixelFormat(create_info->imageFormat); - android_dataspace native_dataspace = + DataSpace native_dataspace = GetNativeDataspace(create_info->imageColorSpace, native_pixel_format); - if (native_dataspace == HAL_DATASPACE_UNKNOWN) { + if (native_dataspace == DataSpace::UNKNOWN) { ALOGE( "CreateSwapchainKHR(VkSwapchainCreateInfoKHR.imageColorSpace = %d) " "failed: Unsupported color space", @@ -1501,8 +1493,9 @@ VkResult CreateSwapchainKHR(VkDevice device, } /* Respect consumer default dataspace upon HAL_DATASPACE_ARBITRARY. */ - if (native_dataspace != HAL_DATASPACE_ARBITRARY) { - err = native_window_set_buffers_data_space(window, native_dataspace); + if (native_dataspace != DataSpace::ARBITRARY) { + err = native_window_set_buffers_data_space( + window, static_cast(native_dataspace)); if (err != android::OK) { ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)", native_dataspace, strerror(-err), err); -- GitLab From c033dfbb5f7053585bbdbd1b8c3f92c78ae3c94b Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 3 Oct 2023 10:45:16 -0700 Subject: [PATCH 0732/1187] Reset no focused window timeout when window gets focus If a window is about to receive focus, then we should stop the "no focused window" timeout. Otherwise, we would report an ANR, even though the focused window was added within the "dispatching timeout" grace period of the application. Bug: 302326393 Test: TEST=inputflinger_tests; m $TEST && adb sync data && adb shell -t data/nativetest64/$TEST/$TEST --gtest_filter="*FocusedWindowWithoutSetFocusedApplication_NoAnr*" --gtest_repeat=3000 --gtest_break_on_failure Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST --gtest_filter="*FocusedWindowWithoutSetFocusedApplication_NoAnr" --gtest_repeat=1000 --gtest_break_on_failure Change-Id: Ie272545e1be23ff5ef4d1bf24507a8ba7e6d170b --- services/inputflinger/dispatcher/InputDispatcher.cpp | 1 + services/inputflinger/tests/InputDispatcher_test.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 42516828c5..6226a19897 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -6596,6 +6596,7 @@ void InputDispatcher::onFocusChangedLocked(const FocusResolver::FocusChanges& ch } } if (changes.newFocus) { + resetNoFocusedWindowTimeoutLocked(); enqueueFocusEventLocked(changes.newFocus, /*hasFocus=*/true, changes.reason); } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 215989d0c4..703c3f74cd 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -7988,7 +7988,7 @@ TEST_F(InputDispatcherMultiWindowAnr, SplitTouch_SingleWindowAnr) { TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) { std::shared_ptr focusedApplication = std::make_shared(); - focusedApplication->setDispatchingTimeout(200ms); + focusedApplication->setDispatchingTimeout(300ms); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication); // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused. mFocusedWindow->setFocusable(false); -- GitLab From ba308f5fd0a120212833e7a7988d819cf263c940 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Fri, 29 Sep 2023 14:50:42 -0700 Subject: [PATCH 0733/1187] [Debugging] Dump display's hdr luminance info. Bug: N/A Test: builds and dump SF to check, see https://screenshot.googleplex.com/7n87kJoocK4LNmc Change-Id: I8ffb659bf04bc55e55f2d525f046bb65e12493b0 --- .../CompositionEngine/src/DisplayColorProfile.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp index 97725ea636..f339d41ef8 100644 --- a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp +++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp @@ -392,6 +392,10 @@ void DisplayColorProfile::dump(std::string& out) const { dumpVal(out, "dv", hasDolbyVisionSupport()); dumpVal(out, "metadata", getSupportedPerFrameMetadata()); + out.append("\n Hdr Luminance Info:"); + dumpVal(out, "desiredMinLuminance", mHdrCapabilities.getDesiredMinLuminance()); + dumpVal(out, "desiredMaxLuminance", mHdrCapabilities.getDesiredMaxLuminance()); + dumpVal(out, "desiredMaxAverageLuminance", mHdrCapabilities.getDesiredMaxAverageLuminance()); out.append("\n"); } -- GitLab From 20dd0bf9318a30489fda8c92e440077649bc7b6e Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Wed, 4 Oct 2023 00:17:03 +0000 Subject: [PATCH 0734/1187] Migrate libsurfaceflinger_unittest off ASan Add to hwasan-presubmit so it gets run with HWASan instead Bug: 300289881 Change-Id: I9ec730cce6f554027fa0206ab9c70f9d64bb9204 --- services/surfaceflinger/TEST_MAPPING | 3 +++ .../surfaceflinger/tests/unittests/Android.bp | 16 ---------------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/services/surfaceflinger/TEST_MAPPING b/services/surfaceflinger/TEST_MAPPING index 6f53d620ba..922fd0718e 100644 --- a/services/surfaceflinger/TEST_MAPPING +++ b/services/surfaceflinger/TEST_MAPPING @@ -36,6 +36,9 @@ "hwasan-presubmit": [ { "name": "libscheduler_test" + }, + { + "name": "libsurfaceflinger_unittest" } ] } diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index f4516c7635..bc27e7e782 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -50,22 +50,6 @@ cc_test { "surfaceflinger_defaults", ], test_suites: ["device-tests"], - sanitize: { - // Using the address sanitizer not only helps uncover issues in the code - // covered by the tests, but also covers some of the tricky injection of - // fakes the unit tests currently do. - // - // Note: If you get an runtime link error like: - // - // CANNOT LINK EXECUTABLE "/data/local/tmp/libsurfaceflinger_unittest": library "libclang_rt.asan-aarch64-android.so" not found - // - // it is because the address sanitizer shared objects are not installed - // by default in the system image. - // - // You can either "make dist tests" before flashing, or set this - // option to false temporarily. - address: true, - }, static_libs: ["libc++fs"], srcs: [ ":libsurfaceflinger_mock_sources", -- GitLab From 631a14e89b5a2d6c47ab001de5ec1333b67c7962 Mon Sep 17 00:00:00 2001 From: Asmita Poddar Date: Tue, 3 Oct 2023 10:22:07 +0000 Subject: [PATCH 0735/1187] Move common device metrics code to InputDeviceMetricsSource Move common device metrics code from InputDeviceMetricsCollector to InputDeviceMetricsSource. The common code moved is: * enum class InputDeviceUsageSource * InputDeviceUsageSource getUsageSourceForKeyArgs(int32_t, const NotifyKeyArgs&) * set getUsageSourcesForMotionArgs(const NotifyMotionArgs&) This code will be used by both InputDeviceMetricsCollector, which is a part of inputflinger as well as LatencyTracker, which is a part of the dispatcher. InputDeviceMetricsSource can be included in the places using the common code. Bug: 303059859 Test: atest inputflinger_tests:InputDeviceMetricsSourceDeviceClassificationTest Change-Id: Ia8528e641cd162d5025495d5bf6903b2dbab2ed3 --- services/inputflinger/Android.bp | 2 + .../InputDeviceMetricsCollector.cpp | 93 +----- .../InputDeviceMetricsCollector.h | 34 +- .../inputflinger/InputDeviceMetricsSource.cpp | 118 +++++++ .../inputflinger/InputDeviceMetricsSource.h | 58 ++++ services/inputflinger/tests/Android.bp | 1 + .../InputDeviceMetricsCollector_test.cpp | 257 --------------- .../tests/InputDeviceMetricsSource_test.cpp | 296 ++++++++++++++++++ 8 files changed, 477 insertions(+), 382 deletions(-) create mode 100644 services/inputflinger/InputDeviceMetricsSource.cpp create mode 100644 services/inputflinger/InputDeviceMetricsSource.h create mode 100644 services/inputflinger/tests/InputDeviceMetricsSource_test.cpp diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 5d1d4af44c..76729efb0a 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -182,6 +182,7 @@ cc_library_headers { filegroup { name: "libinputflinger_base_sources", srcs: [ + "InputDeviceMetricsSource.cpp", "InputListener.cpp", "InputReaderBase.cpp", "InputThread.cpp", @@ -199,6 +200,7 @@ cc_defaults { "libcutils", "libinput", "liblog", + "libstatslog", "libutils", ], header_libs: [ diff --git a/services/inputflinger/InputDeviceMetricsCollector.cpp b/services/inputflinger/InputDeviceMetricsCollector.cpp index 8e04150efa..cefb14059c 100644 --- a/services/inputflinger/InputDeviceMetricsCollector.cpp +++ b/services/inputflinger/InputDeviceMetricsCollector.cpp @@ -17,11 +17,10 @@ #define LOG_TAG "InputDeviceMetricsCollector" #include "InputDeviceMetricsCollector.h" -#include "KeyCodeClassifications.h" +#include "InputDeviceMetricsSource.h" #include #include -#include namespace android { @@ -113,96 +112,6 @@ bool isIgnoredInputDeviceId(int32_t deviceId) { } // namespace -InputDeviceUsageSource getUsageSourceForKeyArgs(int32_t keyboardType, - const NotifyKeyArgs& keyArgs) { - if (!isFromSource(keyArgs.source, AINPUT_SOURCE_KEYBOARD)) { - return InputDeviceUsageSource::UNKNOWN; - } - - if (isFromSource(keyArgs.source, AINPUT_SOURCE_DPAD) && - DPAD_ALL_KEYCODES.count(keyArgs.keyCode) != 0) { - return InputDeviceUsageSource::DPAD; - } - - if (isFromSource(keyArgs.source, AINPUT_SOURCE_GAMEPAD) && - GAMEPAD_KEYCODES.count(keyArgs.keyCode) != 0) { - return InputDeviceUsageSource::GAMEPAD; - } - - if (keyboardType == AINPUT_KEYBOARD_TYPE_ALPHABETIC) { - return InputDeviceUsageSource::KEYBOARD; - } - - return InputDeviceUsageSource::BUTTONS; -} - -std::set getUsageSourcesForMotionArgs(const NotifyMotionArgs& motionArgs) { - LOG_ALWAYS_FATAL_IF(motionArgs.getPointerCount() < 1, "Received motion args without pointers"); - std::set sources; - - for (uint32_t i = 0; i < motionArgs.getPointerCount(); i++) { - const auto toolType = motionArgs.pointerProperties[i].toolType; - if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE)) { - if (toolType == ToolType::MOUSE) { - sources.emplace(InputDeviceUsageSource::MOUSE); - continue; - } - if (toolType == ToolType::FINGER) { - sources.emplace(InputDeviceUsageSource::TOUCHPAD); - continue; - } - if (isStylusToolType(toolType)) { - sources.emplace(InputDeviceUsageSource::STYLUS_INDIRECT); - continue; - } - } - if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE_RELATIVE) && - toolType == ToolType::MOUSE) { - sources.emplace(InputDeviceUsageSource::MOUSE_CAPTURED); - continue; - } - if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHPAD) && - toolType == ToolType::FINGER) { - sources.emplace(InputDeviceUsageSource::TOUCHPAD_CAPTURED); - continue; - } - if (isFromSource(motionArgs.source, AINPUT_SOURCE_BLUETOOTH_STYLUS) && - isStylusToolType(toolType)) { - sources.emplace(InputDeviceUsageSource::STYLUS_FUSED); - continue; - } - if (isFromSource(motionArgs.source, AINPUT_SOURCE_STYLUS) && isStylusToolType(toolType)) { - sources.emplace(InputDeviceUsageSource::STYLUS_DIRECT); - continue; - } - if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCH_NAVIGATION)) { - sources.emplace(InputDeviceUsageSource::TOUCH_NAVIGATION); - continue; - } - if (isFromSource(motionArgs.source, AINPUT_SOURCE_JOYSTICK)) { - sources.emplace(InputDeviceUsageSource::JOYSTICK); - continue; - } - if (isFromSource(motionArgs.source, AINPUT_SOURCE_ROTARY_ENCODER)) { - sources.emplace(InputDeviceUsageSource::ROTARY_ENCODER); - continue; - } - if (isFromSource(motionArgs.source, AINPUT_SOURCE_TRACKBALL)) { - sources.emplace(InputDeviceUsageSource::TRACKBALL); - continue; - } - if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHSCREEN)) { - sources.emplace(InputDeviceUsageSource::TOUCHSCREEN); - continue; - } - sources.emplace(InputDeviceUsageSource::UNKNOWN); - } - - return sources; -} - -// --- InputDeviceMetricsCollector --- - InputDeviceMetricsCollector::InputDeviceMetricsCollector(InputListenerInterface& listener) : InputDeviceMetricsCollector(listener, sStatsdLogger, DEFAULT_USAGE_SESSION_TIMEOUT) {} diff --git a/services/inputflinger/InputDeviceMetricsCollector.h b/services/inputflinger/InputDeviceMetricsCollector.h index 7775087530..9633664a0e 100644 --- a/services/inputflinger/InputDeviceMetricsCollector.h +++ b/services/inputflinger/InputDeviceMetricsCollector.h @@ -16,6 +16,7 @@ #pragma once +#include "InputDeviceMetricsSource.h" #include "InputListener.h" #include "NotifyArgs.h" #include "SyncQueue.h" @@ -23,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -52,38 +52,6 @@ public: virtual void dump(std::string& dump) = 0; }; -/** - * Enum representation of the InputDeviceUsageSource. - */ -enum class InputDeviceUsageSource : int32_t { - UNKNOWN = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__UNKNOWN, - BUTTONS = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__BUTTONS, - KEYBOARD = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__KEYBOARD, - DPAD = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__DPAD, - GAMEPAD = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__GAMEPAD, - JOYSTICK = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__JOYSTICK, - MOUSE = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__MOUSE, - MOUSE_CAPTURED = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__MOUSE_CAPTURED, - TOUCHPAD = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TOUCHPAD, - TOUCHPAD_CAPTURED = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TOUCHPAD_CAPTURED, - ROTARY_ENCODER = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__ROTARY_ENCODER, - STYLUS_DIRECT = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__STYLUS_DIRECT, - STYLUS_INDIRECT = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__STYLUS_INDIRECT, - STYLUS_FUSED = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__STYLUS_FUSED, - TOUCH_NAVIGATION = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TOUCH_NAVIGATION, - TOUCHSCREEN = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TOUCHSCREEN, - TRACKBALL = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TRACKBALL, - - ftl_first = UNKNOWN, - ftl_last = TRACKBALL, -}; - -/** Returns the InputDeviceUsageSource that corresponds to the key event. */ -InputDeviceUsageSource getUsageSourceForKeyArgs(int32_t keyboardType, const NotifyKeyArgs&); - -/** Returns the InputDeviceUsageSources that correspond to the motion event. */ -std::set getUsageSourcesForMotionArgs(const NotifyMotionArgs&); - /** The logging interface for the metrics collector, injected for testing. */ class InputDeviceMetricsLogger { public: diff --git a/services/inputflinger/InputDeviceMetricsSource.cpp b/services/inputflinger/InputDeviceMetricsSource.cpp new file mode 100644 index 0000000000..dee4cb836e --- /dev/null +++ b/services/inputflinger/InputDeviceMetricsSource.cpp @@ -0,0 +1,118 @@ +/* + * Copyright 2023 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 "InputDeviceMetricsSource.h" + +#include "KeyCodeClassifications.h" + +#include +#include +#include +#include + +#include + +namespace android { + +InputDeviceUsageSource getUsageSourceForKeyArgs(int32_t keyboardType, + const NotifyKeyArgs& keyArgs) { + if (!isFromSource(keyArgs.source, AINPUT_SOURCE_KEYBOARD)) { + return InputDeviceUsageSource::UNKNOWN; + } + + if (isFromSource(keyArgs.source, AINPUT_SOURCE_DPAD) && + DPAD_ALL_KEYCODES.count(keyArgs.keyCode) != 0) { + return InputDeviceUsageSource::DPAD; + } + + if (isFromSource(keyArgs.source, AINPUT_SOURCE_GAMEPAD) && + GAMEPAD_KEYCODES.count(keyArgs.keyCode) != 0) { + return InputDeviceUsageSource::GAMEPAD; + } + + if (keyboardType == AINPUT_KEYBOARD_TYPE_ALPHABETIC) { + return InputDeviceUsageSource::KEYBOARD; + } + + return InputDeviceUsageSource::BUTTONS; +} + +std::set getUsageSourcesForMotionArgs(const NotifyMotionArgs& motionArgs) { + LOG_ALWAYS_FATAL_IF(motionArgs.getPointerCount() < 1, "Received motion args without pointers"); + std::set sources; + + for (uint32_t i = 0; i < motionArgs.getPointerCount(); i++) { + const auto toolType = motionArgs.pointerProperties[i].toolType; + if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE)) { + if (toolType == ToolType::MOUSE) { + sources.emplace(InputDeviceUsageSource::MOUSE); + continue; + } + if (toolType == ToolType::FINGER) { + sources.emplace(InputDeviceUsageSource::TOUCHPAD); + continue; + } + if (isStylusToolType(toolType)) { + sources.emplace(InputDeviceUsageSource::STYLUS_INDIRECT); + continue; + } + } + if (isFromSource(motionArgs.source, AINPUT_SOURCE_MOUSE_RELATIVE) && + toolType == ToolType::MOUSE) { + sources.emplace(InputDeviceUsageSource::MOUSE_CAPTURED); + continue; + } + if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHPAD) && + toolType == ToolType::FINGER) { + sources.emplace(InputDeviceUsageSource::TOUCHPAD_CAPTURED); + continue; + } + if (isFromSource(motionArgs.source, AINPUT_SOURCE_BLUETOOTH_STYLUS) && + isStylusToolType(toolType)) { + sources.emplace(InputDeviceUsageSource::STYLUS_FUSED); + continue; + } + if (isFromSource(motionArgs.source, AINPUT_SOURCE_STYLUS) && isStylusToolType(toolType)) { + sources.emplace(InputDeviceUsageSource::STYLUS_DIRECT); + continue; + } + if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCH_NAVIGATION)) { + sources.emplace(InputDeviceUsageSource::TOUCH_NAVIGATION); + continue; + } + if (isFromSource(motionArgs.source, AINPUT_SOURCE_JOYSTICK)) { + sources.emplace(InputDeviceUsageSource::JOYSTICK); + continue; + } + if (isFromSource(motionArgs.source, AINPUT_SOURCE_ROTARY_ENCODER)) { + sources.emplace(InputDeviceUsageSource::ROTARY_ENCODER); + continue; + } + if (isFromSource(motionArgs.source, AINPUT_SOURCE_TRACKBALL)) { + sources.emplace(InputDeviceUsageSource::TRACKBALL); + continue; + } + if (isFromSource(motionArgs.source, AINPUT_SOURCE_TOUCHSCREEN)) { + sources.emplace(InputDeviceUsageSource::TOUCHSCREEN); + continue; + } + sources.emplace(InputDeviceUsageSource::UNKNOWN); + } + + return sources; +} + +} // namespace android diff --git a/services/inputflinger/InputDeviceMetricsSource.h b/services/inputflinger/InputDeviceMetricsSource.h new file mode 100644 index 0000000000..3ac91c812a --- /dev/null +++ b/services/inputflinger/InputDeviceMetricsSource.h @@ -0,0 +1,58 @@ +/* + * Copyright 2023 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 "NotifyArgs.h" + +#include +#include + +namespace android { + +/** + * Enum representation of the InputDeviceUsageSource. + */ +enum class InputDeviceUsageSource : int32_t { + UNKNOWN = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__UNKNOWN, + BUTTONS = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__BUTTONS, + KEYBOARD = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__KEYBOARD, + DPAD = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__DPAD, + GAMEPAD = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__GAMEPAD, + JOYSTICK = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__JOYSTICK, + MOUSE = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__MOUSE, + MOUSE_CAPTURED = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__MOUSE_CAPTURED, + TOUCHPAD = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TOUCHPAD, + TOUCHPAD_CAPTURED = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TOUCHPAD_CAPTURED, + ROTARY_ENCODER = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__ROTARY_ENCODER, + STYLUS_DIRECT = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__STYLUS_DIRECT, + STYLUS_INDIRECT = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__STYLUS_INDIRECT, + STYLUS_FUSED = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__STYLUS_FUSED, + TOUCH_NAVIGATION = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TOUCH_NAVIGATION, + TOUCHSCREEN = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TOUCHSCREEN, + TRACKBALL = util::INPUT_DEVICE_USAGE_REPORTED__USAGE_SOURCES__TRACKBALL, + + ftl_first = UNKNOWN, + ftl_last = TRACKBALL, +}; + +/** Returns the InputDeviceUsageSource that corresponds to the key event. */ +InputDeviceUsageSource getUsageSourceForKeyArgs(int32_t keyboardType, const NotifyKeyArgs&); + +/** Returns the InputDeviceUsageSources that correspond to the motion event. */ +std::set getUsageSourcesForMotionArgs(const NotifyMotionArgs&); + +} // namespace android diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index d87a5a7337..c0353af117 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -50,6 +50,7 @@ cc_test { "HardwareProperties_test.cpp", "HardwareStateConverter_test.cpp", "InputDeviceMetricsCollector_test.cpp", + "InputDeviceMetricsSource_test.cpp", "InputMapperTest.cpp", "InputProcessor_test.cpp", "InputProcessorConverter_test.cpp", diff --git a/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp b/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp index fdf9ed13b9..85e055d98e 100644 --- a/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp +++ b/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp @@ -36,7 +36,6 @@ namespace { constexpr auto USAGE_TIMEOUT = 8765309ns; constexpr auto TIME = 999999ns; -constexpr auto ALL_USAGE_SOURCES = ftl::enum_range(); constexpr int32_t DEVICE_ID = 3; constexpr int32_t DEVICE_ID_2 = 4; @@ -48,10 +47,6 @@ const std::string LOCATION = "California"; const std::string UNIQUE_ID = "Yosemite"; constexpr uint32_t TOUCHSCREEN = AINPUT_SOURCE_TOUCHSCREEN; constexpr uint32_t STYLUS = AINPUT_SOURCE_STYLUS; -constexpr uint32_t KEY_SOURCES = - AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD | AINPUT_SOURCE_GAMEPAD; -constexpr int32_t POINTER_1_DOWN = - AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); InputDeviceIdentifier generateTestIdentifier(int32_t id = DEVICE_ID) { InputDeviceIdentifier identifier; @@ -87,258 +82,6 @@ std::set uids(std::initializer_list vals) { } // namespace -// --- InputDeviceMetricsCollectorDeviceClassificationTest --- - -class DeviceClassificationFixture : public ::testing::Test, - public ::testing::WithParamInterface {}; - -TEST_P(DeviceClassificationFixture, ValidClassifications) { - const InputDeviceUsageSource usageSource = GetParam(); - - // Use a switch to ensure a test is added for all source classifications. - switch (usageSource) { - case InputDeviceUsageSource::UNKNOWN: { - ASSERT_EQ(InputDeviceUsageSource::UNKNOWN, - getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NONE, - KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, TOUCHSCREEN) - .build())); - - std::set srcs{InputDeviceUsageSource::UNKNOWN}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_KEYBOARD) - .pointer(PointerBuilder(/*id=*/1, ToolType::PALM) - .x(100) - .y(200)) - .build())); - break; - } - - case InputDeviceUsageSource::BUTTONS: { - ASSERT_EQ(InputDeviceUsageSource::BUTTONS, - getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, - KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) - .keyCode(AKEYCODE_STYLUS_BUTTON_TAIL) - .build())); - break; - } - - case InputDeviceUsageSource::KEYBOARD: { - ASSERT_EQ(InputDeviceUsageSource::KEYBOARD, - getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_ALPHABETIC, - KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) - .build())); - break; - } - - case InputDeviceUsageSource::DPAD: { - ASSERT_EQ(InputDeviceUsageSource::DPAD, - getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, - KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) - .keyCode(AKEYCODE_DPAD_CENTER) - .build())); - - ASSERT_EQ(InputDeviceUsageSource::DPAD, - getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_ALPHABETIC, - KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) - .keyCode(AKEYCODE_DPAD_CENTER) - .build())); - break; - } - - case InputDeviceUsageSource::GAMEPAD: { - ASSERT_EQ(InputDeviceUsageSource::GAMEPAD, - getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, - KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) - .keyCode(AKEYCODE_BUTTON_A) - .build())); - - ASSERT_EQ(InputDeviceUsageSource::GAMEPAD, - getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_ALPHABETIC, - KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) - .keyCode(AKEYCODE_BUTTON_A) - .build())); - break; - } - - case InputDeviceUsageSource::JOYSTICK: { - std::set srcs{InputDeviceUsageSource::JOYSTICK}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_JOYSTICK) - .pointer(PointerBuilder(/*id=*/1, ToolType::UNKNOWN) - .axis(AMOTION_EVENT_AXIS_GAS, 1.f)) - .build())); - break; - } - - case InputDeviceUsageSource::MOUSE: { - std::set srcs{InputDeviceUsageSource::MOUSE}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, - AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(/*id=*/1, ToolType::MOUSE) - .x(100) - .y(200)) - .build())); - break; - } - - case InputDeviceUsageSource::MOUSE_CAPTURED: { - std::set srcs{InputDeviceUsageSource::MOUSE_CAPTURED}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, - AINPUT_SOURCE_MOUSE_RELATIVE) - .pointer(PointerBuilder(/*id=*/1, ToolType::MOUSE) - .x(100) - .y(200) - .axis(AMOTION_EVENT_AXIS_RELATIVE_X, 100) - .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, 200)) - .build())); - break; - } - - case InputDeviceUsageSource::TOUCHPAD: { - std::set srcs{InputDeviceUsageSource::TOUCHPAD}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) - .x(100) - .y(200)) - .build())); - break; - } - - case InputDeviceUsageSource::TOUCHPAD_CAPTURED: { - std::set srcs{InputDeviceUsageSource::TOUCHPAD_CAPTURED}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHPAD) - .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) - .x(100) - .y(200) - .axis(AMOTION_EVENT_AXIS_RELATIVE_X, 1) - .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, 2)) - .build())); - break; - } - - case InputDeviceUsageSource::ROTARY_ENCODER: { - std::set srcs{InputDeviceUsageSource::ROTARY_ENCODER}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(AMOTION_EVENT_ACTION_SCROLL, - AINPUT_SOURCE_ROTARY_ENCODER) - .pointer(PointerBuilder(/*id=*/1, ToolType::UNKNOWN) - .axis(AMOTION_EVENT_AXIS_SCROLL, 10) - .axis(AMOTION_EVENT_AXIS_VSCROLL, 10)) - .build())); - break; - } - - case InputDeviceUsageSource::STYLUS_DIRECT: { - std::set srcs{InputDeviceUsageSource::STYLUS_DIRECT}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, - STYLUS | TOUCHSCREEN) - .pointer(PointerBuilder(/*id=*/1, ToolType::STYLUS) - .x(100) - .y(200)) - .build())); - break; - } - - case InputDeviceUsageSource::STYLUS_INDIRECT: { - std::set srcs{InputDeviceUsageSource::STYLUS_INDIRECT}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, - STYLUS | TOUCHSCREEN | AINPUT_SOURCE_MOUSE) - .pointer(PointerBuilder(/*id=*/1, ToolType::STYLUS) - .x(100) - .y(200)) - .build())); - break; - } - - case InputDeviceUsageSource::STYLUS_FUSED: { - std::set srcs{InputDeviceUsageSource::STYLUS_FUSED}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, - AINPUT_SOURCE_BLUETOOTH_STYLUS | TOUCHSCREEN) - .pointer(PointerBuilder(/*id=*/1, ToolType::STYLUS) - .x(100) - .y(200)) - .build())); - break; - } - - case InputDeviceUsageSource::TOUCH_NAVIGATION: { - std::set srcs{InputDeviceUsageSource::TOUCH_NAVIGATION}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, - AINPUT_SOURCE_TOUCH_NAVIGATION) - .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) - .x(100) - .y(200)) - .build())); - break; - } - - case InputDeviceUsageSource::TOUCHSCREEN: { - std::set srcs{InputDeviceUsageSource::TOUCHSCREEN}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(POINTER_1_DOWN, TOUCHSCREEN) - .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) - .x(100) - .y(200)) - .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER) - .x(300) - .y(400)) - .build())); - break; - } - - case InputDeviceUsageSource::TRACKBALL: { - std::set srcs{InputDeviceUsageSource::TRACKBALL}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(AMOTION_EVENT_ACTION_SCROLL, - AINPUT_SOURCE_TRACKBALL) - .pointer(PointerBuilder(/*id=*/1, ToolType::UNKNOWN) - .axis(AMOTION_EVENT_AXIS_VSCROLL, 100) - .axis(AMOTION_EVENT_AXIS_HSCROLL, 200)) - .build())); - break; - } - } -} - -INSTANTIATE_TEST_SUITE_P(InputDeviceMetricsCollectorDeviceClassificationTest, - DeviceClassificationFixture, - ::testing::ValuesIn(ALL_USAGE_SOURCES.begin(), ALL_USAGE_SOURCES.end()), - [](const testing::TestParamInfo& testParamInfo) { - return ftl::enum_string(testParamInfo.param); - }); - -TEST(InputDeviceMetricsCollectorDeviceClassificationTest, MixedClassificationTouchscreenStylus) { - std::set srcs{InputDeviceUsageSource::TOUCHSCREEN, - InputDeviceUsageSource::STYLUS_DIRECT}; - ASSERT_EQ(srcs, - getUsageSourcesForMotionArgs( - MotionArgsBuilder(POINTER_1_DOWN, TOUCHSCREEN | STYLUS) - .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(100).y(200)) - .pointer(PointerBuilder(/*id=*/2, ToolType::STYLUS).x(300).y(400)) - .build())); -} - // --- InputDeviceMetricsCollectorTest --- class InputDeviceMetricsCollectorTest : public testing::Test, public InputDeviceMetricsLogger { diff --git a/services/inputflinger/tests/InputDeviceMetricsSource_test.cpp b/services/inputflinger/tests/InputDeviceMetricsSource_test.cpp new file mode 100644 index 0000000000..84ef52c148 --- /dev/null +++ b/services/inputflinger/tests/InputDeviceMetricsSource_test.cpp @@ -0,0 +1,296 @@ +/* + * Copyright 2023 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 "../InputDeviceMetricsSource.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace android { + +namespace { + +constexpr auto ALL_USAGE_SOURCES = ftl::enum_range(); +constexpr uint32_t TOUCHSCREEN = AINPUT_SOURCE_TOUCHSCREEN; +constexpr uint32_t STYLUS = AINPUT_SOURCE_STYLUS; +constexpr uint32_t KEY_SOURCES = + AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_DPAD | AINPUT_SOURCE_GAMEPAD; +constexpr int32_t POINTER_1_DOWN = + AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + +} // namespace + +// --- InputDeviceMetricsSourceDeviceClassificationTest --- + +class DeviceClassificationFixture : public ::testing::Test, + public ::testing::WithParamInterface {}; + +TEST_P(DeviceClassificationFixture, ValidClassifications) { + const InputDeviceUsageSource usageSource = GetParam(); + + // Use a switch to ensure a test is added for all source classifications. + switch (usageSource) { + case InputDeviceUsageSource::UNKNOWN: { + ASSERT_EQ(InputDeviceUsageSource::UNKNOWN, + getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NONE, + KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, TOUCHSCREEN) + .build())); + + std::set srcs{InputDeviceUsageSource::UNKNOWN}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_KEYBOARD) + .pointer(PointerBuilder(/*id=*/1, ToolType::PALM) + .x(100) + .y(200)) + .build())); + break; + } + + case InputDeviceUsageSource::BUTTONS: { + ASSERT_EQ(InputDeviceUsageSource::BUTTONS, + getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, + KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) + .keyCode(AKEYCODE_STYLUS_BUTTON_TAIL) + .build())); + break; + } + + case InputDeviceUsageSource::KEYBOARD: { + ASSERT_EQ(InputDeviceUsageSource::KEYBOARD, + getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_ALPHABETIC, + KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) + .build())); + break; + } + + case InputDeviceUsageSource::DPAD: { + ASSERT_EQ(InputDeviceUsageSource::DPAD, + getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, + KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) + .keyCode(AKEYCODE_DPAD_CENTER) + .build())); + + ASSERT_EQ(InputDeviceUsageSource::DPAD, + getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_ALPHABETIC, + KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) + .keyCode(AKEYCODE_DPAD_CENTER) + .build())); + break; + } + + case InputDeviceUsageSource::GAMEPAD: { + ASSERT_EQ(InputDeviceUsageSource::GAMEPAD, + getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, + KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) + .keyCode(AKEYCODE_BUTTON_A) + .build())); + + ASSERT_EQ(InputDeviceUsageSource::GAMEPAD, + getUsageSourceForKeyArgs(AINPUT_KEYBOARD_TYPE_ALPHABETIC, + KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, KEY_SOURCES) + .keyCode(AKEYCODE_BUTTON_A) + .build())); + break; + } + + case InputDeviceUsageSource::JOYSTICK: { + std::set srcs{InputDeviceUsageSource::JOYSTICK}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_JOYSTICK) + .pointer(PointerBuilder(/*id=*/1, ToolType::UNKNOWN) + .axis(AMOTION_EVENT_AXIS_GAS, 1.f)) + .build())); + break; + } + + case InputDeviceUsageSource::MOUSE: { + std::set srcs{InputDeviceUsageSource::MOUSE}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, + AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(/*id=*/1, ToolType::MOUSE) + .x(100) + .y(200)) + .build())); + break; + } + + case InputDeviceUsageSource::MOUSE_CAPTURED: { + std::set srcs{InputDeviceUsageSource::MOUSE_CAPTURED}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, + AINPUT_SOURCE_MOUSE_RELATIVE) + .pointer(PointerBuilder(/*id=*/1, ToolType::MOUSE) + .x(100) + .y(200) + .axis(AMOTION_EVENT_AXIS_RELATIVE_X, 100) + .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, 200)) + .build())); + break; + } + + case InputDeviceUsageSource::TOUCHPAD: { + std::set srcs{InputDeviceUsageSource::TOUCHPAD}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) + .x(100) + .y(200)) + .build())); + break; + } + + case InputDeviceUsageSource::TOUCHPAD_CAPTURED: { + std::set srcs{InputDeviceUsageSource::TOUCHPAD_CAPTURED}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHPAD) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) + .x(100) + .y(200) + .axis(AMOTION_EVENT_AXIS_RELATIVE_X, 1) + .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, 2)) + .build())); + break; + } + + case InputDeviceUsageSource::ROTARY_ENCODER: { + std::set srcs{InputDeviceUsageSource::ROTARY_ENCODER}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(AMOTION_EVENT_ACTION_SCROLL, + AINPUT_SOURCE_ROTARY_ENCODER) + .pointer(PointerBuilder(/*id=*/1, ToolType::UNKNOWN) + .axis(AMOTION_EVENT_AXIS_SCROLL, 10) + .axis(AMOTION_EVENT_AXIS_VSCROLL, 10)) + .build())); + break; + } + + case InputDeviceUsageSource::STYLUS_DIRECT: { + std::set srcs{InputDeviceUsageSource::STYLUS_DIRECT}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, + STYLUS | TOUCHSCREEN) + .pointer(PointerBuilder(/*id=*/1, ToolType::STYLUS) + .x(100) + .y(200)) + .build())); + break; + } + + case InputDeviceUsageSource::STYLUS_INDIRECT: { + std::set srcs{InputDeviceUsageSource::STYLUS_INDIRECT}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, + STYLUS | TOUCHSCREEN | AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(/*id=*/1, ToolType::STYLUS) + .x(100) + .y(200)) + .build())); + break; + } + + case InputDeviceUsageSource::STYLUS_FUSED: { + std::set srcs{InputDeviceUsageSource::STYLUS_FUSED}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, + AINPUT_SOURCE_BLUETOOTH_STYLUS | TOUCHSCREEN) + .pointer(PointerBuilder(/*id=*/1, ToolType::STYLUS) + .x(100) + .y(200)) + .build())); + break; + } + + case InputDeviceUsageSource::TOUCH_NAVIGATION: { + std::set srcs{InputDeviceUsageSource::TOUCH_NAVIGATION}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, + AINPUT_SOURCE_TOUCH_NAVIGATION) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) + .x(100) + .y(200)) + .build())); + break; + } + + case InputDeviceUsageSource::TOUCHSCREEN: { + std::set srcs{InputDeviceUsageSource::TOUCHSCREEN}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(POINTER_1_DOWN, TOUCHSCREEN) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER) + .x(100) + .y(200)) + .pointer(PointerBuilder(/*id=*/2, ToolType::FINGER) + .x(300) + .y(400)) + .build())); + break; + } + + case InputDeviceUsageSource::TRACKBALL: { + std::set srcs{InputDeviceUsageSource::TRACKBALL}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(AMOTION_EVENT_ACTION_SCROLL, + AINPUT_SOURCE_TRACKBALL) + .pointer(PointerBuilder(/*id=*/1, ToolType::UNKNOWN) + .axis(AMOTION_EVENT_AXIS_VSCROLL, 100) + .axis(AMOTION_EVENT_AXIS_HSCROLL, 200)) + .build())); + break; + } + } +} + +INSTANTIATE_TEST_SUITE_P(InputDeviceMetricsSourceDeviceClassificationTest, + DeviceClassificationFixture, + ::testing::ValuesIn(ALL_USAGE_SOURCES.begin(), ALL_USAGE_SOURCES.end()), + [](const testing::TestParamInfo& testParamInfo) { + return ftl::enum_string(testParamInfo.param); + }); + +TEST(InputDeviceMetricsSourceDeviceClassificationTest, MixedClassificationTouchscreenStylus) { + std::set srcs{InputDeviceUsageSource::TOUCHSCREEN, + InputDeviceUsageSource::STYLUS_DIRECT}; + ASSERT_EQ(srcs, + getUsageSourcesForMotionArgs( + MotionArgsBuilder(POINTER_1_DOWN, TOUCHSCREEN | STYLUS) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(100).y(200)) + .pointer(PointerBuilder(/*id=*/2, ToolType::STYLUS).x(300).y(400)) + .build())); +} + +} // namespace android -- GitLab From 88daa90013a028ecb62dba46113d3935b98dcbc6 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 3 Oct 2023 14:04:18 -0700 Subject: [PATCH 0736/1187] Allow values from SourceClass inside rust Source Inside ViewTest::testOnTouchEventScroll, some MotionEvents are created without a valid source. During injection, they get appended with SourceClass::Pointer. If these events are sent into the InputVerifier, it's basically being asked to convert 0x2 === AINPUT_SOURCE_CLASS_POINTER into rust's input::Source. This fails during unwrap: $ TEST=libinput_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST [ RUN ] InputVerifierTest.BadSourceProcess thread '' panicked at 'called `Option::unwrap()` on a `None` value', frameworks/native/libs/input/rust/lib.rs:84:35 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace fatal runtime error: failed to initiate panic, error 5 Aborted To mitigate this, add the SourceClass definitions into Source, thus allowing such conversions. Bug: 303143553 Bug: 211379801 Test: TEST=libinput_rust_test; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Test: TEST=libinput_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: I46415d88251937959104bb82a3976e72ffcfcaf9 --- libs/input/rust/input.rs | 24 ++++++++++++++++++++++++ libs/input/tests/InputVerifier_test.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs index 9725b00212..804f96db98 100644 --- a/libs/input/rust/input.rs +++ b/libs/input/rust/input.rs @@ -35,7 +35,20 @@ pub enum SourceClass { bitflags! { /// Source of the input device or input events. + #[derive(Debug, PartialEq)] pub struct Source: u32 { + // Constants from SourceClass, added here for compatibility reasons + /// SourceClass::Button + const SourceClassButton = SourceClass::Button as u32; + /// SourceClass::Pointer + const SourceClassPointer = SourceClass::Pointer as u32; + /// SourceClass::Navigation + const SourceClassNavigation = SourceClass::Navigation as u32; + /// SourceClass::Position + const SourceClassPosition = SourceClass::Position as u32; + /// SourceClass::Joystick + const SourceClassJoystick = SourceClass::Joystick as u32; + /// SOURCE_UNKNOWN const Unknown = input_bindgen::AINPUT_SOURCE_UNKNOWN; /// SOURCE_KEYBOARD @@ -190,3 +203,14 @@ impl Source { self.bits() & class_bits == class_bits } } + +#[cfg(test)] +mod tests { + use crate::input::SourceClass; + use crate::Source; + #[test] + fn convert_source_class_pointer() { + let source = Source::from_bits(input_bindgen::AINPUT_SOURCE_CLASS_POINTER).unwrap(); + assert!(source.is_from_class(SourceClass::Pointer)); + } +} diff --git a/libs/input/tests/InputVerifier_test.cpp b/libs/input/tests/InputVerifier_test.cpp index e24fa6ed0b..e2eb08096b 100644 --- a/libs/input/tests/InputVerifier_test.cpp +++ b/libs/input/tests/InputVerifier_test.cpp @@ -20,10 +20,35 @@ namespace android { +using android::base::Result; + TEST(InputVerifierTest, CreationWithInvalidUtfStringDoesNotCrash) { constexpr char bytes[] = {static_cast(0xC0), static_cast(0x80)}; const std::string name(bytes, sizeof(bytes)); InputVerifier verifier(name); } +TEST(InputVerifierTest, ProcessSourceClassPointer) { + InputVerifier verifier("Verify testOnTouchEventScroll"); + + std::vector properties; + properties.push_back({}); + properties.back().clear(); + properties.back().id = 0; + properties.back().toolType = ToolType::UNKNOWN; + + std::vector coords; + coords.push_back({}); + coords.back().clear(); + coords.back().setAxisValue(AMOTION_EVENT_AXIS_X, 75); + coords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, 300); + + const Result result = + verifier.processMovement(/*deviceId=*/0, AINPUT_SOURCE_CLASS_POINTER, + AMOTION_EVENT_ACTION_DOWN, + /*pointerCount=*/properties.size(), properties.data(), + coords.data(), /*flags=*/0); + ASSERT_TRUE(result.ok()); +} + } // namespace android -- GitLab From d7320ef377d8c3043be62dac303c7a6c8bf53d0c Mon Sep 17 00:00:00 2001 From: Trevor David Black Date: Wed, 23 Aug 2023 21:21:51 +0000 Subject: [PATCH 0737/1187] Deprecate GetSwapchainGrallocUsageANDROID from the platform Bug: 259437988 Change-Id: I9ae19978c7ea5f73292343fb187395ed5dbde270 --- .../include/vulkan/vk_android_native_buffer.h | 15 +- vulkan/libvulkan/driver.cpp | 1 + vulkan/libvulkan/driver.h | 1 + vulkan/libvulkan/swapchain.cpp | 324 ++++++++++++------ 4 files changed, 232 insertions(+), 109 deletions(-) diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h index e78f47003b..7c8e695d67 100644 --- a/vulkan/include/vulkan/vk_android_native_buffer.h +++ b/vulkan/include/vulkan/vk_android_native_buffer.h @@ -60,7 +60,12 @@ extern "C" { * * This version of the extension cleans up a bug introduced in version 9 */ -#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 10 +/* + * NOTE ON VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 11 + * + * This version of the extension deprecates the last of grallocusage + */ +#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 11 #define VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME "VK_ANDROID_native_buffer" #define VK_ANDROID_NATIVE_BUFFER_ENUM(type, id) \ @@ -151,6 +156,8 @@ typedef struct { * pNext: NULL or a pointer to a structure extending this structure * format: value specifying the format the image will be created with * imageUsage: bitmask of VkImageUsageFlagBits describing intended usage + * + * DEPRECATED in SPEC_VERSION 10 */ typedef struct { VkStructureType sType; @@ -167,6 +174,8 @@ typedef struct { * format: value specifying the format the image will be created with * imageUsage: bitmask of VkImageUsageFlagBits describing intended usage * swapchainImageUsage: is a bitmask of VkSwapchainImageUsageFlagsANDROID + * + * DEPRECATED in SPEC_VERSION 11 */ typedef struct { VkStructureType sType; @@ -198,7 +207,7 @@ typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsage3ANDROID)( const VkGrallocUsageInfoANDROID* grallocUsageInfo, uint64_t* grallocUsage); -/* ADDED in SPEC_VERSION 10 */ +/* DEPRECATED in SPEC_VERSION 11 */ typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsage4ANDROID)( VkDevice device, const VkGrallocUsageInfo2ANDROID* grallocUsageInfo, @@ -245,7 +254,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsage3ANDROID( uint64_t* grallocUsage ); -/* ADDED in SPEC_VERSION 10 */ +/* DEPRECATED in SPEC_VERSION 11 */ VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsage4ANDROID( VkDevice device, const VkGrallocUsageInfo2ANDROID* grallocUsageInfo, diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index bdba27e6a1..5d7a4aa170 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -1456,6 +1456,7 @@ VkResult CreateDevice(VkPhysicalDevice physicalDevice, } data->driver_device = dev; + data->driver_physical_device = physicalDevice; *pDevice = dev; diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h index 4d2bbd69e3..4b855e5999 100644 --- a/vulkan/libvulkan/driver.h +++ b/vulkan/libvulkan/driver.h @@ -98,6 +98,7 @@ struct DeviceData { VkDevice driver_device; DeviceDriverTable driver; + VkPhysicalDevice driver_physical_device; }; bool OpenHAL(); diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index c5870d4de2..3a11510f77 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -1361,6 +1362,187 @@ static void DestroySwapchainInternal(VkDevice device, allocator->pfnFree(allocator->pUserData, swapchain); } +static VkResult getProducerUsage(const VkDevice& device, + const VkSwapchainCreateInfoKHR* create_info, + const VkSwapchainImageUsageFlagsANDROID swapchain_image_usage, + bool create_protected_swapchain, + uint64_t* producer_usage) { + // Get the physical device to query the appropriate producer usage + const VkPhysicalDevice& pdev = GetData(device).driver_physical_device; + const InstanceData& instance_data = GetData(pdev); + const InstanceDriverTable& instance_dispatch = instance_data.driver; + if (!instance_dispatch.GetPhysicalDeviceImageFormatProperties2 && + !instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR) { + uint64_t native_usage = 0; + void* usage_info_pNext = nullptr; + VkResult result; + VkImageCompressionControlEXT image_compression = {}; + const auto& dispatch = GetData(device).driver; + if (dispatch.GetSwapchainGrallocUsage4ANDROID) { + ATRACE_BEGIN("GetSwapchainGrallocUsage4ANDROID"); + VkGrallocUsageInfo2ANDROID gralloc_usage_info = {}; + gralloc_usage_info.sType = + VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_2_ANDROID; + gralloc_usage_info.format = create_info->imageFormat; + gralloc_usage_info.imageUsage = create_info->imageUsage; + gralloc_usage_info.swapchainImageUsage = swapchain_image_usage; + + // Look through the pNext chain for an image compression control struct + // if one is found AND the appropriate extensions are enabled, + // append it to be the gralloc usage pNext chain + const VkSwapchainCreateInfoKHR* create_infos = create_info; + while (create_infos->pNext) { + create_infos = reinterpret_cast( + create_infos->pNext); + switch (create_infos->sType) { + case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: { + const VkImageCompressionControlEXT* compression_infos = + reinterpret_cast( + create_infos); + image_compression = *compression_infos; + image_compression.pNext = nullptr; + usage_info_pNext = &image_compression; + } break; + + default: + // Ignore all other info structs + break; + } + } + gralloc_usage_info.pNext = usage_info_pNext; + + result = dispatch.GetSwapchainGrallocUsage4ANDROID( + device, &gralloc_usage_info, &native_usage); + ATRACE_END(); + if (result != VK_SUCCESS) { + ALOGE("vkGetSwapchainGrallocUsage4ANDROID failed: %d", result); + return VK_ERROR_SURFACE_LOST_KHR; + } + } else if (dispatch.GetSwapchainGrallocUsage3ANDROID) { + ATRACE_BEGIN("GetSwapchainGrallocUsage3ANDROID"); + VkGrallocUsageInfoANDROID gralloc_usage_info = {}; + gralloc_usage_info.sType = VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID; + gralloc_usage_info.format = create_info->imageFormat; + gralloc_usage_info.imageUsage = create_info->imageUsage; + + // Look through the pNext chain for an image compression control struct + // if one is found AND the appropriate extensions are enabled, + // append it to be the gralloc usage pNext chain + const VkSwapchainCreateInfoKHR* create_infos = create_info; + while (create_infos->pNext) { + create_infos = reinterpret_cast( + create_infos->pNext); + switch (create_infos->sType) { + case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: { + const VkImageCompressionControlEXT* compression_infos = + reinterpret_cast( + create_infos); + image_compression = *compression_infos; + image_compression.pNext = nullptr; + usage_info_pNext = &image_compression; + } break; + + default: + // Ignore all other info structs + break; + } + } + gralloc_usage_info.pNext = usage_info_pNext; + + result = dispatch.GetSwapchainGrallocUsage3ANDROID( + device, &gralloc_usage_info, &native_usage); + ATRACE_END(); + if (result != VK_SUCCESS) { + ALOGE("vkGetSwapchainGrallocUsage3ANDROID failed: %d", result); + return VK_ERROR_SURFACE_LOST_KHR; + } + } else if (dispatch.GetSwapchainGrallocUsage2ANDROID) { + uint64_t consumer_usage, producer_usage; + ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID"); + result = dispatch.GetSwapchainGrallocUsage2ANDROID( + device, create_info->imageFormat, create_info->imageUsage, + swapchain_image_usage, &consumer_usage, &producer_usage); + ATRACE_END(); + if (result != VK_SUCCESS) { + ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result); + return VK_ERROR_SURFACE_LOST_KHR; + } + native_usage = + convertGralloc1ToBufferUsage(producer_usage, consumer_usage); + } else if (dispatch.GetSwapchainGrallocUsageANDROID) { + ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID"); + int32_t legacy_usage = 0; + result = dispatch.GetSwapchainGrallocUsageANDROID( + device, create_info->imageFormat, create_info->imageUsage, + &legacy_usage); + ATRACE_END(); + if (result != VK_SUCCESS) { + ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result); + return VK_ERROR_SURFACE_LOST_KHR; + } + native_usage = static_cast(legacy_usage); + } + *producer_usage = native_usage; + + return VK_SUCCESS; + } + + // call GetPhysicalDeviceImageFormatProperties2KHR + VkPhysicalDeviceExternalImageFormatInfo external_image_format_info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, + .pNext = nullptr, + .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, + }; + + // AHB does not have an sRGB format so we can't pass it to GPDIFP + // We need to convert the format to unorm if it is srgb + VkFormat format = create_info->imageFormat; + if (format == VK_FORMAT_R8G8B8A8_SRGB) { + format = VK_FORMAT_R8G8B8A8_UNORM; + } + + VkPhysicalDeviceImageFormatInfo2 image_format_info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + .pNext = &external_image_format_info, + .format = format, + .type = VK_IMAGE_TYPE_2D, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = create_info->imageUsage, + .flags = create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u, + }; + + VkAndroidHardwareBufferUsageANDROID ahb_usage; + ahb_usage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID; + ahb_usage.pNext = nullptr; + + VkImageFormatProperties2 image_format_properties; + image_format_properties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; + image_format_properties.pNext = &ahb_usage; + + if (instance_dispatch.GetPhysicalDeviceImageFormatProperties2) { + VkResult result = instance_dispatch.GetPhysicalDeviceImageFormatProperties2( + pdev, &image_format_info, &image_format_properties); + if (result != VK_SUCCESS) { + ALOGE("VkGetPhysicalDeviceImageFormatProperties2 for AHB usage failed: %d", result); + return VK_ERROR_SURFACE_LOST_KHR; + } + } + else { + VkResult result = instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR( + pdev, &image_format_info, + &image_format_properties); + if (result != VK_SUCCESS) { + ALOGE("VkGetPhysicalDeviceImageFormatProperties2KHR for AHB usage failed: %d", + result); + return VK_ERROR_SURFACE_LOST_KHR; + } + } + + *producer_usage = ahb_usage.androidHardwareBufferUsage; + + return VK_SUCCESS; +} + VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, @@ -1595,120 +1777,48 @@ VkResult CreateSwapchainKHR(VkDevice device, num_images = 1; } + // Look through the create_info pNext chain passed to createSwapchainKHR + // for an image compression control struct. + // if one is found AND the appropriate extensions are enabled, create a + // VkImageCompressionControlEXT structure to pass on to VkImageCreateInfo + // TODO check for imageCompressionControlSwapchain feature is enabled void* usage_info_pNext = nullptr; VkImageCompressionControlEXT image_compression = {}; - uint64_t native_usage = 0; - if (dispatch.GetSwapchainGrallocUsage4ANDROID) { - ATRACE_BEGIN("GetSwapchainGrallocUsage4ANDROID"); - VkGrallocUsageInfo2ANDROID gralloc_usage_info = {}; - gralloc_usage_info.sType = - VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_2_ANDROID; - gralloc_usage_info.format = create_info->imageFormat; - gralloc_usage_info.imageUsage = create_info->imageUsage; - gralloc_usage_info.swapchainImageUsage = swapchain_image_usage; - - // Look through the pNext chain for an image compression control struct - // if one is found AND the appropriate extensions are enabled, - // append it to be the gralloc usage pNext chain - const VkSwapchainCreateInfoKHR* create_infos = create_info; - while (create_infos->pNext) { - create_infos = reinterpret_cast( - create_infos->pNext); - switch (create_infos->sType) { - case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: { - const VkImageCompressionControlEXT* compression_infos = - reinterpret_cast( - create_infos); - image_compression = *compression_infos; - image_compression.pNext = nullptr; - usage_info_pNext = &image_compression; - } break; - - default: - // Ignore all other info structs - break; - } - } - gralloc_usage_info.pNext = usage_info_pNext; - - result = dispatch.GetSwapchainGrallocUsage4ANDROID( - device, &gralloc_usage_info, &native_usage); - ATRACE_END(); - if (result != VK_SUCCESS) { - ALOGE("vkGetSwapchainGrallocUsage4ANDROID failed: %d", result); - return VK_ERROR_SURFACE_LOST_KHR; - } - } else if (dispatch.GetSwapchainGrallocUsage3ANDROID) { - ATRACE_BEGIN("GetSwapchainGrallocUsage3ANDROID"); - VkGrallocUsageInfoANDROID gralloc_usage_info = {}; - gralloc_usage_info.sType = VK_STRUCTURE_TYPE_GRALLOC_USAGE_INFO_ANDROID; - gralloc_usage_info.format = create_info->imageFormat; - gralloc_usage_info.imageUsage = create_info->imageUsage; - - // Look through the pNext chain for an image compression control struct - // if one is found AND the appropriate extensions are enabled, - // append it to be the gralloc usage pNext chain - const VkSwapchainCreateInfoKHR* create_infos = create_info; - while (create_infos->pNext) { - create_infos = reinterpret_cast( - create_infos->pNext); - switch (create_infos->sType) { - case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: { - const VkImageCompressionControlEXT* compression_infos = - reinterpret_cast( - create_infos); - image_compression = *compression_infos; - image_compression.pNext = nullptr; - usage_info_pNext = &image_compression; - } break; - - default: - // Ignore all other info structs - break; - } - } - gralloc_usage_info.pNext = usage_info_pNext; + const VkSwapchainCreateInfoKHR* create_infos = create_info; + while (create_infos->pNext) { + create_infos = reinterpret_cast(create_infos->pNext); + switch (create_infos->sType) { + case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: { + const VkImageCompressionControlEXT* compression_infos = + reinterpret_cast(create_infos); + image_compression = *compression_infos; + image_compression.pNext = nullptr; + usage_info_pNext = &image_compression; + } break; - result = dispatch.GetSwapchainGrallocUsage3ANDROID( - device, &gralloc_usage_info, &native_usage); - ATRACE_END(); - if (result != VK_SUCCESS) { - ALOGE("vkGetSwapchainGrallocUsage3ANDROID failed: %d", result); - return VK_ERROR_SURFACE_LOST_KHR; - } - } else if (dispatch.GetSwapchainGrallocUsage2ANDROID) { - uint64_t consumer_usage, producer_usage; - ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID"); - result = dispatch.GetSwapchainGrallocUsage2ANDROID( - device, create_info->imageFormat, create_info->imageUsage, - swapchain_image_usage, &consumer_usage, &producer_usage); - ATRACE_END(); - if (result != VK_SUCCESS) { - ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result); - return VK_ERROR_SURFACE_LOST_KHR; - } - native_usage = - convertGralloc1ToBufferUsage(producer_usage, consumer_usage); - } else if (dispatch.GetSwapchainGrallocUsageANDROID) { - ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID"); - int32_t legacy_usage = 0; - result = dispatch.GetSwapchainGrallocUsageANDROID( - device, create_info->imageFormat, create_info->imageUsage, - &legacy_usage); - ATRACE_END(); - if (result != VK_SUCCESS) { - ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result); - return VK_ERROR_SURFACE_LOST_KHR; + default: + // Ignore all other info structs + break; } - native_usage = static_cast(legacy_usage); } - native_usage |= surface.consumer_usage; - bool createProtectedSwapchain = false; + // Get the appropriate native_usage for the images + // Get the consumer usage + uint64_t native_usage = surface.consumer_usage; + // Determine if the swapchain is protected + bool create_protected_swapchain = false; if (create_info->flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR) { - createProtectedSwapchain = true; + create_protected_swapchain = true; native_usage |= BufferUsage::PROTECTED; } + // Get the producer usage + uint64_t producer_usage; + result = getProducerUsage(device, create_info, swapchain_image_usage, create_protected_swapchain, &producer_usage); + if (result != VK_SUCCESS) { + return result; + } + native_usage |= producer_usage; + err = native_window_set_usage(window, native_usage); if (err != android::OK) { ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err); @@ -1736,8 +1846,10 @@ VkResult CreateSwapchainKHR(VkDevice device, void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Swapchain), alignof(Swapchain), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!mem) return VK_ERROR_OUT_OF_HOST_MEMORY; + Swapchain* swapchain = new (mem) Swapchain(surface, num_images, create_info->presentMode, TranslateVulkanToNativeTransform(create_info->preTransform), @@ -1761,7 +1873,7 @@ VkResult CreateSwapchainKHR(VkDevice device, VkImageCreateInfo image_create = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = nullptr, - .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u, + .flags = create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u, .imageType = VK_IMAGE_TYPE_2D, .format = create_info->imageFormat, .extent = { -- GitLab From 85288fdb8b82397e301300d5c63e462e8b85b6c9 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Thu, 5 Oct 2023 04:52:22 +0000 Subject: [PATCH 0738/1187] Fix NDK documentation minor bugs. Bug: 300602767 Change-Id: I114a4cf83978f152959a6ec244d322603ff5257b Test: builds --- libs/nativewindow/include/android/data_space.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h index 968c114ed4..ae6d22350c 100644 --- a/libs/nativewindow/include/android/data_space.h +++ b/libs/nativewindow/include/android/data_space.h @@ -456,6 +456,7 @@ enum ADataSpace { * Adobe RGB * * Use full range, gamma 2.2 transfer and Adobe RGB primaries + * * Note: Application is responsible for gamma encoding the data as * a 2.2 gamma encoding is not supported in HW. */ @@ -493,7 +494,7 @@ enum ADataSpace { * * Ultra High-definition television * - * Use full range, BT.709 transfer and BT2020 standard + * Use full range, SMPTE 170M transfer and BT2020 standard */ ADATASPACE_BT2020 = 147193856, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL @@ -502,7 +503,7 @@ enum ADataSpace { * * High-definition television * - * Use limited range, BT.709 transfer and BT.709 standard. + * Use limited range, SMPTE 170M transfer and BT.709 standard. */ ADATASPACE_BT709 = 281083904, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED @@ -512,6 +513,7 @@ enum ADataSpace { * Digital Cinema DCI-P3 * * Use full range, gamma 2.6 transfer and D65 DCI-P3 standard + * * Note: Application is responsible for gamma encoding the data as * a 2.6 gamma encoding is not supported in HW. */ -- GitLab From b95782290cc3046bc98c0c517ca6b809837fcedf Mon Sep 17 00:00:00 2001 From: Melody Hsu Date: Mon, 2 Oct 2023 23:09:36 +0000 Subject: [PATCH 0739/1187] Replace usages of captureDisplay with captureLayers. Remove captureDisplay with DisplayCaptureArgs from BLASTBufferQueue_test and replace with ScreenCapture#captureLayers. Bug: b/293445881 Test: atest BLASTBufferQueueTest Change-Id: If628e74b35e6342566cffd666ea96bec4cf9a56d --- libs/gui/tests/BLASTBufferQueue_test.cpp | 120 ++++++++--------------- 1 file changed, 42 insertions(+), 78 deletions(-) diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 9618502b6b..9893c7146e 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -31,10 +31,13 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include @@ -197,18 +200,23 @@ protected: ALOGD("Display: %dx%d orientation:%d", mDisplayWidth, mDisplayHeight, displayState.orientation); + mRootSurfaceControl = mClient->createSurface(String8("RootTestSurface"), mDisplayWidth, + mDisplayHeight, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + /*parent*/ nullptr); + + t.setLayerStack(mRootSurfaceControl, ui::DEFAULT_LAYER_STACK) + .setLayer(mRootSurfaceControl, std::numeric_limits::max()) + .show(mRootSurfaceControl) + .apply(); + mSurfaceControl = mClient->createSurface(String8("TestSurface"), mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState, - /*parent*/ nullptr); - t.setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK) - .setLayer(mSurfaceControl, std::numeric_limits::max()) - .show(mSurfaceControl) - .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB) - .apply(); + /*parent*/ mRootSurfaceControl->getHandle()); - mCaptureArgs.displayToken = mDisplayToken; - mCaptureArgs.dataspace = ui::Dataspace::V0_SRGB; + mCaptureArgs.sourceCrop = Rect(ui::Size(mDisplayWidth, mDisplayHeight)); + mCaptureArgs.layerHandle = mRootSurfaceControl->getHandle(); } void setUpProducer(BLASTBufferQueueHelper& adapter, sp& producer, @@ -295,21 +303,6 @@ protected: captureBuf->unlock(); } - static status_t captureDisplay(DisplayCaptureArgs& captureArgs, - ScreenCaptureResults& captureResults) { - const auto sf = ComposerServiceAIDL::getComposerService(); - SurfaceComposerClient::Transaction().apply(true); - - const sp captureListener = new SyncScreenCaptureListener(); - binder::Status status = sf->captureDisplay(captureArgs, captureListener); - status_t err = gui::aidl_utils::statusTFromBinderStatus(status); - if (err != NO_ERROR) { - return err; - } - captureResults = captureListener->waitForResults(); - return fenceStatus(captureResults.fenceResult); - } - void queueBuffer(sp igbp, uint8_t r, uint8_t g, uint8_t b, nsecs_t presentTimeDelay) { int slot; @@ -342,11 +335,12 @@ protected: sp mDisplayToken; sp mSurfaceControl; + sp mRootSurfaceControl; uint32_t mDisplayWidth; uint32_t mDisplayHeight; - DisplayCaptureArgs mCaptureArgs; + LayerCaptureArgs mCaptureArgs; ScreenCaptureResults mCaptureResults; sp mProducerListener; }; @@ -364,7 +358,9 @@ TEST_F(BLASTBufferQueueTest, Update) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); sp updateSurface = mClient->createSurface(String8("UpdateTest"), mDisplayWidth / 2, mDisplayHeight / 2, - PIXEL_FORMAT_RGBA_8888); + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + /*parent*/ mRootSurfaceControl->getHandle()); adapter.update(updateSurface, mDisplayWidth / 2, mDisplayHeight / 2); ASSERT_EQ(updateSurface, adapter.getSurfaceControl()); sp igbProducer; @@ -451,7 +447,7 @@ TEST_F(BLASTBufferQueueTest, onFrameAvailable_Apply) { Transaction().apply(true /* synchronous */); // capture screen and verify that it is red - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } @@ -536,7 +532,7 @@ TEST_F(BLASTBufferQueueTest, SetCrop_Item) { Transaction().apply(true /* synchronous */); // capture screen and verify that it is red - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, @@ -552,16 +548,6 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { (mDisplayWidth < mDisplayHeight) ? mDisplayWidth / 2 : mDisplayHeight / 2; int32_t finalCropSideLength = bufferSideLength / 2; - auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceEffect); - ASSERT_NE(nullptr, bg.get()); - Transaction t; - t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK) - .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) - .setColor(bg, half3{0, 0, 0}) - .setLayer(bg, 0) - .apply(); - BLASTBufferQueueHelper adapter(mSurfaceControl, bufferSideLength, bufferSideLength); sp igbProducer; setUpProducer(adapter, igbProducer); @@ -597,7 +583,7 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { Transaction().apply(true /* synchronous */); // capture screen and verify that it is red - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b, {10, 10, (int32_t)bufferSideLength - 10, (int32_t)bufferSideLength - 10})); @@ -608,17 +594,6 @@ TEST_F(BLASTBufferQueueTest, SetCrop_ScalingModeScaleCrop) { } TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) { - // add black background - auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceEffect); - ASSERT_NE(nullptr, bg.get()); - Transaction t; - t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK) - .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) - .setColor(bg, half3{0, 0, 0}) - .setLayer(bg, 0) - .apply(); - Rect windowSize(1000, 1000); Rect bufferSize(windowSize); Rect bufferCrop(200, 200, 700, 700); @@ -661,7 +636,7 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) { // ensure the buffer queue transaction has been committed Transaction().apply(true /* synchronous */); - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); // Verify cropped region is scaled correctly. ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {10, 10, 490, 490})); @@ -676,17 +651,6 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) { } TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) { - // add black background - auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceEffect); - ASSERT_NE(nullptr, bg.get()); - Transaction t; - t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK) - .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight)) - .setColor(bg, half3{0, 0, 0}) - .setLayer(bg, 0) - .apply(); - Rect windowSize(1000, 1000); Rect bufferSize(500, 500); Rect bufferCrop(100, 100, 350, 350); @@ -729,7 +693,7 @@ TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) { // ensure the buffer queue transaction has been committed Transaction().apply(true /* synchronous */); - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); // Verify cropped region is scaled correctly. ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {10, 10, 490, 490})); ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 255, 0, {10, 510, 490, 990})); @@ -779,7 +743,7 @@ TEST_F(BLASTBufferQueueTest, ScalingModeChanges) { Transaction().apply(true /* synchronous */); } // capture screen and verify that it is red - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, @@ -815,7 +779,7 @@ TEST_F(BLASTBufferQueueTest, ScalingModeChanges) { Transaction().apply(true /* synchronous */); } // capture screen and verify that it is red - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); // verify we still scale the buffer to the new size (half the screen height) ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, @@ -850,12 +814,12 @@ TEST_F(BLASTBufferQueueTest, SyncThenNoSync) { transactionCallback.getCallbackData(&callbackData); // capture screen and verify that it is green - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(0, 255, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); mProducerListener->waitOnNumberReleased(1); - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } @@ -895,7 +859,7 @@ TEST_F(BLASTBufferQueueTest, MultipleSyncTransactions) { transactionCallback.getCallbackData(&callbackData); // capture screen and verify that it is red - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } @@ -943,7 +907,7 @@ TEST_F(BLASTBufferQueueTest, MultipleSyncTransactionWithNonSync) { transactionCallback.getCallbackData(&callbackData); // capture screen and verify that it is red - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } @@ -993,7 +957,7 @@ TEST_F(BLASTBufferQueueTest, MultipleSyncRunOutOfBuffers) { transactionCallback.getCallbackData(&callbackData); // capture screen and verify that it is red - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } @@ -1051,7 +1015,7 @@ TEST_F(BLASTBufferQueueTest, RunOutOfBuffersWaitingOnSF) { transactionCallback.getCallbackData(&callbackData); // capture screen and verify that it is red - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } @@ -1084,13 +1048,13 @@ TEST_F(BLASTBufferQueueTest, SyncNextTransactionAcquireMultipleBuffers) { transactionCallback.getCallbackData(&callbackData); // capture screen and verify that it is blue - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(0, 0, 255, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); mProducerListener->waitOnNumberReleased(2); // capture screen and verify that it is red - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); } @@ -1186,7 +1150,7 @@ TEST_F(BLASTBufferQueueTest, SyncNextTransactionDropBuffer) { CallbackData callbackData; transactionCallback.getCallbackData(&callbackData); - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); sync.apply(); @@ -1205,7 +1169,7 @@ TEST_F(BLASTBufferQueueTest, DISABLED_DisconnectProducerTest) { mClient->createSurface(String8("TestSurface"), mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState, - /*parent*/ nullptr); + /*parent*/ mRootSurfaceControl->getHandle()); Transaction() .setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK) .setLayer(mSurfaceControl, std::numeric_limits::max()) @@ -1230,7 +1194,7 @@ TEST_F(BLASTBufferQueueTest, DISABLED_DisconnectProducerTest) { CallbackData callbackData; transactionCallback.getCallbackData(&callbackData); // capture screen and verify that it is red - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); @@ -1248,7 +1212,7 @@ TEST_F(BLASTBufferQueueTest, DISABLED_UpdateSurfaceControlTest) { mClient->createSurface(String8("TestSurface"), mDisplayWidth, mDisplayHeight, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceBufferState, - /*parent*/ nullptr); + /*parent*/ mRootSurfaceControl->getHandle()); Transaction() .setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK) .setLayer(mSurfaceControl, std::numeric_limits::max()) @@ -1273,7 +1237,7 @@ TEST_F(BLASTBufferQueueTest, DISABLED_UpdateSurfaceControlTest) { CallbackData callbackData; transactionCallback.getCallbackData(&callbackData); // capture screen and verify that it is red - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); @@ -1406,7 +1370,7 @@ public: ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint); Transaction().apply(true /* synchronous */); - ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults)); switch (tr) { case ui::Transform::ROT_0: -- GitLab From f1c4777d018d33c7d6e0544dcc4578695c2773c1 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Wed, 31 May 2023 14:12:33 -0700 Subject: [PATCH 0740/1187] Add missing headers when Building with libstdc++ Test: Build with CMake. See aosp/2629369. Bug: 285204695 Change-Id: Ife316aa5c08ea0f365f52062cff52625ca877c46 --- libs/binder/RpcTlsUtils.cpp | 2 ++ libs/binder/include/binder/BpBinder.h | 1 + libs/binder/include/binder/Parcel.h | 2 ++ libs/binder/include/binder/RpcServer.h | 1 + libs/binder/include/binder/RpcThreads.h | 1 + libs/binder/ndk/include_cpp/android/binder_auto_utils.h | 1 + 6 files changed, 8 insertions(+) diff --git a/libs/binder/RpcTlsUtils.cpp b/libs/binder/RpcTlsUtils.cpp index f3ca02a3bd..d5c86d7227 100644 --- a/libs/binder/RpcTlsUtils.cpp +++ b/libs/binder/RpcTlsUtils.cpp @@ -21,6 +21,8 @@ #include "Utils.h" +#include + namespace android { namespace { diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 5496d61b70..fc8089d069 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -21,6 +21,7 @@ #include #include +#include #include #include diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 4e231edac5..45e5ace73c 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -17,7 +17,9 @@ #pragma once #include +#include #include // for legacy reasons +#include #include #include #include diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h index b804f7b92a..2153f162e5 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -23,6 +23,7 @@ #include #include +#include #include #include diff --git a/libs/binder/include/binder/RpcThreads.h b/libs/binder/include/binder/RpcThreads.h index 8abf04eaf0..b80d116e1c 100644 --- a/libs/binder/include/binder/RpcThreads.h +++ b/libs/binder/include/binder/RpcThreads.h @@ -19,6 +19,7 @@ #include +#include #include #include #include diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h index ed53891e3d..18769b1454 100644 --- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h +++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include -- GitLab From 37d07c04156e1bd9f9039612cfc008e086a85953 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Thu, 5 Oct 2023 17:32:32 +0000 Subject: [PATCH 0741/1187] Correct the comment in Output::getBestDataspace. Bug: N/A Change-Id: Ia34db4dd225752054478ca9977d88657cf556a0c Test: builds --- services/surfaceflinger/CompositionEngine/src/Output.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 78c23daf48..775e6d5094 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -967,7 +967,7 @@ ui::Dataspace Output::getBestDataspace(ui::Dataspace* outHdrDataSpace, case ui::Dataspace::BT2020_ITU_HLG: bestDataSpace = ui::Dataspace::DISPLAY_P3; // When there's mixed PQ content and HLG content, we set the HDR - // data space to be BT2020_PQ and convert HLG to PQ. + // data space to be BT2020_HLG and convert PQ to HLG. if (*outHdrDataSpace == ui::Dataspace::UNKNOWN) { *outHdrDataSpace = ui::Dataspace::BT2020_HLG; } -- GitLab From 112b1ad753d56822b8a947b73d0bea81da9fc588 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 21 Sep 2023 09:53:53 +0000 Subject: [PATCH 0742/1187] InputDispatcher: Use correct coordinate space when canceling motions Input targets for synthesized cancellations were not created using the same pipeline as normal dispatching. Due to this, things like window and display transforms were not being applied to the events. This means ACTION_CANCEL events did not have the correct coordinates in many cases. Here, we fix that by attempting to use the same pipeline as normal dispatching for creating the input target. When it's not possible to do due to there being no window (e.g. for global monitors), we fall back to creating the target ourselves. Bug: 287908447 Test: atest inputflinger_tests Change-Id: Ic82f87c55e4eaf3e87b07986a14933fbdb69e042 --- .../dispatcher/InputDispatcher.cpp | 46 ++++-- .../tests/InputDispatcher_test.cpp | 152 +++++++++++------- 2 files changed, 126 insertions(+), 72 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 6226a19897..7fbd322385 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3944,7 +3944,6 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( android_log_event_list(LOGTAG_INPUT_CANCEL) << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS; - InputTarget target; sp windowHandle; if (options.displayId) { windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken(), @@ -3952,27 +3951,47 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( } else { windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken()); } - if (windowHandle != nullptr) { - const WindowInfo* windowInfo = windowHandle->getInfo(); - target.setDefaultPointerTransform(windowInfo->transform); - target.globalScaleFactor = windowInfo->globalScaleFactor; - } - target.inputChannel = connection->inputChannel; - target.flags = InputTarget::Flags::DISPATCH_AS_IS; const bool wasEmpty = connection->outboundQueue.empty(); for (size_t i = 0; i < cancelationEvents.size(); i++) { std::unique_ptr cancelationEventEntry = std::move(cancelationEvents[i]); + std::vector targets{}; + // The target to use if we don't find a window associated with the channel. + const InputTarget fallbackTarget{.inputChannel = connection->inputChannel, + .flags = InputTarget::Flags::DISPATCH_AS_IS}; + switch (cancelationEventEntry->type) { case EventEntry::Type::KEY: { - logOutboundKeyDetails("cancel - ", - static_cast(*cancelationEventEntry)); + const auto& keyEntry = static_cast(*cancelationEventEntry); + if (windowHandle != nullptr) { + addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_IS, + /*pointerIds=*/{}, keyEntry.downTime, targets); + } else { + targets.emplace_back(fallbackTarget); + } + logOutboundKeyDetails("cancel - ", keyEntry); break; } case EventEntry::Type::MOTION: { - logOutboundMotionDetails("cancel - ", - static_cast(*cancelationEventEntry)); + const auto& motionEntry = static_cast(*cancelationEventEntry); + if (windowHandle != nullptr) { + std::bitset pointerIds; + for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.pointerCount; + pointerIndex++) { + pointerIds.set(motionEntry.pointerProperties[pointerIndex].id); + } + addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_IS, + pointerIds, motionEntry.downTime, targets); + } else { + targets.emplace_back(fallbackTarget); + const auto it = mDisplayInfos.find(motionEntry.displayId); + if (it != mDisplayInfos.end()) { + targets.back().displayTransform = it->second.transform; + targets.back().setDefaultPointerTransform(it->second.transform); + } + } + logOutboundMotionDetails("cancel - ", motionEntry); break; } case EventEntry::Type::FOCUS: @@ -3992,7 +4011,8 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( } } - enqueueDispatchEntryLocked(connection, std::move(cancelationEventEntry), target, + if (targets.size() != 1) LOG(FATAL) << __func__ << ": InputTarget not created"; + enqueueDispatchEntryLocked(connection, std::move(cancelationEventEntry), targets[0], InputTarget::Flags::DISPATCH_AS_IS); } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 703c3f74cd..e8b04b3cab 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1451,6 +1451,69 @@ private: std::atomic FakeWindowHandle::sId{1}; +class FakeMonitorReceiver { +public: + FakeMonitorReceiver(const std::unique_ptr& dispatcher, const std::string name, + int32_t displayId) { + base::Result> channel = + dispatcher->createInputMonitor(displayId, name, MONITOR_PID); + mInputReceiver = std::make_unique(std::move(*channel), name); + } + + sp getToken() { return mInputReceiver->getToken(); } + + void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) { + mInputReceiver->consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId, + expectedFlags); + } + + std::optional receiveEvent() { + return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED); + } + + void finishEvent(uint32_t consumeSeq) { return mInputReceiver->finishEvent(consumeSeq); } + + void consumeMotionDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) { + mInputReceiver->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN, + expectedDisplayId, expectedFlags); + } + + void consumeMotionMove(int32_t expectedDisplayId, int32_t expectedFlags = 0) { + mInputReceiver->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE, + expectedDisplayId, expectedFlags); + } + + void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) { + mInputReceiver->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP, + expectedDisplayId, expectedFlags); + } + + void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) { + mInputReceiver->consumeMotionEvent( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL), + WithDisplayId(expectedDisplayId), + WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED))); + } + + void consumeMotionPointerDown(int32_t pointerIdx) { + int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN | + (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + mInputReceiver->consumeEvent(InputEventType::MOTION, action, ADISPLAY_ID_DEFAULT, + /*expectedFlags=*/0); + } + + void consumeMotionEvent(const ::testing::Matcher& matcher) { + mInputReceiver->consumeMotionEvent(matcher); + } + + MotionEvent* consumeMotion() { return mInputReceiver->consumeMotion(); } + + void assertNoEvents() { mInputReceiver->assertNoEvents(); } + +private: + std::unique_ptr mInputReceiver; +}; + static InputEventInjectionResult injectKey( InputDispatcher& dispatcher, int32_t action, int32_t repeatCount, int32_t displayId = ADISPLAY_ID_NONE, @@ -4607,6 +4670,36 @@ TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinate EXPECT_EQ(80, event->getY(0)); } +TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) { + auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); + // The monitor will always receive events in the logical display's coordinate space, because + // it does not have a window. + FakeMonitorReceiver monitor{mDispatcher, "Monitor", ADISPLAY_ID_DEFAULT}; + + // Send down to the first window. + mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {PointF{50, 100}})); + firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400))); + monitor.consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400))); + + // Second pointer goes down on second window. + mDispatcher->notifyMotion(generateMotionArgs(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, + {PointF{50, 100}, PointF{150, 220}})); + secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80))); + const std::map expectedMonitorPointers{{0, PointF{100, 400}}, + {1, PointF{300, 880}}}; + monitor.consumeMotionEvent( + AllOf(WithMotionAction(POINTER_1_DOWN), WithPointers(expectedMonitorPointers))); + + mDispatcher->cancelCurrentTouch(); + + firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400))); + secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 80))); + monitor.consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers))); +} + /** Ensure consistent behavior of InputDispatcher in all orientations. */ class InputDispatcherDisplayOrientationFixture : public InputDispatcherDisplayProjectionTest, @@ -5389,65 +5482,6 @@ TEST_F(InputDispatcherTest, SendTimeline_DoesNotCrashDispatcher) { mDispatcher->waitForIdle(); } -class FakeMonitorReceiver { -public: - FakeMonitorReceiver(const std::unique_ptr& dispatcher, const std::string name, - int32_t displayId) { - base::Result> channel = - dispatcher->createInputMonitor(displayId, name, MONITOR_PID); - mInputReceiver = std::make_unique(std::move(*channel), name); - } - - sp getToken() { return mInputReceiver->getToken(); } - - void consumeKeyDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) { - mInputReceiver->consumeEvent(InputEventType::KEY, AKEY_EVENT_ACTION_DOWN, expectedDisplayId, - expectedFlags); - } - - std::optional receiveEvent() { - return mInputReceiver->receiveEvent(CONSUME_TIMEOUT_EVENT_EXPECTED); - } - - void finishEvent(uint32_t consumeSeq) { return mInputReceiver->finishEvent(consumeSeq); } - - void consumeMotionDown(int32_t expectedDisplayId, int32_t expectedFlags = 0) { - mInputReceiver->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_DOWN, - expectedDisplayId, expectedFlags); - } - - void consumeMotionMove(int32_t expectedDisplayId, int32_t expectedFlags = 0) { - mInputReceiver->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_MOVE, - expectedDisplayId, expectedFlags); - } - - void consumeMotionUp(int32_t expectedDisplayId, int32_t expectedFlags = 0) { - mInputReceiver->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_UP, - expectedDisplayId, expectedFlags); - } - - void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) { - mInputReceiver->consumeMotionEvent( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL), - WithDisplayId(expectedDisplayId), - WithFlags(expectedFlags | AMOTION_EVENT_FLAG_CANCELED))); - } - - void consumeMotionPointerDown(int32_t pointerIdx) { - int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN | - (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); - mInputReceiver->consumeEvent(InputEventType::MOTION, action, ADISPLAY_ID_DEFAULT, - /*expectedFlags=*/0); - } - - MotionEvent* consumeMotion() { return mInputReceiver->consumeMotion(); } - - void assertNoEvents() { mInputReceiver->assertNoEvents(); } - -private: - std::unique_ptr mInputReceiver; -}; - using InputDispatcherMonitorTest = InputDispatcherTest; /** -- GitLab From 1c29a09b42745d229a77773abe80c9d46137c0e3 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 21 Sep 2023 10:29:29 +0000 Subject: [PATCH 0743/1187] InputDispatcher: Use correct coordinate space when synthesizing down Input targets for synthesized down events were not created using the same pipeline as normal dispatching. Due to this, things like window and display transforms were not being applied to the events. This means the ACTION_DOWN event did not have the correct coordinates in many cases. Here, we fix that by attempting to use the same pipeline as normal dispatching for creating the input target. When it's not possible to do due to there being no window (e.g. for global monitors), we fall back to creating the target ourselves. Bug: 287908447 Test: atest inputflinger_tests Change-Id: I6987619c91e458249aa7c7be884566e4b21363c4 --- .../dispatcher/InputDispatcher.cpp | 33 ++++++++++++------- .../tests/InputDispatcher_test.cpp | 15 +++++++++ 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 7fbd322385..be579329ad 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4041,23 +4041,33 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( connection->getInputChannelName().c_str(), downEvents.size()); } - InputTarget target; sp windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken()); - if (windowHandle != nullptr) { - const WindowInfo* windowInfo = windowHandle->getInfo(); - target.setDefaultPointerTransform(windowInfo->transform); - target.globalScaleFactor = windowInfo->globalScaleFactor; - } - target.inputChannel = connection->inputChannel; - target.flags = targetFlags; const bool wasEmpty = connection->outboundQueue.empty(); for (std::unique_ptr& downEventEntry : downEvents) { + std::vector targets{}; switch (downEventEntry->type) { case EventEntry::Type::MOTION: { - logOutboundMotionDetails("down - ", - static_cast(*downEventEntry)); + const auto& motionEntry = static_cast(*downEventEntry); + if (windowHandle != nullptr) { + std::bitset pointerIds; + for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.pointerCount; + pointerIndex++) { + pointerIds.set(motionEntry.pointerProperties[pointerIndex].id); + } + addWindowTargetLocked(windowHandle, targetFlags, pointerIds, + motionEntry.downTime, targets); + } else { + targets.emplace_back(InputTarget{.inputChannel = connection->inputChannel, + .flags = targetFlags}); + const auto it = mDisplayInfos.find(motionEntry.displayId); + if (it != mDisplayInfos.end()) { + targets.back().displayTransform = it->second.transform; + targets.back().setDefaultPointerTransform(it->second.transform); + } + } + logOutboundMotionDetails("down - ", motionEntry); break; } @@ -4075,7 +4085,8 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( } } - enqueueDispatchEntryLocked(connection, std::move(downEventEntry), target, + if (targets.size() != 1) LOG(FATAL) << __func__ << ": InputTarget not created"; + enqueueDispatchEntryLocked(connection, std::move(downEventEntry), targets[0], InputTarget::Flags::DISPATCH_AS_IS); } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index e8b04b3cab..d532d50051 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -4700,6 +4700,21 @@ TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) AllOf(WithMotionAction(ACTION_CANCEL), WithPointers(expectedMonitorPointers))); } +TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinates) { + auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); + + // Send down to the first window. + mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, + ADISPLAY_ID_DEFAULT, {PointF{50, 100}})); + firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 400))); + + // The pointer is transferred to the second window, and the second window receives it in the + // correct coordinate space. + mDispatcher->transferTouchFocus(firstWindow->getToken(), secondWindow->getToken()); + firstWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithCoords(100, 400))); + secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400))); +} + /** Ensure consistent behavior of InputDispatcher in all orientations. */ class InputDispatcherDisplayOrientationFixture : public InputDispatcherDisplayProjectionTest, -- GitLab From 5af92f97f44ff2b96fd6d78e0843f2f133627f88 Mon Sep 17 00:00:00 2001 From: Linnan Li Date: Fri, 14 Jul 2023 14:36:22 +0800 Subject: [PATCH 0744/1187] Cancel drag and drop when pointers are canceled for the drag window When a cancel event is synthesized for any reason for the drag window when drag and drop is active, we should cancel the ongoing drag and drop operation. Otherwise, the system may end up in an unexpected state resulting in unwanted behavior. Bug: 291181957 Test: atest inputflinger_tests Change-Id: Ic5e328f0e445e3271cb1797725c4c00589a6b5e1 Signed-off-by: Linnan Li --- .../dispatcher/InputDispatcher.cpp | 10 +++ .../tests/InputDispatcher_test.cpp | 70 +++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index be579329ad..1589278a68 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3921,6 +3921,16 @@ void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( const std::shared_ptr& connection, const CancelationOptions& options) { + if ((options.mode == CancelationOptions::Mode::CANCEL_POINTER_EVENTS || + options.mode == CancelationOptions::Mode::CANCEL_ALL_EVENTS) && + mDragState && mDragState->dragWindow->getToken() == connection->inputChannel->getToken()) { + LOG(INFO) << __func__ + << ": Canceling drag and drop because the pointers for the drag window are being " + "canceled."; + sendDropWindowCommandLocked(nullptr, /*x=*/0, /*y=*/0); + mDragState.reset(); + } + if (connection->status == Connection::Status::BROKEN) { return; } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index d532d50051..395ce03826 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -9367,6 +9367,76 @@ TEST_F(InputDispatcherDragTests, MouseDragAndDrop) { mSecondWindow->assertNoEvents(); } +/** + * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag + * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash. + */ +TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) { + // Down on second window + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {150, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown()); + ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown()); + + // Down on first window + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50)) + .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(*mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown()); + ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove()); + ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1)); + + // Start drag on first window + ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN)); + + // Trigger cancel + mDispatcher->cancelCurrentTouch(); + ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel()); + ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel()); + ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel()); + + ASSERT_TRUE(mDispatcher->waitForIdle()); + // The D&D finished with nullptr + mFakePolicy->assertDropTargetEquals(*mDispatcher, nullptr); + + // Remove drag window + mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0}); + + // Inject a simple gesture, ensure dispatcher not crashed + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + PointF{50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown()); + + const MotionEvent moveEvent = + MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(*mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove()); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionUp(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp()); +} + class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {}; TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) { -- GitLab From fb54907dde3d2b91aee8a395fda7f460ab39e7eb Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 5 Oct 2023 19:17:36 +0000 Subject: [PATCH 0745/1187] FakeMonitorReceiver: Take dispatcher param as reference Bug: 245989146 Test: atest inputflinger_tests Change-Id: I93b9a14d959197308630e3ee5307466bc829fdcc --- .../tests/InputDispatcher_test.cpp | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 395ce03826..c3c883774e 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1453,10 +1453,9 @@ std::atomic FakeWindowHandle::sId{1}; class FakeMonitorReceiver { public: - FakeMonitorReceiver(const std::unique_ptr& dispatcher, const std::string name, - int32_t displayId) { + FakeMonitorReceiver(InputDispatcher& dispatcher, const std::string name, int32_t displayId) { base::Result> channel = - dispatcher->createInputMonitor(displayId, name, MONITOR_PID); + dispatcher.createInputMonitor(displayId, name, MONITOR_PID); mInputReceiver = std::make_unique(std::move(*channel), name); } @@ -4674,7 +4673,7 @@ TEST_F(InputDispatcherDisplayProjectionTest, CancelMotionWithCorrectCoordinates) auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); // The monitor will always receive events in the logical display's coordinate space, because // it does not have a window. - FakeMonitorReceiver monitor{mDispatcher, "Monitor", ADISPLAY_ID_DEFAULT}; + FakeMonitorReceiver monitor{*mDispatcher, "Monitor", ADISPLAY_ID_DEFAULT}; // Send down to the first window. mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, @@ -5512,7 +5511,7 @@ TEST_F(InputDispatcherMonitorTest, MonitorTouchIsCanceledWhenForegroundWindowDis sp window = sp::make(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT); - FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); + FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -5554,7 +5553,7 @@ TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) { "Fake Window", ADISPLAY_ID_DEFAULT); mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); - FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); + FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) @@ -5564,7 +5563,7 @@ TEST_F(InputDispatcherMonitorTest, ReceivesMotionEvents) { } TEST_F(InputDispatcherMonitorTest, MonitorCannotPilferPointers) { - FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); + FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, @@ -5598,7 +5597,7 @@ TEST_F(InputDispatcherMonitorTest, NoWindowTransform) { window->setWindowOffset(20, 40); window->setWindowTransform(0, 1, -1, 0); - FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); + FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) @@ -5611,7 +5610,7 @@ TEST_F(InputDispatcherMonitorTest, NoWindowTransform) { TEST_F(InputDispatcherMonitorTest, InjectionFailsWithNoWindow) { std::shared_ptr application = std::make_shared(); - FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); + FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::FAILED, injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT)) @@ -6501,9 +6500,9 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, SetInputWindow_MultiDisplayFocus) // Test per-display input monitors for motion event. TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { FakeMonitorReceiver monitorInPrimary = - FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); + FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); FakeMonitorReceiver monitorInSecondary = - FakeMonitorReceiver(mDispatcher, "M_2", SECOND_DISPLAY_ID); + FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID); // Test touch down on primary display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -6546,9 +6545,9 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorMotionEvent_MultiDisplay) { TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) { // Input monitor per display. FakeMonitorReceiver monitorInPrimary = - FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); + FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); FakeMonitorReceiver monitorInSecondary = - FakeMonitorReceiver(mDispatcher, "M_2", SECOND_DISPLAY_ID); + FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID); // Test inject a key down. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(*mDispatcher)) @@ -6584,9 +6583,9 @@ TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CanFocusWindowOnUnfocusedDisplay) TEST_F(InputDispatcherFocusOnTwoDisplaysTest, CancelTouch_MultiDisplay) { FakeMonitorReceiver monitorInPrimary = - FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); + FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); FakeMonitorReceiver monitorInSecondary = - FakeMonitorReceiver(mDispatcher, "M_2", SECOND_DISPLAY_ID); + FakeMonitorReceiver(*mDispatcher, "M_2", SECOND_DISPLAY_ID); // Test touch down on primary display. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -7510,7 +7509,7 @@ TEST_F(InputDispatcherSingleWindowAnr, SpyWindowReceivesEventsDuringAppAnrOnMoti TEST_F(InputDispatcherSingleWindowAnr, UnresponsiveMonitorAnr) { mDispatcher->setMonitorDispatchingTimeoutForTest(SPY_TIMEOUT); - FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); + FakeMonitorReceiver monitor = FakeMonitorReceiver(*mDispatcher, "M_1", ADISPLAY_ID_DEFAULT); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, -- GitLab From a4f67b98e4b48f6b99c2d8b0966689c66003d10b Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Thu, 5 Oct 2023 19:59:32 +0000 Subject: [PATCH 0746/1187] Correct Transfer and standard tables in dataspace NDK doc. Bug: 300602767 Change-Id: Iccc941a3d44781703cf1dc82513e6354b1839ae7 Test: builds --- .../nativewindow/include/android/data_space.h | 116 ++++++++++-------- 1 file changed, 65 insertions(+), 51 deletions(-) diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h index ae6d22350c..2a7cc6a4e0 100644 --- a/libs/nativewindow/include/android/data_space.h +++ b/libs/nativewindow/include/android/data_space.h @@ -81,11 +81,12 @@ enum ADataSpace { STANDARD_UNSPECIFIED = 0 << 16, /** + *

            * Primaries:       x       y
            *  green           0.300   0.600
            *  blue            0.150   0.060
            *  red             0.640   0.330
      -     *  white (D65)     0.3127  0.3290
      +     *  white (D65)     0.3127  0.3290
      * * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation * for RGB conversion. @@ -93,11 +94,12 @@ enum ADataSpace { STANDARD_BT709 = 1 << 16, /** + *
            * Primaries:       x       y
            *  green           0.290   0.600
            *  blue            0.150   0.060
            *  red             0.640   0.330
      -     *  white (D65)     0.3127  0.3290
      +     *  white (D65)     0.3127  0.3290
      * * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation * for RGB conversion from the one purely determined by the primaries @@ -107,11 +109,12 @@ enum ADataSpace { STANDARD_BT601_625 = 2 << 16, /** + *
            * Primaries:       x       y
            *  green           0.290   0.600
            *  blue            0.150   0.060
            *  red             0.640   0.330
      -     *  white (D65)     0.3127  0.3290
      +     *  white (D65)     0.3127  0.3290
      * * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation * for RGB conversion. @@ -119,11 +122,12 @@ enum ADataSpace { STANDARD_BT601_625_UNADJUSTED = 3 << 16, /** + *
            * Primaries:       x       y
            *  green           0.310   0.595
            *  blue            0.155   0.070
            *  red             0.630   0.340
      -     *  white (D65)     0.3127  0.3290
      +     *  white (D65)     0.3127  0.3290
      * * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation * for RGB conversion from the one purely determined by the primaries @@ -133,11 +137,12 @@ enum ADataSpace { STANDARD_BT601_525 = 4 << 16, /** + *
            * Primaries:       x       y
            *  green           0.310   0.595
            *  blue            0.155   0.070
            *  red             0.630   0.340
      -     *  white (D65)     0.3127  0.3290
      +     *  white (D65)     0.3127  0.3290
      * * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation * for RGB conversion (as in SMPTE 240M). @@ -145,11 +150,12 @@ enum ADataSpace { STANDARD_BT601_525_UNADJUSTED = 5 << 16, /** + *
            * Primaries:       x       y
            *  green           0.170   0.797
            *  blue            0.131   0.046
            *  red             0.708   0.292
      -     *  white (D65)     0.3127  0.3290
      +     *  white (D65)     0.3127  0.3290
      * * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation * for RGB conversion. @@ -157,11 +163,12 @@ enum ADataSpace { STANDARD_BT2020 = 6 << 16, /** + *
            * Primaries:       x       y
            *  green           0.170   0.797
            *  blue            0.131   0.046
            *  red             0.708   0.292
      -     *  white (D65)     0.3127  0.3290
      +     *  white (D65)     0.3127  0.3290
      * * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation * for RGB conversion using the linear domain. @@ -169,11 +176,12 @@ enum ADataSpace { STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16, /** + *
            * Primaries:       x      y
            *  green           0.21   0.71
            *  blue            0.14   0.08
            *  red             0.67   0.33
      -     *  white (C)       0.310  0.316
      +     *  white (C)       0.310  0.316
      * * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation * for RGB conversion. @@ -181,11 +189,12 @@ enum ADataSpace { STANDARD_BT470M = 8 << 16, /** + *
            * Primaries:       x       y
            *  green           0.243   0.692
            *  blue            0.145   0.049
            *  red             0.681   0.319
      -     *  white (C)       0.310   0.316
      +     *  white (C)       0.310   0.316
      * * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation * for RGB conversion. @@ -194,21 +203,23 @@ enum ADataSpace { /** * SMPTE EG 432-1 and SMPTE RP 431-2. (DCI-P3) + *
            * Primaries:       x       y
            *  green           0.265   0.690
            *  blue            0.150   0.060
            *  red             0.680   0.320
      -     *  white (D65)     0.3127  0.3290
      +     *  white (D65)     0.3127  0.3290
      */ STANDARD_DCI_P3 = 10 << 16, /** * Adobe RGB + *
            * Primaries:       x       y
            *  green           0.210   0.710
            *  blue            0.150   0.060
            *  red             0.640   0.330
      -     *  white (D65)     0.3127  0.3290
      +     *  white (D65)     0.3127  0.3290
      */ STANDARD_ADOBE_RGB = 11 << 16, @@ -242,83 +253,86 @@ enum ADataSpace { TRANSFER_UNSPECIFIED = 0 << 22, /** + * Linear transfer. + *
            * Transfer characteristic curve:
      -     *  E = L
      -     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
      -     *      E - corresponding electrical signal
      +     * E = L
      +     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
      +     *     E - corresponding electrical signal
      */ TRANSFER_LINEAR = 1 << 22, /** + * sRGB transfer. + *
            * Transfer characteristic curve:
      -     *
            * E = 1.055 * L^(1/2.4) - 0.055  for 0.0031308 <= L <= 1
            *   = 12.92 * L                  for 0 <= L < 0.0031308
            *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
      -     *     E - corresponding electrical signal
      +     *     E - corresponding electrical signal
      */ TRANSFER_SRGB = 2 << 22, /** - * BT.601 525, BT.601 625, BT.709, BT.2020 - * + * SMPTE 170M transfer. + *
            * Transfer characteristic curve:
      -     *  E = 1.099 * L ^ 0.45 - 0.099  for 0.018 <= L <= 1
      -     *    = 4.500 * L                 for 0 <= L < 0.018
      -     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
      -     *      E - corresponding electrical signal
      +     * E = 1.099 * L ^ 0.45 - 0.099  for 0.018 <= L <= 1
      +     *   = 4.500 * L                 for 0 <= L < 0.018
      +     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
      +     *     E - corresponding electrical signal
      */ TRANSFER_SMPTE_170M = 3 << 22, /** - * Assumed display gamma 2.2. - * + * Display gamma 2.2. + *
            * Transfer characteristic curve:
      -     *  E = L ^ (1/2.2)
      -     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
      -     *      E - corresponding electrical signal
      +     * E = L ^ (1/2.2)
      +     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
      +     *     E - corresponding electrical signal
      */ TRANSFER_GAMMA2_2 = 4 << 22, /** - * display gamma 2.6. - * + * Display gamma 2.6. + *
            * Transfer characteristic curve:
      -     *  E = L ^ (1/2.6)
      -     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
      -     *      E - corresponding electrical signal
      +     * E = L ^ (1/2.6)
      +     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
      +     *     E - corresponding electrical signal
      */ TRANSFER_GAMMA2_6 = 5 << 22, /** - * display gamma 2.8. - * + * Display gamma 2.8. + *
            * Transfer characteristic curve:
      -     *  E = L ^ (1/2.8)
      -     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
      -     *      E - corresponding electrical signal
      +     * E = L ^ (1/2.8)
      +     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
      +     *     E - corresponding electrical signal
      */ TRANSFER_GAMMA2_8 = 6 << 22, /** - * SMPTE ST 2084 (Dolby Perceptual Quantizer) - * + * SMPTE ST 2084 (Dolby Perceptual Quantizer). + *
            * Transfer characteristic curve:
      -     *  E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
      -     *  c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
      -     *  c2 = 32 * 2413 / 4096 = 18.8515625
      -     *  c3 = 32 * 2392 / 4096 = 18.6875
      -     *  m = 128 * 2523 / 4096 = 78.84375
      -     *  n = 0.25 * 2610 / 4096 = 0.1593017578125
      -     *      L - luminance of image 0 <= L <= 1 for HDR colorimetry.
      -     *          L = 1 corresponds to 10000 cd/m2
      -     *      E - corresponding electrical signal
      +     * E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
      +     * c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
      +     * c2 = 32 * 2413 / 4096 = 18.8515625
      +     * c3 = 32 * 2392 / 4096 = 18.6875
      +     * m = 128 * 2523 / 4096 = 78.84375
      +     * n = 0.25 * 2610 / 4096 = 0.1593017578125
      +     *     L - luminance of image 0 <= L <= 1 for HDR colorimetry.
      +     *         L = 1 corresponds to 10000 cd/m2
      +     *     E - corresponding electrical signal
      */ TRANSFER_ST2084 = 7 << 22, /** - * ARIB STD-B67 Hybrid Log Gamma - * + * ARIB STD-B67 Hybrid Log Gamma. + *
            * Transfer characteristic curve:
            *  E = r * L^0.5                 for 0 <= L <= 1
            *    = a * ln(L - b) + c         for 1 < L
      @@ -328,7 +342,7 @@ enum ADataSpace {
            *  r = 0.5
            *      L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
            *          to reference white level of 100 cd/m2
      -     *      E - corresponding electrical signal
      +     *      E - corresponding electrical signal
      */ TRANSFER_HLG = 8 << 22, -- GitLab From cff4fa504677d4c2c37502b3e5d60a22f3eff8bc Mon Sep 17 00:00:00 2001 From: Ameer Armaly Date: Wed, 4 Oct 2023 23:45:11 +0000 Subject: [PATCH 0747/1187] Bring back InputDispatcher crash for inconsistent a11y hover streams. Fix: 299977100 Test: atest InputDispatcherTest Change-Id: I3c74cadb2bae1138b3a1a7c0d37be9210ccc5c70 --- libs/input/input_flags.aconfig | 7 +++++++ services/inputflinger/dispatcher/InputDispatcher.cpp | 6 ++++-- services/inputflinger/tests/Android.bp | 1 + services/inputflinger/tests/InputDispatcher_test.cpp | 6 +++++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index e8575a6103..6302ff5ff3 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -34,3 +34,10 @@ flag { description: "Set to true to enable multi-device input: touch and stylus can be active at the same time, but in different windows" bug: "211379801" } + +flag { + name: "a11y_crash_on_inconsistent_event_stream" + namespace: "accessibility" + description: "Brings back fatal logging for inconsistent event streams originating from accessibility." + bug: "299977100" +} diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 6226a19897..ec19e45cf5 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #if defined(__ANDROID__) @@ -67,6 +68,7 @@ using android::gui::WindowInfo; using android::gui::WindowInfoHandle; using android::os::InputEventInjectionResult; using android::os::InputEventInjectionSync; +namespace input_flags = com::android::input::flags; namespace android::inputdispatcher { @@ -670,11 +672,11 @@ std::vector getHoveringWindowsLocked(const TouchState* oldState, // This pointer was already sent to the window. Use ACTION_HOVER_MOVE. if (CC_UNLIKELY(maskedAction != AMOTION_EVENT_ACTION_HOVER_MOVE)) { android::base::LogSeverity severity = android::base::LogSeverity::FATAL; - if (entry.flags & AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT) { + if (!input_flags::a11y_crash_on_inconsistent_event_stream() && + entry.flags & AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT) { // The Accessibility injected touch exploration event stream // has known inconsistencies, so log ERROR instead of // crashing the device with FATAL. - // TODO(b/299977100): Move a11y severity back to FATAL. severity = android::base::LogSeverity::ERROR; } LOG(severity) << "Expected ACTION_HOVER_MOVE instead of " << entry.getDescription(); diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index d87a5a7337..a68d050621 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -93,6 +93,7 @@ cc_test { }, }, static_libs: [ + "libflagtest", "libc++fs", "libgmock", ], diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 703c3f74cd..5c97b68ef5 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -3764,7 +3766,9 @@ TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) { /** * Test that invalid HOVER events sent by accessibility do not cause a fatal crash. */ -TEST_F(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash) { +TEST_F_WITH_FLAGS(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash, + REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(com::android::input::flags, + a11y_crash_on_inconsistent_event_stream))) { std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); -- GitLab From 0dfcac7cecc90bbff5a098a5b99887aee57beb28 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 5 Oct 2023 20:04:21 +0000 Subject: [PATCH 0748/1187] Add tests to verify hover enter and exit are synthesized correctly ... using the correct coordinate transforms. Bug: 299074463 Test: atest inputflinger_tests Change-Id: I48ef7ca07f3041ba724550bb81e22c9ac37493b5 --- .../tests/InputDispatcher_test.cpp | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index c3c883774e..77d5391380 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -184,6 +184,18 @@ MATCHER_P2(WithCoords, x, y, "MotionEvent with specified coordinates") { return receivedX == x && receivedY == y; } +MATCHER_P2(WithRawCoords, x, y, "MotionEvent with specified raw coordinates") { + if (arg.getPointerCount() != 1) { + *result_listener << "Expected 1 pointer, got " << arg.getPointerCount(); + return false; + } + const float receivedX = arg.getRawX(/*pointerIndex=*/0); + const float receivedY = arg.getRawY(/*pointerIndex=*/0); + *result_listener << "expected raw coords (" << x << ", " << y << "), but got (" << receivedX + << ", " << receivedY << ")"; + return receivedX == x && receivedY == y; +} + MATCHER_P(WithPointerCount, pointerCount, "MotionEvent with specified number of pointers") { *result_listener << "expected pointerCount " << pointerCount << ", but got " << arg.getPointerCount(); @@ -4714,6 +4726,43 @@ TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeDownWithCorrectCoordinate secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithCoords(-100, -400))); } +TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverEnterExitWithCorrectCoordinates) { + auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); + + // Send hover move to the second window, and ensure it shows up as hover enter. + mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, + ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); + secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), + WithCoords(100, 80), WithRawCoords(300, 880))); + + // Touch down at the same location and ensure a hover exit is synthesized. + mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS, + ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); + secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80), + WithRawCoords(300, 880))); + secondWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880))); + secondWindow->assertNoEvents(); + firstWindow->assertNoEvents(); +} + +TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinates) { + auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); + + // Send hover enter to second window + mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS, + ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); + secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), + WithCoords(100, 80), WithRawCoords(300, 880))); + + mDispatcher->cancelCurrentTouch(); + + secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80), + WithRawCoords(300, 880))); + secondWindow->assertNoEvents(); + firstWindow->assertNoEvents(); +} + /** Ensure consistent behavior of InputDispatcher in all orientations. */ class InputDispatcherDisplayOrientationFixture : public InputDispatcherDisplayProjectionTest, -- GitLab From fd16fa82690a91545a125c58d65726439264ba75 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Thu, 31 Aug 2023 00:00:47 -0700 Subject: [PATCH 0749/1187] input: handle change in std::span::size type The pre-standardized version of std::span in external/libcxx had a ptrdiff_t size, but the finalized std::span has a size_t size instead. Also, the std::span::index_type typedef is renamed to size_type. Use an old-style constructor call to implicitly coerce the size value to the proper type. Insert a cast to avoid a signedness comparison warning. Bug: b/175635923 Test: treehugger (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5a8af506b234685a0749b5753ba205c06688f870) Merged-In: I96ccf6d5b54d4118b096f97c901073b4fc2f6f9f Change-Id: I96ccf6d5b54d4118b096f97c901073b4fc2f6f9f --- libs/input/MotionPredictor.cpp | 5 +++-- libs/input/TfLiteMotionPredictor.cpp | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/input/MotionPredictor.cpp b/libs/input/MotionPredictor.cpp index f7ca5e7f65..5736ad7eed 100644 --- a/libs/input/MotionPredictor.cpp +++ b/libs/input/MotionPredictor.cpp @@ -181,7 +181,8 @@ std::unique_ptr MotionPredictor::predict(nsecs_t timestamp) { int64_t predictionTime = mBuffers->lastTimestamp(); const int64_t futureTime = timestamp + mPredictionTimestampOffsetNanos; - for (int i = 0; i < predictedR.size() && predictionTime <= futureTime; ++i) { + for (size_t i = 0; i < static_cast(predictedR.size()) && predictionTime <= futureTime; + ++i) { if (predictedR[i] < mModel->config().distanceNoiseFloor) { // Stop predicting when the predicted output is below the model's noise floor. // @@ -198,7 +199,7 @@ std::unique_ptr MotionPredictor::predict(nsecs_t timestamp) { const TfLiteMotionPredictorSample::Point predictedPoint = convertPrediction(axisFrom, axisTo, predictedR[i], predictedPhi[i]); - ALOGD_IF(isDebug(), "prediction %d: %f, %f", i, predictedPoint.x, predictedPoint.y); + ALOGD_IF(isDebug(), "prediction %zu: %f, %f", i, predictedPoint.x, predictedPoint.y); PointerCoords coords; coords.clear(); coords.setAxisValue(AMOTION_EVENT_AXIS_X, predictedPoint.x); diff --git a/libs/input/TfLiteMotionPredictor.cpp b/libs/input/TfLiteMotionPredictor.cpp index 5984b4d3b9..d17476e216 100644 --- a/libs/input/TfLiteMotionPredictor.cpp +++ b/libs/input/TfLiteMotionPredictor.cpp @@ -143,8 +143,7 @@ std::span getTensorBuffer(typename std::conditional::value, tensor->name, TfLiteTypeGetName(tensor->type), TfLiteTypeGetName(type)); LOG_ALWAYS_FATAL_IF(!tensor->data.data); - return {reinterpret_cast(tensor->data.data), - static_cast::index_type>(tensor->bytes / sizeof(T))}; + return std::span(reinterpret_cast(tensor->data.data), tensor->bytes / sizeof(T)); } // Verifies that a tensor exists and has an underlying buffer of type T. -- GitLab From 6a9953b08a6092b2314b90fc33e59bad75657158 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Fri, 29 Sep 2023 03:46:39 -0700 Subject: [PATCH 0750/1187] [sf] Stop inheriting from std::unary_function std::unary_function was deprecated in C++11 and removed in C++17. Its function is to provide two typedefs, `argument_type` and `result_type`, but these are not needed for std::find_if's Predicate, so stop using std::unary_function. Bug: 175635923 Test: m MODULES-IN-frameworks-native (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:ec8cc07d8ae214453c83cbe00404b9adf73d49c1) Merged-In: Ie16ada6f76bee7d9f248dc8349a095b50777c92d Change-Id: Ie16ada6f76bee7d9f248dc8349a095b50777c92d --- .../surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp index b8a5e79a38..9526948bff 100644 --- a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp +++ b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp @@ -118,7 +118,7 @@ inline void PrintTo(const LayerInfo& info, ::std::ostream* os) { << info.touchableRegionBounds.right << "," << info.touchableRegionBounds.bottom << "}"; } -struct find_id : std::unary_function { +struct find_id { uint64_t id; find_id(uint64_t id) : id(id) {} bool operator()(LayerInfo const& m) const { return m.id == id; } -- GitLab From 47b7bb433909f45d2ee9de3f576ac97ccad61cb5 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 29 Sep 2023 16:27:33 -0700 Subject: [PATCH 0751/1187] [sf-newfe] Update layer history for invisible layers Fixes a bug with new frontend where we were only updating layer history for layers that has something to draw. Cl also adds integration tests to validate frontend to layerhistory path. Test: LayerHistoryIntegrationTest Fixes: 300701739 Change-Id: I223b4817bdf9909e3890de0b5051bc0ff345f829 --- services/surfaceflinger/Layer.cpp | 25 +- services/surfaceflinger/Layer.h | 8 +- .../surfaceflinger/Scheduler/LayerHistory.h | 1 + services/surfaceflinger/Scheduler/LayerInfo.h | 2 + .../surfaceflinger/Scheduler/Scheduler.cpp | 4 +- services/surfaceflinger/Scheduler/Scheduler.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 70 +- services/surfaceflinger/SurfaceFlinger.h | 2 +- .../surfaceflinger/tests/unittests/Android.bp | 1 + .../tests/unittests/LayerHierarchyTest.h | 71 ++ .../unittests/LayerHistoryIntegrationTest.cpp | 873 ++++++++++++++++++ .../tests/unittests/LayerHistoryTest.cpp | 2 + .../tests/unittests/LayerSnapshotTest.cpp | 23 +- .../tests/unittests/SchedulerTest.cpp | 6 +- .../tests/unittests/TestableSurfaceFlinger.h | 9 +- 15 files changed, 1021 insertions(+), 78 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 5ae29990dc..33d1eeb7cc 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1267,7 +1267,8 @@ bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool overr return parentFrameRate; }(); - *transactionNeeded |= setFrameRateForLayerTreeLegacy(frameRate); + auto now = systemTime(); + *transactionNeeded |= setFrameRateForLayerTreeLegacy(frameRate, now); // The frame rate is propagated to the children bool childrenHaveFrameRate = false; @@ -1283,7 +1284,8 @@ bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool overr // layer as NoVote to allow the children to control the refresh rate if (!frameRate.isValid() && childrenHaveFrameRate) { *transactionNeeded |= - setFrameRateForLayerTreeLegacy(FrameRate(Fps(), FrameRateCompatibility::NoVote)); + setFrameRateForLayerTreeLegacy(FrameRate(Fps(), FrameRateCompatibility::NoVote), + now); } // We return whether this layer or its children has a vote. We ignore ExactOrMultiple votes for @@ -1492,7 +1494,7 @@ void Layer::setFrameTimelineVsyncForSkippedFrames(const FrameTimelineInfo& info, addSurfaceFrameDroppedForBuffer(surfaceFrame, postTime); } -bool Layer::setFrameRateForLayerTreeLegacy(FrameRate frameRate) { +bool Layer::setFrameRateForLayerTreeLegacy(FrameRate frameRate, nsecs_t now) { if (mDrawingState.frameRateForLayerTree == frameRate) { return false; } @@ -1506,19 +1508,20 @@ bool Layer::setFrameRateForLayerTreeLegacy(FrameRate frameRate) { setTransactionFlags(eTransactionNeeded); mFlinger->mScheduler - ->recordLayerHistory(sequence, getLayerProps(), systemTime(), + ->recordLayerHistory(sequence, getLayerProps(), now, now, scheduler::LayerHistory::LayerUpdateType::SetFrameRate); return true; } -bool Layer::setFrameRateForLayerTree(FrameRate frameRate, const scheduler::LayerProps& layerProps) { +bool Layer::setFrameRateForLayerTree(FrameRate frameRate, const scheduler::LayerProps& layerProps, + nsecs_t now) { if (mDrawingState.frameRateForLayerTree == frameRate) { return false; } mDrawingState.frameRateForLayerTree = frameRate; mFlinger->mScheduler - ->recordLayerHistory(sequence, layerProps, systemTime(), + ->recordLayerHistory(sequence, layerProps, now, now, scheduler::LayerHistory::LayerUpdateType::SetFrameRate); return true; } @@ -3225,7 +3228,7 @@ bool Layer::setBuffer(std::shared_ptr& buffer, mOwnerUid, postTime, getGameMode()); if (mFlinger->mLegacyFrontEndEnabled) { - recordLayerHistoryBufferUpdate(getLayerProps()); + recordLayerHistoryBufferUpdate(getLayerProps(), systemTime()); } setFrameTimelineVsyncForBufferTransaction(info, postTime); @@ -3256,7 +3259,7 @@ void Layer::setDesiredPresentTime(nsecs_t desiredPresentTime, bool isAutoTimesta mDrawingState.isAutoTimestamp = isAutoTimestamp; } -void Layer::recordLayerHistoryBufferUpdate(const scheduler::LayerProps& layerProps) { +void Layer::recordLayerHistoryBufferUpdate(const scheduler::LayerProps& layerProps, nsecs_t now) { ATRACE_CALL(); const nsecs_t presentTime = [&] { if (!mDrawingState.isAutoTimestamp) { @@ -3310,14 +3313,14 @@ void Layer::recordLayerHistoryBufferUpdate(const scheduler::LayerProps& layerPro ATRACE_FORMAT_INSTANT("presentIn %s", to_string(presentIn).c_str()); } - mFlinger->mScheduler->recordLayerHistory(sequence, layerProps, presentTime, + mFlinger->mScheduler->recordLayerHistory(sequence, layerProps, presentTime, now, scheduler::LayerHistory::LayerUpdateType::Buffer); } -void Layer::recordLayerHistoryAnimationTx(const scheduler::LayerProps& layerProps) { +void Layer::recordLayerHistoryAnimationTx(const scheduler::LayerProps& layerProps, nsecs_t now) { const nsecs_t presentTime = mDrawingState.isAutoTimestamp ? 0 : mDrawingState.desiredPresentTime; - mFlinger->mScheduler->recordLayerHistory(sequence, layerProps, presentTime, + mFlinger->mScheduler->recordLayerHistory(sequence, layerProps, presentTime, now, scheduler::LayerHistory::LayerUpdateType::AnimationTX); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 78a3a7cd5c..0b66866158 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -908,10 +908,10 @@ public: void callReleaseBufferCallback(const sp& listener, const sp& buffer, uint64_t framenumber, const sp& releaseFence); - bool setFrameRateForLayerTreeLegacy(FrameRate); - bool setFrameRateForLayerTree(FrameRate, const scheduler::LayerProps&); - void recordLayerHistoryBufferUpdate(const scheduler::LayerProps&); - void recordLayerHistoryAnimationTx(const scheduler::LayerProps&); + bool setFrameRateForLayerTreeLegacy(FrameRate, nsecs_t now); + bool setFrameRateForLayerTree(FrameRate, const scheduler::LayerProps&, nsecs_t now); + void recordLayerHistoryBufferUpdate(const scheduler::LayerProps&, nsecs_t now); + void recordLayerHistoryAnimationTx(const scheduler::LayerProps&, nsecs_t now); auto getLayerProps() const { return scheduler::LayerProps{ .visible = isVisible(), diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 40bda83e62..bac1ec639a 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -91,6 +91,7 @@ public: private: friend class LayerHistoryTest; + friend class LayerHistoryIntegrationTest; friend class TestableScheduler; using LayerPair = std::pair>; diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 6286b285cf..d580b58f53 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -62,6 +62,7 @@ class LayerInfo { static constexpr size_t kNumSmallDirtyThreshold = 2; friend class LayerHistoryTest; + friend class LayerHistoryIntegrationTest; friend class LayerInfoTest; public: @@ -264,6 +265,7 @@ private: private: friend class LayerHistoryTest; + friend class LayerHistoryIntegrationTest; // Holds the refresh rate when it was calculated struct RefreshRateData { diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 76f1af9f56..daf9898d11 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -625,9 +625,9 @@ void Scheduler::onLayerDestroyed(Layer* layer) { } void Scheduler::recordLayerHistory(int32_t id, const LayerProps& layerProps, nsecs_t presentTime, - LayerHistory::LayerUpdateType updateType) { + nsecs_t now, LayerHistory::LayerUpdateType updateType) { if (pacesetterSelectorPtr()->canSwitch()) { - mLayerHistory.record(id, layerProps, presentTime, systemTime(), updateType); + mLayerHistory.record(id, layerProps, presentTime, now, updateType); } } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index e6db654637..3441318cd0 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -230,7 +230,7 @@ public: // Layers are registered on creation, and unregistered when the weak reference expires. void registerLayer(Layer*); void recordLayerHistory(int32_t id, const LayerProps& layerProps, nsecs_t presentTime, - LayerHistory::LayerUpdateType) EXCLUDES(mDisplayLock); + nsecs_t now, LayerHistory::LayerUpdateType) EXCLUDES(mDisplayLock); void setModeChangePending(bool pending); void setDefaultFrameRateCompatibility(int32_t id, scheduler::FrameRateCompatibility); void deregisterLayer(Layer*); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4d8dc94db5..e32e0fd483 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2203,44 +2203,46 @@ bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, nsecs_t frameTi return mustComposite; } -void SurfaceFlinger::updateLayerHistory(const frontend::LayerSnapshot& snapshot) { - using Changes = frontend::RequestedLayerState::Changes; - if (snapshot.path.isClone()) { - return; - } +void SurfaceFlinger::updateLayerHistory(nsecs_t now) { + for (const auto& snapshot : mLayerSnapshotBuilder.getSnapshots()) { + using Changes = frontend::RequestedLayerState::Changes; + if (snapshot->path.isClone()) { + continue; + } - if (!snapshot.changes.any(Changes::FrameRate | Changes::Buffer | Changes::Animation) && - (snapshot.clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) == 0) { - return; - } + if (!snapshot->changes.any(Changes::FrameRate | Changes::Buffer | Changes::Animation) && + (snapshot->clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) == 0) { + continue; + } - const auto layerProps = scheduler::LayerProps{ - .visible = snapshot.isVisible, - .bounds = snapshot.geomLayerBounds, - .transform = snapshot.geomLayerTransform, - .setFrameRateVote = snapshot.frameRate, - .frameRateSelectionPriority = snapshot.frameRateSelectionPriority, - }; + const auto layerProps = scheduler::LayerProps{ + .visible = snapshot->isVisible, + .bounds = snapshot->geomLayerBounds, + .transform = snapshot->geomLayerTransform, + .setFrameRateVote = snapshot->frameRate, + .frameRateSelectionPriority = snapshot->frameRateSelectionPriority, + }; - auto it = mLegacyLayers.find(snapshot.sequence); - LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), "Couldnt find layer object for %s", - snapshot.getDebugString().c_str()); + auto it = mLegacyLayers.find(snapshot->sequence); + LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), "Couldnt find layer object for %s", + snapshot->getDebugString().c_str()); - if (snapshot.changes.test(Changes::Animation)) { - it->second->recordLayerHistoryAnimationTx(layerProps); - } + if (snapshot->clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) { + mScheduler->setDefaultFrameRateCompatibility(snapshot->sequence, + snapshot->defaultFrameRateCompatibility); + } - if (snapshot.clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) { - mScheduler->setDefaultFrameRateCompatibility(snapshot.sequence, - snapshot.defaultFrameRateCompatibility); - } + if (snapshot->changes.test(Changes::Animation)) { + it->second->recordLayerHistoryAnimationTx(layerProps, now); + } - if (snapshot.changes.test(Changes::FrameRate)) { - it->second->setFrameRateForLayerTree(snapshot.frameRate, layerProps); - } + if (snapshot->changes.test(Changes::FrameRate)) { + it->second->setFrameRateForLayerTree(snapshot->frameRate, layerProps, now); + } - if (snapshot.changes.test(Changes::Buffer)) { - it->second->recordLayerHistoryBufferUpdate(layerProps); + if (snapshot->changes.test(Changes::Buffer)) { + it->second->recordLayerHistoryBufferUpdate(layerProps, now); + } } } @@ -2379,8 +2381,8 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, mLayersIdsWithQueuedFrames.emplace(it->second->sequence); } + updateLayerHistory(latchTime); mLayerSnapshotBuilder.forEachVisibleSnapshot([&](const frontend::LayerSnapshot& snapshot) { - updateLayerHistory(snapshot); if (mLayersIdsWithQueuedFrames.find(snapshot.path.id) == mLayersIdsWithQueuedFrames.end()) return; @@ -4832,7 +4834,7 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin for (const auto& listener : listenerCallbacks) { mTransactionCallbackInvoker.addEmptyTransaction(listener); } - + nsecs_t now = systemTime(); uint32_t clientStateFlags = 0; for (auto& resolvedState : states) { if (mLegacyFrontEndEnabled) { @@ -4854,7 +4856,7 @@ bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelin .setFrameRateVote = layer->getFrameRateForLayerTree(), .frameRateSelectionPriority = layer->getFrameRateSelectionPriority(), }; - layer->recordLayerHistoryAnimationTx(layerProps); + layer->recordLayerHistoryAnimationTx(layerProps, now); } } } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a5a2341b14..7b2d5908e6 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -732,7 +732,7 @@ private: bool& out) REQUIRES(kMainThreadContext); bool updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, bool transactionsFlushed, bool& out) REQUIRES(kMainThreadContext); - void updateLayerHistory(const frontend::LayerSnapshot& snapshot); + void updateLayerHistory(nsecs_t now); frontend::Update flushLifecycleUpdates() REQUIRES(kMainThreadContext); void updateInputFlinger(VsyncId vsyncId, TimePoint frameTime); diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index f4516c7635..858b882589 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -93,6 +93,7 @@ cc_test { "HWComposerTest.cpp", "OneShotTimerTest.cpp", "LayerHistoryTest.cpp", + "LayerHistoryIntegrationTest.cpp", "LayerInfoTest.cpp", "LayerMetadataTest.cpp", "LayerHierarchyTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index d7ac038a84..27961faaf6 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -18,11 +18,13 @@ #include #include +#include #include "Client.h" // temporarily needed for LayerCreationArgs #include "FrontEnd/LayerCreationArgs.h" #include "FrontEnd/LayerHierarchy.h" #include "FrontEnd/LayerLifecycleManager.h" +#include "FrontEnd/LayerSnapshotBuilder.h" namespace android::surfaceflinger::frontend { @@ -358,6 +360,19 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setDefaultFrameRateCompatibility(uint32_t id, int8_t defaultFrameRateCompatibility) { + std::vector transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = + layer_state_t::eDefaultFrameRateCompatibilityChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.defaultFrameRateCompatibility = + defaultFrameRateCompatibility; + mLifecycleManager.applyTransactions(transactions); + } + void setRoundedCorners(uint32_t id, float radius) { std::vector transactions; transactions.emplace_back(); @@ -384,6 +399,16 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setBuffer(uint32_t id) { + static uint64_t sBufferId = 1; + setBuffer(id, + std::make_shared(1U /*width*/, 1U /*height*/, + sBufferId++, + HAL_PIXEL_FORMAT_RGBA_8888, + GRALLOC_USAGE_PROTECTED /*usage*/)); + } + void setBufferCrop(uint32_t id, const Rect& bufferCrop) { std::vector transactions; transactions.emplace_back(); @@ -409,4 +434,50 @@ protected: LayerLifecycleManager mLifecycleManager; }; +class LayerSnapshotTestBase : public LayerHierarchyTestBase { +protected: + LayerSnapshotTestBase() : LayerHierarchyTestBase() {} + + void createRootLayer(uint32_t id) override { + LayerHierarchyTestBase::createRootLayer(id); + setColor(id); + } + + void createLayer(uint32_t id, uint32_t parentId) override { + LayerHierarchyTestBase::createLayer(id, parentId); + setColor(parentId); + } + + void mirrorLayer(uint32_t id, uint32_t parent, uint32_t layerToMirror) override { + LayerHierarchyTestBase::mirrorLayer(id, parent, layerToMirror); + setColor(id); + } + + void update(LayerSnapshotBuilder& snapshotBuilder) { + if (mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)) { + mHierarchyBuilder.update(mLifecycleManager.getLayers(), + mLifecycleManager.getDestroyedLayers()); + } + LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(), + .layerLifecycleManager = mLifecycleManager, + .includeMetadata = false, + .displays = mFrontEndDisplayInfos, + .displayChanges = mHasDisplayChanges, + .globalShadowSettings = globalShadowSettings, + .supportsBlur = true, + .supportedLayerGenericMetadata = {}, + .genericLayerMetadataKeyMap = {}}; + snapshotBuilder.update(args); + + mLifecycleManager.commitChanges(); + } + + LayerHierarchyBuilder mHierarchyBuilder{{}}; + + DisplayInfos mFrontEndDisplayInfos; + bool mHasDisplayChanges = false; + + renderengine::ShadowSettings globalShadowSettings; +}; + } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp new file mode 100644 index 0000000000..a462082141 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp @@ -0,0 +1,873 @@ +/* + * Copyright 2023 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. + */ + +#undef LOG_TAG +#define LOG_TAG "LayerHistoryIntegrationTest" + +#include +#include +#include +#include + +#include + +#include "FpsOps.h" +#include "LayerHierarchyTest.h" +#include "Scheduler/LayerHistory.h" +#include "Scheduler/LayerInfo.h" +#include "TestableScheduler.h" +#include "TestableSurfaceFlinger.h" +#include "mock/DisplayHardware/MockDisplayMode.h" +#include "mock/MockSchedulerCallback.h" + +namespace android::scheduler { + +using android::mock::createDisplayMode; + +class LayerHistoryIntegrationTest : public surfaceflinger::frontend::LayerSnapshotTestBase { +protected: + static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfo::HISTORY_SIZE; + static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfo::kMaxPeriodForFrequentLayerNs; + static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfo::kFrequentLayerWindowSize; + static constexpr auto PRESENT_TIME_HISTORY_DURATION = LayerInfo::HISTORY_DURATION; + + static constexpr Fps LO_FPS = 30_Hz; + static constexpr auto LO_FPS_PERIOD = LO_FPS.getPeriodNsecs(); + + static constexpr Fps HI_FPS = 90_Hz; + static constexpr auto HI_FPS_PERIOD = HI_FPS.getPeriodNsecs(); + + LayerHistoryIntegrationTest() : LayerSnapshotTestBase() { + mFlinger.resetScheduler(mScheduler); + mLifecycleManager = {}; + mHierarchyBuilder = {{}}; + } + + void updateLayerSnapshotsAndLayerHistory(nsecs_t now) { + LayerSnapshotTestBase::update(mFlinger.mutableLayerSnapshotBuilder()); + mFlinger.updateLayerHistory(now); + } + + void setBufferWithPresentTime(sp& layer, nsecs_t time) { + uint32_t sequence = static_cast(layer->sequence); + setBuffer(sequence); + layer->setDesiredPresentTime(time, false /*autotimestamp*/); + updateLayerSnapshotsAndLayerHistory(time); + } + + LayerHistory& history() { return mScheduler->mutableLayerHistory(); } + const LayerHistory& history() const { return mScheduler->mutableLayerHistory(); } + + LayerHistory::Summary summarizeLayerHistory(nsecs_t now) { + // LayerHistory::summarize makes no guarantee of the order of the elements in the summary + // however, for testing only, a stable order is required, therefore we sort the list here. + // Any tests requiring ordered results must create layers with names. + auto summary = history().summarize(*mScheduler->refreshRateSelector(), now); + std::sort(summary.begin(), summary.end(), + [](const RefreshRateSelector::LayerRequirement& lhs, + const RefreshRateSelector::LayerRequirement& rhs) -> bool { + return lhs.name < rhs.name; + }); + return summary; + } + + size_t layerCount() const { return mScheduler->layerHistorySize(); } + size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { + return history().mActiveLayerInfos.size(); + } + + auto frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { + const auto& infos = history().mActiveLayerInfos; + return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) { + return pair.second.second->isFrequent(now).isFrequent; + }); + } + + auto animatingLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { + const auto& infos = history().mActiveLayerInfos; + return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) { + return pair.second.second->isAnimating(now); + }); + } + + auto clearLayerHistoryCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { + const auto& infos = history().mActiveLayerInfos; + return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) { + return pair.second.second->isFrequent(now).clearHistory; + }); + } + + void setDefaultLayerVote(Layer* layer, + LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS { + auto [found, layerPair] = history().findLayer(layer->getSequence()); + if (found != LayerHistory::LayerStatus::NotFound) { + layerPair->second->setDefaultLayerVote(vote); + } + } + + auto createLegacyAndFrontedEndLayer(uint32_t sequence) { + std::string layerName = "test layer:" + std::to_string(sequence); + const auto layer = + sp::make(LayerCreationArgs{mFlinger.flinger(), + nullptr, + layerName, + 0, + {}, + std::make_optional(sequence)}); + mFlinger.injectLegacyLayer(layer); + createRootLayer(sequence); + return layer; + } + + auto destroyLayer(sp& layer) { + uint32_t sequence = static_cast(layer->sequence); + mFlinger.releaseLegacyLayer(sequence); + layer.clear(); + destroyLayerHandle(sequence); + } + + void recordFramesAndExpect(sp& layer, nsecs_t& time, Fps frameRate, + Fps desiredRefreshRate, int numFrames) { + LayerHistory::Summary summary; + for (int i = 0; i < numFrames; i++) { + setBufferWithPresentTime(layer, time); + time += frameRate.getPeriodNsecs(); + + summary = summarizeLayerHistory(time); + } + + ASSERT_EQ(1u, summary.size()); + ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate); + } + + std::shared_ptr mSelector = + std::make_shared(makeModes(createDisplayMode(DisplayModeId(0), + LO_FPS), + createDisplayMode(DisplayModeId(1), + HI_FPS)), + DisplayModeId(0)); + + mock::SchedulerCallback mSchedulerCallback; + + TestableScheduler* mScheduler = new TestableScheduler(mSelector, mSchedulerCallback); + + TestableSurfaceFlinger mFlinger; +}; + +namespace { + +TEST_F(LayerHistoryIntegrationTest, singleLayerNoVoteDefaultCompatibility) { + createLegacyAndFrontedEndLayer(1); + nsecs_t time = systemTime(); + + updateLayerSnapshotsAndLayerHistory(time); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + // No layers returned if no layers are active. + EXPECT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(0u, activeLayerCount()); + + setBuffer(1); + setDefaultFrameRateCompatibility(1, ANATIVEWINDOW_FRAME_RATE_NO_VOTE); + updateLayerSnapshotsAndLayerHistory(time); + + EXPECT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(1u, activeLayerCount()); +} + +TEST_F(LayerHistoryIntegrationTest, singleLayerMinVoteDefaultCompatibility) { + createLegacyAndFrontedEndLayer(1); + nsecs_t time = systemTime(); + updateLayerSnapshotsAndLayerHistory(time); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + EXPECT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(0u, activeLayerCount()); + + setBuffer(1); + setDefaultFrameRateCompatibility(1, ANATIVEWINDOW_FRAME_RATE_MIN); + updateLayerSnapshotsAndLayerHistory(time); + + auto summary = summarizeLayerHistory(time); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); +} + +TEST_F(LayerHistoryIntegrationTest, oneInvisibleLayer) { + createLegacyAndFrontedEndLayer(1); + nsecs_t time = systemTime(); + updateLayerSnapshotsAndLayerHistory(time); + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + setBuffer(1); + updateLayerSnapshotsAndLayerHistory(time); + auto summary = summarizeLayerHistory(time); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + // Layer is still considered inactive so we expect to get Min + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + + hideLayer(1); + setBuffer(1); + updateLayerSnapshotsAndLayerHistory(time); + + summary = summarizeLayerHistory(time); + EXPECT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(0u, activeLayerCount()); +} + +TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVote) { + createLegacyAndFrontedEndLayer(1); + setFrameRate(1, 73.4f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + nsecs_t time = systemTime(); + updateLayerSnapshotsAndLayerHistory(time); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitExactVote) { + createLegacyAndFrontedEndLayer(1); + setFrameRate(1, 73.4f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + nsecs_t time = systemTime(); + updateLayerSnapshotsAndLayerHistory(time); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, + summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitCategory) { + createLegacyAndFrontedEndLayer(1); + setFrameRateCategory(1, ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + + nsecs_t time = systemTime(); + updateLayerSnapshotsAndLayerHistory(time); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + // First LayerRequirement is the frame rate specification + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); +} + +TEST_F(LayerHistoryIntegrationTest, multipleLayers) { + auto layer1 = createLegacyAndFrontedEndLayer(1); + auto layer2 = createLegacyAndFrontedEndLayer(2); + auto layer3 = createLegacyAndFrontedEndLayer(3); + + nsecs_t time = systemTime(); + + EXPECT_EQ(3u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + + LayerHistory::Summary summary; + + // layer1 is active but infrequent. + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer1, time); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + summary = summarizeLayerHistory(time); + } + + ASSERT_EQ(1u, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + + // layer2 is frequent and has high refresh rate. + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer2, time); + time += HI_FPS_PERIOD; + summary = summarizeLayerHistory(time); + } + + // layer1 is still active but infrequent. + setBufferWithPresentTime(layer1, time); + + ASSERT_EQ(2u, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote); + ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote); + EXPECT_EQ(HI_FPS, summarizeLayerHistory(time)[1].desiredRefreshRate); + + EXPECT_EQ(2u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + + // layer1 is no longer active. + // layer2 is frequent and has low refresh rate. + for (size_t i = 0; i < 2 * PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer2, time); + time += LO_FPS_PERIOD; + summary = summarizeLayerHistory(time); + } + + ASSERT_EQ(1u, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + + // layer2 still has low refresh rate. + // layer3 has high refresh rate but not enough history. + constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD; + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) { + if (i % RATIO == 0) { + setBufferWithPresentTime(layer2, time); + } + + setBufferWithPresentTime(layer3, time); + time += HI_FPS_PERIOD; + summary = summarizeLayerHistory(time); + } + + ASSERT_EQ(2u, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summary[1].vote); + EXPECT_EQ(2u, activeLayerCount()); + EXPECT_EQ(2, frequentLayerCount(time)); + + // layer3 becomes recently active. + setBufferWithPresentTime(layer3, time); + summary = summarizeLayerHistory(time); + ASSERT_EQ(2u, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote); + EXPECT_EQ(HI_FPS, summary[1].desiredRefreshRate); + EXPECT_EQ(2u, activeLayerCount()); + EXPECT_EQ(2, frequentLayerCount(time)); + + // layer1 expires. + destroyLayer(layer1); + updateLayerSnapshotsAndLayerHistory(time); + + summary = summarizeLayerHistory(time); + ASSERT_EQ(2u, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote); + EXPECT_EQ(HI_FPS, summary[1].desiredRefreshRate); + EXPECT_EQ(2u, layerCount()); + EXPECT_EQ(2u, activeLayerCount()); + EXPECT_EQ(2, frequentLayerCount(time)); + + // layer2 still has low refresh rate. + // layer3 becomes inactive. + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer2, time); + time += LO_FPS_PERIOD; + summary = summarizeLayerHistory(time); + } + + ASSERT_EQ(1u, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + + // layer2 expires. + destroyLayer(layer2); + updateLayerSnapshotsAndLayerHistory(time); + summary = summarizeLayerHistory(time); + EXPECT_TRUE(summary.empty()); + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + + // layer3 becomes active and has high refresh rate. + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE + FREQUENT_LAYER_WINDOW_SIZE + 1; i++) { + setBufferWithPresentTime(layer3, time); + time += HI_FPS_PERIOD; + summary = summarizeLayerHistory(time); + } + + ASSERT_EQ(1u, summary.size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_EQ(HI_FPS, summary[0].desiredRefreshRate); + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + + // layer3 expires. + destroyLayer(layer3); + updateLayerSnapshotsAndLayerHistory(time); + summary = summarizeLayerHistory(time); + EXPECT_TRUE(summary.empty()); + EXPECT_EQ(0u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryIntegrationTest, inactiveLayers) { + auto layer = createLegacyAndFrontedEndLayer(1); + nsecs_t time = systemTime(); + + // the very first updates makes the layer frequent + for (size_t i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) { + setBufferWithPresentTime(layer, time); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + + EXPECT_EQ(1u, layerCount()); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + } + + // the next update with the MAX_FREQUENT_LAYER_PERIOD_NS will get us to infrequent + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + setBufferWithPresentTime(layer, time); + + EXPECT_EQ(1u, layerCount()); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + + // advance the time for the previous frame to be inactive + time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); + + // Now even if we post a quick few frame we should stay infrequent + for (size_t i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) { + setBufferWithPresentTime(layer, time); + time += HI_FPS_PERIOD; + + EXPECT_EQ(1u, layerCount()); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + } + + // More quick frames will get us to frequent again + setBufferWithPresentTime(layer, time); + time += HI_FPS_PERIOD; + + EXPECT_EQ(1u, layerCount()); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryIntegrationTest, invisibleExplicitLayer) { + auto explicitVisiblelayer = createLegacyAndFrontedEndLayer(1); + auto explicitInvisiblelayer = createLegacyAndFrontedEndLayer(2); + hideLayer(2); + setFrameRate(1, 60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + setFrameRate(2, 90.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + nsecs_t time = systemTime(); + + // Post a buffer to the layers to make them active + setBufferWithPresentTime(explicitVisiblelayer, time); + setBufferWithPresentTime(explicitInvisiblelayer, time); + + EXPECT_EQ(2u, layerCount()); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, + summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(2u, activeLayerCount()); + EXPECT_EQ(2, frequentLayerCount(time)); +} + +TEST_F(LayerHistoryIntegrationTest, infrequentAnimatingLayer) { + auto layer = createLegacyAndFrontedEndLayer(1); + + nsecs_t time = systemTime(); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // layer is active but infrequent. + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer, time); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + } + + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // another update with the same cadence keep in infrequent + setBufferWithPresentTime(layer, time); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + mFlinger.mutableLayerSnapshotBuilder().getSnapshot(1)->changes |= + frontend::RequestedLayerState::Changes::Animation; + mFlinger.updateLayerHistory(time); + // an update as animation will immediately vote for Max + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(1, animatingLayerCount(time)); +} + +TEST_F(LayerHistoryIntegrationTest, frequentLayerBecomingInfrequentAndBack) { + auto layer = createLegacyAndFrontedEndLayer(1); + + nsecs_t time = systemTime(); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // Fill up the window with frequent updates + for (size_t i = 0; i < FREQUENT_LAYER_WINDOW_SIZE; i++) { + setBufferWithPresentTime(layer, time); + time += (60_Hz).getPeriodNsecs(); + + EXPECT_EQ(1u, layerCount()); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + } + + // posting a buffer after long inactivity should retain the layer as active + time += std::chrono::nanoseconds(3s).count(); + setBufferWithPresentTime(layer, time); + EXPECT_EQ(0, clearLayerHistoryCount(time)); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // posting more infrequent buffer should make the layer infrequent + time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count(); + setBufferWithPresentTime(layer, time); + time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count(); + setBufferWithPresentTime(layer, time); + EXPECT_EQ(0, clearLayerHistoryCount(time)); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // posting another buffer should keep the layer infrequent + setBufferWithPresentTime(layer, time); + EXPECT_EQ(0, clearLayerHistoryCount(time)); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // posting more buffers would mean starting of an animation, so making the layer frequent + setBufferWithPresentTime(layer, time); + setBufferWithPresentTime(layer, time); + EXPECT_EQ(1, clearLayerHistoryCount(time)); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // posting a buffer after long inactivity should retain the layer as active + time += std::chrono::nanoseconds(3s).count(); + setBufferWithPresentTime(layer, time); + EXPECT_EQ(0, clearLayerHistoryCount(time)); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // posting another buffer should keep the layer frequent + time += (60_Hz).getPeriodNsecs(); + setBufferWithPresentTime(layer, time); + EXPECT_EQ(0, clearLayerHistoryCount(time)); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); +} + +TEST_F(LayerHistoryIntegrationTest, inconclusiveLayerBecomingFrequent) { + auto layer = createLegacyAndFrontedEndLayer(1); + + nsecs_t time = systemTime(); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // Fill up the window with frequent updates + for (size_t i = 0; i < FREQUENT_LAYER_WINDOW_SIZE; i++) { + setBufferWithPresentTime(layer, time); + time += (60_Hz).getPeriodNsecs(); + + EXPECT_EQ(1u, layerCount()); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + } + + // posting infrequent buffers after long inactivity should make the layer + // inconclusive but frequent. + time += std::chrono::nanoseconds(3s).count(); + setBufferWithPresentTime(layer, time); + time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count(); + setBufferWithPresentTime(layer, time); + EXPECT_EQ(0, clearLayerHistoryCount(time)); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // posting more buffers should make the layer frequent and switch the refresh rate to max + // by clearing the history + setBufferWithPresentTime(layer, time); + setBufferWithPresentTime(layer, time); + setBufferWithPresentTime(layer, time); + EXPECT_EQ(1, clearLayerHistoryCount(time)); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); +} + +TEST_F(LayerHistoryIntegrationTest, getFramerate) { + auto layer = createLegacyAndFrontedEndLayer(1); + + nsecs_t time = systemTime(); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + EXPECT_EQ(0, animatingLayerCount(time)); + + // layer is active but infrequent. + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + setBufferWithPresentTime(layer, time); + time += MAX_FREQUENT_LAYER_PERIOD_NS.count(); + } + + float expectedFramerate = 1e9f / MAX_FREQUENT_LAYER_PERIOD_NS.count(); + EXPECT_FLOAT_EQ(expectedFramerate, history().getLayerFramerate(time, layer->getSequence())); +} + +TEST_F(LayerHistoryIntegrationTest, heuristicLayer60Hz) { + auto layer = createLegacyAndFrontedEndLayer(1); + + nsecs_t time = systemTime(); + for (float fps = 54.0f; fps < 65.0f; fps += 0.1f) { + recordFramesAndExpect(layer, time, Fps::fromValue(fps), 60_Hz, PRESENT_TIME_HISTORY_SIZE); + } +} + +TEST_F(LayerHistoryIntegrationTest, heuristicLayer60_30Hz) { + auto layer = createLegacyAndFrontedEndLayer(1); + + nsecs_t time = systemTime(); + recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE); + + recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 30_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 30_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 60_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE); +} + +TEST_F(LayerHistoryIntegrationTest, heuristicLayerNotOscillating) { + auto layer = createLegacyAndFrontedEndLayer(1); + + nsecs_t time = systemTime(); + + recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 26.9_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 26_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 26.9_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE); + recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE); +} + +TEST_F(LayerHistoryIntegrationTest, smallDirtyLayer) { + auto layer = createLegacyAndFrontedEndLayer(1); + + nsecs_t time = systemTime(); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + + LayerHistory::Summary summary; + + // layer is active but infrequent. + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + auto props = layer->getLayerProps(); + if (i % 3 == 0) { + props.isSmallDirty = false; + } else { + props.isSmallDirty = true; + } + + setBufferWithPresentTime(layer, time); + time += HI_FPS_PERIOD; + summary = summarizeLayerHistory(time); + } + + ASSERT_EQ(1u, summary.size()); + ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote); + EXPECT_GE(HI_FPS, summary[0].desiredRefreshRate); +} + +TEST_F(LayerHistoryIntegrationTest, DISABLED_smallDirtyInMultiLayer) { + auto uiLayer = createLegacyAndFrontedEndLayer(1); + auto videoLayer = createLegacyAndFrontedEndLayer(2); + setFrameRate(2, 30.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + + nsecs_t time = systemTime(); + + EXPECT_EQ(2u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + + LayerHistory::Summary summary; + + // uiLayer is updating small dirty. + for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE + FREQUENT_LAYER_WINDOW_SIZE + 1; i++) { + auto props = uiLayer->getLayerProps(); + props.isSmallDirty = true; + setBuffer(1); + uiLayer->setDesiredPresentTime(0, false /*autotimestamp*/); + updateLayerSnapshotsAndLayerHistory(time); + setBufferWithPresentTime(videoLayer, time); + summary = summarizeLayerHistory(time); + } + + ASSERT_EQ(1u, summary.size()); + ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote); + ASSERT_EQ(30_Hz, summary[0].desiredRefreshRate); +} + +class LayerHistoryIntegrationTestParameterized + : public LayerHistoryIntegrationTest, + public testing::WithParamInterface {}; + +TEST_P(LayerHistoryIntegrationTestParameterized, HeuristicLayerWithInfrequentLayer) { + std::chrono::nanoseconds infrequentUpdateDelta = GetParam(); + auto heuristicLayer = createLegacyAndFrontedEndLayer(1); + auto infrequentLayer = createLegacyAndFrontedEndLayer(2); + + const nsecs_t startTime = systemTime(); + + const std::chrono::nanoseconds heuristicUpdateDelta = 41'666'667ns; + setBufferWithPresentTime(heuristicLayer, startTime); + setBufferWithPresentTime(infrequentLayer, startTime); + + nsecs_t time = startTime; + nsecs_t lastInfrequentUpdate = startTime; + const size_t totalInfrequentLayerUpdates = FREQUENT_LAYER_WINDOW_SIZE * 5; + size_t infrequentLayerUpdates = 0; + while (infrequentLayerUpdates <= totalInfrequentLayerUpdates) { + time += heuristicUpdateDelta.count(); + setBufferWithPresentTime(heuristicLayer, time); + + if (time - lastInfrequentUpdate >= infrequentUpdateDelta.count()) { + ALOGI("submitting infrequent frame [%zu/%zu]", infrequentLayerUpdates, + totalInfrequentLayerUpdates); + lastInfrequentUpdate = time; + setBufferWithPresentTime(infrequentLayer, time); + infrequentLayerUpdates++; + } + + if (time - startTime > PRESENT_TIME_HISTORY_DURATION.count()) { + ASSERT_NE(0u, summarizeLayerHistory(time).size()); + ASSERT_GE(2u, summarizeLayerHistory(time).size()); + + bool max = false; + bool min = false; + Fps heuristic; + for (const auto& layer : summarizeLayerHistory(time)) { + if (layer.vote == LayerHistory::LayerVoteType::Heuristic) { + heuristic = layer.desiredRefreshRate; + } else if (layer.vote == LayerHistory::LayerVoteType::Max) { + max = true; + } else if (layer.vote == LayerHistory::LayerVoteType::Min) { + min = true; + } + } + + if (infrequentLayerUpdates > FREQUENT_LAYER_WINDOW_SIZE) { + EXPECT_EQ(24_Hz, heuristic); + EXPECT_FALSE(max); + if (summarizeLayerHistory(time).size() == 2) { + EXPECT_TRUE(min); + } + } + } + } +} + +INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryIntegrationTestParameterized, + ::testing::Values(1s, 2s, 3s, 4s, 5s)); + +} // namespace +} // namespace android::scheduler diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 549a362af3..33c1d86847 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -45,6 +45,8 @@ using MockLayer = android::mock::MockLayer; using android::mock::createDisplayMode; +// WARNING: LEGACY TESTS FOR LEGACY FRONT END +// Update LayerHistoryIntegrationTest instead class LayerHistoryTest : public testing::Test { protected: static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfo::HISTORY_SIZE; diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 69316bf4e5..e8568162b8 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -50,27 +50,12 @@ using namespace ftl::flag_operators; --gtest_filter="LayerSnapshotTest.*" --gtest_brief=1 */ -class LayerSnapshotTest : public LayerHierarchyTestBase { +class LayerSnapshotTest : public LayerSnapshotTestBase { protected: - LayerSnapshotTest() : LayerHierarchyTestBase() { + LayerSnapshotTest() : LayerSnapshotTestBase() { UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); } - void createRootLayer(uint32_t id) override { - LayerHierarchyTestBase::createRootLayer(id); - setColor(id); - } - - void createLayer(uint32_t id, uint32_t parentId) override { - LayerHierarchyTestBase::createLayer(id, parentId); - setColor(parentId); - } - - void mirrorLayer(uint32_t id, uint32_t parent, uint32_t layerToMirror) override { - LayerHierarchyTestBase::mirrorLayer(id, parent, layerToMirror); - setColor(id); - } - void update(LayerSnapshotBuilder& actualBuilder, LayerSnapshotBuilder::Args& args) { if (mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)) { mHierarchyBuilder.update(mLifecycleManager.getLayers(), @@ -111,11 +96,7 @@ protected: LayerSnapshot* getSnapshot(const LayerHierarchy::TraversalPath path) { return mSnapshotBuilder.getSnapshot(path); } - - LayerHierarchyBuilder mHierarchyBuilder{{}}; LayerSnapshotBuilder mSnapshotBuilder; - DisplayInfos mFrontEndDisplayInfos; - renderengine::ShadowSettings globalShadowSettings; static const std::vector STARTING_ZORDER; }; const std::vector LayerSnapshotTest::STARTING_ZORDER = {1, 11, 111, 12, 121, diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 173f9417b9..a6f23ed091 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -192,7 +192,7 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentIsNoopWhenModeSwitchingIsNotSup // recordLayerHistory should be a noop ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); - mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0, + mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0, 0, LayerHistory::LayerUpdateType::Buffer); ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); @@ -218,7 +218,7 @@ TEST_F(SchedulerTest, updateDisplayModes) { kDisplay1Mode60->getId())); ASSERT_EQ(0u, mScheduler->getNumActiveLayers()); - mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0, + mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0, 0, LayerHistory::LayerUpdateType::Buffer); ASSERT_EQ(1u, mScheduler->getNumActiveLayers()); } @@ -273,7 +273,7 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { const sp layer = sp::make(mFlinger.flinger()); EXPECT_CALL(*layer, isVisible()).WillOnce(Return(true)); - mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0, + mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0, systemTime(), LayerHistory::LayerUpdateType::Buffer); constexpr hal::PowerMode kPowerModeOn = hal::PowerMode::ON; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index dd998ba629..b54392e651 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -604,6 +604,13 @@ public: return static_cast(mFlinger->mFrameTracer.get()); } + void injectLegacyLayer(sp layer) { + mFlinger->mLegacyLayers[static_cast(layer->sequence)] = layer; + }; + + void releaseLegacyLayer(uint32_t sequence) { mFlinger->mLegacyLayers.erase(sequence); }; + + auto updateLayerHistory(nsecs_t now) { return mFlinger->updateLayerHistory(now); }; /* ------------------------------------------------------------------------ * Read-write access to private data to set up preconditions and assert * post-conditions. @@ -644,8 +651,8 @@ public: } auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; } - auto& mutableLayersPendingRemoval() { return mFlinger->mLayersPendingRemoval; } + auto& mutableLayerSnapshotBuilder() { return mFlinger->mLayerSnapshotBuilder; }; auto fromHandle(const sp& handle) { return LayerHandle::getLayer(handle); } -- GitLab From befd3e2f1b09d94c4c668f469e6fb1aa501b87e6 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 5 Oct 2023 17:48:31 +0000 Subject: [PATCH 0752/1187] [sf] fix shadow radius propagation Fixes an issue where shadow radius was not being set on the snapshot. Bug: 302551905 Test: presubmit Change-Id: Ifc4019d67b0c20dccb913dcb36c4a3ee21ec9f47 --- .../surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp | 1 + .../tests/unittests/LayerHierarchyTest.h | 11 +++++++++++ .../tests/unittests/LayerSnapshotTest.cpp | 9 +++++++++ 3 files changed, 21 insertions(+) diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 55be398bd0..a1796e1eb0 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -1006,6 +1006,7 @@ void LayerSnapshotBuilder::updateShadows(LayerSnapshot& snapshot, const Requeste snapshot.shadowSettings.ambientColor *= snapshot.alpha; snapshot.shadowSettings.spotColor *= snapshot.alpha; } + snapshot.shadowSettings.length = snapshot.shadowRadius; } void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot, diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index d7ac038a84..1898f43dcc 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -406,6 +406,17 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setShadowRadius(uint32_t id, float shadowRadius) { + std::vector transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = layer_state_t::eShadowRadiusChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.shadowRadius = shadowRadius; + mLifecycleManager.applyTransactions(transactions); + } + LayerLifecycleManager mLifecycleManager; }; diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 69316bf4e5..2ae01312ae 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -872,4 +872,13 @@ TEST_F(LayerSnapshotTest, setBufferCrop) { UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); EXPECT_EQ(getSnapshot(1)->geomContentCrop, Rect(0, 0, 100, 100)); } + +TEST_F(LayerSnapshotTest, setShadowRadius) { + static constexpr float SHADOW_RADIUS = 123.f; + setShadowRadius(1, SHADOW_RADIUS); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot(1)->shadowSettings.length, SHADOW_RADIUS); + EXPECT_EQ(getSnapshot(1)->shadowRadius, SHADOW_RADIUS); +} + } // namespace android::surfaceflinger::frontend -- GitLab From 50e2e4d5f75fb481b729ef05808008adad7de10a Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 4 Oct 2023 10:58:28 -0400 Subject: [PATCH 0753/1187] SF: Fix freezing after follower display mode set When a mode set is initiated for any display, SF skips committing until HWC confirms the mode set by signaling the corresponding present fence. However, if a concurrent follower display misses a frame (i.e. does not signal the fence) as its mode is set, SF::commit skips endlessly, since the Scheduler only checked for missed frames on followers after commit. Fix this by having all displays FrameTargeter::beginFrame before commit. Fixes: 301082260 Test: Mode set on external display does not sporadically freeze SF. Test: SchedulerTest.onFrameSignalMultipleDisplays Change-Id: Ic97f33975f6d30279cc65cefe5d7ccc2561c45aa --- .../surfaceflinger/Scheduler/Scheduler.cpp | 5 +- .../tests/unittests/SchedulerTest.cpp | 57 +++++++++++++++++++ .../tests/unittests/TestableScheduler.h | 6 ++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 76f1af9f56..b5b20fbd8a 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -192,7 +192,8 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, for (const auto& [id, display] : mDisplays) { if (id == pacesetterId) continue; - const FrameTargeter& targeter = *display.targeterPtr; + FrameTargeter& targeter = *display.targeterPtr; + targeter.beginFrame(beginFrameArgs, *display.schedulePtr); targets.try_emplace(id, &targeter.target()); } @@ -206,8 +207,6 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, if (id == pacesetterId) continue; FrameTargeter& targeter = *display.targeterPtr; - targeter.beginFrame(beginFrameArgs, *display.schedulePtr); - targeters.try_emplace(id, &targeter); } diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 173f9417b9..0df41ed422 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -444,6 +444,63 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { } } +TEST_F(SchedulerTest, onFrameSignalMultipleDisplays) { + mScheduler->registerDisplay(kDisplayId1, + std::make_shared(kDisplay1Modes, + kDisplay1Mode60->getId())); + mScheduler->registerDisplay(kDisplayId2, + std::make_shared(kDisplay2Modes, + kDisplay2Mode60->getId())); + + using VsyncIds = std::vector>; + + struct Compositor final : ICompositor { + VsyncIds vsyncIds; + bool committed = true; + + void configure() override {} + + bool commit(PhysicalDisplayId, const scheduler::FrameTargets& targets) override { + vsyncIds.clear(); + + for (const auto& [id, target] : targets) { + vsyncIds.emplace_back(id, target->vsyncId()); + } + + return committed; + } + + CompositeResultsPerDisplay composite(PhysicalDisplayId, + const scheduler::FrameTargeters&) override { + CompositeResultsPerDisplay results; + + for (const auto& [id, _] : vsyncIds) { + results.try_emplace(id, + CompositeResult{.compositionCoverage = + CompositionCoverage::Hwc}); + } + + return results; + } + + void sample() override {} + } compositor; + + mScheduler->doFrameSignal(compositor, VsyncId(42)); + + const auto makeVsyncIds = [](VsyncId vsyncId) -> VsyncIds { + return {{kDisplayId1, vsyncId}, {kDisplayId2, vsyncId}}; + }; + + EXPECT_EQ(makeVsyncIds(VsyncId(42)), compositor.vsyncIds); + + compositor.committed = false; + mScheduler->doFrameSignal(compositor, VsyncId(43)); + + // FrameTargets should be updated despite the skipped commit. + EXPECT_EQ(makeVsyncIds(VsyncId(43)), compositor.vsyncIds); +} + class AttachedChoreographerTest : public SchedulerTest { protected: void frameRateTestScenario(Fps layerFps, int8_t frameRateCompatibility, Fps displayFps, diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 151b178c01..014d07c38f 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -59,6 +59,12 @@ public: MOCK_METHOD(void, scheduleFrame, (), (override)); MOCK_METHOD(void, postMessage, (sp&&), (override)); + void doFrameSignal(ICompositor& compositor, VsyncId vsyncId) { + ftl::FakeGuard guard1(kMainThreadContext); + ftl::FakeGuard guard2(mDisplayLock); + Scheduler::onFrameSignal(compositor, vsyncId, TimePoint()); + } + // Used to inject mock event thread. ConnectionHandle createConnection(std::unique_ptr eventThread) { return Scheduler::createConnection(std::move(eventThread)); -- GitLab From 5d7b4cacb34e567353be72fe9d0d293001e62deb Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Thu, 5 Oct 2023 18:15:40 +0000 Subject: [PATCH 0754/1187] Fix warning about missing terminating ' character Bug: 302724232 Test: build binder with GCC Change-Id: I5bb7cff8999f6fb6f2411eb8697a79c979d12103 --- libs/binder/Stability.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp index 2d05fb2505..c432b3af29 100644 --- a/libs/binder/Stability.cpp +++ b/libs/binder/Stability.cpp @@ -75,7 +75,7 @@ void Stability::tryMarkCompilationUnit(IBinder* binder) { Stability::Level Stability::getLocalLevel() { #ifdef __ANDROID_APEX__ -#error APEX can't use libbinder (must use libbinder_ndk) +#error "APEX can't use libbinder (must use libbinder_ndk)" #endif #ifdef __ANDROID_VNDK__ -- GitLab From 7b875a6e899010ba6b5117e94ca55849f7ad39b0 Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Thu, 5 Oct 2023 18:07:06 +0000 Subject: [PATCH 0755/1187] Fix the dataspace description in dataspace ndk documentation. Bug: 300602767 Change-Id: Ie67bf2ef39faa8b679fde7831bd8f45d264a3350 Test: builds --- .../nativewindow/include/android/data_space.h | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h index ae6d22350c..bce88bebb9 100644 --- a/libs/nativewindow/include/android/data_space.h +++ b/libs/nativewindow/include/android/data_space.h @@ -384,21 +384,22 @@ enum ADataSpace { RANGE_EXTENDED = 3 << 27, /** - * scRGB linear encoding: + * scRGB linear encoding * * The red, green, and blue components are stored in extended sRGB space, * but are linear, not gamma-encoded. - * The RGB primaries and the white point are the same as BT.709. * * The values are floating point. * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits. * Values beyond the range [0.0 - 1.0] would correspond to other colors * spaces and/or HDR content. + * + * Uses extended range, linear transfer and BT.709 standard. */ ADATASPACE_SCRGB_LINEAR = 406913024, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED /** - * sRGB gamma encoding: + * sRGB gamma encoding * * The red, green and blue components are stored in sRGB space, and * converted to linear space when read, using the SRGB transfer function @@ -408,29 +409,29 @@ enum ADataSpace { * The alpha component, if present, is always stored in linear space and * is left unmodified when read or written. * - * Use full range and BT.709 standard. + * Uses full range, sRGB transfer BT.709 standard. */ ADATASPACE_SRGB = 142671872, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL /** - * scRGB: + * scRGB * * The red, green, and blue components are stored in extended sRGB space, * and gamma-encoded using the SRGB transfer function. - * The RGB primaries and the white point are the same as BT.709. * * The values are floating point. * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits. * Values beyond the range [0.0 - 1.0] would correspond to other colors * spaces and/or HDR content. + * + * Uses extended range, sRGB transfer and BT.709 standard. */ ADATASPACE_SCRGB = 411107328, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED /** * Display P3 * - * Use same primaries and white-point as DCI-P3 - * but sRGB transfer function. + * Uses full range, sRGB transfer and D65 DCI-P3 standard. */ ADATASPACE_DISPLAY_P3 = 143261696, // STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_FULL @@ -439,7 +440,7 @@ enum ADataSpace { * * Ultra High-definition television * - * Use full range, SMPTE 2084 (PQ) transfer and BT2020 standard + * Uses full range, SMPTE 2084 (PQ) transfer and BT2020 standard. */ ADATASPACE_BT2020_PQ = 163971072, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL @@ -448,14 +449,14 @@ enum ADataSpace { * * Ultra High-definition television * - * Use limited range, SMPTE 2084 (PQ) transfer and BT2020 standard + * Uses limited range, SMPTE 2084 (PQ) transfer and BT2020 standard. */ ADATASPACE_BT2020_ITU_PQ = 298188800, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED /** * Adobe RGB * - * Use full range, gamma 2.2 transfer and Adobe RGB primaries + * Uses full range, gamma 2.2 transfer and Adobe RGB standard. * * Note: Application is responsible for gamma encoding the data as * a 2.2 gamma encoding is not supported in HW. @@ -465,9 +466,9 @@ enum ADataSpace { /** * JPEG File Interchange Format (JFIF) * - * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255 + * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255. * - * Use full range, SMPTE 170M transfer and BT.601_625 standard. + * Uses full range, SMPTE 170M transfer and BT.601_625 standard. */ ADATASPACE_JFIF = 146931712, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL @@ -476,7 +477,7 @@ enum ADataSpace { * * Standard-definition television, 625 Lines (PAL) * - * Use limited range, SMPTE 170M transfer and BT.601_625 standard. + * Uses limited range, SMPTE 170M transfer and BT.601_625 standard. */ ADATASPACE_BT601_625 = 281149440, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED @@ -485,7 +486,7 @@ enum ADataSpace { * * Standard-definition television, 525 Lines (NTSC) * - * Use limited range, SMPTE 170M transfer and BT.601_525 standard. + * Uses limited range, SMPTE 170M transfer and BT.601_525 standard. */ ADATASPACE_BT601_525 = 281280512, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED @@ -494,7 +495,7 @@ enum ADataSpace { * * Ultra High-definition television * - * Use full range, SMPTE 170M transfer and BT2020 standard + * Uses full range, SMPTE 170M transfer and BT2020 standard. */ ADATASPACE_BT2020 = 147193856, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL @@ -503,16 +504,16 @@ enum ADataSpace { * * High-definition television * - * Use limited range, SMPTE 170M transfer and BT.709 standard. + * Uses limited range, SMPTE 170M transfer and BT.709 standard. */ ADATASPACE_BT709 = 281083904, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED /** - * SMPTE EG 432-1 and SMPTE RP 431-2. + * SMPTE EG 432-1 and SMPTE RP 431-2 * * Digital Cinema DCI-P3 * - * Use full range, gamma 2.6 transfer and D65 DCI-P3 standard + * Uses full range, gamma 2.6 transfer and D65 DCI-P3 standard. * * Note: Application is responsible for gamma encoding the data as * a 2.6 gamma encoding is not supported in HW. @@ -520,7 +521,7 @@ enum ADataSpace { ADATASPACE_DCI_P3 = 155844608, // STANDARD_DCI_P3 | TRANSFER_GAMMA2_6 | RANGE_FULL /** - * sRGB linear encoding: + * sRGB linear encoding * * The red, green, and blue components are stored in sRGB space, but * are linear, not gamma-encoded. @@ -528,32 +529,34 @@ enum ADataSpace { * * The values are encoded using the full range ([0,255] for 8-bit) for all * components. + * + * Uses full range, linear transfer and BT.709 standard. */ ADATASPACE_SRGB_LINEAR = 138477568, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL /** - * Hybrid Log Gamma encoding: + * Hybrid Log Gamma encoding * - * Use full range, hybrid log gamma transfer and BT2020 standard. + * Uses full range, hybrid log gamma transfer and BT2020 standard. */ ADATASPACE_BT2020_HLG = 168165376, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_FULL /** - * ITU Hybrid Log Gamma encoding: + * ITU Hybrid Log Gamma encoding * - * Use limited range, hybrid log gamma transfer and BT2020 standard. + * Uses limited range, hybrid log gamma transfer and BT2020 standard. */ ADATASPACE_BT2020_ITU_HLG = 302383104, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED /** - * Depth: + * Depth * * This value is valid with formats HAL_PIXEL_FORMAT_Y16 and HAL_PIXEL_FORMAT_BLOB. */ DEPTH = 4096, /** - * ISO 16684-1:2011(E) Dynamic Depth: + * ISO 16684-1:2011(E) Dynamic Depth * * Embedded depth metadata following the dynamic depth specification. */ -- GitLab From 7b6502d628f0293124922de1d570e756e57be6f6 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 6 Oct 2023 04:08:39 +0000 Subject: [PATCH 0756/1187] Move all matchers from dispatcher tests to TestInputListenerMatchers Bug: 245989146 Test: atest inputflinger_tests Change-Id: If628a5053ff1acbe2c4a448bf7aaa194254cfcc9 --- services/inputflinger/tests/Android.bp | 1 - .../tests/InputDispatcher_test.cpp | 68 ---- .../tests/TestInputListenerMatchers.cpp | 37 -- .../tests/TestInputListenerMatchers.h | 349 ++++++++++++++++-- 4 files changed, 315 insertions(+), 140 deletions(-) delete mode 100644 services/inputflinger/tests/TestInputListenerMatchers.cpp diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp index c0353af117..0922354a37 100644 --- a/services/inputflinger/tests/Android.bp +++ b/services/inputflinger/tests/Android.bp @@ -66,7 +66,6 @@ cc_test { "SyncQueue_test.cpp", "TimerProvider_test.cpp", "TestInputListener.cpp", - "TestInputListenerMatchers.cpp", "TouchpadInputMapper_test.cpp", "KeyboardInputMapper_test.cpp", "UinputDevice.cpp", diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 77d5391380..24c586cbc5 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -134,16 +134,6 @@ static constexpr int expectedWallpaperFlags = using ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID; -struct PointF { - float x; - float y; - auto operator<=>(const PointF&) const = default; -}; - -inline std::string pointFToString(const PointF& p) { - return std::string("(") + std::to_string(p.x) + ", " + std::to_string(p.y) + ")"; -} - /** * Return a DOWN key event with KEYCODE_A. */ @@ -156,64 +146,6 @@ static KeyEvent getTestKeyEvent() { return event; } -MATCHER_P(WithDownTime, downTime, "InputEvent with specified downTime") { - *result_listener << "expected downTime " << downTime << ", but got " << arg.getDownTime(); - return arg.getDownTime() == downTime; -} - -MATCHER_P(WithSource, source, "InputEvent with specified source") { - *result_listener << "expected source " << inputEventSourceToString(source) << ", but got " - << inputEventSourceToString(arg.getSource()); - return arg.getSource() == source; -} - -MATCHER_P(WithFlags, flags, "InputEvent with specified flags") { - *result_listener << "expected flags " << std::hex << flags << ", but got " << arg.getFlags(); - return arg.getFlags() == flags; -} - -MATCHER_P2(WithCoords, x, y, "MotionEvent with specified coordinates") { - if (arg.getPointerCount() != 1) { - *result_listener << "Expected 1 pointer, got " << arg.getPointerCount(); - return false; - } - const float receivedX = arg.getX(/*pointerIndex=*/0); - const float receivedY = arg.getY(/*pointerIndex=*/0); - *result_listener << "expected coords (" << x << ", " << y << "), but got (" << receivedX << ", " - << receivedY << ")"; - return receivedX == x && receivedY == y; -} - -MATCHER_P2(WithRawCoords, x, y, "MotionEvent with specified raw coordinates") { - if (arg.getPointerCount() != 1) { - *result_listener << "Expected 1 pointer, got " << arg.getPointerCount(); - return false; - } - const float receivedX = arg.getRawX(/*pointerIndex=*/0); - const float receivedY = arg.getRawY(/*pointerIndex=*/0); - *result_listener << "expected raw coords (" << x << ", " << y << "), but got (" << receivedX - << ", " << receivedY << ")"; - return receivedX == x && receivedY == y; -} - -MATCHER_P(WithPointerCount, pointerCount, "MotionEvent with specified number of pointers") { - *result_listener << "expected pointerCount " << pointerCount << ", but got " - << arg.getPointerCount(); - return arg.getPointerCount() == pointerCount; -} - -MATCHER_P(WithPointers, pointers, "MotionEvent with specified pointers") { - // Build a map for the received pointers, by pointer id - std::map actualPointers; - for (size_t pointerIndex = 0; pointerIndex < arg.getPointerCount(); pointerIndex++) { - const int32_t pointerId = arg.getPointerId(pointerIndex); - actualPointers[pointerId] = {arg.getX(pointerIndex), arg.getY(pointerIndex)}; - } - *result_listener << "expected pointers " << dumpMap(pointers, constToString, pointFToString) - << ", but got " << dumpMap(actualPointers, constToString, pointFToString); - return pointers == actualPointers; -} - // --- FakeInputDispatcherPolicy --- class FakeInputDispatcherPolicy : public InputDispatcherPolicyInterface { diff --git a/services/inputflinger/tests/TestInputListenerMatchers.cpp b/services/inputflinger/tests/TestInputListenerMatchers.cpp deleted file mode 100644 index 1464e6097e..0000000000 --- a/services/inputflinger/tests/TestInputListenerMatchers.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2023 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 "TestInputListenerMatchers.h" - -namespace android { - -WithKeyActionMatcher WithKeyAction(int32_t action) { - return WithKeyActionMatcher(action); -} - -WithMotionActionMatcher WithMotionAction(int32_t action) { - return WithMotionActionMatcher(action); -} - -WithDisplayIdMatcher WithDisplayId(int32_t displayId) { - return WithDisplayIdMatcher(displayId); -} - -WithDeviceIdMatcher WithDeviceId(int32_t deviceId) { - return WithDeviceIdMatcher(deviceId); -} - -} // namespace android diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestInputListenerMatchers.h index 31ad569c27..ee6ff53d8c 100644 --- a/services/inputflinger/tests/TestInputListenerMatchers.h +++ b/services/inputflinger/tests/TestInputListenerMatchers.h @@ -17,21 +17,60 @@ #pragma once #include +#include +#include #include #include #include #include +#include #include "NotifyArgs.h" #include "TestConstants.h" namespace android { -MATCHER_P(WithSource, source, "InputEvent with specified source") { - *result_listener << "expected source " << inputEventSourceToString(source) << ", but got " - << inputEventSourceToString(arg.source); - return arg.source == source; +struct PointF { + float x; + float y; + auto operator<=>(const PointF&) const = default; +}; + +inline std::string pointFToString(const PointF& p) { + return std::string("(") + std::to_string(p.x) + ", " + std::to_string(p.y) + ")"; +} + +/// Source +class WithSourceMatcher { +public: + using is_gtest_matcher = void; + explicit WithSourceMatcher(uint32_t source) : mSource(source) {} + + bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const { + return mSource == args.source; + } + + bool MatchAndExplain(const NotifyKeyArgs& args, std::ostream*) const { + return mSource == args.source; + } + + bool MatchAndExplain(const InputEvent& event, std::ostream*) const { + return mSource == event.getSource(); + } + + void DescribeTo(std::ostream* os) const { + *os << "with source " << inputEventSourceToString(mSource); + } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong source"; } + +private: + const uint32_t mSource; +}; + +inline WithSourceMatcher WithSource(uint32_t source) { + return WithSourceMatcher(source); } /// Key action @@ -58,7 +97,9 @@ private: const int32_t mAction; }; -WithKeyActionMatcher WithKeyAction(int32_t action); +inline WithKeyActionMatcher WithKeyAction(int32_t action) { + return WithKeyActionMatcher(action); +} /// Motion action class WithMotionActionMatcher { @@ -95,7 +136,9 @@ private: const int32_t mAction; }; -WithMotionActionMatcher WithMotionAction(int32_t action); +inline WithMotionActionMatcher WithMotionAction(int32_t action) { + return WithMotionActionMatcher(action); +} /// Display Id class WithDisplayIdMatcher { @@ -123,7 +166,9 @@ private: const int32_t mDisplayId; }; -WithDisplayIdMatcher WithDisplayId(int32_t displayId); +inline WithDisplayIdMatcher WithDisplayId(int32_t displayId) { + return WithDisplayIdMatcher(displayId); +} /// Device Id class WithDeviceIdMatcher { @@ -155,7 +200,269 @@ private: const int32_t mDeviceId; }; -WithDeviceIdMatcher WithDeviceId(int32_t deviceId); +inline WithDeviceIdMatcher WithDeviceId(int32_t deviceId) { + return WithDeviceIdMatcher(deviceId); +} + +/// Flags +class WithFlagsMatcher { +public: + using is_gtest_matcher = void; + explicit WithFlagsMatcher(int32_t flags) : mFlags(flags) {} + + bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const { + return mFlags == args.flags; + } + + bool MatchAndExplain(const NotifyKeyArgs& args, std::ostream*) const { + return mFlags == args.flags; + } + + bool MatchAndExplain(const MotionEvent& event, std::ostream*) const { + return mFlags == event.getFlags(); + } + + bool MatchAndExplain(const KeyEvent& event, std::ostream*) const { + return mFlags == event.getFlags(); + } + + void DescribeTo(std::ostream* os) const { + *os << "with flags " << base::StringPrintf("0x%x", mFlags); + } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong flags"; } + +private: + const int32_t mFlags; +}; + +inline WithFlagsMatcher WithFlags(int32_t flags) { + return WithFlagsMatcher(flags); +} + +/// DownTime +class WithDownTimeMatcher { +public: + using is_gtest_matcher = void; + explicit WithDownTimeMatcher(nsecs_t downTime) : mDownTime(downTime) {} + + bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const { + return mDownTime == args.downTime; + } + + bool MatchAndExplain(const NotifyKeyArgs& args, std::ostream*) const { + return mDownTime == args.downTime; + } + + bool MatchAndExplain(const MotionEvent& event, std::ostream*) const { + return mDownTime == event.getDownTime(); + } + + bool MatchAndExplain(const KeyEvent& event, std::ostream*) const { + return mDownTime == event.getDownTime(); + } + + void DescribeTo(std::ostream* os) const { *os << "with down time " << mDownTime; } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong down time"; } + +private: + const nsecs_t mDownTime; +}; + +inline WithDownTimeMatcher WithDownTime(nsecs_t downTime) { + return WithDownTimeMatcher(downTime); +} + +/// Coordinate matcher +class WithCoordsMatcher { +public: + using is_gtest_matcher = void; + explicit WithCoordsMatcher(size_t pointerIndex, float x, float y) + : mPointerIndex(pointerIndex), mX(x), mY(y) {} + + bool MatchAndExplain(const MotionEvent& event, std::ostream* os) const { + if (mPointerIndex >= event.getPointerCount()) { + *os << "Pointer index " << mPointerIndex << " is out of bounds"; + return false; + } + + bool matches = mX == event.getX(mPointerIndex) && mY == event.getY(mPointerIndex); + if (!matches) { + *os << "expected coords (" << mX << ", " << mY << ") at pointer index " << mPointerIndex + << ", but got (" << event.getX(mPointerIndex) << ", " << event.getY(mPointerIndex) + << ")"; + } + return matches; + } + + bool MatchAndExplain(const NotifyMotionArgs& event, std::ostream* os) const { + if (mPointerIndex >= event.pointerCoords.size()) { + *os << "Pointer index " << mPointerIndex << " is out of bounds"; + return false; + } + + bool matches = mX == event.pointerCoords[mPointerIndex].getX() && + mY == event.pointerCoords[mPointerIndex].getY(); + if (!matches) { + *os << "expected coords (" << mX << ", " << mY << ") at pointer index " << mPointerIndex + << ", but got (" << event.pointerCoords[mPointerIndex].getX() << ", " + << event.pointerCoords[mPointerIndex].getY() << ")"; + } + return matches; + } + + void DescribeTo(std::ostream* os) const { + *os << "with coords (" << mX << ", " << mY << ") at pointer index " << mPointerIndex; + } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong coords"; } + +private: + const size_t mPointerIndex; + const float mX; + const float mY; +}; + +inline WithCoordsMatcher WithCoords(float x, float y) { + return WithCoordsMatcher(0, x, y); +} + +inline WithCoordsMatcher WithPointerCoords(size_t pointerIndex, float x, float y) { + return WithCoordsMatcher(pointerIndex, x, y); +} + +/// Raw coordinate matcher +class WithRawCoordsMatcher { +public: + using is_gtest_matcher = void; + explicit WithRawCoordsMatcher(size_t pointerIndex, float rawX, float rawY) + : mPointerIndex(pointerIndex), mRawX(rawX), mRawY(rawY) {} + + bool MatchAndExplain(const MotionEvent& event, std::ostream* os) const { + if (mPointerIndex >= event.getPointerCount()) { + *os << "Pointer index " << mPointerIndex << " is out of bounds"; + return false; + } + + bool matches = + mRawX == event.getRawX(mPointerIndex) && mRawY == event.getRawY(mPointerIndex); + if (!matches) { + *os << "expected raw coords (" << mRawX << ", " << mRawY << ") at pointer index " + << mPointerIndex << ", but got (" << event.getRawX(mPointerIndex) << ", " + << event.getRawY(mPointerIndex) << ")"; + } + return matches; + } + + void DescribeTo(std::ostream* os) const { + *os << "with raw coords (" << mRawX << ", " << mRawY << ") at pointer index " + << mPointerIndex; + } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong raw coords"; } + +private: + const size_t mPointerIndex; + const float mRawX; + const float mRawY; +}; + +inline WithRawCoordsMatcher WithRawCoords(float rawX, float rawY) { + return WithRawCoordsMatcher(0, rawX, rawY); +} + +inline WithRawCoordsMatcher WithPointerRawCoords(size_t pointerIndex, float rawX, float rawY) { + return WithRawCoordsMatcher(pointerIndex, rawX, rawY); +} + +/// Pointer count +class WithPointerCountMatcher { +public: + using is_gtest_matcher = void; + explicit WithPointerCountMatcher(size_t pointerCount) : mPointerCount(pointerCount) {} + + bool MatchAndExplain(const MotionEvent& event, std::ostream* os) const { + if (event.getPointerCount() != mPointerCount) { + *os << "expected pointer count " << mPointerCount << ", but got " + << event.getPointerCount(); + return false; + } + return true; + } + + bool MatchAndExplain(const NotifyMotionArgs& event, std::ostream* os) const { + if (event.pointerCoords.size() != mPointerCount) { + *os << "expected pointer count " << mPointerCount << ", but got " + << event.pointerCoords.size(); + return false; + } + return true; + } + + void DescribeTo(std::ostream* os) const { *os << "with pointer count " << mPointerCount; } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong pointer count"; } + +private: + const size_t mPointerCount; +}; + +inline WithPointerCountMatcher WithPointerCount(size_t pointerCount) { + return WithPointerCountMatcher(pointerCount); +} + +/// Pointers matcher +class WithPointersMatcher { +public: + using is_gtest_matcher = void; + explicit WithPointersMatcher(std::map pointers) : mPointers(pointers) {} + + bool MatchAndExplain(const MotionEvent& event, std::ostream* os) const { + std::map actualPointers; + for (size_t pointerIndex = 0; pointerIndex < event.getPointerCount(); pointerIndex++) { + const int32_t pointerId = event.getPointerId(pointerIndex); + actualPointers[pointerId] = {event.getX(pointerIndex), event.getY(pointerIndex)}; + } + + if (mPointers != actualPointers) { + *os << "expected pointers " << dumpMap(mPointers, constToString, pointFToString) + << ", but got " << dumpMap(actualPointers, constToString, pointFToString); + return false; + } + return true; + } + + bool MatchAndExplain(const NotifyMotionArgs& event, std::ostream* os) const { + std::map actualPointers; + for (size_t pointerIndex = 0; pointerIndex < event.pointerCoords.size(); pointerIndex++) { + const int32_t pointerId = event.pointerProperties[pointerIndex].id; + actualPointers[pointerId] = {event.pointerCoords[pointerIndex].getX(), + event.pointerCoords[pointerIndex].getY()}; + } + + if (mPointers != actualPointers) { + *os << "expected pointers " << dumpMap(mPointers, constToString, pointFToString) + << ", but got " << dumpMap(actualPointers, constToString, pointFToString); + return false; + } + return true; + } + + void DescribeTo(std::ostream* os) const { + *os << "with pointers " << dumpMap(mPointers, constToString, pointFToString); + } + + void DescribeNegationTo(std::ostream* os) const { *os << "wrong pointers"; } + +private: + const std::map mPointers; +}; + +inline WithPointersMatcher WithPointers( + const std::map& pointers) { + return WithPointersMatcher(pointers); +} MATCHER_P(WithKeyCode, keyCode, "KeyEvent with specified key code") { *result_listener << "expected key code " << keyCode << ", but got " << arg.keyCode; @@ -166,25 +473,12 @@ MATCHER_P(WithRepeatCount, repeatCount, "KeyEvent with specified repeat count") return arg.getRepeatCount() == repeatCount; } -MATCHER_P(WithPointerCount, count, "MotionEvent with specified number of pointers") { - *result_listener << "expected " << count << " pointer(s), but got " << arg.getPointerCount(); - return arg.getPointerCount() == count; -} - MATCHER_P2(WithPointerId, index, id, "MotionEvent with specified pointer ID for pointer index") { const auto argPointerId = arg.pointerProperties[index].id; *result_listener << "expected pointer with index " << index << " to have ID " << argPointerId; return argPointerId == id; } -MATCHER_P2(WithCoords, x, y, "InputEvent with specified coords") { - const auto argX = arg.pointerCoords[0].getX(); - const auto argY = arg.pointerCoords[0].getY(); - *result_listener << "expected coords (" << x << ", " << y << "), but got (" << argX << ", " - << argY << ")"; - return argX == x && argY == y; -} - MATCHER_P2(WithCursorPosition, x, y, "InputEvent with specified cursor position") { const auto argX = arg.xCursorPosition; const auto argY = arg.yCursorPosition; @@ -193,14 +487,6 @@ MATCHER_P2(WithCursorPosition, x, y, "InputEvent with specified cursor position" return (isnan(x) ? isnan(argX) : x == argX) && (isnan(y) ? isnan(argY) : y == argY); } -MATCHER_P3(WithPointerCoords, pointer, x, y, "InputEvent with specified coords for pointer") { - const auto argX = arg.pointerCoords[pointer].getX(); - const auto argY = arg.pointerCoords[pointer].getY(); - *result_listener << "expected pointer " << pointer << " to have coords (" << x << ", " << y - << "), but got (" << argX << ", " << argY << ")"; - return argX == x && argY == y; -} - MATCHER_P2(WithRelativeMotion, x, y, "InputEvent with specified relative motion") { const auto argX = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); const auto argY = arg.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); @@ -288,11 +574,6 @@ MATCHER_P2(WithPointerToolType, pointer, toolType, return argToolType == toolType; } -MATCHER_P(WithFlags, flags, "InputEvent with specified flags") { - *result_listener << "expected flags " << flags << ", but got " << arg.flags; - return arg.flags == static_cast(flags); -} - MATCHER_P(WithMotionClassification, classification, "InputEvent with specified MotionClassification") { *result_listener << "expected classification " << motionClassificationToString(classification) -- GitLab From e3b28ddf7abf80b62066edc0675d2d5f11e51d56 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 6 Oct 2023 04:19:29 +0000 Subject: [PATCH 0757/1187] s/TestInputListenerMatchers.h/TestEventMatchers.h ...because it contains matchers for various event types, like NotifyMotionArgs and MotionEvent, not just for those assocated with InputListeners. Bug: 245989146 Test: atest inputflinger_tests Change-Id: Ibdd75ae6dd9aef90bdf8b3280d0bc0660c60fa31 --- .../inputflinger/tests/CapturedTouchpadEventConverter_test.cpp | 2 +- services/inputflinger/tests/CursorInputMapper_test.cpp | 2 +- services/inputflinger/tests/GestureConverter_test.cpp | 2 +- services/inputflinger/tests/InputDispatcher_test.cpp | 2 +- services/inputflinger/tests/InputReader_test.cpp | 2 +- .../tests/{TestInputListenerMatchers.h => TestEventMatchers.h} | 0 services/inputflinger/tests/TouchpadInputMapper_test.cpp | 2 +- services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp | 2 +- 8 files changed, 7 insertions(+), 7 deletions(-) rename services/inputflinger/tests/{TestInputListenerMatchers.h => TestEventMatchers.h} (100%) diff --git a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp index 99a6a1f5db..b738abf6d2 100644 --- a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp +++ b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp @@ -29,8 +29,8 @@ #include "FakeInputReaderPolicy.h" #include "InstrumentedInputReader.h" #include "TestConstants.h" +#include "TestEventMatchers.h" #include "TestInputListener.h" -#include "TestInputListenerMatchers.h" namespace android { diff --git a/services/inputflinger/tests/CursorInputMapper_test.cpp b/services/inputflinger/tests/CursorInputMapper_test.cpp index e630915116..b55c9cc937 100644 --- a/services/inputflinger/tests/CursorInputMapper_test.cpp +++ b/services/inputflinger/tests/CursorInputMapper_test.cpp @@ -22,7 +22,7 @@ #include "FakePointerController.h" #include "InputMapperTest.h" #include "InterfaceMocks.h" -#include "TestInputListenerMatchers.h" +#include "TestEventMatchers.h" #define TAG "CursorInputMapper_test" diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp index 74ce359cac..d7dc800c82 100644 --- a/services/inputflinger/tests/GestureConverter_test.cpp +++ b/services/inputflinger/tests/GestureConverter_test.cpp @@ -27,8 +27,8 @@ #include "InstrumentedInputReader.h" #include "NotifyArgs.h" #include "TestConstants.h" +#include "TestEventMatchers.h" #include "TestInputListener.h" -#include "TestInputListenerMatchers.h" #include "include/gestures.h" #include "ui/Rotation.h" diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 24c586cbc5..561a81b728 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -16,7 +16,7 @@ #include "../dispatcher/InputDispatcher.h" #include "../BlockingQueue.h" -#include "TestInputListenerMatchers.h" +#include "TestEventMatchers.h" #include #include diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 6032e3037a..64ae9e8b14 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -31,8 +31,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/services/inputflinger/tests/TestInputListenerMatchers.h b/services/inputflinger/tests/TestEventMatchers.h similarity index 100% rename from services/inputflinger/tests/TestInputListenerMatchers.h rename to services/inputflinger/tests/TestEventMatchers.h diff --git a/services/inputflinger/tests/TouchpadInputMapper_test.cpp b/services/inputflinger/tests/TouchpadInputMapper_test.cpp index 02abf9f0f0..6203a1d0b9 100644 --- a/services/inputflinger/tests/TouchpadInputMapper_test.cpp +++ b/services/inputflinger/tests/TouchpadInputMapper_test.cpp @@ -23,7 +23,7 @@ #include "FakePointerController.h" #include "InputMapperTest.h" #include "InterfaceMocks.h" -#include "TestInputListenerMatchers.h" +#include "TestEventMatchers.h" #define TAG "TouchpadInputMapper_test" diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp index 7cfcf718d9..78f7291243 100644 --- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp +++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp @@ -23,8 +23,8 @@ #include #include "ui/events/ozone/evdev/touch_filter/neural_stylus_palm_detection_filter.h" +#include "TestEventMatchers.h" #include "TestInputListener.h" -#include "TestInputListenerMatchers.h" using ::testing::AllOf; -- GitLab From 97649ae47084a1c76e0bdc8c35956741dfc3a985 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Wed, 31 May 2023 14:12:33 -0700 Subject: [PATCH 0758/1187] Add missing "override" annotations Test: Build with CMake. See aosp/2629369. Bug: 285204695 Change-Id: I5a0396d1fba458e11f42266e806634aaa1e9206d --- libs/binder/RpcTransportRaw.cpp | 5 +++-- libs/binder/RpcTransportTls.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp index f3575cc7d8..ddbcb573b1 100644 --- a/libs/binder/RpcTransportRaw.cpp +++ b/libs/binder/RpcTransportRaw.cpp @@ -79,7 +79,7 @@ public: altPoll); } - virtual bool isWaiting() { return mSocket.isInPollingState(); } + bool isWaiting() override { return mSocket.isInPollingState(); } private: android::RpcTransportFd mSocket; @@ -88,7 +88,8 @@ private: // RpcTransportCtx with TLS disabled. class RpcTransportCtxRaw : public RpcTransportCtx { public: - std::unique_ptr newTransport(android::RpcTransportFd socket, FdTrigger*) const { + std::unique_ptr newTransport(android::RpcTransportFd socket, + FdTrigger*) const override { return std::make_unique(std::move(socket)); } std::vector getCertificate(RpcCertificateFormat) const override { return {}; } diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp index 785f6ce2ce..efb09e9004 100644 --- a/libs/binder/RpcTransportTls.cpp +++ b/libs/binder/RpcTransportTls.cpp @@ -292,7 +292,7 @@ public: const std::optional>& altPoll, std::vector>* ancillaryFds) override; - bool isWaiting() { return mSocket.isInPollingState(); }; + bool isWaiting() override { return mSocket.isInPollingState(); }; private: android::RpcTransportFd mSocket; -- GitLab From d9e4f46cc957205d9a583f0dbccbcefeb66cf9bf Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 6 Oct 2023 04:05:45 +0000 Subject: [PATCH 0759/1187] Clean up duplicate shadow lengths in layer snapshot The shadow length is currently tracked in both the LayerFE CompositionState and the shadow settings, which are used by the RenderEngine. We can consolidate these fields and track shadow settings in the LayerFE CompositionState. This makes sense because we want the LayerFE CompositionState to contain all relevant information that it can pass to the RenderEngine without calling back into the frontend. Bug: 302551905 Test: presubmit Change-Id: I583c43993cf73784c6fec9ec2d40f2c76d21adeb --- .../include/renderengine/LayerSettings.h | 42 +----------- libs/renderengine/tests/RenderEngineTest.cpp | 55 +++++++--------- libs/ui/include/ui/ShadowSettings.h | 65 +++++++++++++++++++ .../LayerFECompositionState.h | 4 +- .../src/LayerFECompositionState.cpp | 2 +- .../CompositionEngine/src/Output.cpp | 4 +- .../CompositionEngine/src/OutputLayer.cpp | 4 +- .../tests/OutputLayerTest.cpp | 4 +- .../CompositionEngine/tests/OutputTest.cpp | 6 +- .../surfaceflinger/FrontEnd/LayerSnapshot.cpp | 1 - .../surfaceflinger/FrontEnd/LayerSnapshot.h | 1 - .../FrontEnd/LayerSnapshotBuilder.cpp | 12 ++-- .../FrontEnd/LayerSnapshotBuilder.h | 4 +- services/surfaceflinger/Layer.cpp | 2 +- services/surfaceflinger/LayerFE.cpp | 2 +- services/surfaceflinger/LayerProtoHelper.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.h | 2 +- .../Tracing/tools/LayerTraceGenerator.cpp | 2 +- .../tests/unittests/LayerHierarchyTest.h | 3 +- .../tests/unittests/LayerSnapshotTest.cpp | 1 - 20 files changed, 117 insertions(+), 101 deletions(-) create mode 100644 libs/ui/include/ui/ShadowSettings.h diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index 28aa4dd71d..8ac0af47c6 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -97,36 +98,6 @@ struct PixelSource { half3 solidColor = half3(0.0f, 0.0f, 0.0f); }; -/* - * Contains the configuration for the shadows drawn by single layer. Shadow follows - * material design guidelines. - */ -struct ShadowSettings { - // Boundaries of the shadow. - FloatRect boundaries = FloatRect(); - - // Color to the ambient shadow. The alpha is premultiplied. - vec4 ambientColor = vec4(); - - // Color to the spot shadow. The alpha is premultiplied. The position of the spot shadow - // depends on the light position. - vec4 spotColor = vec4(); - - // Position of the light source used to cast the spot shadow. - vec3 lightPos = vec3(); - - // Radius of the spot light source. Smaller radius will have sharper edges, - // larger radius will have softer shadows - float lightRadius = 0.f; - - // Length of the cast shadow. If length is <= 0.f no shadows will be drawn. - float length = 0.f; - - // If true fill in the casting layer is translucent and the shadow needs to fill the bounds. - // Otherwise the shadow will only be drawn around the edges of the casting layer. - bool casterIsTranslucent = false; -}; - // The settings that RenderEngine requires for correctly rendering a Layer. struct LayerSettings { // Geometry information @@ -194,17 +165,6 @@ static inline bool operator==(const PixelSource& lhs, const PixelSource& rhs) { return lhs.buffer == rhs.buffer && lhs.solidColor == rhs.solidColor; } -static inline bool operator==(const ShadowSettings& lhs, const ShadowSettings& rhs) { - return lhs.boundaries == rhs.boundaries && lhs.ambientColor == rhs.ambientColor && - lhs.spotColor == rhs.spotColor && lhs.lightPos == rhs.lightPos && - lhs.lightRadius == rhs.lightRadius && lhs.length == rhs.length && - lhs.casterIsTranslucent == rhs.casterIsTranslucent; -} - -static inline bool operator!=(const ShadowSettings& lhs, const ShadowSettings& rhs) { - return !(operator==(lhs, rhs)); -} - static inline bool operator==(const LayerSettings& lhs, const LayerSettings& rhs) { if (lhs.blurRegions.size() != rhs.blurRegions.size()) { return false; diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 7dde71632b..6023808aaf 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -403,7 +403,7 @@ public: } void expectShadowColor(const renderengine::LayerSettings& castingLayer, - const renderengine::ShadowSettings& shadow, const ubyte4& casterColor, + const ShadowSettings& shadow, const ubyte4& casterColor, const ubyte4& backgroundColor) { const Rect casterRect(castingLayer.geometry.boundaries); Region casterRegion = Region(casterRect); @@ -443,8 +443,7 @@ public: backgroundColor.a); } - void expectShadowColorWithoutCaster(const FloatRect& casterBounds, - const renderengine::ShadowSettings& shadow, + void expectShadowColorWithoutCaster(const FloatRect& casterBounds, const ShadowSettings& shadow, const ubyte4& backgroundColor) { const float shadowInset = shadow.length * -1.0f; const Rect casterRect(casterBounds); @@ -463,9 +462,9 @@ public: backgroundColor.a); } - static renderengine::ShadowSettings getShadowSettings(const vec2& casterPos, float shadowLength, - bool casterIsTranslucent) { - renderengine::ShadowSettings shadow; + static ShadowSettings getShadowSettings(const vec2& casterPos, float shadowLength, + bool casterIsTranslucent) { + ShadowSettings shadow; shadow.ambientColor = {0.0f, 0.0f, 0.0f, 0.039f}; shadow.spotColor = {0.0f, 0.0f, 0.0f, 0.19f}; shadow.lightPos = vec3(casterPos.x, casterPos.y, 0); @@ -602,12 +601,10 @@ public: void fillGreenColorBufferThenClearRegion(); template - void drawShadow(const renderengine::LayerSettings& castingLayer, - const renderengine::ShadowSettings& shadow, const ubyte4& casterColor, - const ubyte4& backgroundColor); + void drawShadow(const renderengine::LayerSettings& castingLayer, const ShadowSettings& shadow, + const ubyte4& casterColor, const ubyte4& backgroundColor); - void drawShadowWithoutCaster(const FloatRect& castingBounds, - const renderengine::ShadowSettings& shadow, + void drawShadowWithoutCaster(const FloatRect& castingBounds, const ShadowSettings& shadow, const ubyte4& backgroundColor); // Tonemaps grey values from sourceDataspace -> Display P3 and checks that GPU and CPU @@ -1337,8 +1334,8 @@ void RenderEngineTest::fillBufferWithoutPremultiplyAlpha() { template void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLayer, - const renderengine::ShadowSettings& shadow, - const ubyte4& casterColor, const ubyte4& backgroundColor) { + const ShadowSettings& shadow, const ubyte4& casterColor, + const ubyte4& backgroundColor) { renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; settings.physicalDisplay = fullscreenRect(); @@ -1374,7 +1371,7 @@ void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLaye } void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds, - const renderengine::ShadowSettings& shadow, + const ShadowSettings& shadow, const ubyte4& backgroundColor) { renderengine::DisplaySettings settings; settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; @@ -2103,9 +2100,8 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) { const float shadowLength = 5.0f; Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f); casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); - renderengine::ShadowSettings settings = - getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength, - false /* casterIsTranslucent */); + ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top), + shadowLength, false /* casterIsTranslucent */); drawShadowWithoutCaster(casterBounds.toFloatRect(), settings, backgroundColor); expectShadowColorWithoutCaster(casterBounds.toFloatRect(), settings, backgroundColor); @@ -2127,9 +2123,8 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterLayerMinSize) { renderengine::LayerSettings castingLayer; castingLayer.geometry.boundaries = casterBounds.toFloatRect(); castingLayer.alpha = 1.0f; - renderengine::ShadowSettings settings = - getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength, - false /* casterIsTranslucent */); + ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top), + shadowLength, false /* casterIsTranslucent */); drawShadow(castingLayer, settings, casterColor, backgroundColor); expectShadowColor(castingLayer, settings, casterColor, backgroundColor); @@ -2152,9 +2147,8 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterColorLayer) { castingLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; castingLayer.geometry.boundaries = casterBounds.toFloatRect(); castingLayer.alpha = 1.0f; - renderengine::ShadowSettings settings = - getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength, - false /* casterIsTranslucent */); + ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top), + shadowLength, false /* casterIsTranslucent */); drawShadow(castingLayer, settings, casterColor, backgroundColor); expectShadowColor(castingLayer, settings, casterColor, backgroundColor); @@ -2177,9 +2171,8 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterOpaqueBufferLayer) { castingLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; castingLayer.geometry.boundaries = casterBounds.toFloatRect(); castingLayer.alpha = 1.0f; - renderengine::ShadowSettings settings = - getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength, - false /* casterIsTranslucent */); + ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top), + shadowLength, false /* casterIsTranslucent */); drawShadow>(castingLayer, settings, casterColor, backgroundColor); @@ -2204,9 +2197,8 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterWithRoundedCorner) { castingLayer.geometry.roundedCornersRadius = {3.0f, 3.0f}; castingLayer.geometry.roundedCornersCrop = casterBounds.toFloatRect(); castingLayer.alpha = 1.0f; - renderengine::ShadowSettings settings = - getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength, - false /* casterIsTranslucent */); + ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top), + shadowLength, false /* casterIsTranslucent */); drawShadow>(castingLayer, settings, casterColor, backgroundColor); @@ -2227,9 +2219,8 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_translucentCasterWithAlpha) { renderengine::LayerSettings castingLayer; castingLayer.geometry.boundaries = casterBounds.toFloatRect(); castingLayer.alpha = 0.5f; - renderengine::ShadowSettings settings = - getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength, - true /* casterIsTranslucent */); + ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top), + shadowLength, true /* casterIsTranslucent */); drawShadow>(castingLayer, settings, casterColor, backgroundColor); diff --git a/libs/ui/include/ui/ShadowSettings.h b/libs/ui/include/ui/ShadowSettings.h new file mode 100644 index 0000000000..c0b83b8691 --- /dev/null +++ b/libs/ui/include/ui/ShadowSettings.h @@ -0,0 +1,65 @@ +/* + * Copyright 2023 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 +#include "FloatRect.h" + +namespace android { + +/* + * Contains the configuration for the shadows drawn by single layer. Shadow follows + * material design guidelines. + */ +struct ShadowSettings { + // Boundaries of the shadow. + FloatRect boundaries = FloatRect(); + + // Color to the ambient shadow. The alpha is premultiplied. + vec4 ambientColor = vec4(); + + // Color to the spot shadow. The alpha is premultiplied. The position of the spot shadow + // depends on the light position. + vec4 spotColor = vec4(); + + // Position of the light source used to cast the spot shadow. + vec3 lightPos = vec3(); + + // Radius of the spot light source. Smaller radius will have sharper edges, + // larger radius will have softer shadows + float lightRadius = 0.f; + + // Length of the cast shadow. If length is <= 0.f no shadows will be drawn. + float length = 0.f; + + // If true fill in the casting layer is translucent and the shadow needs to fill the bounds. + // Otherwise the shadow will only be drawn around the edges of the casting layer. + bool casterIsTranslucent = false; +}; + +static inline bool operator==(const ShadowSettings& lhs, const ShadowSettings& rhs) { + return lhs.boundaries == rhs.boundaries && lhs.ambientColor == rhs.ambientColor && + lhs.spotColor == rhs.spotColor && lhs.lightPos == rhs.lightPos && + lhs.lightRadius == rhs.lightRadius && lhs.length == rhs.length && + lhs.casterIsTranslucent == rhs.casterIsTranslucent; +} + +static inline bool operator!=(const ShadowSettings& lhs, const ShadowSettings& rhs) { + return !(operator==(lhs, rhs)); +} + +} // namespace android \ No newline at end of file diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 35ca3a58d9..11759b855f 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -26,6 +26,7 @@ #include #include #include +#include #include // TODO(b/129481165): remove the #pragma below and fix conversion issues @@ -132,8 +133,7 @@ struct LayerFECompositionState { // The bounds of the layer in layer local coordinates FloatRect geomLayerBounds; - // length of the shadow in screen space - float shadowRadius{0.f}; + ShadowSettings shadowSettings; // List of regions that require blur std::vector blurRegions; diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp index 426cc57db8..2d10866db3 100644 --- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp @@ -68,7 +68,7 @@ void LayerFECompositionState::dump(std::string& out) const { dumpVal(out, "geomLayerBounds", geomLayerBounds); out.append(" "); - dumpVal(out, "shadowRadius", shadowRadius); + dumpVal(out, "shadowLength", shadowSettings.length); out.append("\n "); dumpVal(out, "blend", toString(blendMode), blendMode); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 775e6d5094..fa3733b540 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -588,10 +588,10 @@ void Output::ensureOutputLayerIfVisible(sp& layerFE, const Rect visibleRect(tr.transform(layerFEState->geomLayerBounds)); visibleRegion.set(visibleRect); - if (layerFEState->shadowRadius > 0.0f) { + if (layerFEState->shadowSettings.length > 0.0f) { // if the layer casts a shadow, offset the layers visible region and // calculate the shadow region. - const auto inset = static_cast(ceilf(layerFEState->shadowRadius) * -1.0f); + const auto inset = static_cast(ceilf(layerFEState->shadowSettings.length) * -1.0f); Rect visibleRectWithShadows(visibleRect); visibleRectWithShadows.inset(inset, inset, inset, inset); visibleRegion.set(visibleRectWithShadows); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index fe56969884..7fe3369f88 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -222,8 +222,8 @@ Rect OutputLayer::calculateOutputDisplayFrame() const { // Some HWCs may clip client composited input to its displayFrame. Make sure // that this does not cut off the shadow. - if (layerState.forceClientComposition && layerState.shadowRadius > 0.0f) { - const auto outset = layerState.shadowRadius; + if (layerState.forceClientComposition && layerState.shadowSettings.length > 0.0f) { + const auto outset = layerState.shadowSettings.length; geomLayerBounds.left -= outset; geomLayerBounds.top -= outset; geomLayerBounds.right += outset; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 630906a5b7..1c54469cc0 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -334,7 +334,7 @@ TEST_F(OutputLayerDisplayFrameTest, outputTransformAffectsDisplayFrame) { TEST_F(OutputLayerDisplayFrameTest, shadowExpandsDisplayFrame) { const int kShadowRadius = 5; - mLayerFEState.shadowRadius = kShadowRadius; + mLayerFEState.shadowSettings.length = kShadowRadius; mLayerFEState.forceClientComposition = true; mLayerFEState.geomLayerBounds = FloatRect{100.f, 100.f, 200.f, 200.f}; @@ -345,7 +345,7 @@ TEST_F(OutputLayerDisplayFrameTest, shadowExpandsDisplayFrame) { TEST_F(OutputLayerDisplayFrameTest, shadowExpandsDisplayFrame_onlyIfForcingClientComposition) { const int kShadowRadius = 5; - mLayerFEState.shadowRadius = kShadowRadius; + mLayerFEState.shadowSettings.length = kShadowRadius; mLayerFEState.forceClientComposition = false; mLayerFEState.geomLayerBounds = FloatRect{100.f, 100.f, 200.f, 200.f}; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index ee6998aef8..cdcb68d9fc 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -1830,7 +1830,7 @@ TEST_F(OutputEnsureOutputLayerIfVisibleTest, coverageAccumulatesWithShadowsTest) ui::Transform translate; translate.set(50, 50); mLayer.layerFEState.geomLayerTransform = translate; - mLayer.layerFEState.shadowRadius = 10.0f; + mLayer.layerFEState.shadowSettings.length = 10.0f; mCoverageState.dirtyRegion = Region(Rect(0, 0, 500, 500)); // half of the layer including the casting shadow is covered and opaque @@ -1872,7 +1872,7 @@ TEST_F(OutputEnsureOutputLayerIfVisibleTest, shadowRegionOnlyTest) { ui::Transform translate; translate.set(50, 50); mLayer.layerFEState.geomLayerTransform = translate; - mLayer.layerFEState.shadowRadius = 10.0f; + mLayer.layerFEState.shadowSettings.length = 10.0f; mCoverageState.dirtyRegion = Region(Rect(0, 0, 500, 500)); // Casting layer is covered by an opaque region leaving only part of its shadow to be drawn @@ -1897,7 +1897,7 @@ TEST_F(OutputEnsureOutputLayerIfVisibleTest, takesNotSoEarlyOutifLayerWithShadow ui::Transform translate; translate.set(50, 50); mLayer.layerFEState.geomLayerTransform = translate; - mLayer.layerFEState.shadowRadius = 10.0f; + mLayer.layerFEState.shadowSettings.length = 10.0f; mCoverageState.dirtyRegion = Region(Rect(0, 0, 500, 500)); // Casting layer and its shadows are covered by an opaque region diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index f9c8e812dd..7a85da056e 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -382,7 +382,6 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate sidebandStream = requested.sidebandStream; } if (forceUpdate || requested.what & layer_state_t::eShadowRadiusChanged) { - shadowRadius = requested.shadowRadius; shadowSettings.length = requested.shadowRadius; } if (forceUpdate || requested.what & layer_state_t::eFrameRateSelectionPriority) { diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index a1c72a94e0..80a51ea94c 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -69,7 +69,6 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { RoundedCornerState roundedCorner; FloatRect transformedBounds; Rect transformedBoundsWithoutTransparentRegion; - renderengine::ShadowSettings shadowSettings; bool premultipliedAlpha; ui::Transform parentTransform; Rect bufferSize; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index a1796e1eb0..03c09932d3 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -353,7 +353,7 @@ LayerSnapshot LayerSnapshotBuilder::getRootSnapshot() { snapshot.isSecure = false; snapshot.color.a = 1.0_hf; snapshot.colorTransformIsIdentity = true; - snapshot.shadowRadius = 0.f; + snapshot.shadowSettings.length = 0.f; snapshot.layerMetadata.mMap.clear(); snapshot.relativeLayerMetadata.mMap.clear(); snapshot.inputInfo.touchOcclusionMode = gui::TouchOcclusionMode::BLOCK_UNTRUSTED; @@ -990,9 +990,12 @@ void LayerSnapshotBuilder::updateLayerBounds(LayerSnapshot& snapshot, } void LayerSnapshotBuilder::updateShadows(LayerSnapshot& snapshot, const RequestedLayerState&, - const renderengine::ShadowSettings& globalShadowSettings) { - if (snapshot.shadowRadius > 0.f) { - snapshot.shadowSettings = globalShadowSettings; + const ShadowSettings& globalShadowSettings) { + if (snapshot.shadowSettings.length > 0.f) { + snapshot.shadowSettings.ambientColor = globalShadowSettings.ambientColor; + snapshot.shadowSettings.spotColor = globalShadowSettings.spotColor; + snapshot.shadowSettings.lightPos = globalShadowSettings.lightPos; + snapshot.shadowSettings.lightRadius = globalShadowSettings.lightRadius; // Note: this preserves existing behavior of shadowing the entire layer and not cropping // it if transparent regions are present. This may not be necessary since shadows are @@ -1006,7 +1009,6 @@ void LayerSnapshotBuilder::updateShadows(LayerSnapshot& snapshot, const Requeste snapshot.shadowSettings.ambientColor *= snapshot.alpha; snapshot.shadowSettings.spotColor *= snapshot.alpha; } - snapshot.shadowSettings.length = snapshot.shadowRadius; } void LayerSnapshotBuilder::updateInput(LayerSnapshot& snapshot, diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h index 3d64b362ea..1506913e15 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h @@ -47,7 +47,7 @@ public: const DisplayInfos& displays; // Set to true if there were display changes since last update. bool displayChanges = false; - const renderengine::ShadowSettings& globalShadowSettings; + const ShadowSettings& globalShadowSettings; bool supportsBlur = true; bool forceFullDamage = false; std::optional parentCrop = std::nullopt; @@ -108,7 +108,7 @@ private: void updateLayerBounds(LayerSnapshot& snapshot, const RequestedLayerState& layerState, const LayerSnapshot& parentSnapshot, uint32_t displayRotationFlags); static void updateShadows(LayerSnapshot& snapshot, const RequestedLayerState& requested, - const renderengine::ShadowSettings& globalShadowSettings); + const ShadowSettings& globalShadowSettings); void updateInput(LayerSnapshot& snapshot, const RequestedLayerState& requested, const LayerSnapshot& parentSnapshot, const LayerHierarchy::TraversalPath& path, const Args& args); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 33d1eeb7cc..2dc8758c3d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -572,7 +572,7 @@ void Layer::prepareBasicGeometryCompositionState() { snapshot->outputFilter = getOutputFilter(); snapshot->isVisible = isVisible(); snapshot->isOpaque = opaque && !usesRoundedCorners && alpha == 1.f; - snapshot->shadowRadius = mEffectiveShadowRadius; + snapshot->shadowSettings.length = mEffectiveShadowRadius; snapshot->contentDirty = contentDirty; contentDirty = false; diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index 97c4145dd1..48a9190794 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -310,7 +310,7 @@ void LayerFE::prepareBufferStateClientComposition( void LayerFE::prepareShadowClientComposition(LayerFE::LayerSettings& caster, const Rect& layerStackRect) const { - renderengine::ShadowSettings state = mSnapshot->shadowSettings; + ShadowSettings state = mSnapshot->shadowSettings; if (state.length <= 0.f || (state.ambientColor.a <= 0.f && state.spotColor.a <= 0.f)) { return; } diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index 144e1f5abf..aa6026ef79 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -402,7 +402,7 @@ void LayerProtoHelper::writeSnapshotToProto(perfetto::protos::LayerProto* layerI [&]() { return layerInfo->mutable_screen_bounds(); }); LayerProtoHelper::writeToProto(snapshot.roundedCorner.cropRect, [&]() { return layerInfo->mutable_corner_radius_crop(); }); - layerInfo->set_shadow_radius(snapshot.shadowRadius); + layerInfo->set_shadow_radius(snapshot.shadowSettings.length); layerInfo->set_id(snapshot.uniqueSequence); layerInfo->set_original_id(snapshot.sequence); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 7b2d5908e6..cbea31239a 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -419,7 +419,7 @@ private: bool colorMatrixChanged = true; mat4 colorMatrix; - renderengine::ShadowSettings globalShadowSettings; + ShadowSettings globalShadowSettings; void traverse(const LayerVector::Visitor& visitor) const; void traverseInZOrder(const LayerVector::Visitor& visitor) const; diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp index 23fe8fa886..c2d1954ee5 100644 --- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp +++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp @@ -56,7 +56,7 @@ bool LayerTraceGenerator::generate(const perfetto::protos::TransactionTraceFile& frontend::LayerSnapshotBuilder snapshotBuilder; ui::DisplayMap displayInfos; - renderengine::ShadowSettings globalShadowSettings{.ambientColor = {1, 1, 1, 1}}; + ShadowSettings globalShadowSettings{.ambientColor = {1, 1, 1, 1}}; char value[PROPERTY_VALUE_MAX]; property_get("ro.surface_flinger.supports_background_blur", value, "0"); bool supportsBlur = atoi(value); diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index c47b0fc93c..d319dcc47e 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -19,6 +19,7 @@ #include #include +#include #include "Client.h" // temporarily needed for LayerCreationArgs #include "FrontEnd/LayerCreationArgs.h" @@ -488,7 +489,7 @@ protected: DisplayInfos mFrontEndDisplayInfos; bool mHasDisplayChanges = false; - renderengine::ShadowSettings globalShadowSettings; + ShadowSettings globalShadowSettings; }; } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 956c0ebca2..50dfcaac5f 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -859,7 +859,6 @@ TEST_F(LayerSnapshotTest, setShadowRadius) { setShadowRadius(1, SHADOW_RADIUS); UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); EXPECT_EQ(getSnapshot(1)->shadowSettings.length, SHADOW_RADIUS); - EXPECT_EQ(getSnapshot(1)->shadowRadius, SHADOW_RADIUS); } } // namespace android::surfaceflinger::frontend -- GitLab From 4c4ac06367116c8ce6eaf30d6d4402aee2c4df59 Mon Sep 17 00:00:00 2001 From: Jing Ji Date: Sat, 7 Oct 2023 15:20:23 -0700 Subject: [PATCH 0760/1187] Move the binder proxy accounting to libbinder So the android.os.Debug#getBinderProxyObjectCount will include the binder proxies from both of the Java and native layers. Bug: 298314844 Test: dumpsys meminfo Merged-In: I822fbbfd47bf1929f587a5147f124d99e7ba1059 Change-Id: I444392f59785c3b40b1b7b052ca6c10ec9a36bef --- libs/binder/BpBinder.cpp | 23 +++++++++++++++++++++++ libs/binder/include/binder/BpBinder.h | 3 +++ 2 files changed, 26 insertions(+) diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 589df9aceb..ef0ae4f654 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -54,6 +54,11 @@ uint32_t BpBinder::sBinderProxyCountHighWatermark = 2500; // Another arbitrary value a binder count needs to drop below before another callback will be called uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000; +std::atomic BpBinder::sBinderProxyCount(0); +std::atomic BpBinder::sBinderProxyCountWarned(0); + +static constexpr uint32_t kBinderProxyCountWarnInterval = 5000; + // Log any transactions for which the data exceeds this size #define LOG_TRANSACTIONS_OVER_SIZE (300 * 1024) @@ -193,6 +198,18 @@ sp BpBinder::create(int32_t handle) { } sTrackingMap[trackedUid]++; } + uint32_t numProxies = sBinderProxyCount.fetch_add(1, std::memory_order_relaxed); + uint32_t numLastWarned = sBinderProxyCountWarned.load(std::memory_order_relaxed); + uint32_t numNextWarn = numLastWarned + kBinderProxyCountWarnInterval; + if (numProxies >= numNextWarn) { + // Multiple threads can get here, make sure only one of them gets to + // update the warn counter. + if (sBinderProxyCountWarned.compare_exchange_strong(numLastWarned, + numNextWarn, + std::memory_order_relaxed)) { + ALOGW("Unexpectedly many live BinderProxies: %d\n", numProxies); + } + } return sp::make(BinderHandle{handle}, trackedUid); } @@ -604,6 +621,7 @@ BpBinder::~BpBinder() { } } } + --sBinderProxyCount; if (ipc) { ipc->expungeHandle(binderHandle(), this); @@ -688,6 +706,11 @@ uint32_t BpBinder::getBinderProxyCount(uint32_t uid) return 0; } +uint32_t BpBinder::getBinderProxyCount() +{ + return sBinderProxyCount.load(); +} + void BpBinder::getCountByUid(Vector& uids, Vector& counts) { AutoMutex _l(sTrackingLock); diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index fc8089d069..28fb9f1bbc 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -88,6 +88,7 @@ public: static void setCountByUidEnabled(bool enable); static void setLimitCallback(binder_proxy_limit_callback cb); static void setBinderProxyCountWatermarks(int high, int low); + static uint32_t getBinderProxyCount(); std::optional getDebugBinderHandle() const; @@ -209,6 +210,8 @@ private: static uint32_t sBinderProxyCountLowWatermark; static bool sBinderProxyThrottleCreate; static std::unordered_map sLastLimitCallbackMap; + static std::atomic sBinderProxyCount; + static std::atomic sBinderProxyCountWarned; }; } // namespace android -- GitLab From bbe9ae6e4be7ce599695457d0a83cf31e3ca3815 Mon Sep 17 00:00:00 2001 From: Jing Ji Date: Sat, 7 Oct 2023 15:26:02 -0700 Subject: [PATCH 0761/1187] Add test to the BpBinder::getBinderProxyCount Bug: 298314844 Test: atest BinderLibTest#BinderProxyCount Merged-In: I97bbb5b7560f36294718ce22015079bc4f96ba22 Change-Id: I97bbb5b7560f36294718ce22015079bc4f96ba22 --- libs/binder/tests/binderLibTest.cpp | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index e021af0264..0396869167 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -1441,6 +1441,36 @@ TEST_F(BinderLibTest, HangingServices) { EXPECT_GE(epochMsAfter, epochMsBefore + delay); } +TEST_F(BinderLibTest, BinderProxyCount) { + Parcel data, reply; + sp server = addServer(); + ASSERT_NE(server, nullptr); + + uint32_t initialCount = BpBinder::getBinderProxyCount(); + size_t iterations = 100; + { + uint32_t count = initialCount; + std::vector > proxies; + sp proxy; + // Create binder proxies and verify the count. + for (size_t i = 0; i < iterations; i++) { + ASSERT_THAT(server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, data, &reply), + StatusEq(NO_ERROR)); + proxies.push_back(reply.readStrongBinder()); + EXPECT_EQ(BpBinder::getBinderProxyCount(), ++count); + } + // Remove every other one and verify the count. + auto it = proxies.begin(); + for (size_t i = 0; it != proxies.end(); i++) { + if (i % 2 == 0) { + it = proxies.erase(it); + EXPECT_EQ(BpBinder::getBinderProxyCount(), --count); + } + } + } + EXPECT_EQ(BpBinder::getBinderProxyCount(), initialCount); +} + class BinderLibRpcTestBase : public BinderLibTest { public: void SetUp() override { -- GitLab From fece5442e8ad08e076be5bd0284a964901cb3713 Mon Sep 17 00:00:00 2001 From: Lais Andrade Date: Mon, 9 Oct 2023 11:55:14 +0000 Subject: [PATCH 0762/1187] Update haptics framework owners file Bug: 304194677 Change-Id: I061fdb3ab6ac2c561242a7bb971c931bd396d4f1 Test: N/A --- libs/vibrator/OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/vibrator/OWNERS b/libs/vibrator/OWNERS index d073e2bd46..c4de58a517 100644 --- a/libs/vibrator/OWNERS +++ b/libs/vibrator/OWNERS @@ -1 +1,2 @@ +# Bug component: 345036 include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS -- GitLab From b48b9fc4693bb5286a84eeefa61641a90a4b57da Mon Sep 17 00:00:00 2001 From: Devin Moore Date: Fri, 6 Oct 2023 23:16:48 +0000 Subject: [PATCH 0763/1187] Allow servicedispatcher to use an ip address Allow it to set up inet servers on different IP addresses. Test: $ adb shell servicedispatcher -i 192.168.1.246 \ android.hardware.vibrator.IVibrator/default Bug: 293615467 Change-Id: I6684c96409425cb1ba397f6a76eafbbff9ae425b --- libs/binder/servicedispatcher.cpp | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp index 692cc95e3b..8e95d69ffc 100644 --- a/libs/binder/servicedispatcher.cpp +++ b/libs/binder/servicedispatcher.cpp @@ -59,12 +59,13 @@ int Usage(const char* program) { auto basename = Basename(program); auto format = R"(dispatch calls to RPC service. Usage: - %s [-g] + %s [-g] [-i ] : the service to connect to. %s [-g] manager Runs an RPC-friendly service that redirects calls to servicemanager. -g: use getService() instead of checkService(). + -i: use ip_address when setting up the server instead of '127.0.0.1' If successful, writes port number and a new line character to stdout, and blocks until killed. @@ -74,7 +75,8 @@ Usage: return EX_USAGE; } -int Dispatch(const char* name, const ServiceRetriever& serviceRetriever) { +int Dispatch(const char* name, const ServiceRetriever& serviceRetriever, + const char* ip_address = kLocalInetAddress) { auto sm = defaultServiceManager(); if (nullptr == sm) { LOG(ERROR) << "No servicemanager"; @@ -91,7 +93,7 @@ int Dispatch(const char* name, const ServiceRetriever& serviceRetriever) { return EX_SOFTWARE; } unsigned int port; - if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) { + if (status_t status = rpcServer->setupInetServer(ip_address, 0, &port); status != OK) { LOG(ERROR) << "setupInetServer failed: " << statusToString(status); return EX_SOFTWARE; } @@ -188,7 +190,8 @@ private: // Workaround for b/191059588. // TODO(b/191059588): Once we can run RpcServer on single-threaded services, // `servicedispatcher manager` should call Dispatch("manager") directly. -int wrapServiceManager(const ServiceRetriever& serviceRetriever) { +int wrapServiceManager(const ServiceRetriever& serviceRetriever, + const char* ip_address = kLocalInetAddress) { auto sm = defaultServiceManager(); if (nullptr == sm) { LOG(ERROR) << "No servicemanager"; @@ -212,7 +215,7 @@ int wrapServiceManager(const ServiceRetriever& serviceRetriever) { auto rpcServer = RpcServer::make(); rpcServer->setRootObject(service); unsigned int port; - if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) { + if (status_t status = rpcServer->setupInetServer(ip_address, 0, &port); status != OK) { LOG(ERROR) << "Unable to set up inet server: " << statusToString(status); return EX_SOFTWARE; } @@ -272,11 +275,15 @@ int main(int argc, char* argv[]) { int opt; ServiceRetriever serviceRetriever = &android::IServiceManager::checkService; - while (-1 != (opt = getopt(argc, argv, "g"))) { + char* ip_address = nullptr; + while (-1 != (opt = getopt(argc, argv, "gi:"))) { switch (opt) { case 'g': { serviceRetriever = &android::IServiceManager::getService; } break; + case 'i': { + ip_address = optarg; + } break; default: { return Usage(argv[0]); } @@ -291,7 +298,15 @@ int main(int argc, char* argv[]) { auto name = argv[optind]; if (name == "manager"sv) { - return wrapServiceManager(serviceRetriever); + if (ip_address) { + return wrapServiceManager(serviceRetriever, ip_address); + } else { + return wrapServiceManager(serviceRetriever); + } + } + if (ip_address) { + return Dispatch(name, serviceRetriever, ip_address); + } else { + return Dispatch(name, serviceRetriever); } - return Dispatch(name, serviceRetriever); } -- GitLab From 0ae29275b930a82d9df33b15294762243f7a966a Mon Sep 17 00:00:00 2001 From: Serdar Kocdemir Date: Mon, 9 Oct 2023 14:33:59 +0100 Subject: [PATCH 0764/1187] Implement array version of GPU stat update calls Adding SET_TARGET_STATS_ARRAY GPU Service tag to reduce the number of binder calls required when setting Vulkan extension usage stats. Bug: b/289491729 Test: adb shell dumpsys gpu Test: atest GpuStatsTest Change-Id: I5bb219e3600c2711a57194ae4518c9f19f7b5ad3 --- libs/graphicsenv/IGpuService.cpp | 39 +++++++++++++++++-- .../include/graphicsenv/IGpuService.h | 1 + 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp index 1c0439ec1e..5dc195c438 100644 --- a/libs/graphicsenv/IGpuService.cpp +++ b/libs/graphicsenv/IGpuService.cpp @@ -64,9 +64,17 @@ public: void setTargetStatsArray(const std::string& appPackageName, const uint64_t driverVersionCode, const GpuStatsInfo::Stats stats, const uint64_t* values, const uint32_t valueCount) override { - for (uint32_t i = 0; i < valueCount; i++) { - setTargetStats(appPackageName, driverVersionCode, stats, values[i]); - } + Parcel data, reply; + data.writeInterfaceToken(IGpuService::getInterfaceDescriptor()); + + data.writeUtf8AsUtf16(appPackageName); + data.writeUint64(driverVersionCode); + data.writeInt32(static_cast(stats)); + data.writeUint32(valueCount); + data.write(values, valueCount * sizeof(uint64_t)); + + remote()->transact(BnGpuService::SET_TARGET_STATS_ARRAY, data, &reply, + IBinder::FLAG_ONEWAY); } void setUpdatableDriverPath(const std::string& driverPath) override { @@ -164,6 +172,31 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* rep return OK; } + case SET_TARGET_STATS_ARRAY: { + CHECK_INTERFACE(IGpuService, data, reply); + + std::string appPackageName; + if ((status = data.readUtf8FromUtf16(&appPackageName)) != OK) return status; + + uint64_t driverVersionCode; + if ((status = data.readUint64(&driverVersionCode)) != OK) return status; + + int32_t stats; + if ((status = data.readInt32(&stats)) != OK) return status; + + uint32_t valueCount; + if ((status = data.readUint32(&valueCount)) != OK) return status; + + std::vector values(valueCount); + if ((status = data.read(values.data(), valueCount * sizeof(uint64_t))) != OK) { + return status; + } + + setTargetStatsArray(appPackageName, driverVersionCode, + static_cast(stats), values.data(), valueCount); + + return OK; + } case SET_UPDATABLE_DRIVER_PATH: { CHECK_INTERFACE(IGpuService, data, reply); diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h index e3857d2ec0..45f05d6555 100644 --- a/libs/graphicsenv/include/graphicsenv/IGpuService.h +++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h @@ -63,6 +63,7 @@ public: SET_UPDATABLE_DRIVER_PATH, GET_UPDATABLE_DRIVER_PATH, TOGGLE_ANGLE_AS_SYSTEM_DRIVER, + SET_TARGET_STATS_ARRAY, // Always append new enum to the end. }; -- GitLab From 766320af7a27c7baeb95c7abe804de5f907aeb1f Mon Sep 17 00:00:00 2001 From: Brian Johnson Date: Mon, 9 Oct 2023 09:18:03 -0700 Subject: [PATCH 0765/1187] SF: Change the bug id for the 24Q1 connected display flag back to the FR bug Bug:299486625 Test: adb shell dumpsys SurfaceFlinger -- check for "ConnectedDisplayFlagValue" Change-Id: I7d866eb66f3f6c88323079072c94f1be510f6eca --- services/surfaceflinger/surfaceflinger_flags.aconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig index fedf08bae8..0f26d566bc 100644 --- a/services/surfaceflinger/surfaceflinger_flags.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags.aconfig @@ -12,7 +12,7 @@ flag { name: "connected_display" namespace: "core_graphics" description: "Controls SurfaceFlinger support for Connected Displays in 24Q1" - bug: "299486625" + bug: "278199093" is_fixed_read_only: true } -- GitLab From 289357d2a9abdb9f88ff763a768c0e00411222d9 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 5 Oct 2023 14:55:30 -0700 Subject: [PATCH 0766/1187] SF: opportunistically try to present the next vsync on early offset When SF changes from "late" vsync configuration to "early", it might skip a frame if the work duration is longer than the next vsync. This in turn causes jank on apps as SF skips a vsync, which will make present the app buffer a vsync later. Bug: 273702768 Test: manual Test: presubmit Change-Id: I3e3ab6a457beaecef9c2be529a53ad40f540e373 --- services/surfaceflinger/Android.bp | 3 -- .../CompositionEngine/Android.bp | 3 ++ .../Scheduler/VSyncDispatchTimerQueue.cpp | 13 +++++- services/surfaceflinger/SurfaceFlinger.cpp | 2 + .../surfaceflinger_flags.aconfig | 7 +++ services/surfaceflinger/tests/Android.bp | 1 + .../surfaceflinger/tests/unittests/Android.bp | 7 +++ .../tests/unittests/FlagUtils.h | 36 +++++++++++++++ .../unittests/VSyncDispatchTimerQueueTest.cpp | 46 +++++++++++++++++++ 9 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/FlagUtils.h diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 71c75f9521..9d0f2858ec 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -31,9 +31,6 @@ cc_defaults { "-Wconversion", "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", ], - static_libs: [ - "libsurfaceflingerflags", - ], } cc_defaults { diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 2dc7332ed7..370e4b66e8 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -63,6 +63,7 @@ cc_defaults { cc_library { name: "libcompositionengine", defaults: ["libcompositionengine_defaults"], + static_libs: ["libsurfaceflingerflags"], srcs: [ "src/planner/CachedSet.cpp", "src/planner/Flattener.cpp", @@ -107,6 +108,7 @@ cc_library { "libgtest", "libgmock", "libcompositionengine", + "libsurfaceflingerflags_test", ], local_include_dirs: ["include"], export_include_dirs: ["include"], @@ -141,6 +143,7 @@ cc_test { "librenderengine_mocks", "libgmock", "libgtest", + "libsurfaceflingerflags_test", ], // For some reason, libvulkan isn't picked up from librenderengine // Probably ASAN related? diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp index 1f922f11fb..c4c9fa56ff 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp @@ -28,10 +28,13 @@ #include "VSyncDispatchTimerQueue.h" #include "VSyncTracker.h" +#include + #undef LOG_TAG #define LOG_TAG "VSyncDispatch" namespace android::scheduler { +using namespace com::android::graphics::surfaceflinger; using base::StringAppendF; @@ -100,8 +103,14 @@ ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTim mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance)); bool const wouldSkipAWakeup = mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance))); - if (wouldSkipAVsyncTarget && wouldSkipAWakeup) { - return getExpectedCallbackTime(nextVsyncTime, timing); + if (flags::dont_skip_on_early()) { + if (wouldSkipAVsyncTarget || wouldSkipAWakeup) { + return getExpectedCallbackTime(mArmedInfo->mActualVsyncTime, timing); + } + } else { + if (wouldSkipAVsyncTarget && wouldSkipAWakeup) { + return getExpectedCallbackTime(nextVsyncTime, timing); + } } nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2b703016ca..7e799bbe30 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -6446,6 +6446,8 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, const std::string& comp mMisc2FlagEarlyBootValue == mMisc2FlagLateBootValue ? "stable" : "modified"); StringAppendF(&result, "VrrConfigFlagValue: %s\n", flagutils::vrrConfigEnabled() ? "true" : "false"); + StringAppendF(&result, "DontSkipOnEarlyFlagValue: %s\n", + flags::dont_skip_on_early() ? "true" : "false"); getRenderEngine().dump(result); diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig index fedf08bae8..01b84479a2 100644 --- a/services/surfaceflinger/surfaceflinger_flags.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags.aconfig @@ -38,3 +38,10 @@ flag { bug: "283055450" is_fixed_read_only: true } + +flag { + name: "dont_skip_on_early" + namespace: "core_graphics" + description: "This flag is guarding the behaviour where SurfaceFlinger is trying to opportunistically present a frame when the configuration change from late to early" + bug: "273702768" +} diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 36b197234a..67f2dcade4 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -67,6 +67,7 @@ cc_test { static_libs: [ "liblayers_proto", "android.hardware.graphics.composer@2.1", + "libsurfaceflingerflags", ], shared_libs: [ "android.hardware.graphics.common@1.2", diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index c99809b60d..ec21eaf488 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -42,6 +42,12 @@ filegroup { ], } +cc_aconfig_library { + name: "libsurfaceflingerflags_test", + aconfig_declarations: "surfaceflinger_flags", + test: true, +} + cc_test { name: "libsurfaceflinger_unittest", defaults: [ @@ -168,6 +174,7 @@ cc_defaults { "libtimestats_proto", "libtonemap", "perfetto_trace_protos", + "libsurfaceflingerflags_test", ], shared_libs: [ "android.hardware.configstore-utils", diff --git a/services/surfaceflinger/tests/unittests/FlagUtils.h b/services/surfaceflinger/tests/unittests/FlagUtils.h new file mode 100644 index 0000000000..7103684577 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/FlagUtils.h @@ -0,0 +1,36 @@ +/* + * Copyright 2023 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 + +#define SET_FLAG_FOR_TEST(name, value) TestFlagSetter _testflag_((name), (name), (value)) + +namespace android { +class TestFlagSetter { +public: + TestFlagSetter(bool (*getter)(), void((*setter)(bool)), bool flagValue) { + const bool initialValue = getter(); + setter(flagValue); + mResetFlagValue = [=] { setter(initialValue); }; + } + + ~TestFlagSetter() { mResetFlagValue(); } + +private: + std::function mResetFlagValue; +}; + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index 7af1da6a31..b8fdce1dce 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -30,13 +30,17 @@ #include +#include "FlagUtils.h" #include "Scheduler/VSyncDispatchTimerQueue.h" #include "Scheduler/VSyncTracker.h" +#include + using namespace testing; using namespace std::literals; namespace android::scheduler { +using namespace com::android::graphics::surfaceflinger; class MockVSyncTracker : public VSyncTracker { public: @@ -1061,6 +1065,48 @@ TEST_F(VSyncDispatchTimerQueueTest, updatesVsyncTimeForCloseWakeupTime) { EXPECT_THAT(cb.mReadyTime[0], Eq(2000)); } +TEST_F(VSyncDispatchTimerQueueTest, skipAVsyc) { + SET_FLAG_FOR_TEST(flags::dont_skip_on_early, false); + + EXPECT_CALL(mMockClock, alarmAt(_, 500)); + CountingCallback cb(mDispatch); + auto result = + mDispatch->schedule(cb, + {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(500, *result); + mMockClock.advanceBy(300); + + result = mDispatch->schedule(cb, + {.workDuration = 800, .readyDuration = 0, .earliestVsync = 1000}); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(1200, *result); + + advanceToNextCallback(); + ASSERT_THAT(cb.mCalls.size(), Eq(1)); +} + +TEST_F(VSyncDispatchTimerQueueTest, dontskipAVsyc) { + SET_FLAG_FOR_TEST(flags::dont_skip_on_early, true); + + EXPECT_CALL(mMockClock, alarmAt(_, 500)); + CountingCallback cb(mDispatch); + auto result = + mDispatch->schedule(cb, + {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(500, *result); + mMockClock.advanceBy(300); + + result = mDispatch->schedule(cb, + {.workDuration = 800, .readyDuration = 0, .earliestVsync = 1000}); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(200, *result); + + advanceToNextCallback(); + ASSERT_THAT(cb.mCalls.size(), Eq(1)); +} + class VSyncDispatchTimerQueueEntryTest : public testing::Test { protected: nsecs_t const mPeriod = 1000; -- GitLab From dd9a6cdf69896d93e22718c11b30c29952125a14 Mon Sep 17 00:00:00 2001 From: Asmita Poddar Date: Tue, 26 Sep 2023 15:35:12 +0000 Subject: [PATCH 0767/1187] Pass ProductId+VendorId+Source info to LatencyTracker Currently InputEventLatencySketch captures the aggregated latency over all devices, and it doesn't capture per-device latency. In order to capture latency metrics per device, we track the timeline for latency information for each Product Id, Vendor Id and Source individually. Bug: 270049345 Test: atest inputflinger_tests:LatencyTrackerTest Change-Id: Ic3265e25ff95266e8cfe8542d4f4afb7b6ac16b1 --- .../inputflinger/InputDeviceMetricsSource.h | 2 + .../dispatcher/InputDispatcher.cpp | 11 +- .../inputflinger/dispatcher/InputDispatcher.h | 2 +- .../dispatcher/InputEventTimeline.cpp | 16 ++- .../dispatcher/InputEventTimeline.h | 8 +- .../dispatcher/LatencyTracker.cpp | 33 +++++- .../inputflinger/dispatcher/LatencyTracker.h | 8 +- .../tests/LatencyTracker_test.cpp | 106 +++++++++++++++--- .../tests/fuzzers/LatencyTrackerFuzzer.cpp | 9 +- 9 files changed, 168 insertions(+), 27 deletions(-) diff --git a/services/inputflinger/InputDeviceMetricsSource.h b/services/inputflinger/InputDeviceMetricsSource.h index 3ac91c812a..a6be8f42cc 100644 --- a/services/inputflinger/InputDeviceMetricsSource.h +++ b/services/inputflinger/InputDeviceMetricsSource.h @@ -47,6 +47,8 @@ enum class InputDeviceUsageSource : int32_t { ftl_first = UNKNOWN, ftl_last = TRACKBALL, + // Used by latency fuzzer + kMaxValue = ftl_last }; /** Returns the InputDeviceUsageSource that corresponds to the key event. */ diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 6226a19897..16ce1e4f13 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -46,6 +46,8 @@ #include #include +#include "../InputDeviceMetricsSource.h" + #include "Connection.h" #include "DebugConfig.h" #include "InputDispatcher.h" @@ -4183,6 +4185,11 @@ std::unique_ptr InputDispatcher::splitMotionEvent( return splitMotionEntry; } +void InputDispatcher::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) { + std::scoped_lock _l(mLock); + mLatencyTracker.setInputDevices(args.inputDeviceInfos); +} + void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) { if (debugInboundEventDetails()) { ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args.eventTime); @@ -4395,7 +4402,9 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) { IdGenerator::getSource(args.id) == IdGenerator::Source::INPUT_READER && !mInputFilterEnabled) { const bool isDown = args.action == AMOTION_EVENT_ACTION_DOWN; - mLatencyTracker.trackListener(args.id, isDown, args.eventTime, args.readTime); + std::set sources = getUsageSourcesForMotionArgs(args); + mLatencyTracker.trackListener(args.id, isDown, args.eventTime, args.readTime, + args.deviceId, sources); } needWake = enqueueInboundEventLocked(std::move(newEntry)); diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 62e2d583d6..ee5a797a87 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -92,7 +92,7 @@ public: status_t start() override; status_t stop() override; - void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override{}; + void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override; void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override; void notifyKey(const NotifyKeyArgs& args) override; void notifyMotion(const NotifyMotionArgs& args) override; diff --git a/services/inputflinger/dispatcher/InputEventTimeline.cpp b/services/inputflinger/dispatcher/InputEventTimeline.cpp index 3edb6381d4..a7c6d162d8 100644 --- a/services/inputflinger/dispatcher/InputEventTimeline.cpp +++ b/services/inputflinger/dispatcher/InputEventTimeline.cpp @@ -16,6 +16,8 @@ #include "InputEventTimeline.h" +#include "../InputDeviceMetricsSource.h" + namespace android::inputdispatcher { ConnectionTimeline::ConnectionTimeline(nsecs_t deliveryTime, nsecs_t consumeTime, @@ -64,8 +66,15 @@ bool ConnectionTimeline::operator!=(const ConnectionTimeline& rhs) const { return !operator==(rhs); } -InputEventTimeline::InputEventTimeline(bool isDown, nsecs_t eventTime, nsecs_t readTime) - : isDown(isDown), eventTime(eventTime), readTime(readTime) {} +InputEventTimeline::InputEventTimeline(bool isDown, nsecs_t eventTime, nsecs_t readTime, + uint16_t vendorId, uint16_t productId, + std::set sources) + : isDown(isDown), + eventTime(eventTime), + readTime(readTime), + vendorId(vendorId), + productId(productId), + sources(sources) {} bool InputEventTimeline::operator==(const InputEventTimeline& rhs) const { if (connectionTimelines.size() != rhs.connectionTimelines.size()) { @@ -80,7 +89,8 @@ bool InputEventTimeline::operator==(const InputEventTimeline& rhs) const { return false; } } - return isDown == rhs.isDown && eventTime == rhs.eventTime && readTime == rhs.readTime; + return isDown == rhs.isDown && eventTime == rhs.eventTime && readTime == rhs.readTime && + vendorId == rhs.vendorId && productId == rhs.productId && sources == rhs.sources; } } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/InputEventTimeline.h b/services/inputflinger/dispatcher/InputEventTimeline.h index daf375d918..e9deb2d3cf 100644 --- a/services/inputflinger/dispatcher/InputEventTimeline.h +++ b/services/inputflinger/dispatcher/InputEventTimeline.h @@ -16,6 +16,8 @@ #pragma once +#include "../InputDeviceMetricsSource.h" + #include #include (data, args); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { // A message will have been logged in read return error; } @@ -694,7 +693,7 @@ private: typename std::enable_if<(I < sizeof...(Params)), status_t>::type dispatchArg( Parcel* reply, RawTuple* args) { status_t error = writeIfOutput(reply, args); - if (CC_UNLIKELY(error != NO_ERROR)) { + if (error != NO_ERROR) [[unlikely]] { // A message will have been logged in read return error; } diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h index 5079431058..0a584bfe56 100644 --- a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h +++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h @@ -26,7 +26,6 @@ #include #include -#include #include #include #include diff --git a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h index bf7c61347f..a6dc182588 100644 --- a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h +++ b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include -- GitLab From 4ab0fdc9e67a7c18e7d87292e3969f215c4a021f Mon Sep 17 00:00:00 2001 From: Jim Shargo Date: Wed, 27 Sep 2023 22:51:58 +0000 Subject: [PATCH 0777/1187] nativewindow: Misc. improvements for AHardwareBuffer Rust wrapper Changes include: - Rename AHardwareBuffer to HardwareBuffer - Expose AHardwareBuffer as a raw pointer type - Making HardwareBuffer Send - HardwareBuffer now derives Debug, PartialEq and Eq - Use NonNull instead of a *mut pointer - Adding an into_raw function to match from_raw - Adding a Clone impl that acquires a ref Bug: 296449936, 296100790 Test: atest libnativewindow_rs-internal_test Change-Id: Iaf916fabe49190f47abd1a9ed34afdb76fd20e40 --- libs/bufferstreams/rust/src/lib.rs | 2 +- libs/bufferstreams/rust/src/stream_config.rs | 6 +- libs/nativewindow/rust/src/lib.rs | 121 +++++++++++++----- .../tests/benchmark/buffer_benchmarks.rs | 4 +- 4 files changed, 98 insertions(+), 35 deletions(-) diff --git a/libs/bufferstreams/rust/src/lib.rs b/libs/bufferstreams/rust/src/lib.rs index 87f3104915..5964281c9d 100644 --- a/libs/bufferstreams/rust/src/lib.rs +++ b/libs/bufferstreams/rust/src/lib.rs @@ -159,7 +159,7 @@ pub type BufferError = anyhow::Error; /// Struct used to contain the buffer. pub struct Frame { /// A handle to the C buffer interface. - pub buffer: AHardwareBuffer, + pub buffer: HardwareBuffer, /// The time at which the buffer was dispatched. pub present_time: Instant, /// A fence used for reading/writing safely. diff --git a/libs/bufferstreams/rust/src/stream_config.rs b/libs/bufferstreams/rust/src/stream_config.rs index d0c621b0c4..454bdf144e 100644 --- a/libs/bufferstreams/rust/src/stream_config.rs +++ b/libs/bufferstreams/rust/src/stream_config.rs @@ -33,9 +33,9 @@ pub struct StreamConfig { } impl StreamConfig { - /// Tries to create a new AHardwareBuffer from settings in a [StreamConfig]. - pub fn create_hardware_buffer(&self) -> Option { - AHardwareBuffer::new(self.width, self.height, self.layers, self.format, self.usage) + /// Tries to create a new HardwareBuffer from settings in a [StreamConfig]. + pub fn create_hardware_buffer(&self) -> Option { + HardwareBuffer::new(self.width, self.height, self.layers, self.format, self.usage) } } diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index a2ec57cd3c..6eb3bbcdb3 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -16,15 +16,17 @@ extern crate nativewindow_bindgen as ffi; -pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; +pub use ffi::{AHardwareBuffer, AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; -use std::os::raw::c_void; -use std::ptr; +use std::fmt::{self, Debug, Formatter}; +use std::mem::ManuallyDrop; +use std::ptr::{self, NonNull}; /// Wrapper around an opaque C AHardwareBuffer. -pub struct AHardwareBuffer(*mut ffi::AHardwareBuffer); +#[derive(PartialEq, Eq)] +pub struct HardwareBuffer(NonNull); -impl AHardwareBuffer { +impl HardwareBuffer { /// Test whether the given format and usage flag combination is allocatable. If this function /// returns true, it means that a buffer with the given description can be allocated on this /// implementation, unless resource exhaustion occurs. If this function returns false, it means @@ -79,13 +81,13 @@ impl AHardwareBuffer { rfu0: 0, rfu1: 0, }; - let mut buffer = ptr::null_mut(); + let mut ptr = ptr::null_mut(); // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail // and return a status, but we check it later. - let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut buffer) }; + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut ptr) }; if status == 0 { - Some(Self(buffer)) + Some(Self(NonNull::new(ptr).expect("Allocated AHardwareBuffer was null"))) } else { None } @@ -101,9 +103,15 @@ impl AHardwareBuffer { /// /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the /// caller uses the pointer after the created object is dropped it will cause a memory leak. - pub unsafe fn take_from_raw(buffer_ptr: *mut c_void) -> Self { - assert!(!buffer_ptr.is_null()); - Self(buffer_ptr as *mut ffi::AHardwareBuffer) + pub unsafe fn from_raw(buffer_ptr: NonNull) -> Self { + Self(buffer_ptr) + } + + /// Get the internal |AHardwareBuffer| pointer without decrementing the refcount. This can + /// be used to provide a pointer to the AHB for a C/C++ API over the FFI. + pub fn into_raw(self) -> NonNull { + let buffer = ManuallyDrop::new(self); + buffer.0 } /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme @@ -113,7 +121,7 @@ impl AHardwareBuffer { pub fn id(&self) -> u64 { let mut out_id = 0; // SAFETY: Neither pointers can be null. - let status = unsafe { ffi::AHardwareBuffer_getId(self.0, &mut out_id) }; + let status = unsafe { ffi::AHardwareBuffer_getId(self.0.as_ref(), &mut out_id) }; assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}"); out_id @@ -161,27 +169,55 @@ impl AHardwareBuffer { rfu1: 0, }; // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null. - unsafe { ffi::AHardwareBuffer_describe(self.0, &mut buffer_desc) }; + unsafe { ffi::AHardwareBuffer_describe(self.0.as_ref(), &mut buffer_desc) }; buffer_desc } } -impl Drop for AHardwareBuffer { +impl Drop for HardwareBuffer { fn drop(&mut self) { // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw // pointer requiring callers to ensure the refcount is managed appropriately. - unsafe { ffi::AHardwareBuffer_release(self.0) } + unsafe { ffi::AHardwareBuffer_release(self.0.as_ptr()) } + } +} + +impl Debug for HardwareBuffer { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("HardwareBuffer").field("id", &self.id()).finish() } } +impl Clone for HardwareBuffer { + fn clone(&self) -> Self { + // SAFETY: ptr is guaranteed to be non-null and the acquire can not fail. + unsafe { ffi::AHardwareBuffer_acquire(self.0.as_ptr()) }; + Self(self.0) + } +} + +// SAFETY: The underlying *AHardwareBuffers can be moved between threads. +unsafe impl Send for HardwareBuffer {} + +// SAFETY: The underlying *AHardwareBuffers can be used from multiple threads. +// +// AHardwareBuffers are backed by C++ GraphicBuffers, which are mostly immutable. The only cases +// where they are not immutable are: +// +// - reallocation (which is never actually done across the codebase and requires special +// privileges/platform code access to do) +// - "locking" for reading/writing (which is explicitly allowed to be done across multiple threads +// according to the docs on the underlying gralloc calls) +unsafe impl Sync for HardwareBuffer {} + #[cfg(test)] -mod ahardwarebuffer_tests { +mod test { use super::*; #[test] fn create_valid_buffer_returns_ok() { - let buffer = AHardwareBuffer::new( + let buffer = HardwareBuffer::new( 512, 512, 1, @@ -193,19 +229,12 @@ mod ahardwarebuffer_tests { #[test] fn create_invalid_buffer_returns_err() { - let buffer = AHardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0)); + let buffer = HardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0)); assert!(buffer.is_none()); } #[test] - #[should_panic] - fn take_from_raw_panics_on_null() { - // SAFETY: Passing a null pointer is safe, it should just panic. - unsafe { AHardwareBuffer::take_from_raw(ptr::null_mut()) }; - } - - #[test] - fn take_from_raw_allows_getters() { + fn from_raw_allows_getters() { let buffer_desc = ffi::AHardwareBuffer_Desc { width: 1024, height: 512, @@ -225,13 +254,13 @@ mod ahardwarebuffer_tests { // SAFETY: The pointer must be valid because it was just allocated successfully, and we // don't use it after calling this. - let buffer = unsafe { AHardwareBuffer::take_from_raw(raw_buffer_ptr as *mut c_void) }; + let buffer = unsafe { HardwareBuffer::from_raw(NonNull::new(raw_buffer_ptr).unwrap()) }; assert_eq!(buffer.width(), 1024); } #[test] fn basic_getters() { - let buffer = AHardwareBuffer::new( + let buffer = HardwareBuffer::new( 1024, 512, 1, @@ -252,7 +281,7 @@ mod ahardwarebuffer_tests { #[test] fn id_getter() { - let buffer = AHardwareBuffer::new( + let buffer = HardwareBuffer::new( 1024, 512, 1, @@ -263,4 +292,38 @@ mod ahardwarebuffer_tests { assert_ne!(0, buffer.id()); } + + #[test] + fn clone() { + let buffer = HardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + let buffer2 = buffer.clone(); + + assert_eq!(buffer, buffer2); + } + + #[test] + fn into_raw() { + let buffer = HardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + let buffer2 = buffer.clone(); + + let raw_buffer = buffer.into_raw(); + // SAFETY: This is the same pointer we had before. + let remade_buffer = unsafe { HardwareBuffer::from_raw(raw_buffer) }; + + assert_eq!(remade_buffer, buffer2); + } } diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs index fbd49c0b50..876f6c8e26 100644 --- a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs @@ -21,8 +21,8 @@ use criterion::*; use nativewindow::*; #[inline] -fn create_720p_buffer() -> AHardwareBuffer { - AHardwareBuffer::new( +fn create_720p_buffer() -> HardwareBuffer { + HardwareBuffer::new( 1280, 720, 1, -- GitLab From 07e54e4aa040e3cb7e5e1c5dfad159e30ca157a1 Mon Sep 17 00:00:00 2001 From: sergiuferentz Date: Tue, 10 Oct 2023 15:48:15 +0000 Subject: [PATCH 0778/1187] Removing tests used to ensure the transition from HIDL to AIDL works File no longer needed so let's remove bloat. Test: Build Bug: 304520517 Change-Id: I23750b4afe3c2b36c261d226b26f50ce858fa235 --- services/surfaceflinger/tests/Android.bp | 1 - .../surfaceflinger/tests/CommonTypes_test.cpp | 200 ------------------ 2 files changed, 201 deletions(-) delete mode 100644 services/surfaceflinger/tests/CommonTypes_test.cpp diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 36b197234a..5cc3154703 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -32,7 +32,6 @@ cc_test { "BootDisplayMode_test.cpp", "Binder_test.cpp", "BufferGenerator.cpp", - "CommonTypes_test.cpp", "Credentials_test.cpp", "DereferenceSurfaceControl_test.cpp", "DisplayConfigs_test.cpp", diff --git a/services/surfaceflinger/tests/CommonTypes_test.cpp b/services/surfaceflinger/tests/CommonTypes_test.cpp deleted file mode 100644 index 25b4615239..0000000000 --- a/services/surfaceflinger/tests/CommonTypes_test.cpp +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (C) 2019 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 -#include - -#include -#include -#include - -using AidlBlendMode = aidl::android::hardware::graphics::common::BlendMode; -using AidlDataspace = aidl::android::hardware::graphics::common::Dataspace; - -using HidlBlendMode = android::hardware::graphics::composer::V2_1::IComposerClient::BlendMode; -using HidlDataspace = android::hardware::graphics::common::V1_2::Dataspace; - -static_assert(static_cast(AidlBlendMode::INVALID) == - static_cast(HidlBlendMode::INVALID)); -static_assert(static_cast(AidlBlendMode::NONE) == - static_cast(HidlBlendMode::NONE)); -static_assert(static_cast(AidlBlendMode::PREMULTIPLIED) == - static_cast(HidlBlendMode::PREMULTIPLIED)); -static_assert(static_cast(AidlBlendMode::COVERAGE) == - static_cast(HidlBlendMode::COVERAGE)); - -static_assert(static_cast(ADATASPACE_UNKNOWN) == - static_cast(AidlDataspace::UNKNOWN)); -static_assert(static_cast(ADATASPACE_SCRGB_LINEAR) == - static_cast(AidlDataspace::SCRGB_LINEAR)); -static_assert(static_cast(ADATASPACE_SRGB) == static_cast(AidlDataspace::SRGB)); -static_assert(static_cast(ADATASPACE_SCRGB) == - static_cast(AidlDataspace::SCRGB)); -static_assert(static_cast(ADATASPACE_DISPLAY_P3) == - static_cast(AidlDataspace::DISPLAY_P3)); -static_assert(static_cast(ADATASPACE_BT2020_PQ) == - static_cast(AidlDataspace::BT2020_PQ)); -static_assert(static_cast(ADATASPACE_ADOBE_RGB) == - static_cast(AidlDataspace::ADOBE_RGB)); -static_assert(static_cast(ADATASPACE_BT2020) == - static_cast(AidlDataspace::BT2020)); -static_assert(static_cast(ADATASPACE_BT709) == - static_cast(AidlDataspace::BT709)); -static_assert(static_cast(ADATASPACE_DCI_P3) == - static_cast(AidlDataspace::DCI_P3)); -static_assert(static_cast(ADATASPACE_SRGB_LINEAR) == - static_cast(AidlDataspace::SRGB_LINEAR)); - -static_assert(static_cast(ADATASPACE_UNKNOWN) == - static_cast(HidlDataspace::UNKNOWN)); -static_assert(static_cast(ADATASPACE_SCRGB_LINEAR) == - static_cast(HidlDataspace::V0_SCRGB_LINEAR)); -static_assert(static_cast(ADATASPACE_SRGB) == - static_cast(HidlDataspace::V0_SRGB)); -static_assert(static_cast(ADATASPACE_SCRGB) == - static_cast(HidlDataspace::V0_SCRGB)); -static_assert(static_cast(ADATASPACE_DISPLAY_P3) == - static_cast(HidlDataspace::DISPLAY_P3)); -static_assert(static_cast(ADATASPACE_BT2020_PQ) == - static_cast(HidlDataspace::BT2020_PQ)); -static_assert(static_cast(ADATASPACE_ADOBE_RGB) == - static_cast(HidlDataspace::ADOBE_RGB)); -static_assert(static_cast(ADATASPACE_BT2020) == - static_cast(HidlDataspace::BT2020)); -static_assert(static_cast(ADATASPACE_BT709) == - static_cast(HidlDataspace::V0_BT709)); -static_assert(static_cast(ADATASPACE_DCI_P3) == - static_cast(HidlDataspace::DCI_P3)); -static_assert(static_cast(ADATASPACE_SRGB_LINEAR) == - static_cast(HidlDataspace::V0_SRGB_LINEAR)); - -static_assert(static_cast(AidlDataspace::UNKNOWN) == - static_cast(HidlDataspace::UNKNOWN)); -static_assert(static_cast(AidlDataspace::ARBITRARY) == - static_cast(HidlDataspace::ARBITRARY)); -static_assert(static_cast(AidlDataspace::STANDARD_SHIFT) == - static_cast(HidlDataspace::STANDARD_SHIFT)); -static_assert(static_cast(AidlDataspace::STANDARD_MASK) == - static_cast(HidlDataspace::STANDARD_MASK)); -static_assert(static_cast(AidlDataspace::STANDARD_UNSPECIFIED) == - static_cast(HidlDataspace::STANDARD_UNSPECIFIED)); -static_assert(static_cast(AidlDataspace::STANDARD_BT709) == - static_cast(HidlDataspace::STANDARD_BT709)); -static_assert(static_cast(AidlDataspace::STANDARD_BT601_625) == - static_cast(HidlDataspace::STANDARD_BT601_625)); -static_assert(static_cast(AidlDataspace::STANDARD_BT601_625_UNADJUSTED) == - static_cast(HidlDataspace::STANDARD_BT601_625_UNADJUSTED)); -static_assert(static_cast(AidlDataspace::STANDARD_BT601_525) == - static_cast(HidlDataspace::STANDARD_BT601_525)); -static_assert(static_cast(AidlDataspace::STANDARD_BT601_525_UNADJUSTED) == - static_cast(HidlDataspace::STANDARD_BT601_525_UNADJUSTED)); -static_assert(static_cast(AidlDataspace::STANDARD_BT2020) == - static_cast(HidlDataspace::STANDARD_BT2020)); -static_assert(static_cast(AidlDataspace::STANDARD_BT2020_CONSTANT_LUMINANCE) == - static_cast(HidlDataspace::STANDARD_BT2020_CONSTANT_LUMINANCE)); -static_assert(static_cast(AidlDataspace::STANDARD_BT470M) == - static_cast(HidlDataspace::STANDARD_BT470M)); -static_assert(static_cast(AidlDataspace::STANDARD_FILM) == - static_cast(HidlDataspace::STANDARD_FILM)); -static_assert(static_cast(AidlDataspace::STANDARD_DCI_P3) == - static_cast(HidlDataspace::STANDARD_DCI_P3)); -static_assert(static_cast(AidlDataspace::STANDARD_ADOBE_RGB) == - static_cast(HidlDataspace::STANDARD_ADOBE_RGB)); -static_assert(static_cast(AidlDataspace::TRANSFER_SHIFT) == - static_cast(HidlDataspace::TRANSFER_SHIFT)); -static_assert(static_cast(AidlDataspace::TRANSFER_MASK) == - static_cast(HidlDataspace::TRANSFER_MASK)); -static_assert(static_cast(AidlDataspace::TRANSFER_UNSPECIFIED) == - static_cast(HidlDataspace::TRANSFER_UNSPECIFIED)); -static_assert(static_cast(AidlDataspace::TRANSFER_LINEAR) == - static_cast(HidlDataspace::TRANSFER_LINEAR)); -static_assert(static_cast(AidlDataspace::TRANSFER_SRGB) == - static_cast(HidlDataspace::TRANSFER_SRGB)); -static_assert(static_cast(AidlDataspace::TRANSFER_SMPTE_170M) == - static_cast(HidlDataspace::TRANSFER_SMPTE_170M)); -static_assert(static_cast(AidlDataspace::TRANSFER_GAMMA2_2) == - static_cast(HidlDataspace::TRANSFER_GAMMA2_2)); -static_assert(static_cast(AidlDataspace::TRANSFER_GAMMA2_6) == - static_cast(HidlDataspace::TRANSFER_GAMMA2_6)); -static_assert(static_cast(AidlDataspace::TRANSFER_GAMMA2_8) == - static_cast(HidlDataspace::TRANSFER_GAMMA2_8)); -static_assert(static_cast(AidlDataspace::TRANSFER_ST2084) == - static_cast(HidlDataspace::TRANSFER_ST2084)); -static_assert(static_cast(AidlDataspace::TRANSFER_HLG) == - static_cast(HidlDataspace::TRANSFER_HLG)); -static_assert(static_cast(AidlDataspace::RANGE_SHIFT) == - static_cast(HidlDataspace::RANGE_SHIFT)); -static_assert(static_cast(AidlDataspace::RANGE_MASK) == - static_cast(HidlDataspace::RANGE_MASK)); -static_assert(static_cast(AidlDataspace::RANGE_UNSPECIFIED) == - static_cast(HidlDataspace::RANGE_UNSPECIFIED)); -static_assert(static_cast(AidlDataspace::RANGE_FULL) == - static_cast(HidlDataspace::RANGE_FULL)); -static_assert(static_cast(AidlDataspace::RANGE_LIMITED) == - static_cast(HidlDataspace::RANGE_LIMITED)); -static_assert(static_cast(AidlDataspace::RANGE_EXTENDED) == - static_cast(HidlDataspace::RANGE_EXTENDED)); -static_assert(static_cast(AidlDataspace::SRGB_LINEAR) == - static_cast(HidlDataspace::V0_SRGB_LINEAR)); -static_assert(static_cast(AidlDataspace::SCRGB_LINEAR) == - static_cast(HidlDataspace::V0_SCRGB_LINEAR)); -static_assert(static_cast(AidlDataspace::SRGB) == - static_cast(HidlDataspace::V0_SRGB)); -static_assert(static_cast(AidlDataspace::SCRGB) == - static_cast(HidlDataspace::V0_SCRGB)); -static_assert(static_cast(AidlDataspace::JFIF) == - static_cast(HidlDataspace::V0_JFIF)); -static_assert(static_cast(AidlDataspace::BT601_625) == - static_cast(HidlDataspace::V0_BT601_625)); -static_assert(static_cast(AidlDataspace::BT601_525) == - static_cast(HidlDataspace::V0_BT601_525)); -static_assert(static_cast(AidlDataspace::BT709) == - static_cast(HidlDataspace::V0_BT709)); -static_assert(static_cast(AidlDataspace::DCI_P3_LINEAR) == - static_cast(HidlDataspace::DCI_P3_LINEAR)); -static_assert(static_cast(AidlDataspace::DCI_P3) == - static_cast(HidlDataspace::DCI_P3)); -static_assert(static_cast(AidlDataspace::DISPLAY_P3_LINEAR) == - static_cast(HidlDataspace::DISPLAY_P3_LINEAR)); -static_assert(static_cast(AidlDataspace::DISPLAY_P3) == - static_cast(HidlDataspace::DISPLAY_P3)); -static_assert(static_cast(AidlDataspace::ADOBE_RGB) == - static_cast(HidlDataspace::ADOBE_RGB)); -static_assert(static_cast(AidlDataspace::BT2020_LINEAR) == - static_cast(HidlDataspace::BT2020_LINEAR)); -static_assert(static_cast(AidlDataspace::BT2020) == - static_cast(HidlDataspace::BT2020)); -static_assert(static_cast(AidlDataspace::BT2020_PQ) == - static_cast(HidlDataspace::BT2020_PQ)); -static_assert(static_cast(AidlDataspace::DEPTH) == - static_cast(HidlDataspace::DEPTH)); -static_assert(static_cast(AidlDataspace::SENSOR) == - static_cast(HidlDataspace::SENSOR)); -static_assert(static_cast(AidlDataspace::BT2020_ITU) == - static_cast(HidlDataspace::BT2020_ITU)); -static_assert(static_cast(AidlDataspace::BT2020_ITU_PQ) == - static_cast(HidlDataspace::BT2020_ITU_PQ)); -static_assert(static_cast(AidlDataspace::BT2020_ITU_HLG) == - static_cast(HidlDataspace::BT2020_ITU_HLG)); -static_assert(static_cast(AidlDataspace::BT2020_HLG) == - static_cast(HidlDataspace::BT2020_HLG)); -static_assert(static_cast(AidlDataspace::DISPLAY_BT2020) == - static_cast(HidlDataspace::DISPLAY_BT2020)); -static_assert(static_cast(AidlDataspace::DYNAMIC_DEPTH) == - static_cast(HidlDataspace::DYNAMIC_DEPTH)); -static_assert(static_cast(AidlDataspace::JPEG_APP_SEGMENTS) == - static_cast(HidlDataspace::JPEG_APP_SEGMENTS)); -static_assert(static_cast(AidlDataspace::HEIF) == - static_cast(HidlDataspace::HEIF)); -- GitLab From 7df9f75955ff5686f6deda4a22d5d262863cae05 Mon Sep 17 00:00:00 2001 From: Jim Shargo Date: Tue, 18 Jul 2023 20:33:45 +0000 Subject: [PATCH 0779/1187] libnativewindow: Add rust library and set up bindgen For now we only expose AHardwareBuffer, but the exposed bindings will make it easy to also expose ANativeWindow, ADataspace, and others in the future. NOTE: This makes the new presubmit post-submit to appease the SLO checker Bug: 291954749 Test: Added new unit tests for both bindings and the rust library. Merged-In: I8ef24fc9111bb3fb72a4cdd941742d42d72fa776 Change-Id: I1dc87c9012fc1c1b805716cf7252fba2da11aec2 --- libs/nativewindow/TEST_MAPPING | 8 + libs/nativewindow/rust/Android.bp | 87 ++++++ libs/nativewindow/rust/src/lib.rs | 260 ++++++++++++++++++ .../rust/sys/nativewindow_bindings.h | 20 ++ 4 files changed, 375 insertions(+) create mode 100644 libs/nativewindow/rust/Android.bp create mode 100644 libs/nativewindow/rust/src/lib.rs create mode 100644 libs/nativewindow/rust/sys/nativewindow_bindings.h diff --git a/libs/nativewindow/TEST_MAPPING b/libs/nativewindow/TEST_MAPPING index 3d7f3c28f4..bbad757a48 100644 --- a/libs/nativewindow/TEST_MAPPING +++ b/libs/nativewindow/TEST_MAPPING @@ -3,5 +3,13 @@ { "name": "libnativewindow_test" } + ], + "postsubmit": [ + { + "name": "libnativewindow_bindgen_test" + }, + { + "name": "libnativewindow_rs-internal_test" + } ] } diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp new file mode 100644 index 0000000000..dc1575ca33 --- /dev/null +++ b/libs/nativewindow/rust/Android.bp @@ -0,0 +1,87 @@ +// Copyright (C) 2023 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. + +package { + default_applicable_licenses: [ + "frameworks_native_libs_nativewindow_license", + ], +} + +rust_bindgen { + name: "libnativewindow_bindgen", + crate_name: "nativewindow_bindgen", + wrapper_src: "sys/nativewindow_bindings.h", + source_stem: "bindings", + bindgen_flags: [ + "--constified-enum-module=AHardwareBuffer_Format", + "--bitfield-enum=AHardwareBuffer_UsageFlags", + + "--allowlist-file=.*/nativewindow/include/.*\\.h", + + "--with-derive-eq", + "--with-derive-partialeq", + ], + shared_libs: [ + "libnativewindow", + ], + + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", +} + +rust_test { + name: "libnativewindow_bindgen_test", + srcs: [":libnativewindow_bindgen"], + crate_name: "nativewindow_bindgen_test", + test_suites: ["general-tests"], + auto_gen_config: true, + clippy_lints: "none", + lints: "none", +} + +rust_defaults { + name: "libnativewindow_defaults", + srcs: ["src/lib.rs"], + rustlibs: [ + "libnativewindow_bindgen", + ], +} + +rust_library { + name: "libnativewindow_rs", + crate_name: "nativewindow", + defaults: ["libnativewindow_defaults"], + + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", +} + +rust_test { + name: "libnativewindow_rs-internal_test", + crate_name: "nativewindow", + defaults: ["libnativewindow_defaults"], + test_suites: ["general-tests"], +} diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs new file mode 100644 index 0000000000..a5bcc6293a --- /dev/null +++ b/libs/nativewindow/rust/src/lib.rs @@ -0,0 +1,260 @@ +// Copyright (C) 2023 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. + +//! Pleasant Rust bindings for libnativewindow, including AHardwareBuffer + +extern crate nativewindow_bindgen as ffi; + +pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; + +use std::os::raw::c_void; +use std::ptr; + +/// Wrapper around an opaque C AHardwareBuffer. +pub struct AHardwareBuffer(*mut ffi::AHardwareBuffer); + +impl AHardwareBuffer { + /// Test whether the given format and usage flag combination is allocatable. If this function + /// returns true, it means that a buffer with the given description can be allocated on this + /// implementation, unless resource exhaustion occurs. If this function returns false, it means + /// that the allocation of the given description will never succeed. + /// + /// Available since API 29 + pub fn is_supported( + width: u32, + height: u32, + layers: u32, + format: AHardwareBuffer_Format::Type, + usage: AHardwareBuffer_UsageFlags, + stride: u32, + ) -> bool { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width, + height, + layers, + format, + usage: usage.0, + stride, + rfu0: 0, + rfu1: 0, + }; + // SAFETY: *buffer_desc will never be null. + let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) }; + + status == 1 + } + + /// Allocates a buffer that matches the passed AHardwareBuffer_Desc. If allocation succeeds, the + /// buffer can be used according to the usage flags specified in its description. If a buffer is + /// used in ways not compatible with its usage flags, the results are undefined and may include + /// program termination. + /// + /// Available since API level 26. + pub fn new( + width: u32, + height: u32, + layers: u32, + format: AHardwareBuffer_Format::Type, + usage: AHardwareBuffer_UsageFlags, + ) -> Option { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width, + height, + layers, + format, + usage: usage.0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + let mut buffer = ptr::null_mut(); + // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail + // and return a status, but we check it later. + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut buffer) }; + + if status == 0 { + Some(Self(buffer)) + } else { + None + } + } + + /// Adopts the raw pointer and wraps it in a Rust AHardwareBuffer. + /// + /// # Errors + /// + /// Will panic if buffer_ptr is null. + /// + /// # Safety + /// + /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the + /// caller uses the pointer after the created object is dropped it will cause a memory leak. + pub unsafe fn take_from_raw(buffer_ptr: *mut c_void) -> Self { + assert!(!buffer_ptr.is_null()); + Self(buffer_ptr as *mut ffi::AHardwareBuffer) + } + + /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme + /// and undocumented circumstances. + /// + /// Available since API level 31. + pub fn id(&self) -> u64 { + let mut out_id = 0; + // SAFETY: Neither pointers can be null. + let status = unsafe { ffi::AHardwareBuffer_getId(self.0, &mut out_id) }; + assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}"); + + out_id + } + + /// Get the width of this buffer + pub fn width(&self) -> u32 { + self.description().width + } + + /// Get the height of this buffer + pub fn height(&self) -> u32 { + self.description().height + } + + /// Get the number of layers of this buffer + pub fn layers(&self) -> u32 { + self.description().layers + } + + /// Get the format of this buffer + pub fn format(&self) -> AHardwareBuffer_Format::Type { + self.description().format + } + + /// Get the usage bitvector of this buffer + pub fn usage(&self) -> AHardwareBuffer_UsageFlags { + AHardwareBuffer_UsageFlags(self.description().usage) + } + + /// Get the stride of this buffer + pub fn stride(&self) -> u32 { + self.description().stride + } + + fn description(&self) -> ffi::AHardwareBuffer_Desc { + let mut buffer_desc = ffi::AHardwareBuffer_Desc { + width: 0, + height: 0, + layers: 0, + format: 0, + usage: 0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null. + unsafe { ffi::AHardwareBuffer_describe(self.0, &mut buffer_desc) }; + buffer_desc + } +} + +impl Drop for AHardwareBuffer { + fn drop(&mut self) { + // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have + // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw + // pointer requiring callers to ensure the refcount is managed appropriately. + unsafe { ffi::AHardwareBuffer_release(self.0) } + } +} + +#[cfg(test)] +mod ahardwarebuffer_tests { + use super::*; + + #[test] + fn create_valid_buffer_returns_ok() { + let buffer = AHardwareBuffer::new( + 512, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ); + assert!(buffer.is_some()); + } + + #[test] + fn create_invalid_buffer_returns_err() { + let buffer = AHardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0)); + assert!(buffer.is_none()); + } + + #[test] + #[should_panic] + fn take_from_raw_panics_on_null() { + unsafe { AHardwareBuffer::take_from_raw(ptr::null_mut()) }; + } + + #[test] + fn take_from_raw_allows_getters() { + let buffer_desc = ffi::AHardwareBuffer_Desc { + width: 1024, + height: 512, + layers: 1, + format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0, + stride: 0, + rfu0: 0, + rfu1: 0, + }; + let mut raw_buffer_ptr = ptr::null_mut(); + + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) }; + assert_eq!(status, 0); + + let buffer = unsafe { AHardwareBuffer::take_from_raw(raw_buffer_ptr as *mut c_void) }; + assert_eq!(buffer.width(), 1024); + } + + #[test] + fn basic_getters() { + let buffer = AHardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + + assert_eq!(buffer.width(), 1024); + assert_eq!(buffer.height(), 512); + assert_eq!(buffer.layers(), 1); + assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM); + assert_eq!( + buffer.usage(), + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN + ); + } + + #[test] + fn id_getter() { + let buffer = AHardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + + assert_ne!(0, buffer.id()); + } +} diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h new file mode 100644 index 0000000000..e652aee711 --- /dev/null +++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h @@ -0,0 +1,20 @@ +/* + * Copyright 2023 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 +#include +#include +#include -- GitLab From b69c6ef0a8b9bff035be10639efeda027d69e325 Mon Sep 17 00:00:00 2001 From: Jim Shargo Date: Thu, 5 Oct 2023 22:54:51 +0000 Subject: [PATCH 0780/1187] nativewindow: Misc. improvements for AHardwareBuffer Rust wrapper Changes include: - Rename AHardwareBuffer to HardwareBuffer - Expose AHardwareBuffer as a raw pointer type - Making HardwareBuffer Send - HardwareBuffer now derives Debug, PartialEq and Eq - Use NonNull instead of a *mut pointer - Adding an into_raw function to match from_raw - Adding a Clone impl that acquires a ref Bug: 296449936, 296100790 Test: atest libnativewindow_rs-internal_test Merged-In: Iaf916fabe49190f47abd1a9ed34afdb76fd20e40 Change-Id: I5da6375582e98e8783b31ad8424f1e21c33467e5 --- libs/nativewindow/rust/src/lib.rs | 121 +++++++++++++----- .../tests/benchmark/buffer_benchmarks.rs | 4 +- 2 files changed, 94 insertions(+), 31 deletions(-) diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index a2ec57cd3c..6eb3bbcdb3 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -16,15 +16,17 @@ extern crate nativewindow_bindgen as ffi; -pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; +pub use ffi::{AHardwareBuffer, AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; -use std::os::raw::c_void; -use std::ptr; +use std::fmt::{self, Debug, Formatter}; +use std::mem::ManuallyDrop; +use std::ptr::{self, NonNull}; /// Wrapper around an opaque C AHardwareBuffer. -pub struct AHardwareBuffer(*mut ffi::AHardwareBuffer); +#[derive(PartialEq, Eq)] +pub struct HardwareBuffer(NonNull); -impl AHardwareBuffer { +impl HardwareBuffer { /// Test whether the given format and usage flag combination is allocatable. If this function /// returns true, it means that a buffer with the given description can be allocated on this /// implementation, unless resource exhaustion occurs. If this function returns false, it means @@ -79,13 +81,13 @@ impl AHardwareBuffer { rfu0: 0, rfu1: 0, }; - let mut buffer = ptr::null_mut(); + let mut ptr = ptr::null_mut(); // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail // and return a status, but we check it later. - let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut buffer) }; + let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut ptr) }; if status == 0 { - Some(Self(buffer)) + Some(Self(NonNull::new(ptr).expect("Allocated AHardwareBuffer was null"))) } else { None } @@ -101,9 +103,15 @@ impl AHardwareBuffer { /// /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the /// caller uses the pointer after the created object is dropped it will cause a memory leak. - pub unsafe fn take_from_raw(buffer_ptr: *mut c_void) -> Self { - assert!(!buffer_ptr.is_null()); - Self(buffer_ptr as *mut ffi::AHardwareBuffer) + pub unsafe fn from_raw(buffer_ptr: NonNull) -> Self { + Self(buffer_ptr) + } + + /// Get the internal |AHardwareBuffer| pointer without decrementing the refcount. This can + /// be used to provide a pointer to the AHB for a C/C++ API over the FFI. + pub fn into_raw(self) -> NonNull { + let buffer = ManuallyDrop::new(self); + buffer.0 } /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme @@ -113,7 +121,7 @@ impl AHardwareBuffer { pub fn id(&self) -> u64 { let mut out_id = 0; // SAFETY: Neither pointers can be null. - let status = unsafe { ffi::AHardwareBuffer_getId(self.0, &mut out_id) }; + let status = unsafe { ffi::AHardwareBuffer_getId(self.0.as_ref(), &mut out_id) }; assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}"); out_id @@ -161,27 +169,55 @@ impl AHardwareBuffer { rfu1: 0, }; // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null. - unsafe { ffi::AHardwareBuffer_describe(self.0, &mut buffer_desc) }; + unsafe { ffi::AHardwareBuffer_describe(self.0.as_ref(), &mut buffer_desc) }; buffer_desc } } -impl Drop for AHardwareBuffer { +impl Drop for HardwareBuffer { fn drop(&mut self) { // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw // pointer requiring callers to ensure the refcount is managed appropriately. - unsafe { ffi::AHardwareBuffer_release(self.0) } + unsafe { ffi::AHardwareBuffer_release(self.0.as_ptr()) } + } +} + +impl Debug for HardwareBuffer { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("HardwareBuffer").field("id", &self.id()).finish() } } +impl Clone for HardwareBuffer { + fn clone(&self) -> Self { + // SAFETY: ptr is guaranteed to be non-null and the acquire can not fail. + unsafe { ffi::AHardwareBuffer_acquire(self.0.as_ptr()) }; + Self(self.0) + } +} + +// SAFETY: The underlying *AHardwareBuffers can be moved between threads. +unsafe impl Send for HardwareBuffer {} + +// SAFETY: The underlying *AHardwareBuffers can be used from multiple threads. +// +// AHardwareBuffers are backed by C++ GraphicBuffers, which are mostly immutable. The only cases +// where they are not immutable are: +// +// - reallocation (which is never actually done across the codebase and requires special +// privileges/platform code access to do) +// - "locking" for reading/writing (which is explicitly allowed to be done across multiple threads +// according to the docs on the underlying gralloc calls) +unsafe impl Sync for HardwareBuffer {} + #[cfg(test)] -mod ahardwarebuffer_tests { +mod test { use super::*; #[test] fn create_valid_buffer_returns_ok() { - let buffer = AHardwareBuffer::new( + let buffer = HardwareBuffer::new( 512, 512, 1, @@ -193,19 +229,12 @@ mod ahardwarebuffer_tests { #[test] fn create_invalid_buffer_returns_err() { - let buffer = AHardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0)); + let buffer = HardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0)); assert!(buffer.is_none()); } #[test] - #[should_panic] - fn take_from_raw_panics_on_null() { - // SAFETY: Passing a null pointer is safe, it should just panic. - unsafe { AHardwareBuffer::take_from_raw(ptr::null_mut()) }; - } - - #[test] - fn take_from_raw_allows_getters() { + fn from_raw_allows_getters() { let buffer_desc = ffi::AHardwareBuffer_Desc { width: 1024, height: 512, @@ -225,13 +254,13 @@ mod ahardwarebuffer_tests { // SAFETY: The pointer must be valid because it was just allocated successfully, and we // don't use it after calling this. - let buffer = unsafe { AHardwareBuffer::take_from_raw(raw_buffer_ptr as *mut c_void) }; + let buffer = unsafe { HardwareBuffer::from_raw(NonNull::new(raw_buffer_ptr).unwrap()) }; assert_eq!(buffer.width(), 1024); } #[test] fn basic_getters() { - let buffer = AHardwareBuffer::new( + let buffer = HardwareBuffer::new( 1024, 512, 1, @@ -252,7 +281,7 @@ mod ahardwarebuffer_tests { #[test] fn id_getter() { - let buffer = AHardwareBuffer::new( + let buffer = HardwareBuffer::new( 1024, 512, 1, @@ -263,4 +292,38 @@ mod ahardwarebuffer_tests { assert_ne!(0, buffer.id()); } + + #[test] + fn clone() { + let buffer = HardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + let buffer2 = buffer.clone(); + + assert_eq!(buffer, buffer2); + } + + #[test] + fn into_raw() { + let buffer = HardwareBuffer::new( + 1024, + 512, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .expect("Buffer with some basic parameters was not created successfully"); + let buffer2 = buffer.clone(); + + let raw_buffer = buffer.into_raw(); + // SAFETY: This is the same pointer we had before. + let remade_buffer = unsafe { HardwareBuffer::from_raw(raw_buffer) }; + + assert_eq!(remade_buffer, buffer2); + } } diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs index fbd49c0b50..876f6c8e26 100644 --- a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs @@ -21,8 +21,8 @@ use criterion::*; use nativewindow::*; #[inline] -fn create_720p_buffer() -> AHardwareBuffer { - AHardwareBuffer::new( +fn create_720p_buffer() -> HardwareBuffer { + HardwareBuffer::new( 1280, 720, 1, -- GitLab From 03350bc91d82d77d9d2fa10daa53c904dc5796aa Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Thu, 3 Aug 2023 16:02:51 +0000 Subject: [PATCH 0781/1187] Add missing safety comments. These will soon be required by a lint. Bug: 290018030 Test: m rust Merged-In: Iaa33bab93c458d963d45ec68daf243057b9f1c15 Change-Id: Ia822853e44cc74d0c27622c8d30ca7c404058663 --- libs/nativewindow/rust/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index a5bcc6293a..0ed381eac5 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -199,6 +199,7 @@ mod ahardwarebuffer_tests { #[test] #[should_panic] fn take_from_raw_panics_on_null() { + // SAFETY: Passing a null pointer is safe, it should just panic. unsafe { AHardwareBuffer::take_from_raw(ptr::null_mut()) }; } @@ -216,9 +217,13 @@ mod ahardwarebuffer_tests { }; let mut raw_buffer_ptr = ptr::null_mut(); + // SAFETY: The pointers are valid because they come from references, and + // `AHardwareBuffer_allocate` doesn't retain them after it returns. let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) }; assert_eq!(status, 0); + // SAFETY: The pointer must be valid because it was just allocated successfully, and we + // don't use it after calling this. let buffer = unsafe { AHardwareBuffer::take_from_raw(raw_buffer_ptr as *mut c_void) }; assert_eq!(buffer.width(), 1024); } -- GitLab From e4680d7599baa9589daf8a95f6536822dd68d57b Mon Sep 17 00:00:00 2001 From: Jim Shargo Date: Mon, 7 Aug 2023 16:46:45 +0000 Subject: [PATCH 0782/1187] nativewindow: Add C++/Rust benchmarks Test: atest nativewindow_buffer_benchmarks_rs nativewindow_buffer_benchmarks_cc Merged-In: Ia2898439da46e57cf65e3d64030d98f052a694c6 Change-Id: Ib5aaa97f7130f1964824a2f6c8ca85d72d61ce4f --- libs/nativewindow/rust/src/lib.rs | 1 + libs/nativewindow/tests/benchmark/Android.bp | 50 +++++++++++++++++++ libs/nativewindow/tests/benchmark/README.md | 22 ++++++++ .../tests/benchmark/buffer_benchmarks.cc | 38 ++++++++++++++ .../tests/benchmark/buffer_benchmarks.rs | 40 +++++++++++++++ 5 files changed, 151 insertions(+) create mode 100644 libs/nativewindow/tests/benchmark/Android.bp create mode 100644 libs/nativewindow/tests/benchmark/README.md create mode 100644 libs/nativewindow/tests/benchmark/buffer_benchmarks.cc create mode 100644 libs/nativewindow/tests/benchmark/buffer_benchmarks.rs diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index 0ed381eac5..a2ec57cd3c 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -61,6 +61,7 @@ impl AHardwareBuffer { /// program termination. /// /// Available since API level 26. + #[inline] pub fn new( width: u32, height: u32, diff --git a/libs/nativewindow/tests/benchmark/Android.bp b/libs/nativewindow/tests/benchmark/Android.bp new file mode 100644 index 0000000000..6f844cf864 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/Android.bp @@ -0,0 +1,50 @@ +// Copyright (C) 2023 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. + +cc_defaults { + name: "nativewindow_benchmark_defaults_cc", + shared_libs: ["libnativewindow"], + static_libs: [ + "libbase", + "libgoogle-benchmark-main", + ], + test_suites: [ + "device-tests", + "NativeWindowBenchmarks", + ], +} + +cc_benchmark { + name: "nativewindow_buffer_benchmarks_cc", + srcs: ["buffer_benchmarks.cc"], + defaults: ["nativewindow_benchmark_defaults_cc"], +} + +rust_defaults { + name: "nativewindow_benchmark_defaults_rs", + rustlibs: [ + "libnativewindow_rs", + "libcriterion", + ], + test_suites: [ + "device-tests", + "NativeWindowBenchmarks", + ], +} + +rust_benchmark { + name: "nativewindow_buffer_benchmarks_rs", + srcs: ["buffer_benchmarks.rs"], + defaults: ["nativewindow_benchmark_defaults_rs"], +} diff --git a/libs/nativewindow/tests/benchmark/README.md b/libs/nativewindow/tests/benchmark/README.md new file mode 100644 index 0000000000..7eae538dd2 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/README.md @@ -0,0 +1,22 @@ +# libnativewindow Benchmarks + +This directory contains benchmarks for the C++ and Rust variants of +libnativewindow. + +## Running + +It is currently a little tricky to get statistics from Rust benchmarks directly +from tradefed. But we can hack it by using atest to build/push, then running +the benchmarks by hand to get stats. + +``` + $ atest nativewindow_buffer_benchmarks_rs nativewindow_buffer_benchmarks_cc -d + $ adb shell /data/local/tmp/nativewindow_buffer_benchmarks_cc/x86_64/nativewindow_buffer_benchmarks_cc + $ adb shell /data/local/tmp/nativewindow_buffer_benchmarks_rs/x86_64/nativewindow_buffer_benchmarks_rs --bench +``` + +## Results + +On a remote emulator, the results we see from the benchmarks from Rust and C++ +seem to be roughly equivalent! Allocating/deallocating a 720p buffer takes +~2.3ms on each. diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc new file mode 100644 index 0000000000..0ead1a2926 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc @@ -0,0 +1,38 @@ +// Copyright (C) 2023 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 +#include +#include + +static void BM_BufferAllocationDeallocation(benchmark::State& state) { + AHardwareBuffer_Desc buffer_desc = {.width = 1280, + .height = 720, + .layers = 1, + .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + .stride = 0}; + AHardwareBuffer* buffer = nullptr; + for (auto _ : state) { + int status = AHardwareBuffer_allocate(&buffer_desc, &buffer); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to allocate buffer."); + } + AHardwareBuffer_release(buffer); + buffer = nullptr; + } +} +BENCHMARK(BM_BufferAllocationDeallocation); + +BENCHMARK_MAIN(); \ No newline at end of file diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs new file mode 100644 index 0000000000..3ef0f5e8c7 --- /dev/null +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs @@ -0,0 +1,40 @@ +// Copyright (C) 2023 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. + +//! Benchmark for libnativewindow AHardwareBuffer bindings + +#![allow(dead_code)] +#![allow(missing_docs)] + +use criterion::*; +use nativewindow::*; + +fn allocate_deallocate() { + let buffer = AHardwareBuffer::new( + 1280, + 720, + 1, + AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + ) + .unwrap(); + drop(buffer); +} + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("allocate_deallocate", |b| b.iter(allocate_deallocate)); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); -- GitLab From ba294d7d80eff07086838e490158a525218f199c Mon Sep 17 00:00:00 2001 From: Jim Shargo Date: Wed, 9 Aug 2023 20:20:17 +0000 Subject: [PATCH 0783/1187] nativewindow: Add more benchmarks to evaluate FFI costs This CL adds two new benchmarks, one for getting an AHardwareBuffer's ID and another for getting its description. These should (and do) ultimately take the same amount of time. Test: just adding new tests Merged-In: I5e09a2736ab829ca465aaa4073b439a605d49b5a Change-Id: I7ee6dd4e989c85fe18221f51a998ae1c25221800 --- .../tests/benchmark/buffer_benchmarks.cc | 52 ++++++++++++++++--- .../tests/benchmark/buffer_benchmarks.rs | 30 +++++++++-- 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc index 0ead1a2926..9b31993809 100644 --- a/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc @@ -16,16 +16,17 @@ #include #include +constexpr AHardwareBuffer_Desc k720pDesc = {.width = 1280, + .height = 720, + .layers = 1, + .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + .stride = 0}; + static void BM_BufferAllocationDeallocation(benchmark::State& state) { - AHardwareBuffer_Desc buffer_desc = {.width = 1280, - .height = 720, - .layers = 1, - .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, - .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, - .stride = 0}; AHardwareBuffer* buffer = nullptr; for (auto _ : state) { - int status = AHardwareBuffer_allocate(&buffer_desc, &buffer); + int status = AHardwareBuffer_allocate(&k720pDesc, &buffer); if (UNLIKELY(status != 0)) { state.SkipWithError("Unable to allocate buffer."); } @@ -35,4 +36,39 @@ static void BM_BufferAllocationDeallocation(benchmark::State& state) { } BENCHMARK(BM_BufferAllocationDeallocation); -BENCHMARK_MAIN(); \ No newline at end of file +static void BM_AHardwareBuffer_Id(benchmark::State& state) { + AHardwareBuffer* buffer = nullptr; + int status = AHardwareBuffer_allocate(&k720pDesc, &buffer); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to allocate buffer."); + } + + for (auto _ : state) { + uint64_t id = 0; + int status = AHardwareBuffer_getId(buffer, &id); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to get ID."); + } + } + + AHardwareBuffer_release(buffer); +} +BENCHMARK(BM_AHardwareBuffer_Id); + +static void BM_AHardwareBuffer_Desc(benchmark::State& state) { + AHardwareBuffer* buffer = nullptr; + int status = AHardwareBuffer_allocate(&k720pDesc, &buffer); + if (UNLIKELY(status != 0)) { + state.SkipWithError("Unable to allocate buffer."); + } + + for (auto _ : state) { + AHardwareBuffer_Desc desc = {}; + AHardwareBuffer_describe(buffer, &desc); + } + + AHardwareBuffer_release(buffer); +} +BENCHMARK(BM_AHardwareBuffer_Desc); + +BENCHMARK_MAIN(); diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs index 3ef0f5e8c7..fbd49c0b50 100644 --- a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs +++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs @@ -20,20 +20,40 @@ use criterion::*; use nativewindow::*; -fn allocate_deallocate() { - let buffer = AHardwareBuffer::new( +#[inline] +fn create_720p_buffer() -> AHardwareBuffer { + AHardwareBuffer::new( 1280, 720, 1, AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, ) - .unwrap(); - drop(buffer); + .unwrap() } fn criterion_benchmark(c: &mut Criterion) { - c.bench_function("allocate_deallocate", |b| b.iter(allocate_deallocate)); + c.bench_function("allocate_deallocate", |b| { + b.iter(|| { + let buffer = create_720p_buffer(); + drop(buffer); + }) + }); + + let buffer = create_720p_buffer(); + c.bench_with_input(BenchmarkId::new("id", "buffer"), &buffer, |b, buffer| { + b.iter(|| { + buffer.id(); + }) + }); + + // This benchmark exercises getters that need to fetch data via an + // underlying call to AHardwareBuffer_describe. + c.bench_with_input(BenchmarkId::new("desc", "buffer"), &buffer, |b, buffer| { + b.iter(|| { + buffer.width(); + }) + }); } criterion_group!(benches, criterion_benchmark); -- GitLab From ca7ea7b97a4b99b964e9e5f8245ab81e92bd9524 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Thu, 7 Sep 2023 13:59:24 -0400 Subject: [PATCH 0784/1187] Add a flag for multithreaded present Bug: 259132483 Test: presubmit Change-Id: I4fb618487f0a2895bd8f41aca7e3e44f0b1816ec --- services/surfaceflinger/surfaceflinger_flags.aconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig index becbb87bc9..5a277bdc89 100644 --- a/services/surfaceflinger/surfaceflinger_flags.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags.aconfig @@ -45,3 +45,11 @@ flag { description: "This flag is guarding the behaviour where SurfaceFlinger is trying to opportunistically present a frame when the configuration change from late to early" bug: "273702768" } + +flag { + name: "multithreaded_present" + namespace: "core_graphics" + description: "Controls whether to offload present calls to another thread" + bug: "259132483" + is_fixed_read_only: true +} -- GitLab From 380ac3eb49975b15c75370ff8b8d0d3a0751071c Mon Sep 17 00:00:00 2001 From: Sally Qi Date: Tue, 10 Oct 2023 20:27:02 +0000 Subject: [PATCH 0785/1187] Fix green line issue when playing 1080p HDR video on Youtube. Relnote: We should also take the filtering of the inverse of the layer transform into consideration. Bug: 293552208 Change-Id: I776445a9e0466c200b59a0f466c799d57573bcd9 Test: play with youtube --- services/surfaceflinger/LayerFE.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp index 48a9190794..f25619a6c0 100644 --- a/services/surfaceflinger/LayerFE.cpp +++ b/services/surfaceflinger/LayerFE.cpp @@ -247,10 +247,13 @@ void LayerFE::prepareBufferStateClientComposition( layerSettings.frameNumber = mSnapshot->frameNumber; layerSettings.bufferId = mSnapshot->externalTexture->getId(); + const bool useFiltering = targetSettings.needsFiltering || + mSnapshot->geomLayerTransform.needsBilinearFiltering(); + // Query the texture matrix given our current filtering mode. float textureMatrix[16]; getDrawingTransformMatrix(layerSettings.source.buffer.buffer, mSnapshot->geomContentCrop, - mSnapshot->geomBufferTransform, targetSettings.needsFiltering, + mSnapshot->geomBufferTransform, useFiltering, textureMatrix); if (mSnapshot->geomBufferUsesDisplayInverseTransform) { @@ -301,7 +304,7 @@ void LayerFE::prepareBufferStateClientComposition( mat4::translate(vec4(translateX, translateY, 0.f, 1.f)) * mat4::scale(vec4(scaleWidth, scaleHeight, 1.0f, 1.0f)); - layerSettings.source.buffer.useTextureFiltering = targetSettings.needsFiltering; + layerSettings.source.buffer.useTextureFiltering = useFiltering; layerSettings.source.buffer.textureTransform = mat4(static_cast(textureMatrix)) * tr; -- GitLab From 70a2438d62df10c32897ab6bd191e372a618af78 Mon Sep 17 00:00:00 2001 From: Jim Shargo Date: Tue, 10 Oct 2023 21:49:34 +0000 Subject: [PATCH 0786/1187] git: Add "**/target" to gitignore This is an annoying artifact generated sometimes by working in rust. It can interfere with git operations and we shouldn't let it be committed. Other packages have similar rules, so this should be OK. Test: n/a Change-Id: I5f166dadb81d246c6d2a587a68299999db91cc11 --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index ed653c6b4a..1ad8a24a4b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ .idea/ .vscode/ *.code-workspace + +# Rust artifacts +**/target/ -- GitLab From 1a352b5a4afd1a128f295e9abbc660566f8afaab Mon Sep 17 00:00:00 2001 From: jiayongqiang Date: Wed, 11 Oct 2023 20:36:40 +0800 Subject: [PATCH 0787/1187] Remove unnecessary local variant definitation. 'Vector displays' has been not used in the approach of SurfaceFlinger::initializeDisplays(), so just remove it. Test: atest SurfaceFlinger_InitializeDisplaysTest Change-Id: I6bb063ccef487ab23bc97e72e342353bdcaea748 Signed-off-by: jiayongqiang --- services/surfaceflinger/SurfaceFlinger.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ee3505d7c8..343a1db265 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5438,7 +5438,6 @@ void SurfaceFlinger::initializeDisplays() { state.id = transactionId; // reset screen orientation and use primary layer stack - Vector displays; DisplayState d; d.what = DisplayState::eDisplayProjectionChanged | DisplayState::eLayerStackChanged; -- GitLab From 43bddb630f6c8aa743ba366d730058a10c18bb6d Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Fri, 1 Sep 2023 16:43:09 +0100 Subject: [PATCH 0788/1187] Support AIDL serializing and deserializing Rust HardwareBuffer. Bug: 295245772 Test: Built a simple binary depending on it. Change-Id: I64856b6063fd0e0ffe9f3bd1f066a73fbeffdb32 --- libs/binder/rust/src/lib.rs | 1 + libs/nativewindow/rust/Android.bp | 42 ++++++- libs/nativewindow/rust/src/lib.rs | 107 ++++++++++++++++-- .../rust/sys/nativewindow_bindings.h | 1 + 4 files changed, 140 insertions(+), 11 deletions(-) diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs index 8841fe640b..ed870b6d8c 100644 --- a/libs/binder/rust/src/lib.rs +++ b/libs/binder/rust/src/lib.rs @@ -144,6 +144,7 @@ pub mod binder_impl { #[doc(hidden)] pub mod unstable_api { pub use crate::binder::AsNative; + pub use crate::error::status_result; pub use crate::proxy::unstable_api::new_spibinder; pub use crate::sys::AIBinder; pub use crate::sys::AParcel; diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp index dc1575ca33..90d0a8e400 100644 --- a/libs/nativewindow/rust/Android.bp +++ b/libs/nativewindow/rust/Android.bp @@ -19,7 +19,7 @@ package { } rust_bindgen { - name: "libnativewindow_bindgen", + name: "libnativewindow_bindgen_internal", crate_name: "nativewindow_bindgen", wrapper_src: "sys/nativewindow_bindings.h", source_stem: "bindings", @@ -28,13 +28,21 @@ rust_bindgen { "--bitfield-enum=AHardwareBuffer_UsageFlags", "--allowlist-file=.*/nativewindow/include/.*\\.h", + "--blocklist-type", + "AParcel", + "--raw-line", + "use binder::unstable_api::AParcel;", "--with-derive-eq", "--with-derive-partialeq", ], shared_libs: [ + "libbinder_ndk", "libnativewindow", ], + rustlibs: [ + "libbinder_rs", + ], // Currently necessary for host builds // TODO(b/31559095): bionic on host should define this @@ -44,12 +52,40 @@ rust_bindgen { }, }, min_sdk_version: "VanillaIceCream", + vendor_available: true, +} + +rust_library { + name: "libnativewindow_bindgen", + crate_name: "nativewindow_bindgen", + srcs: [":libnativewindow_bindgen_internal"], + shared_libs: [ + "libbinder_ndk", + "libnativewindow", + ], + rustlibs: [ + "libbinder_rs", + ], + lints: "none", + clippy_lints: "none", + // Currently necessary for host builds + // TODO(b/31559095): bionic on host should define this + target: { + darwin: { + enabled: false, + }, + }, + min_sdk_version: "VanillaIceCream", + vendor_available: true, } rust_test { name: "libnativewindow_bindgen_test", - srcs: [":libnativewindow_bindgen"], + srcs: [":libnativewindow_bindgen_internal"], crate_name: "nativewindow_bindgen_test", + rustlibs: [ + "libbinder_rs", + ], test_suites: ["general-tests"], auto_gen_config: true, clippy_lints: "none", @@ -60,6 +96,7 @@ rust_defaults { name: "libnativewindow_defaults", srcs: ["src/lib.rs"], rustlibs: [ + "libbinder_rs", "libnativewindow_bindgen", ], } @@ -77,6 +114,7 @@ rust_library { }, }, min_sdk_version: "VanillaIceCream", + vendor_available: true, } rust_test { diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs index 6eb3bbcdb3..6f86c4a48f 100644 --- a/libs/nativewindow/rust/src/lib.rs +++ b/libs/nativewindow/rust/src/lib.rs @@ -16,13 +16,22 @@ extern crate nativewindow_bindgen as ffi; -pub use ffi::{AHardwareBuffer, AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; - +pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; + +use binder::{ + binder_impl::{ + BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, + SerializeArray, SerializeOption, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG, + }, + unstable_api::{status_result, AsNative}, + StatusCode, +}; +use ffi::{AHardwareBuffer, AHardwareBuffer_readFromParcel, AHardwareBuffer_writeToParcel}; use std::fmt::{self, Debug, Formatter}; use std::mem::ManuallyDrop; -use std::ptr::{self, NonNull}; +use std::ptr::{self, null_mut, NonNull}; -/// Wrapper around an opaque C AHardwareBuffer. +/// Wrapper around an opaque C `AHardwareBuffer`. #[derive(PartialEq, Eq)] pub struct HardwareBuffer(NonNull); @@ -120,8 +129,11 @@ impl HardwareBuffer { /// Available since API level 31. pub fn id(&self) -> u64 { let mut out_id = 0; - // SAFETY: Neither pointers can be null. - let status = unsafe { ffi::AHardwareBuffer_getId(self.0.as_ref(), &mut out_id) }; + // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid + // because it must have been allocated by `AHardwareBuffer_allocate`, + // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet + // released it. The id pointer must be valid because it comes from a reference. + let status = unsafe { ffi::AHardwareBuffer_getId(self.0.as_ptr(), &mut out_id) }; assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}"); out_id @@ -176,9 +188,10 @@ impl HardwareBuffer { impl Drop for HardwareBuffer { fn drop(&mut self) { - // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have - // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw - // pointer requiring callers to ensure the refcount is managed appropriately. + // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid + // because it must have been allocated by `AHardwareBuffer_allocate`, + // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet + // released it. unsafe { ffi::AHardwareBuffer_release(self.0.as_ptr()) } } } @@ -197,6 +210,82 @@ impl Clone for HardwareBuffer { } } +impl Serialize for HardwareBuffer { + fn serialize(&self, parcel: &mut BorrowedParcel) -> Result<(), StatusCode> { + SerializeOption::serialize_option(Some(self), parcel) + } +} + +impl SerializeOption for HardwareBuffer { + fn serialize_option( + this: Option<&Self>, + parcel: &mut BorrowedParcel, + ) -> Result<(), StatusCode> { + if let Some(this) = this { + parcel.write(&NON_NULL_PARCELABLE_FLAG)?; + + let status = + // SAFETY: The AHardwareBuffer pointer we pass is guaranteed to be non-null and valid + // because it must have been allocated by `AHardwareBuffer_allocate`, + // `AHardwareBuffer_readFromParcel` or the caller of `from_raw` and we have not yet + // released it. + unsafe { AHardwareBuffer_writeToParcel(this.0.as_ptr(), parcel.as_native_mut()) }; + status_result(status) + } else { + parcel.write(&NULL_PARCELABLE_FLAG) + } + } +} + +impl Deserialize for HardwareBuffer { + type UninitType = Option; + + fn uninit() -> Option { + None + } + + fn from_init(value: Self) -> Option { + Some(value) + } + + fn deserialize(parcel: &BorrowedParcel) -> Result { + DeserializeOption::deserialize_option(parcel) + .transpose() + .unwrap_or(Err(StatusCode::UNEXPECTED_NULL)) + } +} + +impl DeserializeOption for HardwareBuffer { + fn deserialize_option(parcel: &BorrowedParcel) -> Result, StatusCode> { + let present: i32 = parcel.read()?; + match present { + NULL_PARCELABLE_FLAG => Ok(None), + NON_NULL_PARCELABLE_FLAG => { + let mut buffer = null_mut(); + + let status = + // SAFETY: Both pointers must be valid because they are obtained from references. + // `AHardwareBuffer_readFromParcel` doesn't store them or do anything else special + // with them. If it returns success then it will have allocated a new + // `AHardwareBuffer` and incremented the reference count, so we can use it until we + // release it. + unsafe { AHardwareBuffer_readFromParcel(parcel.as_native(), &mut buffer) }; + + status_result(status)?; + + Ok(Some(Self(NonNull::new(buffer).expect( + "AHardwareBuffer_readFromParcel returned success but didn't allocate buffer", + )))) + } + _ => Err(StatusCode::BAD_VALUE), + } + } +} + +impl SerializeArray for HardwareBuffer {} + +impl DeserializeArray for HardwareBuffer {} + // SAFETY: The underlying *AHardwareBuffers can be moved between threads. unsafe impl Send for HardwareBuffer {} diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h index e652aee711..4525a42502 100644 --- a/libs/nativewindow/rust/sys/nativewindow_bindings.h +++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h @@ -16,5 +16,6 @@ #include #include +#include #include #include -- GitLab From 67afbeaac2c284356f2b2aa61f48258bc0758911 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Thu, 28 Sep 2023 15:35:07 -0700 Subject: [PATCH 0789/1187] Add smooth switch bool for setFrameRateCategory This allows the platform to have a different behavior depending on whether a device is MRR or dVRR. When the bool is `true`, MRR devices (those with DisplayModes that do not have vrr config) will not change frame rates if it would cause jank. The expected usage is to mark the bool true when an animation is running. Bug: 300491171 Test: atest libsurfaceflinger_unittest Change-Id: I5e87d276c11ecc806ede3e943f0a6498a7b910c4 --- libs/gui/LayerState.cpp | 7 +- libs/gui/SurfaceComposerClient.cpp | 3 +- libs/gui/include/gui/LayerState.h | 1 + libs/gui/include/gui/SurfaceComposerClient.h | 3 +- .../FrontEnd/RequestedLayerState.cpp | 1 + services/surfaceflinger/Layer.cpp | 6 +- services/surfaceflinger/Layer.h | 2 +- .../surfaceflinger/Scheduler/LayerHistory.cpp | 3 +- .../surfaceflinger/Scheduler/LayerInfo.cpp | 3 +- services/surfaceflinger/Scheduler/LayerInfo.h | 3 +- .../Scheduler/RefreshRateSelector.cpp | 30 +- .../Scheduler/RefreshRateSelector.h | 14 +- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- .../unittests/RefreshRateSelectorTest.cpp | 470 +++++++++++------- 14 files changed, 366 insertions(+), 182 deletions(-) diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 613721e103..fd8fc8d123 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -85,6 +85,7 @@ layer_state_t::layer_state_t() changeFrameRateStrategy(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS), defaultFrameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), frameRateCategory(ANATIVEWINDOW_FRAME_RATE_CATEGORY_DEFAULT), + frameRateCategorySmoothSwitchOnly(false), frameRateSelectionStrategy(ANATIVEWINDOW_FRAME_RATE_SELECTION_STRATEGY_SELF), fixedTransformHint(ui::Transform::ROT_INVALID), autoRefresh(false), @@ -162,6 +163,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeByte, changeFrameRateStrategy); SAFE_PARCEL(output.writeByte, defaultFrameRateCompatibility); SAFE_PARCEL(output.writeByte, frameRateCategory); + SAFE_PARCEL(output.writeBool, frameRateCategorySmoothSwitchOnly); SAFE_PARCEL(output.writeByte, frameRateSelectionStrategy); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeBool, autoRefresh); @@ -296,6 +298,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readByte, &changeFrameRateStrategy); SAFE_PARCEL(input.readByte, &defaultFrameRateCompatibility); SAFE_PARCEL(input.readByte, &frameRateCategory); + SAFE_PARCEL(input.readBool, &frameRateCategorySmoothSwitchOnly); SAFE_PARCEL(input.readByte, &frameRateSelectionStrategy); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); @@ -669,6 +672,7 @@ void layer_state_t::merge(const layer_state_t& other) { if (other.what & eFrameRateCategoryChanged) { what |= eFrameRateCategoryChanged; frameRateCategory = other.frameRateCategory; + frameRateCategorySmoothSwitchOnly = other.frameRateCategorySmoothSwitchOnly; } if (other.what & eFrameRateSelectionStrategyChanged) { what |= eFrameRateSelectionStrategyChanged; @@ -784,7 +788,8 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eFrameRateSelectionPriority, other, frameRateSelectionPriority); CHECK_DIFF3(diff, eFrameRateChanged, other, frameRate, frameRateCompatibility, changeFrameRateStrategy); - CHECK_DIFF(diff, eFrameRateCategoryChanged, other, frameRateCategory); + CHECK_DIFF2(diff, eFrameRateCategoryChanged, other, frameRateCategory, + frameRateCategorySmoothSwitchOnly); CHECK_DIFF(diff, eFrameRateSelectionStrategyChanged, other, frameRateSelectionStrategy); CHECK_DIFF(diff, eFixedTransformHintChanged, other, fixedTransformHint); CHECK_DIFF(diff, eAutoRefreshChanged, other, autoRefresh); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 8a57f925ec..d9d99a414e 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2098,7 +2098,7 @@ SurfaceComposerClient::Transaction::setDefaultFrameRateCompatibility(const sp& sc, int8_t category) { + const sp& sc, int8_t category, bool smoothSwitchOnly) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; @@ -2106,6 +2106,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame } s->what |= layer_state_t::eFrameRateCategoryChanged; s->frameRateCategory = category; + s->frameRateCategorySmoothSwitchOnly = smoothSwitchOnly; return *this; } diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 4371007778..d3cde74963 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -361,6 +361,7 @@ struct layer_state_t { // Frame rate category to suggest what frame rate range a surface should run. int8_t frameRateCategory; + bool frameRateCategorySmoothSwitchOnly; // Strategy of the layer for frame rate selection. int8_t frameRateSelectionStrategy; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 26b1fbd2ba..bc63c412f7 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -686,7 +686,8 @@ public: Transaction& setDefaultFrameRateCompatibility(const sp& sc, int8_t compatibility); - Transaction& setFrameRateCategory(const sp& sc, int8_t category); + Transaction& setFrameRateCategory(const sp& sc, int8_t category, + bool smoothSwitchOnly); Transaction& setFrameRateSelectionStrategy(const sp& sc, int8_t strategy); diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 168267bb50..087d7c89e4 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -124,6 +124,7 @@ RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) dimmingEnabled = true; defaultFrameRateCompatibility = static_cast(scheduler::FrameRateCompatibility::Default); frameRateCategory = static_cast(FrameRateCategory::Default); + frameRateCategorySmoothSwitchOnly = false; frameRateSelectionStrategy = static_cast(scheduler::LayerInfo::FrameRateSelectionStrategy::Self); dataspace = ui::Dataspace::V0_SRGB; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 2dc8758c3d..0c1c014640 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1334,13 +1334,15 @@ bool Layer::setFrameRate(FrameRate::FrameRateVote frameRateVote) { return true; } -bool Layer::setFrameRateCategory(FrameRateCategory category) { - if (mDrawingState.frameRate.category == category) { +bool Layer::setFrameRateCategory(FrameRateCategory category, bool smoothSwitchOnly) { + if (mDrawingState.frameRate.category == category && + mDrawingState.frameRate.categorySmoothSwitchOnly == smoothSwitchOnly) { return false; } mDrawingState.sequence++; mDrawingState.frameRate.category = category; + mDrawingState.frameRate.categorySmoothSwitchOnly = smoothSwitchOnly; mDrawingState.modified = true; updateTreeHasFrameRateVote(); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 0b66866158..1b9925539b 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -783,7 +783,7 @@ public: Rect getCroppedBufferSize(const Layer::State& s) const; bool setFrameRate(FrameRate::FrameRateVote); - bool setFrameRateCategory(FrameRateCategory); + bool setFrameRateCategory(FrameRateCategory, bool smoothSwitchOnly); bool setFrameRateSelectionStrategy(FrameRateSelectionStrategy); diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 4e5659ec5a..069d89bc42 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -194,7 +194,8 @@ auto LayerHistory::summarize(const RefreshRateSelector& selector, nsecs_t now) - to_string(vote.fps).c_str(), categoryString.c_str(), weight * 100); summary.push_back({info->getName(), info->getOwnerUid(), vote.type, vote.fps, - vote.seamlessness, vote.category, weight, layerFocused}); + vote.seamlessness, vote.category, vote.categorySmoothSwitchOnly, + weight, layerFocused}); if (CC_UNLIKELY(mTraceEnabled)) { trace(*info, vote.type, vote.fps.getIntValue()); diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index dd96930a06..36f2475d8e 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -309,7 +309,8 @@ LayerInfo::RefreshRateVotes LayerInfo::getRefreshRateVote(const RefreshRateSelec ALOGV("%s uses frame rate category: %d", mName.c_str(), static_cast(mLayerVote.category)); votes.push_back({LayerHistory::LayerVoteType::ExplicitCategory, Fps(), - Seamlessness::Default, mLayerVote.category}); + Seamlessness::Default, mLayerVote.category, + mLayerVote.categorySmoothSwitchOnly}); } if (mLayerVote.fps.isValid() || diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index d580b58f53..7d3cffabf7 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -71,8 +71,8 @@ public: LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic; Fps fps; Seamlessness seamlessness = Seamlessness::Default; - // Category is in effect if fps is not specified. FrameRateCategory category = FrameRateCategory::Default; + bool categorySmoothSwitchOnly = false; // Returns true if the layer explicitly should contribute to frame rate scoring. bool isNoVote() const { return RefreshRateSelector::isNoVote(type); } @@ -111,6 +111,7 @@ public: } vote; FrameRateCategory category = FrameRateCategory::Default; + bool categorySmoothSwitchOnly = false; FrameRate() = default; diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index b06723ddab..1d23fb5f38 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -494,6 +494,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector 0 || @@ -578,10 +582,17 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector 0; + const DisplayModeId activeModeId = activeMode.getId(); + // Only if all layers want Min we should return Min if (noVoteLayers + minVoteLayers == layers.size()) { ALOGV("All layers Min"); - const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Ascending); + const auto ranking = rankFrameRates(activeMode.getGroup(), RefreshRateOrder::Ascending, + std::nullopt, [&](FrameRateMode mode) { + return !smoothSwitchOnly || + mode.modePtr->getId() == activeModeId; + }); ATRACE_FORMAT_INSTANT("%s (All layers Min)", to_string(ranking.front().frameRateMode.fps).c_str()); return {ranking, kNoSignals}; @@ -627,6 +638,14 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vectorgetId() != activeModeId) { + ALOGV("%s ignores %s because it's non-VRR and smooth switch only." + " Current mode = %s", + formatLayerInfo(layer, weight).c_str(), to_string(*modePtr).c_str(), + to_string(activeMode).c_str()); + continue; + } + // Layers with default seamlessness vote for the current mode group if // there are layers with seamlessness=SeamedAndSeamless and for the default // mode group otherwise. In second case, if the current mode group is different @@ -770,6 +789,7 @@ auto RefreshRateSelector::getRankedFrameRatesLocked(const std::vector anchorGroupOpt, RefreshRateOrder refreshRateOrder, - std::optional preferredDisplayModeOpt) const + std::optional preferredDisplayModeOpt, + const RankFrameRatesPredicate& predicate) const -> FrameRateRanking { using fps_approx_ops::operator<; const char* const whence = __func__; @@ -1044,7 +1067,8 @@ auto RefreshRateSelector::rankFrameRates(std::optional anchorGroupOpt, std::deque ranking; const auto rankFrameRate = [&](const FrameRateMode& frameRateMode) REQUIRES(mLock) { const auto& modePtr = frameRateMode.modePtr; - if (anchorGroupOpt && modePtr->getGroup() != anchorGroupOpt) { + if ((anchorGroupOpt && modePtr->getGroup() != anchorGroupOpt) || + !predicate(frameRateMode)) { return; } diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.h b/services/surfaceflinger/Scheduler/RefreshRateSelector.h index 5d32414ee5..545b939b3d 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.h +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.h @@ -170,8 +170,11 @@ public: Fps desiredRefreshRate; // If a seamless mode switch is required. Seamlessness seamlessness = Seamlessness::Default; - // Layer frame rate category. Superseded by desiredRefreshRate. + // Layer frame rate category. FrameRateCategory frameRateCategory = FrameRateCategory::Default; + // Goes together with frame rate category vote. Allow refresh rate changes only + // if there would be no jank. + bool frameRateCategorySmoothSwitchOnly = false; // Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer // would have on choosing the refresh rate. float weight = 0.0f; @@ -446,10 +449,15 @@ private: ftl_last = Descending }; - // Only uses the primary range, not the app request range. + typedef std::function RankFrameRatesPredicate; + + // Rank the frame rates. + // Only modes in the primary range for which `predicate` is `true` will be scored. + // Does not use the app requested range. FrameRateRanking rankFrameRates( std::optional anchorGroupOpt, RefreshRateOrder refreshRateOrder, - std::optional preferredDisplayModeOpt = std::nullopt) const + std::optional preferredDisplayModeOpt = std::nullopt, + const RankFrameRatesPredicate& predicate = [](FrameRateMode) { return true; }) const REQUIRES(mLock); const Policy* getCurrentPolicyLocked() const REQUIRES(mLock); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7e799bbe30..3d3c1690a1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5228,7 +5228,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } if (what & layer_state_t::eFrameRateCategoryChanged) { const FrameRateCategory category = Layer::FrameRate::convertCategory(s.frameRateCategory); - if (layer->setFrameRateCategory(category)) { + if (layer->setFrameRateCategory(category, s.frameRateCategorySmoothSwitchOnly)) { flags |= eTraversalNeeded; } } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index 0b671376f8..faa12a1032 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -117,9 +117,9 @@ struct TestableRefreshRateSelector : RefreshRateSelector { return std::make_pair(ranking, consideredSignals); } - ftl::NonNull getBestFrameRateMode( - const std::vector& layers = {}, GlobalSignals signals = {}) const { - return getRankedFrameRates(layers, signals).ranking.front().frameRateMode.modePtr; + FrameRateMode getBestFrameRateMode(const std::vector& layers = {}, + GlobalSignals signals = {}) const { + return getRankedFrameRates(layers, signals).ranking.front().frameRateMode; } ScoredFrameRate getBestScoredFrameRate(const std::vector& layers = {}, @@ -429,11 +429,11 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_noLayers) { // If there are no layers we select the default frame rate, which is the max of the primary // range. - EXPECT_EQ(kMode90, selector.getBestFrameRateMode()); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode().modePtr); EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); - EXPECT_EQ(kMode60, selector.getBestFrameRateMode()); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode().modePtr); } { // We select max even when this will cause a non-seamless switch. @@ -442,7 +442,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_noLayers) { EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy( {kModeId90, {0_Hz, 90_Hz}, kAllowGroupSwitching})); - EXPECT_EQ(kMode90_G1, selector.getBestFrameRateMode()); + EXPECT_EQ(kMode90_G1, selector.getBestFrameRateMode().modePtr); } } @@ -455,7 +455,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_exactDontChangeRefreshRateW EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy({kModeId72, {0_Hz, 90_Hz}})); - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_60_90) { @@ -466,107 +466,107 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_60_90) { lr.vote = LayerVoteType::Min; lr.name = "Min"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; lr.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; lr.name = "45Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; lr.name = "30Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; lr.name = "24Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.name = ""; EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy({kModeId60, {60_Hz, 60_Hz}})); lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}})); lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy({kModeId60, {0_Hz, 120_Hz}})); lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_multipleThreshold_60_90) { @@ -577,32 +577,32 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_multipleThreshold_60_90) { lr.vote = LayerVoteType::Min; lr.name = "Min"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; lr.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; lr.name = "45Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; lr.name = "30Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; lr.name = "24Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_60_72_90) { @@ -612,26 +612,26 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_60_72_90) { auto& lr = layers[0]; lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_72_90_120) { @@ -645,19 +645,19 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_72_90_120) { lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 48_Hz; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 48_Hz; lr2.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes) { @@ -673,7 +673,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -681,7 +681,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -689,7 +689,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "60Hz ExplicitDefault"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -697,7 +697,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -705,7 +705,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; @@ -713,7 +713,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; @@ -721,7 +721,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -729,7 +729,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; @@ -737,7 +737,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_90_120_DifferentTypes lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.name = "90Hz ExplicitExactOrMultiple"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, @@ -756,7 +756,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -764,7 +764,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "60Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -772,7 +772,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "60Hz ExplicitDefault"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -780,7 +780,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -788,7 +788,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; @@ -796,7 +796,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::Heuristic; @@ -804,7 +804,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -812,7 +812,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitDefault; @@ -820,14 +820,14 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.name = "90Hz ExplicitExactOrMultiple"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.name = "24Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -835,7 +835,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 120_Hz; lr2.vote = LayerVoteType::ExplicitDefault; lr2.name = "120Hz ExplicitDefault"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 24_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -843,7 +843,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 120_Hz; lr2.vote = LayerVoteType::ExplicitExact; lr2.name = "120Hz ExplicitExact"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 10_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -851,7 +851,7 @@ TEST_P(RefreshRateSelectorTest, lr2.desiredRefreshRate = 120_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.name = "120Hz ExplicitExact"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); lr1.desiredRefreshRate = 30_Hz; lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -862,7 +862,7 @@ TEST_P(RefreshRateSelectorTest, lr3.vote = LayerVoteType::Heuristic; lr3.desiredRefreshRate = 120_Hz; lr3.name = "120Hz Heuristic"; - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60) { @@ -872,26 +872,26 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60) { auto& lr = layers[0]; lr.vote = LayerVoteType::Min; - EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_72_90) { @@ -902,42 +902,42 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_30_60_72_90) { lr.vote = LayerVoteType::Min; lr.name = "Min"; - EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; lr.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 90_Hz; lr.vote = LayerVoteType::Heuristic; lr.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); lr.desiredRefreshRate = 45_Hz; lr.name = "45Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); lr.desiredRefreshRate = 30_Hz; lr.name = "30Hz Heuristic"; - EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers)); - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode30, selector.getBestFrameRateMode(layers).modePtr); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); lr.desiredRefreshRate = 24_Hz; lr.name = "24Hz Heuristic"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); lr.desiredRefreshRate = 24_Hz; lr.vote = LayerVoteType::ExplicitExactOrMultiple; lr.name = "24Hz ExplicitExactOrMultiple"; - EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers)); - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode72, selector.getBestFrameRateMode(layers).modePtr); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_PriorityTest) { @@ -949,39 +949,39 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_PriorityTest) { lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::Max; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Min; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 24_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Max; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Max; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 15_Hz; lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 30_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 45_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_24FpsVideo) { @@ -993,7 +993,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_24FpsVideo) { lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { lr.desiredRefreshRate = Fps::fromValue(fps); - const auto mode = selector.getBestFrameRateMode(layers); + const auto mode = selector.getBestFrameRateMode(layers).modePtr; EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses " << to_string(mode->getPeakFps()) << "(" << to_string(mode->getVsyncRate()) << ")"; @@ -1009,7 +1009,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_24FpsVideo_multipleThreshol lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) { lr.desiredRefreshRate = Fps::fromValue(fps); - const auto mode = selector.getBestFrameRateMode(layers); + const auto mode = selector.getBestFrameRateMode(layers).modePtr; EXPECT_EQ(kMode60, mode) << lr.desiredRefreshRate << " chooses " << to_string(mode->getPeakFps()) << "(" << to_string(mode->getVsyncRate()) << ")"; @@ -1027,19 +1027,19 @@ TEST_P(RefreshRateSelectorTest, twoModes_getBestFrameRateMode_Explicit) { lr1.desiredRefreshRate = 60_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 90_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::ExplicitDefault; lr1.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::Heuristic; lr1.desiredRefreshRate = 90_Hz; lr2.vote = LayerVoteType::ExplicitExactOrMultiple; lr2.desiredRefreshRate = 60_Hz; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_75HzContent) { @@ -1051,7 +1051,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_75HzContent) { lr.vote = LayerVoteType::ExplicitExactOrMultiple; for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) { lr.desiredRefreshRate = Fps::fromValue(fps); - const auto mode = selector.getBestFrameRateMode(layers, {}); + const auto mode = selector.getBestFrameRateMode(layers, {}).modePtr; EXPECT_EQ(kMode90, mode) << lr.desiredRefreshRate << " chooses " << to_string(mode->getPeakFps()) << "(" << to_string(mode->getVsyncRate()) << ")"; @@ -1071,7 +1071,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_Multiples) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; @@ -1079,14 +1079,14 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_Multiples) { lr2.vote = LayerVoteType::ExplicitDefault; lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz ExplicitDefault"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 30_Hz; @@ -1094,14 +1094,14 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_Multiples) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 30_Hz; lr1.name = "30Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, scrollWhileWatching60fps_60_90) { @@ -1116,28 +1116,28 @@ TEST_P(RefreshRateSelectorTest, scrollWhileWatching60fps_60_90) { lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::NoVote; lr2.name = "NoVote"; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::NoVote; lr2.name = "NoVote"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); lr1.vote = LayerVoteType::ExplicitExactOrMultiple; lr1.desiredRefreshRate = 60_Hz; lr1.name = "60Hz ExplicitExactOrMultiple"; lr2.vote = LayerVoteType::Max; lr2.name = "Max"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); // The other layer starts to provide buffers lr1.vote = LayerVoteType::ExplicitExactOrMultiple; @@ -1146,7 +1146,7 @@ TEST_P(RefreshRateSelectorTest, scrollWhileWatching60fps_60_90) { lr2.vote = LayerVoteType::Heuristic; lr2.desiredRefreshRate = 90_Hz; lr2.name = "90Hz Heuristic"; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, getMaxRefreshRatesByPolicy) { @@ -1464,7 +1464,8 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_30_60 layers.push_back(layer); } - EXPECT_EQ(testCase.expectedFrameRate, selector.getBestFrameRateMode(layers)->getPeakFps()) + EXPECT_EQ(testCase.expectedFrameRate, + selector.getBestFrameRateMode(layers).modePtr->getPeakFps()) << "Did not get expected frame rate for frameRate=" << to_string(testCase.desiredFrameRate) << " category=" << ftl::enum_string(testCase.frameRateCategory); @@ -1528,13 +1529,147 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_60_12 layers.push_back(layer); } - EXPECT_EQ(testCase.expectedFrameRate, selector.getBestFrameRateMode(layers)->getPeakFps()) + EXPECT_EQ(testCase.expectedFrameRate, + selector.getBestFrameRateMode(layers).modePtr->getPeakFps()) << "Did not get expected frame rate for frameRate=" << to_string(testCase.desiredFrameRate) << " category=" << ftl::enum_string(testCase.frameRateCategory); } } +TEST_P(RefreshRateSelectorTest, + getBestFrameRateMode_withFrameRateCategory_smoothSwitchOnly_60_120_nonVrr) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + // VRR compatibility is determined by the presence of a vrr config in the DisplayMode. + auto selector = createSelector(makeModes(kMode60, kMode120), kModeId120); + + struct Case { + // Params + FrameRateCategory frameRateCategory = FrameRateCategory::Default; + bool smoothSwitchOnly = false; + + // Expected result + Fps expectedFrameRate = 0_Hz; + DisplayModeId expectedModeId = kModeId60; + }; + + const std::initializer_list testCases = { + // These layers may switch modes because smoothSwitchOnly=false. + {FrameRateCategory::Default, false, 120_Hz, kModeId120}, + // TODO(b/266481656): Once this bug is fixed, NoPreference should be a lower frame rate. + {FrameRateCategory::NoPreference, false, 60_Hz, kModeId60}, + {FrameRateCategory::Low, false, 30_Hz, kModeId60}, + {FrameRateCategory::Normal, false, 60_Hz, kModeId60}, + {FrameRateCategory::High, false, 120_Hz, kModeId120}, + + // These layers cannot change mode due to smoothSwitchOnly, and will definitely use + // active mode (120Hz). + {FrameRateCategory::NoPreference, true, 120_Hz, kModeId120}, + {FrameRateCategory::Low, true, 40_Hz, kModeId120}, + {FrameRateCategory::Normal, true, 40_Hz, kModeId120}, + {FrameRateCategory::High, true, 120_Hz, kModeId120}, + }; + + for (auto testCase : testCases) { + std::vector layers; + ALOGI("**** %s: Testing frameRateCategory=%s (smooth=%d)", __func__, + ftl::enum_string(testCase.frameRateCategory).c_str(), testCase.smoothSwitchOnly); + + if (testCase.frameRateCategory != FrameRateCategory::Default) { + std::stringstream ss; + ss << "ExplicitCategory (" << ftl::enum_string(testCase.frameRateCategory) + << " smooth:" << testCase.smoothSwitchOnly << ")"; + LayerRequirement layer = {.name = ss.str(), + .vote = LayerVoteType::ExplicitCategory, + .frameRateCategory = testCase.frameRateCategory, + .frameRateCategorySmoothSwitchOnly = + testCase.smoothSwitchOnly, + .weight = 1.f}; + layers.push_back(layer); + } + + auto actualFrameRateMode = selector.getBestFrameRateMode(layers); + EXPECT_EQ(testCase.expectedFrameRate, actualFrameRateMode.fps) + << "Did not get expected frame rate for category=" + << ftl::enum_string(testCase.frameRateCategory) + << " (smooth=" << testCase.smoothSwitchOnly << ")"; + + EXPECT_EQ(testCase.expectedModeId, actualFrameRateMode.modePtr->getId()) + << "Did not get expected mode for category=" + << ftl::enum_string(testCase.frameRateCategory) + << " (smooth=" << testCase.smoothSwitchOnly << ")"; + } +} + +TEST_P(RefreshRateSelectorTest, + getBestFrameRateMode_withFrameRateCategory_smoothSwitchOnly_60_120_vrr) { + if (GetParam() != Config::FrameRateOverride::Enabled) { + return; + } + + // VRR compatibility is determined by the presence of a vrr config in the DisplayMode. + auto selector = createSelector(kVrrModes_60_120, kModeId120); + + struct Case { + // Params + FrameRateCategory frameRateCategory = FrameRateCategory::Default; + bool smoothSwitchOnly = false; + + // Expected result + Fps expectedFrameRate = 0_Hz; + }; + + // Note that `smoothSwitchOnly` should not have an effect. + const std::initializer_list testCases = { + {FrameRateCategory::Default, false, 240_Hz}, + // TODO(b/266481656): Once this bug is fixed, NoPreference should be a lower frame rate. + {FrameRateCategory::NoPreference, false, 240_Hz}, + {FrameRateCategory::Low, false, 30_Hz}, + {FrameRateCategory::Normal, false, 60_Hz}, + {FrameRateCategory::High, false, 120_Hz}, + {FrameRateCategory::Default, true, 240_Hz}, + // TODO(b/266481656): Once this bug is fixed, NoPreference should be a lower frame rate. + {FrameRateCategory::NoPreference, true, 240_Hz}, + {FrameRateCategory::Low, true, 30_Hz}, + {FrameRateCategory::Normal, true, 60_Hz}, + {FrameRateCategory::High, true, 120_Hz}, + }; + + for (auto testCase : testCases) { + std::vector layers; + ALOGI("**** %s: Testing frameRateCategory=%s (smooth=%d)", __func__, + ftl::enum_string(testCase.frameRateCategory).c_str(), testCase.smoothSwitchOnly); + + if (testCase.frameRateCategory != FrameRateCategory::Default) { + std::stringstream ss; + ss << "ExplicitCategory (" << ftl::enum_string(testCase.frameRateCategory) + << " smooth:" << testCase.smoothSwitchOnly << ")"; + LayerRequirement layer = {.name = ss.str(), + .vote = LayerVoteType::ExplicitCategory, + .frameRateCategory = testCase.frameRateCategory, + .frameRateCategorySmoothSwitchOnly = + testCase.smoothSwitchOnly, + .weight = 1.f}; + layers.push_back(layer); + } + + auto actualFrameRateMode = selector.getBestFrameRateMode(layers); + EXPECT_EQ(testCase.expectedFrameRate, actualFrameRateMode.fps) + << "Did not get expected frame rate for category=" + << ftl::enum_string(testCase.frameRateCategory) + << " (smooth=" << testCase.smoothSwitchOnly << ")"; + + // Expect all cases to be able to stay at the mode with TE 240 due to VRR compatibility. + EXPECT_EQ(kVrrMode120TE240->getId(), actualFrameRateMode.modePtr->getId()) + << "Did not get expected mode for category=" + << ftl::enum_string(testCase.frameRateCategory) + << " (smooth=" << testCase.smoothSwitchOnly << ")"; + } +} + TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitDefault) { auto selector = createSelector(kModes_60_90_72_120, kModeId60); @@ -1568,7 +1703,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitDefault) { ss << "ExplicitDefault " << desired; lr.name = ss.str(); - const auto bestMode = selector.getBestFrameRateMode(layers); + const auto bestMode = selector.getBestFrameRateMode(layers).modePtr; EXPECT_EQ(expected, bestMode->getPeakFps()) << "expected " << expected << " for " << desired << " but got " << bestMode->getPeakFps() << "(" << bestMode->getVsyncRate() << ")"; @@ -1589,7 +1724,7 @@ TEST_P(RefreshRateSelectorTest, lr.vote = LayerVoteType::ExplicitExactOrMultiple; lr.desiredRefreshRate = 23.976_Hz; lr.name = "ExplicitExactOrMultiple 23.976 Hz"; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } // Test that 24 will choose 23.976 if 24 is not supported @@ -1600,7 +1735,7 @@ TEST_P(RefreshRateSelectorTest, lr.desiredRefreshRate = 24_Hz; lr.name = "ExplicitExactOrMultiple 24 Hz"; - EXPECT_EQ(kModeId24Frac, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId24Frac, selector.getBestFrameRateMode(layers).modePtr->getId()); } // Test that 29.97 will prefer 59.94 over 60 and 30 @@ -1611,7 +1746,7 @@ TEST_P(RefreshRateSelectorTest, lr.desiredRefreshRate = 29.97_Hz; lr.name = "ExplicitExactOrMultiple 29.97 Hz"; - EXPECT_EQ(kModeId60Frac, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60Frac, selector.getBestFrameRateMode(layers).modePtr->getId()); } // Test that 29.97 will choose 60 if 59.94 is not supported @@ -1620,7 +1755,7 @@ TEST_P(RefreshRateSelectorTest, lr.desiredRefreshRate = 29.97_Hz; lr.name = "ExplicitExactOrMultiple 29.97 Hz"; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } // Test that 59.94 will choose 60 if 59.94 is not supported @@ -1629,7 +1764,7 @@ TEST_P(RefreshRateSelectorTest, lr.desiredRefreshRate = 59.94_Hz; lr.name = "ExplicitExactOrMultiple 59.94 Hz"; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } } @@ -1648,7 +1783,8 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitExact_WithFractiona ss << "ExplicitExact " << desired; lr.name = ss.str(); - EXPECT_EQ(lr.desiredRefreshRate, selector.getBestFrameRateMode(layers)->getPeakFps()); + EXPECT_EQ(lr.desiredRefreshRate, + selector.getBestFrameRateMode(layers).modePtr->getPeakFps()); } } } @@ -1694,7 +1830,7 @@ TEST_P(RefreshRateSelectorTest, lr.desiredRefreshRate = 90_Hz; lr.name = "90Hz ExplicitDefault"; lr.focused = true; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.idle = true})); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers, {.idle = true}).modePtr); } TEST_P(RefreshRateSelectorTest, testDisplayModeOrdering) { @@ -1905,46 +2041,46 @@ TEST_P(RefreshRateSelectorTest, lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz ExplicitExactOrMultiple"; lr.focused = false; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.focused = true; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::ExplicitDefault; lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz ExplicitDefault"; lr.focused = false; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.focused = true; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Heuristic; lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Heuristic"; lr.focused = false; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.focused = true; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Max; lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Max"; lr.focused = false; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.focused = true; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.vote = LayerVoteType::Min; lr.desiredRefreshRate = 60_Hz; lr.name = "60Hz Min"; lr.focused = false; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); lr.focused = true; - EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode90, selector.getBestFrameRateMode(layers).modePtr); } TEST_P(RefreshRateSelectorTest, groupSwitchingNotAllowed) { @@ -1960,7 +2096,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingNotAllowed) { layer.name = "90Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayer) { @@ -1978,7 +2114,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayer) { layer.seamlessness = Seamlessness::SeamedAndSeamless; layer.name = "90Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayerOnlySeamless) { @@ -1997,7 +2133,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayerOnlySeamless) { layer.seamlessness = Seamlessness::OnlySeamless; layer.name = "90Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps) { @@ -2018,7 +2154,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayerOnlySeamlessDefaultFps layer.seamlessness = Seamlessness::OnlySeamless; layer.name = "60Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayerDefaultSeamlessness) { @@ -2042,7 +2178,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithOneLayerDefaultSeamlessness) { layer.name = "60Hz ExplicitDefault"; layer.focused = true; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed) { @@ -2071,7 +2207,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithTwoLayersOnlySeamlessAndSeamed layers[1].name = "90Hz ExplicitDefault"; layers[1].focused = false; - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeamed) { @@ -2104,7 +2240,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithTwoLayersDefaultFocusedAndSeam layers[1].vote = LayerVoteType::ExplicitDefault; layers[1].name = "90Hz ExplicitDefault"; - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndSeamed) { @@ -2134,7 +2270,7 @@ TEST_P(RefreshRateSelectorTest, groupSwitchingWithTwoLayersDefaultNotFocusedAndS layers[1].vote = LayerVoteType::ExplicitDefault; layers[1].name = "90Hz ExplicitDefault"; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, nonSeamlessVotePrefersSeamlessSwitches) { @@ -2154,10 +2290,10 @@ TEST_P(RefreshRateSelectorTest, nonSeamlessVotePrefersSeamlessSwitches) { layer.name = "60Hz ExplicitExactOrMultiple"; layer.focused = true; - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode(layers).modePtr->getId()); selector.setActiveMode(kModeId120, 120_Hz); - EXPECT_EQ(kModeId120, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId120, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, nonSeamlessExactAndSeamlessMultipleLayers) { @@ -2182,14 +2318,14 @@ TEST_P(RefreshRateSelectorTest, nonSeamlessExactAndSeamlessMultipleLayers) { .weight = 1.f, .focused = true}}; - EXPECT_EQ(kModeId50, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId50, selector.getBestFrameRateMode(layers).modePtr->getId()); auto& seamedLayer = layers[0]; seamedLayer.desiredRefreshRate = 30_Hz; seamedLayer.name = "30Hz ExplicitDefault"; selector.setActiveMode(kModeId30, 30_Hz); - EXPECT_EQ(kModeId25, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId25, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, minLayersDontTrigerSeamedSwitch) { @@ -2204,7 +2340,7 @@ TEST_P(RefreshRateSelectorTest, minLayersDontTrigerSeamedSwitch) { std::vector layers = { {.name = "Min", .vote = LayerVoteType::Min, .weight = 1.f, .focused = true}}; - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers)->getId()); + EXPECT_EQ(kModeId90, selector.getBestFrameRateMode(layers).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, primaryVsAppRequestPolicy) { @@ -2225,7 +2361,7 @@ TEST_P(RefreshRateSelectorTest, primaryVsAppRequestPolicy) { layers[0].vote = voteType; layers[0].desiredRefreshRate = fps; layers[0].focused = args.focused; - return selector.getBestFrameRateMode(layers, {.touch = args.touch})->getId(); + return selector.getBestFrameRateMode(layers, {.touch = args.touch}).modePtr->getId(); }; constexpr FpsRange k30_60 = {30_Hz, 60_Hz}; @@ -2234,7 +2370,7 @@ TEST_P(RefreshRateSelectorTest, primaryVsAppRequestPolicy) { EXPECT_EQ(SetPolicyResult::Changed, selector.setDisplayManagerPolicy({kModeId60, {k30_60, k30_60}, {k30_90, k30_90}})); - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode()->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode().modePtr->getId()); EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::NoVote, 90_Hz)); EXPECT_EQ(kModeId30, getFrameRate(LayerVoteType::Min, 90_Hz)); EXPECT_EQ(kModeId60, getFrameRate(LayerVoteType::Max, 90_Hz)); @@ -2302,7 +2438,8 @@ TEST_P(RefreshRateSelectorTest, idle) { } // With no layers, idle should still be lower priority than touch boost. - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode({}, {.touch = true, .idle = true})->getId()); + EXPECT_EQ(kModeId90, + selector.getBestFrameRateMode({}, {.touch = true, .idle = true}).modePtr->getId()); // Idle should be higher precedence than other layer frame rate considerations. selector.setActiveMode(kModeId90, 90_Hz); @@ -2319,7 +2456,7 @@ TEST_P(RefreshRateSelectorTest, idle) { } // Idle should be applied rather than the active mode when there are no layers. - EXPECT_EQ(kModeId60, selector.getBestFrameRateMode({}, {.idle = true})->getId()); + EXPECT_EQ(kModeId60, selector.getBestFrameRateMode({}, {.idle = true}).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, findClosestKnownFrameRate) { @@ -2368,7 +2505,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_KnownFrameRate) { for (const auto& [fps, mode] : knownFrameRatesExpectations) { layer.desiredRefreshRate = fps; - EXPECT_EQ(mode, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(mode, selector.getBestFrameRateMode(layers).modePtr); } } @@ -2471,17 +2608,17 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_ExplicitExactTouchBoost) { explicitExactLayer.name = "ExplicitExact"; explicitExactLayer.desiredRefreshRate = 30_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); if (GetParam() == Config::FrameRateOverride::Disabled) { - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); } else { - EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode120, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); } explicitExactOrMultipleLayer.vote = LayerVoteType::NoVote; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers, {.touch = true})); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers, {.touch = true}).modePtr); } TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_FractionalRefreshRates_ExactAndDefault) { @@ -2499,7 +2636,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_FractionalRefreshRates_Exac explicitDefaultLayer.name = "ExplicitDefault"; explicitDefaultLayer.desiredRefreshRate = 59.94_Hz; - EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers)); + EXPECT_EQ(kMode60, selector.getBestFrameRateMode(layers).modePtr); } // b/190578904 @@ -2526,7 +2663,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withCloseRefreshRates) { layers[0].desiredRefreshRate = fps; layers[0].vote = vote; EXPECT_EQ(fps.getIntValue(), - selector.getBestFrameRateMode(layers)->getPeakFps().getIntValue()) + selector.getBestFrameRateMode(layers).modePtr->getPeakFps().getIntValue()) << "Failed for " << ftl::enum_string(vote); }; @@ -2565,7 +2702,7 @@ TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_conflictingVotes) { }, }; - EXPECT_EQ(53_Hz, selector.getBestFrameRateMode(layers, globalSignals)->getPeakFps()); + EXPECT_EQ(53_Hz, selector.getBestFrameRateMode(layers, globalSignals).modePtr->getPeakFps()); } TEST_P(RefreshRateSelectorTest, modeComparison) { @@ -3176,7 +3313,8 @@ TEST_P(RefreshRateSelectorTest, idleWhenLowestRefreshRateIsNotDivisor) { selector.setDisplayManagerPolicy({kModeId60, {0_Hz, 90_Hz}})); // With no layers, idle should still be lower priority than touch boost. - EXPECT_EQ(kModeId90, selector.getBestFrameRateMode({}, {.touch = true, .idle = true})->getId()); + EXPECT_EQ(kModeId90, + selector.getBestFrameRateMode({}, {.touch = true, .idle = true}).modePtr->getId()); // Idle should be higher precedence than other layer frame rate considerations. selector.setActiveMode(kModeId90, 90_Hz); @@ -3192,7 +3330,7 @@ TEST_P(RefreshRateSelectorTest, idleWhenLowestRefreshRateIsNotDivisor) { } // Idle should be applied rather than the active mode when there are no layers. - EXPECT_EQ(kModeId35, selector.getBestFrameRateMode({}, {.idle = true})->getId()); + EXPECT_EQ(kModeId35, selector.getBestFrameRateMode({}, {.idle = true}).modePtr->getId()); } TEST_P(RefreshRateSelectorTest, policyCanBeInfinity) { -- GitLab From 8f285d987a63ecb3c132b06a14bd5bf63aa72fd8 Mon Sep 17 00:00:00 2001 From: Mark Wheatley Date: Fri, 7 Jul 2023 20:07:18 +0000 Subject: [PATCH 0790/1187] Add HAL Bypass Data Injection mode to Sensor Service Add a new mode, HAL_BYPASS_REPLAY_DATA_INJECTION, which behaves similar to Replay Data Injection with the difference that injected sensor data is not injected into the HAL but simply passed back up to clients in the platform. Also, while I was in there, hook up the remaining bits and bobs to get Replay Data Injection working and accessible from APIs in SystemSensorManager in the platform. Bug: 287257057 Test: manual Change-Id: I9fc33a8bf5b67c02483089f849ba7ff0346d8097 (cherry picked from commit b0df44e2a6a40fb70a6e98a1e4e629945995a5f6) --- libs/sensor/ISensorServer.cpp | 28 ++++++++++ libs/sensor/SensorManager.cpp | 16 ++++++ libs/sensor/include/sensor/ISensorServer.h | 2 + libs/sensor/include/sensor/SensorManager.h | 2 + services/sensorservice/SensorDevice.cpp | 64 ++++++++++++++++++++-- services/sensorservice/SensorDevice.h | 9 +++ services/sensorservice/SensorService.cpp | 56 +++++++++++++++---- services/sensorservice/SensorService.h | 9 +++ 8 files changed, 168 insertions(+), 18 deletions(-) diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp index 634d35a5b8..12f600e97e 100644 --- a/libs/sensor/ISensorServer.cpp +++ b/libs/sensor/ISensorServer.cpp @@ -43,6 +43,8 @@ enum { CREATE_SENSOR_DIRECT_CONNECTION, SET_OPERATION_PARAMETER, GET_RUNTIME_SENSOR_LIST, + ENABLE_REPLAY_DATA_INJECTION, + ENABLE_HAL_BYPASS_REPLAY_DATA_INJECTION, }; class BpSensorServer : public BpInterface @@ -162,6 +164,20 @@ public: return reply.readInt32(); } + virtual int isReplayDataInjectionEnabled() { + Parcel data, reply; + data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); + remote()->transact(ENABLE_REPLAY_DATA_INJECTION, data, &reply); + return reply.readInt32(); + } + + virtual int isHalBypassReplayDataInjectionEnabled() { + Parcel data, reply; + data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); + remote()->transact(ENABLE_HAL_BYPASS_REPLAY_DATA_INJECTION, data, &reply); + return reply.readInt32(); + } + virtual sp createSensorDirectConnection(const String16& opPackageName, int deviceId, uint32_t size, int32_t type, int32_t format, const native_handle_t *resource) { @@ -237,6 +253,18 @@ status_t BnSensorServer::onTransact( reply->writeInt32(static_cast(ret)); return NO_ERROR; } + case ENABLE_REPLAY_DATA_INJECTION: { + CHECK_INTERFACE(ISensorServer, data, reply); + int32_t ret = isReplayDataInjectionEnabled(); + reply->writeInt32(static_cast(ret)); + return NO_ERROR; + } + case ENABLE_HAL_BYPASS_REPLAY_DATA_INJECTION: { + CHECK_INTERFACE(ISensorServer, data, reply); + int32_t ret = isHalBypassReplayDataInjectionEnabled(); + reply->writeInt32(static_cast(ret)); + return NO_ERROR; + } case GET_DYNAMIC_SENSOR_LIST: { CHECK_INTERFACE(ISensorServer, data, reply); const String16& opPackageName = data.readString16(); diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp index 980f8d16d2..3ed8c8ac26 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -310,6 +310,22 @@ bool SensorManager::isDataInjectionEnabled() { return false; } +bool SensorManager::isReplayDataInjectionEnabled() { + Mutex::Autolock _l(mLock); + if (assertStateLocked() == NO_ERROR) { + return mSensorServer->isReplayDataInjectionEnabled(); + } + return false; +} + +bool SensorManager::isHalBypassReplayDataInjectionEnabled() { + Mutex::Autolock _l(mLock); + if (assertStateLocked() == NO_ERROR) { + return mSensorServer->isHalBypassReplayDataInjectionEnabled(); + } + return false; +} + int SensorManager::createDirectChannel( size_t size, int channelType, const native_handle_t *resourceHandle) { static constexpr int DEFAULT_DEVICE_ID = 0; diff --git a/libs/sensor/include/sensor/ISensorServer.h b/libs/sensor/include/sensor/ISensorServer.h index 58157280b1..00bc1d68b8 100644 --- a/libs/sensor/include/sensor/ISensorServer.h +++ b/libs/sensor/include/sensor/ISensorServer.h @@ -48,6 +48,8 @@ public: virtual sp createSensorEventConnection(const String8& packageName, int mode, const String16& opPackageName, const String16& attributionTag) = 0; virtual int32_t isDataInjectionEnabled() = 0; + virtual int32_t isReplayDataInjectionEnabled() = 0; + virtual int32_t isHalBypassReplayDataInjectionEnabled() = 0; virtual sp createSensorDirectConnection(const String16& opPackageName, int deviceId, uint32_t size, int32_t type, int32_t format, diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h index bb44cb8869..64b4501868 100644 --- a/libs/sensor/include/sensor/SensorManager.h +++ b/libs/sensor/include/sensor/SensorManager.h @@ -65,6 +65,8 @@ public: sp createEventQueue( String8 packageName = String8(""), int mode = 0, String16 attributionTag = String16("")); bool isDataInjectionEnabled(); + bool isReplayDataInjectionEnabled(); + bool isHalBypassReplayDataInjectionEnabled(); int createDirectChannel(size_t size, int channelType, const native_handle_t *channelData); int createDirectChannel( int deviceId, size_t size, int channelType, const native_handle_t *channelData); diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index 3155b4ceaf..c86022e748 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -37,6 +37,8 @@ #include #include #include +#include +#include using namespace android::hardware::sensors; using android::util::ProtoOutputStream; @@ -352,13 +354,17 @@ ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) { if (mHalWrapper == nullptr) return NO_INIT; ssize_t eventsRead = 0; - if (mHalWrapper->supportsMessageQueues()) { - eventsRead = mHalWrapper->pollFmq(buffer, count); - } else if (mHalWrapper->supportsPolling()) { - eventsRead = mHalWrapper->poll(buffer, count); + if (mInHalBypassMode) [[unlikely]] { + eventsRead = getHalBypassInjectedEvents(buffer, count); } else { - ALOGE("Must support polling or FMQ"); - eventsRead = -1; + if (mHalWrapper->supportsMessageQueues()) { + eventsRead = mHalWrapper->pollFmq(buffer, count); + } else if (mHalWrapper->supportsPolling()) { + eventsRead = mHalWrapper->poll(buffer, count); + } else { + ALOGE("Must support polling or FMQ"); + eventsRead = -1; + } } if (eventsRead > 0) { @@ -762,11 +768,38 @@ status_t SensorDevice::injectSensorData(const sensors_event_t* injected_sensor_e injected_sensor_event->data[2], injected_sensor_event->data[3], injected_sensor_event->data[4], injected_sensor_event->data[5]); + if (mInHalBypassMode) { + std::lock_guard _l(mHalBypassLock); + mHalBypassInjectedEventQueue.push(*injected_sensor_event); + mHalBypassCV.notify_one(); + return OK; + } return mHalWrapper->injectSensorData(injected_sensor_event); } status_t SensorDevice::setMode(uint32_t mode) { if (mHalWrapper == nullptr) return NO_INIT; + if (mode == SensorService::Mode::HAL_BYPASS_REPLAY_DATA_INJECTION) { + if (!mInHalBypassMode) { + std::lock_guard _l(mHalBypassLock); + while (!mHalBypassInjectedEventQueue.empty()) { + // flush any stale events from the injected event queue + mHalBypassInjectedEventQueue.pop(); + } + mInHalBypassMode = true; + } + return OK; + } else { + if (mInHalBypassMode) { + // We are transitioning out of HAL Bypass mode. We need to notify the reader thread + // (specifically getHalBypassInjectedEvents()) of this change in state so that it is not + // stuck waiting on more injected events to come and therefore preventing events coming + // from the HAL from being read. + std::lock_guard _l(mHalBypassLock); + mInHalBypassMode = false; + mHalBypassCV.notify_one(); + } + } return mHalWrapper->setOperationMode(static_cast(mode)); } @@ -872,5 +905,24 @@ float SensorDevice::getResolutionForSensor(int sensorHandle) { return 0; } +ssize_t SensorDevice::getHalBypassInjectedEvents(sensors_event_t* buffer, + size_t maxNumEventsToRead) { + std::unique_lock _l(mHalBypassLock); + if (mHalBypassInjectedEventQueue.empty()) { + // if the injected event queue is empty, block and wait till there are events to process + // or if we are no longer in HAL Bypass mode so that this method is not called in a tight + // loop. Otherwise, continue copying the injected events into the supplied buffer. + mHalBypassCV.wait(_l, [this] { + return (!mHalBypassInjectedEventQueue.empty() || !mInHalBypassMode); + }); + } + size_t eventsToRead = std::min(mHalBypassInjectedEventQueue.size(), maxNumEventsToRead); + for (size_t i = 0; i < eventsToRead; i++) { + buffer[i] = mHalBypassInjectedEventQueue.front(); + mHalBypassInjectedEventQueue.pop(); + } + return eventsToRead; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h index 747a6b0926..f127c0f8cd 100644 --- a/services/sensorservice/SensorDevice.h +++ b/services/sensorservice/SensorDevice.h @@ -35,6 +35,9 @@ #include #include //std::max std::min +#include +#include +#include #include #include #include @@ -225,6 +228,12 @@ private: float getResolutionForSensor(int sensorHandle); bool mIsDirectReportSupported; + + std::mutex mHalBypassLock; + std::condition_variable mHalBypassCV; + std::queue mHalBypassInjectedEventQueue; + ssize_t getHalBypassInjectedEvents(sensors_event_t* buffer, size_t count); + bool mInHalBypassMode; }; // --------------------------------------------------------------------------- diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index 9c51fd9586..44d0d708e0 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -665,6 +665,10 @@ status_t SensorService::dump(int fd, const Vector& args) { result.appendFormat(" REPLAY_DATA_INJECTION : %s\n", mAllowListedPackage.c_str()); break; + case HAL_BYPASS_REPLAY_DATA_INJECTION: + result.appendFormat(" HAL_BYPASS_REPLAY_DATA_INJECTION : %s\n", + mAllowListedPackage.c_str()); + break; default: result.appendFormat(" UNKNOWN\n"); break; @@ -1529,10 +1533,9 @@ Vector SensorService::getRuntimeSensorList(const String16& opPackageName sp SensorService::createSensorEventConnection(const String8& packageName, int requestedMode, const String16& opPackageName, const String16& attributionTag) { - // Only 3 modes supported for a SensorEventConnection ... NORMAL, DATA_INJECTION and - // REPLAY_DATA_INJECTION. - if (requestedMode != NORMAL && requestedMode != DATA_INJECTION && - requestedMode != REPLAY_DATA_INJECTION) { + // Only 4 modes supported for a SensorEventConnection ... NORMAL, DATA_INJECTION, + // REPLAY_DATA_INJECTION and HAL_BYPASS_REPLAY_DATA_INJECTION + if (requestedMode != NORMAL && !isInjectionMode(requestedMode)) { return nullptr; } resetTargetSdkVersionCache(opPackageName); @@ -1553,9 +1556,9 @@ sp SensorService::createSensorEventConnection(const Stri String16 connOpPackageName = (opPackageName == String16("")) ? String16(connPackageName) : opPackageName; sp result(new SensorEventConnection(this, uid, connPackageName, - requestedMode == DATA_INJECTION || requestedMode == REPLAY_DATA_INJECTION, - connOpPackageName, attributionTag)); - if (requestedMode == DATA_INJECTION || requestedMode == REPLAY_DATA_INJECTION) { + isInjectionMode(requestedMode), + connOpPackageName, attributionTag)); + if (isInjectionMode(requestedMode)) { mConnectionHolder.addEventConnectionIfNotPresent(result); // Add the associated file descriptor to the Looper for polling whenever there is data to // be injected. @@ -1566,7 +1569,22 @@ sp SensorService::createSensorEventConnection(const Stri int SensorService::isDataInjectionEnabled() { Mutex::Autolock _l(mLock); - return (mCurrentOperatingMode == DATA_INJECTION); + return mCurrentOperatingMode == DATA_INJECTION; +} + +int SensorService::isReplayDataInjectionEnabled() { + Mutex::Autolock _l(mLock); + return mCurrentOperatingMode == REPLAY_DATA_INJECTION; +} + +int SensorService::isHalBypassReplayDataInjectionEnabled() { + Mutex::Autolock _l(mLock); + return mCurrentOperatingMode == HAL_BYPASS_REPLAY_DATA_INJECTION; +} + +bool SensorService::isInjectionMode(int mode) { + return (mode == DATA_INJECTION || mode == REPLAY_DATA_INJECTION || + mode == HAL_BYPASS_REPLAY_DATA_INJECTION); } sp SensorService::createSensorDirectConnection( @@ -2332,6 +2350,10 @@ bool SensorService::getTargetOperatingMode(const std::string &inputString, Mode *targetModeOut = REPLAY_DATA_INJECTION; return true; } + if (inputString == std::string("hal_bypass_replay_data_injection")) { + *targetModeOut = HAL_BYPASS_REPLAY_DATA_INJECTION; + return true; + } return false; } @@ -2357,7 +2379,8 @@ status_t SensorService::changeOperatingMode(const Vector& args, dev.disableAllSensors(); } if (mCurrentOperatingMode == DATA_INJECTION || - mCurrentOperatingMode == REPLAY_DATA_INJECTION) { + mCurrentOperatingMode == REPLAY_DATA_INJECTION || + mCurrentOperatingMode == HAL_BYPASS_REPLAY_DATA_INJECTION) { resetToNormalModeLocked(); } mAllowListedPackage.clear(); @@ -2373,6 +2396,8 @@ status_t SensorService::changeOperatingMode(const Vector& args, disableAllSensorsLocked(&connLock); mAllowListedPackage = String8(args[1]); return status_t(NO_ERROR); + case HAL_BYPASS_REPLAY_DATA_INJECTION: + FALLTHROUGH_INTENDED; case REPLAY_DATA_INJECTION: if (SensorServiceUtil::isUserBuild()) { return INVALID_OPERATION; @@ -2381,9 +2406,16 @@ status_t SensorService::changeOperatingMode(const Vector& args, case DATA_INJECTION: if (mCurrentOperatingMode == NORMAL) { dev.disableAllSensors(); - // Always use DATA_INJECTION here since this value goes to the HAL and the HAL - // doesn't have an understanding of replay vs. normal data injection. - status_t err = dev.setMode(DATA_INJECTION); + status_t err = NO_ERROR; + if (targetOperatingMode == HAL_BYPASS_REPLAY_DATA_INJECTION) { + // Set SensorDevice to HAL_BYPASS_REPLAY_DATA_INJECTION_MODE. This value is not + // injected into the HAL, nor will any events be injected into the HAL + err = dev.setMode(HAL_BYPASS_REPLAY_DATA_INJECTION); + } else { + // Otherwise use DATA_INJECTION here since this value goes to the HAL and the HAL + // doesn't have an understanding of replay vs. normal data injection. + err = dev.setMode(DATA_INJECTION); + } if (err == NO_ERROR) { mCurrentOperatingMode = targetOperatingMode; } diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index bf4310119d..b643f6b382 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -122,6 +122,11 @@ public: // delivered to all requesting apps rather than just the package allowed to inject data. // This mode is only allowed to be used on development builds. REPLAY_DATA_INJECTION = 3, + // Like REPLAY_DATA_INJECTION but injected data is not sent into the HAL. It is stored in a + // buffer in SensorDevice and played back to SensorService when SensorDevice::poll() is + // called. This is useful for playing back sensor data on the platform without relying on + // the HAL to support data injection. + HAL_BYPASS_REPLAY_DATA_INJECTION = 4, // State Transitions supported. // RESTRICTED <--- NORMAL ---> DATA_INJECTION/REPLAY_DATA_INJECTION @@ -389,6 +394,8 @@ private: const String8& packageName, int requestedMode, const String16& opPackageName, const String16& attributionTag); virtual int isDataInjectionEnabled(); + virtual int isReplayDataInjectionEnabled(); + virtual int isHalBypassReplayDataInjectionEnabled(); virtual sp createSensorDirectConnection(const String16& opPackageName, int deviceId, uint32_t size, int32_t type, int32_t format, const native_handle *resource); @@ -507,6 +514,8 @@ private: // Removes the capped rate on active direct connections (when the mic toggle is flipped to off) void uncapRates(); + bool isInjectionMode(int mode); + static inline bool isAudioServerOrSystemServerUid(uid_t uid) { return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER; } -- GitLab From f1d517de5dcfe79cc874d8a976f2f72c31b2417d Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 10 Oct 2023 15:24:33 -0700 Subject: [PATCH 0791/1187] SF: compile libsurfaceflingerflags_test as test Bug: 304338314 Test: presubmit Change-Id: I63daf9be78af684db11f3c6fc6207c69bb17a865 --- services/surfaceflinger/tests/unittests/Android.bp | 3 +-- .../tests/unittests/VSyncDispatchTimerQueueTest.cpp | 8 ++------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 91910c7d64..ec21eaf488 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -45,8 +45,7 @@ filegroup { cc_aconfig_library { name: "libsurfaceflingerflags_test", aconfig_declarations: "surfaceflinger_flags", - // TODO(b/304338314): uncomment the below line once the bug is fixed - // test: true, + test: true, } cc_test { diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index a1eda949fd..b8fdce1dce 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -1065,10 +1065,8 @@ TEST_F(VSyncDispatchTimerQueueTest, updatesVsyncTimeForCloseWakeupTime) { EXPECT_THAT(cb.mReadyTime[0], Eq(2000)); } -// TODO(b/304338314): Set the flag value instead of skipping the test TEST_F(VSyncDispatchTimerQueueTest, skipAVsyc) { - // SET_FLAG_FOR_TEST(flags::dont_skip_on_early, false); - if (flags::dont_skip_on_early()) GTEST_SKIP(); + SET_FLAG_FOR_TEST(flags::dont_skip_on_early, false); EXPECT_CALL(mMockClock, alarmAt(_, 500)); CountingCallback cb(mDispatch); @@ -1088,10 +1086,8 @@ TEST_F(VSyncDispatchTimerQueueTest, skipAVsyc) { ASSERT_THAT(cb.mCalls.size(), Eq(1)); } -// TODO(b/304338314): Set the flag value instead of skipping the test TEST_F(VSyncDispatchTimerQueueTest, dontskipAVsyc) { - // SET_FLAG_FOR_TEST(flags::dont_skip_on_early, true); - if (!flags::dont_skip_on_early()) GTEST_SKIP(); + SET_FLAG_FOR_TEST(flags::dont_skip_on_early, true); EXPECT_CALL(mMockClock, alarmAt(_, 500)); CountingCallback cb(mDispatch); -- GitLab From db002509f1d9fdc34ba8fb1ba8eb15793b9c5330 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 10 Oct 2023 20:00:25 +0000 Subject: [PATCH 0792/1187] Make the boot config tests more hermetic Use a test harness to try to reset boot configs to its original state on completion. Otherwise we would be polluting the state of other tests. Ideally these tests hit a fake HWC instead and leave hitting a real HWC instance for xTS. Alas, we don't have a convenient fake set up, and the alternative is deleting these tests which is worse. Bug: 304555116 Test: SurfaceFlinger_test, followed by inputflinger_tests Change-Id: Id70d11713aca69c9da9f404060f377b2b0d2629e --- .../tests/BootDisplayMode_test.cpp | 108 ++++++++++++++---- 1 file changed, 85 insertions(+), 23 deletions(-) diff --git a/services/surfaceflinger/tests/BootDisplayMode_test.cpp b/services/surfaceflinger/tests/BootDisplayMode_test.cpp index f2874ae0e1..4f41a81011 100644 --- a/services/surfaceflinger/tests/BootDisplayMode_test.cpp +++ b/services/surfaceflinger/tests/BootDisplayMode_test.cpp @@ -28,33 +28,95 @@ namespace android { using gui::aidl_utils::statusTFromBinderStatus; -TEST(BootDisplayModeTest, setBootDisplayMode) { - sp sf(ComposerServiceAIDL::getComposerService()); - - const auto ids = SurfaceComposerClient::getPhysicalDisplayIds(); - ASSERT_FALSE(ids.empty()); - auto displayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front()); - bool bootModeSupport = false; - binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport); - ASSERT_NO_FATAL_FAILURE(statusTFromBinderStatus(status)); - if (bootModeSupport) { - status = sf->setBootDisplayMode(displayToken, 0); +struct BootDisplayModeTest : public ::testing::Test { +protected: + void SetUp() override { + mSf = ComposerServiceAIDL::getComposerService(); + + const auto ids = SurfaceComposerClient::getPhysicalDisplayIds(); + ASSERT_FALSE(ids.empty()); + mDisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front()); + bool bootModeSupport = false; + binder::Status status = mSf->getBootDisplayModeSupport(&bootModeSupport); + ASSERT_NO_FATAL_FAILURE(statusTFromBinderStatus(status)); + + if (!bootModeSupport) { + GTEST_SKIP() << "Boot mode not supported"; + } + + gui::DynamicDisplayInfo info; + status = mSf->getDynamicDisplayInfoFromToken(mDisplayToken, &info); ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); + mOldMode = info.preferredBootDisplayMode; + const auto newMode = [&]() -> std::optional { + for (const auto& mode : info.supportedDisplayModes) { + if (mode.id != mOldMode) { + return std::optional(mode.id); + } + } + return std::nullopt; + }(); + + if (!newMode) { + GTEST_SKIP() << "Only a single mode is supported"; + } + + mNewMode = *newMode; } -} -TEST(BootDisplayModeTest, clearBootDisplayMode) { - sp sf(ComposerServiceAIDL::getComposerService()); - const auto ids = SurfaceComposerClient::getPhysicalDisplayIds(); - ASSERT_FALSE(ids.empty()); - auto displayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front()); - bool bootModeSupport = false; - binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport); - ASSERT_NO_FATAL_FAILURE(statusTFromBinderStatus(status)); - if (bootModeSupport) { - status = sf->clearBootDisplayMode(displayToken); - ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); + void TearDown() override { + binder::Status status = mSf->setBootDisplayMode(mDisplayToken, mOldMode); + EXPECT_EQ(NO_ERROR, statusTFromBinderStatus(status)); + + gui::DynamicDisplayInfo info; + status = mSf->getDynamicDisplayInfoFromToken(mDisplayToken, &info); + EXPECT_EQ(NO_ERROR, statusTFromBinderStatus(status)); + EXPECT_EQ(mOldMode, info.preferredBootDisplayMode); } + + ui::DisplayModeId mOldMode; + ui::DisplayModeId mNewMode; + sp mSf; + sp mDisplayToken; +}; + +TEST_F(BootDisplayModeTest, setBootDisplayMode) { + // Set a new mode and check that it got applied + binder::Status status = mSf->setBootDisplayMode(mDisplayToken, mNewMode); + EXPECT_EQ(NO_ERROR, statusTFromBinderStatus(status)); + + gui::DynamicDisplayInfo info; + status = mSf->getDynamicDisplayInfoFromToken(mDisplayToken, &info); + EXPECT_EQ(NO_ERROR, statusTFromBinderStatus(status)); + EXPECT_EQ(mNewMode, info.preferredBootDisplayMode); +} + +TEST_F(BootDisplayModeTest, clearBootDisplayMode) { + // Clear once to figure out what the system default is + binder::Status status = mSf->clearBootDisplayMode(mDisplayToken); + EXPECT_EQ(NO_ERROR, statusTFromBinderStatus(status)); + + gui::DynamicDisplayInfo info; + status = mSf->getDynamicDisplayInfoFromToken(mDisplayToken, &info); + EXPECT_EQ(NO_ERROR, statusTFromBinderStatus(status)); + + const ui::DisplayModeId systemMode = info.preferredBootDisplayMode; + const ui::DisplayModeId newMode = systemMode == mOldMode ? mNewMode : mOldMode; + + // Now set a new mode and clear the boot mode again to figure out if the api worked. + status = mSf->setBootDisplayMode(mDisplayToken, newMode); + EXPECT_EQ(NO_ERROR, statusTFromBinderStatus(status)); + + status = mSf->getDynamicDisplayInfoFromToken(mDisplayToken, &info); + EXPECT_EQ(NO_ERROR, statusTFromBinderStatus(status)); + EXPECT_EQ(newMode, info.preferredBootDisplayMode); + + status = mSf->clearBootDisplayMode(mDisplayToken); + EXPECT_EQ(NO_ERROR, statusTFromBinderStatus(status)); + + status = mSf->getDynamicDisplayInfoFromToken(mDisplayToken, &info); + EXPECT_EQ(NO_ERROR, statusTFromBinderStatus(status)); + EXPECT_EQ(systemMode, info.preferredBootDisplayMode); } } // namespace android -- GitLab From d122a1cb046cc6ebf0aa34b91c9dca2e9741e6a8 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Sat, 30 Sep 2023 01:36:33 +0000 Subject: [PATCH 0793/1187] Add vsync rate to DisplayMode Bug: 301462354 Test: builds Test: dumpsys display Change-Id: I68bf4a12b8f730af529ea6ce1047cd294180499a --- libs/gui/SurfaceComposerClient.cpp | 1 + libs/gui/aidl/android/gui/DisplayMode.aidl | 2 ++ libs/ui/include/ui/DisplayMode.h | 4 +++- services/surfaceflinger/SurfaceFlinger.cpp | 2 ++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 8a57f925ec..f0604b9bfc 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2604,6 +2604,7 @@ void SurfaceComposerClient::getDynamicDisplayInfoInternal(gui::DynamicDisplayInf outMode.xDpi = mode.xDpi; outMode.yDpi = mode.yDpi; outMode.refreshRate = mode.refreshRate; + outMode.vsyncRate = mode.vsyncRate; outMode.appVsyncOffset = mode.appVsyncOffset; outMode.sfVsyncOffset = mode.sfVsyncOffset; outMode.presentationDeadline = mode.presentationDeadline; diff --git a/libs/gui/aidl/android/gui/DisplayMode.aidl b/libs/gui/aidl/android/gui/DisplayMode.aidl index ce30426cb5..b057653200 100644 --- a/libs/gui/aidl/android/gui/DisplayMode.aidl +++ b/libs/gui/aidl/android/gui/DisplayMode.aidl @@ -29,7 +29,9 @@ parcelable DisplayMode { float yDpi = 0.0f; int[] supportedHdrTypes; + // Some modes have peak refresh rate lower than the panel vsync rate. float refreshRate = 0.0f; + float vsyncRate = 0.0f; long appVsyncOffset = 0; long sfVsyncOffset = 0; long presentationDeadline = 0; diff --git a/libs/ui/include/ui/DisplayMode.h b/libs/ui/include/ui/DisplayMode.h index 65a8769c98..a469c78070 100644 --- a/libs/ui/include/ui/DisplayMode.h +++ b/libs/ui/include/ui/DisplayMode.h @@ -37,7 +37,9 @@ struct DisplayMode { float yDpi = 0; std::vector supportedHdrTypes; - float refreshRate = 0; + // Some modes have peak refresh rate lower than the panel vsync rate. + float refreshRate = 0.f; + float vsyncRate = 0.f; nsecs_t appVsyncOffset = 0; nsecs_t sfVsyncOffset = 0; nsecs_t presentationDeadline = 0; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7e799bbe30..e08690a2bb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1047,6 +1047,7 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info const auto peakFps = mode->getPeakFps(); outMode.refreshRate = peakFps.getValue(); + outMode.vsyncRate = mode->getVsyncRate().getValue(); const auto vsyncConfigSet = mVsyncConfiguration->getConfigsForRefreshRate(Fps::fromValue(outMode.refreshRate)); @@ -9189,6 +9190,7 @@ void SurfaceComposerAIDL::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo& outMode.xDpi = mode.xDpi; outMode.yDpi = mode.yDpi; outMode.refreshRate = mode.refreshRate; + outMode.vsyncRate = mode.vsyncRate; outMode.appVsyncOffset = mode.appVsyncOffset; outMode.sfVsyncOffset = mode.sfVsyncOffset; outMode.presentationDeadline = mode.presentationDeadline; -- GitLab From b74093a642c7d2e3f169f78ce5665eb93e8d552f Mon Sep 17 00:00:00 2001 From: Chavi Weingarten Date: Wed, 11 Oct 2023 20:29:59 +0000 Subject: [PATCH 0794/1187] Store isTrustedOverlay before returning early for hidden layers. When a layer is hidden, we will still gather input info, but not continue down the updateSnapshot method. Extracting isTrustedOverlay was happening after so if the caller was a hidden spy window that also was a trusted overlay, it would crash InputDispatcher since it would receive the hidden windowInfo data with spy but not trusted overlay. This fix moves the isTrustedOverlay extraction before the hidden check so input info will contain trusted overlay info even if the window was hidden Test: LayerSnapshotTest#setTrustedOverlayForNonVisibleInput Fixes: 304391559 Change-Id: Ie068c179635998e189814448062d86db0b089f40 --- .../surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp | 8 ++++---- .../tests/unittests/LayerHierarchyTest.h | 11 +++++++++++ .../tests/unittests/LayerSnapshotTest.cpp | 11 +++++++++++ 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 03c09932d3..4db2b669a5 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -731,6 +731,10 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a : parentSnapshot.outputFilter.layerStack; } + if (forceUpdate || snapshot.clientChanges & layer_state_t::eTrustedOverlayChanged) { + snapshot.isTrustedOverlay = parentSnapshot.isTrustedOverlay || requested.isTrustedOverlay; + } + if (snapshot.isHiddenByPolicyFromParent && !snapshot.changes.test(RequestedLayerState::Changes::Created)) { if (forceUpdate || @@ -761,10 +765,6 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a (requested.flags & layer_state_t::eLayerSkipScreenshot); } - if (forceUpdate || snapshot.clientChanges & layer_state_t::eTrustedOverlayChanged) { - snapshot.isTrustedOverlay = parentSnapshot.isTrustedOverlay || requested.isTrustedOverlay; - } - if (forceUpdate || snapshot.clientChanges & layer_state_t::eStretchChanged) { snapshot.stretchEffect = (requested.stretchEffect.hasEffect()) ? requested.stretchEffect diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index d319dcc47e..7f3171f13f 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -443,6 +443,17 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setTrustedOverlay(uint32_t id, bool isTrustedOverlay) { + std::vector transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = layer_state_t::eTrustedOverlayChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.isTrustedOverlay = isTrustedOverlay; + mLifecycleManager.applyTransactions(transactions); + } + LayerLifecycleManager mLifecycleManager; }; diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 50dfcaac5f..fc4bb229be 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -861,4 +861,15 @@ TEST_F(LayerSnapshotTest, setShadowRadius) { EXPECT_EQ(getSnapshot(1)->shadowSettings.length, SHADOW_RADIUS); } +TEST_F(LayerSnapshotTest, setTrustedOverlayForNonVisibleInput) { + hideLayer(1); + setTrustedOverlay(1, true); + Region touch{Rect{0, 0, 1000, 1000}}; + setTouchableRegion(1, touch); + + UPDATE_AND_VERIFY(mSnapshotBuilder, {2}); + EXPECT_TRUE(getSnapshot(1)->inputInfo.inputConfig.test( + gui::WindowInfo::InputConfig::TRUSTED_OVERLAY)); +} + } // namespace android::surfaceflinger::frontend -- GitLab From ed7686cc0949b90f4ce69ad66f04885a862e3173 Mon Sep 17 00:00:00 2001 From: Melody Hsu Date: Wed, 11 Oct 2023 21:02:07 +0000 Subject: [PATCH 0795/1187] [LayerTypeTransactionTest] Remove captureDisplay Replace usages of ScreenCapture#captureDisplay with ScreenCapture#captureLayers. Bug: 293445881 Test: atest LayerTypeTransactionTest Change-Id: Ib6f3db0db2bcc87ab7b41e11c77c0ec8dda98969 --- .../surfaceflinger/tests/LayerTypeTransaction_test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp index 34c918261a..f9b4bbac22 100644 --- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp +++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp @@ -167,18 +167,18 @@ TEST_P(LayerTypeTransactionTest, SetFlagsSecure) { .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure) .apply(true); - DisplayCaptureArgs args; - args.displayToken = mDisplay; + LayerCaptureArgs args; + args.layerHandle = layer->getHandle(); ScreenCaptureResults captureResults; { // Ensure the UID is not root because root has all permissions UIDFaker f(AID_APP_START); - ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(args, captureResults)); + ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(args, captureResults)); } Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true); - ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(args, captureResults)); + ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(args, captureResults)); } TEST_P(LayerTypeTransactionTest, RefreshRateIsInitialized) { -- GitLab From aa89cb795ca52069f77c79a5d3e46aed725d6b73 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Wed, 16 Aug 2023 12:52:12 -0700 Subject: [PATCH 0796/1187] Add CtsSurfaceControlTestsStaging to SF postsubmit Bug: 284911776 Test: postsubmit Change-Id: Ief5488b2954d97b031b4f14e423c8a4bebed4bf8 --- services/surfaceflinger/TEST_MAPPING | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/surfaceflinger/TEST_MAPPING b/services/surfaceflinger/TEST_MAPPING index 55127349eb..6391f5e634 100644 --- a/services/surfaceflinger/TEST_MAPPING +++ b/services/surfaceflinger/TEST_MAPPING @@ -34,5 +34,10 @@ { "name": "libscheduler_test" } + ], + "postsubmit": [ + { + "name": "CtsSurfaceControlTestsStaging" + } ] } -- GitLab From 538c8f7276bad38cd9db35382a6c4cda09c4d050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 28 Sep 2023 05:12:28 +0000 Subject: [PATCH 0797/1187] make it clear mGpuMemTotalMap is R/O MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Signed-off-by: Maciej Żenczykowski (cherry picked from https://android-review.googlesource.com/q/commit:af8d3a709b93cb2a857ff783840b3b3f1d83d16b) Merged-In: I0484c629a02b84b59ca19b35e24a6496fbfd0990 Change-Id: I0484c629a02b84b59ca19b35e24a6496fbfd0990 --- services/gpuservice/gpumem/GpuMem.cpp | 2 +- services/gpuservice/gpumem/include/gpumem/GpuMem.h | 4 ++-- services/gpuservice/tests/unittests/TestableGpuMem.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/services/gpuservice/gpumem/GpuMem.cpp b/services/gpuservice/gpumem/GpuMem.cpp index dd3cc3bd86..141fe021ee 100644 --- a/services/gpuservice/gpumem/GpuMem.cpp +++ b/services/gpuservice/gpumem/GpuMem.cpp @@ -77,7 +77,7 @@ void GpuMem::initialize() { mInitialized.store(true); } -void GpuMem::setGpuMemTotalMap(bpf::BpfMap& map) { +void GpuMem::setGpuMemTotalMap(bpf::BpfMapRO& map) { mGpuMemTotalMap = std::move(map); } diff --git a/services/gpuservice/gpumem/include/gpumem/GpuMem.h b/services/gpuservice/gpumem/include/gpumem/GpuMem.h index 7588b54818..9aa74d6863 100644 --- a/services/gpuservice/gpumem/include/gpumem/GpuMem.h +++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h @@ -44,12 +44,12 @@ private: friend class TestableGpuMem; // set gpu memory total map - void setGpuMemTotalMap(bpf::BpfMap& map); + void setGpuMemTotalMap(bpf::BpfMapRO& map); // indicate whether ebpf has been initialized std::atomic mInitialized = false; // bpf map for GPU memory total data - android::bpf::BpfMap mGpuMemTotalMap; + android::bpf::BpfMapRO mGpuMemTotalMap; // gpu memory tracepoint event category static constexpr char kGpuMemTraceGroup[] = "gpu_mem"; diff --git a/services/gpuservice/tests/unittests/TestableGpuMem.h b/services/gpuservice/tests/unittests/TestableGpuMem.h index 6c8becb075..f21843fe1a 100644 --- a/services/gpuservice/tests/unittests/TestableGpuMem.h +++ b/services/gpuservice/tests/unittests/TestableGpuMem.h @@ -28,7 +28,7 @@ public: void setInitialized() { mGpuMem->mInitialized.store(true); } - void setGpuMemTotalMap(bpf::BpfMap& map) { + void setGpuMemTotalMap(bpf::BpfMapRO& map) { mGpuMem->setGpuMemTotalMap(map); } -- GitLab From 020b29f42dd6dc62bd05f5abc958d154e05c280e Mon Sep 17 00:00:00 2001 From: Melody Hsu Date: Wed, 11 Oct 2023 21:23:44 +0000 Subject: [PATCH 0798/1187] [CredentialsTest] Remove captureDisplay Replace ScreenCapture#captureDisplay with captureLayers. CredentialsTest#CaptureLayersTest already uses captureLayers, which makes CaptureTest unncessary. Test with the full path because of multiple files with the same test name. Bug: b/293445881 Test: atest services/surfaceflinger/tests/Credentials_test.cpp Change-Id: Ief4db33ab2a437cd8aec0ee35bac60ae966a4b94 --- services/surfaceflinger/tests/Credentials_test.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index 69e9a169e3..822ac4d99f 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -275,18 +275,6 @@ TEST_F(CredentialsTest, CreateDisplayTest) { ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); } -TEST_F(CredentialsTest, CaptureTest) { - const auto display = getFirstDisplayToken(); - std::function condition = [=]() { - sp outBuffer; - DisplayCaptureArgs captureArgs; - captureArgs.displayToken = display; - ScreenCaptureResults captureResults; - return ScreenCapture::captureDisplay(captureArgs, captureResults); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); -} - TEST_F(CredentialsTest, CaptureLayersTest) { setupBackgroundSurface(); sp outBuffer; -- GitLab From f3621106fc277a0b16609927e81a47aca87c22c6 Mon Sep 17 00:00:00 2001 From: Tony Huang Date: Mon, 4 Sep 2023 17:14:22 +0800 Subject: [PATCH 0799/1187] VRR: Use appId to replace uid mapping Uid is combination of user id and app id. Because the allowlist is recored by pkg for each users. We could ignore the user id part and it also could solve the issue we didn't update the mapping when user added case. Bug: 298722189 Test: atest SmallAreaDetectionAllowMappingsTest Test: atest SmallAreaDetectionControllerTest Test: Add new user and open Youtube short to check refresh rate Change-Id: Ic80be38ebc19938bc061bf6121c68efc4ff9ac4c --- libs/gui/SurfaceComposerClient.cpp | 8 ++--- .../aidl/android/gui/ISurfaceComposer.aidl | 8 ++--- libs/gui/include/gui/SurfaceComposerClient.h | 10 +++--- libs/gui/tests/Surface_test.cpp | 4 +-- services/surfaceflinger/Layer.cpp | 3 +- services/surfaceflinger/Layer.h | 8 +++++ .../surfaceflinger/Scheduler/Scheduler.cpp | 15 ++++---- services/surfaceflinger/Scheduler/Scheduler.h | 6 ++-- .../SmallAreaDetectionAllowMappings.cpp | 12 +++---- .../SmallAreaDetectionAllowMappings.h | 10 +++--- services/surfaceflinger/SurfaceFlinger.cpp | 22 ++++++------ services/surfaceflinger/SurfaceFlinger.h | 8 ++--- .../SmallAreaDetectionAllowMappingsTest.cpp | 36 +++++++++---------- 13 files changed, 78 insertions(+), 72 deletions(-) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 4db960e7fa..d23b9e66a9 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2768,16 +2768,16 @@ status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) return statusTFromBinderStatus(status); } -status_t SurfaceComposerClient::updateSmallAreaDetection(std::vector& uids, +status_t SurfaceComposerClient::updateSmallAreaDetection(std::vector& appIds, std::vector& thresholds) { binder::Status status = - ComposerServiceAIDL::getComposerService()->updateSmallAreaDetection(uids, thresholds); + ComposerServiceAIDL::getComposerService()->updateSmallAreaDetection(appIds, thresholds); return statusTFromBinderStatus(status); } -status_t SurfaceComposerClient::setSmallAreaDetectionThreshold(uid_t uid, float threshold) { +status_t SurfaceComposerClient::setSmallAreaDetectionThreshold(int32_t appId, float threshold) { binder::Status status = - ComposerServiceAIDL::getComposerService()->setSmallAreaDetectionThreshold(uid, + ComposerServiceAIDL::getComposerService()->setSmallAreaDetectionThreshold(appId, threshold); return statusTFromBinderStatus(status); } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index 1c604a1f8b..2c8b4b83ca 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -479,14 +479,14 @@ interface ISurfaceComposer { */ void setOverrideFrameRate(int uid, float frameRate); - oneway void updateSmallAreaDetection(in int[] uids, in float[] thresholds); + oneway void updateSmallAreaDetection(in int[] appIds, in float[] thresholds); /** - * Set the small area detection threshold for a specified uid by SmallAreaDetectionController. - * Passing the threshold and uid to SurfaceFlinger to update the uid-threshold mapping + * Set the small area detection threshold for a specified appId by SmallAreaDetectionController. + * Passing the threshold and appId to SurfaceFlinger to update the appId-threshold mapping * in the scheduler. */ - oneway void setSmallAreaDetectionThreshold(int uid, float threshold); + oneway void setSmallAreaDetectionThreshold(int appId, float threshold); /** * Enables or disables the frame rate overlay in the top left corner. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 6fef5d2378..cb48807207 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -203,15 +203,15 @@ public: // by GameManager. static status_t setOverrideFrameRate(uid_t uid, float frameRate); - // Update the small area detection whole uid-threshold mappings by same size uid and threshold - // vector. + // Update the small area detection whole appId-threshold mappings by same size appId and + // threshold vector. // Ref:setSmallAreaDetectionThreshold. - static status_t updateSmallAreaDetection(std::vector& uids, + static status_t updateSmallAreaDetection(std::vector& appIds, std::vector& thresholds); - // Sets the small area detection threshold to particular apps (uid). Passing value 0 means + // Sets the small area detection threshold to particular apps (appId). Passing value 0 means // to disable small area detection to the app. - static status_t setSmallAreaDetectionThreshold(uid_t uid, float threshold); + static status_t setSmallAreaDetectionThreshold(int32_t appId, float threshold); // Switches on/off Auto Low Latency Mode on the connected display. This should only be // called if the connected display supports Auto Low Latency Mode as reported by diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index daed764cd6..edd95bad6d 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -999,12 +999,12 @@ public: binder::Status scheduleCommit() override { return binder::Status::ok(); } - binder::Status updateSmallAreaDetection(const std::vector& /*uids*/, + binder::Status updateSmallAreaDetection(const std::vector& /*appIds*/, const std::vector& /*thresholds*/) { return binder::Status::ok(); } - binder::Status setSmallAreaDetectionThreshold(int32_t /*uid*/, float /*threshold*/) { + binder::Status setSmallAreaDetectionThreshold(int32_t /*appId*/, float /*threshold*/) { return binder::Status::ok(); } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 9a5173ba9b..6b5613849a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -205,6 +205,7 @@ Layer::Layer(const surfaceflinger::LayerCreationArgs& args) mOwnerUid = args.ownerUid; mOwnerPid = args.ownerPid; + mOwnerAppId = mOwnerUid % PER_USER_RANGE; mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied); mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow; @@ -4388,7 +4389,7 @@ void Layer::setIsSmallDirty() { // If the damage region is a small dirty, this could give the hint for the layer history that // it could suppress the heuristic rate when calculating. - mSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(mOwnerUid, + mSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(mOwnerAppId, bounds.getWidth() * bounds.getHeight()); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index dc4ceb0bfa..e67a290d50 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -831,6 +831,8 @@ public: pid_t getOwnerPid() { return mOwnerPid; } + int32_t getOwnerAppId() { return mOwnerAppId; } + // This layer is not a clone, but it's the parent to the cloned hierarchy. The // variable mClonedChild represents the top layer that will be cloned so this // layer will be the parent of mClonedChild. @@ -1056,6 +1058,8 @@ protected: // If created from a system process, the value can be passed in. pid_t mOwnerPid; + int32_t mOwnerAppId; + // Keeps track of the time SF latched the last buffer from this layer. // Used in buffer stuffing analysis in FrameTimeline. nsecs_t mLastLatchTime = 0; @@ -1065,6 +1069,10 @@ protected: sp mLastClientCompositionFence; bool mClearClientCompositionFenceOnLayerDisplayed = false; private: + // Range of uids allocated for a user. + // This value is taken from android.os.UserHandle#PER_USER_RANGE. + static constexpr int32_t PER_USER_RANGE = 100000; + friend class SlotGenerationTest; friend class TransactionFrameTracerTest; friend class TransactionSurfaceFrameTest; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 27c96f7d4f..09ce9a68e8 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -1180,18 +1180,19 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid } void Scheduler::updateSmallAreaDetection( - std::vector>& uidThresholdMappings) { + std::vector>& uidThresholdMappings) { mSmallAreaDetectionAllowMappings.update(uidThresholdMappings); } -void Scheduler::setSmallAreaDetectionThreshold(uid_t uid, float threshold) { - mSmallAreaDetectionAllowMappings.setThesholdForUid(uid, threshold); +void Scheduler::setSmallAreaDetectionThreshold(int32_t appId, float threshold) { + mSmallAreaDetectionAllowMappings.setThesholdForAppId(appId, threshold); } -bool Scheduler::isSmallDirtyArea(uid_t uid, uint32_t dirtyArea) { - std::optional oThreshold = mSmallAreaDetectionAllowMappings.getThresholdForUid(uid); - if (oThreshold) return mLayerHistory.isSmallDirtyArea(dirtyArea, oThreshold.value()); - +bool Scheduler::isSmallDirtyArea(int32_t appId, uint32_t dirtyArea) { + std::optional oThreshold = mSmallAreaDetectionAllowMappings.getThresholdForAppId(appId); + if (oThreshold) { + return mLayerHistory.isSmallDirtyArea(dirtyArea, oThreshold.value()); + } return false; } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index d65df2a65d..23a21e8170 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -292,12 +292,12 @@ public: void setGameModeRefreshRateForUid(FrameRateOverride); - void updateSmallAreaDetection(std::vector>& uidThresholdMappings); + void updateSmallAreaDetection(std::vector>& uidThresholdMappings); - void setSmallAreaDetectionThreshold(uid_t uid, float threshold); + void setSmallAreaDetectionThreshold(int32_t appId, float threshold); // Returns true if the dirty area is less than threshold. - bool isSmallDirtyArea(uid_t uid, uint32_t dirtyArea); + bool isSmallDirtyArea(int32_t appId, uint32_t dirtyArea); // Retrieves the overridden refresh rate for a given uid. std::optional getFrameRateOverride(uid_t) const EXCLUDES(mDisplayLock); diff --git a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp index 95cd5d199a..38c6da48f6 100644 --- a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp +++ b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.cpp @@ -19,26 +19,26 @@ namespace android::scheduler { void SmallAreaDetectionAllowMappings::update( - std::vector>& uidThresholdMappings) { + std::vector>& appIdThresholdMappings) { std::lock_guard lock(mLock); mMap.clear(); - for (std::pair row : uidThresholdMappings) { + for (std::pair row : appIdThresholdMappings) { if (!isValidThreshold(row.second)) continue; mMap.emplace(row.first, row.second); } } -void SmallAreaDetectionAllowMappings::setThesholdForUid(uid_t uid, float threshold) { +void SmallAreaDetectionAllowMappings::setThesholdForAppId(int32_t appId, float threshold) { if (!isValidThreshold(threshold)) return; std::lock_guard lock(mLock); - mMap.emplace(uid, threshold); + mMap.emplace(appId, threshold); } -std::optional SmallAreaDetectionAllowMappings::getThresholdForUid(uid_t uid) { +std::optional SmallAreaDetectionAllowMappings::getThresholdForAppId(int32_t appId) { std::lock_guard lock(mLock); - const auto iter = mMap.find(uid); + const auto iter = mMap.find(appId); if (iter != mMap.end()) { return iter->second; } diff --git a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h index cbab69091f..e10301c1e8 100644 --- a/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h +++ b/services/surfaceflinger/Scheduler/SmallAreaDetectionAllowMappings.h @@ -24,16 +24,16 @@ namespace android::scheduler { class SmallAreaDetectionAllowMappings { - using UidThresholdMap = std::unordered_map; + using AppIdThresholdMap = std::unordered_map; public: - void update(std::vector>& uidThresholdMappings); - void setThesholdForUid(uid_t uid, float threshold) EXCLUDES(mLock); - std::optional getThresholdForUid(uid_t uid) EXCLUDES(mLock); + void update(std::vector>& appIdThresholdMappings); + void setThesholdForAppId(int32_t appId, float threshold) EXCLUDES(mLock); + std::optional getThresholdForAppId(int32_t uid) EXCLUDES(mLock); private: static bool isValidThreshold(float threshold) { return threshold >= 0.0f && threshold <= 1.0f; } mutable std::mutex mLock; - UidThresholdMap mMap GUARDED_BY(mLock); + AppIdThresholdMap mMap GUARDED_BY(mLock); }; } // namespace android::scheduler diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 38dc435357..ec3050c375 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -8157,13 +8157,13 @@ status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) { } status_t SurfaceFlinger::updateSmallAreaDetection( - std::vector>& uidThresholdMappings) { - mScheduler->updateSmallAreaDetection(uidThresholdMappings); + std::vector>& appIdThresholdMappings) { + mScheduler->updateSmallAreaDetection(appIdThresholdMappings); return NO_ERROR; } -status_t SurfaceFlinger::setSmallAreaDetectionThreshold(uid_t uid, float threshold) { - mScheduler->setSmallAreaDetectionThreshold(uid, threshold); +status_t SurfaceFlinger::setSmallAreaDetectionThreshold(int32_t appId, float threshold) { + mScheduler->setSmallAreaDetectionThreshold(appId, threshold); return NO_ERROR; } @@ -9530,18 +9530,18 @@ binder::Status SurfaceComposerAIDL::scheduleCommit() { return binder::Status::ok(); } -binder::Status SurfaceComposerAIDL::updateSmallAreaDetection(const std::vector& uids, +binder::Status SurfaceComposerAIDL::updateSmallAreaDetection(const std::vector& appIds, const std::vector& thresholds) { status_t status; const int c_uid = IPCThreadState::self()->getCallingUid(); if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) { - if (uids.size() != thresholds.size()) return binderStatusFromStatusT(BAD_VALUE); + if (appIds.size() != thresholds.size()) return binderStatusFromStatusT(BAD_VALUE); - std::vector> mappings; - const size_t size = uids.size(); + std::vector> mappings; + const size_t size = appIds.size(); mappings.reserve(size); for (int i = 0; i < size; i++) { - auto row = std::make_pair(static_cast(uids[i]), thresholds[i]); + auto row = std::make_pair(appIds[i], thresholds[i]); mappings.push_back(row); } status = mFlinger->updateSmallAreaDetection(mappings); @@ -9552,11 +9552,11 @@ binder::Status SurfaceComposerAIDL::updateSmallAreaDetection(const std::vectorgetCallingUid(); if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) { - status = mFlinger->setSmallAreaDetectionThreshold(uid, threshold); + status = mFlinger->setSmallAreaDetectionThreshold(appId, threshold); } else { ALOGE("setSmallAreaDetectionThreshold() permission denied for uid: %d", c_uid); status = PERMISSION_DENIED; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index dc4e7cf2fe..550319576b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -606,9 +606,9 @@ private: status_t setOverrideFrameRate(uid_t uid, float frameRate); - status_t updateSmallAreaDetection(std::vector>& uidThresholdMappings); + status_t updateSmallAreaDetection(std::vector>& uidThresholdMappings); - status_t setSmallAreaDetectionThreshold(uid_t uid, float threshold); + status_t setSmallAreaDetectionThreshold(int32_t appId, float threshold); int getGpuContextPriority(); @@ -1560,9 +1560,9 @@ public: binder::Status setDebugFlash(int delay) override; binder::Status scheduleComposite() override; binder::Status scheduleCommit() override; - binder::Status updateSmallAreaDetection(const std::vector& uids, + binder::Status updateSmallAreaDetection(const std::vector& appIds, const std::vector& thresholds) override; - binder::Status setSmallAreaDetectionThreshold(int32_t uid, float threshold) override; + binder::Status setSmallAreaDetectionThreshold(int32_t appId, float threshold) override; binder::Status getGpuContextPriority(int32_t* outPriority) override; binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override; binder::Status addWindowInfosListener(const sp& windowInfosListener, diff --git a/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp b/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp index b910485c06..05f9eed30b 100644 --- a/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp +++ b/services/surfaceflinger/tests/unittests/SmallAreaDetectionAllowMappingsTest.cpp @@ -23,38 +23,34 @@ namespace android::scheduler { -class SmallAreaDetectionMappingsAllowTest : public testing::Test { +class SmallAreaDetectionAllowMappingsTest : public testing::Test { protected: SmallAreaDetectionAllowMappings mMappings; + static constexpr int32_t kAppId1 = 10100; + static constexpr int32_t kAppId2 = 10101; + static constexpr float kThreshold1 = 0.05f; + static constexpr float kThreshold2 = 0.07f; }; namespace { -TEST_F(SmallAreaDetectionMappingsAllowTest, testUpdate) { - const uid_t uid1 = 10100; - const uid_t uid2 = 10101; - const float threshold1 = 0.05f; - const float threshold2 = 0.07f; - std::vector> mappings; +TEST_F(SmallAreaDetectionAllowMappingsTest, testUpdate) { + std::vector> mappings; mappings.reserve(2); - mappings.push_back(std::make_pair(uid1, threshold1)); - mappings.push_back(std::make_pair(uid2, threshold2)); + mappings.push_back(std::make_pair(kAppId1, kThreshold1)); + mappings.push_back(std::make_pair(kAppId2, kThreshold2)); mMappings.update(mappings); - ASSERT_EQ(mMappings.getThresholdForUid(uid1).value(), threshold1); - ASSERT_EQ(mMappings.getThresholdForUid(uid2).value(), threshold2); + ASSERT_EQ(mMappings.getThresholdForAppId(kAppId1).value(), kThreshold1); + ASSERT_EQ(mMappings.getThresholdForAppId(kAppId2).value(), kThreshold2); } -TEST_F(SmallAreaDetectionMappingsAllowTest, testSetThesholdForUid) { - const uid_t uid = 10111; - const float threshold = 0.05f; - - mMappings.setThesholdForUid(uid, threshold); - ASSERT_EQ(mMappings.getThresholdForUid(uid), threshold); +TEST_F(SmallAreaDetectionAllowMappingsTest, testSetThesholdForAppId) { + mMappings.setThesholdForAppId(kAppId1, kThreshold1); + ASSERT_EQ(mMappings.getThresholdForAppId(kAppId1), kThreshold1); } -TEST_F(SmallAreaDetectionMappingsAllowTest, testUidNotInTheMappings) { - const uid_t uid = 10222; - ASSERT_EQ(mMappings.getThresholdForUid(uid), std::nullopt); +TEST_F(SmallAreaDetectionAllowMappingsTest, testAppIdNotInTheMappings) { + ASSERT_EQ(mMappings.getThresholdForAppId(kAppId1), std::nullopt); } } // namespace -- GitLab From 33e7f424d7d90ffa9a01a5f31086bd029a6760fc Mon Sep 17 00:00:00 2001 From: Biswarup Pal Date: Thu, 12 Oct 2023 09:05:37 +0000 Subject: [PATCH 0800/1187] Exclude CtsHardwareTestCases flaky tests in inputflinger presubmit Test: presubmit Bug: 304878808 Change-Id: I4ba67ad5057eb0063af33f24e938390b31d0a233 --- services/inputflinger/TEST_MAPPING | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING index ee1f3cbe6a..6f092a6098 100644 --- a/services/inputflinger/TEST_MAPPING +++ b/services/inputflinger/TEST_MAPPING @@ -39,6 +39,9 @@ "options": [ { "include-filter": "android.hardware.input.cts.tests" + }, + { + "exclude-annotation": "androidx.test.filters.FlakyTest" } ] }, -- GitLab From a2764b777637789a7382e08fd9eeb8d379537eb2 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 10 Oct 2023 19:43:43 +0000 Subject: [PATCH 0801/1187] Use the test version of the aconfig flagging library in libinput This means we can avoid adding the flagging library as a separate shared dependency of libinput wherever libinput is used. Bug: 304574138 Test: build, atest inputflinger_tests Change-Id: I1b14554c410baf0f8d020ddf314f1b38365e3b16 --- libs/input/Android.bp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libs/input/Android.bp b/libs/input/Android.bp index ab4af1a7b6..69a4f0aed1 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -46,6 +46,14 @@ cc_aconfig_library { name: "aconfig_input_flags_c_lib", aconfig_declarations: "aconfig_input_flags", host_supported: true, + // Use the test version of the aconfig flag library by default to allow tests to set local + // overrides for flags, without having to link against a separate version of libinput or of this + // library. Bundling this library directly into libinput prevents us from having to add this + // library as a shared lib dependency everywhere where libinput is used. + test: true, + shared: { + enabled: false, + }, } aidl_interface { -- GitLab From b8ebcca6826ee6e746c0b2aec5a36f9a5402bef2 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Mon, 9 Oct 2023 19:54:20 +0000 Subject: [PATCH 0802/1187] Don't depend on private/android_filesystem_config.h Bug: 302723053 Test: mma Change-Id: I855fedd40dc51fd3a6378f5d011a80797d590092 --- libs/binder/Binder.cpp | 9 +++++---- libs/binder/ndk/ibinder.cpp | 8 +++++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index aa67869649..9f091ef756 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -45,6 +44,8 @@ namespace android { +constexpr uid_t kUidRoot = 0; + // Service implementations inherit from BBinder and IBinder, and this is frozen // in prebuilts. #ifdef __LP64__ @@ -300,7 +301,7 @@ status_t BBinder::startRecordingTransactions(const Parcel& data) { return INVALID_OPERATION; } uid_t uid = IPCThreadState::self()->getCallingUid(); - if (uid != AID_ROOT) { + if (uid != kUidRoot) { ALOGE("Binder recording not allowed because client %" PRIu32 " is not root", uid); return PERMISSION_DENIED; } @@ -330,7 +331,7 @@ status_t BBinder::stopRecordingTransactions() { return INVALID_OPERATION; } uid_t uid = IPCThreadState::self()->getCallingUid(); - if (uid != AID_ROOT) { + if (uid != kUidRoot) { ALOGE("Binder recording not allowed because client %" PRIu32 " is not root", uid); return PERMISSION_DENIED; } @@ -634,7 +635,7 @@ status_t BBinder::setRpcClientDebug(const Parcel& data) { return INVALID_OPERATION; } uid_t uid = IPCThreadState::self()->getCallingUid(); - if (uid != AID_ROOT) { + if (uid != kUidRoot) { ALOGE("%s: not allowed because client %" PRIu32 " is not root", __PRETTY_FUNCTION__, uid); return PERMISSION_DENIED; } diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp index f7dd9c9715..47da296b70 100644 --- a/libs/binder/ndk/ibinder.cpp +++ b/libs/binder/ndk/ibinder.cpp @@ -21,7 +21,9 @@ #include #include #include +#if __has_include() #include +#endif #include "ibinder_internal.h" #include "parcel_internal.h" @@ -229,7 +231,11 @@ status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parce // Shell commands should only be callable by ADB. uid_t uid = AIBinder_getCallingUid(); - if (uid != AID_ROOT && uid != AID_SHELL) { + if (uid != 0 /* root */ +#ifdef AID_SHELL + && uid != AID_SHELL +#endif + ) { if (resultReceiver != nullptr) { resultReceiver->send(-1); } -- GitLab From bb07b9837531fe6cd42a1130ce09d403df331197 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Wed, 11 Oct 2023 21:25:36 +0000 Subject: [PATCH 0803/1187] Fix or silence binder build warnings on clang Bug: 302724232 Test: mma Change-Id: Ibd0dd5ef3c985901ab850cb0a589256efadb06a1 --- libs/binder/ndk/tests/iface.cpp | 3 ++ .../ndk/tests/libbinder_ndk_unit_test.cpp | 39 +++++++++++++++++++ libs/binder/rust/tests/serialization.hpp | 3 ++ libs/binder/servicedispatcher.cpp | 3 ++ libs/binder/tests/binderClearBufTest.cpp | 3 ++ libs/binder/tests/binderHostDeviceTest.cpp | 3 ++ libs/binder/tests/binderLibTest.cpp | 10 ++++- libs/binder/tests/binderRecordReplayTest.cpp | 3 ++ libs/binder/tests/binderSafeInterfaceTest.cpp | 3 ++ libs/binder/tests/binderStabilityTest.cpp | 9 +++++ libs/binder/tests/binderThroughputTest.cpp | 3 ++ libs/binder/tests/schd-dbg.cpp | 3 ++ 12 files changed, 83 insertions(+), 2 deletions(-) diff --git a/libs/binder/ndk/tests/iface.cpp b/libs/binder/ndk/tests/iface.cpp index 76acff50bf..3ee36cd8c3 100644 --- a/libs/binder/ndk/tests/iface.cpp +++ b/libs/binder/ndk/tests/iface.cpp @@ -156,7 +156,10 @@ binder_status_t IFoo::addService(const char* instance) { } sp IFoo::getService(const char* instance, AIBinder** outBinder) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr +#pragma clang diagnostic pop if (binder == nullptr) { return nullptr; } diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 15708ca738..cab1a60370 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -341,7 +341,10 @@ TEST(NdkBinder, UnimplementedShell) { // libbinder across processes to the NDK service which doesn't implement // shell static const sp sm(android::defaultServiceManager()); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp testService = sm->getService(String16(IFoo::kSomeInstanceName)); +#pragma clang diagnostic pop Vector argsVec; EXPECT_EQ(OK, IBinder::shellCommand(testService, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, @@ -384,7 +387,10 @@ TEST(NdkBinder, GetTestServiceStressTest) { // checkService on it, since the other process serving it might not be started yet. { // getService, not waitForService, to take advantage of timeout +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" auto binder = ndk::SpAIBinder(AServiceManager_getService(IFoo::kSomeInstanceName)); +#pragma clang diagnostic pop ASSERT_NE(nullptr, binder.get()); } @@ -574,7 +580,10 @@ TEST(NdkBinder, DeathRecipient) { } TEST(NdkBinder, RetrieveNonNdkService) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); +#pragma clang diagnostic pop ASSERT_NE(nullptr, binder); EXPECT_TRUE(AIBinder_isRemote(binder)); EXPECT_TRUE(AIBinder_isAlive(binder)); @@ -588,7 +597,10 @@ void OnBinderDeath(void* cookie) { } TEST(NdkBinder, LinkToDeath) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); +#pragma clang diagnostic pop ASSERT_NE(nullptr, binder); AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(OnBinderDeath); @@ -618,7 +630,10 @@ TEST(NdkBinder, SetInheritRt) { } TEST(NdkBinder, SetInheritRtNonLocal) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); +#pragma clang diagnostic pop ASSERT_NE(binder, nullptr); ASSERT_TRUE(AIBinder_isRemote(binder)); @@ -654,11 +669,14 @@ TEST(NdkBinder, GetServiceInProcess) { } TEST(NdkBinder, EqualityOfRemoteBinderPointer) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" AIBinder* binderA = AServiceManager_getService(kExistingNonNdkService); ASSERT_NE(nullptr, binderA); AIBinder* binderB = AServiceManager_getService(kExistingNonNdkService); ASSERT_NE(nullptr, binderB); +#pragma clang diagnostic pop EXPECT_EQ(binderA, binderB); @@ -672,7 +690,10 @@ TEST(NdkBinder, ToFromJavaNullptr) { } TEST(NdkBinder, ABpBinderRefCount) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); +#pragma clang diagnostic pop AIBinder_Weak* wBinder = AIBinder_Weak_new(binder); ASSERT_NE(nullptr, binder); @@ -695,7 +716,10 @@ TEST(NdkBinder, AddServiceMultipleTimes) { } TEST(NdkBinder, RequestedSidWorks) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService)); +#pragma clang diagnostic pop std::shared_ptr service = aidl::IBinderNdkUnitTest::fromBinder(binder); @@ -718,7 +742,10 @@ TEST(NdkBinder, SentAidlBinderCanBeDestroyed) { std::shared_ptr empty = ndk::SharedRefBase::make(); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService)); +#pragma clang diagnostic pop std::shared_ptr service = aidl::IBinderNdkUnitTest::fromBinder(binder); @@ -741,7 +768,10 @@ TEST(NdkBinder, SentAidlBinderCanBeDestroyed) { TEST(NdkBinder, ConvertToPlatformBinder) { for (const ndk::SpAIBinder& binder : {// remote +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" ndk::SpAIBinder(AServiceManager_getService(kBinderNdkUnitTestService)), +#pragma clang diagnostic pop // local ndk::SharedRefBase::make()->asBinder()}) { // convert to platform binder @@ -774,7 +804,10 @@ TEST(NdkBinder, ConvertToPlatformParcel) { TEST(NdkBinder, GetAndVerifyScopedAIBinder_Weak) { for (const ndk::SpAIBinder& binder : {// remote +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" ndk::SpAIBinder(AServiceManager_getService(kBinderNdkUnitTestService)), +#pragma clang diagnostic pop // local ndk::SharedRefBase::make()->asBinder()}) { // get a const ScopedAIBinder_Weak and verify promote @@ -869,7 +902,10 @@ std::string shellCmdToString(sp unitTestService, const std::vector sm(android::defaultServiceManager()); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp testService = sm->getService(String16(kBinderNdkUnitTestService)); +#pragma clang diagnostic pop EXPECT_EQ("", shellCmdToString(testService, {})); EXPECT_EQ("", shellCmdToString(testService, {"", ""})); @@ -879,7 +915,10 @@ TEST(NdkBinder, UseHandleShellCommand) { TEST(NdkBinder, FlaggedServiceAccessible) { static const sp sm(android::defaultServiceManager()); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp testService = sm->getService(String16(kBinderNdkUnitTestServiceFlagged)); +#pragma clang diagnostic pop ASSERT_NE(nullptr, testService); } diff --git a/libs/binder/rust/tests/serialization.hpp b/libs/binder/rust/tests/serialization.hpp index 0041608ae0..9edcd6d9b6 100644 --- a/libs/binder/rust/tests/serialization.hpp +++ b/libs/binder/rust/tests/serialization.hpp @@ -14,7 +14,10 @@ * limitations under the License. */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpragma-once-outside-header" #pragma once +#pragma clang diagnostic pop #include diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp index 692cc95e3b..738ff4c8f5 100644 --- a/libs/binder/servicedispatcher.cpp +++ b/libs/binder/servicedispatcher.cpp @@ -275,7 +275,10 @@ int main(int argc, char* argv[]) { while (-1 != (opt = getopt(argc, argv, "g"))) { switch (opt) { case 'g': { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" serviceRetriever = &android::IServiceManager::getService; +#pragma clang diagnostic pop } break; default: { return Usage(argv[0]); diff --git a/libs/binder/tests/binderClearBufTest.cpp b/libs/binder/tests/binderClearBufTest.cpp index 307151c7de..3ea5b553bc 100644 --- a/libs/binder/tests/binderClearBufTest.cpp +++ b/libs/binder/tests/binderClearBufTest.cpp @@ -74,7 +74,10 @@ class FooBar : public BBinder { }; TEST(BinderClearBuf, ClearKernelBuffer) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp binder = defaultServiceManager()->getService(kServerName); +#pragma clang diagnostic pop ASSERT_NE(nullptr, binder); std::string replyBuffer; diff --git a/libs/binder/tests/binderHostDeviceTest.cpp b/libs/binder/tests/binderHostDeviceTest.cpp index 77a5fa8d65..0075688ed3 100644 --- a/libs/binder/tests/binderHostDeviceTest.cpp +++ b/libs/binder/tests/binderHostDeviceTest.cpp @@ -135,7 +135,10 @@ TEST_F(HostDeviceTest, CheckService) { TEST_F(HostDeviceTest, GetService) { auto sm = defaultServiceManager(); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" auto rpcBinder = sm->getService(String16(kServiceName)); +#pragma clang diagnostic pop ASSERT_NE(nullptr, rpcBinder); EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK)); diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index e021af0264..853be01a2a 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -213,7 +213,10 @@ class BinderLibTestEnv : public ::testing::Environment { sp sm = defaultServiceManager(); //printf("%s: pid %d, get service\n", __func__, m_pid); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" m_server = sm->getService(binderLibTestServiceName); +#pragma clang diagnostic pop ASSERT_TRUE(m_server != nullptr); //printf("%s: pid %d, get service done\n", __func__, m_pid); } @@ -1107,6 +1110,7 @@ TEST_F(BinderLibTest, WorkSourcePropagatedForAllFollowingBinderCalls) status_t ret; data.writeInterfaceToken(binderLibTestServiceName); ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply); + EXPECT_EQ(NO_ERROR, ret); Parcel data2, reply2; status_t ret2; @@ -1565,9 +1569,8 @@ public: } switch (code) { case BINDER_LIB_TEST_REGISTER_SERVER: { - int32_t id; sp binder; - id = data.readInt32(); + /*id =*/data.readInt32(); binder = data.readStrongBinder(); if (binder == nullptr) { return BAD_VALUE; @@ -1963,7 +1966,10 @@ int run_server(int index, int readypipefd, bool usePoll) if (index == 0) { ret = sm->addService(binderLibTestServiceName, testService); } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp server = sm->getService(binderLibTestServiceName); +#pragma clang diagnostic pop Parcel data, reply; data.writeInt32(index); data.writeStrongBinder(testService); diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp index 6773c95ed6..d08a9bb430 100644 --- a/libs/binder/tests/binderRecordReplayTest.cpp +++ b/libs/binder/tests/binderRecordReplayTest.cpp @@ -133,7 +133,10 @@ class BinderRecordReplayTest : public ::testing::Test { public: void SetUp() override { // get the remote service +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" auto binder = defaultServiceManager()->getService(kServerName); +#pragma clang diagnostic pop ASSERT_NE(nullptr, binder); mInterface = interface_cast(binder); mBpBinder = binder->remoteBinder(); diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp index 5e8a32a61b..1c13866626 100644 --- a/libs/binder/tests/binderSafeInterfaceTest.cpp +++ b/libs/binder/tests/binderSafeInterfaceTest.cpp @@ -605,7 +605,10 @@ private: static constexpr const char* getLogTag() { return "SafeInterfaceTest"; } sp getRemoteService() { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp binder = defaultServiceManager()->getService(kServiceName); +#pragma clang diagnostic pop sp iface = interface_cast(binder); EXPECT_TRUE(iface != nullptr); diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp index 2398e1e1ef..3d993588a4 100644 --- a/libs/binder/tests/binderStabilityTest.cpp +++ b/libs/binder/tests/binderStabilityTest.cpp @@ -155,7 +155,10 @@ TEST(BinderStability, NdkForceDowngradeToLocalStability) { } TEST(BinderStability, ForceDowngradeToVendorStability) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer); +#pragma clang diagnostic pop auto server = interface_cast(serverBinder); ASSERT_NE(nullptr, server.get()); @@ -206,7 +209,10 @@ TEST(BinderStability, ConnectionInfoRequiresManifestEntries) { EXPECT_EQ(connectionInfo, std::nullopt); } TEST(BinderStability, CantCallVendorBinderInSystemContext) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" sp serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer); +#pragma clang diagnostic pop auto server = interface_cast(serverBinder); ASSERT_NE(nullptr, server.get()); @@ -310,8 +316,11 @@ static AIBinder_Class* kNdkBadStableBinder = extern "C" void AIBinder_markVendorStability(AIBinder* binder); // <- BAD DO NOT COPY TEST(BinderStability, NdkCantCallVendorBinderInSystemContext) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" SpAIBinder binder = SpAIBinder(AServiceManager_getService( String8(kSystemStabilityServer).c_str())); +#pragma clang diagnostic pop std::shared_ptr remoteServer = aidl::IBinderStabilityTest::fromBinder(binder); diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp index cfaf2a987f..0ea4a3faaa 100644 --- a/libs/binder/tests/binderThroughputTest.cpp +++ b/libs/binder/tests/binderThroughputTest.cpp @@ -204,7 +204,10 @@ void worker_fx(int num, for (int i = 0; i < server_count; i++) { if (num == i) continue; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" workers.push_back(serviceMgr->getService(generateServiceName(i))); +#pragma clang diagnostic pop } // Run the benchmark if client diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp index 0035e4ee5a..d3cd528e26 100644 --- a/libs/binder/tests/schd-dbg.cpp +++ b/libs/binder/tests/schd-dbg.cpp @@ -340,7 +340,10 @@ void worker_fx(int num, int no_process, int iterations, int payload_size, for (int i = 0; i < server_count; i++) { // self service is in-process so just skip if (num == i) continue; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" workers.push_back(serviceMgr->getService(generateServiceName(i))); +#pragma clang diagnostic pop } // Client for each pair iterates here -- GitLab From f7878b76c97e140a862967427b3bb7af16798327 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Tue, 13 Jun 2023 20:51:03 +0000 Subject: [PATCH 0804/1187] Only use the first available suffix value when loading drivers. Change the EGL loader to use only the first available suffix value when loading the GLES drivers. Previously the loader will continue to read values from a list of properties if it fails to load the value from the previous property. However, this silent fallback should not have happened, the value of the driver suffix properties must be set correctly or left empty if it's not intended to be used. Bug: b/277100371 Test: boot with persist.graphics.egl points to a nonexisted drivers Change-Id: Id6dd9a5aec5e737e8251f9b5f63176a9f8ebc594 Merged-In: Id6dd9a5aec5e737e8251f9b5f63176a9f8ebc594 --- opengl/libs/EGL/Loader.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 2c3ce16f66..bb3b43abb5 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -137,12 +137,14 @@ static void* load_wrapper(const char* path) { #endif #endif -static const char* DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl"; +static const char* PERSIST_DRIVER_SUFFIX_PROPERTY = "persist.graphics.egl"; +static const char* RO_DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl"; +static const char* RO_BOARD_PLATFORM_PROPERTY = "ro.board.platform"; static const char* HAL_SUBNAME_KEY_PROPERTIES[3] = { - "persist.graphics.egl", - DRIVER_SUFFIX_PROPERTY, - "ro.board.platform", + PERSIST_DRIVER_SUFFIX_PROPERTY, + RO_DRIVER_SUFFIX_PROPERTY, + RO_BOARD_PLATFORM_PROPERTY, }; static bool should_unload_system_driver(egl_connection_t* cnx) { @@ -245,17 +247,20 @@ void* Loader::open(egl_connection_t* cnx) continue; } hnd = attempt_to_load_system_driver(cnx, prop.c_str(), true); - if (hnd) { - break; - } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) { + if (!hnd) { + ALOGD("Failed to load drivers from property %s with value %s", key, prop.c_str()); failToLoadFromDriverSuffixProperty = true; } + + // Abort regardless of whether subsequent properties are set, the value must be set + // correctly with the first property that has a value. + break; } } if (!hnd) { - // Can't find graphics driver by appending system properties, now search for the exact name - // without any suffix of the GLES userspace driver in both locations. + // Can't find graphics driver by appending the value from system properties, now search for + // the exact name without any suffix of the GLES userspace driver in both locations. // i.e.: // libGLES.so, or: // libEGL.so, libGLESv1_CM.so, libGLESv2.so -- GitLab From 891f6b06b98208d4dd8c2f837b5138e7f1b2aa3b Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Wed, 11 Oct 2023 18:35:42 +0000 Subject: [PATCH 0805/1187] Copy HexString to libbinder Bug: 302723053 Test: mma Change-Id: I5c7a71a91b7dc95bfa0cd653eabe554bdd3f7812 --- libs/binder/RpcServer.cpp | 12 +++++------- libs/binder/RpcSession.cpp | 6 ++---- libs/binder/RpcState.cpp | 5 ++--- libs/binder/Utils.cpp | 19 +++++++++++++++++++ libs/binder/Utils.h | 6 ++++++ libs/binder/tests/binderClearBufTest.cpp | 5 +++-- .../tests/binderRpcWireProtocolTest.cpp | 4 ++-- libs/binder/tests/parcel_fuzzer/binder.cpp | 5 +++-- libs/binder/tests/parcel_fuzzer/hwbinder.cpp | 5 +++-- .../fuzzseeds/random_parcel_seeds.h | 2 -- libs/binder/tests/parcel_fuzzer/main.cpp | 5 +++-- 11 files changed, 48 insertions(+), 26 deletions(-) diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 55fc16de45..9622313699 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -484,7 +483,7 @@ void RpcServer::establishConnection( // don't block if there is some entropy issue if (tries++ > 5) { ALOGE("Cannot find new address: %s", - base::HexString(sessionId.data(), sessionId.size()).c_str()); + HexString(sessionId.data(), sessionId.size()).c_str()); return; } @@ -536,7 +535,7 @@ void RpcServer::establishConnection( auto it = server->mSessions.find(sessionId); if (it == server->mSessions.end()) { ALOGE("Cannot add thread, no record of session with ID %s", - base::HexString(sessionId.data(), sessionId.size()).c_str()); + HexString(sessionId.data(), sessionId.size()).c_str()); return; } session = it->second; @@ -610,15 +609,14 @@ status_t RpcServer::setupRawSocketServer(unique_fd socket_fd) { void RpcServer::onSessionAllIncomingThreadsEnded(const sp& session) { const std::vector& id = session->mId; LOG_ALWAYS_FATAL_IF(id.empty(), "Server sessions must be initialized with ID"); - LOG_RPC_DETAIL("Dropping session with address %s", - base::HexString(id.data(), id.size()).c_str()); + LOG_RPC_DETAIL("Dropping session with address %s", HexString(id.data(), id.size()).c_str()); RpcMutexLockGuard _l(mLock); auto it = mSessions.find(id); LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %s", - base::HexString(id.data(), id.size()).c_str()); + HexString(id.data(), id.size()).c_str()); LOG_ALWAYS_FATAL_IF(it->second != session, "Bad state, session has id mismatch %s", - base::HexString(id.data(), id.size()).c_str()); + HexString(id.data(), id.size()).c_str()); (void)mSessions.erase(it); } diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index c3dee1650e..edac56ba3b 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -26,7 +26,6 @@ #include -#include #include #include #include @@ -310,8 +309,7 @@ status_t RpcSession::readId() { status = state()->getSessionId(connection.get(), sp::fromExisting(this), &mId); if (status != OK) return status; - LOG_RPC_DETAIL("RpcSession %p has id %s", this, - base::HexString(mId.data(), mId.size()).c_str()); + LOG_RPC_DETAIL("RpcSession %p has id %s", this, HexString(mId.data(), mId.size()).c_str()); return OK; } @@ -709,7 +707,7 @@ status_t RpcSession::initAndAddConnection(RpcTransportFd fd, const std::vector #include #include #include @@ -363,7 +362,7 @@ status_t RpcState::rpcSend( for (int i = 0; i < niovs; i++) { LOG_RPC_DETAIL("Sending %s (part %d of %d) on RpcTransport %p: %s", what, i + 1, niovs, connection->rpcTransport.get(), - android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str()); + HexString(iovs[i].iov_base, iovs[i].iov_len).c_str()); } if (status_t status = @@ -398,7 +397,7 @@ status_t RpcState::rpcRec( for (int i = 0; i < niovs; i++) { LOG_RPC_DETAIL("Received %s (part %d of %d) on RpcTransport %p: %s", what, i + 1, niovs, connection->rpcTransport.get(), - android::base::HexString(iovs[i].iov_base, iovs[i].iov_len).c_str()); + HexString(iovs[i].iov_base, iovs[i].iov_len).c_str()); } return OK; } diff --git a/libs/binder/Utils.cpp b/libs/binder/Utils.cpp index 0314b0fea7..47fd17dcb1 100644 --- a/libs/binder/Utils.cpp +++ b/libs/binder/Utils.cpp @@ -16,6 +16,7 @@ #include "Utils.h" +#include #include namespace android { @@ -24,4 +25,22 @@ void zeroMemory(uint8_t* data, size_t size) { memset(data, 0, size); } +std::string HexString(const void* bytes, size_t len) { + CHECK(bytes != nullptr || len == 0) << bytes << " " << len; + + // b/132916539: Doing this the 'C way', std::setfill triggers ubsan implicit conversion + const uint8_t* bytes8 = static_cast(bytes); + const char chars[] = "0123456789abcdef"; + std::string result; + result.resize(len * 2); + + for (size_t i = 0; i < len; i++) { + const auto c = bytes8[i]; + result[2 * i] = chars[c >> 4]; + result[2 * i + 1] = chars[c & 0xf]; + } + + return result; +} + } // namespace android diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h index e04199c75a..dd632c0b26 100644 --- a/libs/binder/Utils.h +++ b/libs/binder/Utils.h @@ -70,4 +70,10 @@ struct Span { } }; +// Converts binary data into a hexString. +// +// Hex values are printed in order, e.g. 0xDEAD will result in 'adde' because +// Android is little-endian. +std::string HexString(const void* bytes, size_t len); + } // namespace android diff --git a/libs/binder/tests/binderClearBufTest.cpp b/libs/binder/tests/binderClearBufTest.cpp index 3ea5b553bc..e43ee5fcf5 100644 --- a/libs/binder/tests/binderClearBufTest.cpp +++ b/libs/binder/tests/binderClearBufTest.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include #include @@ -24,6 +23,8 @@ #include #include +#include "../Utils.h" + #include #include @@ -68,7 +69,7 @@ class FooBar : public BBinder { lastReply = reply.data(); lastReplySize = reply.dataSize(); } - *outBuffer = android::base::HexString(lastReply, lastReplySize); + *outBuffer = android::HexString(lastReply, lastReplySize); return result; } }; diff --git a/libs/binder/tests/binderRpcWireProtocolTest.cpp b/libs/binder/tests/binderRpcWireProtocolTest.cpp index 642cea440d..d0ce37d952 100644 --- a/libs/binder/tests/binderRpcWireProtocolTest.cpp +++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include #include @@ -25,6 +24,7 @@ #include #include "../Debug.h" +#include "../Utils.h" namespace android { @@ -176,7 +176,7 @@ static std::string buildRepr(uint32_t version) { setParcelForRpc(&p, version); kFillFuns[i](&p); - result += base::HexString(p.data(), p.dataSize()); + result += HexString(p.data(), p.dataSize()); } return result; } diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp index 46d387ce86..416ffad466 100644 --- a/libs/binder/tests/parcel_fuzzer/binder.cpp +++ b/libs/binder/tests/parcel_fuzzer/binder.cpp @@ -21,14 +21,15 @@ #include "parcelables/SingleDataParcelable.h" #include "util.h" -#include #include #include #include #include +#include "../../Utils.h" + using ::android::status_t; -using ::android::base::HexString; +using ::android::HexString; enum ByteEnum : int8_t {}; enum IntEnum : int32_t {}; diff --git a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp index 438e8ae9b2..cdc8bccf0c 100644 --- a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp +++ b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp @@ -18,12 +18,13 @@ #include "hwbinder.h" #include "util.h" -#include #include #include +#include "../../Utils.h" + using ::android::status_t; -using ::android::base::HexString; +using ::android::HexString; // TODO: support scatter-gather types diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h index 5755239c8b..071250ddf1 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h @@ -15,7 +15,6 @@ */ #include -#include #include #include @@ -27,7 +26,6 @@ #include using android::Parcel; -using android::base::HexString; using std::vector; namespace android { diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp index bef4ab6e99..5b1e9eac23 100644 --- a/libs/binder/tests/parcel_fuzzer/main.cpp +++ b/libs/binder/tests/parcel_fuzzer/main.cpp @@ -22,7 +22,6 @@ #include -#include #include #include #include @@ -34,10 +33,12 @@ #include #include +#include "../../Utils.h" + using android::fillRandomParcel; using android::RandomParcelOptions; using android::sp; -using android::base::HexString; +using android::HexString; void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider, RandomParcelOptions* options) { -- GitLab From aa20c5818e3d5c609b49c7b346214262f069e2bf Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Wed, 11 Oct 2023 19:44:54 +0000 Subject: [PATCH 0806/1187] Clear out callback when canceling an alarm VSyncDispatchTimerQueue tries to cancel its timer callback when destroying itself, but Timekeeper might still run the callback if disarming its timer happened immediately after polling but before invoking the callback. To avoid this race condition, delete the callback while holding Timekeeper's mutex. Bug: 304675978 Test: builds Change-Id: Ifa7a4fcb65481b6a5ddfcfeb6bc7a53cb37ec168 --- .../Scheduler/include/scheduler/Timer.h | 2 ++ services/surfaceflinger/Scheduler/src/Timer.cpp | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Timer.h b/services/surfaceflinger/Scheduler/include/scheduler/Timer.h index 58ad6cb991..67f7abe4ff 100644 --- a/services/surfaceflinger/Scheduler/include/scheduler/Timer.h +++ b/services/surfaceflinger/Scheduler/include/scheduler/Timer.h @@ -60,6 +60,7 @@ private: void reset() EXCLUDES(mMutex); void cleanup() REQUIRES(mMutex); void setDebugState(DebugState) EXCLUDES(mMutex); + void setCallback(std::function&&) REQUIRES(mMutex); int mTimerFd = -1; @@ -71,6 +72,7 @@ private: void endDispatch(); mutable std::mutex mMutex; + std::function mCallback GUARDED_BY(mMutex); bool mExpectingCallback GUARDED_BY(mMutex) = false; DebugState mDebugState GUARDED_BY(mMutex); diff --git a/services/surfaceflinger/Scheduler/src/Timer.cpp b/services/surfaceflinger/Scheduler/src/Timer.cpp index a4cf57fbaa..09e8a1ebe0 100644 --- a/services/surfaceflinger/Scheduler/src/Timer.cpp +++ b/services/surfaceflinger/Scheduler/src/Timer.cpp @@ -93,8 +93,8 @@ void Timer::cleanup() { close(mPipes[kWritePipe]); mPipes[kWritePipe] = -1; } - mExpectingCallback = false; - mCallback = {}; + + setCallback({}); } void Timer::endDispatch() { @@ -112,8 +112,7 @@ void Timer::alarmAt(std::function callback, nsecs_t time) { static constexpr int ns_per_s = std::chrono::duration_cast(1s).count(); - mCallback = std::move(callback); - mExpectingCallback = true; + setCallback(std::move(callback)); struct itimerspec old_timer; struct itimerspec new_timer { @@ -142,6 +141,8 @@ void Timer::alarmCancel() { if (timerfd_settime(mTimerFd, 0, &new_timer, &old_timer)) { ALOGW("Failed to disarm timerfd"); } + + setCallback({}); } void Timer::threadMain() { @@ -231,6 +232,11 @@ void Timer::setDebugState(DebugState state) { mDebugState = state; } +void Timer::setCallback(std::function&& callback) { + mExpectingCallback = bool(callback); + mCallback = std::move(callback); +} + void Timer::dump(std::string& result) const { std::lock_guard lock(mMutex); result.append("\t\tDebugState: "); -- GitLab From 164633818b22bf3485b519e000d48bb33b3b1764 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Thu, 12 Oct 2023 23:03:19 +0000 Subject: [PATCH 0807/1187] Send cancel events to the correct display when mirroring When a display is mirrored, such as when screen recording is enabled, there will be clones of the input windows on the mirrored display that are on the mirror display. When there is a stream of input going to the channel through one of those windows and that stream should be canceled, the generated cancel event should be sent to the correct window on the correct display. Bug: 299074463 Test: atest inputflinger_tests Change-Id: I7b9eab69c9e9086750cf9fe8a10998a12c30d084 --- .../dispatcher/InputDispatcher.cpp | 57 +++++++++---------- .../inputflinger/dispatcher/InputDispatcher.h | 9 +-- .../tests/InputDispatcher_test.cpp | 30 ++++++++++ 3 files changed, 60 insertions(+), 36 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 276f75caff..d0a72eee20 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -3958,28 +3958,24 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( android_log_event_list(LOGTAG_INPUT_CANCEL) << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS; - sp windowHandle; - if (options.displayId) { - windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken(), - options.displayId.value()); - } else { - windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken()); - } - const bool wasEmpty = connection->outboundQueue.empty(); + // The target to use if we don't find a window associated with the channel. + const InputTarget fallbackTarget{.inputChannel = connection->inputChannel, + .flags = InputTarget::Flags::DISPATCH_AS_IS}; + const auto& token = connection->inputChannel->getConnectionToken(); for (size_t i = 0; i < cancelationEvents.size(); i++) { std::unique_ptr cancelationEventEntry = std::move(cancelationEvents[i]); std::vector targets{}; - // The target to use if we don't find a window associated with the channel. - const InputTarget fallbackTarget{.inputChannel = connection->inputChannel, - .flags = InputTarget::Flags::DISPATCH_AS_IS}; switch (cancelationEventEntry->type) { case EventEntry::Type::KEY: { const auto& keyEntry = static_cast(*cancelationEventEntry); - if (windowHandle != nullptr) { - addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_IS, + const std::optional targetDisplay = keyEntry.displayId != ADISPLAY_ID_NONE + ? std::make_optional(keyEntry.displayId) + : std::nullopt; + if (const auto& window = getWindowHandleLocked(token, targetDisplay); window) { + addWindowTargetLocked(window, InputTarget::Flags::DISPATCH_AS_IS, /*pointerIds=*/{}, keyEntry.downTime, targets); } else { targets.emplace_back(fallbackTarget); @@ -3989,14 +3985,18 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( } case EventEntry::Type::MOTION: { const auto& motionEntry = static_cast(*cancelationEventEntry); - if (windowHandle != nullptr) { + const std::optional targetDisplay = + motionEntry.displayId != ADISPLAY_ID_NONE + ? std::make_optional(motionEntry.displayId) + : std::nullopt; + if (const auto& window = getWindowHandleLocked(token, targetDisplay); window) { std::bitset pointerIds; for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.pointerCount; pointerIndex++) { pointerIds.set(motionEntry.pointerProperties[pointerIndex].id); } - addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_IS, - pointerIds, motionEntry.downTime, targets); + addWindowTargetLocked(window, InputTarget::Flags::DISPATCH_AS_IS, pointerIds, + motionEntry.downTime, targets); } else { targets.emplace_back(fallbackTarget); const auto it = mDisplayInfos.find(motionEntry.displayId); @@ -4905,29 +4905,26 @@ const std::vector>& InputDispatcher::getWindowHandlesLocked } sp InputDispatcher::getWindowHandleLocked( - const sp& windowHandleToken) const { + const sp& windowHandleToken, std::optional displayId) const { if (windowHandleToken == nullptr) { return nullptr; } - for (auto& it : mWindowHandlesByDisplay) { - const std::vector>& windowHandles = it.second; - for (const sp& windowHandle : windowHandles) { - if (windowHandle->getToken() == windowHandleToken) { - return windowHandle; + if (!displayId) { + // Look through all displays. + for (auto& it : mWindowHandlesByDisplay) { + const std::vector>& windowHandles = it.second; + for (const sp& windowHandle : windowHandles) { + if (windowHandle->getToken() == windowHandleToken) { + return windowHandle; + } } } - } - return nullptr; -} - -sp InputDispatcher::getWindowHandleLocked(const sp& windowHandleToken, - int displayId) const { - if (windowHandleToken == nullptr) { return nullptr; } - for (const sp& windowHandle : getWindowHandlesLocked(displayId)) { + // Only look through the requested display. + for (const sp& windowHandle : getWindowHandlesLocked(*displayId)) { if (windowHandle->getToken() == windowHandleToken) { return windowHandle; } diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index ee5a797a87..002030168b 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -354,14 +354,11 @@ private: // Get a reference to window handles by display, return an empty vector if not found. const std::vector>& getWindowHandlesLocked( int32_t displayId) const REQUIRES(mLock); - sp getWindowHandleLocked( - const sp& windowHandleToken) const REQUIRES(mLock); ui::Transform getTransformLocked(int32_t displayId) const REQUIRES(mLock); - // Same function as above, but faster. Since displayId is provided, this avoids the need - // to loop through all displays. - sp getWindowHandleLocked(const sp& windowHandleToken, - int displayId) const REQUIRES(mLock); + sp getWindowHandleLocked( + const sp& windowHandleToken, std::optional displayId = {}) const + REQUIRES(mLock); sp getWindowHandleLocked( const sp& windowHandle) const REQUIRES(mLock); std::shared_ptr getInputChannelLocked(const sp& windowToken) const diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 2f63b2a6d0..ff3eff16eb 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -4699,6 +4699,36 @@ TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorre firstWindow->assertNoEvents(); } +TEST_F(InputDispatcherDisplayProjectionTest, + SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) { + auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); + + const std::array matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; + ui::Transform secondDisplayTransform; + secondDisplayTransform.set(matrix); + addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform); + + sp secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID); + secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4); + addWindow(secondWindowClone); + + // Send hover enter to second window + mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS, + ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); + secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), + WithCoords(100, 80), WithRawCoords(300, 880), + WithDisplayId(ADISPLAY_ID_DEFAULT))); + + mDispatcher->cancelCurrentTouch(); + + // Ensure the cancelation happens with the correct displayId and the correct coordinates. + secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80), + WithRawCoords(300, 880), + WithDisplayId(ADISPLAY_ID_DEFAULT))); + secondWindow->assertNoEvents(); + firstWindow->assertNoEvents(); +} + /** Ensure consistent behavior of InputDispatcher in all orientations. */ class InputDispatcherDisplayOrientationFixture : public InputDispatcherDisplayProjectionTest, -- GitLab From 6574613a530a3a94006992f227f92aaec4eda5ed Mon Sep 17 00:00:00 2001 From: Mattias Simonsson Date: Tue, 15 Aug 2023 13:26:16 +0000 Subject: [PATCH 0808/1187] RenderEngine: Pre-warm shaders for dimmed layers Bug: b/295257834 Test: BootPerformanceTest Change-Id: Ia374bb88ccd7a2e0ee4a76c71b5fca6971d7e74d --- libs/renderengine/skia/Cache.cpp | 168 +++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index 9d61d629de..4de42fd142 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -49,6 +49,11 @@ const auto kFlip = mat4(1.1f, -0.1f, 0.f, 0.f, // a color correction effect is added to the shader. constexpr auto kDestDataSpace = ui::Dataspace::SRGB; constexpr auto kOtherDataSpace = ui::Dataspace::DISPLAY_P3; +// Dimming is needed to trigger linear effects for some dataspace pairs +const std::array kLayerWhitePoints = { + 1000.0f, 500.0f, + 100.0f, // trigger dithering by dimming below 20% +}; } // namespace static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, @@ -317,6 +322,150 @@ static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySett renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); } +static void drawImageDimmedLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, + const std::shared_ptr& dstTexture, + const std::shared_ptr& srcTexture) { + const Rect& displayRect = display.physicalDisplay; + FloatRect rect(0, 0, displayRect.width(), displayRect.height()); + LayerSettings layer{ + .geometry = + Geometry{ + // The position transform doesn't matter when the reduced shader mode + // in in effect. A matrix transform stage is always included. + .positionTransform = mat4(), + .boundaries = rect, + .roundedCornersCrop = rect, + .roundedCornersRadius = {0.f, 0.f}, + }, + .source = PixelSource{.buffer = Buffer{.buffer = srcTexture, + .maxLuminanceNits = 1000.f, + .usePremultipliedAlpha = true, + .isOpaque = true}}, + .alpha = 1.f, + .sourceDataspace = kDestDataSpace, + }; + + std::vector layers; + + for (auto layerWhitePoint : kLayerWhitePoints) { + layer.whitePointNits = layerWhitePoint; + layers.push_back(layer); + } + renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); +} + +static void drawTransparentImageDimmedLayers(SkiaRenderEngine* renderengine, + const DisplaySettings& display, + const std::shared_ptr& dstTexture, + const std::shared_ptr& srcTexture) { + const Rect& displayRect = display.physicalDisplay; + FloatRect rect(0, 0, displayRect.width(), displayRect.height()); + LayerSettings layer{ + .geometry = + Geometry{ + .positionTransform = mat4(), + .boundaries = rect, + .roundedCornersCrop = rect, + }, + .source = PixelSource{.buffer = + Buffer{ + .buffer = srcTexture, + .maxLuminanceNits = 1000.f, + .usePremultipliedAlpha = true, + .isOpaque = false, + }}, + .sourceDataspace = kDestDataSpace, + }; + + for (auto roundedCornerRadius : {0.f, 50.f}) { + layer.geometry.roundedCornersRadius = {roundedCornerRadius, roundedCornerRadius}; + for (auto alpha : {0.5f, 1.0f}) { + layer.alpha = alpha; + std::vector layers; + + for (auto layerWhitePoint : kLayerWhitePoints) { + layer.whitePointNits = layerWhitePoint; + layers.push_back(layer); + } + renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); + } + } +} + +static void drawClippedDimmedImageLayers(SkiaRenderEngine* renderengine, + const DisplaySettings& display, + const std::shared_ptr& dstTexture, + const std::shared_ptr& srcTexture) { + const Rect& displayRect = display.physicalDisplay; + + // If rect and boundary is too small compared to roundedCornersRadius, Skia will switch to + // blending instead of EllipticalRRect, so enlarge them a bit. + FloatRect rect(0, 0, displayRect.width(), displayRect.height()); + FloatRect boundary(0, 0, displayRect.width(), + displayRect.height() - 20); // boundary is smaller + LayerSettings layer{ + .geometry = + Geometry{ + .positionTransform = mat4(), + .boundaries = boundary, + .roundedCornersCrop = rect, + .roundedCornersRadius = {27.f, 27.f}, + }, + .source = PixelSource{.buffer = + Buffer{ + .buffer = srcTexture, + .maxLuminanceNits = 1000.f, + .usePremultipliedAlpha = true, + .isOpaque = false, + }}, + .alpha = 1.f, + .sourceDataspace = kDestDataSpace, + }; + + std::array transforms = {kScaleAndTranslate, kScaleAsymmetric}; + + constexpr float radius = 27.f; + + for (size_t i = 0; i < transforms.size(); i++) { + layer.geometry.positionTransform = transforms[i]; + layer.geometry.roundedCornersRadius = {radius, radius}; + + std::vector layers; + + for (auto layerWhitePoint : kLayerWhitePoints) { + layer.whitePointNits = layerWhitePoint; + layers.push_back(layer); + } + renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); + } +} + +static void drawSolidDimmedLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, + const std::shared_ptr& dstTexture) { + const Rect& displayRect = display.physicalDisplay; + FloatRect rect(0, 0, displayRect.width(), displayRect.height()); + LayerSettings layer{ + .geometry = + Geometry{ + .boundaries = rect, + .roundedCornersCrop = rect, + }, + .source = + PixelSource{ + .solidColor = half3(0.1f, 0.2f, 0.3f), + }, + .alpha = 1.f, + }; + + std::vector layers; + + for (auto layerWhitePoint : kLayerWhitePoints) { + layer.whitePointNits = layerWhitePoint; + layers.push_back(layer); + } + renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); +} + // // The collection of shaders cached here were found by using perfetto to record shader compiles // during actions that involve RenderEngine, logging the layer settings, and the shader code @@ -353,6 +502,15 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { .maxLuminance = 500, .outputDataspace = kOtherDataSpace, }; + DisplaySettings bt2020Display{.physicalDisplay = displayRect, + .clip = displayRect, + .maxLuminance = 500, + .outputDataspace = ui::Dataspace::BT2020, + .deviceHandlesColorTransform = true, + .dimmingStage = aidl::android::hardware::graphics::composer3:: + DimmingStage::GAMMA_OETF, + .renderIntent = aidl::android::hardware::graphics::composer3:: + RenderIntent::TONE_MAP_ENHANCE}; const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; @@ -377,6 +535,7 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { impl::ExternalTexture::Usage::WRITEABLE); drawHolePunchLayer(renderengine, display, dstTexture); drawSolidLayers(renderengine, display, dstTexture); + drawSolidDimmedLayers(renderengine, display, dstTexture); drawShadowLayers(renderengine, display, srcTexture); drawShadowLayers(renderengine, p3Display, srcTexture); @@ -417,12 +576,21 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { for (auto texture : textures) { drawImageLayers(renderengine, display, dstTexture, texture); + drawImageDimmedLayers(renderengine, display, dstTexture, texture); + drawImageDimmedLayers(renderengine, p3Display, dstTexture, texture); + drawImageDimmedLayers(renderengine, bt2020Display, dstTexture, texture); // Draw layers for b/185569240. drawClippedLayers(renderengine, display, dstTexture, texture); } drawPIPImageLayer(renderengine, display, dstTexture, externalTexture); + drawTransparentImageDimmedLayers(renderengine, bt2020Display, dstTexture, externalTexture); + drawTransparentImageDimmedLayers(renderengine, display, dstTexture, externalTexture); + drawTransparentImageDimmedLayers(renderengine, p3Display, dstTexture, externalTexture); + + drawClippedDimmedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture); + // draw one final layer synchronously to force GL submit LayerSettings layer{ .source = PixelSource{.solidColor = half3(0.f, 0.f, 0.f)}, -- GitLab From 458adf1b94b1b299f9dbfad60be577dbddab1ec2 Mon Sep 17 00:00:00 2001 From: Mattias Simonsson Date: Wed, 16 Aug 2023 10:49:30 +0000 Subject: [PATCH 0809/1187] RenderEngine: Pre-warm layers with BT2020_ITU_PQ dataspace Bug: b/295257834 Test: BootPerformanceTest Change-Id: Iff94575be7cfdc8050796633bf03cf154e716ad9 --- libs/renderengine/skia/Cache.cpp | 71 ++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index 4de42fd142..ef00e9056e 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -49,6 +49,7 @@ const auto kFlip = mat4(1.1f, -0.1f, 0.f, 0.f, // a color correction effect is added to the shader. constexpr auto kDestDataSpace = ui::Dataspace::SRGB; constexpr auto kOtherDataSpace = ui::Dataspace::DISPLAY_P3; +constexpr auto kBT2020DataSpace = ui::Dataspace::BT2020_ITU_PQ; // Dimming is needed to trigger linear effects for some dataspace pairs const std::array kLayerWhitePoints = { 1000.0f, 500.0f, @@ -466,6 +467,72 @@ static void drawSolidDimmedLayers(SkiaRenderEngine* renderengine, const DisplayS renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); } +static void drawBT2020ImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, + const std::shared_ptr& dstTexture, + const std::shared_ptr& srcTexture) { + const Rect& displayRect = display.physicalDisplay; + FloatRect rect(0, 0, displayRect.width(), displayRect.height()); + LayerSettings layer{ + .geometry = + Geometry{ + // The position transform doesn't matter when the reduced shader mode + // in in effect. A matrix transform stage is always included. + .positionTransform = mat4(), + .boundaries = rect, + .roundedCornersCrop = rect, + .roundedCornersRadius = {0.f, 0.f}, + }, + .source = PixelSource{.buffer = Buffer{.buffer = srcTexture, + .maxLuminanceNits = 1000.f, + .usePremultipliedAlpha = true, + .isOpaque = true}}, + .alpha = 1.f, + .sourceDataspace = kBT2020DataSpace, + }; + + for (auto alpha : {0.5f, 1.f}) { + layer.alpha = alpha; + std::vector layers; + layer.whitePointNits = -1.f; + layers.push_back(layer); + + renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); + } +} +static void drawBT2020ClippedImageLayers(SkiaRenderEngine* renderengine, + const DisplaySettings& display, + const std::shared_ptr& dstTexture, + const std::shared_ptr& srcTexture) { + const Rect& displayRect = display.physicalDisplay; + + // If rect and boundary is too small compared to roundedCornersRadius, Skia will switch to + // blending instead of EllipticalRRect, so enlarge them a bit. + FloatRect rect(0, 0, displayRect.width(), displayRect.height()); + FloatRect boundary(0, 0, displayRect.width(), + displayRect.height() - 10); // boundary is smaller + LayerSettings layer{ + .geometry = + Geometry{ + .positionTransform = kScaleAsymmetric, + .boundaries = boundary, + .roundedCornersCrop = rect, + .roundedCornersRadius = {64.1f, 64.1f}, + }, + .source = PixelSource{.buffer = + Buffer{ + .buffer = srcTexture, + .maxLuminanceNits = 1000.f, + .usePremultipliedAlpha = true, + .isOpaque = true, + }}, + .alpha = 0.5f, + .sourceDataspace = kBT2020DataSpace, + }; + + std::vector layers = {layer}; + renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); +} + // // The collection of shaders cached here were found by using perfetto to record shader compiles // during actions that involve RenderEngine, logging the layer settings, and the shader code @@ -590,6 +657,10 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { drawTransparentImageDimmedLayers(renderengine, p3Display, dstTexture, externalTexture); drawClippedDimmedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture); + drawBT2020ClippedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture); + + drawBT2020ImageLayers(renderengine, bt2020Display, dstTexture, externalTexture); + drawBT2020ImageLayers(renderengine, p3Display, dstTexture, externalTexture); // draw one final layer synchronously to force GL submit LayerSettings layer{ -- GitLab From 5860d9286aeb1df020431536ba779952044ce6b4 Mon Sep 17 00:00:00 2001 From: Mattias Simonsson Date: Wed, 16 Aug 2023 13:47:41 +0000 Subject: [PATCH 0810/1187] RenderEngine: Pre-warm P3 and ExtendedHDR layers Bug: b/295257834 Test: BootPerformanceTest Change-Id: I8cedce2c78089e183b33e2aa2eba4d95b8fe03b7 --- libs/renderengine/skia/Cache.cpp | 114 +++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 5 deletions(-) diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index ef00e9056e..25296f06ee 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -50,6 +50,9 @@ const auto kFlip = mat4(1.1f, -0.1f, 0.f, 0.f, constexpr auto kDestDataSpace = ui::Dataspace::SRGB; constexpr auto kOtherDataSpace = ui::Dataspace::DISPLAY_P3; constexpr auto kBT2020DataSpace = ui::Dataspace::BT2020_ITU_PQ; +constexpr auto kExtendedHdrDataSpce = + static_cast(ui::Dataspace::RANGE_EXTENDED | ui::Dataspace::TRANSFER_SRGB | + ui::Dataspace::STANDARD_DCI_P3); // Dimming is needed to trigger linear effects for some dataspace pairs const std::array kLayerWhitePoints = { 1000.0f, 500.0f, @@ -382,13 +385,21 @@ static void drawTransparentImageDimmedLayers(SkiaRenderEngine* renderengine, layer.geometry.roundedCornersRadius = {roundedCornerRadius, roundedCornerRadius}; for (auto alpha : {0.5f, 1.0f}) { layer.alpha = alpha; - std::vector layers; + for (auto isOpaque : {true, false}) { + if (roundedCornerRadius == 0.f && isOpaque) { + // already covered in drawImageDimmedLayers + continue; + } - for (auto layerWhitePoint : kLayerWhitePoints) { - layer.whitePointNits = layerWhitePoint; - layers.push_back(layer); + layer.source.buffer.isOpaque = isOpaque; + std::vector layers; + + for (auto layerWhitePoint : kLayerWhitePoints) { + layer.whitePointNits = layerWhitePoint; + layers.push_back(layer); + } + renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); } - renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); } } } @@ -533,6 +544,80 @@ static void drawBT2020ClippedImageLayers(SkiaRenderEngine* renderengine, renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); } +static void drawExtendedHDRImageLayers(SkiaRenderEngine* renderengine, + const DisplaySettings& display, + const std::shared_ptr& dstTexture, + const std::shared_ptr& srcTexture) { + const Rect& displayRect = display.physicalDisplay; + FloatRect rect(0, 0, displayRect.width(), displayRect.height()); + LayerSettings layer{ + .geometry = + Geometry{ + // The position transform doesn't matter when the reduced shader mode + // in in effect. A matrix transform stage is always included. + .positionTransform = mat4(), + .boundaries = rect, + .roundedCornersCrop = rect, + .roundedCornersRadius = {50.f, 50.f}, + }, + .source = PixelSource{.buffer = Buffer{.buffer = srcTexture, + .maxLuminanceNits = 1000.f, + .usePremultipliedAlpha = true, + .isOpaque = true}}, + .alpha = 0.5f, + .sourceDataspace = kExtendedHdrDataSpce, + }; + + for (auto roundedCornerRadius : {0.f, 50.f}) { + layer.geometry.roundedCornersRadius = {roundedCornerRadius, roundedCornerRadius}; + for (auto alpha : {0.5f, 1.f}) { + layer.alpha = alpha; + std::vector layers; + + for (auto layerWhitePoint : kLayerWhitePoints) { + layer.whitePointNits = layerWhitePoint; + layers.push_back(layer); + } + renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); + } + } +} + +static void drawP3ImageLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, + const std::shared_ptr& dstTexture, + const std::shared_ptr& srcTexture) { + const Rect& displayRect = display.physicalDisplay; + FloatRect rect(0, 0, displayRect.width(), displayRect.height()); + LayerSettings layer{ + .geometry = + Geometry{ + // The position transform doesn't matter when the reduced shader mode + // in in effect. A matrix transform stage is always included. + .positionTransform = mat4(), + .boundaries = rect, + .roundedCornersCrop = rect, + .roundedCornersRadius = {50.f, 50.f}, + }, + .source = PixelSource{.buffer = Buffer{.buffer = srcTexture, + .maxLuminanceNits = 1000.f, + .usePremultipliedAlpha = true, + .isOpaque = false}}, + .alpha = 0.5f, + .sourceDataspace = kOtherDataSpace, + }; + + for (auto alpha : {0.5f, 1.f}) { + layer.alpha = alpha; + std::vector layers; + + for (auto layerWhitePoint : kLayerWhitePoints) { + layer.whitePointNits = layerWhitePoint; + layers.push_back(layer); + } + renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()); + } +} + // // The collection of shaders cached here were found by using perfetto to record shader compiles // during actions that involve RenderEngine, logging the layer settings, and the shader code @@ -569,6 +654,14 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { .maxLuminance = 500, .outputDataspace = kOtherDataSpace, }; + DisplaySettings p3DisplayEnhance{.physicalDisplay = displayRect, + .clip = displayRect, + .maxLuminance = 500, + .outputDataspace = kOtherDataSpace, + .dimmingStage = aidl::android::hardware::graphics:: + composer3::DimmingStage::GAMMA_OETF, + .renderIntent = aidl::android::hardware::graphics:: + composer3::RenderIntent::ENHANCE}; DisplaySettings bt2020Display{.physicalDisplay = displayRect, .clip = displayRect, .maxLuminance = 500, @@ -602,6 +695,7 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { impl::ExternalTexture::Usage::WRITEABLE); drawHolePunchLayer(renderengine, display, dstTexture); drawSolidLayers(renderengine, display, dstTexture); + drawSolidLayers(renderengine, p3Display, dstTexture); drawSolidDimmedLayers(renderengine, display, dstTexture); drawShadowLayers(renderengine, display, srcTexture); @@ -643,9 +737,11 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { for (auto texture : textures) { drawImageLayers(renderengine, display, dstTexture, texture); + drawImageDimmedLayers(renderengine, display, dstTexture, texture); drawImageDimmedLayers(renderengine, p3Display, dstTexture, texture); drawImageDimmedLayers(renderengine, bt2020Display, dstTexture, texture); + // Draw layers for b/185569240. drawClippedLayers(renderengine, display, dstTexture, texture); } @@ -655,6 +751,8 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { drawTransparentImageDimmedLayers(renderengine, bt2020Display, dstTexture, externalTexture); drawTransparentImageDimmedLayers(renderengine, display, dstTexture, externalTexture); drawTransparentImageDimmedLayers(renderengine, p3Display, dstTexture, externalTexture); + drawTransparentImageDimmedLayers(renderengine, p3DisplayEnhance, dstTexture, + externalTexture); drawClippedDimmedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture); drawBT2020ClippedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture); @@ -662,6 +760,12 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { drawBT2020ImageLayers(renderengine, bt2020Display, dstTexture, externalTexture); drawBT2020ImageLayers(renderengine, p3Display, dstTexture, externalTexture); + drawExtendedHDRImageLayers(renderengine, display, dstTexture, externalTexture); + drawExtendedHDRImageLayers(renderengine, p3Display, dstTexture, externalTexture); + drawExtendedHDRImageLayers(renderengine, p3DisplayEnhance, dstTexture, externalTexture); + + drawP3ImageLayers(renderengine, p3DisplayEnhance, dstTexture, externalTexture); + // draw one final layer synchronously to force GL submit LayerSettings layer{ .source = PixelSource{.solidColor = half3(0.f, 0.f, 0.f)}, -- GitLab From 2fc491182c7b866838fbf1eceac55898867ee068 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Fri, 13 Oct 2023 13:10:48 +0000 Subject: [PATCH 0811/1187] [native] Use newer GrDirectContexts::MakeVulkan This was added in http://review.skia.org/764516 and the old versions were deprecated. This should not change any functionality as the deprecated APIs call the new APIs. Change-Id: I78c0f3b1a14995d9ba6122ea5e93032bcd4f9573 Bug: b:293490566 --- libs/renderengine/skia/SkiaVkRenderEngine.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libs/renderengine/skia/SkiaVkRenderEngine.cpp b/libs/renderengine/skia/SkiaVkRenderEngine.cpp index 17f263d2ce..8821c0e97d 100644 --- a/libs/renderengine/skia/SkiaVkRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaVkRenderEngine.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -603,11 +604,11 @@ SkiaRenderEngine::Contexts SkiaVkRenderEngine::createDirectContexts( sSetupVulkanInterface(); SkiaRenderEngine::Contexts contexts; - contexts.first = GrDirectContext::MakeVulkan(sVulkanInterface.getBackendContext(), options); + contexts.first = GrDirectContexts::MakeVulkan(sVulkanInterface.getBackendContext(), options); if (supportsProtectedContentImpl()) { contexts.second = - GrDirectContext::MakeVulkan(sProtectedContentVulkanInterface.getBackendContext(), - options); + GrDirectContexts::MakeVulkan(sProtectedContentVulkanInterface.getBackendContext(), + options); } return contexts; -- GitLab From 453ae736b8cd0e9993077fa530f82e813eb65d6b Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 13 Oct 2023 14:30:14 +0000 Subject: [PATCH 0812/1187] Add a test case to ensure hover enter/exit synth is WAI when mirrored Adding the mirrored test case for completeness. Bug: 299074463 Test: atest inputflinger_tests Change-Id: I20532e3487fb7a64a144d1a4bcf63ea27e88dca4 --- .../tests/InputDispatcher_test.cpp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index ff3eff16eb..34323c33c2 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -4682,6 +4682,38 @@ TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverEnterExitWithCorrect firstWindow->assertNoEvents(); } +// Same as above, but while the window is being mirrored. +TEST_F(InputDispatcherDisplayProjectionTest, + SynthesizeHoverEnterExitWithCorrectCoordinatesWhenMirrored) { + auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); + + const std::array matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; + ui::Transform secondDisplayTransform; + secondDisplayTransform.set(matrix); + addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform); + + sp secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID); + secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4); + addWindow(secondWindowClone); + + // Send hover move to the second window, and ensure it shows up as hover enter. + mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS, + ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); + secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), + WithCoords(100, 80), WithRawCoords(300, 880))); + + // Touch down at the same location and ensure a hover exit is synthesized for the correct + // display. + mDispatcher->notifyMotion(generateMotionArgs(ACTION_DOWN, AINPUT_SOURCE_STYLUS, + ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); + secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80), + WithRawCoords(300, 880))); + secondWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_DOWN), WithCoords(100, 80), WithRawCoords(300, 880))); + secondWindow->assertNoEvents(); + firstWindow->assertNoEvents(); +} + TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinates) { auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); @@ -4699,6 +4731,7 @@ TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorre firstWindow->assertNoEvents(); } +// Same as above, but while the window is being mirrored. TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) { auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); -- GitLab From fd028785dbe4e2281b798ae9a93e93b8c9ea4104 Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Fri, 13 Oct 2023 14:39:53 +0000 Subject: [PATCH 0813/1187] SF: use 'base::GetBoolProperty' Simple clean-up, as I was in the area. Test: manual - check that the cache is still being generated Change-Id: I4e1ab726064cdfa45d7adbd321d0647bab4507b6 --- services/surfaceflinger/SurfaceFlinger.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e08690a2bb..1ea4bcd70a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -864,9 +864,7 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { mPowerAdvisor->init(); - char primeShaderCache[PROPERTY_VALUE_MAX]; - property_get("service.sf.prime_shader_cache", primeShaderCache, "1"); - if (atoi(primeShaderCache)) { + if (base::GetBoolProperty("service.sf.prime_shader_cache"s, true)) { if (setSchedFifo(false) != NO_ERROR) { ALOGW("Can't set SCHED_OTHER for primeCache"); } -- GitLab From 8f91fe5593a7e2e73c6fddd0bc1de5ab0d9f204b Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 9 Oct 2023 22:08:43 +0000 Subject: [PATCH 0814/1187] libbinder: trusty, move libutils sources These are now moved. Bug: 302720583 Test: TH Change-Id: Ic4987694777378a0dcc886a42621a392e47dfc1d --- libs/binder/trusty/kernel/rules.mk | 23 ++++++++--------------- libs/binder/trusty/rules.mk | 23 ++++++++--------------- 2 files changed, 16 insertions(+), 30 deletions(-) diff --git a/libs/binder/trusty/kernel/rules.mk b/libs/binder/trusty/kernel/rules.mk index ab7a50d3f7..f6e894c064 100644 --- a/libs/binder/trusty/kernel/rules.mk +++ b/libs/binder/trusty/kernel/rules.mk @@ -37,22 +37,15 @@ MODULE_SRCS := \ $(LIBBINDER_DIR)/Utils.cpp \ $(LIBBASE_DIR)/hex.cpp \ $(LIBBASE_DIR)/stringprintf.cpp \ - $(LIBUTILS_DIR)/Errors.cpp \ + $(LIBUTILS_DIR)/binder/Errors.cpp \ + $(LIBUTILS_DIR)/binder/RefBase.cpp \ + $(LIBUTILS_DIR)/binder/SharedBuffer.cpp \ + $(LIBUTILS_DIR)/binder/String16.cpp \ + $(LIBUTILS_DIR)/binder/String8.cpp \ + $(LIBUTILS_DIR)/binder/StrongPointer.cpp \ + $(LIBUTILS_DIR)/binder/Unicode.cpp \ + $(LIBUTILS_DIR)/binder/VectorImpl.cpp \ $(LIBUTILS_DIR)/misc.cpp \ - $(LIBUTILS_DIR)/RefBase.cpp \ - $(LIBUTILS_DIR)/StrongPointer.cpp \ - $(LIBUTILS_DIR)/Unicode.cpp \ - -# TODO: remove the following when libbinder supports std::string -# instead of String16 and String8 for Status and descriptors -MODULE_SRCS += \ - $(LIBUTILS_DIR)/SharedBuffer.cpp \ - $(LIBUTILS_DIR)/String16.cpp \ - $(LIBUTILS_DIR)/String8.cpp \ - -# TODO: disable dump() transactions to get rid of Vector -MODULE_SRCS += \ - $(LIBUTILS_DIR)/VectorImpl.cpp \ MODULE_DEFINES += \ LK_DEBUGLEVEL_NO_ALIASES=1 \ diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk index 42db29a2ef..9df9a5501f 100644 --- a/libs/binder/trusty/rules.mk +++ b/libs/binder/trusty/rules.mk @@ -45,22 +45,15 @@ MODULE_SRCS := \ $(LIBBINDER_DIR)/Utils.cpp \ $(LIBBASE_DIR)/hex.cpp \ $(LIBBASE_DIR)/stringprintf.cpp \ - $(LIBUTILS_DIR)/Errors.cpp \ + $(LIBUTILS_DIR)/binder/Errors.cpp \ + $(LIBUTILS_DIR)/binder/RefBase.cpp \ + $(LIBUTILS_DIR)/binder/SharedBuffer.cpp \ + $(LIBUTILS_DIR)/binder/String16.cpp \ + $(LIBUTILS_DIR)/binder/String8.cpp \ + $(LIBUTILS_DIR)/binder/StrongPointer.cpp \ + $(LIBUTILS_DIR)/binder/Unicode.cpp \ + $(LIBUTILS_DIR)/binder/VectorImpl.cpp \ $(LIBUTILS_DIR)/misc.cpp \ - $(LIBUTILS_DIR)/RefBase.cpp \ - $(LIBUTILS_DIR)/StrongPointer.cpp \ - $(LIBUTILS_DIR)/Unicode.cpp \ - -# TODO: remove the following when libbinder supports std::string -# instead of String16 and String8 for Status and descriptors -MODULE_SRCS += \ - $(LIBUTILS_DIR)/SharedBuffer.cpp \ - $(LIBUTILS_DIR)/String16.cpp \ - $(LIBUTILS_DIR)/String8.cpp \ - -# TODO: disable dump() transactions to get rid of Vector -MODULE_SRCS += \ - $(LIBUTILS_DIR)/VectorImpl.cpp \ MODULE_EXPORT_INCLUDES += \ $(LOCAL_DIR)/include \ -- GitLab From 614cc2438a87e72810feb646a27073be9d4a9ac1 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 13 Oct 2023 18:35:45 +0000 Subject: [PATCH 0815/1187] servicemanager_fuzzer: fix ODR libbinder was statically included from service defaults and shared included by servicemanager_defaults. For some reason, this worked before, but it is now broken. Bug: N/A Test: N/A Change-Id: I69a037eb8f2f80b7832cba88ae94d618af3dca44 --- cmds/servicemanager/Android.bp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index d73a30bf9b..e00c2a2b5a 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -24,7 +24,6 @@ cc_defaults { shared_libs: [ "libbase", - "libbinder", // also contains servicemanager_interface "libvintf", "libcutils", "liblog", @@ -33,6 +32,21 @@ cc_defaults { ], target: { + android: { + shared_libs: [ + "libbinder", + "libutils", + ], + }, + host: { + static_libs: [ + "libbinder", + "libutils", + ], + }, + darwin: { + enabled: false, + }, vendor: { exclude_shared_libs: ["libvintf"], }, -- GitLab From 442907b0f89717bc72cd9b07ce06ebfceb0ce89d Mon Sep 17 00:00:00 2001 From: Keith Mok Date: Wed, 11 Oct 2023 20:36:18 +0000 Subject: [PATCH 0816/1187] RPC binder: set TCP_NDELAY System by default cache TCP data trying to pack more data before sending out to the wire, this cause delay in rpc communication. Currently we set TCP_NDELAY in RpcSession, but not in RpcServer. This CL add TCP_NDELAY to RpcServer also. Bug: 304823925 Test: manual Change-Id: I8bfda370a78eff9b8e0ab75e6bc2fd0a5ba743ed --- libs/binder/RpcServer.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 55fc16de45..03dad2baca 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "RpcServer" #include +#include #include #include #include @@ -572,6 +573,17 @@ status_t RpcServer::setupSocketServer(const RpcSocketAddress& addr) { return -savedErrno; } + if (addr.addr()->sa_family == AF_INET || addr.addr()->sa_family == AF_INET6) { + int noDelay = 1; + int result = + setsockopt(socket_fd.get(), IPPROTO_TCP, TCP_NODELAY, &noDelay, sizeof(noDelay)); + if (result < 0) { + int savedErrno = errno; + ALOGE("Could not set TCP_NODELAY on %s", strerror(savedErrno)); + return -savedErrno; + } + } + { RpcMutexLockGuard _l(mLock); if (mServerSocketModifier != nullptr) { -- GitLab From e339cf4ed5d2cf0ac632f6921466a1db469fa6e8 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 13 Oct 2023 18:40:58 +0000 Subject: [PATCH 0817/1187] binder random fd: always nonblock blocking sockets can cause the fuzzer to hang. While we'd like to fix these issues, they're of secondary importance, so forcing nonblock here for now. Bug: 236812909 Test: servicemanager_fuzzer Change-Id: Ic7ee9cd185c448a227fd23a916dd94feb05f735a --- libs/binder/tests/parcel_fuzzer/random_fd.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp index 7390d497c4..4a9bd07c6e 100644 --- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp @@ -51,7 +51,9 @@ std::vector getRandomFds(FuzzedDataProvider* provider) { int flags = O_CLOEXEC; if (provider->ConsumeBool()) flags |= O_DIRECT; - if (provider->ConsumeBool()) flags |= O_NONBLOCK; + + // TODO(b/236812909): also test blocking + if (true) flags |= O_NONBLOCK; CHECK_EQ(0, pipe2(pipefds, flags)) << flags; -- GitLab From 50858e61d95220b67a0eac75429c5b5f8a6076a5 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 13 Oct 2023 23:28:24 +0000 Subject: [PATCH 0818/1187] Destroy transaction tracing from main thread Fixes: 304996860 Test: presubmit Change-Id: I3b11570fdb3ea5ba42124f23667be0dfd7d8af11 --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e08690a2bb..358aab922c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -7060,7 +7060,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r if (mTransactionTracing) { int arg = data.readInt32(); if (arg == -1) { - mTransactionTracing.reset(); + mScheduler->schedule([&]() { mTransactionTracing.reset(); }).get(); } else if (arg > 0) { // Transaction tracing is always running but allow the user to temporarily // increase the buffer when actively debugging. -- GitLab From 316b7f443541f6220ef6b51d8fa5d63ec72736f0 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 13 Oct 2023 23:44:46 +0000 Subject: [PATCH 0819/1187] Fix mPreviouslyPresentedLayerStacks leak for bufferless layers Fix: 295344852 Test: presubmit Change-Id: Ib906c9002c56b8a7398cfcc2ede4a07be7484ce0 --- services/surfaceflinger/Layer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 0c1c014640..da87e8e0fc 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2941,7 +2941,9 @@ void Layer::onLayerDisplayed(ftl::SharedFuture futureFenceResult, ch->previousReleaseFences.emplace_back(std::move(futureFenceResult)); ch->name = mName; } - mPreviouslyPresentedLayerStacks.push_back(layerStack); + if (mBufferInfo.mBuffer) { + mPreviouslyPresentedLayerStacks.push_back(layerStack); + } } void Layer::onSurfaceFrameCreated( -- GitLab From 2f51e7564194653ef5371179584853b5f39881d1 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Thu, 15 Jun 2023 22:35:14 +0000 Subject: [PATCH 0820/1187] Clean up ANGLE integration logic. Rename variables to clarify the meanings, remove unused methods. Bug: b/283858001 Test: test with camera with dialog on Test: atest CtsAngleIntegrationHostTestCases Change-Id: I1db89b79879dec663f198fd3faad7501a3511698 Merged-In: I1db89b79879dec663f198fd3faad7501a3511698 --- libs/graphicsenv/GraphicsEnv.cpp | 74 ++++++------------ .../include/graphicsenv/GraphicsEnv.h | 76 +++++++++++-------- opengl/libs/EGL/Loader.cpp | 23 +++--- opengl/libs/EGL/Loader.h | 2 +- opengl/libs/EGL/egl_display.cpp | 6 +- opengl/libs/EGL/egl_object.cpp | 2 +- opengl/libs/EGL/egl_platform_entries.cpp | 16 ++-- opengl/libs/EGL/egldefs.h | 5 +- 8 files changed, 96 insertions(+), 108 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 16315ed858..1a638c1e5b 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -160,8 +160,8 @@ bool GraphicsEnv::isDebuggable() { return appDebuggable || platformDebuggable; } -void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string path, - const std::string sphalLibraries) { +void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string& path, + const std::string& sphalLibraries) { if (!mDriverPath.empty() || !mSphalLibraries.empty()) { ALOGV("ignoring attempt to change driver path from '%s' to '%s' or change sphal libraries " "from '%s' to '%s'", @@ -410,55 +410,24 @@ bool GraphicsEnv::setInjectLayersPrSetDumpable() { return true; } -void* GraphicsEnv::loadLibrary(std::string name) { - const android_dlextinfo dlextinfo = { - .flags = ANDROID_DLEXT_USE_NAMESPACE, - .library_namespace = getAngleNamespace(), - }; - - std::string libName = std::string("lib") + name + "_angle.so"; - - void* so = android_dlopen_ext(libName.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo); - - if (so) { - ALOGD("dlopen_ext from APK (%s) success at %p", libName.c_str(), so); - return so; - } else { - ALOGE("dlopen_ext(\"%s\") failed: %s", libName.c_str(), dlerror()); - } - - return nullptr; -} - -bool GraphicsEnv::shouldUseAngle(std::string appName) { - if (appName != mAngleAppName) { - // Make sure we are checking the app we were init'ed for - ALOGE("App name does not match: expected '%s', got '%s'", mAngleAppName.c_str(), - appName.c_str()); - return false; - } - - return shouldUseAngle(); -} - bool GraphicsEnv::shouldUseAngle() { // Make sure we are init'ed - if (mAngleAppName.empty()) { - ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE."); + if (mPackageName.empty()) { + ALOGV("Package name is empty. setAngleInfo() has not been called to enable ANGLE."); return false; } - return (mUseAngle == YES) ? true : false; + return (mShouldUseAngle == YES) ? true : false; } -void GraphicsEnv::updateUseAngle() { +void GraphicsEnv::updateShouldUseAngle() { const char* ANGLE_PREFER_ANGLE = "angle"; const char* ANGLE_PREFER_NATIVE = "native"; - mUseAngle = NO; + mShouldUseAngle = NO; if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) { ALOGV("User set \"Developer Options\" to force the use of ANGLE"); - mUseAngle = YES; + mShouldUseAngle = YES; } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) { ALOGV("User set \"Developer Options\" to force the use of Native"); } else { @@ -466,13 +435,13 @@ void GraphicsEnv::updateUseAngle() { } } -void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName, - const std::string developerOptIn, +void GraphicsEnv::setAngleInfo(const std::string& path, const std::string& packageName, + const std::string& developerOptIn, const std::vector eglFeatures) { - if (mUseAngle != UNKNOWN) { + if (mShouldUseAngle != UNKNOWN) { // We've already figured out an answer for this app, so just return. - ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", appName.c_str(), - (mUseAngle == YES) ? "true" : "false"); + ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", packageName.c_str(), + (mShouldUseAngle == YES) ? "true" : "false"); return; } @@ -480,16 +449,17 @@ void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName ALOGV("setting ANGLE path to '%s'", path.c_str()); mAnglePath = path; - ALOGV("setting ANGLE app name to '%s'", appName.c_str()); - mAngleAppName = appName; + ALOGV("setting app package name to '%s'", packageName.c_str()); + mPackageName = packageName; ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str()); mAngleDeveloperOptIn = developerOptIn; // Update the current status of whether we should use ANGLE or not - updateUseAngle(); + updateShouldUseAngle(); } -void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) { +void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, + const std::string& layerPaths) { if (mLayerPaths.empty()) { mLayerPaths = layerPaths; mAppNamespace = appNamespace; @@ -503,8 +473,8 @@ NativeLoaderNamespace* GraphicsEnv::getAppNamespace() { return mAppNamespace; } -std::string& GraphicsEnv::getAngleAppName() { - return mAngleAppName; +std::string& GraphicsEnv::getPackageName() { + return mPackageName; } const std::vector& GraphicsEnv::getAngleEglFeatures() { @@ -523,11 +493,11 @@ const std::string& GraphicsEnv::getDebugLayersGLES() { return mDebugLayersGLES; } -void GraphicsEnv::setDebugLayers(const std::string layers) { +void GraphicsEnv::setDebugLayers(const std::string& layers) { mDebugLayers = layers; } -void GraphicsEnv::setDebugLayersGLES(const std::string layers) { +void GraphicsEnv::setDebugLayersGLES(const std::string& layers) { mDebugLayersGLES = layers; } diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index f9b234a047..a1b5e50c93 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -55,7 +55,7 @@ public: // Also set additional required sphal libraries to the linker for loading // graphics drivers. The string is a list of libraries separated by ':', // which is required by android_link_namespaces. - void setDriverPathAndSphalLibraries(const std::string path, const std::string sphalLibraries); + void setDriverPathAndSphalLibraries(const std::string& path, const std::string& sphalLibraries); // Get the updatable driver namespace. android_namespace_t* getDriverNamespace(); std::string getDriverPath() const; @@ -96,8 +96,6 @@ public: /* * Apis for ANGLE */ - // Check if the requested app should use ANGLE. - bool shouldUseAngle(std::string appName); // Check if this app process should use ANGLE. bool shouldUseAngle(); // Set a search path for loading ANGLE libraries. The path is a list of @@ -105,42 +103,39 @@ public: // (libraries must be stored uncompressed and page aligned); such elements // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a - void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn, - const std::vector eglFeatures); + void setAngleInfo(const std::string& path, const std::string& packageName, + const std::string& devOptIn, const std::vector eglFeatures); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); - // Get the app name for ANGLE debug message. - std::string& getAngleAppName(); - + // Get the app package name. + std::string& getPackageName(); const std::vector& getAngleEglFeatures(); + // Set the persist.graphics.egl system property value. + void nativeToggleAngleAsSystemDriver(bool enabled); /* * Apis for debug layer */ // Set additional layer search paths. - void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths); + void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string& layerPaths); // Get the app namespace for loading layers. NativeLoaderNamespace* getAppNamespace(); // Get additional layer search paths. const std::string& getLayerPaths(); // Set the Vulkan debug layers. - void setDebugLayers(const std::string layers); + void setDebugLayers(const std::string& layers); // Set the GL debug layers. - void setDebugLayersGLES(const std::string layers); + void setDebugLayersGLES(const std::string& layers); // Get the debug layers to load. const std::string& getDebugLayers(); // Get the debug layers to load. const std::string& getDebugLayersGLES(); - // Set the persist.graphics.egl system property value. - void nativeToggleAngleAsSystemDriver(bool enabled); private: enum UseAngle { UNKNOWN, YES, NO }; - // Load requested ANGLE library. - void* loadLibrary(std::string name); // Update whether ANGLE should be used. - void updateUseAngle(); + void updateShouldUseAngle(); // Link updatable driver namespace with llndk and vndk-sp libs. bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace); // Check whether this process is ready to send stats. @@ -149,39 +144,56 @@ private: void sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); GraphicsEnv() = default; + + // This mutex protects the namespace creation. + std::mutex mNamespaceMutex; + + /** + * Updatable driver variables. + */ // Path to updatable driver libs. std::string mDriverPath; // Path to additional sphal libs linked to updatable driver namespace. std::string mSphalLibraries; - // This mutex protects mGpuStats and get gpuservice call. - std::mutex mStatsLock; - // Cache the activity launch info - bool mActivityLaunched = false; - // Information bookkept for GpuStats. - GpuStatsInfo mGpuStats; + // Updatable driver namespace. + android_namespace_t* mDriverNamespace = nullptr; + + /** + * ANGLE variables. + */ // Path to ANGLE libs. std::string mAnglePath; - // This App's name. - std::string mAngleAppName; + // App's package name. + std::string mPackageName; // ANGLE developer opt in status. std::string mAngleDeveloperOptIn; // ANGLE EGL features; std::vector mAngleEglFeatures; // Use ANGLE flag. - UseAngle mUseAngle = UNKNOWN; + UseAngle mShouldUseAngle = UNKNOWN; + // ANGLE namespace. + android_namespace_t* mAngleNamespace = nullptr; + + /** + * GPU metrics. + */ + // This mutex protects mGpuStats and get gpuservice call. + std::mutex mStatsLock; + // Cache the activity launch info + bool mActivityLaunched = false; + // Information bookkept for GpuStats. + GpuStatsInfo mGpuStats; + + /** + * Debug layers. + */ // Vulkan debug layers libs. std::string mDebugLayers; // GL debug layers libs. std::string mDebugLayersGLES; // Additional debug layers search path. std::string mLayerPaths; - // This mutex protects the namespace creation. - std::mutex mNamespaceMutex; - // Updatable driver namespace. - android_namespace_t* mDriverNamespace = nullptr; - // ANGLE namespace. - android_namespace_t* mAngleNamespace = nullptr; - // This App's namespace. + // This App's namespace to open native libraries. NativeLoaderNamespace* mAppNamespace = nullptr; }; diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index bb3b43abb5..b4fc5f0dd2 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -147,13 +147,18 @@ static const char* HAL_SUBNAME_KEY_PROPERTIES[3] = { RO_BOARD_PLATFORM_PROPERTY, }; +// Check whether the loaded system drivers should be unloaded in order to +// load ANGLE or the updatable graphics drivers. +// If ANGLE namespace is set, it means the application is identified to run on top of ANGLE. +// If updatable graphics driver namespace is set, it means the application is identified to +// run on top of updatable graphics drivers. static bool should_unload_system_driver(egl_connection_t* cnx) { // Return false if the system driver has been unloaded once. if (cnx->systemDriverUnloaded) { return false; } - // Return true if Angle namespace is set. + // Return true if ANGLE namespace is set. android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace(); if (ns) { return true; @@ -279,10 +284,10 @@ void* Loader::open(egl_connection_t* cnx) false, systemTime() - openTime); } else { // init_angle_backend will check if loaded driver is ANGLE or not, - // will set cnx->useAngle appropriately. + // will set cnx->angleLoaded appropriately. // Do this here so that we use ANGLE path when driver is ANGLE (e.g. loaded as native), // not just loading ANGLE as option. - init_angle_backend(hnd->dso[2], cnx); + attempt_to_init_angle_backend(hnd->dso[2], cnx); } LOG_ALWAYS_FATAL_IF(!hnd, @@ -324,7 +329,7 @@ void Loader::close(egl_connection_t* cnx) delete hnd; cnx->dso = nullptr; - cnx->useAngle = false; + cnx->angleLoaded = false; } void Loader::init_api(void* dso, @@ -565,14 +570,14 @@ Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) { return hnd; } -void Loader::init_angle_backend(void* dso, egl_connection_t* cnx) { +void Loader::attempt_to_init_angle_backend(void* dso, egl_connection_t* cnx) { void* pANGLEGetDisplayPlatform = dlsym(dso, "ANGLEGetDisplayPlatform"); if (pANGLEGetDisplayPlatform) { - ALOGV("ANGLE GLES library in use"); - cnx->useAngle = true; + ALOGV("ANGLE GLES library loaded"); + cnx->angleLoaded = true; } else { - ALOGV("Native GLES library in use"); - cnx->useAngle = false; + ALOGV("Native GLES library loaded"); + cnx->angleLoaded = false; } } diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h index 81742ab9ae..cadbd4639b 100644 --- a/opengl/libs/EGL/Loader.h +++ b/opengl/libs/EGL/Loader.h @@ -57,7 +57,7 @@ private: driver_t* attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix, const bool exact); void unload_system_driver(egl_connection_t* cnx); void initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask); - void init_angle_backend(void* dso, egl_connection_t* cnx); + void attempt_to_init_angle_backend(void* dso, egl_connection_t* cnx); static __attribute__((noinline)) void init_api(void* dso, const char* const* api, const char* const* ref_api, diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index 525fed115d..3317347066 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -191,7 +191,7 @@ EGLDisplay egl_display_t::getPlatformDisplay(EGLNativeDisplayType display, if (cnx->dso) { EGLDisplay dpy = EGL_NO_DISPLAY; - if (cnx->useAngle) { + if (cnx->angleLoaded) { EGLint error; dpy = getPlatformDisplayAngle(display, cnx, attrib_list, &error); if (error != EGL_NONE) { @@ -324,7 +324,7 @@ EGLBoolean egl_display_t::initialize(EGLint* major, EGLint* minor) { // b/269060366 Conditionally enabled EGL_ANDROID_get_frame_timestamps extension if the // device's present timestamps are reliable (which may not be the case on emulators). - if (cnx->useAngle) { + if (cnx->angleLoaded) { if (android::base::GetBoolProperty("service.sf.present_timestamp", false)) { mExtensionString.append("EGL_ANDROID_get_frame_timestamps "); } @@ -432,7 +432,7 @@ EGLBoolean egl_display_t::terminate() { egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso && disp.state == egl_display_t::INITIALIZED) { // If we're using ANGLE reset any custom DisplayPlatform - if (cnx->useAngle) { + if (cnx->angleLoaded) { angle::resetAnglePlatform(disp.dpy); } if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) { diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp index efbe613542..33a77c4470 100644 --- a/opengl/libs/EGL/egl_object.cpp +++ b/opengl/libs/EGL/egl_object.cpp @@ -84,7 +84,7 @@ void egl_surface_t::disconnect() { if (win != nullptr && connected) { // NOTE: When using Vulkan backend, the Vulkan runtime makes all the // native_window_* calls, so don't do them here. - if (!cnx->useAngle) { + if (!cnx->angleLoaded) { native_window_set_buffers_format(win, 0); if (native_window_api_disconnect(win, NATIVE_WINDOW_API_EGL)) { ALOGW("EGLNativeWindowType %p disconnect failed", win); diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp index aefa1f0db5..440eb17873 100644 --- a/opengl/libs/EGL/egl_platform_entries.cpp +++ b/opengl/libs/EGL/egl_platform_entries.cpp @@ -685,7 +685,7 @@ EGLSurface eglCreateWindowSurfaceTmpl(egl_display_t* dp, egl_connection_t* cnx, // NOTE: When using Vulkan backend, the Vulkan runtime makes all the // native_window_* calls, so don't do them here. - if (!cnx->useAngle) { + if (!cnx->angleLoaded) { int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL); if (result < 0) { ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) " @@ -704,14 +704,14 @@ EGLSurface eglCreateWindowSurfaceTmpl(egl_display_t* dp, egl_connection_t* cnx, std::vector strippedAttribList; if (!processAttributes(dp, window, attrib_list, &colorSpace, &strippedAttribList)) { ALOGE("error invalid colorspace: %d", colorSpace); - if (!cnx->useAngle) { + if (!cnx->angleLoaded) { native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); } return EGL_NO_SURFACE; } attrib_list = strippedAttribList.data(); - if (!cnx->useAngle) { + if (!cnx->angleLoaded) { int err = native_window_set_buffers_format(window, static_cast(format)); if (err != 0) { ALOGE("error setting native window pixel format: %s (%d)", strerror(-err), err); @@ -743,7 +743,7 @@ EGLSurface eglCreateWindowSurfaceTmpl(egl_display_t* dp, egl_connection_t* cnx, } // EGLSurface creation failed - if (!cnx->useAngle) { + if (!cnx->angleLoaded) { native_window_set_buffers_format(window, 0); native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); } @@ -1354,7 +1354,7 @@ EGLBoolean eglSwapBuffersWithDamageKHRImpl(EGLDisplay dpy, EGLSurface draw, EGLi } } - if (!s->cnx->useAngle) { + if (!s->cnx->angleLoaded) { if (!sendSurfaceMetadata(s)) { native_window_api_disconnect(s->getNativeWindow(), NATIVE_WINDOW_API_EGL); return setError(EGL_BAD_NATIVE_WINDOW, (EGLBoolean)EGL_FALSE); @@ -1379,7 +1379,7 @@ EGLBoolean eglSwapBuffersWithDamageKHRImpl(EGLDisplay dpy, EGLSurface draw, EGLi androidRect.bottom = y; androidRects.push_back(androidRect); } - if (!s->cnx->useAngle) { + if (!s->cnx->angleLoaded) { native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(), androidRects.size()); } @@ -1470,7 +1470,7 @@ EGLBoolean eglSurfaceAttribImpl(EGLDisplay dpy, EGLSurface surface, EGLint attri int err = native_window_set_auto_refresh(s->getNativeWindow(), value != 0); if (err != 0) { return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } else if (!s->cnx->useAngle) { + } else if (!s->cnx->angleLoaded) { return EGL_TRUE; } // else if ANGLE, fall through to the call to the driver (i.e. ANGLE) below } @@ -1484,7 +1484,7 @@ EGLBoolean eglSurfaceAttribImpl(EGLDisplay dpy, EGLSurface surface, EGLint attri int err = native_window_enable_frame_timestamps(s->getNativeWindow(), value != 0); if (err != 0) { return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE); - } else if (!s->cnx->useAngle) { + } else if (!s->cnx->angleLoaded) { return EGL_TRUE; } // else if ANGLE, fall through to the call to the driver (i.e. ANGLE) below } diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h index fcc11f1b55..3bd37cb399 100644 --- a/opengl/libs/EGL/egldefs.h +++ b/opengl/libs/EGL/egldefs.h @@ -41,7 +41,8 @@ struct egl_connection_t { libEgl(nullptr), libGles1(nullptr), libGles2(nullptr), - systemDriverUnloaded(false) { + systemDriverUnloaded(false), + angleLoaded(false) { const char* const* entries = platform_names; EGLFuncPointer* curr = reinterpret_cast(&platform); while (*entries) { @@ -73,7 +74,7 @@ struct egl_connection_t { void* libGles2; bool systemDriverUnloaded; - bool useAngle; // Was ANGLE successfully loaded + bool angleLoaded; // Was ANGLE successfully loaded }; extern gl_hooks_t gHooks[2]; -- GitLab From 6a45a054a228db626e92f21d930f1da37012b184 Mon Sep 17 00:00:00 2001 From: jiayongqiang Date: Mon, 16 Oct 2023 17:29:46 +0800 Subject: [PATCH 0821/1187] Remove redundant call in Layer's constructor. 'mDrawingState.crop.makeInvalid()' has been called twice in the approach of Layer::Layer(const LayerCreationArgs& args), so remove the second call. Test: atest LayerSnapshotTest, LayerTest Change-Id: I4cc40d9ec697ff20a1b71fa7aa50f09cef6c7afc Signed-off-by: jiayongqiang --- services/surfaceflinger/Layer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index f12aab766e..7ea547dece 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -172,7 +172,6 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.barrierProducerId = 0; mDrawingState.bufferTransform = 0; mDrawingState.transformToDisplayInverse = false; - mDrawingState.crop.makeInvalid(); mDrawingState.acquireFence = sp::make(-1); mDrawingState.acquireFenceTime = std::make_shared(mDrawingState.acquireFence); mDrawingState.dataspace = ui::Dataspace::V0_SRGB; -- GitLab From 9399243816f042d1348f6e4558ecbe41ca22312f Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 9 Oct 2023 15:47:48 -0700 Subject: [PATCH 0822/1187] input_verifier: add isolated MotionEvent checks Previously, we were checking the consistency of MotionEvents inside input_verifier in one large 'match' statement. However, the verifier should only be used to check whether a given MotionEvent makes sense in relation to all of the preceding motions. To improve the situation, in this CL some checks are moved into a separate function. Those checks allow us to test whether the event itself makes sense. If the event is bad, then no need to do the remaining checks in input_verifier. This CL makes the rust code a bit closer to the current checks implemented in the InputDispatcher. Bug: 211379801 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: I60437797980f4f8f050023419a03d80e4ee4e1f1 --- libs/input/rust/input.rs | 1 + libs/input/rust/input_verifier.rs | 85 +++++++++++++++++++++++-------- 2 files changed, 66 insertions(+), 20 deletions(-) diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs index 804f96db98..705c959d04 100644 --- a/libs/input/rust/input.rs +++ b/libs/input/rust/input.rs @@ -180,6 +180,7 @@ impl MotionAction { bitflags! { /// MotionEvent flags. + #[derive(Debug)] pub struct MotionFlags: u32 { /// FLAG_CANCELED const CANCELED = input_bindgen::AMOTION_EVENT_FLAG_CANCELED as u32; diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs index 2d94e70309..bbc6d98847 100644 --- a/libs/input/rust/input_verifier.rs +++ b/libs/input/rust/input_verifier.rs @@ -22,6 +22,49 @@ use log::info; use std::collections::HashMap; use std::collections::HashSet; +fn verify_event( + action: MotionAction, + pointer_properties: &[RustPointerProperties], + flags: &MotionFlags, +) -> Result<(), String> { + let pointer_count = pointer_properties.len(); + if pointer_count < 1 { + return Err(format!("Invalid {} event: no pointers", action)); + } + match action { + MotionAction::Down + | MotionAction::HoverEnter + | MotionAction::HoverExit + | MotionAction::HoverMove + | MotionAction::Up => { + if pointer_count != 1 { + return Err(format!( + "Invalid {} event: there are {} pointers in the event", + action, pointer_count + )); + } + } + + MotionAction::Cancel => { + if !flags.contains(MotionFlags::CANCELED) { + return Err(format!( + "For ACTION_CANCEL, must set FLAG_CANCELED. Received flags: {:#?}", + flags + )); + } + } + + MotionAction::PointerDown { action_index } | MotionAction::PointerUp { action_index } => { + if action_index >= pointer_count { + return Err(format!("Got {}, but event has {} pointer(s)", action, pointer_count)); + } + } + + _ => {} + } + Ok(()) +} + /// The InputVerifier is used to validate a stream of input events. pub struct InputVerifier { name: String, @@ -71,15 +114,10 @@ impl InputVerifier { ); } + verify_event(action.into(), pointer_properties, &flags)?; + match action.into() { MotionAction::Down => { - if pointer_properties.len() != 1 { - return Err(format!( - "{}: Invalid DOWN event: there are {} pointers in the event", - self.name, - pointer_properties.len() - )); - } let it = self .touching_pointer_ids_by_device .entry(device_id) @@ -140,13 +178,6 @@ impl InputVerifier { it.remove(&pointer_id); } MotionAction::Up => { - if pointer_properties.len() != 1 { - return Err(format!( - "{}: Invalid UP event: there are {} pointers in the event", - self.name, - pointer_properties.len() - )); - } if !self.touching_pointer_ids_by_device.contains_key(&device_id) { return Err(format!( "{} Received ACTION_UP but no pointers are currently down for device {:?}", @@ -171,12 +202,6 @@ impl InputVerifier { self.touching_pointer_ids_by_device.remove(&device_id); } MotionAction::Cancel => { - if !flags.contains(MotionFlags::CANCELED) { - return Err(format!( - "{}: For ACTION_CANCEL, must set FLAG_CANCELED", - self.name - )); - } if !self.ensure_touching_pointers_match(device_id, pointer_properties) { return Err(format!( "{}: Got ACTION_CANCEL, but the pointers don't match. \ @@ -274,6 +299,26 @@ mod tests { use crate::MotionFlags; use crate::RustPointerProperties; use crate::Source; + + #[test] + /** + * Send a DOWN event with 2 pointers and ensure that it's marked as invalid. + */ + fn bad_down_event() { + let mut verifier = InputVerifier::new("Test", /*should_log*/ true); + let pointer_properties = + Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]); + assert!(verifier + .process_movement( + DeviceId(1), + Source::Touchscreen, + input_bindgen::AMOTION_EVENT_ACTION_DOWN, + &pointer_properties, + MotionFlags::empty(), + ) + .is_err()); + } + #[test] fn single_pointer_stream() { let mut verifier = InputVerifier::new("Test", /*should_log*/ false); -- GitLab From b9b5b706d449212094fd020dfd30509234a8c0b4 Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Fri, 13 Oct 2023 13:25:11 +0000 Subject: [PATCH 0823/1187] RenderEngine, SF: gate HDR priming behind property This should make it so that devices which do not see any benefit from priming those shaders can avoid computing them at boot time. Bug: b/295257834 Test: manual - delta of -37 shaders generated before/after this patch Test: atest librenderengine_test Change-Id: I01962b690d636def86c1ebed40187eaf74ab0246 --- .../include/renderengine/RenderEngine.h | 2 +- .../include/renderengine/mock/RenderEngine.h | 2 +- libs/renderengine/skia/Cache.cpp | 20 ++++++++----- libs/renderengine/skia/Cache.h | 2 +- libs/renderengine/skia/SkiaRenderEngine.cpp | 4 +-- libs/renderengine/skia/SkiaRenderEngine.h | 2 +- libs/renderengine/tests/RenderEngineTest.cpp | 2 +- .../tests/RenderEngineThreadedTest.cpp | 4 +-- .../threaded/RenderEngineThreaded.cpp | 29 ++++++++++--------- .../threaded/RenderEngineThreaded.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 4 ++- 11 files changed, 40 insertions(+), 33 deletions(-) diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index b992d82fdb..818d0350c0 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -107,7 +107,7 @@ public: // This interface, while still in use until a suitable replacement is built, // should be considered deprecated, minus some methods which still may be // used to support legacy behavior. - virtual std::future primeCache() = 0; + virtual std::future primeCache(bool shouldPrimeUltraHDR) = 0; // dump the extension strings. always call the base class. virtual void dump(std::string& result) = 0; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index 160006d5e6..a58a65ca9f 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -33,7 +33,7 @@ public: RenderEngine(); ~RenderEngine() override; - MOCK_METHOD0(primeCache, std::future()); + MOCK_METHOD1(primeCache, std::future(bool)); MOCK_METHOD1(dump, void(std::string&)); MOCK_CONST_METHOD0(getMaxTextureSize, size_t()); MOCK_CONST_METHOD0(getMaxViewportDims, size_t()); diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index 25296f06ee..abe0d9b0a6 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -17,6 +17,7 @@ #include "AutoBackendTexture.h" #include "SkiaRenderEngine.h" #include "android-base/unique_fd.h" +#include "cutils/properties.h" #include "renderengine/DisplaySettings.h" #include "renderengine/LayerSettings.h" #include "renderengine/impl/ExternalTexture.h" @@ -629,7 +630,7 @@ static void drawP3ImageLayers(SkiaRenderEngine* renderengine, const DisplaySetti // kFlushAfterEveryLayer = true // in external/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp // gPrintSKSL = true -void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { +void Cache::primeShaderCache(SkiaRenderEngine* renderengine, bool shouldPrimeUltraHDR) { const int previousCount = renderengine->reportShadersCompiled(); if (previousCount) { ALOGD("%d Shaders already compiled before Cache::primeShaderCache ran\n", previousCount); @@ -755,16 +756,19 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { externalTexture); drawClippedDimmedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture); - drawBT2020ClippedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture); - drawBT2020ImageLayers(renderengine, bt2020Display, dstTexture, externalTexture); - drawBT2020ImageLayers(renderengine, p3Display, dstTexture, externalTexture); + if (shouldPrimeUltraHDR) { + drawBT2020ClippedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture); - drawExtendedHDRImageLayers(renderengine, display, dstTexture, externalTexture); - drawExtendedHDRImageLayers(renderengine, p3Display, dstTexture, externalTexture); - drawExtendedHDRImageLayers(renderengine, p3DisplayEnhance, dstTexture, externalTexture); + drawBT2020ImageLayers(renderengine, bt2020Display, dstTexture, externalTexture); + drawBT2020ImageLayers(renderengine, p3Display, dstTexture, externalTexture); - drawP3ImageLayers(renderengine, p3DisplayEnhance, dstTexture, externalTexture); + drawExtendedHDRImageLayers(renderengine, display, dstTexture, externalTexture); + drawExtendedHDRImageLayers(renderengine, p3Display, dstTexture, externalTexture); + drawExtendedHDRImageLayers(renderengine, p3DisplayEnhance, dstTexture, externalTexture); + + drawP3ImageLayers(renderengine, p3DisplayEnhance, dstTexture, externalTexture); + } // draw one final layer synchronously to force GL submit LayerSettings layer{ diff --git a/libs/renderengine/skia/Cache.h b/libs/renderengine/skia/Cache.h index 437571e616..62f6705c89 100644 --- a/libs/renderengine/skia/Cache.h +++ b/libs/renderengine/skia/Cache.h @@ -22,7 +22,7 @@ class SkiaRenderEngine; class Cache { public: - static void primeShaderCache(SkiaRenderEngine*); + static void primeShaderCache(SkiaRenderEngine*, bool shouldPrimeUltraHDR); private: Cache() = default; diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index 7ec98eab97..3729be6ca2 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -243,8 +243,8 @@ namespace skia { using base::StringAppendF; -std::future SkiaRenderEngine::primeCache() { - Cache::primeShaderCache(this); +std::future SkiaRenderEngine::primeCache(bool shouldPrimeUltraHDR) { + Cache::primeShaderCache(this, shouldPrimeUltraHDR); return {}; } diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 3db0c1b58b..ac134afa64 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -62,7 +62,7 @@ public: SkiaRenderEngine(RenderEngineType type, PixelFormat pixelFormat, bool supportsBackgroundBlur); ~SkiaRenderEngine() override; - std::future primeCache() override final; + std::future primeCache(bool shouldPrimeUltraHDR) override final; void cleanupPostRender() override final; bool supportsBackgroundBlur() override final { return mBlurFilter != nullptr; diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 6023808aaf..11d4fdebdc 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -3204,7 +3204,7 @@ TEST_P(RenderEngineTest, primeShaderCache) { } initializeRenderEngine(); - auto fut = mRE->primeCache(); + auto fut = mRE->primeCache(false); if (fut.valid()) { fut.wait(); } diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index 7289fe721d..1b9adba063 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -50,8 +50,8 @@ TEST_F(RenderEngineThreadedTest, dump) { } TEST_F(RenderEngineThreadedTest, primeCache) { - EXPECT_CALL(*mRenderEngine, primeCache()); - mThreadedRE->primeCache(); + EXPECT_CALL(*mRenderEngine, primeCache(false)); + mThreadedRE->primeCache(false); // need to call ANY synchronous function after primeCache to ensure that primeCache has // completed asynchronously before the test completes execution. mThreadedRE->getContextPriority(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index 786a6fef12..367bee89f9 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -129,7 +129,7 @@ void RenderEngineThreaded::waitUntilInitialized() const { mInitializedCondition.wait(lock, [=] { return mIsInitialized; }); } -std::future RenderEngineThreaded::primeCache() { +std::future RenderEngineThreaded::primeCache(bool shouldPrimeUltraHDR) { const auto resultPromise = std::make_shared>(); std::future resultFuture = resultPromise->get_future(); ATRACE_CALL(); @@ -137,19 +137,20 @@ std::future RenderEngineThreaded::primeCache() { // for the futures. { std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([resultPromise](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::primeCache"); - if (setSchedFifo(false) != NO_ERROR) { - ALOGW("Couldn't set SCHED_OTHER for primeCache"); - } - - instance.primeCache(); - resultPromise->set_value(); - - if (setSchedFifo(true) != NO_ERROR) { - ALOGW("Couldn't set SCHED_FIFO for primeCache"); - } - }); + mFunctionCalls.push( + [resultPromise, shouldPrimeUltraHDR](renderengine::RenderEngine& instance) { + ATRACE_NAME("REThreaded::primeCache"); + if (setSchedFifo(false) != NO_ERROR) { + ALOGW("Couldn't set SCHED_OTHER for primeCache"); + } + + instance.primeCache(shouldPrimeUltraHDR); + resultPromise->set_value(); + + if (setSchedFifo(true) != NO_ERROR) { + ALOGW("Couldn't set SCHED_FIFO for primeCache"); + } + }); } mCondition.notify_one(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 1093f5fad3..74af2bd776 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -42,7 +42,7 @@ public: RenderEngineThreaded(CreateInstanceFactory factory, RenderEngineType type); ~RenderEngineThreaded() override; - std::future primeCache() override; + std::future primeCache(bool shouldPrimeUltraHDR) override; void dump(std::string& result) override; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1ea4bcd70a..9c2ce94855 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -869,7 +869,9 @@ void SurfaceFlinger::init() FTL_FAKE_GUARD(kMainThreadContext) { ALOGW("Can't set SCHED_OTHER for primeCache"); } - mRenderEnginePrimeCacheFuture = getRenderEngine().primeCache(); + bool shouldPrimeUltraHDR = + base::GetBoolProperty("ro.surface_flinger.prime_shader_cache.ultrahdr"s, false); + mRenderEnginePrimeCacheFuture = getRenderEngine().primeCache(shouldPrimeUltraHDR); if (setSchedFifo(true) != NO_ERROR) { ALOGW("Can't set SCHED_OTHER for primeCache"); -- GitLab From 3acaaf57fe3326635743e622910128e6eb88c168 Mon Sep 17 00:00:00 2001 From: ramindani Date: Mon, 25 Sep 2023 10:31:27 -0700 Subject: [PATCH 0824/1187] [SF] Adds support to call notifyExpectedPresentHint Adds the supporting code to make the call over HAL. BUG: 296636253 BUG: 284845445 Test: m Change-Id: I44e26affc7b179c125524351d01ea54431b51ace --- .../CompositionEngine/tests/MockHWComposer.h | 1 + .../DisplayHardware/AidlComposerHal.cpp | 14 ++++++++++++++ .../DisplayHardware/AidlComposerHal.h | 2 ++ .../surfaceflinger/DisplayHardware/ComposerHal.h | 2 ++ .../surfaceflinger/DisplayHardware/HWComposer.cpp | 13 +++++++++++++ .../surfaceflinger/DisplayHardware/HWComposer.h | 4 ++++ .../DisplayHardware/HidlComposerHal.cpp | 4 ++++ .../DisplayHardware/HidlComposerHal.h | 1 + .../unittests/mock/DisplayHardware/MockComposer.h | 1 + 9 files changed, 42 insertions(+) diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index 892bb8f726..facb80885f 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -147,6 +147,7 @@ public: MOCK_METHOD(const aidl::android::hardware::graphics::composer3::OverlayProperties&, getOverlaySupport, (), (const, override)); MOCK_METHOD(status_t, setRefreshRateChangedCallbackDebugEnabled, (PhysicalDisplayId, bool)); + MOCK_METHOD(status_t, notifyExpectedPresent, (PhysicalDisplayId, nsecs_t, int32_t)); }; } // namespace mock diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index 1f409c6ee7..1643ad0659 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -1450,6 +1450,20 @@ Error AidlComposer::setRefreshRateChangedCallbackDebugEnabled(Display displayId, return Error::NONE; } +Error AidlComposer::notifyExpectedPresent(Display displayId, nsecs_t expectedPresentTime, + int32_t frameIntervalNs) { + const auto status = + mAidlComposerClient->notifyExpectedPresent(translate(displayId), + ClockMonotonicTimestamp{expectedPresentTime}, + frameIntervalNs); + + if (!status.isOk()) { + ALOGE("notifyExpectedPresent failed %s", status.getDescription().c_str()); + return static_cast(status.getServiceSpecificError()); + } + return Error::NONE; +} + Error AidlComposer::getClientTargetProperty( Display display, ClientTargetPropertyWithBrightness* outClientTargetProperty) { Error error = Error::NONE; diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index b1b57a4528..7693a80a76 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -240,6 +240,8 @@ public: Error getHdrConversionCapabilities(std::vector*) override; Error setHdrConversionStrategy(HdrConversionStrategy, Hdr*) override; Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) override; + Error notifyExpectedPresent(Display, nsecs_t expectedPresentTime, + int32_t frameIntervalNs) override; private: // Many public functions above simply write a command into the command diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index e94258707b..6704d88696 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -298,6 +298,8 @@ public: virtual Error setHdrConversionStrategy( ::aidl::android::hardware::graphics::common::HdrConversionStrategy, Hdr*) = 0; virtual Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) = 0; + virtual Error notifyExpectedPresent(Display, nsecs_t expectedPresentTime, + int32_t frameIntervalNs) = 0; }; } // namespace Hwc2 diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 812621f40a..d6ef203765 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -876,6 +876,19 @@ status_t HWComposer::setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId return NO_ERROR; } +status_t HWComposer::notifyExpectedPresent(PhysicalDisplayId displayId, nsecs_t expectedPresentTime, + int32_t frameIntervalNs) { + ATRACE_CALL(); + RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); + const auto error = mComposer->notifyExpectedPresent(mDisplayData[displayId].hwcDisplay->getId(), + expectedPresentTime, frameIntervalNs); + if (error != hal::Error::NONE) { + ALOGE("Error in notifyExpectedPresent call %s", to_string(error).c_str()); + return INVALID_OPERATION; + } + return NO_ERROR; +} + status_t HWComposer::getDisplayDecorationSupport( PhysicalDisplayId displayId, std::optional* diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index b4d3d28a35..e9dc4dec73 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -300,6 +300,8 @@ public: aidl::android::hardware::graphics::common::HdrConversionStrategy, aidl::android::hardware::graphics::common::Hdr*) = 0; virtual status_t setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId, bool enabled) = 0; + virtual status_t notifyExpectedPresent(PhysicalDisplayId, nsecs_t expectedPresentTime, + int32_t frameIntervalNs) = 0; }; static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs, @@ -458,6 +460,8 @@ public: aidl::android::hardware::graphics::common::HdrConversionStrategy, aidl::android::hardware::graphics::common::Hdr*) override; status_t setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId, bool enabled) override; + status_t notifyExpectedPresent(PhysicalDisplayId, nsecs_t expectedPresentTime, + int32_t frameIntervalNs) override; // for debugging ---------------------------------------------------------- void dump(std::string& out) const override; diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index 70d48de75a..c13e568936 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -1378,6 +1378,10 @@ Error HidlComposer::setRefreshRateChangedCallbackDebugEnabled(Display, bool) { return Error::UNSUPPORTED; } +Error HidlComposer::notifyExpectedPresent(Display, nsecs_t, int32_t) { + return Error::UNSUPPORTED; +} + Error HidlComposer::getClientTargetProperty( Display display, ClientTargetPropertyWithBrightness* outClientTargetProperty) { IComposerClient::ClientTargetProperty property; diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index 26d22227ce..1004ddd011 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -348,6 +348,7 @@ public: Error setHdrConversionStrategy(aidl::android::hardware::graphics::common::HdrConversionStrategy, Hdr*) override; Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) override; + Error notifyExpectedPresent(Display, nsecs_t, int32_t) override; private: class CommandWriter : public CommandWriterBase { diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index 95004a485b..0b0774551a 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -178,6 +178,7 @@ public: MOCK_METHOD1(onHotplugConnect, void(Display)); MOCK_METHOD1(onHotplugDisconnect, void(Display)); MOCK_METHOD(Error, setRefreshRateChangedCallbackDebugEnabled, (Display, bool)); + MOCK_METHOD(Error, notifyExpectedPresent, (Display, nsecs_t, int32_t)); }; } // namespace Hwc2::mock -- GitLab From b90711b24ba44a47d743c4e5b4f94b5d20812fef Mon Sep 17 00:00:00 2001 From: ramindani Date: Mon, 2 Oct 2023 15:13:19 -0700 Subject: [PATCH 0825/1187] [SF] Adds notifyExpectedPresent call for timeoutNs Update notifyExpectedPresent to notifyExpectedPresentIfRequired BUG: 296636253 BUG: 284845445 Test: atest HWComposerTest && libsurfaceflinger_unittest Change-Id: Ibb2b70cd6073be7c0c2be0507b47e6f5732a9303 --- .../CompositionEngine/tests/MockHWComposer.h | 3 +- .../DisplayHardware/HWComposer.cpp | 21 ++++- .../DisplayHardware/HWComposer.h | 13 ++- .../tests/unittests/HWComposerTest.cpp | 80 +++++++++++++++++-- 4 files changed, 100 insertions(+), 17 deletions(-) diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index facb80885f..6807c8e5d7 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -147,7 +147,8 @@ public: MOCK_METHOD(const aidl::android::hardware::graphics::composer3::OverlayProperties&, getOverlaySupport, (), (const, override)); MOCK_METHOD(status_t, setRefreshRateChangedCallbackDebugEnabled, (PhysicalDisplayId, bool)); - MOCK_METHOD(status_t, notifyExpectedPresent, (PhysicalDisplayId, nsecs_t, int32_t)); + MOCK_METHOD(status_t, notifyExpectedPresentIfRequired, + (PhysicalDisplayId, nsecs_t, int32_t, int32_t)); }; } // namespace mock diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index d6ef203765..fb6089dfbe 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -484,6 +485,7 @@ status_t HWComposer::getDeviceCompositionChanges( }(); displayData.validateWasSkipped = false; + displayData.lastExpectedPresentTimestamp = expectedPresentTime; if (canSkipValidate) { sp outPresentFence; uint32_t state = UINT32_MAX; @@ -876,12 +878,23 @@ status_t HWComposer::setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId return NO_ERROR; } -status_t HWComposer::notifyExpectedPresent(PhysicalDisplayId displayId, nsecs_t expectedPresentTime, - int32_t frameIntervalNs) { - ATRACE_CALL(); +status_t HWComposer::notifyExpectedPresentIfRequired(PhysicalDisplayId displayId, + nsecs_t expectedPresentTime, + int32_t frameIntervalNs, int32_t timeoutNs) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); - const auto error = mComposer->notifyExpectedPresent(mDisplayData[displayId].hwcDisplay->getId(), + + auto& displayData = mDisplayData[displayId]; + if (expectedPresentTime >= displayData.lastExpectedPresentTimestamp && + expectedPresentTime < displayData.lastExpectedPresentTimestamp + timeoutNs) { + return NO_ERROR; + } + + displayData.lastExpectedPresentTimestamp = expectedPresentTime; + ATRACE_FORMAT("%s ExpectedPresentTime %" PRId64 " frameIntervalNs %d", __func__, + expectedPresentTime, frameIntervalNs); + const auto error = mComposer->notifyExpectedPresent(displayData.hwcDisplay->getId(), expectedPresentTime, frameIntervalNs); + if (error != hal::Error::NONE) { ALOGE("Error in notifyExpectedPresent call %s", to_string(error).c_str()); return INVALID_OPERATION; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index e9dc4dec73..726a8eafbf 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -60,6 +60,7 @@ namespace hal = hardware::graphics::composer::hal; struct DisplayedFrameStats; class GraphicBuffer; class TestableSurfaceFlinger; +struct HWComposerTest; struct CompositionInfo; namespace Hwc2 { @@ -300,8 +301,9 @@ public: aidl::android::hardware::graphics::common::HdrConversionStrategy, aidl::android::hardware::graphics::common::Hdr*) = 0; virtual status_t setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId, bool enabled) = 0; - virtual status_t notifyExpectedPresent(PhysicalDisplayId, nsecs_t expectedPresentTime, - int32_t frameIntervalNs) = 0; + virtual status_t notifyExpectedPresentIfRequired(PhysicalDisplayId, nsecs_t expectedPresentTime, + int32_t frameIntervalNs, + int32_t timeoutNs) = 0; }; static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs, @@ -460,8 +462,8 @@ public: aidl::android::hardware::graphics::common::HdrConversionStrategy, aidl::android::hardware::graphics::common::Hdr*) override; status_t setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId, bool enabled) override; - status_t notifyExpectedPresent(PhysicalDisplayId, nsecs_t expectedPresentTime, - int32_t frameIntervalNs) override; + status_t notifyExpectedPresentIfRequired(PhysicalDisplayId, nsecs_t expectedPresentTime, + int32_t frameIntervalNs, int32_t timeoutNs) override; // for debugging ---------------------------------------------------------- void dump(std::string& out) const override; @@ -487,6 +489,7 @@ public: private: // For unit tests friend TestableSurfaceFlinger; + friend HWComposerTest; struct DisplayData { std::unique_ptr hwcDisplay; @@ -494,6 +497,8 @@ private: sp lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires nsecs_t lastPresentTimestamp = 0; + nsecs_t lastExpectedPresentTimestamp = 0; + std::unordered_map> releaseFences; bool validateWasSkipped; diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index 8a45f17e2f..4f545a9ef3 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -32,6 +32,7 @@ #include #include +#include #include "DisplayHardware/DisplayMode.h" #include "DisplayHardware/HWComposer.h" @@ -44,11 +45,11 @@ #pragma clang diagnostic pop // ignored "-Wconversion" namespace android { -namespace { namespace V2_1 = hardware::graphics::composer::V2_1; namespace V2_4 = hardware::graphics::composer::V2_4; namespace aidl = aidl::android::hardware::graphics::composer3; +using namespace std::chrono_literals; using Hwc2::Config; @@ -77,6 +78,12 @@ struct HWComposerTest : testing::Test { EXPECT_CALL(*mHal, setVsyncEnabled(hwcDisplayId, Hwc2::IComposerClient::Vsync::DISABLE)); EXPECT_CALL(*mHal, onHotplugConnect(hwcDisplayId)); } + + void setDisplayData(HalDisplayId displayId, nsecs_t lastExpectedPresentTimestamp) { + ASSERT_TRUE(mHwc.mDisplayData.find(displayId) != mHwc.mDisplayData.end()); + auto& displayData = mHwc.mDisplayData.at(displayId); + displayData.lastExpectedPresentTimestamp = lastExpectedPresentTimestamp; + } }; TEST_F(HWComposerTest, isHeadless) { @@ -227,12 +234,19 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations) { constexpr int32_t kHeight = 720; constexpr int32_t kConfigGroup = 1; constexpr int32_t kVsyncPeriod = 16666667; - hal::DisplayConfiguration displayConfiguration; - displayConfiguration.configId = kConfigId; - displayConfiguration.configGroup = kConfigGroup; - displayConfiguration.height = kHeight; - displayConfiguration.width = kWidth; - displayConfiguration.vsyncPeriod = kVsyncPeriod; + const hal::VrrConfig vrrConfig = + hal::VrrConfig{.minFrameIntervalNs = static_cast(120_Hz).getPeriodNsecs(), + .notifyExpectedPresentConfig = hal::VrrConfig:: + NotifyExpectedPresentConfig{.notifyExpectedPresentHeadsUpNs = + ms2ns(30), + .notifyExpectedPresentTimeoutNs = + ms2ns(30)}}; + hal::DisplayConfiguration displayConfiguration{.configId = kConfigId, + .width = kWidth, + .height = kHeight, + .configGroup = kConfigGroup, + .vsyncPeriod = kVsyncPeriod, + .vrrConfig = vrrConfig}; EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _, _)) .WillOnce(DoAll(SetArgPointee<2>(std::vector{ @@ -247,6 +261,7 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations) { EXPECT_EQ(modes.front().height, kHeight); EXPECT_EQ(modes.front().configGroup, kConfigGroup); EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); + EXPECT_EQ(modes.front().vrrConfig, vrrConfig); EXPECT_EQ(modes.front().dpiX, -1); EXPECT_EQ(modes.front().dpiY, -1); @@ -266,6 +281,7 @@ TEST_F(HWComposerTest, getModesWithDisplayConfigurations) { EXPECT_EQ(modes.front().height, kHeight); EXPECT_EQ(modes.front().configGroup, kConfigGroup); EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod); + EXPECT_EQ(modes.front().vrrConfig, vrrConfig); EXPECT_EQ(modes.front().dpiX, kDpi); EXPECT_EQ(modes.front().dpiY, kDpi); } @@ -299,6 +315,55 @@ TEST_F(HWComposerTest, onVsyncInvalid) { EXPECT_FALSE(displayIdOpt); } +TEST_F(HWComposerTest, notifyExpectedPresentTimeout) { + constexpr hal::HWDisplayId kHwcDisplayId = 2; + expectHotplugConnect(kHwcDisplayId); + const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); + ASSERT_TRUE(info); + + auto expectedPresentTime = systemTime() + ms2ns(10); + const int32_t frameIntervalNs = static_cast(60_Hz).getPeriodNsecs(); + static constexpr nsecs_t kTimeoutNs = ms2ns(30); + + ASSERT_NO_FATAL_FAILURE(setDisplayData(info->id, /* lastExpectedPresentTimestamp= */ 0)); + + { + // Very first ExpectedPresent after idle, no previous timestamp + EXPECT_CALL(*mHal, + notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, frameIntervalNs)) + .WillOnce(Return(HalError::NONE)); + mHwc.notifyExpectedPresentIfRequired(info->id, expectedPresentTime, frameIntervalNs, + kTimeoutNs); + } + { + // ExpectedPresent is after the timeoutNs + expectedPresentTime += ms2ns(50); + EXPECT_CALL(*mHal, + notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, frameIntervalNs)) + .WillOnce(Return(HalError::NONE)); + mHwc.notifyExpectedPresentIfRequired(info->id, expectedPresentTime, frameIntervalNs, + kTimeoutNs); + } + { + // ExpectedPresent is after the last reported ExpectedPresent. + expectedPresentTime += ms2ns(10); + EXPECT_CALL(*mHal, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0); + mHwc.notifyExpectedPresentIfRequired(info->id, expectedPresentTime, frameIntervalNs, + kTimeoutNs); + } + { + // ExpectedPresent is before the last reported ExpectedPresent but after the timeoutNs, + // representing we changed our decision and want to present earlier than previously + // reported. + expectedPresentTime -= ms2ns(20); + EXPECT_CALL(*mHal, + notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, frameIntervalNs)) + .WillOnce(Return(HalError::NONE)); + mHwc.notifyExpectedPresentIfRequired(info->id, expectedPresentTime, frameIntervalNs, + kTimeoutNs); + } +} + struct MockHWC2ComposerCallback final : StrictMock { MOCK_METHOD2(onComposerHalHotplug, void(hal::HWDisplayId, hal::Connection)); MOCK_METHOD1(onComposerHalRefresh, void(hal::HWDisplayId)); @@ -423,5 +488,4 @@ TEST_F(HWComposerLayerGenericMetadataTest, forwardsSupportedMetadata) { EXPECT_EQ(hal::Error::UNSUPPORTED, result); } -} // namespace } // namespace android -- GitLab From 44b89d1fc7444832fb924f64b9502972231de6ec Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 16 Oct 2023 16:32:26 +0000 Subject: [PATCH 0826/1187] Remove all of ChildLayerTest from frameworks/native/TEST_MAPPING Flaking in presubmit Bug: 305711387 Change-Id: Iec532d7720d58d3791e742355521b3574ce4c38e --- TEST_MAPPING | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TEST_MAPPING b/TEST_MAPPING index cd8f3cdcc2..9c0116957d 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -7,7 +7,8 @@ "include-filter": "*" }, { - "exclude-filter": "*ChildLayerTest#ChildrenSurviveParentDestruction" + // TODO(b/305717998): Deflake and re-enable + "exclude-filter": "*ChildLayerTest*" } ] }, -- GitLab From 53f8b579869acdce0f8a721a21f00eb65d9ca6b5 Mon Sep 17 00:00:00 2001 From: Carlos Martinez Romero Date: Thu, 5 Oct 2023 19:36:14 +0000 Subject: [PATCH 0827/1187] libbufferstreams: Add the BufferPoolPublisher. The BufferPoolPublisher submits buffers from a pool over to a subscriber. Pair: jshargo Bug: 296450854, 296101127 Test: atest libbufferstreams-internal_test Change-Id: Ic473677c9c71b0505c3fcd2b4fb7d0fdf3d7d01b --- .../src/publishers/buffer_pool_publisher.rs | 112 ++++++++++++++++++ libs/bufferstreams/rust/src/publishers/mod.rs | 3 + 2 files changed, 115 insertions(+) create mode 100644 libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs diff --git a/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs b/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs new file mode 100644 index 0000000000..846105dacd --- /dev/null +++ b/libs/bufferstreams/rust/src/publishers/buffer_pool_publisher.rs @@ -0,0 +1,112 @@ +// Copyright (C) 2023 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. + +//! + +use std::time::Instant; + +use crate::{ + buffers::BufferPool, subscriptions::SharedBufferSubscription, BufferPublisher, + BufferSubscriber, Frame, StreamConfig, +}; + +/// The [BufferPoolPublisher] submits buffers from a pool over to the subscriber. +pub struct BufferPoolPublisher { + stream_config: StreamConfig, + buffer_pool: BufferPool, + subscription: SharedBufferSubscription, + subscriber: Option>, +} + +impl BufferPoolPublisher { + /// The [BufferPoolPublisher] needs to initialize a [BufferPool], the [BufferPool] will create + /// all buffers at initialization using the stream_config. + pub fn new(stream_config: StreamConfig, size: usize) -> Option { + BufferPool::new(size, stream_config).map(|buffer_pool| Self { + stream_config, + buffer_pool, + subscription: SharedBufferSubscription::new(), + subscriber: None, + }) + } + + /// If the [SharedBufferSubscription] is ready for a [Frame], a buffer will be requested from + /// [BufferPool] and sent over to the [BufferSubscriber]. + pub fn send_next_frame(&mut self, present_time: Instant) -> bool { + if let Some(subscriber) = self.subscriber.as_mut() { + if self.subscription.take_request() { + if let Some(buffer) = self.buffer_pool.next_buffer() { + let frame = Frame { buffer, present_time, fence: 0 }; + + subscriber.on_next(frame); + return true; + } + } + } + false + } +} + +impl BufferPublisher for BufferPoolPublisher { + fn get_publisher_stream_config(&self) -> StreamConfig { + self.stream_config + } + + fn subscribe(&mut self, subscriber: impl BufferSubscriber + 'static) { + assert!(self.subscriber.is_none()); + + self.subscriber = Some(Box::new(subscriber)); + self.subscriber.as_mut().unwrap().on_subscribe(self.subscription.clone_for_subscriber()); + } +} + +#[cfg(test)] +mod test { + use nativewindow::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; + + use super::*; + + use crate::{ + subscribers::{ + testing::{TestSubscriber, TestingSubscriberEvent}, + SharedSubscriber, + }, + StreamConfig, + }; + + const STREAM_CONFIG: StreamConfig = StreamConfig { + width: 1, + height: 1, + layers: 1, + format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + stride: 0, + }; + + #[test] + fn test_send_next_frame() { + let subscriber = SharedSubscriber::new(TestSubscriber::new(STREAM_CONFIG)); + + let mut buffer_pool_publisher = BufferPoolPublisher::new(STREAM_CONFIG, 1).unwrap(); + buffer_pool_publisher.subscribe(subscriber.clone()); + + subscriber.map_inner(|s| s.request(1)); + + assert!(buffer_pool_publisher.send_next_frame(Instant::now())); + + let events = subscriber.map_inner_mut(|s| s.take_events()); + assert!(matches!(events.last().unwrap(), TestingSubscriberEvent::Next(_))); + assert_eq!(buffer_pool_publisher.subscription.pending_requests(), 0); + } +} diff --git a/libs/bufferstreams/rust/src/publishers/mod.rs b/libs/bufferstreams/rust/src/publishers/mod.rs index 2fd518efee..8ed3ba0e00 100644 --- a/libs/bufferstreams/rust/src/publishers/mod.rs +++ b/libs/bufferstreams/rust/src/publishers/mod.rs @@ -14,4 +14,7 @@ //! This module provides [BufferSubscriber] implementations and helpers. +mod buffer_pool_publisher; pub mod testing; + +pub use buffer_pool_publisher::*; -- GitLab From f1bf56ba244e6d9da220904b63f464773d73cf59 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen Date: Fri, 13 Oct 2023 00:00:52 +0000 Subject: [PATCH 0828/1187] Revert "Add FEATURE_TELEPHONY_SATELLITE feature definition" Revert submission 20583557-Satellite APIs Reason for revert: Radio HAL for satellite APIs are not needed. Reverted changes: /q/submissionid:20583557-Satellite+APIs Bug: 304622222 Test: SMS, MMS, call with live network. SatelliteManagerTestOnMockService SatelliteManagerTest SatelliteControllerTest DatagramDispatcherTest DatagramReceiverTest SatelliteSOSMessageRecommenderTest NtnCapabilityResolverTest ServiceStateTrackerTest VtsHalRadioTargetTest Change-Id: I5bc729acf325b991148b6d3d5f9672dc235382e7 --- data/etc/Android.bp | 6 ------ .../android.hardware.telephony.satellite.xml | 20 ------------------- 2 files changed, 26 deletions(-) delete mode 100644 data/etc/android.hardware.telephony.satellite.xml diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 1418e1f7a6..e286a8405b 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -274,12 +274,6 @@ prebuilt_etc { defaults: ["frameworks_native_data_etc_defaults"], } -prebuilt_etc { - name: "android.hardware.telephony.satellite.prebuilt.xml", - src: "android.hardware.telephony.satellite.xml", - defaults: ["frameworks_native_data_etc_defaults"], -} - prebuilt_etc { name: "android.hardware.thread_network.prebuilt.xml", src: "android.hardware.thread_network.xml", diff --git a/data/etc/android.hardware.telephony.satellite.xml b/data/etc/android.hardware.telephony.satellite.xml deleted file mode 100644 index 5966cba277..0000000000 --- a/data/etc/android.hardware.telephony.satellite.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - -- GitLab From 89aab24732c006106e7fe200ed4c551ff3eaafd6 Mon Sep 17 00:00:00 2001 From: Carlos Martinez Romero Date: Tue, 3 Oct 2023 21:03:47 +0000 Subject: [PATCH 0829/1187] libbufferstreams: Add Buffer, BufferPool and BufferOwner. This change adds supoprt for a simple buffer pool. Buffer pools can be notified when a buffer is dropped, so the buffer can be provided by the pool again. We introduced the concept of a BufferOwner, which is generic and can be implemented by a client for their own custom buffer pools. Along the way we updated the Frame struct to use a Buffer instead of a AHardwareBuffer. Pair: jshargo Bug: 296450854, 296101127 Test: atest libbufferstreams-internal_test Change-Id: Ib7c1ba19f96d1deb3d329366aa9215ad89228f9e --- libs/bufferstreams/rust/src/buffers/buffer.rs | 80 ++++++++++ .../rust/src/buffers/buffer_owner.rs | 28 ++++ .../rust/src/buffers/buffer_pool.rs | 137 ++++++++++++++++++ libs/bufferstreams/rust/src/buffers/mod.rs | 23 +++ libs/bufferstreams/rust/src/lib.rs | 17 ++- 5 files changed, 279 insertions(+), 6 deletions(-) create mode 100644 libs/bufferstreams/rust/src/buffers/buffer.rs create mode 100644 libs/bufferstreams/rust/src/buffers/buffer_owner.rs create mode 100644 libs/bufferstreams/rust/src/buffers/buffer_pool.rs create mode 100644 libs/bufferstreams/rust/src/buffers/mod.rs diff --git a/libs/bufferstreams/rust/src/buffers/buffer.rs b/libs/bufferstreams/rust/src/buffers/buffer.rs new file mode 100644 index 0000000000..0a8516e8e3 --- /dev/null +++ b/libs/bufferstreams/rust/src/buffers/buffer.rs @@ -0,0 +1,80 @@ +// Copyright (C) 2023 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. + +//! Wrapper around the HardwareBuffer + +use nativewindow::*; + +use super::{buffer_owner::NoBufferOwner, BufferOwner}; + +/// A wrapper for a hardware buffer. +/// +/// This buffer may be associated with a buffer pool to which it will be returned to it when dropped. +pub struct Buffer { + buffer_owner: Box, + hardware_buffer: HardwareBuffer, +} + +impl Buffer { + /// Create new buffer with a custom [BufferOwner]. + pub fn new(buffer_owner: Box, hardware_buffer: HardwareBuffer) -> Self { + Self { buffer_owner, hardware_buffer } + } + + /// Create a new buffer with no association to any buffer pool. + pub fn new_unowned(hardware_buffer: HardwareBuffer) -> Self { + Self { buffer_owner: Box::new(NoBufferOwner), hardware_buffer } + } + + /// Get the id of the underlying buffer. + pub fn id(&self) -> u64 { + self.hardware_buffer.id() + } + + /// Get a reference to the underlying hardware buffer. + pub fn buffer(&self) -> &HardwareBuffer { + &self.hardware_buffer + } +} + +impl Drop for Buffer { + fn drop(&mut self) { + self.buffer_owner.on_return(self); + } +} + +#[cfg(test)] +mod test { + use super::*; + + use crate::StreamConfig; + + const STREAM_CONFIG: StreamConfig = StreamConfig { + width: 1, + height: 1, + layers: 1, + format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + stride: 0, + }; + + #[test] + fn test_get_buffer_id() { + let hardware_buffer = STREAM_CONFIG.create_hardware_buffer().unwrap(); + let buffer_id = hardware_buffer.id(); + + let buffer = Buffer::new_unowned(hardware_buffer); + assert_eq!(buffer_id, buffer.id()); + } +} diff --git a/libs/bufferstreams/rust/src/buffers/buffer_owner.rs b/libs/bufferstreams/rust/src/buffers/buffer_owner.rs new file mode 100644 index 0000000000..a4abb9d3b7 --- /dev/null +++ b/libs/bufferstreams/rust/src/buffers/buffer_owner.rs @@ -0,0 +1,28 @@ +// Copyright (C) 2023 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. + +use super::Buffer; + +/// Trait that represents an owner of a buffer that might need to handle events such as a buffer +/// being dropped. +pub trait BufferOwner { + /// Called when a buffer is dropped. + fn on_return(&self, buffer: &Buffer); +} + +pub(super) struct NoBufferOwner; + +impl BufferOwner for NoBufferOwner { + fn on_return(&self, _buffer: &Buffer) {} +} diff --git a/libs/bufferstreams/rust/src/buffers/buffer_pool.rs b/libs/bufferstreams/rust/src/buffers/buffer_pool.rs new file mode 100644 index 0000000000..05804e2e3a --- /dev/null +++ b/libs/bufferstreams/rust/src/buffers/buffer_pool.rs @@ -0,0 +1,137 @@ +// Copyright (C) 2023 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. + +//! A Buffer Pool containing and managing HardwareBuffers + +use std::{ + collections::HashMap, + sync::{Arc, Mutex, Weak}, +}; + +use nativewindow::*; + +use crate::StreamConfig; + +use super::{Buffer, BufferOwner}; + +pub(super) struct BufferPoolInner { + size: usize, + hardware_buffers: HashMap, + available_buffers: Vec, +} + +impl BufferPoolInner { + pub(super) fn return_buffer(&mut self, buffer_id: u64) { + assert!(self.hardware_buffers.contains_key(&buffer_id)); + assert!(!self.available_buffers.contains(&buffer_id)); + + self.available_buffers.push(buffer_id); + } +} + +struct BufferPoolOwner(Weak>); + +impl BufferOwner for BufferPoolOwner { + fn on_return(&self, buffer: &Buffer) { + if let Some(locked_buffer_pool) = self.0.upgrade() { + let mut buffer_pool = locked_buffer_pool.lock().unwrap(); + + buffer_pool.return_buffer(buffer.id()); + } + } +} + +/// A thread-safe collection of buffers. +/// +/// A buffer pool can be of arbitrary size. It creates and then holds references to all buffers +/// associated with it. +pub struct BufferPool(Arc>); + +impl BufferPool { + /// Creates a new buffer pool of size pool_size. All buffers will be created according to + /// the stream config. + /// + /// This constructor creates all buffers at initialization. + pub fn new(pool_size: usize, stream_config: StreamConfig) -> Option { + let mut hardware_buffers = HashMap::new(); + let mut available_buffers = Vec::new(); + for _ in 0..pool_size { + if let Some(buffer) = stream_config.create_hardware_buffer() { + available_buffers.push(buffer.id()); + hardware_buffers.insert(buffer.id(), buffer); + } else { + return None; + } + } + Some(Self(Arc::new(Mutex::new(BufferPoolInner { + size: pool_size, + hardware_buffers, + available_buffers, + })))) + } + + /// Try to acquire the next available buffer in the buffer pool. + /// + /// If all buffers are in use it will return None. + pub fn next_buffer(&mut self) -> Option { + let mut inner = self.0.lock().unwrap(); + if let Some(buffer_id) = inner.available_buffers.pop() { + Some(Buffer::new( + Box::new(BufferPoolOwner(Arc::downgrade(&self.0))), + inner.hardware_buffers[&buffer_id].clone(), + )) + } else { + None + } + } + + /// Gets the size of the buffer pool. + pub fn size(&self) -> usize { + let inner = self.0.lock().unwrap(); + inner.size + } +} + +#[cfg(test)] +mod test { + use super::*; + + const STREAM_CONFIG: StreamConfig = StreamConfig { + width: 1, + height: 1, + layers: 1, + format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM, + usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, + stride: 0, + }; + + #[test] + fn buffer_pool_next_buffer() { + let mut buffer_pool = BufferPool::new(1, STREAM_CONFIG).unwrap(); + let next_buffer = buffer_pool.next_buffer(); + + assert!(next_buffer.is_some()); + assert!(buffer_pool.next_buffer().is_none()); + } + + #[test] + fn drop_buffer_returns_to_pool() { + let mut buffer_pool = BufferPool::new(1, STREAM_CONFIG).unwrap(); + let next_buffer = buffer_pool.next_buffer(); + + assert!(next_buffer.is_some()); + drop(next_buffer); + assert!(buffer_pool.next_buffer().is_some()); + } +} diff --git a/libs/bufferstreams/rust/src/buffers/mod.rs b/libs/bufferstreams/rust/src/buffers/mod.rs new file mode 100644 index 0000000000..83360d6c00 --- /dev/null +++ b/libs/bufferstreams/rust/src/buffers/mod.rs @@ -0,0 +1,23 @@ +// Copyright (C) 2023 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. + +//! Module containing Buffers and BufferPools + +mod buffer; +mod buffer_owner; +mod buffer_pool; + +pub use buffer::*; +pub use buffer_owner::*; +pub use buffer_pool::*; diff --git a/libs/bufferstreams/rust/src/lib.rs b/libs/bufferstreams/rust/src/lib.rs index 5964281c9d..be1525d41f 100644 --- a/libs/bufferstreams/rust/src/lib.rs +++ b/libs/bufferstreams/rust/src/lib.rs @@ -14,14 +14,15 @@ //! libbufferstreams: Reactive Streams for Graphics Buffers +pub mod buffers; pub mod publishers; mod stream_config; pub mod subscribers; pub mod subscriptions; +use buffers::Buffer; pub use stream_config::*; -use nativewindow::*; use std::time::Instant; /// This function will print Hello World. @@ -158,8 +159,8 @@ pub type BufferError = anyhow::Error; /// Struct used to contain the buffer. pub struct Frame { - /// A handle to the C buffer interface. - pub buffer: HardwareBuffer, + /// A buffer to be used this frame. + pub buffer: Buffer, /// The time at which the buffer was dispatched. pub present_time: Instant, /// A fence used for reading/writing safely. @@ -172,6 +173,8 @@ mod test { use super::*; use anyhow::anyhow; + use buffers::Buffer; + use nativewindow::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags}; use std::borrow::BorrowMut; use std::error::Error; use std::ops::Add; @@ -192,9 +195,11 @@ mod test { fn make_frame() -> Frame { Frame { - buffer: STREAM_CONFIG - .create_hardware_buffer() - .expect("Unable to create hardware buffer for test"), + buffer: Buffer::new_unowned( + STREAM_CONFIG + .create_hardware_buffer() + .expect("Unable to create hardware buffer for test"), + ), present_time: Instant::now() + Duration::from_secs(1), fence: 0, } -- GitLab From cd90eaa28c2add8cc5bb4aa759512acaacfb32e4 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Wed, 31 May 2023 14:12:33 -0700 Subject: [PATCH 0830/1187] Add Default Constructor Required by libstdc++ Test: Build with CMake. See aosp/2629369. Bug: 285204695 Change-Id: I105552df72fe8b4f15f75192a5c36480c1bdc5c7 --- libs/binder/include/binder/Parcel.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 45e5ace73c..b94267c360 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -1289,6 +1289,7 @@ private: // Fields only needed when parcelling for "kernel Binder". struct KernelFields { + KernelFields() {} binder_size_t* mObjects = nullptr; size_t mObjectsSize = 0; size_t mObjectsCapacity = 0; -- GitLab From 0d9dec207e5c9b208ff841a4f73a91046c92ed25 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Fri, 6 Oct 2023 20:28:49 +0000 Subject: [PATCH 0831/1187] Binder: Split OS to Android and Unix part, abstract GetThreadId out Bug: 302723053 Test: mma in binder folder Test: aosp/2616196 Change-Id: I73df8fc453df0edf496960853cb0004f1c3a6a43 --- libs/binder/Android.bp | 4 ++- libs/binder/OS.h | 6 +++-- libs/binder/OS_android.cpp | 31 ++++++++++++++++++++++++ libs/binder/{OS.cpp => OS_unix_base.cpp} | 4 +-- libs/binder/Parcel.cpp | 10 ++++---- libs/binder/RpcServer.cpp | 8 +++--- libs/binder/RpcSession.cpp | 10 ++++---- libs/binder/RpcTransportRaw.cpp | 6 ++--- libs/binder/include/binder/RpcThreads.h | 10 -------- libs/binder/tests/binderRpcTest.cpp | 4 +-- libs/binder/trusty/OS.cpp | 4 +-- libs/binder/trusty/rules.mk | 1 + 12 files changed, 62 insertions(+), 36 deletions(-) create mode 100644 libs/binder/OS_android.cpp rename libs/binder/{OS.cpp => OS_unix_base.cpp} (98%) diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 6c2b313f8a..fd2b27f839 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -118,7 +118,8 @@ cc_defaults { ], srcs: [ - "OS.cpp", + "OS_android.cpp", + "OS_unix_base.cpp", "RpcTransportRaw.cpp", ], @@ -249,6 +250,7 @@ cc_library_shared { srcs: [ // Trusty-specific files + "OS_android.cpp", "trusty/logging.cpp", "trusty/OS.cpp", "trusty/RpcServerTrusty.cpp", diff --git a/libs/binder/OS.h b/libs/binder/OS.h index fecae31763..db4b7a5379 100644 --- a/libs/binder/OS.h +++ b/libs/binder/OS.h @@ -23,7 +23,7 @@ #include #include -namespace android { +namespace android::binder::os { android::base::Result setNonBlocking(android::base::borrowed_fd fd); @@ -41,4 +41,6 @@ ssize_t receiveMessageFromSocket( const RpcTransportFd& socket, iovec* iovs, int niovs, std::vector>* ancillaryFds); -} // namespace android +uint64_t GetThreadId(); + +} // namespace android::binder::os diff --git a/libs/binder/OS_android.cpp b/libs/binder/OS_android.cpp new file mode 100644 index 0000000000..1e1442b7c0 --- /dev/null +++ b/libs/binder/OS_android.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2023 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 "OS.h" + +#include + +namespace android::binder::os { + +uint64_t GetThreadId() { +#ifdef BINDER_RPC_SINGLE_THREADED + return 0; +#else + return base::GetThreadId(); +#endif +} + +} // namespace android::binder::os diff --git a/libs/binder/OS.cpp b/libs/binder/OS_unix_base.cpp similarity index 98% rename from libs/binder/OS.cpp rename to libs/binder/OS_unix_base.cpp index ce60e33ba7..81933d5c6b 100644 --- a/libs/binder/OS.cpp +++ b/libs/binder/OS_unix_base.cpp @@ -24,7 +24,7 @@ using android::base::ErrnoError; using android::base::Result; -namespace android { +namespace android::binder::os { // Linux kernel supports up to 253 (from SCM_MAX_FD) for unix sockets. constexpr size_t kMaxFdsPerMsg = 253; @@ -162,4 +162,4 @@ ssize_t receiveMessageFromSocket( return TEMP_FAILURE_RETRY(recvmsg(socket.fd.get(), &msg, MSG_NOSIGNAL)); } -} // namespace android +} // namespace android::binder::os diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index d92de1b151..16944a6221 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -621,7 +621,7 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { // To match kernel binder behavior, we always dup, even if the // FD was unowned in the source parcel. int newFd = -1; - if (status_t status = dupFileDescriptor(oldFd, &newFd); status != OK) { + if (status_t status = binder::os::dupFileDescriptor(oldFd, &newFd); status != OK) { ALOGW("Failed to duplicate file descriptor %d: %s", oldFd, strerror(-status)); } rpcFields->mFds->emplace_back(base::unique_fd(newFd)); @@ -1513,7 +1513,7 @@ status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership) { status_t Parcel::writeDupFileDescriptor(int fd) { int dupFd; - if (status_t err = dupFileDescriptor(fd, &dupFd); err != OK) { + if (status_t err = binder::os::dupFileDescriptor(fd, &dupFd); err != OK) { return err; } status_t err = writeFileDescriptor(dupFd, true /*takeOwnership*/); @@ -1532,7 +1532,7 @@ status_t Parcel::writeParcelFileDescriptor(int fd, bool takeOwnership) status_t Parcel::writeDupParcelFileDescriptor(int fd) { int dupFd; - if (status_t err = dupFileDescriptor(fd, &dupFd); err != OK) { + if (status_t err = binder::os::dupFileDescriptor(fd, &dupFd); err != OK) { return err; } status_t err = writeParcelFileDescriptor(dupFd, true /*takeOwnership*/); @@ -2345,7 +2345,7 @@ status_t Parcel::readUniqueFileDescriptor(base::unique_fd* val) const } int dupFd; - if (status_t err = dupFileDescriptor(got, &dupFd); err != OK) { + if (status_t err = binder::os::dupFileDescriptor(got, &dupFd); err != OK) { return BAD_VALUE; } @@ -2367,7 +2367,7 @@ status_t Parcel::readUniqueParcelFileDescriptor(base::unique_fd* val) const } int dupFd; - if (status_t err = dupFileDescriptor(got, &dupFd); err != OK) { + if (status_t err = binder::os::dupFileDescriptor(got, &dupFd); err != OK) { return BAD_VALUE; } diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index 55fc16de45..354a4b3294 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -57,7 +57,7 @@ RpcServer::~RpcServer() { sp RpcServer::make(std::unique_ptr rpcTransportCtxFactory) { // Default is without TLS. if (rpcTransportCtxFactory == nullptr) - rpcTransportCtxFactory = makeDefaultRpcTransportCtxFactory(); + rpcTransportCtxFactory = binder::os::makeDefaultRpcTransportCtxFactory(); auto ctx = rpcTransportCtxFactory->newServerCtx(); if (ctx == nullptr) return nullptr; return sp::make(std::move(ctx)); @@ -216,7 +216,7 @@ status_t RpcServer::recvmsgSocketConnection(const RpcServer& server, RpcTranspor iovec iov{&zero, sizeof(zero)}; std::vector> fds; - ssize_t num_bytes = receiveMessageFromSocket(server.mServer, &iov, 1, &fds); + ssize_t num_bytes = binder::os::receiveMessageFromSocket(server.mServer, &iov, 1, &fds); if (num_bytes < 0) { int savedErrno = errno; ALOGE("Failed recvmsg: %s", strerror(savedErrno)); @@ -231,7 +231,7 @@ status_t RpcServer::recvmsgSocketConnection(const RpcServer& server, RpcTranspor } unique_fd fd(std::move(std::get(fds.back()))); - if (auto res = setNonBlocking(fd); !res.ok()) { + if (auto res = binder::os::setNonBlocking(fd); !res.ok()) { ALOGE("Failed setNonBlocking: %s", res.error().message().c_str()); return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code(); } @@ -488,7 +488,7 @@ void RpcServer::establishConnection( return; } - auto status = getRandomBytes(sessionId.data(), sessionId.size()); + auto status = binder::os::getRandomBytes(sessionId.data(), sessionId.size()); if (status != OK) { ALOGE("Failed to read random session ID: %s", strerror(-status)); return; diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index c3dee1650e..679b194426 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -70,7 +70,7 @@ RpcSession::~RpcSession() { sp RpcSession::make() { // Default is without TLS. - return make(makeDefaultRpcTransportCtxFactory()); + return make(binder::os::makeDefaultRpcTransportCtxFactory()); } sp RpcSession::make(std::unique_ptr rpcTransportCtxFactory) { @@ -195,7 +195,7 @@ status_t RpcSession::setupPreconnectedClient(base::unique_fd fd, fd = request(); if (!fd.ok()) return BAD_VALUE; } - if (auto res = setNonBlocking(fd); !res.ok()) { + if (auto res = binder::os::setNonBlocking(fd); !res.ok()) { ALOGE("setupPreconnectedClient: %s", res.error().message().c_str()); return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code(); } @@ -770,7 +770,7 @@ status_t RpcSession::addOutgoingConnection(std::unique_ptr rpcTran { RpcMutexLockGuard _l(mMutex); connection->rpcTransport = std::move(rpcTransport); - connection->exclusiveTid = rpcGetThreadId(); + connection->exclusiveTid = binder::os::GetThreadId(); mConnections.mOutgoing.push_back(connection); } @@ -825,7 +825,7 @@ sp RpcSession::assignIncomingConnectionToThisThread( sp session = sp::make(); session->rpcTransport = std::move(rpcTransport); - session->exclusiveTid = rpcGetThreadId(); + session->exclusiveTid = binder::os::GetThreadId(); mConnections.mIncoming.push_back(session); mConnections.mMaxIncoming = mConnections.mIncoming.size(); @@ -870,7 +870,7 @@ status_t RpcSession::ExclusiveConnection::find(const sp& session, Co connection->mConnection = nullptr; connection->mReentrant = false; - uint64_t tid = rpcGetThreadId(); + uint64_t tid = binder::os::GetThreadId(); RpcMutexUniqueLock _l(session->mMutex); session->mConnections.mWaitingThreads++; diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp index ddbcb573b1..c089811561 100644 --- a/libs/binder/RpcTransportRaw.cpp +++ b/libs/binder/RpcTransportRaw.cpp @@ -59,8 +59,8 @@ public: override { bool sentFds = false; auto send = [&](iovec* iovs, int niovs) -> ssize_t { - ssize_t ret = - sendMessageOnSocket(mSocket, iovs, niovs, sentFds ? nullptr : ancillaryFds); + ssize_t ret = binder::os::sendMessageOnSocket(mSocket, iovs, niovs, + sentFds ? nullptr : ancillaryFds); sentFds |= ret > 0; return ret; }; @@ -73,7 +73,7 @@ public: const std::optional>& altPoll, std::vector>* ancillaryFds) override { auto recv = [&](iovec* iovs, int niovs) -> ssize_t { - return receiveMessageFromSocket(mSocket, iovs, niovs, ancillaryFds); + return binder::os::receiveMessageFromSocket(mSocket, iovs, niovs, ancillaryFds); }; return interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, recv, "recvmsg", POLLIN, altPoll); diff --git a/libs/binder/include/binder/RpcThreads.h b/libs/binder/include/binder/RpcThreads.h index b80d116e1c..d25f29277c 100644 --- a/libs/binder/include/binder/RpcThreads.h +++ b/libs/binder/include/binder/RpcThreads.h @@ -17,8 +17,6 @@ #include -#include - #include #include #include @@ -121,10 +119,6 @@ static inline RpcMaybeThread::id get_id() { } } // namespace rpc_this_thread -static inline uint64_t rpcGetThreadId() { - return 0; -} - static inline void rpcJoinIfSingleThreaded(RpcMaybeThread& t) { t.join(); } @@ -136,10 +130,6 @@ using RpcConditionVariable = std::condition_variable; using RpcMaybeThread = std::thread; namespace rpc_this_thread = std::this_thread; -static inline uint64_t rpcGetThreadId() { - return base::GetThreadId(); -} - static inline void rpcJoinIfSingleThreaded(RpcMaybeThread&) {} #endif // BINDER_RPC_SINGLE_THREADED diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 4c3c68e2e7..5884dbe66f 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -227,7 +227,7 @@ static base::unique_fd connectToUnixBootstrap(const RpcTransportFd& transportFd) std::vector> fds; fds.emplace_back(std::move(sockServer)); - if (sendMessageOnSocket(transportFd, &iov, 1, &fds) < 0) { + if (binder::os::sendMessageOnSocket(transportFd, &iov, 1, &fds) < 0) { int savedErrno = errno; LOG(FATAL) << "Failed sendMessageOnSocket: " << strerror(savedErrno); } @@ -1589,7 +1589,7 @@ public: int buf; iovec iov{&buf, sizeof(buf)}; - if (receiveMessageFromSocket(mFd, &iov, 1, &fds) < 0) { + if (binder::os::receiveMessageFromSocket(mFd, &iov, 1, &fds) < 0) { int savedErrno = errno; LOG(FATAL) << "Failed receiveMessage: " << strerror(savedErrno); } diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp index 8ec982345d..43e06e013d 100644 --- a/libs/binder/trusty/OS.cpp +++ b/libs/binder/trusty/OS.cpp @@ -28,7 +28,7 @@ using android::base::Result; -namespace android { +namespace android::binder::os { Result setNonBlocking(android::base::borrowed_fd /*fd*/) { // Trusty IPC syscalls are all non-blocking by default. @@ -73,4 +73,4 @@ ssize_t receiveMessageFromSocket( return -1; } -} // namespace android +} // namespace android::binder::os diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk index 42db29a2ef..c916670515 100644 --- a/libs/binder/trusty/rules.mk +++ b/libs/binder/trusty/rules.mk @@ -35,6 +35,7 @@ MODULE_SRCS := \ $(LIBBINDER_DIR)/FdTrigger.cpp \ $(LIBBINDER_DIR)/IInterface.cpp \ $(LIBBINDER_DIR)/IResultReceiver.cpp \ + $(LIBBINDER_DIR)/OS_android.cpp \ $(LIBBINDER_DIR)/Parcel.cpp \ $(LIBBINDER_DIR)/ParcelFileDescriptor.cpp \ $(LIBBINDER_DIR)/RpcServer.cpp \ -- GitLab From 17190c9e0cdc78f35b148d3fa0cbc0139e208190 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 21 Jun 2023 07:03:47 +0000 Subject: [PATCH 0832/1187] Allow per-app opt in to use system ANGLE. Previously the per-app opt in only works for ANGLE apk, this patch refactors the logic to allow per-app opt in to work for system ANGLE. This patch checks whether system ANGLE is supported and if it presents, uses it if the ANGLE apk setup fails. With this patch, the per-app opt in will function this way: 1) When full ANGLE apk is installed Regardless of whether system ANGLE is present, the "angle" option will use ANGLE apk, the "native" option will switch to native GLES drivers specified by ro.hardware.egl, the "default" option will use whatever the default graphics driver is loaded. 2) When full ANGLE apk is not installed and system ANGLE is present The "angle" option will use system ANGLE, the "native" option will switch to native GLES drivers specified by ro.hardware.egl, the "default" option will use whatever the default graphics driver is loaded. 3) When full ANGLE apk is not installed and system ANGLE doesn't exist The per-app option will not function at all. To Properly load ANGLE, the namespace of system ANGLE should be inherited from sphal namespace so that search paths and libraries linkage are properly constructed. Minor: clean up unused and unnecessary variables. Bug: b/283858001 Test: test with camera Test: atest CtsAngleIntegrationHostTestCases Change-Id: I2c9d4e1747796d2b0ae58c4456b781b9940fbb26 Merged-In: I2c9d4e1747796d2b0ae58c4456b781b9940fbb26 --- libs/graphicsenv/GraphicsEnv.cpp | 105 ++++++++++-------- .../include/graphicsenv/GraphicsEnv.h | 25 +++-- 2 files changed, 73 insertions(+), 57 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 1a638c1e5b..2c274be08e 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -417,45 +417,28 @@ bool GraphicsEnv::shouldUseAngle() { return false; } - return (mShouldUseAngle == YES) ? true : false; + return mShouldUseAngle; } -void GraphicsEnv::updateShouldUseAngle() { - const char* ANGLE_PREFER_ANGLE = "angle"; - const char* ANGLE_PREFER_NATIVE = "native"; - - mShouldUseAngle = NO; - if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) { - ALOGV("User set \"Developer Options\" to force the use of ANGLE"); - mShouldUseAngle = YES; - } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) { - ALOGV("User set \"Developer Options\" to force the use of Native"); - } else { - ALOGV("User set invalid \"Developer Options\": '%s'", mAngleDeveloperOptIn.c_str()); - } -} - -void GraphicsEnv::setAngleInfo(const std::string& path, const std::string& packageName, - const std::string& developerOptIn, +void GraphicsEnv::setAngleInfo(const std::string& path, const bool useSystemAngle, + const std::string& packageName, const std::vector eglFeatures) { - if (mShouldUseAngle != UNKNOWN) { - // We've already figured out an answer for this app, so just return. - ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", packageName.c_str(), - (mShouldUseAngle == YES) ? "true" : "false"); + if (mShouldUseAngle) { + // ANGLE is already set up for this application process, even if the application + // needs to switch from apk to system or vice versa, the application process must + // be killed and relaunch so that the loader can properly load ANGLE again. + // The architecture does not support runtime switch between drivers, so just return. + ALOGE("ANGLE is already set for %s", packageName.c_str()); return; } mAngleEglFeatures = std::move(eglFeatures); - ALOGV("setting ANGLE path to '%s'", path.c_str()); - mAnglePath = path; + mAnglePath = std::move(path); ALOGV("setting app package name to '%s'", packageName.c_str()); - mPackageName = packageName; - ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str()); - mAngleDeveloperOptIn = developerOptIn; - - // Update the current status of whether we should use ANGLE or not - updateShouldUseAngle(); + mPackageName = std::move(packageName); + mShouldUseAngle = true; + mUseSystemAngle = useSystemAngle; } void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, @@ -502,13 +485,15 @@ void GraphicsEnv::setDebugLayersGLES(const std::string& layers) { } // Return true if all the required libraries from vndk and sphal namespace are -// linked to the updatable gfx driver namespace correctly. -bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) { +// linked to the driver namespace correctly. +bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* destNamespace, + android_namespace_t* vndkNamespace, + const std::string& sharedSphalLibraries) { const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK); if (llndkLibraries.empty()) { return false; } - if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) { + if (!android_link_namespaces(destNamespace, nullptr, llndkLibraries.c_str())) { ALOGE("Failed to link default namespace[%s]", dlerror()); return false; } @@ -517,12 +502,12 @@ bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) if (vndkspLibraries.empty()) { return false; } - if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) { + if (!android_link_namespaces(destNamespace, vndkNamespace, vndkspLibraries.c_str())) { ALOGE("Failed to link vndk namespace[%s]", dlerror()); return false; } - if (mSphalLibraries.empty()) { + if (sharedSphalLibraries.empty()) { return true; } @@ -530,11 +515,11 @@ bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) auto sphalNamespace = android_get_exported_namespace("sphal"); if (!sphalNamespace) { ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace", - mSphalLibraries.c_str()); + sharedSphalLibraries.c_str()); return false; } - if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) { + if (!android_link_namespaces(destNamespace, sphalNamespace, sharedSphalLibraries.c_str())) { ALOGE("Failed to link sphal namespace[%s]", dlerror()); return false; } @@ -586,7 +571,7 @@ android_namespace_t* GraphicsEnv::getDriverNamespace() { nullptr, // permitted_when_isolated_path nullptr); - if (!linkDriverNamespaceLocked(vndkNamespace)) { + if (!linkDriverNamespaceLocked(mDriverNamespace, vndkNamespace, mSphalLibraries)) { mDriverNamespace = nullptr; } @@ -604,20 +589,48 @@ android_namespace_t* GraphicsEnv::getAngleNamespace() { return mAngleNamespace; } - if (mAnglePath.empty()) { - ALOGV("mAnglePath is empty, not creating ANGLE namespace"); + if (mAnglePath.empty() && !mUseSystemAngle) { + ALOGV("mAnglePath is empty and not using system ANGLE, abort creating ANGLE namespace"); return nullptr; } - mAngleNamespace = android_create_namespace("ANGLE", - nullptr, // ld_library_path - mAnglePath.c_str(), // default_library_path - ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED, - nullptr, // permitted_when_isolated_path - nullptr); + // Construct the search paths for system ANGLE. + const char* const defaultLibraryPaths = +#if defined(__LP64__) + "/vendor/lib64/egl:/system/lib64/egl"; +#else + "/vendor/lib/egl:/system/lib/egl"; +#endif + + // If the application process will run on top of system ANGLE, construct the namespace + // with sphal namespace being the parent namespace so that search paths and libraries + // are properly inherited. + mAngleNamespace = + android_create_namespace("ANGLE", + mUseSystemAngle ? defaultLibraryPaths + : mAnglePath.c_str(), // ld_library_path + mUseSystemAngle ? defaultLibraryPaths + : mAnglePath.c_str(), // default_library_path + ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED, + nullptr, // permitted_when_isolated_path + mUseSystemAngle ? android_get_exported_namespace("sphal") + : nullptr); // parent ALOGD_IF(!mAngleNamespace, "Could not create ANGLE namespace from default"); + if (!mUseSystemAngle) { + return mAngleNamespace; + } + + auto vndkNamespace = android_get_exported_namespace("vndk"); + if (!vndkNamespace) { + return nullptr; + } + + if (!linkDriverNamespaceLocked(mAngleNamespace, vndkNamespace, "")) { + mAngleNamespace = nullptr; + } + return mAngleNamespace; } diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index a1b5e50c93..e78d038ea5 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -29,6 +29,11 @@ namespace android { struct NativeLoaderNamespace; +// The GraphicsEnv is a singleton per application process and is used to properly set up the +// graphics drivers for the application process during application starts. The architecture of +// the graphics driver loader does not support runtime switch and only supports switch to different +// graphics drivers when application process launches and hence the only way to switch to different +// graphics drivers is to completely kill the application process and relaunch the application. class GraphicsEnv { public: static GraphicsEnv& getInstance(); @@ -103,8 +108,8 @@ public: // (libraries must be stored uncompressed and page aligned); such elements // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a - void setAngleInfo(const std::string& path, const std::string& packageName, - const std::string& devOptIn, const std::vector eglFeatures); + void setAngleInfo(const std::string& path, const bool useSystemAngle, + const std::string& packageName, const std::vector eglFeatures); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); // Get the app package name. @@ -132,12 +137,10 @@ public: const std::string& getDebugLayersGLES(); private: - enum UseAngle { UNKNOWN, YES, NO }; - - // Update whether ANGLE should be used. - void updateShouldUseAngle(); // Link updatable driver namespace with llndk and vndk-sp libs. - bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace); + bool linkDriverNamespaceLocked(android_namespace_t* destNamespace, + android_namespace_t* vndkNamespace, + const std::string& sharedSphalLibraries); // Check whether this process is ready to send stats. bool readyToSendGpuStatsLocked(); // Send the initial complete GpuStats to GpuService. @@ -165,12 +168,12 @@ private: std::string mAnglePath; // App's package name. std::string mPackageName; - // ANGLE developer opt in status. - std::string mAngleDeveloperOptIn; // ANGLE EGL features; std::vector mAngleEglFeatures; - // Use ANGLE flag. - UseAngle mShouldUseAngle = UNKNOWN; + // Whether ANGLE should be used. + bool mShouldUseAngle = false; + // Whether loader should load system ANGLE. + bool mUseSystemAngle = false; // ANGLE namespace. android_namespace_t* mAngleNamespace = nullptr; -- GitLab From 93e26b9575944951f3e231a2e64d1a590b25ba58 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 16 Oct 2023 21:36:51 -0700 Subject: [PATCH 0833/1187] Set visible region dirty flag when alpha changes Removes an optimzation which only set the visible region dirty flag when alpha changed from 1->0 or 0->1. This optimization broke an assumption in CE. Alpha is only passed to HWC when there are geometry changes which are tracked by the visible region dirty flag. Fixes: 299256533 Test: presubmit Test: dim layer alpha animates when showing a dialog Change-Id: I4c56171d19d582e26b9c2c7be6c555a6c1d7494c --- libs/gui/include/gui/LayerState.h | 4 +-- .../FrontEnd/RequestedLayerState.cpp | 3 +- .../unittests/LayerLifecycleManagerTest.cpp | 35 +++++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 4371007778..2c123b3ad3 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -277,8 +277,8 @@ struct layer_state_t { layer_state_t::eLayerStackChanged; // Changes that affect the visible region on a display. - static constexpr uint64_t VISIBLE_REGION_CHANGES = - layer_state_t::GEOMETRY_CHANGES | layer_state_t::HIERARCHY_CHANGES; + static constexpr uint64_t VISIBLE_REGION_CHANGES = layer_state_t::GEOMETRY_CHANGES | + layer_state_t::HIERARCHY_CHANGES | layer_state_t::eAlphaChanged; bool hasValidBuffer() const; void sanitize(int32_t permissions); diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index 168267bb50..f137ec4f4f 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -237,8 +237,7 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta } if (what & (layer_state_t::eAlphaChanged)) { if (oldAlpha == 0 || color.a == 0) { - changes |= RequestedLayerState::Changes::Visibility | - RequestedLayerState::Changes::VisibleRegion; + changes |= RequestedLayerState::Changes::Visibility; } } diff --git a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp index 1fde9b8efa..aecfcba6e6 100644 --- a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp @@ -525,4 +525,39 @@ TEST_F(LayerLifecycleManagerTest, roundedCornerChangesSetsVisibilityChangeFlag) mLifecycleManager.commitChanges(); } +// Even when it does not change visible region, we should mark alpha changes as affecting +// visible region because HWC impl depends on it. writeOutputIndependentGeometryStateToHWC +// is only called if we are updating geometry. +TEST_F(LayerLifecycleManagerTest, alphaChangesAlwaysSetsVisibleRegionFlag) { + mLifecycleManager.commitChanges(); + float startingAlpha = 0.5f; + setAlpha(1, startingAlpha); + + // this is expected because layer alpha changes from 1 to 0.5, it may no longer be opaque + EXPECT_EQ(mLifecycleManager.getGlobalChanges().string(), + ftl::Flags( + RequestedLayerState::Changes::Content | + RequestedLayerState::Changes::AffectsChildren | + RequestedLayerState::Changes::VisibleRegion) + .string()); + EXPECT_EQ(mLifecycleManager.getChangedLayers()[0]->color.a, static_cast(startingAlpha)); + mLifecycleManager.commitChanges(); + + float endingAlpha = 0.2f; + setAlpha(1, endingAlpha); + + // this is not expected but we should make sure this behavior does not change + EXPECT_EQ(mLifecycleManager.getGlobalChanges().string(), + ftl::Flags( + RequestedLayerState::Changes::Content | + RequestedLayerState::Changes::AffectsChildren | + RequestedLayerState::Changes::VisibleRegion) + .string()); + EXPECT_EQ(mLifecycleManager.getChangedLayers()[0]->color.a, static_cast(endingAlpha)); + mLifecycleManager.commitChanges(); + + EXPECT_EQ(mLifecycleManager.getGlobalChanges().string(), + ftl::Flags().string()); +} + } // namespace android::surfaceflinger::frontend -- GitLab From 841b07c666cd03f478e206a934e8393a2db8f703 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Thu, 5 Oct 2023 14:52:00 -0700 Subject: [PATCH 0834/1187] input: handle change in std::span::size type The pre-standardized version of std::span in external/libcxx had a ptrdiff_t size, but the finalized std::span has a size_t size instead. Also, the std::span::index_type typedef is renamed to size_type. Use an old-style constructor call to implicitly coerce the size value to the proper type. Insert a cast to avoid a signedness comparison warning. Bug: b/175635923 Test: treehugger Change-Id: I96ccf6d5b54d4118b096f97c901073b4fc2f6f9f Merged-In: I96ccf6d5b54d4118b096f97c901073b4fc2f6f9f --- libs/input/MotionPredictor.cpp | 5 +++-- libs/input/TfLiteMotionPredictor.cpp | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/input/MotionPredictor.cpp b/libs/input/MotionPredictor.cpp index 3037573538..abcca345d3 100644 --- a/libs/input/MotionPredictor.cpp +++ b/libs/input/MotionPredictor.cpp @@ -176,12 +176,13 @@ std::unique_ptr MotionPredictor::predict(nsecs_t timestamp) { int64_t predictionTime = mBuffers->lastTimestamp(); const int64_t futureTime = timestamp + mPredictionTimestampOffsetNanos; - for (int i = 0; i < predictedR.size() && predictionTime <= futureTime; ++i) { + for (size_t i = 0; i < static_cast(predictedR.size()) && predictionTime <= futureTime; + ++i) { const TfLiteMotionPredictorSample::Point point = convertPrediction(axisFrom, axisTo, predictedR[i], predictedPhi[i]); // TODO(b/266747654): Stop predictions if confidence is < some threshold. - ALOGD_IF(isDebug(), "prediction %d: %f, %f", i, point.x, point.y); + ALOGD_IF(isDebug(), "prediction %zu: %f, %f", i, point.x, point.y); PointerCoords coords; coords.clear(); coords.setAxisValue(AMOTION_EVENT_AXIS_X, point.x); diff --git a/libs/input/TfLiteMotionPredictor.cpp b/libs/input/TfLiteMotionPredictor.cpp index 85fa176129..8d10ff56b0 100644 --- a/libs/input/TfLiteMotionPredictor.cpp +++ b/libs/input/TfLiteMotionPredictor.cpp @@ -115,8 +115,7 @@ std::span getTensorBuffer(typename std::conditional::value, tensor->name, TfLiteTypeGetName(tensor->type), TfLiteTypeGetName(type)); LOG_ALWAYS_FATAL_IF(!tensor->data.data); - return {reinterpret_cast(tensor->data.data), - static_cast::index_type>(tensor->bytes / sizeof(T))}; + return std::span(reinterpret_cast(tensor->data.data), tensor->bytes / sizeof(T)); } // Verifies that a tensor exists and has an underlying buffer of type T. -- GitLab From ac7bcd98bd331eca678ffc21188dd78c63aabbdd Mon Sep 17 00:00:00 2001 From: Pascal Muetschard Date: Tue, 3 Oct 2023 15:05:36 +0200 Subject: [PATCH 0835/1187] Include the frame's expected duration in the jank data. Bug: b/261839034 Test: atest libsurfaceflinger_unittest Change-Id: I65c85be8825e36671612a47000261c04f0289551 --- libs/gui/ITransactionCompletedListener.cpp | 2 + .../gui/ITransactionCompletedListener.h | 7 +- .../FrameTimeline/FrameTimeline.cpp | 20 +- .../FrameTimeline/FrameTimeline.h | 18 +- services/surfaceflinger/Layer.cpp | 5 +- services/surfaceflinger/SurfaceFlinger.cpp | 3 +- .../tests/unittests/FrameTimelineTest.cpp | 186 +++++++++++------- .../unittests/TransactionSurfaceFrameTest.cpp | 6 +- .../tests/unittests/mock/MockFrameTimeline.h | 2 +- 9 files changed, 158 insertions(+), 91 deletions(-) diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index ffe79a3a03..29d64afb24 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -111,12 +111,14 @@ JankData::JankData() status_t JankData::writeToParcel(Parcel* output) const { SAFE_PARCEL(output->writeInt64, frameVsyncId); SAFE_PARCEL(output->writeInt32, jankType); + SAFE_PARCEL(output->writeInt64, frameIntervalNs); return NO_ERROR; } status_t JankData::readFromParcel(const Parcel* input) { SAFE_PARCEL(input->readInt64, &frameVsyncId); SAFE_PARCEL(input->readInt32, &jankType); + SAFE_PARCEL(input->readInt64, &frameIntervalNs); return NO_ERROR; } diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index 39bcb4a56c..364a57b8dd 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -120,14 +120,17 @@ public: status_t readFromParcel(const Parcel* input) override; JankData(); - JankData(int64_t frameVsyncId, int32_t jankType) - : frameVsyncId(frameVsyncId), jankType(jankType) {} + JankData(int64_t frameVsyncId, int32_t jankType, nsecs_t frameIntervalNs) + : frameVsyncId(frameVsyncId), jankType(jankType), frameIntervalNs(frameIntervalNs) {} // Identifier for the frame submitted with Transaction.setFrameTimelineVsyncId int64_t frameVsyncId; // Bitmask of janks that occurred int32_t jankType; + + // Expected duration of the frame + nsecs_t frameIntervalNs; }; class SurfaceStats : public Parcelable { diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index dcc29b9913..1b1307b13a 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -366,6 +366,11 @@ void SurfaceFrame::setRenderRate(Fps renderRate) { mRenderRate = renderRate; } +Fps SurfaceFrame::getRenderRate() const { + std::lock_guard lock(mMutex); + return mRenderRate ? *mRenderRate : mDisplayFrameRenderRate; +} + void SurfaceFrame::setGpuComposition() { std::scoped_lock lock(mMutex); mGpuComposition = true; @@ -611,9 +616,11 @@ void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& r } void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate, - nsecs_t displayDeadlineDelta, nsecs_t displayPresentDelta) { + Fps displayFrameRenderRate, nsecs_t displayDeadlineDelta, + nsecs_t displayPresentDelta) { std::scoped_lock lock(mMutex); + mDisplayFrameRenderRate = displayFrameRenderRate; mActuals.presentTime = presentTime; nsecs_t deadlineDelta = 0; @@ -837,10 +844,11 @@ void FrameTimeline::addSurfaceFrame(std::shared_ptr surfaceFrame) mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame); } -void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, Fps refreshRate) { +void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, Fps refreshRate, + Fps renderRate) { ATRACE_CALL(); std::scoped_lock lock(mMutex); - mCurrentDisplayFrame->onSfWakeUp(token, refreshRate, + mCurrentDisplayFrame->onSfWakeUp(token, refreshRate, renderRate, mTokenManager.getPredictionsForToken(token), wakeUpTime); } @@ -860,11 +868,12 @@ void FrameTimeline::DisplayFrame::addSurfaceFrame(std::shared_ptr mSurfaceFrames.push_back(surfaceFrame); } -void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, Fps refreshRate, +void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, Fps refreshRate, Fps renderRate, std::optional predictions, nsecs_t wakeUpTime) { mToken = token; mRefreshRate = refreshRate; + mRenderRate = renderRate; if (!predictions) { mPredictionState = PredictionState::Expired; } else { @@ -1026,7 +1035,8 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime, nsecs_t previous classifyJank(deadlineDelta, deltaToVsync, previousPresentTime); for (auto& surfaceFrame : mSurfaceFrames) { - surfaceFrame->onPresent(signalTime, mJankType, mRefreshRate, deadlineDelta, deltaToVsync); + surfaceFrame->onPresent(signalTime, mJankType, mRefreshRate, mRenderRate, deadlineDelta, + deltaToVsync); } } diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index d54d22d53b..538ea1288b 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -183,6 +183,8 @@ public: void setDropTime(nsecs_t dropTime); void setPresentState(PresentState presentState, nsecs_t lastLatchTime = 0); void setRenderRate(Fps renderRate); + // Return the render rate if it exists, otherwise returns the DisplayFrame's render rate. + Fps getRenderRate() const; void setGpuComposition(); // When a bufferless SurfaceFrame is promoted to a buffer SurfaceFrame, we also have to update @@ -197,7 +199,8 @@ public: // displayRefreshRate, displayDeadlineDelta, and displayPresentDelta are propagated from the // display frame. void onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate, - nsecs_t displayDeadlineDelta, nsecs_t displayPresentDelta); + Fps displayFrameRenderRate, nsecs_t displayDeadlineDelta, + nsecs_t displayPresentDelta); // All the timestamps are dumped relative to the baseTime void dump(std::string& result, const std::string& indent, nsecs_t baseTime) const; // Dumps only the layer, token, is buffer, jank metadata, prediction and present states. @@ -251,6 +254,8 @@ private: int32_t mJankType GUARDED_BY(mMutex) = JankType::None; // Indicates if this frame was composited by the GPU or not bool mGpuComposition GUARDED_BY(mMutex) = false; + // Refresh rate for this frame. + Fps mDisplayFrameRenderRate GUARDED_BY(mMutex); // Rendering rate for this frame. std::optional mRenderRate GUARDED_BY(mMutex); // Enum for the type of present @@ -298,7 +303,8 @@ public: // The first function called by SF for the current DisplayFrame. Fetches SF predictions based on // the token and sets the actualSfWakeTime for the current DisplayFrame. - virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) = 0; + virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate, + Fps renderRate) = 0; // Sets the sfPresentTime and finalizes the current DisplayFrame. Tracks the // given present fence until it's signaled, and updates the present timestamps of all presented @@ -374,8 +380,8 @@ public: // and SYSTEM_TIME_MONOTONIC. void trace(pid_t surfaceFlingerPid, nsecs_t monoBootOffset) const; // Sets the token, vsyncPeriod, predictions and SF start time. - void onSfWakeUp(int64_t token, Fps refreshRate, std::optional predictions, - nsecs_t wakeUpTime); + void onSfWakeUp(int64_t token, Fps refreshRate, Fps renderRate, + std::optional predictions, nsecs_t wakeUpTime); // Sets the appropriate metadata and classifies the jank. void onPresent(nsecs_t signalTime, nsecs_t previousPresentTime); // Adds the provided SurfaceFrame to the current display frame. @@ -437,6 +443,8 @@ public: // The refresh rate (vsync period) in nanoseconds as seen by SF during this DisplayFrame's // timeline Fps mRefreshRate; + // The current render rate for this DisplayFrame. + Fps mRenderRate; // TraceCookieCounter is used to obtain the cookie for sendig trace packets to perfetto. // Using a reference here because the counter is owned by FrameTimeline, which outlives // DisplayFrame. @@ -453,7 +461,7 @@ public: int32_t layerId, std::string layerName, std::string debugName, bool isBuffer, GameMode) override; void addSurfaceFrame(std::shared_ptr surfaceFrame) override; - void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override; + void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate, Fps renderRate) override; void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr& presentFence, const std::shared_ptr& gpuFence = FenceTime::NO_FENCE) override; void parseArgs(const Vector& args, std::string& result) override; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index a73c5115b1..5f90a7f82d 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -787,8 +787,9 @@ void Layer::transferAvailableJankData(const std::deque>& hand if (includeJankData) { std::shared_ptr surfaceFrame = mPendingJankClassifications.front(); - jankData.emplace_back( - JankData(surfaceFrame->getToken(), surfaceFrame->getJankType().value())); + jankData.emplace_back(JankData(surfaceFrame->getToken(), + surfaceFrame->getJankType().value(), + surfaceFrame->getRenderRate().getPeriodNsecs())); } mPendingJankClassifications.pop_front(); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b7d2f9a053..2583868c6e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2487,7 +2487,8 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, { mFrameTimeline->setSfWakeUp(ftl::to_underlying(vsyncId), pacesetterFrameTarget.frameBeginTime().ns(), - Fps::fromPeriodNsecs(vsyncPeriod.ns())); + Fps::fromPeriodNsecs(vsyncPeriod.ns()), + mScheduler->getPacesetterRefreshRate()); const bool flushTransactions = clearTransactionFlags(eTransactionFlushNeeded); bool transactionsAreEmpty; diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index 8911430790..636d852651 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -54,6 +54,8 @@ constexpr int32_t sInputEventId = 5; constexpr int32_t sLayerIdOne = 1; constexpr int32_t sLayerIdTwo = 2; constexpr GameMode sGameMode = GameMode::Unsupported; +constexpr Fps RR_11 = Fps::fromPeriodNsecs(11); +constexpr Fps RR_30 = Fps::fromPeriodNsecs(30); class FrameTimelineTest : public testing::Test { public: @@ -276,7 +278,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { /*isBuffer*/ true, sGameMode); // Set up the display frame - mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(token1, 20, RR_11, RR_11); surfaceFrame1->setDropTime(12); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -309,7 +311,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdTwo, sLayerNameTwo, sLayerNameTwo, /*isBuffer*/ true, sGameMode); - mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken1, 22, RR_11, RR_11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -354,7 +356,7 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); - mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, RR_11, RR_11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence); @@ -379,7 +381,7 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); - mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, RR_11, RR_11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence); @@ -422,7 +424,7 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); - mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken, 22, RR_11, RR_11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); mFrameTimeline->setSfPresent(27, presentFence); @@ -439,7 +441,7 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); - mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken, 22, RR_11, RR_11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); mFrameTimeline->setSfPresent(27, presentFence); @@ -456,7 +458,7 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); - mFrameTimeline->setSfWakeUp(sfToken, 22, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken, 22, RR_11, RR_11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); mFrameTimeline->setSfPresent(27, presentFence); @@ -465,7 +467,7 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { } TEST_F(FrameTimelineTest, presentFenceSignaled_invalidSignalTime) { - Fps refreshRate = Fps::fromPeriodNsecs(11); + Fps refreshRate = RR_11; auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); @@ -478,7 +480,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_invalidSignalTime) { mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); - mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); + mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -496,7 +498,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_invalidSignalTime) { // Tests related to TimeStats TEST_F(FrameTimelineTest, presentFenceSignaled_doesNotReportForInvalidTokens) { - Fps refreshRate = Fps::fromPeriodNsecs(11); + Fps refreshRate = RR_11; EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(0); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = -1; @@ -509,7 +511,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_doesNotReportForInvalidTokens) { mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); - mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); + mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -519,7 +521,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_doesNotReportForInvalidTokens) { } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { - Fps refreshRate = Fps::fromPeriodNsecs(11); + Fps refreshRate = RR_11; EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, @@ -537,7 +539,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); - mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); + mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -547,7 +549,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfGpu) { - Fps refreshRate = Fps::fromPeriodNsecs(11); + Fps refreshRate = RR_11; EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, @@ -566,7 +568,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfGpu) { mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); - mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); + mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -577,7 +579,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfGpu) { } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { - Fps refreshRate = Fps::fromPeriodNsecs(30); + Fps refreshRate = RR_30; EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, sLayerNameOne, sGameMode, @@ -594,7 +596,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); - mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); + mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate, refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); surfaceFrame1->setAcquireFenceTime(20); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -622,7 +624,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); - mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); + mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate, refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -651,7 +653,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) { sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); - mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); + mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate, refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -680,7 +682,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) { sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); - mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); + mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate, refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -709,7 +711,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) { sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); - mFrameTimeline->setSfWakeUp(sfToken1, 82, refreshRate); + mFrameTimeline->setSfWakeUp(sfToken1, 82, refreshRate, refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented, /*previousLatchTime*/ 56); @@ -721,8 +723,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) { } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { - Fps refreshRate = Fps::fromPeriodNsecs(11); - Fps renderRate = Fps::fromPeriodNsecs(30); + Fps refreshRate = RR_11; + Fps renderRate = RR_30; EXPECT_CALL(*mTimeStats, incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne, sGameMode, @@ -740,7 +742,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); - mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); + mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate, refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); surfaceFrame1->setRenderRate(renderRate); @@ -752,8 +754,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { } TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPresentsSurfaceFrame) { - Fps refreshRate = Fps::fromPeriodNsecs(11); - Fps renderRate = Fps::fromPeriodNsecs(30); + Fps refreshRate = RR_11; + Fps renderRate = RR_30; EXPECT_CALL(*mTimeStats, incrementJankyFrames( @@ -775,7 +777,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPres surfaceFrame1->setAcquireFenceTime(45); // Trigger a prediction expiry flushTokens(); - mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); + mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate, refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); surfaceFrame1->setRenderRate(renderRate); @@ -814,7 +816,7 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { /*isBuffer*/ true, sGameMode); // Set up the display frame - mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(token1, 20, RR_11, RR_11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(25, presentFence1); @@ -844,7 +846,7 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { /*isBuffer*/ true, sGameMode); // Set up the display frame - mFrameTimeline->setSfWakeUp(token2, 20, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(token2, 20, RR_11, RR_11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(25, presentFence1); @@ -866,7 +868,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) tracingSession->StartBlocking(); // Set up the display frame - mFrameTimeline->setSfWakeUp(-1, 20, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(-1, 20, RR_11, RR_11); mFrameTimeline->setSfPresent(25, presentFence1); presentFence1->signalForTest(30); @@ -890,7 +892,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) /*isBuffer*/ true, sGameMode); // Set up the display frame - mFrameTimeline->setSfWakeUp(token1, 20, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(token1, 20, RR_11, RR_11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(25, presentFence1); @@ -1068,7 +1070,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 30, 30}); // Set up the display frame - mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, RR_11, RR_11); mFrameTimeline->setSfPresent(26, presentFence1); presentFence1->signalForTest(31); @@ -1150,7 +1152,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_predictionExpiredDoesNotTraceExpecte addEmptySurfaceFrame(); // Set up the display frame - mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, RR_11, RR_11); mFrameTimeline->setSfPresent(26, presentFence1); presentFence1->signalForTest(31); @@ -1252,7 +1254,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { auto protoPresentedSurfaceFrameActualEnd = createProtoFrameEnd(traceCookie + 4); // Set up the display frame - mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, RR_11, RR_11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -1398,7 +1400,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredIsAppMissedDeadline auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1); // Set up the display frame - mFrameTimeline->setSfWakeUp(displayFrameToken, sfStartTime, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(displayFrameToken, sfStartTime, RR_11, RR_11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(sfEndTime, presentFence1); @@ -1475,7 +1477,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDroppedFramesTraced auto protoActualSurfaceFrameEnd = createProtoFrameEnd(traceCookie + 1); // Set up the display frame - mFrameTimeline->setSfWakeUp(displayFrameToken, sfStartTime, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(displayFrameToken, sfStartTime, RR_11, RR_11); surfaceFrame1->setDropTime(sfStartTime); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Dropped); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -1528,7 +1530,7 @@ TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) { mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); - mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken1, 22, RR_11, RR_11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); mFrameTimeline->setSfPresent(26, presentFence1); @@ -1552,11 +1554,11 @@ TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) { } TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresent) { - Fps vsyncRate = Fps::fromPeriodNsecs(11); + Fps vsyncRate = RR_11; auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 40}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70}); - mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate); + mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate, vsyncRate); mFrameTimeline->setSfPresent(26, presentFence1); auto displayFrame = getDisplayFrame(0); presentFence1->signalForTest(30); @@ -1566,7 +1568,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresen // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); - mFrameTimeline->setSfWakeUp(sfToken2, 52, vsyncRate); + mFrameTimeline->setSfWakeUp(sfToken2, 52, vsyncRate, vsyncRate); mFrameTimeline->setSfPresent(56, presentFence2); displayFrame = getDisplayFrame(0); @@ -1591,11 +1593,11 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresen } TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent) { - Fps vsyncRate = Fps::fromPeriodNsecs(11); + Fps vsyncRate = RR_11; auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 40}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70}); - mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate); + mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate, vsyncRate); mFrameTimeline->setSfPresent(26, presentFence1); auto displayFrame = getDisplayFrame(0); presentFence1->signalForTest(50); @@ -1605,7 +1607,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); - mFrameTimeline->setSfWakeUp(sfToken2, 52, vsyncRate); + mFrameTimeline->setSfWakeUp(sfToken2, 52, vsyncRate, vsyncRate); mFrameTimeline->setSfPresent(56, presentFence2); displayFrame = getDisplayFrame(0); @@ -1633,7 +1635,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishEarlyPresent) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({12, 18, 40}); - mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken1, 12, RR_11, RR_11); mFrameTimeline->setSfPresent(22, presentFence1); auto displayFrame = getDisplayFrame(0); @@ -1673,7 +1675,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) int64_t sfToken4 = mTokenManager->generateTokenForPredictions({112, 120, 120}); // case 1 - cpu time = 33 - 12 = 21, vsync period = 11 - mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken1, 12, RR_11, RR_11); mFrameTimeline->setSfPresent(33, presentFence1, gpuFence1); auto displayFrame0 = getDisplayFrame(0); gpuFence1->signalForTest(36); @@ -1683,7 +1685,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) EXPECT_EQ(displayFrame0->getActuals().presentTime, 0); // case 2 - cpu time = 56 - 52 = 4, vsync period = 30 - mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(30)); + mFrameTimeline->setSfWakeUp(sfToken2, 52, RR_30, RR_30); mFrameTimeline->setSfPresent(56, presentFence2, gpuFence2); auto displayFrame1 = getDisplayFrame(1); gpuFence2->signalForTest(76); @@ -1697,7 +1699,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) EXPECT_EQ(displayFrame0->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed); // case 3 - cpu time = 86 - 82 = 4, vsync period = 30 - mFrameTimeline->setSfWakeUp(sfToken3, 106, Fps::fromPeriodNsecs(30)); + mFrameTimeline->setSfWakeUp(sfToken3, 106, RR_30, RR_30); mFrameTimeline->setSfPresent(112, presentFence3, gpuFence3); auto displayFrame2 = getDisplayFrame(2); gpuFence3->signalForTest(116); @@ -1711,7 +1713,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) EXPECT_EQ(displayFrame1->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed); // case 4 - cpu time = 86 - 82 = 4, vsync period = 30 - mFrameTimeline->setSfWakeUp(sfToken4, 120, Fps::fromPeriodNsecs(30)); + mFrameTimeline->setSfWakeUp(sfToken4, 120, RR_30, RR_30); mFrameTimeline->setSfPresent(140, presentFence4, gpuFence4); auto displayFrame3 = getDisplayFrame(3); gpuFence4->signalForTest(156); @@ -1748,7 +1750,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(16); - mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken1, 22, RR_11, RR_11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(27, presentFence1); @@ -1771,7 +1773,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(36); - mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken2, 52, RR_11, RR_11); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); mFrameTimeline->setSfPresent(57, presentFence2); @@ -1799,10 +1801,10 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen ::testing::Mock::VerifyAndClearExpectations(mTimeStats.get()); EXPECT_CALL(*mTimeStats, - incrementJankyFrames( - TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne, - sLayerNameOne, sGameMode, - JankType::PredictionError, -3, 5, 0})); + incrementJankyFrames(TimeStats::JankyFramesInfo{RR_11, std::nullopt, sUidOne, + sLayerNameOne, sGameMode, + JankType::PredictionError, -3, 5, + 0})); addEmptyDisplayFrame(); @@ -1834,7 +1836,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(16); - mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken1, 22, RR_11, RR_11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(26, presentFence1); @@ -1857,7 +1859,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(36); - mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken2, 52, RR_11, RR_11); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); mFrameTimeline->setSfPresent(57, presentFence2); @@ -1885,10 +1887,10 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent ::testing::Mock::VerifyAndClearExpectations(mTimeStats.get()); EXPECT_CALL(*mTimeStats, - incrementJankyFrames( - TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne, - sLayerNameOne, sGameMode, - JankType::PredictionError, -3, 5, 0})); + incrementJankyFrames(TimeStats::JankyFramesInfo{RR_11, std::nullopt, sUidOne, + sLayerNameOne, sGameMode, + JankType::PredictionError, -3, 5, + 0})); addEmptyDisplayFrame(); @@ -1919,7 +1921,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); - mFrameTimeline->setSfWakeUp(sfToken1, 42, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken1, 42, RR_11, RR_11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(46, presentFence1); @@ -1966,7 +1968,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(26); - mFrameTimeline->setSfWakeUp(sfToken1, 32, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken1, 32, RR_11, RR_11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(36, presentFence1); @@ -1989,7 +1991,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(40); - mFrameTimeline->setSfWakeUp(sfToken2, 43, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken2, 43, RR_11, RR_11); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame2); mFrameTimeline->setSfPresent(56, presentFence2); @@ -2047,7 +2049,7 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); - mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30)); + mFrameTimeline->setSfWakeUp(sfToken1, 52, RR_30, RR_30); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(56, presentFence1); @@ -2070,7 +2072,7 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(84); - mFrameTimeline->setSfWakeUp(sfToken2, 112, Fps::fromPeriodNsecs(30)); + mFrameTimeline->setSfWakeUp(sfToken2, 112, RR_30, RR_30); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54); mFrameTimeline->addSurfaceFrame(surfaceFrame2); mFrameTimeline->setSfPresent(116, presentFence2); @@ -2131,7 +2133,7 @@ TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffin sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); - mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30)); + mFrameTimeline->setSfWakeUp(sfToken1, 52, RR_30, RR_30); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); mFrameTimeline->setSfPresent(56, presentFence1); @@ -2154,7 +2156,7 @@ TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffin sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(80); - mFrameTimeline->setSfWakeUp(sfToken2, 82, Fps::fromPeriodNsecs(30)); + mFrameTimeline->setSfWakeUp(sfToken2, 82, RR_30, RR_30); // Setting previous latch time to 54, adjusted deadline will be 54 + vsyncTime(30) = 84 surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54); mFrameTimeline->addSurfaceFrame(surfaceFrame2); @@ -2206,7 +2208,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent_G int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 60}); // Case 1: cpu time = 33 - 12 = 21, vsync period = 11 - mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken1, 12, RR_11, RR_11); mFrameTimeline->setSfPresent(33, presentFence1, gpuFence1); auto displayFrame = getDisplayFrame(0); gpuFence1->signalForTest(36); @@ -2225,7 +2227,7 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent_G EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed); // Case 2: No GPU fence so it will not use GPU composition. - mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(30)); + mFrameTimeline->setSfWakeUp(sfToken2, 52, RR_30, RR_30); mFrameTimeline->setSfPresent(66, presentFence2); auto displayFrame2 = getDisplayFrame(2); // 2 because of previous empty frame presentFence2->signalForTest(90); @@ -2250,13 +2252,13 @@ TEST_F(FrameTimelineTest, jankClassification_presentFenceError) { int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 60}); int64_t sfToken3 = mTokenManager->generateTokenForPredictions({72, 80, 80}); - mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken1, 22, RR_11, RR_11); mFrameTimeline->setSfPresent(26, erroneousPresentFence1); - mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken2, 52, RR_11, RR_11); mFrameTimeline->setSfPresent(60, erroneousPresentFence2); - mFrameTimeline->setSfWakeUp(sfToken3, 72, Fps::fromPeriodNsecs(11)); + mFrameTimeline->setSfWakeUp(sfToken3, 72, RR_11, RR_11); mFrameTimeline->setSfPresent(80, validPresentFence); erroneousPresentFence2->signalForTest(2); @@ -2479,4 +2481,44 @@ TEST_F(FrameTimelineTest, getMinTime) { mFrameTimeline->setSfPresent(50, presentFence); ASSERT_EQ(surfaceFrame->getBaseTime(), 50); } + +TEST_F(FrameTimelineTest, surfaceFrameRenderRateUsingDisplayRate) { + auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = sInputEventId; + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); + + mFrameTimeline->setSfWakeUp(token1, 20, RR_30, RR_11); + surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); + mFrameTimeline->addSurfaceFrame(surfaceFrame); + presentFence1->signalForTest(std::chrono::nanoseconds(50ns).count()); + mFrameTimeline->setSfPresent(50, presentFence1); + + EXPECT_EQ(surfaceFrame->getRenderRate().getPeriodNsecs(), 11); +} + +TEST_F(FrameTimelineTest, surfaceFrameRenderRateUsingAppFrameRate) { + auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = sInputEventId; + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); + surfaceFrame->setRenderRate(RR_30); + mFrameTimeline->setSfWakeUp(token1, 20, RR_11, RR_11); + surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); + mFrameTimeline->addSurfaceFrame(surfaceFrame); + presentFence1->signalForTest(std::chrono::nanoseconds(50ns).count()); + mFrameTimeline->setSfPresent(50, presentFence1); + + EXPECT_EQ(surfaceFrame->getRenderRate().getPeriodNsecs(), 30); +} } // namespace android::frametimeline diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index caa265fcd9..5046a86304 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -347,7 +347,7 @@ public: // Both the droppedSurfaceFrame and presentedSurfaceFrame should be in // pendingJankClassifications. EXPECT_EQ(2u, layer->mPendingJankClassifications.size()); - presentedSurfaceFrame->onPresent(20, JankType::None, 90_Hz, + presentedSurfaceFrame->onPresent(20, JankType::None, 90_Hz, 90_Hz, /*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0); layer->releasePendingBuffer(25); @@ -484,10 +484,10 @@ public: // BufferlessSurfaceFrames are immediately set to presented and added to the DisplayFrame. // Since we don't have access to DisplayFrame here, trigger an onPresent directly. for (auto& surfaceFrame : bufferlessSurfaceFrames) { - surfaceFrame->onPresent(20, JankType::None, 90_Hz, + surfaceFrame->onPresent(20, JankType::None, 90_Hz, 90_Hz, /*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0); } - presentedBufferSurfaceFrame->onPresent(20, JankType::None, 90_Hz, + presentedBufferSurfaceFrame->onPresent(20, JankType::None, 90_Hz, 90_Hz, /*displayDeadlineDelta*/ 0, /*displayPresentDelta*/ 0); diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h index 5dc48c3703..3f2a917ddc 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h +++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h @@ -31,7 +31,7 @@ public: MOCK_METHOD0(onBootFinished, void()); MOCK_METHOD1(addSurfaceFrame, void(std::shared_ptr)); - MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, Fps)); + MOCK_METHOD4(setSfWakeUp, void(int64_t, nsecs_t, Fps, Fps)); MOCK_METHOD3(setSfPresent, void(nsecs_t, const std::shared_ptr&, const std::shared_ptr&)); -- GitLab From e88e0ba23124042c6127b2258e67b39b116bc47d Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 28 Jun 2023 15:09:09 +0000 Subject: [PATCH 0836/1187] [Cherry-pick] Avoid unloading ANGLE. Previously when ANGLE is the default GLES driver and preloaded, by setting an application to use ANGLE when ANGLE apk doesn't present, the system ANGLE should be used. However, the loader will unload the default driver and load ANGLE. And hence when ANGLE is the default GLES driver, it will be unloaded and then reloaded. This patch makes sure the loader skips unloading and immediately return in this case. Minor: Only unload the drivers when there are preloaded drivers. Bug: b/283858001 Test: verified with camera Test: verified by forcing GLES driver preloading Change-Id: I82b6408405ef7c507e50ab259204bdce95fda110 Merged-In: I82b6408405ef7c507e50ab259204bdce95fda110 --- libs/graphicsenv/GraphicsEnv.cpp | 25 +++++++++++-------- .../include/graphicsenv/GraphicsEnv.h | 3 ++- opengl/libs/EGL/Loader.cpp | 25 +++++++++++-------- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 2c274be08e..5bdffe0368 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -420,7 +420,7 @@ bool GraphicsEnv::shouldUseAngle() { return mShouldUseAngle; } -void GraphicsEnv::setAngleInfo(const std::string& path, const bool useSystemAngle, +void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSystemAngle, const std::string& packageName, const std::vector eglFeatures) { if (mShouldUseAngle) { @@ -438,7 +438,7 @@ void GraphicsEnv::setAngleInfo(const std::string& path, const bool useSystemAngl ALOGV("setting app package name to '%s'", packageName.c_str()); mPackageName = std::move(packageName); mShouldUseAngle = true; - mUseSystemAngle = useSystemAngle; + mShouldUseSystemAngle = shouldUseSystemAngle; } void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, @@ -589,7 +589,7 @@ android_namespace_t* GraphicsEnv::getAngleNamespace() { return mAngleNamespace; } - if (mAnglePath.empty() && !mUseSystemAngle) { + if (mAnglePath.empty() && !mShouldUseSystemAngle) { ALOGV("mAnglePath is empty and not using system ANGLE, abort creating ANGLE namespace"); return nullptr; } @@ -607,18 +607,19 @@ android_namespace_t* GraphicsEnv::getAngleNamespace() { // are properly inherited. mAngleNamespace = android_create_namespace("ANGLE", - mUseSystemAngle ? defaultLibraryPaths - : mAnglePath.c_str(), // ld_library_path - mUseSystemAngle ? defaultLibraryPaths - : mAnglePath.c_str(), // default_library_path + mShouldUseSystemAngle ? defaultLibraryPaths + : mAnglePath.c_str(), // ld_library_path + mShouldUseSystemAngle + ? defaultLibraryPaths + : mAnglePath.c_str(), // default_library_path ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED, nullptr, // permitted_when_isolated_path - mUseSystemAngle ? android_get_exported_namespace("sphal") - : nullptr); // parent + mShouldUseSystemAngle ? android_get_exported_namespace("sphal") + : nullptr); // parent ALOGD_IF(!mAngleNamespace, "Could not create ANGLE namespace from default"); - if (!mUseSystemAngle) { + if (!mShouldUseSystemAngle) { return mAngleNamespace; } @@ -643,4 +644,8 @@ void GraphicsEnv::nativeToggleAngleAsSystemDriver(bool enabled) { gpuService->toggleAngleAsSystemDriver(enabled); } +bool GraphicsEnv::shouldUseSystemAngle() { + return mShouldUseSystemAngle; +} + } // namespace android diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index e78d038ea5..fbf2902869 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -117,6 +117,7 @@ public: const std::vector& getAngleEglFeatures(); // Set the persist.graphics.egl system property value. void nativeToggleAngleAsSystemDriver(bool enabled); + bool shouldUseSystemAngle(); /* * Apis for debug layer @@ -173,7 +174,7 @@ private: // Whether ANGLE should be used. bool mShouldUseAngle = false; // Whether loader should load system ANGLE. - bool mUseSystemAngle = false; + bool mShouldUseSystemAngle = false; // ANGLE namespace. android_namespace_t* mAngleNamespace = nullptr; diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index b4fc5f0dd2..8d0eb590bf 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -161,7 +161,12 @@ static bool should_unload_system_driver(egl_connection_t* cnx) { // Return true if ANGLE namespace is set. android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace(); if (ns) { - return true; + // Unless the default GLES driver is ANGLE and the process should use system ANGLE, since + // the intended GLES driver is already loaded. + // This should be updated in a later patch that cleans up namespaces + if (!(cnx->angleLoaded && android::GraphicsEnv::getInstance().shouldUseSystemAngle())) { + return true; + } } // Return true if updated driver namespace is set. @@ -206,17 +211,17 @@ void Loader::unload_system_driver(egl_connection_t* cnx) { do_android_unload_sphal_library(hnd->dso[0]); } cnx->dso = nullptr; + cnx->angleLoaded = false; } cnx->systemDriverUnloaded = true; } -void* Loader::open(egl_connection_t* cnx) -{ +void* Loader::open(egl_connection_t* cnx) { ATRACE_CALL(); const nsecs_t openTime = systemTime(); - if (should_unload_system_driver(cnx)) { + if (cnx->dso && should_unload_system_driver(cnx)) { unload_system_driver(cnx); } @@ -225,8 +230,12 @@ void* Loader::open(egl_connection_t* cnx) return cnx->dso; } - // Firstly, try to load ANGLE driver. - driver_t* hnd = attempt_to_load_angle(cnx); + driver_t* hnd = nullptr; + // Firstly, try to load ANGLE driver, if ANGLE should be loaded and fail, abort. + if (android::GraphicsEnv::getInstance().shouldUseAngle()) { + hnd = attempt_to_load_angle(cnx); + LOG_ALWAYS_FATAL_IF(!hnd, "Failed to load ANGLE."); + } if (!hnd) { // Secondly, try to load from driver apk. @@ -541,10 +550,6 @@ static void* load_updated_driver(const char* kind, android_namespace_t* ns) { Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) { ATRACE_CALL(); - if (!android::GraphicsEnv::getInstance().shouldUseAngle()) { - return nullptr; - } - android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace(); if (!ns) { return nullptr; -- GitLab From 0884c553986c4ea13ef4e449c900bb1ca13160b6 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 17 Oct 2023 18:23:31 +0000 Subject: [PATCH 0837/1187] binderRpcTest: conditional experimental protocol Previously this test failed in REL mode and required a change. This was done so that we made sure to freeze it for release. Now that we have TARGET_RELEASE, we need to make this conditional. Bug: 305786304 Test: binderRpcTest on '-next' configuration Change-Id: I726c71399c7e469698abc630a006ce089dc4bca8 --- libs/binder/RpcState.cpp | 3 ++- libs/binder/tests/binderRpcTestCommon.h | 13 ++++++++++++- libs/binder/tests/binderRpcUniversalTests.cpp | 3 ++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index bac2808b26..f9e833b126 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -409,10 +409,11 @@ bool RpcState::validateProtocolVersion(uint32_t version) { char codename[PROPERTY_VALUE_MAX]; property_get("ro.build.version.codename", codename, ""); if (!strcmp(codename, "REL")) { - ALOGE("Cannot use experimental RPC binder protocol on a release branch."); + ALOGE("Cannot use experimental RPC binder protocol in a release configuration."); return false; } #else + // TODO(b/305983144) // don't restrict on other platforms, though experimental should // only really be used for testing, we don't have a good way to see // what is shipping outside of Android diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h index c1364dd9a0..eceff35e3e 100644 --- a/libs/binder/tests/binderRpcTestCommon.h +++ b/libs/binder/tests/binderRpcTestCommon.h @@ -70,12 +70,23 @@ static inline std::vector RpcSecurityValues() { return {RpcSecurity::RAW, RpcSecurity::TLS}; } +static inline bool hasExperimentalRpc() { +#ifdef __ANDROID__ + return base::GetProperty("ro.build.version.codename", "") != "REL"; +#else + // TODO(b/305983144): restrict on other platforms + return true; +#endif +} + static inline std::vector testVersions() { std::vector versions; for (size_t i = 0; i < RPC_WIRE_PROTOCOL_VERSION_NEXT; i++) { versions.push_back(i); } - versions.push_back(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL); + if (hasExperimentalRpc()) { + versions.push_back(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL); + } return versions; } diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp index e43508ee79..885bb45d82 100644 --- a/libs/binder/tests/binderRpcUniversalTests.cpp +++ b/libs/binder/tests/binderRpcUniversalTests.cpp @@ -50,7 +50,8 @@ TEST(BinderRpc, CannotUseNextWireVersion) { TEST(BinderRpc, CanUseExperimentalWireVersion) { auto session = RpcSession::make(); - EXPECT_TRUE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL)); + EXPECT_EQ(hasExperimentalRpc(), + session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL)); } TEST_P(BinderRpc, Ping) { -- GitLab From a5fec0bbd30c82016b06aedddc2fe6fa6ee93588 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 17 Oct 2023 18:27:46 +0000 Subject: [PATCH 0838/1187] binderRpcWireProtocolTest: remove experimental We are no longer testing that when the wire protocol version is not experimental, that the experimental wire protocol version has no changes. Due to TARGET_RELEASE, we will never mark the 'current' or 'default' version of the wire protocol to be the experimental version. Instead, the experimental version would stage various changes to the wire protocol, and we'd update the default once we want to stabilize that. Bug: 305786304 Test: binderRpcWireProtocolTest on -next Change-Id: Ie4db164bc00ff5980c2c10f0697a05557c752a3a --- libs/binder/tests/binderRpcWireProtocolTest.cpp | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/libs/binder/tests/binderRpcWireProtocolTest.cpp b/libs/binder/tests/binderRpcWireProtocolTest.cpp index 642cea440d..2718af6d70 100644 --- a/libs/binder/tests/binderRpcWireProtocolTest.cpp +++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp @@ -263,16 +263,4 @@ TEST(RpcWire, ReleaseBranchHasFrozenRpcWireProtocol) { } } -TEST(RpcWire, IfNotExperimentalCodeHasNoExperimentalFeatures) { - if (RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) { - GTEST_SKIP() << "Version is experimental, so experimental features are okay."; - } - - // if we set the wire protocol version to experimental, none of the code - // should introduce a difference (if this fails, it means we have features - // which are enabled under experimental mode, but we aren't actually using - // or testing them!) - checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL); -} - } // namespace android -- GitLab From 2661b73e149e99a3202e922d07174cb80b5d6122 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Fri, 30 Jun 2023 00:35:07 +0000 Subject: [PATCH 0839/1187] [Cherry-pick] Load native GLES driver when specified. Since ANGLE and native GLES drivers can coexist, when native is specified, the loader must load the native GLES drivers specified in ro.hardware.egl. This patch adds the support to load native GLES drivers when specified. Bug: b/283858001 Test: atest CtsAngleDeveloperOptionHostTest -c with ANGLE being default Test: atest CtsAngleDeveloperOptionHostTest -c with native being default Change-Id: I85840811d9586bd9f2765b47f3cd1a94c9a8580a Merged-In: I85840811d9586bd9f2765b47f3cd1a94c9a8580a --- libs/graphicsenv/GraphicsEnv.cpp | 21 +++++++++++--- .../include/graphicsenv/GraphicsEnv.h | 8 ++++- opengl/libs/EGL/Loader.cpp | 29 +++++++++++++++---- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 5bdffe0368..1adf1afaa2 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -420,7 +420,11 @@ bool GraphicsEnv::shouldUseAngle() { return mShouldUseAngle; } -void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSystemAngle, +// Set ANGLE information. +// If path is "system", it means system ANGLE must be used for the process. +// If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. +// If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. +void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, const std::string& packageName, const std::vector eglFeatures) { if (mShouldUseAngle) { @@ -437,8 +441,13 @@ void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSyst mAnglePath = std::move(path); ALOGV("setting app package name to '%s'", packageName.c_str()); mPackageName = std::move(packageName); - mShouldUseAngle = true; - mShouldUseSystemAngle = shouldUseSystemAngle; + if (path == "system") { + mShouldUseSystemAngle = true; + } + if (!path.empty()) { + mShouldUseAngle = true; + } + mShouldUseNativeDriver = shouldUseNativeDriver; } void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, @@ -564,7 +573,7 @@ android_namespace_t* GraphicsEnv::getDriverNamespace() { return nullptr; } - mDriverNamespace = android_create_namespace("gfx driver", + mDriverNamespace = android_create_namespace("updatable gfx driver", mDriverPath.c_str(), // ld_library_path mDriverPath.c_str(), // default_library_path ANDROID_NAMESPACE_TYPE_ISOLATED, @@ -648,4 +657,8 @@ bool GraphicsEnv::shouldUseSystemAngle() { return mShouldUseSystemAngle; } +bool GraphicsEnv::shouldUseNativeDriver() { + return mShouldUseNativeDriver; +} + } // namespace android diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index fbf2902869..6cce3f6998 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -108,7 +108,10 @@ public: // (libraries must be stored uncompressed and page aligned); such elements // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a - void setAngleInfo(const std::string& path, const bool useSystemAngle, + // If the search patch is "system", then it means the system ANGLE should be used. + // If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. + // If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. + void setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, const std::string& packageName, const std::vector eglFeatures); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); @@ -118,6 +121,7 @@ public: // Set the persist.graphics.egl system property value. void nativeToggleAngleAsSystemDriver(bool enabled); bool shouldUseSystemAngle(); + bool shouldUseNativeDriver(); /* * Apis for debug layer @@ -175,6 +179,8 @@ private: bool mShouldUseAngle = false; // Whether loader should load system ANGLE. bool mShouldUseSystemAngle = false; + // Whether loader should load native GLES driver. + bool mShouldUseNativeDriver = false; // ANGLE namespace. android_namespace_t* mAngleNamespace = nullptr; diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 8d0eb590bf..654e5b7c03 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -169,6 +169,11 @@ static bool should_unload_system_driver(egl_connection_t* cnx) { } } + // Return true if native GLES drivers should be used and ANGLE is already loaded. + if (android::GraphicsEnv::getInstance().shouldUseNativeDriver() && cnx->angleLoaded) { + return true; + } + // Return true if updated driver namespace is set. ns = android::GraphicsEnv::getInstance().getDriverNamespace(); if (ns) { @@ -240,16 +245,28 @@ void* Loader::open(egl_connection_t* cnx) { if (!hnd) { // Secondly, try to load from driver apk. hnd = attempt_to_load_updated_driver(cnx); + + // If updated driver apk is set but fail to load, abort here. + LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace(), + "couldn't find an OpenGL ES implementation from %s", + android::GraphicsEnv::getInstance().getDriverPath().c_str()); } + // Attempt to load native GLES drivers specified by ro.hardware.egl if native is selected. + // If native is selected but fail to load, abort. + if (!hnd && android::GraphicsEnv::getInstance().shouldUseNativeDriver()) { + auto driverSuffix = base::GetProperty(RO_DRIVER_SUFFIX_PROPERTY, ""); + LOG_ALWAYS_FATAL_IF(driverSuffix.empty(), + "Native GLES driver is selected but not specified in %s", + RO_DRIVER_SUFFIX_PROPERTY); + hnd = attempt_to_load_system_driver(cnx, driverSuffix.c_str(), true); + LOG_ALWAYS_FATAL_IF(!hnd, "Native GLES driver is selected but failed to load. %s=%s", + RO_DRIVER_SUFFIX_PROPERTY, driverSuffix.c_str()); + } + + // Finally, try to load default driver. bool failToLoadFromDriverSuffixProperty = false; if (!hnd) { - // If updated driver apk is set but fail to load, abort here. - if (android::GraphicsEnv::getInstance().getDriverNamespace()) { - LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s", - android::GraphicsEnv::getInstance().getDriverPath().c_str()); - } - // Finally, try to load system driver. // Start by searching for the library name appended by the system // properties of the GLES userspace driver in both locations. // i.e.: -- GitLab From 0df8c2e698f36da0faf34f5a5491ac9b70af5cf7 Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Tue, 17 Oct 2023 19:18:38 +0000 Subject: [PATCH 0840/1187] Remove some unused fields from Layer Bug: 295456126 Test: builds Change-Id: Ic8ffd8326eec571883366e6254f3c5e53d06bcc8 --- services/surfaceflinger/Layer.cpp | 5 ----- services/surfaceflinger/Layer.h | 3 --- 2 files changed, 8 deletions(-) diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 97326e98c1..28f4720ae2 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2931,11 +2931,6 @@ void Layer::onLayerDisplayed(ftl::SharedFuture futureFenceResult, } } - // Prevent tracing the same release multiple times. - if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) { - mPreviousReleasedFrameNumber = mPreviousFrameNumber; - } - if (ch != nullptr) { ch->previousReleaseCallbackId = mPreviousReleaseCallbackId; ch->previousReleaseFences.emplace_back(std::move(futureFenceResult)); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index f67da2aee4..26e4666ab1 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -1235,9 +1235,6 @@ private: ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; sp mPreviousReleaseBufferEndpoint; - uint64_t mPreviousReleasedFrameNumber = 0; - - uint64_t mPreviousBarrierFrameNumber = 0; bool mReleasePreviousBuffer = false; -- GitLab From ef20e4e8052e0ae02e37dbba1d4663cb09839a0b Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Mon, 3 Jul 2023 02:33:00 +0000 Subject: [PATCH 0841/1187] [Cherry-pick] Group methods with similar purpose. Bug: b/283858001 Test: atest CtsAngleDeveloperOptionHostTest -c Change-Id: I8654b19d3a582477ea59cbff875b5ecf0817d06d Merged-In: I8654b19d3a582477ea59cbff875b5ecf0817d06d --- libs/graphicsenv/GraphicsEnv.cpp | 306 ++++++++++++++++--------------- 1 file changed, 161 insertions(+), 145 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 1adf1afaa2..ed5d5c1095 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -138,6 +138,16 @@ static const std::string getSystemNativeLibraries(NativeLibrary type) { return base::Join(soNames, ':'); } +static sp getGpuService() { + static const sp binder = defaultServiceManager()->checkService(String16("gpu")); + if (!binder) { + ALOGE("Failed to get gpu service"); + return nullptr; + } + + return interface_cast(binder); +} + /*static*/ GraphicsEnv& GraphicsEnv::getInstance() { static GraphicsEnv env; return env; @@ -160,6 +170,10 @@ bool GraphicsEnv::isDebuggable() { return appDebuggable || platformDebuggable; } +/** + * APIs for updatable graphics drivers + */ + void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string& path, const std::string& sphalLibraries) { if (!mDriverPath.empty() || !mSphalLibraries.empty()) { @@ -174,6 +188,108 @@ void GraphicsEnv::setDriverPathAndSphalLibraries(const std::string& path, mSphalLibraries = sphalLibraries; } +// Return true if all the required libraries from vndk and sphal namespace are +// linked to the driver namespace correctly. +bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* destNamespace, + android_namespace_t* vndkNamespace, + const std::string& sharedSphalLibraries) { + const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK); + if (llndkLibraries.empty()) { + return false; + } + if (!android_link_namespaces(destNamespace, nullptr, llndkLibraries.c_str())) { + ALOGE("Failed to link default namespace[%s]", dlerror()); + return false; + } + + const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP); + if (vndkspLibraries.empty()) { + return false; + } + if (!android_link_namespaces(destNamespace, vndkNamespace, vndkspLibraries.c_str())) { + ALOGE("Failed to link vndk namespace[%s]", dlerror()); + return false; + } + + if (sharedSphalLibraries.empty()) { + return true; + } + + // Make additional libraries in sphal to be accessible + auto sphalNamespace = android_get_exported_namespace("sphal"); + if (!sphalNamespace) { + ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace", + sharedSphalLibraries.c_str()); + return false; + } + + if (!android_link_namespaces(destNamespace, sphalNamespace, sharedSphalLibraries.c_str())) { + ALOGE("Failed to link sphal namespace[%s]", dlerror()); + return false; + } + + return true; +} + +android_namespace_t* GraphicsEnv::getDriverNamespace() { + std::lock_guard lock(mNamespaceMutex); + + if (mDriverNamespace) { + return mDriverNamespace; + } + + if (mDriverPath.empty()) { + // For an application process, driver path is empty means this application is not opted in + // to use updatable driver. Application process doesn't have the ability to set up + // environment variables and hence before `getenv` call will return. + // For a process that is not an application process, if it's run from an environment, + // for example shell, where environment variables can be set, then it can opt into using + // udpatable driver by setting UPDATABLE_GFX_DRIVER to 1. By setting to 1 the developer + // driver will be used currently. + // TODO(b/159240322) Support the production updatable driver. + const char* id = getenv("UPDATABLE_GFX_DRIVER"); + if (id == nullptr || std::strcmp(id, "1") != 0) { + return nullptr; + } + const sp gpuService = getGpuService(); + if (!gpuService) { + return nullptr; + } + mDriverPath = gpuService->getUpdatableDriverPath(); + if (mDriverPath.empty()) { + return nullptr; + } + mDriverPath.append(UPDATABLE_DRIVER_ABI); + ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str()); + } + + auto vndkNamespace = android_get_exported_namespace("vndk"); + if (!vndkNamespace) { + return nullptr; + } + + mDriverNamespace = android_create_namespace("updatable gfx driver", + mDriverPath.c_str(), // ld_library_path + mDriverPath.c_str(), // default_library_path + ANDROID_NAMESPACE_TYPE_ISOLATED, + nullptr, // permitted_when_isolated_path + nullptr); + + if (!linkDriverNamespaceLocked(mDriverNamespace, vndkNamespace, mSphalLibraries)) { + mDriverNamespace = nullptr; + } + + return mDriverNamespace; +} + +std::string GraphicsEnv::getDriverPath() const { + return mDriverPath; +} + +/** + * APIs for GpuStats + */ + void GraphicsEnv::hintActivityLaunch() { ATRACE_CALL(); @@ -328,16 +444,6 @@ void GraphicsEnv::setVulkanDeviceExtensions(uint32_t enabledExtensionCount, extensionHashes, numStats); } -static sp getGpuService() { - static const sp binder = defaultServiceManager()->checkService(String16("gpu")); - if (!binder) { - ALOGE("Failed to get gpu service"); - return nullptr; - } - - return interface_cast(binder); -} - bool GraphicsEnv::readyToSendGpuStatsLocked() { // Only send stats for processes having at least one activity launched and that process doesn't // skip the GraphicsEnvironment setup. @@ -410,6 +516,10 @@ bool GraphicsEnv::setInjectLayersPrSetDumpable() { return true; } +/** + * APIs for ANGLE + */ + bool GraphicsEnv::shouldUseAngle() { // Make sure we are init'ed if (mPackageName.empty()) { @@ -441,30 +551,15 @@ void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNati mAnglePath = std::move(path); ALOGV("setting app package name to '%s'", packageName.c_str()); mPackageName = std::move(packageName); - if (path == "system") { + if (mAnglePath == "system") { mShouldUseSystemAngle = true; } - if (!path.empty()) { + if (!mAnglePath.empty()) { mShouldUseAngle = true; } mShouldUseNativeDriver = shouldUseNativeDriver; } -void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, - const std::string& layerPaths) { - if (mLayerPaths.empty()) { - mLayerPaths = layerPaths; - mAppNamespace = appNamespace; - } else { - ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'", - layerPaths.c_str(), appNamespace); - } -} - -NativeLoaderNamespace* GraphicsEnv::getAppNamespace() { - return mAppNamespace; -} - std::string& GraphicsEnv::getPackageName() { return mPackageName; } @@ -473,124 +568,6 @@ const std::vector& GraphicsEnv::getAngleEglFeatures() { return mAngleEglFeatures; } -const std::string& GraphicsEnv::getLayerPaths() { - return mLayerPaths; -} - -const std::string& GraphicsEnv::getDebugLayers() { - return mDebugLayers; -} - -const std::string& GraphicsEnv::getDebugLayersGLES() { - return mDebugLayersGLES; -} - -void GraphicsEnv::setDebugLayers(const std::string& layers) { - mDebugLayers = layers; -} - -void GraphicsEnv::setDebugLayersGLES(const std::string& layers) { - mDebugLayersGLES = layers; -} - -// Return true if all the required libraries from vndk and sphal namespace are -// linked to the driver namespace correctly. -bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* destNamespace, - android_namespace_t* vndkNamespace, - const std::string& sharedSphalLibraries) { - const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK); - if (llndkLibraries.empty()) { - return false; - } - if (!android_link_namespaces(destNamespace, nullptr, llndkLibraries.c_str())) { - ALOGE("Failed to link default namespace[%s]", dlerror()); - return false; - } - - const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP); - if (vndkspLibraries.empty()) { - return false; - } - if (!android_link_namespaces(destNamespace, vndkNamespace, vndkspLibraries.c_str())) { - ALOGE("Failed to link vndk namespace[%s]", dlerror()); - return false; - } - - if (sharedSphalLibraries.empty()) { - return true; - } - - // Make additional libraries in sphal to be accessible - auto sphalNamespace = android_get_exported_namespace("sphal"); - if (!sphalNamespace) { - ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace", - sharedSphalLibraries.c_str()); - return false; - } - - if (!android_link_namespaces(destNamespace, sphalNamespace, sharedSphalLibraries.c_str())) { - ALOGE("Failed to link sphal namespace[%s]", dlerror()); - return false; - } - - return true; -} - -android_namespace_t* GraphicsEnv::getDriverNamespace() { - std::lock_guard lock(mNamespaceMutex); - - if (mDriverNamespace) { - return mDriverNamespace; - } - - if (mDriverPath.empty()) { - // For an application process, driver path is empty means this application is not opted in - // to use updatable driver. Application process doesn't have the ability to set up - // environment variables and hence before `getenv` call will return. - // For a process that is not an application process, if it's run from an environment, - // for example shell, where environment variables can be set, then it can opt into using - // udpatable driver by setting UPDATABLE_GFX_DRIVER to 1. By setting to 1 the developer - // driver will be used currently. - // TODO(b/159240322) Support the production updatable driver. - const char* id = getenv("UPDATABLE_GFX_DRIVER"); - if (id == nullptr || std::strcmp(id, "1")) { - return nullptr; - } - const sp gpuService = getGpuService(); - if (!gpuService) { - return nullptr; - } - mDriverPath = gpuService->getUpdatableDriverPath(); - if (mDriverPath.empty()) { - return nullptr; - } - mDriverPath.append(UPDATABLE_DRIVER_ABI); - ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str()); - } - - auto vndkNamespace = android_get_exported_namespace("vndk"); - if (!vndkNamespace) { - return nullptr; - } - - mDriverNamespace = android_create_namespace("updatable gfx driver", - mDriverPath.c_str(), // ld_library_path - mDriverPath.c_str(), // default_library_path - ANDROID_NAMESPACE_TYPE_ISOLATED, - nullptr, // permitted_when_isolated_path - nullptr); - - if (!linkDriverNamespaceLocked(mDriverNamespace, vndkNamespace, mSphalLibraries)) { - mDriverNamespace = nullptr; - } - - return mDriverNamespace; -} - -std::string GraphicsEnv::getDriverPath() const { - return mDriverPath; -} - android_namespace_t* GraphicsEnv::getAngleNamespace() { std::lock_guard lock(mNamespaceMutex); @@ -661,4 +638,43 @@ bool GraphicsEnv::shouldUseNativeDriver() { return mShouldUseNativeDriver; } +/** + * APIs for debuggable layers + */ + +void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, + const std::string& layerPaths) { + if (mLayerPaths.empty()) { + mLayerPaths = layerPaths; + mAppNamespace = appNamespace; + } else { + ALOGV("Vulkan layer search path already set, not clobbering with '%s' for namespace %p'", + layerPaths.c_str(), appNamespace); + } +} + +NativeLoaderNamespace* GraphicsEnv::getAppNamespace() { + return mAppNamespace; +} + +const std::string& GraphicsEnv::getLayerPaths() { + return mLayerPaths; +} + +const std::string& GraphicsEnv::getDebugLayers() { + return mDebugLayers; +} + +const std::string& GraphicsEnv::getDebugLayersGLES() { + return mDebugLayersGLES; +} + +void GraphicsEnv::setDebugLayers(const std::string& layers) { + mDebugLayers = layers; +} + +void GraphicsEnv::setDebugLayersGLES(const std::string& layers) { + mDebugLayersGLES = layers; +} + } // namespace android -- GitLab From 28a4b078dba128e0e4355fd5fa1c7e1354d7596d Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Fri, 7 Jul 2023 16:46:16 +0000 Subject: [PATCH 0842/1187] [Cherry-pick] Revert "Load native GLES driver when specified." This reverts commit 0d60e80ad8162e791305dfb8844a59f1ef9840d3. Reason for revert: culprit of boot memory regression Original commit message: """ Load native GLES driver when specified. Since ANGLE and native GLES drivers can coexist, when native is specified, the loader must load the native GLES drivers specified in ro.hardware.egl. This patch adds the support to load native GLES drivers when specified. Bug: b/283858001 Test: atest CtsAngleDeveloperOptionHostTest -c with ANGLE being default Test: atest CtsAngleDeveloperOptionHostTest -c with native being default """ Bug: b/283858001 Bug: b/289956225 Test: forrest test Change-Id: I785d2d3ff8dd21a1a207ccd814b5dddb080e9b52 Merged-In: I785d2d3ff8dd21a1a207ccd814b5dddb080e9b52 --- libs/graphicsenv/GraphicsEnv.cpp | 19 ++---------- .../include/graphicsenv/GraphicsEnv.h | 8 +---- opengl/libs/EGL/Loader.cpp | 29 ++++--------------- 3 files changed, 10 insertions(+), 46 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index ed5d5c1095..0a5416128e 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -530,11 +530,7 @@ bool GraphicsEnv::shouldUseAngle() { return mShouldUseAngle; } -// Set ANGLE information. -// If path is "system", it means system ANGLE must be used for the process. -// If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. -// If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. -void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, +void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSystemAngle, const std::string& packageName, const std::vector eglFeatures) { if (mShouldUseAngle) { @@ -551,13 +547,8 @@ void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNati mAnglePath = std::move(path); ALOGV("setting app package name to '%s'", packageName.c_str()); mPackageName = std::move(packageName); - if (mAnglePath == "system") { - mShouldUseSystemAngle = true; - } - if (!mAnglePath.empty()) { - mShouldUseAngle = true; - } - mShouldUseNativeDriver = shouldUseNativeDriver; + mShouldUseAngle = true; + mShouldUseSystemAngle = shouldUseSystemAngle; } std::string& GraphicsEnv::getPackageName() { @@ -634,10 +625,6 @@ bool GraphicsEnv::shouldUseSystemAngle() { return mShouldUseSystemAngle; } -bool GraphicsEnv::shouldUseNativeDriver() { - return mShouldUseNativeDriver; -} - /** * APIs for debuggable layers */ diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index 6cce3f6998..fbf2902869 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -108,10 +108,7 @@ public: // (libraries must be stored uncompressed and page aligned); such elements // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a - // If the search patch is "system", then it means the system ANGLE should be used. - // If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. - // If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. - void setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, + void setAngleInfo(const std::string& path, const bool useSystemAngle, const std::string& packageName, const std::vector eglFeatures); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); @@ -121,7 +118,6 @@ public: // Set the persist.graphics.egl system property value. void nativeToggleAngleAsSystemDriver(bool enabled); bool shouldUseSystemAngle(); - bool shouldUseNativeDriver(); /* * Apis for debug layer @@ -179,8 +175,6 @@ private: bool mShouldUseAngle = false; // Whether loader should load system ANGLE. bool mShouldUseSystemAngle = false; - // Whether loader should load native GLES driver. - bool mShouldUseNativeDriver = false; // ANGLE namespace. android_namespace_t* mAngleNamespace = nullptr; diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 654e5b7c03..8d0eb590bf 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -169,11 +169,6 @@ static bool should_unload_system_driver(egl_connection_t* cnx) { } } - // Return true if native GLES drivers should be used and ANGLE is already loaded. - if (android::GraphicsEnv::getInstance().shouldUseNativeDriver() && cnx->angleLoaded) { - return true; - } - // Return true if updated driver namespace is set. ns = android::GraphicsEnv::getInstance().getDriverNamespace(); if (ns) { @@ -245,28 +240,16 @@ void* Loader::open(egl_connection_t* cnx) { if (!hnd) { // Secondly, try to load from driver apk. hnd = attempt_to_load_updated_driver(cnx); - - // If updated driver apk is set but fail to load, abort here. - LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace(), - "couldn't find an OpenGL ES implementation from %s", - android::GraphicsEnv::getInstance().getDriverPath().c_str()); } - // Attempt to load native GLES drivers specified by ro.hardware.egl if native is selected. - // If native is selected but fail to load, abort. - if (!hnd && android::GraphicsEnv::getInstance().shouldUseNativeDriver()) { - auto driverSuffix = base::GetProperty(RO_DRIVER_SUFFIX_PROPERTY, ""); - LOG_ALWAYS_FATAL_IF(driverSuffix.empty(), - "Native GLES driver is selected but not specified in %s", - RO_DRIVER_SUFFIX_PROPERTY); - hnd = attempt_to_load_system_driver(cnx, driverSuffix.c_str(), true); - LOG_ALWAYS_FATAL_IF(!hnd, "Native GLES driver is selected but failed to load. %s=%s", - RO_DRIVER_SUFFIX_PROPERTY, driverSuffix.c_str()); - } - - // Finally, try to load default driver. bool failToLoadFromDriverSuffixProperty = false; if (!hnd) { + // If updated driver apk is set but fail to load, abort here. + if (android::GraphicsEnv::getInstance().getDriverNamespace()) { + LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s", + android::GraphicsEnv::getInstance().getDriverPath().c_str()); + } + // Finally, try to load system driver. // Start by searching for the library name appended by the system // properties of the GLES userspace driver in both locations. // i.e.: -- GitLab From ce0eb13cb6fceb7190e68a7dcea9771d68e09df2 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Thu, 5 Oct 2023 15:26:37 -0700 Subject: [PATCH 0843/1187] [sf] Stop inheriting from std::unary_function std::unary_function was deprecated in C++11 and removed in C++17. Its function is to provide two typedefs, `argument_type` and `result_type`, but these are not needed for std::find_if's Predicate, so stop using std::unary_function. Bug: 175635923 Test: m MODULES-IN-frameworks-native Change-Id: Ie16ada6f76bee7d9f248dc8349a095b50777c92d Merged-In: Ie16ada6f76bee7d9f248dc8349a095b50777c92d --- .../surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp index 2b295309e7..0b2e5a3c9d 100644 --- a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp +++ b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp @@ -118,7 +118,7 @@ inline void PrintTo(const LayerInfo& info, ::std::ostream* os) { << info.touchableRegionBounds.right << "," << info.touchableRegionBounds.bottom << "}"; } -struct find_id : std::unary_function { +struct find_id { int id; find_id(int id) : id(id) {} bool operator()(LayerInfo const& m) const { return m.id == id; } -- GitLab From 346f104bd866baeace03cc87a9329f315698291e Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Mon, 9 Oct 2023 17:02:46 +0000 Subject: [PATCH 0844/1187] Binder: abstract report_sysprop_change to OS layer Bug: 302723053 Test: mma Change-Id: Ia479cbf435eeba108cf21e6adddf2d1034174019 --- libs/binder/Binder.cpp | 3 ++- libs/binder/OS.h | 2 ++ libs/binder/OS_android.cpp | 6 ++++++ libs/binder/trusty/kernel/rules.mk | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index 9f091ef756..f22e90a03f 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -40,6 +40,7 @@ #endif #include "BuildFlags.h" +#include "OS.h" #include "RpcState.h" namespace android { @@ -795,7 +796,7 @@ status_t BBinder::onTransact( } case SYSPROPS_TRANSACTION: { - report_sysprop_change(); + if (!binder::os::report_sysprop_change()) return INVALID_OPERATION; return NO_ERROR; } diff --git a/libs/binder/OS.h b/libs/binder/OS.h index db4b7a5379..8dc1f6ae70 100644 --- a/libs/binder/OS.h +++ b/libs/binder/OS.h @@ -43,4 +43,6 @@ ssize_t receiveMessageFromSocket( uint64_t GetThreadId(); +bool report_sysprop_change(); + } // namespace android::binder::os diff --git a/libs/binder/OS_android.cpp b/libs/binder/OS_android.cpp index 1e1442b7c0..ad458eb705 100644 --- a/libs/binder/OS_android.cpp +++ b/libs/binder/OS_android.cpp @@ -17,6 +17,7 @@ #include "OS.h" #include +#include namespace android::binder::os { @@ -28,4 +29,9 @@ uint64_t GetThreadId() { #endif } +bool report_sysprop_change() { + android::report_sysprop_change(); + return true; +} + } // namespace android::binder::os diff --git a/libs/binder/trusty/kernel/rules.mk b/libs/binder/trusty/kernel/rules.mk index f6e894c064..1f05ef757a 100644 --- a/libs/binder/trusty/kernel/rules.mk +++ b/libs/binder/trusty/kernel/rules.mk @@ -31,6 +31,7 @@ MODULE_SRCS := \ $(LIBBINDER_DIR)/FdTrigger.cpp \ $(LIBBINDER_DIR)/IInterface.cpp \ $(LIBBINDER_DIR)/IResultReceiver.cpp \ + $(LIBBINDER_DIR)/OS_android.cpp \ $(LIBBINDER_DIR)/Parcel.cpp \ $(LIBBINDER_DIR)/Stability.cpp \ $(LIBBINDER_DIR)/Status.cpp \ -- GitLab From c69068fe0eb9784134815d4d83440399f7ac73b3 Mon Sep 17 00:00:00 2001 From: ramindani Date: Mon, 16 Oct 2023 15:37:14 -0700 Subject: [PATCH 0845/1187] Enable vrr_config flag for RefreshRateSelectorTest BUG: 284845445 Test: atest RefreshRateSelectorTest Change-Id: I0271f935ed5c9a8ac544a34d4f4b74452e556d61 --- .../tests/unittests/RefreshRateSelectorTest.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index faa12a1032..f816b645ff 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -34,6 +34,7 @@ #include "mock/DisplayHardware/MockDisplayMode.h" #include "mock/MockFrameRateMode.h" +#include "FlagUtils.h" #include "libsurfaceflinger_unittest_main.h" #include @@ -1610,6 +1611,7 @@ TEST_P(RefreshRateSelectorTest, return; } + SET_FLAG_FOR_TEST(flags::vrr_config, true); // VRR compatibility is determined by the presence of a vrr config in the DisplayMode. auto selector = createSelector(kVrrModes_60_120, kModeId120); @@ -3486,10 +3488,11 @@ TEST_P(RefreshRateSelectorTest, frameRateOverrideInBlockingZone60_90_NonDivisor) // VRR tests TEST_P(RefreshRateSelectorTest, singleMinMaxRateForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { + if (GetParam() != Config::FrameRateOverride::Enabled) { return; } + SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrMode_120, kModeId120); EXPECT_TRUE(selector.supportsFrameRateOverride()); @@ -3505,10 +3508,11 @@ TEST_P(RefreshRateSelectorTest, singleMinMaxRateForVrr) { } TEST_P(RefreshRateSelectorTest, renderRateChangesWithPolicyChangeForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { + if (GetParam() != Config::FrameRateOverride::Enabled) { return; } + SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrModes_60_120, kModeId120); const FpsRange only120 = {120_Hz, 120_Hz}; @@ -3562,10 +3566,11 @@ TEST_P(RefreshRateSelectorTest, renderRateChangesWithPolicyChangeForVrr) { } TEST_P(RefreshRateSelectorTest, modeChangesWithPolicyChangeForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { + if (GetParam() != Config::FrameRateOverride::Enabled) { return; } + SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrModes_60_120, kModeId120); const FpsRange range120 = {0_Hz, 120_Hz}; @@ -3585,10 +3590,11 @@ TEST_P(RefreshRateSelectorTest, modeChangesWithPolicyChangeForVrr) { } TEST_P(RefreshRateSelectorTest, getFrameRateOverridesForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { + if (GetParam() != Config::FrameRateOverride::Enabled) { return; } + SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrMode_120, kModeId120); // TODO(b/297600226) Run at lower than 30 Fps for dVRR const std::vector desiredRefreshRates = {30_Hz, 34.285_Hz, 40_Hz, 48_Hz, @@ -3614,10 +3620,11 @@ TEST_P(RefreshRateSelectorTest, getFrameRateOverridesForVrr) { } TEST_P(RefreshRateSelectorTest, renderFrameRatesForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { + if (GetParam() != Config::FrameRateOverride::Enabled) { return; } + SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrMode_120, kModeId120); const FpsRange only120 = {120_Hz, 120_Hz}; const FpsRange range120 = {0_Hz, 120_Hz}; -- GitLab From 8134c1a5c8fc053978cb39f373ce9d62f365ff72 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 17 Oct 2023 22:55:49 -0700 Subject: [PATCH 0846/1187] Avoid clearing transaction flags too early Transaction flags were cleared in commitTransactions before checking if we needed to run the composite stage. This caused us to miss some updates. In addition, display color matrix is only updated if the colorMatrixChanged is set so, if we miss an update device would be in an invalid state until the next update. Fixes: 300194609 Test: presubmit Change-Id: Ie397d4c37af6b54ff8d59e1151ddee24811e2d13 --- services/surfaceflinger/SurfaceFlinger.cpp | 6 +- services/surfaceflinger/SurfaceFlinger.h | 2 + .../surfaceflinger/tests/unittests/Android.bp | 1 + .../tests/unittests/CommitTest.cpp | 59 +++++++++++++++++++ .../tests/unittests/TestableSurfaceFlinger.h | 9 +++ 5 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 services/surfaceflinger/tests/unittests/CommitTest.cpp diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e08690a2bb..3d08574bda 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2401,8 +2401,6 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, mLayerLifecycleManager.commitChanges(); } - commitTransactions(); - // enter boot animation on first buffer latch if (CC_UNLIKELY(mBootStage == BootStage::BOOTLOADER && newDataLatched)) { ALOGI("Enter boot animation"); @@ -2410,6 +2408,10 @@ bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, } } mustComposite |= (getTransactionFlags() & ~eTransactionFlushNeeded) || newDataLatched; + if (mustComposite && !mLegacyFrontEndEnabled) { + commitTransactions(); + } + return mustComposite; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index cbea31239a..9c3c935c4c 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -728,8 +728,10 @@ private: compositionengine::CompositionRefreshArgs& refreshArgs, bool cursorOnly); void moveSnapshotsFromCompositionArgs(compositionengine::CompositionRefreshArgs& refreshArgs, const std::vector>& layers); + // Return true if we must composite this frame bool updateLayerSnapshotsLegacy(VsyncId vsyncId, nsecs_t frameTimeNs, bool transactionsFlushed, bool& out) REQUIRES(kMainThreadContext); + // Return true if we must composite this frame bool updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, bool transactionsFlushed, bool& out) REQUIRES(kMainThreadContext); void updateLayerHistory(nsecs_t now); diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index ec21eaf488..5a3bca115b 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -63,6 +63,7 @@ cc_test { "libsurfaceflinger_unittest_main.cpp", "ActiveDisplayRotationFlagsTest.cpp", "BackgroundExecutorTest.cpp", + "CommitTest.cpp", "CompositionTest.cpp", "DisplayIdGeneratorTest.cpp", "DisplayTransactionTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/CommitTest.cpp b/services/surfaceflinger/tests/unittests/CommitTest.cpp new file mode 100644 index 0000000000..df53d1988d --- /dev/null +++ b/services/surfaceflinger/tests/unittests/CommitTest.cpp @@ -0,0 +1,59 @@ +/* + * Copyright 2023 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. + */ + +#undef LOG_TAG +#define LOG_TAG "CommitTest" + +#include +#include + +#include +#include "TestableSurfaceFlinger.h" + +namespace android { + +class CommitTest : public testing::Test { +protected: + CommitTest() { + mFlinger.setupMockScheduler(); + mFlinger.setupComposer(std::make_unique()); + mFlinger.setupRenderEngine(std::unique_ptr(mRenderEngine)); + } + TestableSurfaceFlinger mFlinger; + renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); +}; + +namespace { + +TEST_F(CommitTest, noUpdatesDoesNotScheduleComposite) { + bool unused; + bool mustComposite = mFlinger.updateLayerSnapshots(VsyncId{1}, /*frameTimeNs=*/0, + /*transactionsFlushed=*/0, unused); + EXPECT_FALSE(mustComposite); +} + +// Ensure that we handle eTransactionNeeded correctly +TEST_F(CommitTest, eTransactionNeededFlagSchedulesComposite) { + // update display level color matrix + mFlinger.setDaltonizerType(ColorBlindnessType::Deuteranomaly); + bool unused; + bool mustComposite = mFlinger.updateLayerSnapshots(VsyncId{1}, /*frameTimeNs=*/0, + /*transactionsFlushed=*/0, unused); + EXPECT_TRUE(mustComposite); +} + +} // namespace +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index b54392e651..3b3942012f 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -611,6 +611,15 @@ public: void releaseLegacyLayer(uint32_t sequence) { mFlinger->mLegacyLayers.erase(sequence); }; auto updateLayerHistory(nsecs_t now) { return mFlinger->updateLayerHistory(now); }; + auto setDaltonizerType(ColorBlindnessType type) { + mFlinger->mDaltonizer.setType(type); + return mFlinger->updateColorMatrixLocked(); + } + auto updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, bool transactionsFlushed, + bool& out) { + ftl::FakeGuard guard(kMainThreadContext); + return mFlinger->updateLayerSnapshots(vsyncId, frameTimeNs, transactionsFlushed, out); + } /* ------------------------------------------------------------------------ * Read-write access to private data to set up preconditions and assert * post-conditions. -- GitLab From 18efdb7009cd65011180827c353ccc799ece61d1 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Wed, 18 Oct 2023 08:29:54 +0000 Subject: [PATCH 0847/1187] TFLite: Accommodate change in std::span size type The WIP version of std::span in external/libcxx uses a ptrdiff_t size, but the finalized C++20 std::span uses a size_t size instead. Comparing the size_t size() against a signed integer causes a -Werror,-Wsign-compare build error. Cast the size() expression so that the code compiles with both the old and the new libc++. Bug: 175635923 Test: m MODULES-IN-frameworks-native (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a119a69b066f7bb03d51665a35bef17cecacbe95) Merged-In: I50cc5354b6205b62918157b69df6cf1aa7bad6cc Change-Id: I50cc5354b6205b62918157b69df6cf1aa7bad6cc --- .../tests/TfLiteMotionPredictor_test.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libs/input/tests/TfLiteMotionPredictor_test.cpp b/libs/input/tests/TfLiteMotionPredictor_test.cpp index b5ed9e4430..c3ac0b7cfb 100644 --- a/libs/input/tests/TfLiteMotionPredictor_test.cpp +++ b/libs/input/tests/TfLiteMotionPredictor_test.cpp @@ -130,19 +130,19 @@ TEST(TfLiteMotionPredictorTest, ModelInputOutputLength) { std::unique_ptr model = TfLiteMotionPredictorModel::create(); ASSERT_GT(model->inputLength(), 0u); - const int inputLength = model->inputLength(); - ASSERT_EQ(inputLength, model->inputR().size()); - ASSERT_EQ(inputLength, model->inputPhi().size()); - ASSERT_EQ(inputLength, model->inputPressure().size()); - ASSERT_EQ(inputLength, model->inputOrientation().size()); - ASSERT_EQ(inputLength, model->inputTilt().size()); + const size_t inputLength = model->inputLength(); + ASSERT_EQ(inputLength, static_cast(model->inputR().size())); + ASSERT_EQ(inputLength, static_cast(model->inputPhi().size())); + ASSERT_EQ(inputLength, static_cast(model->inputPressure().size())); + ASSERT_EQ(inputLength, static_cast(model->inputOrientation().size())); + ASSERT_EQ(inputLength, static_cast(model->inputTilt().size())); ASSERT_TRUE(model->invoke()); - const int outputLength = model->outputLength(); - ASSERT_EQ(outputLength, model->outputR().size()); - ASSERT_EQ(outputLength, model->outputPhi().size()); - ASSERT_EQ(outputLength, model->outputPressure().size()); + const size_t outputLength = model->outputLength(); + ASSERT_EQ(outputLength, static_cast(model->outputR().size())); + ASSERT_EQ(outputLength, static_cast(model->outputPhi().size())); + ASSERT_EQ(outputLength, static_cast(model->outputPressure().size())); } TEST(TfLiteMotionPredictorTest, ModelOutput) { -- GitLab From 5260e525830c7bbd67511d5f8e83a59042890f24 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Wed, 18 Oct 2023 08:35:03 +0000 Subject: [PATCH 0848/1187] [sf] HdrOutputControlTest: fix strategy arguments The code was previously passing an aidl::[...]::common::HdrConversionStrategy* argument to gui::ISurfaceComposer::setHdrConversionStrategy, which accepts a const gui::HdrConversionStrategy& parameter. Converting between these two kinds of HdrConversionStrategy is laborious -- see SurfaceFlinger::setHdrConversionStrategy. This code was previously avoiding the conversion difficulty by passing a pointer to HdrConversionStrategy, which is wrong because the function actually accepts a const reference. It worked, though, because gui::HdrConversionStrategy's _value has type: std::variant, int32_t> ... and aidl::[...]::common::HdrConversionStrategy* can be coerced to bool. The pointer is always non-nullptr, so each sf->setHdrConversionStrategy was actually passing a {passthrough==true} strategy. The C++ standard tightened the rules around variant conversion (P0608R3, P1957R2), and after upgrading libc++, this code no longer compiles. Fix the compile error by using gui::HdrConversionStrategy for the type of the strategy vector elements. Bug: 175635923 Test: m MODULES-IN-frameworks-native-services-surfaceflinger (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:0dfa358c79fc8047dd622d82020c37559871c8e7) Merged-In: I820ac945113da0317d0eaa44f581fd6ab1b61645 Change-Id: I820ac945113da0317d0eaa44f581fd6ab1b61645 --- .../SurfaceFlinger_HdrOutputControlTest.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp index a2c54ac621..db6df229d5 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HdrOutputControlTest.cpp @@ -26,8 +26,6 @@ namespace android { -using aidl::android::hardware::graphics::common::HdrConversionCapability; -using aidl::android::hardware::graphics::common::HdrConversionStrategy; using GuiHdrConversionStrategyTag = gui::HdrConversionStrategy::Tag; using gui::aidl_utils::statusTFromBinderStatus; @@ -66,17 +64,15 @@ TEST(HdrOutputControlTest, testSetHdrConversionStrategy) { sf->getHdrOutputConversionSupport(&hdrOutputConversionSupport); ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(getSupportStatus)); - std::vector strategies = - {HdrConversionStrategy(std::in_place_index( - GuiHdrConversionStrategyTag::passthrough)>), - HdrConversionStrategy(std::in_place_index( - GuiHdrConversionStrategyTag::autoAllowedHdrTypes)>), - HdrConversionStrategy(std::in_place_index( - GuiHdrConversionStrategyTag::forceHdrConversion)>)}; + std::vector strategies = { + gui::HdrConversionStrategy::make(), + gui::HdrConversionStrategy::make(), + gui::HdrConversionStrategy::make(), + }; int32_t outPreferredHdrOutputType = 0; - for (HdrConversionStrategy strategy : strategies) { - binder::Status status = sf->setHdrConversionStrategy(&strategy, &outPreferredHdrOutputType); + for (const gui::HdrConversionStrategy& strategy : strategies) { + binder::Status status = sf->setHdrConversionStrategy(strategy, &outPreferredHdrOutputType); if (hdrOutputConversionSupport) { ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); -- GitLab From 4b92c98dc7f50eb3e8a891529186dde17213a67a Mon Sep 17 00:00:00 2001 From: Steven Ng Date: Wed, 18 Oct 2023 08:32:58 +0000 Subject: [PATCH 0849/1187] Revert "Enable vrr_config flag for RefreshRateSelectorTest" This reverts commit c69068fe0eb9784134815d4d83440399f7ac73b3. Reason for revert: Droid TestMonitor revert because this is a suspected culprit for b/306058275 Change-Id: Ia0d1523c0af4200acad923449d37bed249d0bb28 --- .../tests/unittests/RefreshRateSelectorTest.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp index f816b645ff..faa12a1032 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp @@ -34,7 +34,6 @@ #include "mock/DisplayHardware/MockDisplayMode.h" #include "mock/MockFrameRateMode.h" -#include "FlagUtils.h" #include "libsurfaceflinger_unittest_main.h" #include @@ -1611,7 +1610,6 @@ TEST_P(RefreshRateSelectorTest, return; } - SET_FLAG_FOR_TEST(flags::vrr_config, true); // VRR compatibility is determined by the presence of a vrr config in the DisplayMode. auto selector = createSelector(kVrrModes_60_120, kModeId120); @@ -3488,11 +3486,10 @@ TEST_P(RefreshRateSelectorTest, frameRateOverrideInBlockingZone60_90_NonDivisor) // VRR tests TEST_P(RefreshRateSelectorTest, singleMinMaxRateForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled) { + if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { return; } - SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrMode_120, kModeId120); EXPECT_TRUE(selector.supportsFrameRateOverride()); @@ -3508,11 +3505,10 @@ TEST_P(RefreshRateSelectorTest, singleMinMaxRateForVrr) { } TEST_P(RefreshRateSelectorTest, renderRateChangesWithPolicyChangeForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled) { + if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { return; } - SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrModes_60_120, kModeId120); const FpsRange only120 = {120_Hz, 120_Hz}; @@ -3566,11 +3562,10 @@ TEST_P(RefreshRateSelectorTest, renderRateChangesWithPolicyChangeForVrr) { } TEST_P(RefreshRateSelectorTest, modeChangesWithPolicyChangeForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled) { + if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { return; } - SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrModes_60_120, kModeId120); const FpsRange range120 = {0_Hz, 120_Hz}; @@ -3590,11 +3585,10 @@ TEST_P(RefreshRateSelectorTest, modeChangesWithPolicyChangeForVrr) { } TEST_P(RefreshRateSelectorTest, getFrameRateOverridesForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled) { + if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { return; } - SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrMode_120, kModeId120); // TODO(b/297600226) Run at lower than 30 Fps for dVRR const std::vector desiredRefreshRates = {30_Hz, 34.285_Hz, 40_Hz, 48_Hz, @@ -3620,11 +3614,10 @@ TEST_P(RefreshRateSelectorTest, getFrameRateOverridesForVrr) { } TEST_P(RefreshRateSelectorTest, renderFrameRatesForVrr) { - if (GetParam() != Config::FrameRateOverride::Enabled) { + if (GetParam() != Config::FrameRateOverride::Enabled || !flags::vrr_config()) { return; } - SET_FLAG_FOR_TEST(flags::vrr_config, true); auto selector = createSelector(kVrrMode_120, kModeId120); const FpsRange only120 = {120_Hz, 120_Hz}; const FpsRange range120 = {0_Hz, 120_Hz}; -- GitLab From 96bd21c3f800eed4fff8e5aaf230be42f29eb928 Mon Sep 17 00:00:00 2001 From: Rajesh Nyamagoud Date: Wed, 18 Oct 2023 15:44:12 +0000 Subject: [PATCH 0850/1187] Removing `device_id_attestation` from exclude feature list of AOSP targets. AOSP builds can support ID attestation - aosp/2237500 Bug: 110779648 Test: atest keystore2_client_tests; atest CtsKeystoreTestCases:android.keystore.cts.KeyAttestationTest CtsKeystoreTestCases:DeviceOwnerKeyManagementTest Change-Id: I14fc73e5e169f6161c85a6fd1f8b40f9cc975de2 --- data/etc/aosp_excluded_hardware.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/data/etc/aosp_excluded_hardware.xml b/data/etc/aosp_excluded_hardware.xml index c12f4358c5..013f278f34 100644 --- a/data/etc/aosp_excluded_hardware.xml +++ b/data/etc/aosp_excluded_hardware.xml @@ -18,5 +18,4 @@ - -- GitLab From dcc6e6ede741905fa2ec2ff91722f85d3979276c Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 18 Oct 2023 09:20:07 -0700 Subject: [PATCH 0851/1187] Change isStylusEvent behaviour This function is now getting moved to Input.h. We are also making its behaviour deterministic: if at least one pointer is stylus, then the event is a stylus event (unless the source wasn't set to "stylus"). This way, an event with 1 finger and 1 stylus pointers will have the same consistent behaviour, regardless of the order that the pointers are stored inside the event. Bug: 211379801 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: Ie164e32b7c0e9cf21b3819b01a03ac2885666191 --- include/input/Input.h | 4 +++ libs/input/Input.cpp | 13 ++++++++++ .../reader/mapper/TouchInputMapper.cpp | 26 +++++++------------ 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/include/input/Input.h b/include/input/Input.h index 567361d679..bd544b5264 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -257,6 +257,10 @@ enum class KeyState { bool isStylusToolType(ToolType toolType); +struct PointerProperties; + +bool isStylusEvent(uint32_t source, const std::vector& properties); + /* * Flags that flow alongside events in the input dispatch system to help with certain * policy decisions such as waking from device sleep. diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index c1274110d3..bd5b67b1d0 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -217,6 +217,19 @@ bool isStylusToolType(ToolType toolType) { return toolType == ToolType::STYLUS || toolType == ToolType::ERASER; } +bool isStylusEvent(uint32_t source, const std::vector& properties) { + if (!isFromSource(source, AINPUT_SOURCE_STYLUS)) { + return false; + } + // Need at least one stylus pointer for this event to be considered a stylus event + for (const PointerProperties& pointerProperties : properties) { + if (isStylusToolType(pointerProperties.toolType)) { + return true; + } + } + return false; +} + VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) { return {{VerifiedInputEvent::Type::KEY, event.getDeviceId(), event.getEventTime(), event.getSource(), event.getDisplayId()}, diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 90bd7c9c74..3c26d1d73e 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -3782,34 +3782,26 @@ std::list TouchInputMapper::abortPointerSimple(nsecs_t when, nsecs_t return out; } -static bool isStylusEvent(uint32_t source, int32_t action, const PointerProperties* properties) { - if (!isFromSource(source, AINPUT_SOURCE_STYLUS)) { - return false; - } - const auto actionIndex = action >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - return isStylusToolType(properties[actionIndex].toolType); -} - NotifyMotionArgs TouchInputMapper::dispatchMotion( nsecs_t when, nsecs_t readTime, uint32_t policyFlags, uint32_t source, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PropertiesArray& properties, const CoordsArray& coords, const IdToIndexArray& idToIndex, BitSet32 idBits, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime, MotionClassification classification) { - PointerCoords pointerCoords[MAX_POINTERS]; - PointerProperties pointerProperties[MAX_POINTERS]; + std::vector pointerCoords; + std::vector pointerProperties; uint32_t pointerCount = 0; while (!idBits.isEmpty()) { uint32_t id = idBits.clearFirstMarkedBit(); uint32_t index = idToIndex[id]; - pointerProperties[pointerCount] = properties[index]; - pointerCoords[pointerCount] = coords[index]; + pointerProperties.push_back(properties[index]); + pointerCoords.push_back(coords[index]); if (changedId >= 0 && id == uint32_t(changedId)) { action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } - pointerCount += 1; + pointerCount++; } ALOG_ASSERT(pointerCount != 0); @@ -3837,7 +3829,7 @@ NotifyMotionArgs TouchInputMapper::dispatchMotion( const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE); const bool showDirectStylusPointer = mConfig.stylusPointerIconEnabled && - mDeviceMode == DeviceMode::DIRECT && isStylusEvent(source, action, pointerProperties) && + mDeviceMode == DeviceMode::DIRECT && isStylusEvent(source, pointerProperties) && mPointerController && displayId != ADISPLAY_ID_NONE && displayId == mPointerController->getDisplayId(); if (showDirectStylusPointer) { @@ -3869,9 +3861,9 @@ NotifyMotionArgs TouchInputMapper::dispatchMotion( [this](TouchVideoFrame& frame) { frame.rotate(this->mInputDeviceOrientation); }); return NotifyMotionArgs(getContext()->getNextId(), when, readTime, deviceId, source, displayId, policyFlags, action, actionButton, flags, metaState, buttonState, - classification, edgeFlags, pointerCount, pointerProperties, - pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition, - downTime, std::move(frames)); + classification, edgeFlags, pointerCount, pointerProperties.data(), + pointerCoords.data(), xPrecision, yPrecision, xCursorPosition, + yCursorPosition, downTime, std::move(frames)); } std::list TouchInputMapper::cancelTouch(nsecs_t when, nsecs_t readTime) { -- GitLab From ad1b27ce5a5b38e43f541283681da845d058160f Mon Sep 17 00:00:00 2001 From: Charisee Chiw Date: Thu, 12 Oct 2023 16:02:39 -0700 Subject: [PATCH 0852/1187] Update needed for Rust v1.73.0 error: incorrect implementation of `partial_cmp` on an `Ord` type --> frameworks/native/libs/binder/rust/src/binder.rs:437:1 | 437 | / impl PartialOrd for Strong { 438 | | fn partial_cmp(&self, other: &Self) -> Option { | | _____________________________________________________________- 439 | || self.0.as_binder().partial_cmp(&other.0.as_binder()) 440 | || } | ||_____- help: change this to: `{ Some(self.cmp(other)) }` 441 | | } | |__^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#incorrect_partial_ord_impl_on_ord_type = note: `#[deny(clippy::incorrect_partial_ord_impl_on_ord_type)]` on by default Bug: 303252546 Test: ./test_compiler.py --prebuilt-path dist/rust-dev.tar.xz --target aosp_cf_x86_64_phone --image Change-Id: Ied87ef07475b0ed8e430b622be68b211d58ef89f --- libs/binder/rust/src/binder.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 463c210316..a08cb7ab39 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -436,7 +436,7 @@ impl Ord for Strong { impl PartialOrd for Strong { fn partial_cmp(&self, other: &Self) -> Option { - self.0.as_binder().partial_cmp(&other.0.as_binder()) + Some(self.cmp(other)) } } @@ -483,7 +483,7 @@ impl Ord for Weak { impl PartialOrd for Weak { fn partial_cmp(&self, other: &Self) -> Option { - self.weak_binder.partial_cmp(&other.weak_binder) + Some(self.cmp(other)) } } -- GitLab From 0db92f1464cffe5a3ef8c7c9e548cbfb9ee63348 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Wed, 18 Oct 2023 12:02:06 -0500 Subject: [PATCH 0853/1187] Fix RequestedLayerState logging for out of order buffers Bug: 302249537 Test: presubmits Change-Id: I2bedc3cda9c0c5385027deac2a3efebf667a1fac --- services/surfaceflinger/FrontEnd/RequestedLayerState.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index ce845d9fdf..0e49b754f5 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -209,7 +209,7 @@ void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerSta (barrierFrameNumber > bufferData->frameNumber))) { ALOGE("Out of order buffers detected for %s producedId=%d frameNumber=%" PRIu64 " -> producedId=%d frameNumber=%" PRIu64, - getDebugString().c_str(), bufferData->producerId, bufferData->frameNumber, + getDebugString().c_str(), barrierProducerId, barrierFrameNumber, bufferData->producerId, frameNumber); TransactionTraceWriter::getInstance().invoke("out_of_order_buffers_", /*overwrite=*/false); @@ -401,6 +401,7 @@ std::string RequestedLayerState::getDebugString() const { if (!handleAlive) debug << " !handle"; if (z != 0) debug << " z=" << z; if (layerStack.id != 0) debug << " layerStack=" << layerStack.id; + debug << "}"; return debug.str(); } -- GitLab From 47a02a18a66f42daca79669e1e6d49481be0d03a Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 18 Oct 2023 09:56:00 -0700 Subject: [PATCH 0854/1187] Use std::vector for pointers in InputState This simplifies calls to other APIs, because we can now pass the vector by ref instead of having to separately store the pointerCount. Bug: 211379801 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: I0f8af524afe99fee93b937890754d9676f8af5e7 --- .../inputflinger/dispatcher/InputState.cpp | 41 +++++++++++-------- services/inputflinger/dispatcher/InputState.h | 6 +-- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index b21427dad8..57a6336d9a 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -235,7 +235,9 @@ void InputState::addMotionMemento(const MotionEntry& entry, int32_t flags, bool } void InputState::MotionMemento::setPointers(const MotionEntry& entry) { - pointerCount = 0; + pointerProperties.clear(); + pointerCoords.clear(); + for (uint32_t i = 0; i < entry.pointerCount; i++) { if (MotionEvent::getActionMasked(entry.action) == AMOTION_EVENT_ACTION_POINTER_UP) { // In POINTER_UP events, the pointer is leaving. Since the action is not stored, @@ -245,23 +247,25 @@ void InputState::MotionMemento::setPointers(const MotionEntry& entry) { continue; } } - pointerProperties[pointerCount] = entry.pointerProperties[i]; - pointerCoords[pointerCount] = entry.pointerCoords[i]; - pointerCount++; + pointerProperties.push_back(entry.pointerProperties[i]); + pointerCoords.push_back(entry.pointerCoords[i]); } } void InputState::MotionMemento::mergePointerStateTo(MotionMemento& other) const { - for (uint32_t i = 0; i < pointerCount; i++) { + for (uint32_t i = 0; i < getPointerCount(); i++) { if (other.firstNewPointerIdx < 0) { - other.firstNewPointerIdx = other.pointerCount; + other.firstNewPointerIdx = other.getPointerCount(); } - other.pointerProperties[other.pointerCount] = pointerProperties[i]; - other.pointerCoords[other.pointerCount] = pointerCoords[i]; - other.pointerCount++; + other.pointerProperties.push_back(pointerProperties[i]); + other.pointerCoords.push_back(pointerCoords[i]); } } +size_t InputState::MotionMemento::getPointerCount() const { + return pointerProperties.size(); +} + std::vector> InputState::synthesizeCancelationEvents( nsecs_t currentTime, const CancelationOptions& options) { std::vector> events; @@ -296,9 +300,9 @@ std::vector> InputState::synthesizeCancelationEvents memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - memento.pointerCount, - memento.pointerProperties, - memento.pointerCoords)); + memento.getPointerCount(), + memento.pointerProperties.data(), + memento.pointerCoords.data())); } else { std::vector> pointerCancelEvents = synthesizeCancelationEventsForPointers(memento, options.pointerIds.value(), @@ -336,7 +340,7 @@ std::vector> InputState::synthesizePointerDownEvents // We will send explicit events for all pointers the target doesn't know about for (uint32_t i = static_cast(memento.firstNewPointerIdx); - i < memento.pointerCount; i++) { + i < memento.getPointerCount(); i++) { pointerProperties[i] = memento.pointerProperties[i]; pointerCoords[i] = memento.pointerCoords[i]; pointerCount++; @@ -372,7 +376,7 @@ std::vector> InputState::synthesizeCancelationEvent std::vector canceledPointerIndices; std::vector pointerProperties(MAX_POINTERS); std::vector pointerCoords(MAX_POINTERS); - for (uint32_t pointerIdx = 0; pointerIdx < memento.pointerCount; pointerIdx++) { + for (uint32_t pointerIdx = 0; pointerIdx < memento.getPointerCount(); pointerIdx++) { uint32_t pointerId = uint32_t(memento.pointerProperties[pointerIdx].id); pointerProperties[pointerIdx] = memento.pointerProperties[pointerIdx]; pointerCoords[pointerIdx] = memento.pointerCoords[pointerIdx]; @@ -381,7 +385,7 @@ std::vector> InputState::synthesizeCancelationEvent } } - if (canceledPointerIndices.size() == memento.pointerCount) { + if (canceledPointerIndices.size() == memento.getPointerCount()) { const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL; int32_t flags = memento.flags; @@ -397,8 +401,9 @@ std::vector> InputState::synthesizeCancelationEvent AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - memento.pointerCount, memento.pointerProperties, - memento.pointerCoords)); + memento.getPointerCount(), + memento.pointerProperties.data(), + memento.pointerCoords.data())); } else { // If we aren't canceling all pointers, we need to generate ACTION_POINTER_UP with // FLAG_CANCELED for each of the canceled pointers. For each event, we must remove the @@ -409,7 +414,7 @@ std::vector> InputState::synthesizeCancelationEvent std::sort(canceledPointerIndices.begin(), canceledPointerIndices.end(), std::greater()); - uint32_t pointerCount = memento.pointerCount; + uint32_t pointerCount = memento.getPointerCount(); for (const uint32_t pointerIdx : canceledPointerIndices) { const int32_t action = pointerCount == 1 ? AMOTION_EVENT_ACTION_CANCEL : AMOTION_EVENT_ACTION_POINTER_UP | diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h index 32df034f67..3adbba0902 100644 --- a/services/inputflinger/dispatcher/InputState.h +++ b/services/inputflinger/dispatcher/InputState.h @@ -97,9 +97,8 @@ private: float xCursorPosition; float yCursorPosition; nsecs_t downTime; - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; + std::vector pointerProperties; + std::vector pointerCoords; // Track for which pointers the target doesn't know about. int32_t firstNewPointerIdx = INVALID_POINTER_INDEX; bool hovering; @@ -107,6 +106,7 @@ private: void setPointers(const MotionEntry& entry); void mergePointerStateTo(MotionMemento& other) const; + size_t getPointerCount() const; }; const IdGenerator& mIdGenerator; // InputDispatcher owns it so we won't have dangling reference. -- GitLab From 6d34bbb15029de797f65362ddf5aa2063766eb84 Mon Sep 17 00:00:00 2001 From: Mark Wheatley Date: Wed, 18 Oct 2023 18:54:26 +0000 Subject: [PATCH 0855/1187] Initialize mInHalBypassMode to false Initialize mInHalBypassMode to false in the SensorDevice constructor. This was uninitialized and was causing issues where SensorService was waiting for injected sensor data as if it was in hal bypass mode instead of passing up real sensor data to the platform. Bug: 306117477 Bug: 306092529 Test: manual Change-Id: I89b5ed8a9be65020fb70ce39f692e7e400851fb3 --- services/sensorservice/SensorDevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index c86022e748..dd83fdefc3 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -67,7 +67,7 @@ enum DevicePrivateBase : int32_t { } // anonymous namespace -SensorDevice::SensorDevice() { +SensorDevice::SensorDevice() : mInHalBypassMode(false) { if (!connectHalService()) { return; } -- GitLab From edd6120f08d29c92cf3cf7ad9ccb3858867f6038 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 18 Oct 2023 11:22:40 -0700 Subject: [PATCH 0856/1187] Store pointers in vector inside MotionEntry For better support of arbitrary number of pointers, and for easier interfacing with the rest of the system, convert MotionEntry to use std::vector for PointerCoords and PointerProperties. Bug: 211379801 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: I91b4a88ec5df3f017ade8a6e55be3d3c1281de75 --- services/inputflinger/dispatcher/Entry.cpp | 14 +-- services/inputflinger/dispatcher/Entry.h | 12 ++- .../dispatcher/InputDispatcher.cpp | 94 +++++++++---------- .../inputflinger/dispatcher/InputState.cpp | 33 +++---- 4 files changed, 71 insertions(+), 82 deletions(-) diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index fa8f5485c0..30e68024f9 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -215,8 +215,8 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 int32_t buttonState, MotionClassification classification, int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime, - uint32_t pointerCount, const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords) + const std::vector& pointerProperties, + const std::vector& pointerCoords) : EventEntry(id, Type::MOTION, eventTime, policyFlags), deviceId(deviceId), source(source), @@ -233,12 +233,8 @@ MotionEntry::MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32 xCursorPosition(xCursorPosition), yCursorPosition(yCursorPosition), downTime(downTime), - pointerCount(pointerCount) { - for (uint32_t i = 0; i < pointerCount; i++) { - this->pointerProperties[i] = pointerProperties[i]; - this->pointerCoords[i] = pointerCoords[i]; - } -} + pointerProperties(pointerProperties), + pointerCoords(pointerCoords) {} MotionEntry::~MotionEntry() {} @@ -258,7 +254,7 @@ std::string MotionEntry::getDescription() const { buttonState, motionClassificationToString(classification), edgeFlags, xPrecision, yPrecision, xCursorPosition, yCursorPosition); - for (uint32_t i = 0; i < pointerCount; i++) { + for (uint32_t i = 0; i < getPointerCount(); i++) { if (i) { msg += ", "; } diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 98e2507a94..b341784eda 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -175,16 +175,18 @@ struct MotionEntry : EventEntry { float xCursorPosition; float yCursorPosition; nsecs_t downTime; - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; + std::vector pointerProperties; + std::vector pointerCoords; + + size_t getPointerCount() const { return pointerProperties.size(); } MotionEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification, int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition, - float yCursorPosition, nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); + float yCursorPosition, nsecs_t downTime, + const std::vector& pointerProperties, + const std::vector& pointerCoords); std::string getDescription() const override; ~MotionEntry() override; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index d0a72eee20..45649dd146 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -365,7 +365,7 @@ std::unique_ptr createDispatchEntry( const MotionEntry& motionEntry = static_cast(*eventEntry); std::vector pointerCoords; - pointerCoords.resize(motionEntry.pointerCount); + pointerCoords.resize(motionEntry.getPointerCount()); // Use the first pointer information to normalize all other pointers. This could be any pointer // as long as all other pointers are normalized to the same value and the final DispatchEntry @@ -375,7 +375,7 @@ std::unique_ptr createDispatchEntry( ui::Transform inverseFirstTransform = firstPointerTransform.inverse(); // Iterate through all pointers in the event to normalize against the first. - for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.pointerCount; pointerIndex++) { + for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.getPointerCount(); pointerIndex++) { const PointerProperties& pointerProperties = motionEntry.pointerProperties[pointerIndex]; uint32_t pointerId = uint32_t(pointerProperties.id); const ui::Transform& currTransform = inputTarget.pointerTransforms[pointerId]; @@ -399,8 +399,7 @@ std::unique_ptr createDispatchEntry( motionEntry.edgeFlags, motionEntry.xPrecision, motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, motionEntry.downTime, - motionEntry.pointerCount, motionEntry.pointerProperties, - pointerCoords.data()); + motionEntry.pointerProperties, pointerCoords); if (motionEntry.injectionState) { combinedMotionEntry->injectionState = motionEntry.injectionState; @@ -2000,7 +1999,7 @@ void InputDispatcher::logOutboundMotionDetails(const char* prefix, const MotionE entry.metaState, entry.buttonState, entry.edgeFlags, entry.xPrecision, entry.yPrecision, entry.downTime); - for (uint32_t i = 0; i < entry.pointerCount; i++) { + for (uint32_t i = 0; i < entry.getPointerCount(); i++) { ALOGD(" Pointer %d: id=%d, toolType=%s, " "x=%f, y=%f, pressure=%f, size=%f, " "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " @@ -2514,7 +2513,7 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( addDragEventLocked(entry); // Check whether touches should slip outside of the current foreground window. - if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry.pointerCount == 1 && + if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry.getPointerCount() == 1 && tempTouchState.isSlippery()) { const auto [x, y] = resolveTouchedPosition(entry); const bool isStylus = isPointerFromStylus(entry, /*pointerIndex=*/0); @@ -2793,14 +2792,14 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { // Find the pointer index by id. int32_t pointerIndex = 0; - for (; static_cast(pointerIndex) < entry.pointerCount; pointerIndex++) { + for (; static_cast(pointerIndex) < entry.getPointerCount(); pointerIndex++) { const PointerProperties& pointerProperties = entry.pointerProperties[pointerIndex]; if (pointerProperties.id == mDragState->pointerId) { break; } } - if (uint32_t(pointerIndex) == entry.pointerCount) { + if (uint32_t(pointerIndex) == entry.getPointerCount()) { LOG_ALWAYS_FATAL("Should find a valid pointer index by id %d", mDragState->pointerId); } @@ -3225,7 +3224,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, ftl::enum_string(eventEntry->type).c_str()); const MotionEntry& originalMotionEntry = static_cast(*eventEntry); - if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) { + if (inputTarget.pointerIds.count() != originalMotionEntry.getPointerCount()) { if (!inputTarget.firstDownTimeInTarget.has_value()) { logDispatchStateLocked(); LOG(FATAL) << "Splitting motion events requires a down time to be set for the " @@ -3537,14 +3536,14 @@ status_t InputDispatcher::publishMotionEvent(Connection& connection, const MotionEntry& motionEntry = static_cast(eventEntry); PointerCoords scaledCoords[MAX_POINTERS]; - const PointerCoords* usingCoords = motionEntry.pointerCoords; + const PointerCoords* usingCoords = motionEntry.pointerCoords.data(); // Set the X and Y offset and X and Y scale depending on the input source. if ((motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) && !(dispatchEntry.targetFlags.test(InputTarget::Flags::ZERO_COORDS))) { float globalScaleFactor = dispatchEntry.globalScaleFactor; if (globalScaleFactor != 1.0f) { - for (uint32_t i = 0; i < motionEntry.pointerCount; i++) { + for (uint32_t i = 0; i < motionEntry.getPointerCount(); i++) { scaledCoords[i] = motionEntry.pointerCoords[i]; // Don't apply window scale here since we don't want scale to affect raw // coordinates. The scale will be sent back to the client and applied @@ -3555,7 +3554,7 @@ status_t InputDispatcher::publishMotionEvent(Connection& connection, } } else if (dispatchEntry.targetFlags.test(InputTarget::Flags::ZERO_COORDS)) { // We don't want the dispatch target to know the coordinates - for (uint32_t i = 0; i < motionEntry.pointerCount; i++) { + for (uint32_t i = 0; i < motionEntry.getPointerCount(); i++) { scaledCoords[i].clear(); } usingCoords = scaledCoords; @@ -3575,7 +3574,7 @@ status_t InputDispatcher::publishMotionEvent(Connection& connection, motionEntry.yPrecision, motionEntry.xCursorPosition, motionEntry.yCursorPosition, dispatchEntry.rawTransform, motionEntry.downTime, motionEntry.eventTime, - motionEntry.pointerCount, motionEntry.pointerProperties, + motionEntry.getPointerCount(), motionEntry.pointerProperties.data(), usingCoords); } @@ -3991,7 +3990,7 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( : std::nullopt; if (const auto& window = getWindowHandleLocked(token, targetDisplay); window) { std::bitset pointerIds; - for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.pointerCount; + for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.getPointerCount(); pointerIndex++) { pointerIds.set(motionEntry.pointerProperties[pointerIndex].id); } @@ -4066,7 +4065,7 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( const auto& motionEntry = static_cast(*downEventEntry); if (windowHandle != nullptr) { std::bitset pointerIds; - for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.pointerCount; + for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.getPointerCount(); pointerIndex++) { pointerIds.set(motionEntry.pointerProperties[pointerIndex].id); } @@ -4127,10 +4126,10 @@ std::unique_ptr InputDispatcher::splitMotionEvent( ALOG_ASSERT(pointerIds.any()); uint32_t splitPointerIndexMap[MAX_POINTERS]; - PointerProperties splitPointerProperties[MAX_POINTERS]; - PointerCoords splitPointerCoords[MAX_POINTERS]; + std::vector splitPointerProperties; + std::vector splitPointerCoords; - uint32_t originalPointerCount = originalMotionEntry.pointerCount; + uint32_t originalPointerCount = originalMotionEntry.getPointerCount(); uint32_t splitPointerCount = 0; for (uint32_t originalPointerIndex = 0; originalPointerIndex < originalPointerCount; @@ -4140,9 +4139,8 @@ std::unique_ptr InputDispatcher::splitMotionEvent( uint32_t pointerId = uint32_t(pointerProperties.id); if (pointerIds.test(pointerId)) { splitPointerIndexMap[splitPointerCount] = originalPointerIndex; - splitPointerProperties[splitPointerCount] = pointerProperties; - splitPointerCoords[splitPointerCount] = - originalMotionEntry.pointerCoords[originalPointerIndex]; + splitPointerProperties.push_back(pointerProperties); + splitPointerCoords.push_back(originalMotionEntry.pointerCoords[originalPointerIndex]); splitPointerCount += 1; } } @@ -4217,8 +4215,7 @@ std::unique_ptr InputDispatcher::splitMotionEvent( originalMotionEntry.yPrecision, originalMotionEntry.xCursorPosition, originalMotionEntry.yCursorPosition, splitDownTime, - splitPointerCount, splitPointerProperties, - splitPointerCoords); + splitPointerProperties, splitPointerCoords); if (originalMotionEntry.injectionState) { splitMotionEntry->injectionState = originalMotionEntry.injectionState; @@ -4437,9 +4434,8 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs& args) { args.buttonState, args.classification, args.edgeFlags, args.xPrecision, args.yPrecision, args.xCursorPosition, args.yCursorPosition, - args.downTime, args.getPointerCount(), - args.pointerProperties.data(), - args.pointerCoords.data()); + args.downTime, args.pointerProperties, + args.pointerCoords); if (args.id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID && IdGenerator::getSource(args.id) == IdGenerator::Source::INPUT_READER && @@ -4653,6 +4649,11 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev mLock.lock(); const nsecs_t* sampleEventTimes = motionEvent.getSampleEventTimes(); + const size_t pointerCount = motionEvent.getPointerCount(); + const std::vector + pointerProperties(motionEvent.getPointerProperties(), + motionEvent.getPointerProperties() + pointerCount); + const PointerCoords* samplePointerCoords = motionEvent.getSamplePointerCoords(); std::unique_ptr injectedEntry = std::make_unique(motionEvent.getId(), *sampleEventTimes, @@ -4667,33 +4668,28 @@ InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* ev motionEvent.getYPrecision(), motionEvent.getRawXCursorPosition(), motionEvent.getRawYCursorPosition(), - motionEvent.getDownTime(), - motionEvent.getPointerCount(), - motionEvent.getPointerProperties(), - samplePointerCoords); + motionEvent.getDownTime(), pointerProperties, + std::vector(samplePointerCoords, + samplePointerCoords + + pointerCount)); transformMotionEntryForInjectionLocked(*injectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(injectedEntry)); for (size_t i = motionEvent.getHistorySize(); i > 0; i--) { sampleEventTimes += 1; samplePointerCoords += motionEvent.getPointerCount(); - std::unique_ptr nextInjectedEntry = - std::make_unique(motionEvent.getId(), *sampleEventTimes, - resolvedDeviceId, motionEvent.getSource(), - displayId, policyFlags, - motionEvent.getAction(), - motionEvent.getActionButton(), flags, - motionEvent.getMetaState(), - motionEvent.getButtonState(), - motionEvent.getClassification(), - motionEvent.getEdgeFlags(), - motionEvent.getXPrecision(), - motionEvent.getYPrecision(), - motionEvent.getRawXCursorPosition(), - motionEvent.getRawYCursorPosition(), - motionEvent.getDownTime(), - motionEvent.getPointerCount(), - motionEvent.getPointerProperties(), - samplePointerCoords); + std::unique_ptr nextInjectedEntry = std::make_unique< + MotionEntry>(motionEvent.getId(), *sampleEventTimes, resolvedDeviceId, + motionEvent.getSource(), displayId, policyFlags, + motionEvent.getAction(), motionEvent.getActionButton(), flags, + motionEvent.getMetaState(), motionEvent.getButtonState(), + motionEvent.getClassification(), motionEvent.getEdgeFlags(), + motionEvent.getXPrecision(), motionEvent.getYPrecision(), + motionEvent.getRawXCursorPosition(), + motionEvent.getRawYCursorPosition(), motionEvent.getDownTime(), + pointerProperties, + std::vector(samplePointerCoords, + samplePointerCoords + + pointerCount)); transformMotionEntryForInjectionLocked(*nextInjectedEntry, motionEvent.getTransform()); injectedEntries.push(std::move(nextInjectedEntry)); @@ -4872,7 +4868,7 @@ void InputDispatcher::transformMotionEntryForInjectionLocked( entry.xCursorPosition = cursor.x; entry.yCursorPosition = cursor.y; } - for (uint32_t i = 0; i < entry.pointerCount; i++) { + for (uint32_t i = 0; i < entry.getPointerCount(); i++) { entry.pointerCoords[i] = MotionEvent::calculateTransformedCoords(entry.source, transformToDisplay, entry.pointerCoords[i]); diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index 57a6336d9a..b348808b13 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -238,7 +238,7 @@ void InputState::MotionMemento::setPointers(const MotionEntry& entry) { pointerProperties.clear(); pointerCoords.clear(); - for (uint32_t i = 0; i < entry.pointerCount; i++) { + for (uint32_t i = 0; i < entry.getPointerCount(); i++) { if (MotionEvent::getActionMasked(entry.action) == AMOTION_EVENT_ACTION_POINTER_UP) { // In POINTER_UP events, the pointer is leaving. Since the action is not stored, // this departing pointer should not be recorded. @@ -300,9 +300,8 @@ std::vector> InputState::synthesizeCancelationEvents memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - memento.getPointerCount(), - memento.pointerProperties.data(), - memento.pointerCoords.data())); + memento.pointerProperties, + memento.pointerCoords)); } else { std::vector> pointerCancelEvents = synthesizeCancelationEventsForPointers(memento, options.pointerIds.value(), @@ -327,23 +326,22 @@ std::vector> InputState::synthesizePointerDownEvents continue; } - uint32_t pointerCount = 0; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; + std::vector pointerProperties; + std::vector pointerCoords; // We will deliver all pointers the target already knows about for (uint32_t i = 0; i < static_cast(memento.firstNewPointerIdx); i++) { - pointerProperties[i] = memento.pointerProperties[i]; - pointerCoords[i] = memento.pointerCoords[i]; - pointerCount++; + pointerProperties.push_back(memento.pointerProperties[i]); + pointerCoords.push_back(memento.pointerCoords[i]); } // We will send explicit events for all pointers the target doesn't know about for (uint32_t i = static_cast(memento.firstNewPointerIdx); i < memento.getPointerCount(); i++) { - pointerProperties[i] = memento.pointerProperties[i]; - pointerCoords[i] = memento.pointerCoords[i]; - pointerCount++; + pointerProperties.push_back(memento.pointerProperties[i]); + pointerCoords.push_back(memento.pointerCoords[i]); + + const size_t pointerCount = pointerProperties.size(); // Down only if the first pointer, pointer down otherwise const int32_t action = (pointerCount <= 1) @@ -360,7 +358,7 @@ std::vector> InputState::synthesizePointerDownEvents AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - pointerCount, pointerProperties, pointerCoords)); + pointerProperties, pointerCoords)); } memento.firstNewPointerIdx = INVALID_POINTER_INDEX; @@ -401,9 +399,7 @@ std::vector> InputState::synthesizeCancelationEvent AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - memento.getPointerCount(), - memento.pointerProperties.data(), - memento.pointerCoords.data())); + memento.pointerProperties, memento.pointerCoords)); } else { // If we aren't canceling all pointers, we need to generate ACTION_POINTER_UP with // FLAG_CANCELED for each of the canceled pointers. For each event, we must remove the @@ -430,8 +426,7 @@ std::vector> InputState::synthesizeCancelationEvent AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, memento.yPrecision, memento.xCursorPosition, memento.yCursorPosition, memento.downTime, - pointerCount, pointerProperties.data(), - pointerCoords.data())); + pointerProperties, pointerCoords)); // Cleanup pointer information pointerProperties.erase(pointerProperties.begin() + pointerIdx); -- GitLab From 17464dc4ca65657e02a51d43f13f47588f0fb77f Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Thu, 13 Jul 2023 05:31:43 +0000 Subject: [PATCH 0857/1187] [Cherry-pick] Revert "Revert "Load native GLES driver when specified."" This reverts commit 1d6261388df9c5f6866bd4f2b296ad685c79badc. Reason for revert: Revert the revert to reland the patch. Original patch was reverted due to rss memory regression. Attempt to reland the patch with a fix, the original regression seems to be caused by usage of enum. Original commit message: """ Load native GLES driver when specified. Since ANGLE and native GLES drivers can coexist, when native is specified, the loader must load the native GLES drivers specified in ro.hardware.egl. This patch adds the support to load native GLES drivers when specified. Bug: b/283858001 Test: atest CtsAngleDeveloperOptionHostTest -c with ANGLE being default Test: atest CtsAngleDeveloperOptionHostTest -c with native being default """ Bug: b/283858001 Test: atest CtsAngleDeveloperOptionHostTest -c with ANGLE being default Test: atest CtsAngleDeveloperOptionHostTest -c with native being default Change-Id: I6a2e716d340d9be3610c31abbcbe7984bf472f9f Merged-In: I6a2e716d340d9be3610c31abbcbe7984bf472f9f --- libs/graphicsenv/GraphicsEnv.cpp | 19 ++++++++++-- .../include/graphicsenv/GraphicsEnv.h | 8 ++++- opengl/libs/EGL/Loader.cpp | 29 +++++++++++++++---- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 0a5416128e..ed5d5c1095 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -530,7 +530,11 @@ bool GraphicsEnv::shouldUseAngle() { return mShouldUseAngle; } -void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSystemAngle, +// Set ANGLE information. +// If path is "system", it means system ANGLE must be used for the process. +// If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. +// If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. +void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, const std::string& packageName, const std::vector eglFeatures) { if (mShouldUseAngle) { @@ -547,8 +551,13 @@ void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSyst mAnglePath = std::move(path); ALOGV("setting app package name to '%s'", packageName.c_str()); mPackageName = std::move(packageName); - mShouldUseAngle = true; - mShouldUseSystemAngle = shouldUseSystemAngle; + if (mAnglePath == "system") { + mShouldUseSystemAngle = true; + } + if (!mAnglePath.empty()) { + mShouldUseAngle = true; + } + mShouldUseNativeDriver = shouldUseNativeDriver; } std::string& GraphicsEnv::getPackageName() { @@ -625,6 +634,10 @@ bool GraphicsEnv::shouldUseSystemAngle() { return mShouldUseSystemAngle; } +bool GraphicsEnv::shouldUseNativeDriver() { + return mShouldUseNativeDriver; +} + /** * APIs for debuggable layers */ diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index fbf2902869..6cce3f6998 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -108,7 +108,10 @@ public: // (libraries must be stored uncompressed and page aligned); such elements // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a - void setAngleInfo(const std::string& path, const bool useSystemAngle, + // If the search patch is "system", then it means the system ANGLE should be used. + // If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. + // If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. + void setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, const std::string& packageName, const std::vector eglFeatures); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); @@ -118,6 +121,7 @@ public: // Set the persist.graphics.egl system property value. void nativeToggleAngleAsSystemDriver(bool enabled); bool shouldUseSystemAngle(); + bool shouldUseNativeDriver(); /* * Apis for debug layer @@ -175,6 +179,8 @@ private: bool mShouldUseAngle = false; // Whether loader should load system ANGLE. bool mShouldUseSystemAngle = false; + // Whether loader should load native GLES driver. + bool mShouldUseNativeDriver = false; // ANGLE namespace. android_namespace_t* mAngleNamespace = nullptr; diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 8d0eb590bf..654e5b7c03 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -169,6 +169,11 @@ static bool should_unload_system_driver(egl_connection_t* cnx) { } } + // Return true if native GLES drivers should be used and ANGLE is already loaded. + if (android::GraphicsEnv::getInstance().shouldUseNativeDriver() && cnx->angleLoaded) { + return true; + } + // Return true if updated driver namespace is set. ns = android::GraphicsEnv::getInstance().getDriverNamespace(); if (ns) { @@ -240,16 +245,28 @@ void* Loader::open(egl_connection_t* cnx) { if (!hnd) { // Secondly, try to load from driver apk. hnd = attempt_to_load_updated_driver(cnx); + + // If updated driver apk is set but fail to load, abort here. + LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace(), + "couldn't find an OpenGL ES implementation from %s", + android::GraphicsEnv::getInstance().getDriverPath().c_str()); } + // Attempt to load native GLES drivers specified by ro.hardware.egl if native is selected. + // If native is selected but fail to load, abort. + if (!hnd && android::GraphicsEnv::getInstance().shouldUseNativeDriver()) { + auto driverSuffix = base::GetProperty(RO_DRIVER_SUFFIX_PROPERTY, ""); + LOG_ALWAYS_FATAL_IF(driverSuffix.empty(), + "Native GLES driver is selected but not specified in %s", + RO_DRIVER_SUFFIX_PROPERTY); + hnd = attempt_to_load_system_driver(cnx, driverSuffix.c_str(), true); + LOG_ALWAYS_FATAL_IF(!hnd, "Native GLES driver is selected but failed to load. %s=%s", + RO_DRIVER_SUFFIX_PROPERTY, driverSuffix.c_str()); + } + + // Finally, try to load default driver. bool failToLoadFromDriverSuffixProperty = false; if (!hnd) { - // If updated driver apk is set but fail to load, abort here. - if (android::GraphicsEnv::getInstance().getDriverNamespace()) { - LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s", - android::GraphicsEnv::getInstance().getDriverPath().c_str()); - } - // Finally, try to load system driver. // Start by searching for the library name appended by the system // properties of the GLES userspace driver in both locations. // i.e.: -- GitLab From c6dd01653eec4ea15a90b5bb9cf76cc1c5f2418c Mon Sep 17 00:00:00 2001 From: Gaurav Sarode Date: Mon, 16 Oct 2023 20:17:40 +0000 Subject: [PATCH 0858/1187] Disable android.software.picture_in_picture for automotive bug: 302349570 Test: Refer bug for testing details. Change-Id: Id9195b68fdd0bb830df9e7058a0da1e21cf47621 --- data/etc/android.hardware.type.automotive.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/etc/android.hardware.type.automotive.xml b/data/etc/android.hardware.type.automotive.xml index a9b4b0526a..8605d18d19 100644 --- a/data/etc/android.hardware.type.automotive.xml +++ b/data/etc/android.hardware.type.automotive.xml @@ -17,4 +17,6 @@ + + -- GitLab From 2899c55fc54fc13089396eb41b0c919612b1c16a Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 10 Jul 2023 18:20:46 -0700 Subject: [PATCH 0859/1187] Allow multi-window multiple device streams Before this CL, only one device could be active in the system at a given time. This was enforced early inside the dispatcher code. In this CL, this restriction is removed, and a new restriction is introduced: - At most one input device can be active for a given connection That means that it's now possible to touch one window and draw with stylus in another. This is implemented by moving the "changed device" check from the TouchState into InputState. This should work OK because there will be a unique ViewRootImpl per connection, and the UI toolkit will continue to process the events in a single-device mode. In the future, we can consider enabling same-window multi-device streams. This would likely require a new public API. After this CL, the dispatcher will work in the following manner: TouchState -> always works in the multi-device mode. Assumes 1 window can receive multiple pointers from different devices. InputState (per-connection) -> acts as a rejector / multiplexor. It only selects a single device to be active for the given connection. This is done so that in the future, we can potentially turn off the "single device active" behaviour of InputState without having to change other parts of the dispatcher. What happens if there are multiple device streams being sent? - In general, latest device always wins - Exception: stylus always takes precedence over other devices - Latest stylus device cancels the current stylus device One other behaviour there: - If for the same device id, source changed (this is one of the tests), then the current gesture is canceled. Additional changes: The case of touch pointer down -> mouse down -> second touch pointer down does not cancel mouse. For simplicity, we just wait for a new touch gesture to start before canceling the current mouse gesture. Pilfer pointers changes: Previously, two devices being active in one window cause pilferPointers to fail. The new behaviour is that all of the active gestures in the spy window that's doing the pilfering are going to get pilfered. So if a spy window is receiving mouse and touch, then both mouse and touch gestures are going to be pilfered (because the windows below the spy would be getting independent mouse and touch streams). In practice, in this CL the spy will never receive two devices at the same time, because we are only allowing single device to be active per-window. But the understanding here is that eventually, we may want to have multiple devices going to the spy. How same-token windows are handled: During TouchState computation, the windows with the same token are treated separately (since they do have a different layer id). Then later, during TouchState -> InputTarget conversion, they are all lumped into one target. One problem with this approach is that sometimes, we want to generate HOVER_EXIT with response to receiving ACTION_DOWN event. This is because InputReader today doesn't always generate HOVER_EXIT prior to sending ACTION_DOWN. That means that the dispatcher has to have a special logic for dealing with these cases. The approach taken in this CL is to force-generate new DISPATCH_AS_HOVER_EXIT input targets, which would allow them to remain separate from DISPATCH_AS_IS input targets for the ACTION_DOWN event. This avoid the collision of pointers. Otherwise, we would add a pointer id for the HOVER_EXIT event, which would not be valid for the ACTION_DOWN event's pointer id. Bug: 211379801 Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST Change-Id: If2eae87bc2a40b61144ddcd019a9800c2d526072 --- .../dispatcher/InputDispatcher.cpp | 272 ++++++++------- .../inputflinger/dispatcher/InputDispatcher.h | 8 +- .../inputflinger/dispatcher/InputState.cpp | 184 ++++++++++- services/inputflinger/dispatcher/InputState.h | 7 + .../inputflinger/dispatcher/TouchState.cpp | 37 ++- services/inputflinger/dispatcher/TouchState.h | 8 +- .../inputflinger/dispatcher/TouchedWindow.cpp | 14 +- .../inputflinger/dispatcher/TouchedWindow.h | 2 +- .../tests/InputDispatcher_test.cpp | 311 ++++++++++++++---- 9 files changed, 598 insertions(+), 245 deletions(-) diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 45649dd146..7dfbf94883 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -634,11 +634,10 @@ std::vector getHoveringWindowsLocked(const TouchState* oldState, const MotionEntry& entry) { std::vector out; const int32_t maskedAction = MotionEvent::getActionMasked(entry.action); - if (maskedAction != AMOTION_EVENT_ACTION_HOVER_ENTER && - maskedAction != AMOTION_EVENT_ACTION_HOVER_MOVE && - maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT) { - // Not a hover event - don't need to do anything - return out; + + if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { + // ACTION_SCROLL events should not affect the hovering pointer dispatch + return {}; } // We should consider all hovering pointers here. But for now, just use the first one @@ -1315,8 +1314,9 @@ std::vector InputDispatcher::findOutsideTargetsLocked( if (info.inputConfig.test(WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH)) { std::bitset pointerIds; pointerIds.set(pointerId); - addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_OUTSIDE, pointerIds, - /*firstDownTimeInTarget=*/std::nullopt, outsideTargets); + addPointerWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_OUTSIDE, + pointerIds, + /*firstDownTimeInTarget=*/std::nullopt, outsideTargets); } } return outsideTargets; @@ -1821,7 +1821,7 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr inputTargets; addWindowTargetLocked(focusedWindow, InputTarget::Flags::FOREGROUND | InputTarget::Flags::DISPATCH_AS_IS, - /*pointerIds=*/{}, getDownTime(*entry), inputTargets); + getDownTime(*entry), inputTargets); // Add monitor channels from event's or focused display. addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry)); @@ -1905,7 +1905,6 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< // Identify targets. std::vector inputTargets; - bool conflictingPointerActions = false; InputEventInjectionResult injectionResult; if (isPointerEvent) { // Pointer event. (eg. touchscreen) @@ -1917,8 +1916,7 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< } inputTargets = - findTouchedWindowTargetsLocked(currentTime, *entry, &conflictingPointerActions, - /*byref*/ injectionResult); + findTouchedWindowTargetsLocked(currentTime, *entry, /*byref*/ injectionResult); LOG_ALWAYS_FATAL_IF(injectionResult != InputEventInjectionResult::SUCCEEDED && !inputTargets.empty()); } else { @@ -1930,7 +1928,7 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< addWindowTargetLocked(focusedWindow, InputTarget::Flags::FOREGROUND | InputTarget::Flags::DISPATCH_AS_IS, - /*pointerIds=*/{}, getDownTime(*entry), inputTargets); + getDownTime(*entry), inputTargets); } } if (injectionResult == InputEventInjectionResult::PENDING) { @@ -1954,11 +1952,6 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry)); // Dispatch the motion. - if (conflictingPointerActions) { - CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS, - "conflicting pointer actions"); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } dispatchEventLocked(currentTime, entry, inputTargets); return true; } @@ -2258,7 +2251,7 @@ std::vector InputDispatcher::selectResponsiveMonitorsLocked( } std::vector InputDispatcher::findTouchedWindowTargetsLocked( - nsecs_t currentTime, const MotionEntry& entry, bool* outConflictingPointerActions, + nsecs_t currentTime, const MotionEntry& entry, InputEventInjectionResult& outInjectionResult) { ATRACE_CALL(); @@ -2283,20 +2276,13 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( } bool isSplit = shouldSplitTouch(tempTouchState, entry); - bool switchedDevice = false; - if (oldState != nullptr) { - std::set oldActiveDevices = oldState->getActiveDeviceIds(); - const bool anotherDeviceIsActive = - oldActiveDevices.count(entry.deviceId) == 0 && !oldActiveDevices.empty(); - switchedDevice |= anotherDeviceIsActive; - } const bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); // A DOWN could be generated from POINTER_DOWN if the initial pointers did not land into any // touchable windows. - const bool wasDown = oldState != nullptr && oldState->isDown(); + const bool wasDown = oldState != nullptr && oldState->isDown(entry.deviceId); const bool isDown = (maskedAction == AMOTION_EVENT_ACTION_DOWN) || (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN && !wasDown); const bool newGesture = isDown || maskedAction == AMOTION_EVENT_ACTION_SCROLL || @@ -2304,34 +2290,19 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE; const bool isFromMouse = isFromSource(entry.source, AINPUT_SOURCE_MOUSE); - // If pointers are already down, let's finish the current gesture and ignore the new events - // from another device. However, if the new event is a down event, let's cancel the current - // touch and let the new one take over. - if (switchedDevice && wasDown && !isDown) { - LOG(INFO) << "Dropping event because a pointer for another device " - << " is already down in display " << displayId << ": " << entry.getDescription(); - // TODO(b/211379801): test multiple simultaneous input streams. - outInjectionResult = InputEventInjectionResult::FAILED; - return {}; // wrong device - } - if (newGesture) { - // If a new gesture is starting, clear the touch state completely. - tempTouchState.reset(); isSplit = false; - } else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) { - ALOGI("Dropping move event because a pointer for a different device is already active " - "in display %" PRId32, - displayId); - // TODO(b/211379801): test multiple simultaneous input streams. - outInjectionResult = InputEventInjectionResult::FAILED; - return {}; // wrong device + } + + if (isDown && tempTouchState.hasHoveringPointers(entry.deviceId)) { + // Compatibility behaviour: ACTION_DOWN causes HOVER_EXIT to get generated. + tempTouchState.clearHoveringPointers(entry.deviceId); } if (isHoverAction) { // For hover actions, we will treat 'tempTouchState' as a new state, so let's erase // all of the existing hovering pointers and recompute. - tempTouchState.clearHoveringPointers(); + tempTouchState.clearHoveringPointers(entry.deviceId); } if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) { @@ -2402,8 +2373,7 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( continue; } - if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || - maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { + if (isHoverAction) { // The "windowHandle" is the target of this hovering pointer. tempTouchState.addHoveringPointerToWindow(windowHandle, entry.deviceId, pointerId); } @@ -2426,31 +2396,24 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( } // Update the temporary touch state. - std::bitset pointerIds; + if (!isHoverAction) { + std::bitset pointerIds; pointerIds.set(pointerId); - } - - const bool isDownOrPointerDown = maskedAction == AMOTION_EVENT_ACTION_DOWN || - maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN; - - // TODO(b/211379801): Currently, even if pointerIds are empty (hover case), we would - // still add a window to the touch state. We should avoid doing that, but some of the - // later checks ("at least one foreground window") rely on this in order to dispatch - // the event properly, so that needs to be updated, possibly by looking at InputTargets. - tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, entry.deviceId, pointerIds, - isDownOrPointerDown - ? std::make_optional(entry.eventTime) - : std::nullopt); - - // If this is the pointer going down and the touched window has a wallpaper - // then also add the touched wallpaper windows so they are locked in for the duration - // of the touch gesture. - // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper - // engine only supports touch events. We would need to add a mechanism similar - // to View.onGenericMotionEvent to enable wallpapers to handle these events. - if (isDownOrPointerDown) { - if (targetFlags.test(InputTarget::Flags::FOREGROUND) && + const bool isDownOrPointerDown = maskedAction == AMOTION_EVENT_ACTION_DOWN || + maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN; + tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, entry.deviceId, + pointerIds, + isDownOrPointerDown + ? std::make_optional(entry.eventTime) + : std::nullopt); + // If this is the pointer going down and the touched window has a wallpaper + // then also add the touched wallpaper windows so they are locked in for the + // duration of the touch gesture. We do not collect wallpapers during HOVER_MOVE or + // SCROLL because the wallpaper engine only supports touch events. We would need to + // add a mechanism similar to View.onGenericMotionEvent to enable wallpapers to + // handle these events. + if (isDownOrPointerDown && targetFlags.test(InputTarget::Flags::FOREGROUND) && windowHandle->getInfo()->inputConfig.test( gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) { sp wallpaper = findWallpaperWindowBelow(windowHandle); @@ -2488,8 +2451,10 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ // If the pointer is not currently down, then ignore the event. - if (!tempTouchState.isDown() && maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT) { - LOG(INFO) << "Dropping event because the pointer is not down or we previously " + if (!tempTouchState.isDown(entry.deviceId) && + maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT) { + LOG(INFO) << "Dropping event because the pointer for device " << entry.deviceId + << " is not down or we previously " "dropped the pointer down event in display " << displayId << ": " << entry.getDescription(); outInjectionResult = InputEventInjectionResult::FAILED; @@ -2538,7 +2503,7 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( if (newTouchedWindowHandle != nullptr && !haveSameToken(oldTouchedWindowHandle, newTouchedWindowHandle)) { - ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32, + ALOGI("Touch is slipping out of window %s into window %s in display %" PRId32, oldTouchedWindowHandle->getName().c_str(), newTouchedWindowHandle->getName().c_str(), displayId); @@ -2549,9 +2514,11 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( const TouchedWindow& touchedWindow = tempTouchState.getTouchedWindow(oldTouchedWindowHandle); - addWindowTargetLocked(oldTouchedWindowHandle, - InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT, pointerIds, - touchedWindow.getDownTimeInTarget(entry.deviceId), targets); + addPointerWindowTargetLocked(oldTouchedWindowHandle, + InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT, + pointerIds, + touchedWindow.getDownTimeInTarget(entry.deviceId), + targets); // Make a slippery entrance into the new window. if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { @@ -2664,16 +2631,14 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( // Output targets from the touch state. for (const TouchedWindow& touchedWindow : tempTouchState.windows) { - if (!touchedWindow.hasTouchingPointers(entry.deviceId) && - !touchedWindow.hasHoveringPointers(entry.deviceId)) { - // Windows with hovering pointers are getting persisted inside TouchState. - // Do not send this event to those windows. + std::bitset touchingPointers = + touchedWindow.getTouchingPointers(entry.deviceId); + if (touchingPointers.none()) { continue; } - - addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, - touchedWindow.getTouchingPointers(entry.deviceId), - touchedWindow.getDownTimeInTarget(entry.deviceId), targets); + addPointerWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, + touchingPointers, + touchedWindow.getDownTimeInTarget(entry.deviceId), targets); } // During targeted injection, only allow owned targets to receive events @@ -2706,37 +2671,30 @@ std::vector InputDispatcher::findTouchedWindowTargetsLocked( } outInjectionResult = InputEventInjectionResult::SUCCEEDED; - // Drop the outside or hover touch windows since we will not care about them - // in the next iteration. - tempTouchState.filterNonAsIsTouchWindows(); - // Update final pieces of touch state if the injector had permission. - if (switchedDevice) { - if (DEBUG_FOCUS) { - ALOGD("Conflicting pointer actions: Switched to a different device."); + for (TouchedWindow& touchedWindow : tempTouchState.windows) { + // Targets that we entered in a slippery way will now become AS-IS targets + if (touchedWindow.targetFlags.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER)) { + touchedWindow.targetFlags.clear(InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER); + touchedWindow.targetFlags |= InputTarget::Flags::DISPATCH_AS_IS; } - *outConflictingPointerActions = true; } + // Update final pieces of touch state if the injector had permission. if (isHoverAction) { - // Started hovering, therefore no longer down. - if (oldState && oldState->isDown()) { - ALOGD_IF(DEBUG_FOCUS, - "Conflicting pointer actions: Hover received while pointer was down."); - *outConflictingPointerActions = true; + if (oldState && oldState->isDown(entry.deviceId)) { + // Started hovering, but the device is already down: reject the hover event + LOG(ERROR) << "Got hover event " << entry.getDescription() + << " but the device is already down " << oldState->dump(); + outInjectionResult = InputEventInjectionResult::FAILED; + return {}; } } else if (maskedAction == AMOTION_EVENT_ACTION_UP) { // Pointer went up. tempTouchState.removeTouchingPointer(entry.deviceId, entry.pointerProperties[0].id); } else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) { // All pointers up or canceled. - tempTouchState.reset(); - } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - // First pointer went down. - if (oldState && (oldState->isDown() || oldState->hasHoveringPointers())) { - ALOGD("Conflicting pointer actions: Down received while already down or hovering."); - *outConflictingPointerActions = true; - } + tempTouchState.removeAllPointersForDevice(entry.deviceId); } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { // One pointer went up. const int32_t pointerIndex = MotionEvent::getActionIndex(action); @@ -2885,7 +2843,6 @@ std::optional InputDispatcher::createInputTargetLocked( void InputDispatcher::addWindowTargetLocked(const sp& windowHandle, ftl::Flags targetFlags, - std::bitset pointerIds, std::optional firstDownTimeInTarget, std::vector& inputTargets) const { std::vector::iterator it = @@ -2907,8 +2864,54 @@ void InputDispatcher::addWindowTargetLocked(const sp& windowHa it = inputTargets.end() - 1; } - ALOG_ASSERT(it->flags == targetFlags); - ALOG_ASSERT(it->globalScaleFactor == windowInfo->globalScaleFactor); + LOG_ALWAYS_FATAL_IF(it->flags != targetFlags); + LOG_ALWAYS_FATAL_IF(it->globalScaleFactor != windowInfo->globalScaleFactor); +} + +void InputDispatcher::addPointerWindowTargetLocked( + const sp& windowHandle, + ftl::Flags targetFlags, std::bitset pointerIds, + std::optional firstDownTimeInTarget, std::vector& inputTargets) const + REQUIRES(mLock) { + if (pointerIds.none()) { + for (const auto& target : inputTargets) { + LOG(INFO) << "Target: " << target; + } + LOG(FATAL) << "No pointers specified for " << windowHandle->getName(); + return; + } + std::vector::iterator it = + std::find_if(inputTargets.begin(), inputTargets.end(), + [&windowHandle](const InputTarget& inputTarget) { + return inputTarget.inputChannel->getConnectionToken() == + windowHandle->getToken(); + }); + + // This is a hack, because the actual entry could potentially be an ACTION_DOWN event that + // causes a HOVER_EXIT to be generated. That means that the same entry of ACTION_DOWN would + // have DISPATCH_AS_HOVER_EXIT and DISPATCH_AS_IS. And therefore, we have to create separate + // input targets for hovering pointers and for touching pointers. + // If we picked an existing input target above, but it's for HOVER_EXIT - let's use a new + // target instead. + if (it != inputTargets.end() && it->flags.test(InputTarget::Flags::DISPATCH_AS_HOVER_EXIT)) { + // Force the code below to create a new input target + it = inputTargets.end(); + } + + const WindowInfo* windowInfo = windowHandle->getInfo(); + + if (it == inputTargets.end()) { + std::optional target = + createInputTargetLocked(windowHandle, targetFlags, firstDownTimeInTarget); + if (!target) { + return; + } + inputTargets.push_back(*target); + it = inputTargets.end() - 1; + } + + LOG_ALWAYS_FATAL_IF(it->flags != targetFlags); + LOG_ALWAYS_FATAL_IF(it->globalScaleFactor != windowInfo->globalScaleFactor); it->addPointers(pointerIds, windowInfo->transform); } @@ -3366,6 +3369,27 @@ void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptrresolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; } + // Check if we need to cancel any of the ongoing gestures. We don't support multiple + // devices being active at the same time in the same window, so if a new device is + // active, cancel the gesture from the old device. + + std::unique_ptr cancelEvent = + connection->inputState + .cancelConflictingInputStream(motionEntry, + dispatchEntry->resolvedAction); + if (cancelEvent != nullptr) { + LOG(INFO) << "Canceling pointers for device " << motionEntry.deviceId << " in " + << connection->getInputChannelName() << " with event " + << cancelEvent->getDescription(); + std::unique_ptr cancelDispatchEntry = + createDispatchEntry(inputTarget, std::move(cancelEvent), + InputTarget::Flags::DISPATCH_AS_IS); + + // Send these cancel events to the queue before sending the event from the new + // device. + connection->outboundQueue.emplace_back(std::move(cancelDispatchEntry)); + } + if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { LOG(WARNING) << "channel " << connection->getInputChannelName() @@ -3975,7 +3999,7 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( : std::nullopt; if (const auto& window = getWindowHandleLocked(token, targetDisplay); window) { addWindowTargetLocked(window, InputTarget::Flags::DISPATCH_AS_IS, - /*pointerIds=*/{}, keyEntry.downTime, targets); + keyEntry.downTime, targets); } else { targets.emplace_back(fallbackTarget); } @@ -3994,8 +4018,8 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( pointerIndex++) { pointerIds.set(motionEntry.pointerProperties[pointerIndex].id); } - addWindowTargetLocked(window, InputTarget::Flags::DISPATCH_AS_IS, pointerIds, - motionEntry.downTime, targets); + addPointerWindowTargetLocked(window, InputTarget::Flags::DISPATCH_AS_IS, + pointerIds, motionEntry.downTime, targets); } else { targets.emplace_back(fallbackTarget); const auto it = mDisplayInfos.find(motionEntry.displayId); @@ -4069,8 +4093,8 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( pointerIndex++) { pointerIds.set(motionEntry.pointerProperties[pointerIndex].id); } - addWindowTargetLocked(windowHandle, targetFlags, pointerIds, - motionEntry.downTime, targets); + addPointerWindowTargetLocked(windowHandle, targetFlags, pointerIds, + motionEntry.downTime, targets); } else { targets.emplace_back(InputTarget{.inputChannel = connection->inputChannel, .flags = targetFlags}); @@ -5139,10 +5163,8 @@ void InputDispatcher::setInputWindowsLocked( for (size_t i = 0; i < state.windows.size();) { TouchedWindow& touchedWindow = state.windows[i]; if (getWindowHandleLocked(touchedWindow.windowHandle) == nullptr) { - if (DEBUG_FOCUS) { - ALOGD("Touched window was removed: %s in display %" PRId32, - touchedWindow.windowHandle->getName().c_str(), displayId); - } + LOG(INFO) << "Touched window was removed: " << touchedWindow.windowHandle->getName() + << " in display %" << displayId; std::shared_ptr touchedInputChannel = getInputChannelLocked(touchedWindow.windowHandle->getToken()); if (touchedInputChannel != nullptr) { @@ -5973,9 +5995,8 @@ status_t InputDispatcher::pilferPointersLocked(const sp& token) { return BAD_VALUE; } std::set deviceIds = windowPtr->getTouchingDeviceIds(); - if (deviceIds.size() != 1) { - LOG(WARNING) << "Can't pilfer. Currently touching devices: " << dumpSet(deviceIds) - << " in window: " << windowPtr->dump(); + if (deviceIds.empty()) { + LOG(WARNING) << "Can't pilfer: no touching devices in window: " << windowPtr->dump(); return BAD_VALUE; } @@ -6818,10 +6839,11 @@ void InputDispatcher::slipWallpaperTouch(ftl::Flags targetFl if (oldWallpaper != nullptr) { const TouchedWindow& oldTouchedWindow = state.getTouchedWindow(oldWallpaper); - addWindowTargetLocked(oldWallpaper, - oldTouchedWindow.targetFlags | - InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT, - pointerIds, oldTouchedWindow.getDownTimeInTarget(deviceId), targets); + addPointerWindowTargetLocked(oldWallpaper, + oldTouchedWindow.targetFlags | + InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT, + pointerIds, oldTouchedWindow.getDownTimeInTarget(deviceId), + targets); state.removeTouchingPointerFromWindow(deviceId, pointerId, oldWallpaper); } diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index 002030168b..a1127a0f45 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -524,7 +524,7 @@ private: nsecs_t currentTime, const EventEntry& entry, nsecs_t* nextWakeupTime, android::os::InputEventInjectionResult& outInjectionResult) REQUIRES(mLock); std::vector findTouchedWindowTargetsLocked( - nsecs_t currentTime, const MotionEntry& entry, bool* outConflictingPointerActions, + nsecs_t currentTime, const MotionEntry& entry, android::os::InputEventInjectionResult& outInjectionResult) REQUIRES(mLock); std::vector selectResponsiveMonitorsLocked( const std::vector& gestureMonitors) const REQUIRES(mLock); @@ -535,9 +535,13 @@ private: std::optional firstDownTimeInTarget) const REQUIRES(mLock); void addWindowTargetLocked(const sp& windowHandle, ftl::Flags targetFlags, - std::bitset pointerIds, std::optional firstDownTimeInTarget, std::vector& inputTargets) const REQUIRES(mLock); + void addPointerWindowTargetLocked(const sp& windowHandle, + ftl::Flags targetFlags, + std::bitset pointerIds, + std::optional firstDownTimeInTarget, + std::vector& inputTargets) const REQUIRES(mLock); void addGlobalMonitoringTargetsLocked(std::vector& inputTargets, int32_t displayId) REQUIRES(mLock); void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock); diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index b348808b13..09b5186a69 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -24,6 +24,19 @@ namespace android::inputdispatcher { +namespace { +bool isHoverAction(int32_t action) { + switch (MotionEvent::getActionMasked(action)) { + case AMOTION_EVENT_ACTION_HOVER_ENTER: + case AMOTION_EVENT_ACTION_HOVER_MOVE: + case AMOTION_EVENT_ACTION_HOVER_EXIT: { + return true; + } + } + return false; +} +} // namespace + InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerator) {} InputState::~InputState() {} @@ -89,6 +102,28 @@ bool InputState::trackKey(const KeyEntry& entry, int32_t action, int32_t flags) * false if the incoming event should be dropped. */ bool InputState::trackMotion(const MotionEntry& entry, int32_t action, int32_t flags) { + // Don't track non-pointer events + if (!isFromSource(entry.source, AINPUT_SOURCE_CLASS_POINTER)) { + // This is a focus-dispatched event; we don't track its state. + return true; + } + + if (!mMotionMementos.empty()) { + const MotionMemento& lastMemento = mMotionMementos.back(); + if (isStylusEvent(lastMemento.source, lastMemento.pointerProperties) && + !isStylusEvent(entry.source, entry.pointerProperties)) { + // We already have a stylus stream, and the new event is not from stylus. + if (!lastMemento.hovering) { + // If stylus is currently down, reject the new event unconditionally. + return false; + } + } + if (!lastMemento.hovering && isHoverAction(action)) { + // Reject hovers if already down + return false; + } + } + int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK; switch (actionMasked) { case AMOTION_EVENT_ACTION_UP: @@ -266,6 +301,136 @@ size_t InputState::MotionMemento::getPointerCount() const { return pointerProperties.size(); } +bool InputState::shouldCancelPreviousStream(const MotionEntry& motionEntry, + int32_t resolvedAction) const { + if (!isFromSource(motionEntry.source, AINPUT_SOURCE_CLASS_POINTER)) { + // This is a focus-dispatched event that should not affect the previous stream. + return false; + } + + // New MotionEntry pointer event is coming in. + + // If this is a new gesture, and it's from a different device, then, in general, we will cancel + // the current gesture. + // However, because stylus should be preferred over touch, we need to treat some cases in a + // special way. + if (mMotionMementos.empty()) { + // There is no ongoing pointer gesture, so there is nothing to cancel + return false; + } + + const MotionMemento& lastMemento = mMotionMementos.back(); + const int32_t actionMasked = MotionEvent::getActionMasked(resolvedAction); + + // For compatibility, only one input device can be active at a time in the same window. + if (lastMemento.deviceId == motionEntry.deviceId) { + // In general, the same device should produce self-consistent streams so nothing needs to + // be canceled. But there is one exception: + // Sometimes ACTION_DOWN is received without a corresponding HOVER_EXIT. To account for + // that, cancel the previous hovering stream + if (actionMasked == AMOTION_EVENT_ACTION_DOWN && lastMemento.hovering) { + return true; + } + + // Use the previous stream cancellation logic to generate all HOVER_EXIT events. + // If this hover event was generated as a result of the pointer leaving the window, + // the HOVER_EXIT event should have the same coordinates as the previous + // HOVER_MOVE event in this stream. Ensure that all HOVER_EXITs have the same + // coordinates as the previous event by cancelling the stream here. With this approach, the + // HOVER_EXIT event is generated from the previous event. + if (actionMasked == AMOTION_EVENT_ACTION_HOVER_EXIT && lastMemento.hovering) { + return true; + } + + // If the stream changes its source, just cancel the current gesture to be safe. It's + // possible that the app isn't handling source changes properly + if (motionEntry.source != lastMemento.source) { + LOG(INFO) << "Canceling stream: last source was " + << inputEventSourceToString(lastMemento.source) << " and new event is " + << motionEntry; + return true; + } + + // If the injection is happening into two different displays, the same injected device id + // could be going into both. And at this time, if mirroring is active, the same connection + // would receive different events from each display. Since the TouchStates are per-display, + // it's unlikely that those two streams would be consistent with each other. Therefore, + // cancel the previous gesture if the display id changes. + if (motionEntry.displayId != lastMemento.displayId) { + LOG(INFO) << "Canceling stream: last displayId was " + << inputEventSourceToString(lastMemento.displayId) << " and new event is " + << motionEntry; + return true; + } + + return false; + } + + // We want stylus down to block touch and other source types, but stylus hover should not + // have such an effect. + if (isHoverAction(motionEntry.action) && !lastMemento.hovering) { + // New event is a hover. Keep the current non-hovering gesture instead + return false; + } + + if (isStylusEvent(lastMemento.source, lastMemento.pointerProperties) && !lastMemento.hovering) { + // We have non-hovering stylus already active. + if (isStylusEvent(motionEntry.source, motionEntry.pointerProperties) && + actionMasked == AMOTION_EVENT_ACTION_DOWN) { + // If this new event is a stylus from a different device going down, then cancel the old + // stylus and allow the new stylus to take over + return true; + } + + // Keep the current stylus gesture. + return false; + } + + // Cancel the current gesture if this is a start of a new gesture from a new device. + if (actionMasked == AMOTION_EVENT_ACTION_DOWN || + actionMasked == AMOTION_EVENT_ACTION_HOVER_ENTER) { + return true; + } + // By default, don't cancel any events. + return false; +} + +std::unique_ptr InputState::cancelConflictingInputStream(const MotionEntry& motionEntry, + int32_t resolvedAction) { + if (!shouldCancelPreviousStream(motionEntry, resolvedAction)) { + return {}; + } + + const MotionMemento& memento = mMotionMementos.back(); + + // Cancel the last device stream + std::unique_ptr cancelEntry = + createCancelEntryForMemento(memento, motionEntry.eventTime); + + if (!trackMotion(*cancelEntry, cancelEntry->action, cancelEntry->flags)) { + LOG(FATAL) << "Generated inconsistent cancel event!"; + } + return cancelEntry; +} + +std::unique_ptr InputState::createCancelEntryForMemento(const MotionMemento& memento, + nsecs_t eventTime) const { + const int32_t action = + memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL; + int32_t flags = memento.flags; + if (action == AMOTION_EVENT_ACTION_CANCEL) { + flags |= AMOTION_EVENT_FLAG_CANCELED; + } + return std::make_unique(mIdGenerator.nextId(), eventTime, memento.deviceId, + memento.source, memento.displayId, memento.policyFlags, + action, /*actionButton=*/0, flags, AMETA_NONE, + /*buttonState=*/0, MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, + memento.yPrecision, memento.xCursorPosition, + memento.yCursorPosition, memento.downTime, + memento.pointerProperties, memento.pointerCoords); +} + std::vector> InputState::synthesizeCancelationEvents( nsecs_t currentTime, const CancelationOptions& options) { std::vector> events; @@ -284,24 +449,7 @@ std::vector> InputState::synthesizeCancelationEvents for (const MotionMemento& memento : mMotionMementos) { if (shouldCancelMotion(memento, options)) { if (options.pointerIds == std::nullopt) { - const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT - : AMOTION_EVENT_ACTION_CANCEL; - int32_t flags = memento.flags; - if (action == AMOTION_EVENT_ACTION_CANCEL) { - flags |= AMOTION_EVENT_FLAG_CANCELED; - } - events.push_back( - std::make_unique(mIdGenerator.nextId(), currentTime, - memento.deviceId, memento.source, - memento.displayId, memento.policyFlags, - action, /*actionButton=*/0, flags, AMETA_NONE, - /*buttonState=*/0, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, - memento.xPrecision, memento.yPrecision, - memento.xCursorPosition, - memento.yCursorPosition, memento.downTime, - memento.pointerProperties, - memento.pointerCoords)); + events.push_back(createCancelEntryForMemento(memento, currentTime)); } else { std::vector> pointerCancelEvents = synthesizeCancelationEventsForPointers(memento, options.pointerIds.value(), diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h index 3adbba0902..686c4323a4 100644 --- a/services/inputflinger/dispatcher/InputState.h +++ b/services/inputflinger/dispatcher/InputState.h @@ -48,6 +48,10 @@ public: // and should be skipped. bool trackMotion(const MotionEntry& entry, int32_t action, int32_t flags); + // Create cancel events for the previous stream if the current motionEntry requires it. + std::unique_ptr cancelConflictingInputStream(const MotionEntry& motionEntry, + int32_t resolvedAction); + // Synthesizes cancelation events for the current state and resets the tracked state. std::vector> synthesizeCancelationEvents( nsecs_t currentTime, const CancelationOptions& options); @@ -123,6 +127,9 @@ private: static bool shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options); static bool shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options); + bool shouldCancelPreviousStream(const MotionEntry& motionEntry, int32_t resolvedAction) const; + std::unique_ptr createCancelEntryForMemento(const MotionMemento& memento, + nsecs_t eventTime) const; // Synthesizes pointer cancel events for a particular set of pointers. std::vector> synthesizeCancelationEventsForPointers( diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index 9dcf615479..2ead171155 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include @@ -31,15 +32,6 @@ void TouchState::reset() { *this = TouchState(); } -std::set TouchState::getActiveDeviceIds() const { - std::set out; - for (const TouchedWindow& w : windows) { - std::set deviceIds = w.getActiveDeviceIds(); - out.insert(deviceIds.begin(), deviceIds.end()); - } - return out; -} - bool TouchState::hasTouchingPointers(DeviceId deviceId) const { return std::any_of(windows.begin(), windows.end(), [&](const TouchedWindow& window) { return window.hasTouchingPointers(deviceId); @@ -65,9 +57,9 @@ void TouchState::removeTouchingPointerFromWindow( } } -void TouchState::clearHoveringPointers() { +void TouchState::clearHoveringPointers(DeviceId deviceId) { for (TouchedWindow& touchedWindow : windows) { - touchedWindow.clearHoveringPointers(); + touchedWindow.removeAllHoveringPointersForDevice(deviceId); } clearWindowsWithoutPointers(); } @@ -82,9 +74,16 @@ void TouchState::addOrUpdateWindow(const sp& windowHandle, ftl::Flags targetFlags, DeviceId deviceId, std::bitset touchingPointerIds, std::optional firstDownTimeInTarget) { + if (touchingPointerIds.none()) { + LOG(FATAL) << __func__ << "No pointers specified for " << windowHandle->getName(); + return; + } for (TouchedWindow& touchedWindow : windows) { // We do not compare windows by token here because two windows that share the same token - // may have a different transform + // may have a different transform. They will be combined later when we create InputTargets. + // At that point, per-pointer window transform will be considered. + // An alternative design choice here would have been to compare here by token, but to + // store per-pointer transform. if (touchedWindow.windowHandle == windowHandle) { touchedWindow.targetFlags |= targetFlags; if (targetFlags.test(InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT)) { @@ -237,14 +236,16 @@ const TouchedWindow& TouchState::getTouchedWindow(const sp& wi return *it; } -bool TouchState::isDown() const { - return std::any_of(windows.begin(), windows.end(), - [](const TouchedWindow& window) { return window.hasTouchingPointers(); }); +bool TouchState::isDown(DeviceId deviceId) const { + return std::any_of(windows.begin(), windows.end(), [&deviceId](const TouchedWindow& window) { + return window.hasTouchingPointers(deviceId); + }); } -bool TouchState::hasHoveringPointers() const { - return std::any_of(windows.begin(), windows.end(), - [](const TouchedWindow& window) { return window.hasHoveringPointers(); }); +bool TouchState::hasHoveringPointers(DeviceId deviceId) const { + return std::any_of(windows.begin(), windows.end(), [&deviceId](const TouchedWindow& window) { + return window.hasHoveringPointers(deviceId); + }); } std::set> TouchState::getWindowsWithHoveringPointer(DeviceId deviceId, diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index f01693662c..e79c73b5e5 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -39,8 +39,6 @@ struct TouchState { void reset(); void clearWindowsWithoutPointers(); - std::set getActiveDeviceIds() const; - bool hasTouchingPointers(DeviceId deviceId) const; void removeTouchingPointer(DeviceId deviceId, int32_t pointerId); void removeTouchingPointerFromWindow(DeviceId deviceId, int32_t pointerId, @@ -52,7 +50,7 @@ struct TouchState { void addHoveringPointerToWindow(const sp& windowHandle, DeviceId deviceId, int32_t hoveringPointerId); void removeHoveringPointer(DeviceId deviceId, int32_t hoveringPointerId); - void clearHoveringPointers(); + void clearHoveringPointers(DeviceId deviceId); void removeAllPointersForDevice(DeviceId deviceId); void removeWindowByToken(const sp& token); @@ -72,8 +70,8 @@ struct TouchState { const TouchedWindow& getTouchedWindow( const sp& windowHandle) const; // Whether any of the windows are currently being touched - bool isDown() const; - bool hasHoveringPointers() const; + bool isDown(DeviceId deviceId) const; + bool hasHoveringPointers(DeviceId deviceId) const; std::set> getWindowsWithHoveringPointer( DeviceId deviceId, int32_t pointerId) const; diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp index ff4b425da3..536775100a 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.cpp +++ b/services/inputflinger/dispatcher/TouchedWindow.cpp @@ -45,12 +45,16 @@ bool TouchedWindow::hasHoveringPointers(DeviceId deviceId) const { return state.hoveringPointerIds.any(); } -void TouchedWindow::clearHoveringPointers() { - for (auto& [_, state] : mDeviceStates) { - state.hoveringPointerIds.reset(); +void TouchedWindow::clearHoveringPointers(DeviceId deviceId) { + auto stateIt = mDeviceStates.find(deviceId); + if (stateIt == mDeviceStates.end()) { + return; + } + DeviceState& state = stateIt->second; + state.hoveringPointerIds.reset(); + if (!state.hasPointers()) { + mDeviceStates.erase(stateIt); } - - std::erase_if(mDeviceStates, [](const auto& pair) { return !pair.second.hasPointers(); }); } bool TouchedWindow::hasHoveringPointer(DeviceId deviceId, int32_t pointerId) const { diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h index 3f760c0fac..6d2283e0af 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ b/services/inputflinger/dispatcher/TouchedWindow.h @@ -71,7 +71,7 @@ struct TouchedWindow { void removeAllTouchingPointersForDevice(DeviceId deviceId); void removeAllHoveringPointersForDevice(DeviceId deviceId); - void clearHoveringPointers(); + void clearHoveringPointers(DeviceId deviceId); std::string dump() const; private: diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 34323c33c2..3c87f7194d 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -2409,9 +2409,10 @@ TEST_F(InputDispatcherTest, HoverMoveAndScroll) { using InputDispatcherMultiDeviceTest = InputDispatcherTest; /** - * One window. Stylus down on the window. Next, touch from another device goes down. + * One window. Stylus down on the window. Next, touch from another device goes down. Ensure that + * touch is dropped, because stylus should be preferred over touch. */ -TEST_F(InputDispatcherMultiDeviceTest, StylusDownAndTouchDown) { +TEST_F(InputDispatcherMultiDeviceTest, StylusDownBlocksTouchDown) { std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); @@ -2434,34 +2435,31 @@ TEST_F(InputDispatcherMultiDeviceTest, StylusDownAndTouchDown) { .deviceId(touchDeviceId) .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) .build()); - // Touch cancels stylus - window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId), - WithCoords(100, 110))); - window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId), - WithCoords(140, 145))); // Touch move mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) .build()); - window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId), - WithCoords(141, 146))); + // Touch is ignored because stylus is already down - // Subsequent stylus movements are dropped + // Subsequent stylus movements are delivered correctly mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) .build()); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId), + WithCoords(101, 111))); + window->assertNoEvents(); } /** * One window and one spy window. Stylus down on the window. Next, touch from another device goes - * down. + * down. Ensure that touch is dropped, because stylus should be preferred over touch. * Similar test as above, but with added SPY window. */ -TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyAndTouchDown) { +TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyBlocksTouchDown) { std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); @@ -2497,30 +2495,28 @@ TEST_F(InputDispatcherMultiDeviceTest, StylusDownWithSpyAndTouchDown) { .deviceId(touchDeviceId) .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) .build()); - window->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); - spyWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); - window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); - spyWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); - window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); - spyWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); - // Subsequent stylus movements are dropped + + // Touch is ignored because stylus is already down + + // Subsequent stylus movements are delivered correctly mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) .build()); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId), + WithCoords(101, 111))); + spyWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId), + WithCoords(101, 111))); window->assertNoEvents(); spyWindow->assertNoEvents(); } /** - * One window. Stylus hover on the window. Next, touch from another device goes down. + * One window. Stylus hover on the window. Next, touch from another device goes down. Ensure that + * touch is not dropped, because stylus hover should be ignored. */ -TEST_F(InputDispatcherMultiDeviceTest, StylusHoverAndTouchDown) { +TEST_F(InputDispatcherMultiDeviceTest, StylusHoverDoesNotBlockTouchDown) { std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); @@ -2548,18 +2544,173 @@ TEST_F(InputDispatcherMultiDeviceTest, StylusHoverAndTouchDown) { .deviceId(touchDeviceId) .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) .build()); - window->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId))); + + // Stylus hover is canceled because touch is down + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), + WithDeviceId(stylusDeviceId), WithCoords(100, 110))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId), + WithCoords(140, 145))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId), + WithCoords(141, 146))); + + // Subsequent stylus movements are ignored + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) + .build()); + + // but subsequent touches continue to be delivered + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147)) + .build()); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId), + WithCoords(142, 147))); +} + +/** + * One window. Touch down on the window. Then, stylus hover on the window from another device. + * Ensure that touch is not canceled, because stylus hover should be dropped. + */ +TEST_F(InputDispatcherMultiDeviceTest, TouchIsNotCanceledByStylusHover) { + std::shared_ptr application = std::make_shared(); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 200, 200)); + + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); + + constexpr int32_t touchDeviceId = 4; + constexpr int32_t stylusDeviceId = 2; + + // Touch down on window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) + .build()); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) + .build()); window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); - // Subsequent stylus movements are ignored + + // Stylus hover on the window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) + .build()); mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) .build()); + // Stylus hover movement is dropped + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(142).y(147)) + .build()); + // Subsequent touch movements are delivered correctly + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId), + WithCoords(142, 147))); +} + +/** + * One window. Stylus down on the window. Then, stylus from another device goes down. Ensure that + * the latest stylus takes over. That is, old stylus should be canceled and the new stylus should + * become active. + */ +TEST_F(InputDispatcherMultiDeviceTest, LatestStylusWins) { + std::shared_ptr application = std::make_shared(); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 200, 200)); + + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); + + constexpr int32_t stylusDeviceId1 = 3; + constexpr int32_t stylusDeviceId2 = 5; + + // Touch down on window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId1) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(99).y(100)) + .build()); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId1) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(101)) + .build()); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId1))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId1))); + + // Second stylus down + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId2) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(9).y(10)) + .build()); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId2) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(10).y(11)) + .build()); + + // First stylus is canceled, second one takes over. + window->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId1))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId2))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId2))); + + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId1) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(102)) + .build()); + // Subsequent stylus movements are delivered correctly window->assertNoEvents(); } +/** + * One window. Touch down on the window. Then, stylus down on the window from another device. + * Ensure that is canceled, because stylus down should be preferred over touch. + */ +TEST_F(InputDispatcherMultiDeviceTest, TouchIsCanceledByStylusDown) { + std::shared_ptr application = std::make_shared(); + sp window = + sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 200, 200)); + + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); + + constexpr int32_t touchDeviceId = 4; + constexpr int32_t stylusDeviceId = 2; + + // Touch down on window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(140).y(145)) + .build()); + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) + .deviceId(touchDeviceId) + .pointer(PointerBuilder(0, ToolType::FINGER).x(141).y(146)) + .build()); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); + + // Stylus down on the window + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(100).y(110)) + .build()); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId))); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(stylusDeviceId))); + + // Subsequent stylus movements are delivered correctly + mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) + .deviceId(stylusDeviceId) + .pointer(PointerBuilder(0, ToolType::STYLUS).x(101).y(111)) + .build()); + window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId), + WithCoords(101, 111))); +} + /** * Two windows: a window on the left and a window on the right. * Mouse is clicked on the left window and remains down. Touch is touched on the right and remains @@ -2617,8 +2768,8 @@ TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch) { .deviceId(touchDeviceId) .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .build()); - leftWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(mouseDeviceId))); + leftWindow->assertNoEvents(); + rightWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN)); // Second touch pointer down on left window @@ -2627,6 +2778,11 @@ TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceSplitTouch) { .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .pointer(PointerBuilder(1, ToolType::FINGER).x(100).y(100)) .build()); + // Since this is now a new splittable pointer going down on the left window, and it's coming + // from a different device, the current gesture in the left window (pointer down) should first + // be canceled. + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(mouseDeviceId))); leftWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); // This MOVE event is not necessary (doesn't carry any new information), but it's there in the @@ -2672,8 +2828,6 @@ TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHover) { .deviceId(stylusDeviceId) .pointer(PointerBuilder(0, ToolType::STYLUS).x(300).y(100)) .build()); - leftWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId))); rightWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); @@ -2683,18 +2837,14 @@ TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHover) { .pointer(PointerBuilder(0, ToolType::MOUSE).x(110).y(120)) .build()); leftWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(mouseDeviceId))); - rightWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId))); + AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(mouseDeviceId))); mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) .pointer(PointerBuilder(0, ToolType::STYLUS).x(310).y(110)) .build()); - leftWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(mouseDeviceId))); rightWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); + AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId))); leftWindow->assertNoEvents(); rightWindow->assertNoEvents(); @@ -2745,29 +2895,30 @@ TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy) { .deviceId(touchDeviceId) .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .build()); - leftWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); - spyWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); + leftWindow->assertNoEvents(); rightWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); - spyWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); - // Stylus movements continue, but are ignored because the touch went down more recently. + // Spy window does not receive touch events, because stylus events take precedence, and it + // already has an active stylus gesture. + + // Stylus movements continue. They should be delivered to the left window and to the spy window mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110)) .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId))); + spyWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId))); + // Further MOVE events keep going to the right window only mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .pointer(PointerBuilder(0, ToolType::FINGER).x(310).y(110)) .build()); rightWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); - spyWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); spyWindow->assertNoEvents(); leftWindow->assertNoEvents(); @@ -2779,8 +2930,10 @@ TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceWithSpy) { * both. * Check hover in left window and touch down in the right window. * At first, spy should receive hover, but the touch down should cancel hovering inside spy. + * At the same time, left and right should be getting independent streams of hovering and touch, + * respectively. */ -TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverAndTouchWithSpy) { +TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverBlockedByTouchWithSpy) { std::shared_ptr application = std::make_shared(); sp spyWindow = @@ -2813,13 +2966,13 @@ TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverAndTouchWithSpy) { spyWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithDeviceId(stylusDeviceId))); - // Touch down on the right window. + // Touch down on the right window. Spy doesn't receive this touch because it already has + // stylus hovering there. mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .pointer(PointerBuilder(0, ToolType::FINGER).x(300).y(100)) .build()); - leftWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId))); + leftWindow->assertNoEvents(); spyWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId))); spyWindow->consumeMotionEvent( @@ -2827,11 +2980,13 @@ TEST_F(InputDispatcherMultiDeviceTest, MultiDeviceHoverAndTouchWithSpy) { rightWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); - // Stylus movements continue, but are ignored because the touch is down. + // Stylus movements continue. They should be delivered to the left window only. mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) .pointer(PointerBuilder(0, ToolType::STYLUS).x(110).y(110)) .build()); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_HOVER_MOVE), WithDeviceId(stylusDeviceId))); // Touch movements continue. They should be delivered to the right window and to the spy mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN) @@ -3054,7 +3209,7 @@ TEST_F(InputDispatcherMultiDeviceTest, HoverTapAndSplitTouch) { * While the touch is down, new hover events from the stylus device should be ignored. After the * touch is gone, stylus hovering should start working again. */ -TEST_F(InputDispatcherMultiDeviceTest, StylusHoverAndTouchTap) { +TEST_F(InputDispatcherMultiDeviceTest, StylusHoverDroppedWhenTouchTap) { std::shared_ptr application = std::make_shared(); sp window = sp::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); @@ -3080,20 +3235,20 @@ TEST_F(InputDispatcherMultiDeviceTest, StylusHoverAndTouchTap) { .deviceId(touchDeviceId) .pointer(PointerBuilder(0, ToolType::FINGER).x(100).y(100)) .build())); + // The touch device should cause hover to stop! window->consumeMotionEvent( AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithDeviceId(stylusDeviceId))); window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); - // Continue hovering with stylus. Injection will fail because touch is already down. - ASSERT_EQ(InputEventInjectionResult::FAILED, + // Continue hovering with stylus. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_STYLUS) .deviceId(stylusDeviceId) .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60)) .build())); - // No event should be sent. This event should be ignored because a pointer from another device - // is already down. + // Hovers are now ignored // Lift up the finger ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, @@ -3105,7 +3260,6 @@ TEST_F(InputDispatcherMultiDeviceTest, StylusHoverAndTouchTap) { .build())); window->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(touchDeviceId))); - // Now that the touch is gone, stylus hovering should start working again ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(*mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, @@ -7822,10 +7976,23 @@ private: // should be ANR'd first. TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) { ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - FOCUSED_WINDOW_LOCATION)) - << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + injectMotionEvent(*mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER) + .x(FOCUSED_WINDOW_LOCATION.x) + .y(FOCUSED_WINDOW_LOCATION.y)) + .build())); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(*mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_UP, + AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER) + .x(FOCUSED_WINDOW_LOCATION.x) + .y(FOCUSED_WINDOW_LOCATION.y)) + .build())); mFocusedWindow->consumeMotionDown(); + mFocusedWindow->consumeMotionUp(); mUnfocusedWindow->consumeEvent(InputEventType::MOTION, AMOTION_EVENT_ACTION_OUTSIDE, ADISPLAY_ID_DEFAULT, /*flags=*/0); // We consumed all events, so no ANR @@ -7833,17 +8000,20 @@ TEST_F(InputDispatcherMultiWindowAnr, TwoWindows_BothUnresponsive) { mFakePolicy->assertNotifyAnrWasNotCalled(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, - injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - FOCUSED_WINDOW_LOCATION)); + injectMotionEvent(*mDispatcher, + MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, + AINPUT_SOURCE_TOUCHSCREEN) + .pointer(PointerBuilder(0, ToolType::FINGER) + .x(FOCUSED_WINDOW_LOCATION.x) + .y(FOCUSED_WINDOW_LOCATION.y)) + .build())); std::optional unfocusedSequenceNum = mUnfocusedWindow->receiveEvent(); ASSERT_TRUE(unfocusedSequenceNum); const std::chrono::duration timeout = mFocusedWindow->getDispatchingTimeout(DISPATCHING_TIMEOUT); mFakePolicy->assertNotifyWindowUnresponsiveWasCalled(timeout, mFocusedWindow); - // Because we injected two DOWN events in a row, CANCEL is enqueued for the first event - // sequence to make it consistent - mFocusedWindow->consumeMotionCancel(); + mUnfocusedWindow->finishEvent(*unfocusedSequenceNum); mFocusedWindow->consumeMotionDown(); // This cancel is generated because the connection was unresponsive @@ -10356,13 +10526,12 @@ TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) { .build()); rightWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); - leftWindow->consumeMotionEvent( - AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); - spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); - spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(touchDeviceId))); + spy->assertNoEvents(); // Act: pilfer from spy. Spy is currently receiving touch events. EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); + leftWindow->consumeMotionEvent( + AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(stylusDeviceId))); rightWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_CANCEL), WithDeviceId(touchDeviceId))); @@ -10376,7 +10545,7 @@ TEST_F(InputDispatcherPilferPointersTest, MultiDevicePilfer) { .deviceId(touchDeviceId) .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(52)) .build()); - spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(touchDeviceId))); + spy->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(stylusDeviceId))); spy->assertNoEvents(); leftWindow->assertNoEvents(); -- GitLab From 69f9522d248a61a25d2ca6435c835a68a40fcba2 Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Wed, 4 Oct 2023 07:39:02 +0000 Subject: [PATCH 0860/1187] Change small area detection to support new front end design This will still use legacy layer to calculate the small dirty, and update the info to the LayerSnapshot. Also fix some issues in setIsSmallDirty() for 1. Set mSmallDirty flag as false if the surface damage region is invalid. 2. Apply the scaling to the damage region before dirty area calculations. Bug: 295062543 Bug: 303258910 Bug: 303609027 Test: atest LayerHistoryTest Test: atest SmallAreaDetectionTest Change-Id: Ib0e3737e63b5653422b5b5054b893578dc63f768 --- .../surfaceflinger/FrontEnd/LayerSnapshot.h | 2 + services/surfaceflinger/Layer.cpp | 17 +++- services/surfaceflinger/Layer.h | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 39 +++++--- .../tests/unittests/LayerHierarchyTest.h | 24 +++++ .../unittests/LayerHistoryIntegrationTest.cpp | 98 +++++++++++++++++++ .../tests/unittests/TestableScheduler.h | 5 +- .../tests/unittests/TestableSurfaceFlinger.h | 5 + 8 files changed, 173 insertions(+), 20 deletions(-) diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 80a51ea94c..1b6fdae8aa 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -122,6 +122,8 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { ReachableByRelativeParent }; Reachablilty reachablilty; + // True when the surfaceDamage is recognized as a small area update. + bool isSmallDirty = false; static bool isOpaqueFormat(PixelFormat format); static bool isTransformValid(const ui::Transform& t); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 73b1ca825f..f75f9f6d68 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -3369,7 +3369,7 @@ bool Layer::setSurfaceDamageRegion(const Region& surfaceDamage) { mDrawingState.surfaceDamageRegion = surfaceDamage; mDrawingState.modified = true; setTransactionFlags(eTransactionNeeded); - setIsSmallDirty(); + setIsSmallDirty(surfaceDamage, getTransform()); return true; } @@ -4416,7 +4416,9 @@ void Layer::updateLastLatchTime(nsecs_t latchTime) { mLastLatchTime = latchTime; } -void Layer::setIsSmallDirty() { +void Layer::setIsSmallDirty(const Region& damageRegion, + const ui::Transform& layerToDisplayTransform) { + mSmallDirty = false; if (!mFlinger->mScheduler->supportSmallDirtyDetection()) { return; } @@ -4425,17 +4427,26 @@ void Layer::setIsSmallDirty() { mWindowType != WindowInfo::Type::BASE_APPLICATION) { return; } - Rect bounds = mDrawingState.surfaceDamageRegion.getBounds(); + + Rect bounds = damageRegion.getBounds(); if (!bounds.isValid()) { return; } + // Transform to screen space. + bounds = layerToDisplayTransform.transform(bounds); + // If the damage region is a small dirty, this could give the hint for the layer history that // it could suppress the heuristic rate when calculating. mSmallDirty = mFlinger->mScheduler->isSmallDirtyArea(mOwnerAppId, bounds.getWidth() * bounds.getHeight()); } +void Layer::setIsSmallDirty(frontend::LayerSnapshot* snapshot) { + setIsSmallDirty(snapshot->surfaceDamage, snapshot->localTransform); + snapshot->isSmallDirty = mSmallDirty; +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index f67da2aee4..c042395a6d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -937,7 +937,8 @@ public: const sp mFlinger; // Check if the damage region is a small dirty. - void setIsSmallDirty(); + void setIsSmallDirty(const Region& damageRegion, const ui::Transform& layerToDisplayTransform); + void setIsSmallDirty(frontend::LayerSnapshot* snapshot); protected: // For unit tests diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b13c0e8c1f..181a9bfc36 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2211,8 +2211,29 @@ void SurfaceFlinger::updateLayerHistory(nsecs_t now) { continue; } - if (!snapshot->changes.any(Changes::FrameRate | Changes::Buffer | Changes::Animation) && - (snapshot->clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) == 0) { + const bool updateSmallDirty = mScheduler->supportSmallDirtyDetection() && + ((snapshot->clientChanges & layer_state_t::eSurfaceDamageRegionChanged) || + snapshot->changes.any(Changes::Geometry)); + + const bool hasChanges = + snapshot->changes.any(Changes::FrameRate | Changes::Buffer | Changes::Animation) || + (snapshot->clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) != + 0; + + if (!updateSmallDirty && !hasChanges) { + continue; + } + + auto it = mLegacyLayers.find(snapshot->sequence); + LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), "Couldn't find layer object for %s", + snapshot->getDebugString().c_str()); + + if (updateSmallDirty) { + // Update small dirty flag while surface damage region or geometry changed + it->second->setIsSmallDirty(snapshot.get()); + } + + if (!hasChanges) { continue; } @@ -2222,12 +2243,9 @@ void SurfaceFlinger::updateLayerHistory(nsecs_t now) { .transform = snapshot->geomLayerTransform, .setFrameRateVote = snapshot->frameRate, .frameRateSelectionPriority = snapshot->frameRateSelectionPriority, + .isSmallDirty = snapshot->isSmallDirty, }; - auto it = mLegacyLayers.find(snapshot->sequence); - LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), "Couldnt find layer object for %s", - snapshot->getDebugString().c_str()); - if (snapshot->clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) { mScheduler->setDefaultFrameRateCompatibility(snapshot->sequence, snapshot->defaultFrameRateCompatibility); @@ -8492,15 +8510,6 @@ void SurfaceFlinger::sample() { void SurfaceFlinger::onActiveDisplaySizeChanged(const DisplayDevice& activeDisplay) { mScheduler->onActiveDisplayAreaChanged(activeDisplay.getWidth() * activeDisplay.getHeight()); getRenderEngine().onActiveDisplaySizeChanged(activeDisplay.getSize()); - - // Notify layers to update small dirty flag. - if (mScheduler->supportSmallDirtyDetection()) { - mCurrentState.traverse([&](Layer* layer) { - if (layer->getLayerStack() == activeDisplay.getLayerStack()) { - layer->setIsSmallDirty(); - } - }); - } } sp SurfaceFlinger::getActivatableDisplay() const { diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index 7f3171f13f..48f8923415 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -421,6 +421,17 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setDamageRegion(uint32_t id, const Region& damageRegion) { + std::vector transactions; + 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; + mLifecycleManager.applyTransactions(transactions); + } + void setDataspace(uint32_t id, ui::Dataspace dataspace) { std::vector transactions; transactions.emplace_back(); @@ -432,6 +443,19 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setMatrix(uint32_t id, float dsdx, float dtdx, float dtdy, float dsdy) { + layer_state_t::matrix22_t matrix{dsdx, dtdx, dtdy, dsdy}; + + std::vector transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = layer_state_t::eMatrixChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.matrix = matrix; + mLifecycleManager.applyTransactions(transactions); + } + void setShadowRadius(uint32_t id, float shadowRadius) { std::vector transactions; transactions.emplace_back(); diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp index a462082141..631adf11c8 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp @@ -866,6 +866,104 @@ TEST_P(LayerHistoryIntegrationTestParameterized, HeuristicLayerWithInfrequentLay } } +class SmallAreaDetectionTest : public LayerHistoryIntegrationTest { +protected: + static constexpr int32_t DISPLAY_WIDTH = 100; + static constexpr int32_t DISPLAY_HEIGHT = 100; + + static constexpr int32_t kAppId1 = 10100; + static constexpr int32_t kAppId2 = 10101; + + static constexpr float kThreshold1 = 0.05f; + static constexpr float kThreshold2 = 0.07f; + + SmallAreaDetectionTest() : LayerHistoryIntegrationTest() { + std::vector> mappings; + mappings.reserve(2); + mappings.push_back(std::make_pair(kAppId1, kThreshold1)); + mappings.push_back(std::make_pair(kAppId2, kThreshold2)); + + mFlinger.enableNewFrontEnd(); + + mScheduler->onActiveDisplayAreaChanged(DISPLAY_WIDTH * DISPLAY_HEIGHT); + mScheduler->updateSmallAreaDetection(mappings); + } + + auto createLegacyAndFrontedEndLayer(uint32_t sequence) { + std::string layerName = "test layer:" + std::to_string(sequence); + + LayerCreationArgs args = LayerCreationArgs{mFlinger.flinger(), + nullptr, + layerName, + 0, + {}, + std::make_optional(sequence)}; + args.ownerUid = kAppId1; + args.metadata.setInt32(gui::METADATA_WINDOW_TYPE, 2); // APPLICATION + const auto layer = sp::make(args); + mFlinger.injectLegacyLayer(layer); + createRootLayer(sequence); + return layer; + } +}; + +TEST_F(SmallAreaDetectionTest, SmallDirtyLayer) { + auto layer = createLegacyAndFrontedEndLayer(1); + + nsecs_t time = systemTime(); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + + uint32_t sequence = static_cast(layer->sequence); + setBuffer(sequence); + setDamageRegion(sequence, Region(Rect(10, 10))); + updateLayerSnapshotsAndLayerHistory(time); + + ASSERT_EQ(true, mFlinger.mutableLayerSnapshotBuilder().getSnapshot(1)->isSmallDirty); +} + +TEST_F(SmallAreaDetectionTest, NotSmallDirtyLayer) { + auto layer = createLegacyAndFrontedEndLayer(1); + + nsecs_t time = systemTime(); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + + uint32_t sequence = static_cast(layer->sequence); + setBuffer(sequence); + setDamageRegion(sequence, Region(Rect(50, 50))); + updateLayerSnapshotsAndLayerHistory(time); + + ASSERT_EQ(false, mFlinger.mutableLayerSnapshotBuilder().getSnapshot(1)->isSmallDirty); +} + +TEST_F(SmallAreaDetectionTest, smallDirtyLayerWithMatrix) { + auto layer = createLegacyAndFrontedEndLayer(1); + + nsecs_t time = systemTime(); + + EXPECT_EQ(1u, layerCount()); + EXPECT_EQ(0u, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); + + // Original damage region is a small dirty. + uint32_t sequence = static_cast(layer->sequence); + setBuffer(sequence); + setDamageRegion(sequence, Region(Rect(20, 20))); + updateLayerSnapshotsAndLayerHistory(time); + ASSERT_EQ(true, mFlinger.mutableLayerSnapshotBuilder().getSnapshot(1)->isSmallDirty); + + setMatrix(sequence, 2.0f, 0, 0, 2.0f); + updateLayerSnapshotsAndLayerHistory(time); + + // Verify if the small dirty is scaled. + ASSERT_EQ(false, mFlinger.mutableLayerSnapshotBuilder().getSnapshot(1)->isSmallDirty); +} + INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryIntegrationTestParameterized, ::testing::Values(1s, 2s, 3s, 4s, 5s)); diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 014d07c38f..3d1c900dcf 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -44,7 +44,10 @@ public: TestableScheduler(std::unique_ptr controller, std::shared_ptr tracker, RefreshRateSelectorPtr selectorPtr, sp modulatorPtr, ISchedulerCallback& callback) - : Scheduler(*this, callback, Feature::kContentDetection, std::move(modulatorPtr)) { + : Scheduler(*this, callback, + (FeatureFlags)Feature::kContentDetection | + Feature::kSmallDirtyContentDetection, + std::move(modulatorPtr)) { const auto displayId = selectorPtr->getActiveMode().modePtr->getPhysicalDisplayId(); registerDisplay(displayId, std::move(selectorPtr), std::move(controller), std::move(tracker)); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 3b3942012f..8f1982d6c3 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -670,6 +670,11 @@ public: return mFlinger->initTransactionTraceWriter(); } + void enableNewFrontEnd() { + mFlinger->mLayerLifecycleManagerEnabled = true; + mFlinger->mLegacyFrontEndEnabled = false; + } + ~TestableSurfaceFlinger() { // All these pointer and container clears help ensure that GMock does // not report a leaked object, since the SurfaceFlinger instance may -- GitLab From bca8f94b73f48080e1d4fa8bc1a9a9efabf9f629 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Mon, 9 Oct 2023 17:42:37 +0000 Subject: [PATCH 0861/1187] Disable Blob outside of Android Bug: 302723053 Test: mma Change-Id: I2abc138831da28783b26efe75ee6f4583e263692 --- libs/binder/Android.bp | 16 ++++++++++++++++ libs/binder/Parcel.cpp | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index fd2b27f839..67e92ca1cb 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -358,6 +358,22 @@ cc_library_static { ], } +cc_library_static { + name: "libbinder_rpc_no_blob", + vendor_available: true, + defaults: [ + "libbinder_common_defaults", + "libbinder_android_defaults", + "libbinder_kernel_defaults", + ], + cflags: [ + "-DBINDER_DISABLE_BLOB", + ], + visibility: [ + ":__subpackages__", + ], +} + cc_library_static { name: "libbinder_rpc_single_threaded", defaults: [ diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 16944a6221..a59b9284fc 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -40,7 +40,9 @@ #include #include +#ifndef BINDER_DISABLE_BLOB #include +#endif #include #include #include @@ -1548,6 +1550,12 @@ status_t Parcel::writeUniqueFileDescriptor(const base::unique_fd& fd) { status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob) { +#ifdef BINDER_DISABLE_BLOB + (void)len; + (void)mutableCopy; + (void)outBlob; + return INVALID_OPERATION; +#else if (len > INT32_MAX) { // don't accept size_t values which may have come from an // inadvertent conversion from a negative int. @@ -1599,6 +1607,7 @@ status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob) } ::close(fd); return status; +#endif } status_t Parcel::writeDupImmutableBlobFileDescriptor(int fd) @@ -2382,6 +2391,11 @@ status_t Parcel::readUniqueParcelFileDescriptor(base::unique_fd* val) const status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const { +#ifdef BINDER_DISABLE_BLOB + (void)len; + (void)outBlob; + return INVALID_OPERATION; +#else int32_t blobType; status_t status = readInt32(&blobType); if (status) return status; @@ -2415,6 +2429,7 @@ status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const outBlob->init(fd, ptr, len, isMutable); return NO_ERROR; +#endif } status_t Parcel::read(FlattenableHelperInterface& val) const @@ -3158,6 +3173,7 @@ size_t Parcel::getOpenAshmemSize() const } size_t openAshmemSize = 0; +#ifndef BINDER_DISABLE_BLOB for (size_t i = 0; i < kernelFields->mObjectsSize; i++) { const flat_binder_object* flat = reinterpret_cast(mData + kernelFields->mObjects[i]); @@ -3172,6 +3188,7 @@ size_t Parcel::getOpenAshmemSize() const } } } +#endif return openAshmemSize; } #endif // BINDER_WITH_KERNEL_IPC -- GitLab From 6718881cfd79139d4a75b21e30a20cb7c2c32db3 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Thu, 19 Oct 2023 10:19:44 -0400 Subject: [PATCH 0862/1187] [frameworks/native] Make MemoryReporter::TraceValue own its string TraceValue had an unowned pointer to a const char (string). But there was no guarantee that the string lived long enough for TraceValue's use. Switch to an owned string type. Bug: 305919946 Test: adb shell dumpsys SurfaceFlinger Change-Id: I30b990771cc7f3ccf2769efc5aafb68c957eca9f --- .../skia/debug/SkiaMemoryReporter.cpp | 15 +++++++-------- libs/renderengine/skia/debug/SkiaMemoryReporter.h | 5 +++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libs/renderengine/skia/debug/SkiaMemoryReporter.cpp b/libs/renderengine/skia/debug/SkiaMemoryReporter.cpp index f24a4f1c05..5bf6560cad 100644 --- a/libs/renderengine/skia/debug/SkiaMemoryReporter.cpp +++ b/libs/renderengine/skia/debug/SkiaMemoryReporter.cpp @@ -18,7 +18,6 @@ #include "SkiaMemoryReporter.h" -#include #include #include @@ -142,7 +141,7 @@ void SkiaMemoryReporter::logOutput(std::string& log, bool wrappedResources) { TraceValue traceValue = convertUnits(result->second); const char* entry = (traceValue.count > 1) ? "entries" : "entry"; StringAppendF(&log, " %s: %.2f %s (%d %s)\n", categoryItem->first.c_str(), - traceValue.value, traceValue.units, traceValue.count, entry); + traceValue.value, traceValue.units.c_str(), traceValue.count, entry); } if (mItemize) { for (const auto& individualItem : resultsMap) { @@ -153,7 +152,7 @@ void SkiaMemoryReporter::logOutput(std::string& log, bool wrappedResources) { auto result = individualItem.second.find("size"); TraceValue size = convertUnits(result->second); StringAppendF(&log, " %s: size[%.2f %s]", individualItem.first.c_str(), - size.value, size.units); + size.value, size.units.c_str()); if (!wrappedResources) { for (const auto& itemValues : individualItem.second) { if (strcmp("size", itemValues.first) == 0) { @@ -162,10 +161,10 @@ void SkiaMemoryReporter::logOutput(std::string& log, bool wrappedResources) { TraceValue traceValue = convertUnits(itemValues.second); if (traceValue.value == 0.0f) { StringAppendF(&log, " %s[%s]", itemValues.first, - traceValue.units); + traceValue.units.c_str()); } else { StringAppendF(&log, " %s[%.2f %s]", itemValues.first, - traceValue.value, traceValue.units); + traceValue.value, traceValue.units.c_str()); } } } @@ -184,16 +183,16 @@ void SkiaMemoryReporter::logTotals(std::string& log) { TraceValue total = convertUnits(mTotalSize); TraceValue purgeable = convertUnits(mPurgeableSize); StringAppendF(&log, " %.0f bytes, %.2f %s (%.2f %s is purgeable)\n", mTotalSize.value, - total.value, total.units, purgeable.value, purgeable.units); + total.value, total.units.c_str(), purgeable.value, purgeable.units.c_str()); } SkiaMemoryReporter::TraceValue SkiaMemoryReporter::convertUnits(const TraceValue& value) { TraceValue output(value); - if (SkString("bytes") == SkString(output.units) && output.value >= 1024) { + if (SkString("bytes") == output.units && output.value >= 1024) { output.value = output.value / 1024.0f; output.units = "KB"; } - if (SkString("KB") == SkString(output.units) && output.value >= 1024) { + if (SkString("KB") == output.units && output.value >= 1024) { output.value = output.value / 1024.0f; output.units = "MB"; } diff --git a/libs/renderengine/skia/debug/SkiaMemoryReporter.h b/libs/renderengine/skia/debug/SkiaMemoryReporter.h index dbbd65b3da..da91674e1f 100644 --- a/libs/renderengine/skia/debug/SkiaMemoryReporter.h +++ b/libs/renderengine/skia/debug/SkiaMemoryReporter.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include @@ -75,7 +76,7 @@ private: TraceValue(const char* units, uint64_t value) : units(units), value(value), count(1) {} TraceValue(const TraceValue& v) : units(v.units), value(v.value), count(v.count) {} - const char* units; + SkString units; float value; int count; }; @@ -104,4 +105,4 @@ private: } /* namespace skia */ } /* namespace renderengine */ -} /* namespace android */ \ No newline at end of file +} /* namespace android */ -- GitLab From dac89e904f6557d60b2645ad7f17c038cd9692ac Mon Sep 17 00:00:00 2001 From: Arthur Hung Date: Thu, 19 Oct 2023 15:24:23 +0000 Subject: [PATCH 0863/1187] Rename small dirty detection flag To align the same feature name declared in display and correct the infra error for previous flag that used wrong enable flag. Bug: 283055450 Test: presubmit Change-Id: I5f495d3fb2614ecd22978d820abe19c88e2cb90b --- services/surfaceflinger/SurfaceFlinger.cpp | 2 +- .../surfaceflinger/surfaceflinger_flags.aconfig | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b13c0e8c1f..e6d6866093 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -4031,7 +4031,7 @@ void SurfaceFlinger::initScheduler(const sp& display) { if (sysprop::use_content_detection_for_refresh_rate(false)) { features |= Feature::kContentDetection; - if (flags::vrr_small_dirty_detection()) { + if (flags::enable_small_area_detection()) { features |= Feature::kSmallDirtyContentDetection; } } diff --git a/services/surfaceflinger/surfaceflinger_flags.aconfig b/services/surfaceflinger/surfaceflinger_flags.aconfig index 5a277bdc89..19d194f5b7 100644 --- a/services/surfaceflinger/surfaceflinger_flags.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags.aconfig @@ -31,14 +31,6 @@ flag { is_fixed_read_only: true } -flag { - name: "vrr_small_dirty_detection" - namespace: "core_graphics" - description: "Controls small dirty detection for VRR" - bug: "283055450" - is_fixed_read_only: true -} - flag { name: "dont_skip_on_early" namespace: "core_graphics" @@ -53,3 +45,11 @@ flag { bug: "259132483" is_fixed_read_only: true } + +flag { + name: "enable_small_area_detection" + namespace: "core_graphics" + description: "Feature flag for SmallAreaDetection" + bug: "283055450" + is_fixed_read_only: true +} \ No newline at end of file -- GitLab From 232d0b3721be5009bdbda017496ee9c205e39d23 Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Mon, 9 Oct 2023 17:37:16 +0000 Subject: [PATCH 0864/1187] Disable native_handle outside of Android Bug: 302723053 Test: mma Change-Id: Ia6d80574a3b137c7646b4a8a7575e03197fcb527 --- libs/binder/Android.bp | 16 ++++++++++++++++ libs/binder/Parcel.cpp | 4 ++++ libs/binder/include/binder/Parcel.h | 9 +++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 67e92ca1cb..620c23c1bb 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -374,6 +374,22 @@ cc_library_static { ], } +cc_library_static { + name: "libbinder_rpc_no_native_handle", + vendor_available: true, + defaults: [ + "libbinder_common_defaults", + "libbinder_android_defaults", + "libbinder_kernel_defaults", + ], + cflags: [ + "-DBINDER_DISABLE_NATIVE_HANDLE", + ], + visibility: [ + ":__subpackages__", + ], +} + cc_library_static { name: "libbinder_rpc_single_threaded", defaults: [ diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index a59b9284fc..17bdc455be 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -1436,6 +1436,7 @@ status_t Parcel::writeRawNullableParcelable(const Parcelable* parcelable) { return writeParcelable(*parcelable); } +#ifndef BINDER_DISABLE_NATIVE_HANDLE status_t Parcel::writeNativeHandle(const native_handle* handle) { if (!handle || handle->version != sizeof(native_handle)) @@ -1458,6 +1459,7 @@ status_t Parcel::writeNativeHandle(const native_handle* handle) err = write(handle->data + handle->numFds, sizeof(int)*handle->numInts); return err; } +#endif status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership) { if (auto* rpcFields = maybeRpcFields()) { @@ -2239,6 +2241,7 @@ int32_t Parcel::readExceptionCode() const return status.exceptionCode(); } +#ifndef BINDER_DISABLE_NATIVE_HANDLE native_handle* Parcel::readNativeHandle() const { int numFds, numInts; @@ -2271,6 +2274,7 @@ native_handle* Parcel::readNativeHandle() const } return h; } +#endif int Parcel::readFileDescriptor() const { if (const auto* rpcFields = maybeRpcFields()) { diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index b94267c360..98d12bb120 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -26,7 +26,9 @@ #include #include +#ifndef BINDER_DISABLE_NATIVE_HANDLE #include +#endif #include #include #include @@ -324,11 +326,13 @@ public: template status_t writeVectorSize(const std::unique_ptr>& val) __attribute__((deprecated("use std::optional version instead"))); +#ifndef BINDER_DISABLE_NATIVE_HANDLE // Place a native_handle into the parcel (the native_handle's file- // descriptors are dup'ed, so it is safe to delete the native_handle // when this function returns). // Doesn't take ownership of the native_handle. status_t writeNativeHandle(const native_handle* handle); +#endif // Place a file descriptor into the parcel. The given fd must remain // valid for the lifetime of the parcel. @@ -559,13 +563,14 @@ public: // response headers rather than doing it by hand. int32_t readExceptionCode() const; +#ifndef BINDER_DISABLE_NATIVE_HANDLE // Retrieve native_handle from the parcel. This returns a copy of the // parcel's native_handle (the caller takes ownership). The caller - // must free the native_handle with native_handle_close() and + // must free the native_handle with native_handle_close() and // native_handle_delete(). native_handle* readNativeHandle() const; +#endif - // Retrieve a file descriptor from the parcel. This returns the raw fd // in the parcel, which you do not own -- use dup() to get your own copy. int readFileDescriptor() const; -- GitLab From c7aa7ed75d9894babc0721d97e4c04f0de4e208b Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Mon, 31 Jul 2023 15:35:42 +0000 Subject: [PATCH 0865/1187] [Cherry-pick] Revert^2 "Revert "Load native GLES driver when specified."" Revert reason: PcmaPhotoEditingV3 regressed, see b/293486861. Original change id: I6a2e716d340d9be3610c31abbcbe7984bf472f9f Bug: b/283858001 Bug: b/293486861 Test: atest CtsAngleDeveloperOptionHostTest -c with ANGLE being default Test: atest CtsAngleDeveloperOptionHostTest -c with native being default Change-Id: Id08acb6e18db095c632aa8d1a7810ede0c1a1ad2 Merged-In: Id08acb6e18db095c632aa8d1a7810ede0c1a1ad2 --- libs/graphicsenv/GraphicsEnv.cpp | 19 ++---------- .../include/graphicsenv/GraphicsEnv.h | 8 +---- opengl/libs/EGL/Loader.cpp | 29 ++++--------------- 3 files changed, 10 insertions(+), 46 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index ed5d5c1095..0a5416128e 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -530,11 +530,7 @@ bool GraphicsEnv::shouldUseAngle() { return mShouldUseAngle; } -// Set ANGLE information. -// If path is "system", it means system ANGLE must be used for the process. -// If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. -// If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. -void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, +void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSystemAngle, const std::string& packageName, const std::vector eglFeatures) { if (mShouldUseAngle) { @@ -551,13 +547,8 @@ void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNati mAnglePath = std::move(path); ALOGV("setting app package name to '%s'", packageName.c_str()); mPackageName = std::move(packageName); - if (mAnglePath == "system") { - mShouldUseSystemAngle = true; - } - if (!mAnglePath.empty()) { - mShouldUseAngle = true; - } - mShouldUseNativeDriver = shouldUseNativeDriver; + mShouldUseAngle = true; + mShouldUseSystemAngle = shouldUseSystemAngle; } std::string& GraphicsEnv::getPackageName() { @@ -634,10 +625,6 @@ bool GraphicsEnv::shouldUseSystemAngle() { return mShouldUseSystemAngle; } -bool GraphicsEnv::shouldUseNativeDriver() { - return mShouldUseNativeDriver; -} - /** * APIs for debuggable layers */ diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index 6cce3f6998..fbf2902869 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -108,10 +108,7 @@ public: // (libraries must be stored uncompressed and page aligned); such elements // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a - // If the search patch is "system", then it means the system ANGLE should be used. - // If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. - // If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. - void setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, + void setAngleInfo(const std::string& path, const bool useSystemAngle, const std::string& packageName, const std::vector eglFeatures); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); @@ -121,7 +118,6 @@ public: // Set the persist.graphics.egl system property value. void nativeToggleAngleAsSystemDriver(bool enabled); bool shouldUseSystemAngle(); - bool shouldUseNativeDriver(); /* * Apis for debug layer @@ -179,8 +175,6 @@ private: bool mShouldUseAngle = false; // Whether loader should load system ANGLE. bool mShouldUseSystemAngle = false; - // Whether loader should load native GLES driver. - bool mShouldUseNativeDriver = false; // ANGLE namespace. android_namespace_t* mAngleNamespace = nullptr; diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 654e5b7c03..8d0eb590bf 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -169,11 +169,6 @@ static bool should_unload_system_driver(egl_connection_t* cnx) { } } - // Return true if native GLES drivers should be used and ANGLE is already loaded. - if (android::GraphicsEnv::getInstance().shouldUseNativeDriver() && cnx->angleLoaded) { - return true; - } - // Return true if updated driver namespace is set. ns = android::GraphicsEnv::getInstance().getDriverNamespace(); if (ns) { @@ -245,28 +240,16 @@ void* Loader::open(egl_connection_t* cnx) { if (!hnd) { // Secondly, try to load from driver apk. hnd = attempt_to_load_updated_driver(cnx); - - // If updated driver apk is set but fail to load, abort here. - LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace(), - "couldn't find an OpenGL ES implementation from %s", - android::GraphicsEnv::getInstance().getDriverPath().c_str()); } - // Attempt to load native GLES drivers specified by ro.hardware.egl if native is selected. - // If native is selected but fail to load, abort. - if (!hnd && android::GraphicsEnv::getInstance().shouldUseNativeDriver()) { - auto driverSuffix = base::GetProperty(RO_DRIVER_SUFFIX_PROPERTY, ""); - LOG_ALWAYS_FATAL_IF(driverSuffix.empty(), - "Native GLES driver is selected but not specified in %s", - RO_DRIVER_SUFFIX_PROPERTY); - hnd = attempt_to_load_system_driver(cnx, driverSuffix.c_str(), true); - LOG_ALWAYS_FATAL_IF(!hnd, "Native GLES driver is selected but failed to load. %s=%s", - RO_DRIVER_SUFFIX_PROPERTY, driverSuffix.c_str()); - } - - // Finally, try to load default driver. bool failToLoadFromDriverSuffixProperty = false; if (!hnd) { + // If updated driver apk is set but fail to load, abort here. + if (android::GraphicsEnv::getInstance().getDriverNamespace()) { + LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s", + android::GraphicsEnv::getInstance().getDriverPath().c_str()); + } + // Finally, try to load system driver. // Start by searching for the library name appended by the system // properties of the GLES userspace driver in both locations. // i.e.: -- GitLab From 38a22eebdedb81043c694b6d07329188a9c4148a Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Thu, 19 Oct 2023 20:04:46 +0000 Subject: [PATCH 0866/1187] Don't include AIDL NDK output if not needed Bug: 302724232 Test: mma Change-Id: Ibdc5a0f58dd4adb3aaf64b9176b1b6e545318e08 --- libs/binder/tests/binderRpcTest.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 5884dbe66f..1340ea1d2c 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -14,7 +14,10 @@ * limitations under the License. */ +#ifndef __ANDROID_VENDOR__ +// only used on NDK tests outside of vendor #include +#endif #include #include -- GitLab From 2df5a0080467a19b23952b402cb00f84186256b4 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Tue, 1 Aug 2023 23:31:34 +0000 Subject: [PATCH 0867/1187] [Cherry-pick] Revert^3 "Revert "Load native GLES driver when specified."" Reason for revert: Revert to reland the patch. Original patch was reverted due to PcmaPhotoEditingV3 regression, see b/293486861. Original commit message: """ Load native GLES driver when specified. Since ANGLE and native GLES drivers can coexist, when native is specified, the loader must load the native GLES drivers specified in ro.hardware.egl. This patch passes this information down to the native graphics environment so that the EGL loader can properly check. Bug: b/283858001 Test: atest CtsAngleDeveloperOptionHostTest -c with ANGLE being default Test: atest CtsAngleDeveloperOptionHostTest -c with native being default """ Bug: b/283858001 Test: atest CtsAngleDeveloperOptionHostTest -c with ANGLE being default Test: atest CtsAngleDeveloperOptionHostTest -c with native being default Change-Id: Ibcf9d765ce1bd8931859d1c11e849a311adda172 Merged-In: Ibcf9d765ce1bd8931859d1c11e849a311adda172 --- libs/graphicsenv/GraphicsEnv.cpp | 19 ++++++++++-- .../include/graphicsenv/GraphicsEnv.h | 8 ++++- opengl/libs/EGL/Loader.cpp | 29 +++++++++++++++---- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 0a5416128e..ed5d5c1095 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -530,7 +530,11 @@ bool GraphicsEnv::shouldUseAngle() { return mShouldUseAngle; } -void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSystemAngle, +// Set ANGLE information. +// If path is "system", it means system ANGLE must be used for the process. +// If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. +// If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. +void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, const std::string& packageName, const std::vector eglFeatures) { if (mShouldUseAngle) { @@ -547,8 +551,13 @@ void GraphicsEnv::setAngleInfo(const std::string& path, const bool shouldUseSyst mAnglePath = std::move(path); ALOGV("setting app package name to '%s'", packageName.c_str()); mPackageName = std::move(packageName); - mShouldUseAngle = true; - mShouldUseSystemAngle = shouldUseSystemAngle; + if (mAnglePath == "system") { + mShouldUseSystemAngle = true; + } + if (!mAnglePath.empty()) { + mShouldUseAngle = true; + } + mShouldUseNativeDriver = shouldUseNativeDriver; } std::string& GraphicsEnv::getPackageName() { @@ -625,6 +634,10 @@ bool GraphicsEnv::shouldUseSystemAngle() { return mShouldUseSystemAngle; } +bool GraphicsEnv::shouldUseNativeDriver() { + return mShouldUseNativeDriver; +} + /** * APIs for debuggable layers */ diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index fbf2902869..6cce3f6998 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -108,7 +108,10 @@ public: // (libraries must be stored uncompressed and page aligned); such elements // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a - void setAngleInfo(const std::string& path, const bool useSystemAngle, + // If the search patch is "system", then it means the system ANGLE should be used. + // If shouldUseNativeDriver is true, it means native GLES drivers must be used for the process. + // If path is set to nonempty and shouldUseNativeDriver is true, ANGLE will be used regardless. + void setAngleInfo(const std::string& path, const bool shouldUseNativeDriver, const std::string& packageName, const std::vector eglFeatures); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); @@ -118,6 +121,7 @@ public: // Set the persist.graphics.egl system property value. void nativeToggleAngleAsSystemDriver(bool enabled); bool shouldUseSystemAngle(); + bool shouldUseNativeDriver(); /* * Apis for debug layer @@ -175,6 +179,8 @@ private: bool mShouldUseAngle = false; // Whether loader should load system ANGLE. bool mShouldUseSystemAngle = false; + // Whether loader should load native GLES driver. + bool mShouldUseNativeDriver = false; // ANGLE namespace. android_namespace_t* mAngleNamespace = nullptr; diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 8d0eb590bf..654e5b7c03 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -169,6 +169,11 @@ static bool should_unload_system_driver(egl_connection_t* cnx) { } } + // Return true if native GLES drivers should be used and ANGLE is already loaded. + if (android::GraphicsEnv::getInstance().shouldUseNativeDriver() && cnx->angleLoaded) { + return true; + } + // Return true if updated driver namespace is set. ns = android::GraphicsEnv::getInstance().getDriverNamespace(); if (ns) { @@ -240,16 +245,28 @@ void* Loader::open(egl_connection_t* cnx) { if (!hnd) { // Secondly, try to load from driver apk. hnd = attempt_to_load_updated_driver(cnx); + + // If updated driver apk is set but fail to load, abort here. + LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace(), + "couldn't find an OpenGL ES implementation from %s", + android::GraphicsEnv::getInstance().getDriverPath().c_str()); } + // Attempt to load native GLES drivers specified by ro.hardware.egl if native is selected. + // If native is selected but fail to load, abort. + if (!hnd && android::GraphicsEnv::getInstance().shouldUseNativeDriver()) { + auto driverSuffix = base::GetProperty(RO_DRIVER_SUFFIX_PROPERTY, ""); + LOG_ALWAYS_FATAL_IF(driverSuffix.empty(), + "Native GLES driver is selected but not specified in %s", + RO_DRIVER_SUFFIX_PROPERTY); + hnd = attempt_to_load_system_driver(cnx, driverSuffix.c_str(), true); + LOG_ALWAYS_FATAL_IF(!hnd, "Native GLES driver is selected but failed to load. %s=%s", + RO_DRIVER_SUFFIX_PROPERTY, driverSuffix.c_str()); + } + + // Finally, try to load default driver. bool failToLoadFromDriverSuffixProperty = false; if (!hnd) { - // If updated driver apk is set but fail to load, abort here. - if (android::GraphicsEnv::getInstance().getDriverNamespace()) { - LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s", - android::GraphicsEnv::getInstance().getDriverPath().c_str()); - } - // Finally, try to load system driver. // Start by searching for the library name appended by the system // properties of the GLES userspace driver in both locations. // i.e.: -- GitLab From 3802726f3c4b8ec0bbe51110cb2640daa25d8687 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 17 Oct 2023 16:58:25 -0700 Subject: [PATCH 0868/1187] SF: add the ability to specify render fps to 1035 Test: adb shell service call SurfaceFlinger 1035 i32 1 i64 4619827677550801152 f 30 f 60 Change-Id: I6bc0705d870f47e69fefa2dfbd2a08ef46b11228 --- services/surfaceflinger/SurfaceFlinger.cpp | 29 +++++++++++++++++++--- services/surfaceflinger/SurfaceFlinger.h | 3 ++- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b13c0e8c1f..c2e704ce6f 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1232,7 +1232,7 @@ void SurfaceFlinger::setDesiredActiveMode(display::DisplayModeRequest&& request, } status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp& displayToken, - DisplayModeId modeId) { + DisplayModeId modeId, Fps minFps, Fps maxFps) { ATRACE_CALL(); if (!displayToken) { @@ -1265,13 +1265,15 @@ status_t SurfaceFlinger::setActiveModeFromBackdoor(const sprefreshRateSelector().getCurrentPolicy().allowGroupSwitching; - const scheduler::RefreshRateSelector::DisplayManagerPolicy policy{modeId, - {fps, fps}, + const scheduler::RefreshRateSelector::DisplayManagerPolicy policy{modeId, ranges, ranges, allowGroupSwitching}; return setDesiredDisplayModeSpecsInternal(display, policy); @@ -6932,6 +6934,12 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return NO_ERROR; } case 1035: { + // Parameters: + // - (required) i32 mode id. + // - (optional) i64 display id. Using default display if not provided. + // - (optional) f min render rate. Using mode's fps is not provided. + // - (optional) f max render rate. Using mode's fps is not provided. + const int modeId = data.readInt32(); const auto display = [&]() -> sp { @@ -6948,8 +6956,21 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r return nullptr; }(); + const auto getFps = [&] { + float value; + if (data.readFloat(&value) == NO_ERROR) { + return Fps::fromValue(value); + } + + return Fps(); + }; + + const auto minFps = getFps(); + const auto maxFps = getFps(); + mDebugDisplayModeSetByBackdoor = false; - const status_t result = setActiveModeFromBackdoor(display, DisplayModeId{modeId}); + const status_t result = + setActiveModeFromBackdoor(display, DisplayModeId{modeId}, minFps, maxFps); mDebugDisplayModeSetByBackdoor = result == NO_ERROR; return result; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 7500b96c8c..96b67b8176 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -684,7 +684,8 @@ private: void setDesiredActiveMode(display::DisplayModeRequest&&, bool force = false) REQUIRES(mStateLock); - status_t setActiveModeFromBackdoor(const sp&, DisplayModeId); + status_t setActiveModeFromBackdoor(const sp&, DisplayModeId, Fps minFps, + Fps maxFps); void initiateDisplayModeChanges() REQUIRES(mStateLock, kMainThreadContext); void finalizeDisplayModeChange(DisplayDevice&) REQUIRES(mStateLock, kMainThreadContext); -- GitLab From 30515cb768dad2e39c484d65183e123888332c78 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 19 Oct 2023 21:54:08 -0700 Subject: [PATCH 0869/1187] Propagate frame rate correctly to child layers If a child layer has a valid frame rate, and its parent does not have a valid frame rate, we need to override the parent's frame rate to no vote. If the parent has a valid vote, including no vote, children would inherit this vote if it has no valid vote. When we were updating the hierarchy, we incorrectly propagated novote due to a child having a novote to all its siblings in the tree. Fix this by tracking inherited frame rate separately. Bug: 304208511 Test: presubmit Change-Id: I873e75d678fba8c8217a1887f48726d1e4828049 --- .../surfaceflinger/FrontEnd/LayerSnapshot.h | 1 + .../FrontEnd/LayerSnapshotBuilder.cpp | 11 +++-- .../tests/unittests/LayerSnapshotTest.cpp | 48 ++++++++++++++----- 3 files changed, 46 insertions(+), 14 deletions(-) diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h index 80a51ea94c..59ccf96e10 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h @@ -84,6 +84,7 @@ struct LayerSnapshot : public compositionengine::LayerFECompositionState { bool isTrustedOverlay; gui::GameMode gameMode; scheduler::LayerInfo::FrameRate frameRate; + scheduler::LayerInfo::FrameRate inheritedFrameRate; scheduler::LayerInfo::FrameRateSelectionStrategy frameRateSelectionStrategy; scheduler::FrameRateCompatibility defaultFrameRateCompatibility = scheduler::FrameRateCompatibility::Default; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 4db2b669a5..2a0857d4dd 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -815,9 +815,14 @@ void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& a RequestedLayerState::Changes::Hierarchy)) { bool shouldOverrideChildren = parentSnapshot.frameRateSelectionStrategy == scheduler::LayerInfo::FrameRateSelectionStrategy::OverrideChildren; - snapshot.frameRate = !requested.requestedFrameRate.isValid() || shouldOverrideChildren - ? parentSnapshot.frameRate - : requested.requestedFrameRate; + if (!requested.requestedFrameRate.isValid() || shouldOverrideChildren) { + snapshot.inheritedFrameRate = parentSnapshot.inheritedFrameRate; + } else { + snapshot.inheritedFrameRate = requested.requestedFrameRate; + } + // Set the framerate as the inherited frame rate and allow children to override it if + // needed. + snapshot.frameRate = snapshot.inheritedFrameRate; snapshot.changes |= RequestedLayerState::Changes::FrameRate; } diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index fc4bb229be..e784eb76f3 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -282,25 +282,51 @@ TEST_F(LayerSnapshotTest, NoLayerVoteForParentWithChildVotes) { // │ └── 13 // └── 2 - std::vector transactions; - transactions.emplace_back(); - transactions.back().states.push_back({}); - transactions.back().states.front().state.what = layer_state_t::eFrameRateChanged; - transactions.back().states.front().state.frameRate = 90.0; - transactions.back().states.front().state.frameRateCompatibility = - ANATIVEWINDOW_FRAME_RATE_EXACT; - transactions.back().states.front().state.changeFrameRateStrategy = - ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS; - transactions.back().states.front().layerId = 11; - mLifecycleManager.applyTransactions(transactions); + setFrameRate(11, 90.0, ANATIVEWINDOW_FRAME_RATE_EXACT, ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + + EXPECT_EQ(getSnapshot(11)->frameRate.vote.rate.getIntValue(), 90); + EXPECT_EQ(getSnapshot(11)->frameRate.vote.type, scheduler::FrameRateCompatibility::Exact); + EXPECT_EQ(getSnapshot(111)->frameRate.vote.rate.getIntValue(), 90); + EXPECT_EQ(getSnapshot(111)->frameRate.vote.type, scheduler::FrameRateCompatibility::Exact); + EXPECT_EQ(getSnapshot(1)->frameRate.vote.rate.getIntValue(), 0); + EXPECT_EQ(getSnapshot(1)->frameRate.vote.type, scheduler::FrameRateCompatibility::NoVote); +} + +TEST_F(LayerSnapshotTest, NoLayerVoteForParentWithChildVotesDoesNotAffectSiblings) { + // ROOT + // ├── 1 (verify layer has no vote) + // │ ├── 11 (frame rate set) + // │ │ └── 111 + // │ ├── 12 (frame rate set) + // │ │ ├── 121 + // │ │ └── 122 + // │ │ └── 1221 + // │ └── 13 (verify layer has default vote) + // └── 2 + + setFrameRate(11, 90.0, ANATIVEWINDOW_FRAME_RATE_EXACT, ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS); + setFrameRate(12, 45.0, ANATIVEWINDOW_FRAME_RATE_EXACT, ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); EXPECT_EQ(getSnapshot(11)->frameRate.vote.rate.getIntValue(), 90); EXPECT_EQ(getSnapshot(11)->frameRate.vote.type, scheduler::FrameRateCompatibility::Exact); EXPECT_EQ(getSnapshot(111)->frameRate.vote.rate.getIntValue(), 90); EXPECT_EQ(getSnapshot(111)->frameRate.vote.type, scheduler::FrameRateCompatibility::Exact); + EXPECT_EQ(getSnapshot(12)->frameRate.vote.rate.getIntValue(), 45); + EXPECT_EQ(getSnapshot(12)->frameRate.vote.type, scheduler::FrameRateCompatibility::Exact); + EXPECT_EQ(getSnapshot(121)->frameRate.vote.rate.getIntValue(), 45); + EXPECT_EQ(getSnapshot(121)->frameRate.vote.type, scheduler::FrameRateCompatibility::Exact); + EXPECT_EQ(getSnapshot(1221)->frameRate.vote.rate.getIntValue(), 45); + EXPECT_EQ(getSnapshot(1221)->frameRate.vote.type, scheduler::FrameRateCompatibility::Exact); + EXPECT_EQ(getSnapshot(1)->frameRate.vote.rate.getIntValue(), 0); EXPECT_EQ(getSnapshot(1)->frameRate.vote.type, scheduler::FrameRateCompatibility::NoVote); + EXPECT_EQ(getSnapshot(13)->frameRate.vote.rate.getIntValue(), 0); + EXPECT_EQ(getSnapshot(13)->frameRate.vote.type, scheduler::FrameRateCompatibility::Default); + EXPECT_EQ(getSnapshot(2)->frameRate.vote.rate.getIntValue(), 0); + EXPECT_EQ(getSnapshot(2)->frameRate.vote.type, scheduler::FrameRateCompatibility::Default); } TEST_F(LayerSnapshotTest, CanCropTouchableRegion) { -- GitLab From f1d48af0002a89aa933bdb732a19883f9ada5563 Mon Sep 17 00:00:00 2001 From: Vladimir Komsiyski Date: Fri, 6 Oct 2023 10:11:44 +0200 Subject: [PATCH 0870/1187] Device-aware native SensorManager. Add device id to SensorManager instances based on the devices this UID is present on. SensorManager queries the native VDM instance for the deviceId and the sensor policy of that device. If the UID is present only on a single virtual device and that device has custom sensors, then give it that device's sensors by default. If the UID is not on any virtual devices or is on more than one, then give it the default device's sensors. Fix: 303535376 Test: manual with streamed app using sensor NDK to a virtual device Change-Id: I275a010a7a70b34176deaf4c9dcd61188c83ac32 --- libs/sensor/Android.bp | 1 + libs/sensor/SensorManager.cpp | 58 +++++++++++++++++-- libs/sensor/include/sensor/SensorManager.h | 3 +- services/sensorservice/aidl/fuzzer/Android.bp | 1 + 4 files changed, 57 insertions(+), 6 deletions(-) diff --git a/libs/sensor/Android.bp b/libs/sensor/Android.bp index b6b9cc4099..d992aa5105 100644 --- a/libs/sensor/Android.bp +++ b/libs/sensor/Android.bp @@ -49,6 +49,7 @@ cc_library { "liblog", "libhardware", "libpermission", + "android.companion.virtual.virtualdevice_aidl-cpp", ], export_include_dirs: ["include"], diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp index 980f8d16d2..f3de2efb96 100644 --- a/libs/sensor/SensorManager.cpp +++ b/libs/sensor/SensorManager.cpp @@ -26,6 +26,8 @@ #include #include +#include + #include #include #include @@ -39,6 +41,43 @@ namespace android { // ---------------------------------------------------------------------------- +namespace { + +using ::android::companion::virtualnative::IVirtualDeviceManagerNative; + +static constexpr int DEVICE_ID_DEFAULT = 0; + +// Returns the deviceId of the device where this uid is observed. If the uid is present on more than +// one devices, return the default deviceId. +int getDeviceIdForUid(uid_t uid) { + sp binder = + defaultServiceManager()->checkService(String16("virtualdevice_native")); + if (binder != nullptr) { + auto vdm = interface_cast(binder); + std::vector deviceIds; + vdm->getDeviceIdsForUid(uid, &deviceIds); + // If the UID is associated with multiple virtual devices, use the default device's + // sensors as we cannot disambiguate here. This effectively means that the app has + // activities on different devices at the same time, so it must handle the device + // awareness by itself. + if (deviceIds.size() == 1) { + const int deviceId = deviceIds.at(0); + int devicePolicy = IVirtualDeviceManagerNative::DEVICE_POLICY_DEFAULT; + vdm->getDevicePolicy(deviceId, + IVirtualDeviceManagerNative::POLICY_TYPE_SENSORS, + &devicePolicy); + if (devicePolicy == IVirtualDeviceManagerNative::DEVICE_POLICY_CUSTOM) { + return deviceId; + } + } + } else { + ALOGW("Cannot get virtualdevice_native service"); + } + return DEVICE_ID_DEFAULT; +} + +} // namespace + Mutex SensorManager::sLock; std::map SensorManager::sPackageInstances; @@ -53,6 +92,7 @@ SensorManager& SensorManager::getInstanceForPackage(const String16& packageName) sensorManager = iterator->second; } else { String16 opPackageName = packageName; + const uid_t uid = IPCThreadState::self()->getCallingUid(); // It is possible that the calling code has no access to the package name. // In this case we will get the packages for the calling UID and pick the @@ -63,7 +103,6 @@ SensorManager& SensorManager::getInstanceForPackage(const String16& packageName) if (opPackageName.size() <= 0) { sp binder = defaultServiceManager()->getService(String16("permission")); if (binder != nullptr) { - const uid_t uid = IPCThreadState::self()->getCallingUid(); Vector packages; interface_cast(binder)->getPackagesForUid(uid, packages); if (!packages.isEmpty()) { @@ -76,7 +115,10 @@ SensorManager& SensorManager::getInstanceForPackage(const String16& packageName) } } - sensorManager = new SensorManager(opPackageName); + // Check if the calling UID is observed on a virtual device. If so, provide that device's + // sensors by default instead of the default device's sensors. + const int deviceId = getDeviceIdForUid(uid); + sensorManager = new SensorManager(opPackageName, deviceId); // If we had no package name, we looked it up from the UID and the sensor // manager instance we created should also be mapped to the empty package @@ -102,8 +144,9 @@ void SensorManager::removeInstanceForPackage(const String16& packageName) { } } -SensorManager::SensorManager(const String16& opPackageName) - : mSensorList(nullptr), mOpPackageName(opPackageName), mDirectConnectionHandle(1) { +SensorManager::SensorManager(const String16& opPackageName, int deviceId) + : mSensorList(nullptr), mOpPackageName(opPackageName), mDeviceId(deviceId), + mDirectConnectionHandle(1) { Mutex::Autolock _l(mLock); assertStateLocked(); } @@ -174,7 +217,12 @@ status_t SensorManager::assertStateLocked() { mDeathObserver = new DeathObserver(*const_cast(this)); IInterface::asBinder(mSensorServer)->linkToDeath(mDeathObserver); - mSensors = mSensorServer->getSensorList(mOpPackageName); + if (mDeviceId == DEVICE_ID_DEFAULT) { + mSensors = mSensorServer->getSensorList(mOpPackageName); + } else { + mSensors = mSensorServer->getRuntimeSensorList(mOpPackageName, mDeviceId); + } + size_t count = mSensors.size(); // If count is 0, mSensorList will be non-null. This is old // existing behavior and callers expect this. diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h index bb44cb8869..432983ce0f 100644 --- a/libs/sensor/include/sensor/SensorManager.h +++ b/libs/sensor/include/sensor/SensorManager.h @@ -77,7 +77,7 @@ private: void sensorManagerDied(); static status_t waitForSensorService(sp *server); - explicit SensorManager(const String16& opPackageName); + explicit SensorManager(const String16& opPackageName, int deviceId); status_t assertStateLocked(); private: @@ -92,6 +92,7 @@ private: Vector mDynamicSensors; sp mDeathObserver; const String16 mOpPackageName; + const int mDeviceId; std::unordered_map> mDirectConnection; int32_t mDirectConnectionHandle; }; diff --git a/services/sensorservice/aidl/fuzzer/Android.bp b/services/sensorservice/aidl/fuzzer/Android.bp index 6870d4e539..f6f104ee88 100644 --- a/services/sensorservice/aidl/fuzzer/Android.bp +++ b/services/sensorservice/aidl/fuzzer/Android.bp @@ -17,6 +17,7 @@ cc_fuzz { static_libs: [ "libsensorserviceaidl", "libpermission", + "android.companion.virtual.virtualdevice_aidl-cpp", "android.frameworks.sensorservice-V1-ndk", "android.hardware.sensors-V1-convert", "android.hardware.sensors-V2-ndk", -- GitLab From c34489c91ed1d589045b73156d8875994de1ae2b Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Fri, 20 Oct 2023 13:52:29 +0000 Subject: [PATCH 0871/1187] Fix file permissions of generated layers trace Fix: 305129514 Test: adb shell rm /data/misc/wmtrace/layers_trace_from_transactions.winscope \ && adb bugreport \ && check generated bugreport contains FS/data/misc/wmtrace/layers_trace_from_transactions.winscope Change-Id: I7cf087265df9ce1cc5da8536d6b03285685cd26e --- services/surfaceflinger/Tracing/tools/main.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/services/surfaceflinger/Tracing/tools/main.cpp b/services/surfaceflinger/Tracing/tools/main.cpp index 698ef06534..18022b1697 100644 --- a/services/surfaceflinger/Tracing/tools/main.cpp +++ b/services/surfaceflinger/Tracing/tools/main.cpp @@ -64,8 +64,17 @@ int main(int argc, char** argv) { if (!LayerTraceGenerator().generate(transactionTraceFile, traceFlags, layerTracing, generateLastEntryOnly)) { - std::cout << "Error: Failed to generate layers trace " << outputLayersTracePath; + std::cout << "Error: Failed to generate layers trace " << outputLayersTracePath << "\n"; return -1; } + + // Set output file permissions (-rw-r--r--) + outStream.close(); + const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + if (chmod(outputLayersTracePath, mode) != 0) { + std::cout << "Error: Failed to set permissions of " << outputLayersTracePath << "\n"; + return -1; + } + return 0; } -- GitLab From 8b5c6bd000352c77007c1f00b966b9de957d757e Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Wed, 20 Sep 2023 06:50:41 +0000 Subject: [PATCH 0872/1187] Add layer tracing's MODE_GENERATED_BUGREPORT_ONLY The generated layers trace can be quite large (100-400 MB), which is way above the perfetto's field upload budget. On the field (AOT) we want the layers trace to be generated only when a bugreport is taken and not when a perfetto's field upload happens. We achieve it as follows: - In the AOT configuration, enable the 'android.surfaceflinger_layers' data source with MODE_GENERATED_BUGREPORT_ONLY. - When LayerTracing receives perfetto's OnFlush event and MODE_GENERATED_BUGREPORT_ONLY is enabled, generate the layers trace only if the OnFlush event is due to a bugreport being taken: args.flush_flags.reason() == perfetto::FlushFlags::Reason::kTraceClone && args.flush_flags.clone_target() == perfetto::FlushFlags::CloneTarget::kBugreport In a test environment instead, we can use MODE_GENERATED to test the layers trace generation without having to take a bugreport. Bug: b/293429094 Test: 1. Manually start the perfetto's android.surfaceflinger_layers data source with MODE_GENERATED_BUGREPORT_ONLY setting a high bugreport_score (e.g. 50000) 2. Take a bugreport (adb bugreport) 3. Verify that FS/data/misc/perfetto-traces/bugreport/systrace.pftrace (in the bugreport) contains the generated layers trace. E.g. inspect bugreport with go/winscope. Change-Id: I5b3ce59cc762fd5a22170e677e48be987380c94e --- .../Tracing/LayerDataSource.cpp | 17 +++++-- .../surfaceflinger/Tracing/LayerTracing.cpp | 49 ++++++++++++++++--- .../surfaceflinger/Tracing/LayerTracing.h | 8 +-- 3 files changed, 59 insertions(+), 15 deletions(-) diff --git a/services/surfaceflinger/Tracing/LayerDataSource.cpp b/services/surfaceflinger/Tracing/LayerDataSource.cpp index 25e768e0ca..ed1e2ec89c 100644 --- a/services/surfaceflinger/Tracing/LayerDataSource.cpp +++ b/services/surfaceflinger/Tracing/LayerDataSource.cpp @@ -51,8 +51,9 @@ void LayerDataSource::OnSetup(const LayerDataSource::SetupArgs& args) { if (config.has_mode() && config.mode() != LayerTracing::Mode::MODE_UNSPECIFIED) { mMode = static_cast(config.mode()); } else { - mMode = LayerTracing::Mode::MODE_GENERATED; - ALOGD("Received config with unspecified 'mode'. Using 'GENERATED' as default"); + mMode = LayerTracing::Mode::MODE_GENERATED_BUGREPORT_ONLY; + ALOGD("Received config with unspecified 'mode'." + " Using 'MODE_GENERATED_BUGREPORT_ONLY' as default"); } mFlags = 0; @@ -68,10 +69,16 @@ void LayerDataSource::OnStart(const LayerDataSource::StartArgs&) { } } -void LayerDataSource::OnFlush(const LayerDataSource::FlushArgs&) { - ALOGD("Received OnFlush event (mode = 0x%02x, flags = 0x%02x)", mMode, mFlags); +void LayerDataSource::OnFlush(const LayerDataSource::FlushArgs& args) { + ALOGD("Received OnFlush event" + " (mode = 0x%02x, flags = 0x%02x, reason = 0x%" PRIx64 ", clone_target = 0x%0" PRIx64 ")", + mMode, mFlags, args.flush_flags.reason(), args.flush_flags.clone_target()); + + bool isBugreport = args.flush_flags.reason() == perfetto::FlushFlags::Reason::kTraceClone && + args.flush_flags.clone_target() == perfetto::FlushFlags::CloneTarget::kBugreport; + if (auto* p = mLayerTracing.load()) { - p->onFlush(mMode, mFlags); + p->onFlush(mMode, mFlags, isBugreport); } } diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp index 403e1050d1..41bcdf05c3 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.cpp +++ b/services/surfaceflinger/Tracing/LayerTracing.cpp @@ -67,9 +67,27 @@ void LayerTracing::onStart(Mode mode, uint32_t flags) { break; } case Mode::MODE_GENERATED: { + // This tracing mode processes the buffer of transactions (owned by TransactionTracing), + // generates layers snapshots and writes them to perfetto. This happens every time an + // OnFlush event is received. ALOGD("Started generated tracing (waiting for OnFlush event to generated layers)"); break; } + case Mode::MODE_GENERATED_BUGREPORT_ONLY: { + // Same as MODE_GENERATED, but only when the received OnFlush event is due to a + // bugreport being taken. This mode exists because the generated layers trace is very + // large (hundreds of MB), hence we want to include it only in bugreports and not in + // field uploads. + // + // Note that perfetto communicates only whether the OnFlush event is due to a bugreport + // or not, hence we need an additional "bugreport only" tracing mode. + // If perfetto had communicated when the OnFlush is due to a field upload, then we could + // have had a single "generated" tracing mode that would have been a noop in case of + // field uploads. + ALOGD("Started 'generated bugreport only' tracing" + " (waiting for bugreport's OnFlush event to generate layers)"); + break; + } case Mode::MODE_DUMP: { auto snapshot = mTakeLayersSnapshotProto(flags); addProtoSnapshotToOstream(std::move(snapshot), Mode::MODE_DUMP); @@ -82,10 +100,18 @@ void LayerTracing::onStart(Mode mode, uint32_t flags) { } } -void LayerTracing::onFlush(Mode mode, uint32_t flags) { +void LayerTracing::onFlush(Mode mode, uint32_t flags, bool isBugreport) { // In "generated" mode process the buffer of transactions (owned by TransactionTracing), - // generate a sequence of layers snapshots and write them to perfetto. - if (mode != Mode::MODE_GENERATED) { + // generate layers snapshots and write them to perfetto. + if (mode != Mode::MODE_GENERATED && mode != Mode::MODE_GENERATED_BUGREPORT_ONLY) { + ALOGD("Skipping layers trace generation (not a 'generated' tracing session)"); + return; + } + + // In "generated bugreport only" mode skip the layers snapshot generation + // if the perfetto's OnFlush event is not due to a bugreport being taken. + if (mode == Mode::MODE_GENERATED_BUGREPORT_ONLY && !isBugreport) { + ALOGD("Skipping layers trace generation (not a bugreport OnFlush event)"); return; } @@ -147,14 +173,23 @@ void LayerTracing::writeSnapshotToStream(perfetto::protos::LayersSnapshotProto&& } void LayerTracing::writeSnapshotToPerfetto(const perfetto::protos::LayersSnapshotProto& snapshot, - Mode mode) { + Mode srcMode) { const auto snapshotBytes = snapshot.SerializeAsString(); LayerDataSource::Trace([&](LayerDataSource::TraceContext context) { - if (mode != context.GetCustomTlsState()->mMode) { + auto dstMode = context.GetCustomTlsState()->mMode; + if (srcMode == Mode::MODE_GENERATED) { + // Layers snapshots produced by LayerTraceGenerator have srcMode == MODE_GENERATED + // and should be written to tracing sessions with MODE_GENERATED + // or MODE_GENERATED_BUGREPORT_ONLY. + if (dstMode != Mode::MODE_GENERATED && dstMode != Mode::MODE_GENERATED_BUGREPORT_ONLY) { + return; + } + } else if (srcMode != dstMode) { return; } - if (!checkAndUpdateLastVsyncIdWrittenToPerfetto(mode, snapshot.vsync_id())) { + + if (!checkAndUpdateLastVsyncIdWrittenToPerfetto(srcMode, snapshot.vsync_id())) { return; } { @@ -176,7 +211,7 @@ bool LayerTracing::checkAndUpdateLastVsyncIdWrittenToPerfetto(Mode mode, std::in // In some situations (e.g. two bugreports taken shortly one after the other) the generated // sequence of layers snapshots might overlap. Here we check the snapshot's vsyncid to make // sure that in generated tracing mode a given snapshot is written only once to perfetto. - if (mode != Mode::MODE_GENERATED) { + if (mode != Mode::MODE_GENERATED && mode != Mode::MODE_GENERATED_BUGREPORT_ONLY) { return true; } diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h index fe7f06d0f6..2895ba7026 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.h +++ b/services/surfaceflinger/Tracing/LayerTracing.h @@ -55,7 +55,9 @@ class TransactionTracing; * and written to perfetto. * * - * E.g. start active mode tracing: + * E.g. start active mode tracing + * (replace mode value with MODE_DUMP, MODE_GENERATED or MODE_GENERATED_BUGREPORT_ONLY to enable + * different tracing modes): * adb shell -t perfetto \ -c - --txt \ @@ -79,7 +81,7 @@ class TransactionTracing; } } } - EOF +EOF * */ class LayerTracing { @@ -106,7 +108,7 @@ public: // Start event from perfetto data source void onStart(Mode mode, uint32_t flags); // Flush event from perfetto data source - void onFlush(Mode mode, uint32_t flags); + void onFlush(Mode mode, uint32_t flags, bool isBugreport); // Stop event from perfetto data source void onStop(Mode mode); -- GitLab From b19830835f681fd30e108b09689e556f12e12297 Mon Sep 17 00:00:00 2001 From: Trevor David Black Date: Thu, 19 Oct 2023 16:56:06 +0000 Subject: [PATCH 0873/1187] Add deqp.level-latest.xml to aosp Bug: 305647982 Test: Build Change-Id: Ifbbc3d8f0d323dfaa7ada08c991597f536111b56 --- data/etc/Android.bp | 12 +++++++++++ ...id.software.opengles.deqp.level-latest.xml | 21 +++++++++++++++++++ ...roid.software.vulkan.deqp.level-latest.xml | 21 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 data/etc/android.software.opengles.deqp.level-latest.xml create mode 100644 data/etc/android.software.vulkan.deqp.level-latest.xml diff --git a/data/etc/Android.bp b/data/etc/Android.bp index e95432c98f..1418e1f7a6 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -358,6 +358,12 @@ prebuilt_etc { defaults: ["frameworks_native_data_etc_defaults"], } +prebuilt_etc { + name: "android.software.opengles.deqp.level-latest.prebuilt.xml", + src: "android.software.opengles.deqp.level-latest.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + prebuilt_etc { name: "android.software.sip.voip.prebuilt.xml", src: "android.software.sip.voip.xml", @@ -388,6 +394,12 @@ prebuilt_etc { defaults: ["frameworks_native_data_etc_defaults"], } +prebuilt_etc { + name: "android.software.vulkan.deqp.level-latest.prebuilt.xml", + src: "android.software.vulkan.deqp.level-latest.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + prebuilt_etc { name: "aosp_excluded_hardware.prebuilt.xml", src: "aosp_excluded_hardware.xml", diff --git a/data/etc/android.software.opengles.deqp.level-latest.xml b/data/etc/android.software.opengles.deqp.level-latest.xml new file mode 100644 index 0000000000..bd15eb6eb2 --- /dev/null +++ b/data/etc/android.software.opengles.deqp.level-latest.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/data/etc/android.software.vulkan.deqp.level-latest.xml b/data/etc/android.software.vulkan.deqp.level-latest.xml new file mode 100644 index 0000000000..87be0709d6 --- /dev/null +++ b/data/etc/android.software.vulkan.deqp.level-latest.xml @@ -0,0 +1,21 @@ + + + + + + + -- GitLab From f06ef956d159e98b9ec8874dc15b07707a570885 Mon Sep 17 00:00:00 2001 From: Andy Yu Date: Thu, 19 Oct 2023 15:25:24 -0700 Subject: [PATCH 0874/1187] SF: Add a sysprop for game default frame rate Bug: 286084594 Test: SurfaceFlinger unit tests Change-Id: Icc3ed7642e45c8c28b063cbe1799e09c00a05e35 --- services/surfaceflinger/SurfaceFlingerProperties.cpp | 4 ++++ services/surfaceflinger/SurfaceFlingerProperties.h | 2 ++ .../sysprop/SurfaceFlingerProperties.sysprop | 12 ++++++++++++ .../sysprop/api/SurfaceFlingerProperties-current.txt | 5 +++++ 4 files changed, 23 insertions(+) diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp index 66c8f33fe5..a7650783b4 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.cpp +++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp @@ -371,5 +371,9 @@ bool clear_slots_with_set_layer_buffer(bool defaultValue) { return SurfaceFlingerProperties::clear_slots_with_set_layer_buffer().value_or(defaultValue); } +int32_t game_default_frame_rate_override(int32_t defaultValue) { + return SurfaceFlingerProperties::game_default_frame_rate_override().value_or(defaultValue); +} + } // namespace sysprop } // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h index a08042009b..65ebe2af21 100644 --- a/services/surfaceflinger/SurfaceFlingerProperties.h +++ b/services/surfaceflinger/SurfaceFlingerProperties.h @@ -101,6 +101,8 @@ bool ignore_hdr_camera_layers(bool defaultValue); bool clear_slots_with_set_layer_buffer(bool defaultValue); +int32_t game_default_frame_rate_override(int32_t defaultValue); + } // namespace sysprop } // namespace android #endif // SURFACEFLINGERPROPERTIES_H_ diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index be29be4ef4..0ad5ac9956 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -495,3 +495,15 @@ prop { access: Readonly prop_name: "ro.surface_flinger.clear_slots_with_set_layer_buffer" } + +# Controls the default frame rate override of game applications. Ideally, game applications set +# desired frame rate via setFrameRate() API. However, to cover the scenario when the game didn't +# have a set frame rate, we introduce the default frame rate. The priority of this override is the +# lowest among setFrameRate() and game intervention override. +prop { + api_name: "game_default_frame_rate_override" + type: Integer + scope: Public + access: Readonly + prop_name: "ro.surface_flinger.game_default_frame_rate_override" +} diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt index ba88acc2fb..00173009f5 100644 --- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt +++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt @@ -64,6 +64,11 @@ props { api_name: "force_hwc_copy_for_virtual_displays" prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays" } + prop { + api_name: "game_default_frame_rate_override" + type: Integer + prop_name: "ro.surface_flinger.game_default_frame_rate_override" + } prop { api_name: "has_HDR_display" prop_name: "ro.surface_flinger.has_HDR_display" -- GitLab From d30aaadb8c35f4dcc64225bd8275101d2b4204c9 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Thu, 3 Aug 2023 19:12:49 +0000 Subject: [PATCH 0875/1187] [Cherry-pick] Clean up EGL Loader. Removes deprecated driver loading path, clean up comments and misc. Bug: b/293503000 Test: boot Change-Id: Ibc62bf59ed7b0cb3671583d2af853c457977d1d1 Merged-In: Ibc62bf59ed7b0cb3671583d2af853c457977d1d1 --- opengl/libs/EGL/Loader.cpp | 107 ++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 56 deletions(-) diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 654e5b7c03..04e2fffaef 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -41,24 +41,44 @@ namespace android { /* * EGL userspace drivers must be provided either: * - as a single library: - * /vendor/lib/egl/libGLES.so + * /vendor/${LIB}/egl/libGLES.so * * - as separate libraries: - * /vendor/lib/egl/libEGL.so - * /vendor/lib/egl/libGLESv1_CM.so - * /vendor/lib/egl/libGLESv2.so + * /vendor/${LIB}/egl/libEGL.so + * /vendor/${LIB}/egl/libGLESv1_CM.so + * /vendor/${LIB}/egl/libGLESv2.so * * For backward compatibility and to facilitate the transition to * this new naming scheme, the loader will additionally look for: * - * /{vendor|system}/lib/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_*.so + * /vendor/${LIB}/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_${SUFFIX}.so * */ -Loader& Loader::getInstance() { - static Loader loader; - return loader; -} +#ifndef SYSTEM_LIB_PATH +#if defined(__LP64__) +#define SYSTEM_LIB_PATH "/system/lib64" +#else +#define SYSTEM_LIB_PATH "/system/lib" +#endif +#endif + +static const char* PERSIST_DRIVER_SUFFIX_PROPERTY = "persist.graphics.egl"; +static const char* RO_DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl"; +static const char* RO_BOARD_PLATFORM_PROPERTY = "ro.board.platform"; + +static const char* HAL_SUBNAME_KEY_PROPERTIES[3] = { + PERSIST_DRIVER_SUFFIX_PROPERTY, + RO_DRIVER_SUFFIX_PROPERTY, + RO_BOARD_PLATFORM_PROPERTY, +}; + +static const char* const VENDOR_LIB_EGL_DIR = +#if defined(__LP64__) + "/vendor/lib64/egl"; +#else + "/vendor/lib/egl"; +#endif static void* do_dlopen(const char* path, int mode) { ATRACE_CALL(); @@ -80,6 +100,17 @@ static int do_android_unload_sphal_library(void* dso) { return android_unload_sphal_library(dso); } +static void* load_wrapper(const char* path) { + void* so = do_dlopen(path, RTLD_NOW | RTLD_LOCAL); + ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror()); + return so; +} + +Loader& Loader::getInstance() { + static Loader loader; + return loader; +} + Loader::driver_t::driver_t(void* gles) { dso[0] = gles; @@ -123,30 +154,6 @@ Loader::Loader() Loader::~Loader() { } -static void* load_wrapper(const char* path) { - void* so = do_dlopen(path, RTLD_NOW | RTLD_LOCAL); - ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror()); - return so; -} - -#ifndef EGL_WRAPPER_DIR -#if defined(__LP64__) -#define EGL_WRAPPER_DIR "/system/lib64" -#else -#define EGL_WRAPPER_DIR "/system/lib" -#endif -#endif - -static const char* PERSIST_DRIVER_SUFFIX_PROPERTY = "persist.graphics.egl"; -static const char* RO_DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl"; -static const char* RO_BOARD_PLATFORM_PROPERTY = "ro.board.platform"; - -static const char* HAL_SUBNAME_KEY_PROPERTIES[3] = { - PERSIST_DRIVER_SUFFIX_PROPERTY, - RO_DRIVER_SUFFIX_PROPERTY, - RO_BOARD_PLATFORM_PROPERTY, -}; - // Check whether the loaded system drivers should be unloaded in order to // load ANGLE or the updatable graphics drivers. // If ANGLE namespace is set, it means the application is identified to run on top of ANGLE. @@ -323,13 +330,13 @@ void* Loader::open(egl_connection_t* cnx) { HAL_SUBNAME_KEY_PROPERTIES[2]); if (!cnx->libEgl) { - cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so"); + cnx->libEgl = load_wrapper(SYSTEM_LIB_PATH "/libEGL.so"); } if (!cnx->libGles1) { - cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so"); + cnx->libGles1 = load_wrapper(SYSTEM_LIB_PATH "/libGLESv1_CM.so"); } if (!cnx->libGles2) { - cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so"); + cnx->libGles2 = load_wrapper(SYSTEM_LIB_PATH "/libGLESv2.so"); } if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) { @@ -432,31 +439,19 @@ static void* load_system_driver(const char* kind, const char* suffix, const bool class MatchFile { public: static std::string find(const char* libraryName, const bool exact) { - const char* const searchPaths[] = { -#if defined(__LP64__) - "/vendor/lib64/egl", - "/system/lib64/egl" -#else - "/vendor/lib/egl", - "/system/lib/egl" -#endif - }; - - for (auto dir : searchPaths) { - std::string absolutePath; - if (find(absolutePath, libraryName, dir, exact)) { - return absolutePath; - } + std::string absolutePath; + if (findLibPath(absolutePath, libraryName, exact)) { + return absolutePath; } // Driver not found. gah. return std::string(); } private: - static bool find(std::string& result, - const std::string& pattern, const char* const search, bool exact) { + static bool findLibPath(std::string& result, const std::string& pattern, bool exact) { + const std::string vendorLibEglDirString = std::string(VENDOR_LIB_EGL_DIR); if (exact) { - std::string absolutePath = std::string(search) + "/" + pattern + ".so"; + std::string absolutePath = vendorLibEglDirString + "/" + pattern + ".so"; if (!access(absolutePath.c_str(), R_OK)) { result = absolutePath; return true; @@ -464,7 +459,7 @@ static void* load_system_driver(const char* kind, const char* suffix, const bool return false; } - DIR* d = opendir(search); + DIR* d = opendir(VENDOR_LIB_EGL_DIR); if (d != nullptr) { struct dirent* e; while ((e = readdir(d)) != nullptr) { @@ -477,7 +472,7 @@ static void* load_system_driver(const char* kind, const char* suffix, const bool } if (strstr(e->d_name, pattern.c_str()) == e->d_name) { if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) { - result = std::string(search) + "/" + e->d_name; + result = vendorLibEglDirString + "/" + e->d_name; closedir(d); return true; } -- GitLab From 55e3103c33bdb6da73d45be50bff0161e5a5822f Mon Sep 17 00:00:00 2001 From: Alec Mouri Date: Mon, 2 Oct 2023 20:34:18 +0000 Subject: [PATCH 0876/1187] Rename DisplayMode::refreshRate to peakRefreshRate Peak refresh rate is a more clear name Bug: 301462354 Test: builds, boots Test: dumpsys display Change-Id: I2f7f98859ae2a1d9191b1e377921eb7a04e784bf --- libs/gui/SurfaceComposerClient.cpp | 2 +- libs/gui/aidl/android/gui/DisplayMode.aidl | 2 +- libs/gui/tests/EndToEndNativeInputTest.cpp | 2 +- libs/nativedisplay/ADisplay.cpp | 2 +- libs/ui/include/ui/DisplayMode.h | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 10 +++++----- services/surfaceflinger/tests/DisplayConfigs_test.cpp | 4 ++-- services/surfaceflinger/tests/LayerTransactionTest.h | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 05e2ddf198..a3518110cd 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -2604,7 +2604,7 @@ void SurfaceComposerClient::getDynamicDisplayInfoInternal(gui::DynamicDisplayInf outMode.resolution.height = mode.resolution.height; outMode.xDpi = mode.xDpi; outMode.yDpi = mode.yDpi; - outMode.refreshRate = mode.refreshRate; + outMode.peakRefreshRate = mode.peakRefreshRate; outMode.vsyncRate = mode.vsyncRate; outMode.appVsyncOffset = mode.appVsyncOffset; outMode.sfVsyncOffset = mode.sfVsyncOffset; diff --git a/libs/gui/aidl/android/gui/DisplayMode.aidl b/libs/gui/aidl/android/gui/DisplayMode.aidl index b057653200..f605177cfd 100644 --- a/libs/gui/aidl/android/gui/DisplayMode.aidl +++ b/libs/gui/aidl/android/gui/DisplayMode.aidl @@ -30,7 +30,7 @@ parcelable DisplayMode { int[] supportedHdrTypes; // Some modes have peak refresh rate lower than the panel vsync rate. - float refreshRate = 0.0f; + float peakRefreshRate = 0.0f; float vsyncRate = 0.0f; long appVsyncOffset = 0; long sfVsyncOffset = 0; diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 662e9fe74a..d4b8dbeeb9 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -394,7 +394,7 @@ public: // After a new buffer is queued, SurfaceFlinger is notified and will // latch the new buffer on next vsync. Let's heuristically wait for 3 // vsyncs. - mBufferPostDelay = static_cast(1e6 / mode.refreshRate) * 3; + mBufferPostDelay = static_cast(1e6 / mode.peakRefreshRate) * 3; } void TearDown() { diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp index bf0805b46c..e3be3bc8f8 100644 --- a/libs/nativedisplay/ADisplay.cpp +++ b/libs/nativedisplay/ADisplay.cpp @@ -155,7 +155,7 @@ int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) { const ui::DisplayMode& mode = modes[j]; modesPerDisplay[i].emplace_back( DisplayConfigImpl{static_cast(mode.id), mode.resolution.getWidth(), - mode.resolution.getHeight(), mode.refreshRate, + mode.resolution.getHeight(), mode.peakRefreshRate, mode.sfVsyncOffset, mode.appVsyncOffset}); } } diff --git a/libs/ui/include/ui/DisplayMode.h b/libs/ui/include/ui/DisplayMode.h index a469c78070..ddb9bbd4bc 100644 --- a/libs/ui/include/ui/DisplayMode.h +++ b/libs/ui/include/ui/DisplayMode.h @@ -38,7 +38,7 @@ struct DisplayMode { std::vector supportedHdrTypes; // Some modes have peak refresh rate lower than the panel vsync rate. - float refreshRate = 0.f; + float peakRefreshRate = 0.f; float vsyncRate = 0.f; nsecs_t appVsyncOffset = 0; nsecs_t sfVsyncOffset = 0; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9b9a67aa5f..fc517212ea 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -266,7 +266,7 @@ bool getKernelIdleTimerSyspropConfig(DisplayId displayId) { bool isAbove4k30(const ui::DisplayMode& outMode) { using fps_approx_ops::operator>; - Fps refreshRate = Fps::fromValue(outMode.refreshRate); + Fps refreshRate = Fps::fromValue(outMode.peakRefreshRate); return outMode.resolution.getWidth() >= FOUR_K_WIDTH && outMode.resolution.getHeight() >= FOUR_K_HEIGHT && refreshRate > 30_Hz; } @@ -1046,11 +1046,11 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info outMode.yDpi = yDpi; const auto peakFps = mode->getPeakFps(); - outMode.refreshRate = peakFps.getValue(); + outMode.peakRefreshRate = peakFps.getValue(); outMode.vsyncRate = mode->getVsyncRate().getValue(); - const auto vsyncConfigSet = - mVsyncConfiguration->getConfigsForRefreshRate(Fps::fromValue(outMode.refreshRate)); + const auto vsyncConfigSet = mVsyncConfiguration->getConfigsForRefreshRate( + Fps::fromValue(outMode.peakRefreshRate)); outMode.appVsyncOffset = vsyncConfigSet.late.appOffset; outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset; outMode.group = mode->getGroup(); @@ -9221,7 +9221,7 @@ void SurfaceComposerAIDL::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo& outMode.resolution.height = mode.resolution.height; outMode.xDpi = mode.xDpi; outMode.yDpi = mode.yDpi; - outMode.refreshRate = mode.refreshRate; + outMode.peakRefreshRate = mode.peakRefreshRate; outMode.vsyncRate = mode.vsyncRate; outMode.appVsyncOffset = mode.appVsyncOffset; outMode.sfVsyncOffset = mode.sfVsyncOffset; diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp index 4be961bda1..0a951d49e3 100644 --- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp +++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp @@ -75,8 +75,8 @@ TEST_F(RefreshRateRangeTest, setAllConfigs) { setSpecs.allowGroupSwitching = false; for (size_t i = 0; i < modes.size(); i++) { setSpecs.defaultMode = modes[i].id; - setSpecs.primaryRanges.physical.min = modes[i].refreshRate; - setSpecs.primaryRanges.physical.max = modes[i].refreshRate; + setSpecs.primaryRanges.physical.min = modes[i].peakRefreshRate; + setSpecs.primaryRanges.physical.max = modes[i].peakRefreshRate; setSpecs.primaryRanges.render = setSpecs.primaryRanges.physical; setSpecs.appRequestRanges = setSpecs.primaryRanges; res = SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, setSpecs); diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 2bdb8a452d..9269e7c8a0 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -299,7 +299,7 @@ private: // After a new buffer is queued, SurfaceFlinger is notified and will // latch the new buffer on next vsync. Let's heuristically wait for 3 // vsyncs. - mBufferPostDelay = static_cast(1e6 / mode.refreshRate) * 3; + mBufferPostDelay = static_cast(1e6 / mode.peakRefreshRate) * 3; mBlackBgSurface = createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */, -- GitLab From 277f6f95fa85f169e2d89af0854744e7af9484a1 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 6 Sep 2023 19:55:45 +0000 Subject: [PATCH 0877/1187] [Cherry-pick] Make sure the correct ANGLE binary is used. Previously when eglGetDisplay is called, the code would attempt to initialize ANGLE platform methods and acquire pointers to reset the ANGLE platform. However, without this patch we continue using ro.hardware.egl to form the ANGLE binary name, which is now wrong. Not being able to correctly load the ANGLE binaries means platform methods are not initialize. This currently doesn't have known side effect except that we are observing a bunch of error messages that don't make sense that point to the native OpenGL ES driver loading failure. This patch makes sure ANGLE binary is used when initialize ANGLE platform. Bug: b/293503000 Test: atest CtsAngleIntegrationHostTestCases -c Change-Id: I5189042efc41fa7bef06d20f43ed4da3b1271dab Merged-In: I5189042efc41fa7bef06d20f43ed4da3b1271dab --- opengl/libs/EGL/egl_angle_platform.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp index 9a6bb7a61c..ee605c2011 100644 --- a/opengl/libs/EGL/egl_angle_platform.cpp +++ b/opengl/libs/EGL/egl_angle_platform.cpp @@ -35,6 +35,7 @@ namespace angle { +constexpr char kAngleEs2Lib[] = "libGLESv2_angle.so"; constexpr int kAngleDlFlags = RTLD_LOCAL | RTLD_NOW; static GetDisplayPlatformFunc angleGetDisplayPlatform = nullptr; @@ -115,8 +116,6 @@ bool initializeAnglePlatform(EGLDisplay dpy) { android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace(); void* so = nullptr; if (ns) { - // Loading from an APK, so hard-code the suffix to "_angle". - constexpr char kAngleEs2Lib[] = "libGLESv2_angle.so"; const android_dlextinfo dlextinfo = { .flags = ANDROID_DLEXT_USE_NAMESPACE, .library_namespace = ns, @@ -130,19 +129,11 @@ bool initializeAnglePlatform(EGLDisplay dpy) { } } else { // If we are here, ANGLE is loaded as built-in gl driver in the sphal. - // Get the specified ANGLE library filename suffix. - std::string angleEs2LibSuffix = android::base::GetProperty("ro.hardware.egl", ""); - if (angleEs2LibSuffix.empty()) { - ALOGE("%s failed to get valid ANGLE library filename suffix!", __FUNCTION__); - return false; - } - - std::string angleEs2LibName = "libGLESv2_" + angleEs2LibSuffix + ".so"; - so = android_load_sphal_library(angleEs2LibName.c_str(), kAngleDlFlags); + so = android_load_sphal_library(kAngleEs2Lib, kAngleDlFlags); if (so) { - ALOGD("dlopen (%s) success at %p", angleEs2LibName.c_str(), so); + ALOGD("dlopen (%s) success at %p", kAngleEs2Lib, so); } else { - ALOGE("%s failed to dlopen %s!", __FUNCTION__, angleEs2LibName.c_str()); + ALOGE("%s failed to dlopen %s: %s!", __FUNCTION__, kAngleEs2Lib, dlerror()); return false; } } -- GitLab From c7b93c036d2d58a257f18aca7268fe84f124f19b Mon Sep 17 00:00:00 2001 From: Jared Duke Date: Fri, 20 Oct 2023 19:58:53 +0000 Subject: [PATCH 0878/1187] Remove installd support for compiled views This feature did not ship and is being removed. Remove the associated compilation hooks in installd. Bug: 158121974 Test: m Change-Id: I9d80f67faaddf2813e1c0389116b510139915939 --- cmds/installd/Android.bp | 2 - cmds/installd/InstalldNativeService.cpp | 12 -- cmds/installd/InstalldNativeService.h | 3 - .../installd/binder/android/os/IInstalld.aidl | 2 - cmds/installd/view_compiler.cpp | 111 ------------------ cmds/installd/view_compiler.h | 29 ----- 6 files changed, 159 deletions(-) delete mode 100644 cmds/installd/view_compiler.cpp delete mode 100644 cmds/installd/view_compiler.h diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp index ac101ecb29..334bae44e3 100644 --- a/cmds/installd/Android.bp +++ b/cmds/installd/Android.bp @@ -34,7 +34,6 @@ cc_defaults { "unique_file.cpp", "utils.cpp", "utils_default.cpp", - "view_compiler.cpp", ":installd_aidl", ], shared_libs: [ @@ -254,7 +253,6 @@ cc_binary { "unique_file.cpp", "utils.cpp", "utils_default.cpp", - "view_compiler.cpp", ], static_libs: [ diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 073d0c4854..d7c9b40d92 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -69,7 +69,6 @@ #include "installd_deps.h" #include "otapreopt_utils.h" #include "utils.h" -#include "view_compiler.h" #include "CacheTracker.h" #include "CrateManager.h" @@ -3258,17 +3257,6 @@ binder::Status InstalldNativeService::controlDexOptBlocking(bool block) { return ok(); } -binder::Status InstalldNativeService::compileLayouts(const std::string& apkPath, - const std::string& packageName, - const std ::string& outDexFile, int uid, - bool* _aidl_return) { - const char* apk_path = apkPath.c_str(); - const char* package_name = packageName.c_str(); - const char* out_dex_file = outDexFile.c_str(); - *_aidl_return = android::installd::view_compiler(apk_path, package_name, out_dex_file, uid); - return *_aidl_return ? ok() : error("viewcompiler failed"); -} - binder::Status InstalldNativeService::linkNativeLibraryDirectory( const std::optional& uuid, const std::string& packageName, const std::string& nativeLibPath32, int32_t userId) { diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 1ec092d8b5..1b56144061 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -146,9 +146,6 @@ public: binder::Status controlDexOptBlocking(bool block); - binder::Status compileLayouts(const std::string& apkPath, const std::string& packageName, - const std::string& outDexFile, int uid, bool* _aidl_return); - binder::Status rmdex(const std::string& codePath, const std::string& instructionSet); binder::Status mergeProfiles(int32_t uid, const std::string& packageName, diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 8893e38c03..f5a770977c 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -70,8 +70,6 @@ interface IInstalld { // Blocks (when block is true) or unblock (when block is false) dexopt. // Blocking also invloves cancelling the currently running dexopt. void controlDexOptBlocking(boolean block); - boolean compileLayouts(@utf8InCpp String apkPath, @utf8InCpp String packageName, - @utf8InCpp String outDexFile, int uid); void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet); diff --git a/cmds/installd/view_compiler.cpp b/cmds/installd/view_compiler.cpp deleted file mode 100644 index 8c000a11c9..0000000000 --- a/cmds/installd/view_compiler.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2019 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 "view_compiler.h" - -#include - -#include -#include -#include -#include -#include - -#include "utils.h" - -#include "android-base/logging.h" -#include "android-base/stringprintf.h" -#include "android-base/unique_fd.h" - -namespace android { -namespace installd { - -namespace { - -using ::android::base::unique_fd; - -constexpr int kTimeoutMs = 300000; - -} // namespace - -bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file, - int uid) { - CHECK(apk_path != nullptr); - CHECK(package_name != nullptr); - CHECK(out_dex_file != nullptr); - - // viewcompiler won't have permission to open anything, so we have to open the files first - // and pass file descriptors. - - // Open input file - unique_fd infd{open(apk_path, O_RDONLY)}; // NOLINT(android-cloexec-open) - if (infd.get() < 0) { - PLOG(ERROR) << "Could not open input file: " << apk_path; - return false; - } - - // Set up output file. viewcompiler can't open outputs by fd, but it can write to stdout, so - // we close stdout and open it towards the right output. - unique_fd outfd{open(out_dex_file, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644)}; - if (outfd.get() < 0) { - PLOG(ERROR) << "Could not open output file: " << out_dex_file; - return false; - } - if (fchmod(outfd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0) { - PLOG(ERROR) << "Could not change output file permissions"; - return false; - } - if (dup2(outfd, STDOUT_FILENO) < 0) { - PLOG(ERROR) << "Could not duplicate output file descriptor"; - return false; - } - - // Prepare command line arguments for viewcompiler - std::string args[] = {"/system/bin/viewcompiler", - "--apk", - "--infd", - android::base::StringPrintf("%d", infd.get()), - "--dex", - "--package", - package_name}; - char* const argv[] = {const_cast(args[0].c_str()), const_cast(args[1].c_str()), - const_cast(args[2].c_str()), const_cast(args[3].c_str()), - const_cast(args[4].c_str()), const_cast(args[5].c_str()), - const_cast(args[6].c_str()), nullptr}; - - pid_t pid = fork(); - if (pid == 0) { - // Now that we've opened the files we need, drop privileges. - drop_capabilities(uid); - execv("/system/bin/viewcompiler", argv); - _exit(1); - } - - int return_code = wait_child_with_timeout(pid, kTimeoutMs); - if (!WIFEXITED(return_code)) { - LOG(WARNING) << "viewcompiler failed for " << package_name << ":" << apk_path; - if (WTERMSIG(return_code) == SIGKILL) { - // If the subprocess is killed while it's writing to the file, the file is likely - // corrupted, so we should remove it. - remove_file_at_fd(outfd.get()); - } - return false; - } - return WEXITSTATUS(return_code) == 0; -} - -} // namespace installd -} // namespace android diff --git a/cmds/installd/view_compiler.h b/cmds/installd/view_compiler.h deleted file mode 100644 index aa141ca257..0000000000 --- a/cmds/installd/view_compiler.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef VIEW_COMPILER_H_ -#define VIEW_COMPILER_H_ - -namespace android { -namespace installd { - -bool view_compiler(const char* apk_path, const char* package_name, const char* out_dex_file, - int uid); - -} // namespace installd -} // namespace android - -#endif // VIEW_COMPILER_H_ -- GitLab From 3e01997d10b9aa66b7078d7b3e124816cc71e9bd Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 20 Oct 2023 13:23:48 -0700 Subject: [PATCH 0879/1187] SF: minor bug fix to flags::dont_skip_on_early Bug: 306686616 Test: presubmit Change-Id: I352ad2f6ad5971e598441972066cdcab71382b4d --- .../Scheduler/VSyncDispatchTimerQueue.cpp | 14 ++-- .../unittests/VSyncDispatchTimerQueueTest.cpp | 74 ++++++++++++++++++- 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp index c4c9fa56ff..f4676706fd 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp @@ -40,16 +40,18 @@ using base::StringAppendF; namespace { -nsecs_t getExpectedCallbackTime(nsecs_t nextVsyncTime, +nsecs_t getExpectedCallbackTime(nsecs_t now, nsecs_t nextVsyncTime, const VSyncDispatch::ScheduleTiming& timing) { - return nextVsyncTime - timing.readyDuration - timing.workDuration; + const auto expectedCallbackTime = nextVsyncTime - timing.readyDuration - timing.workDuration; + const auto baseTime = flags::dont_skip_on_early() ? now : expectedCallbackTime; + return std::max(baseTime, expectedCallbackTime); } nsecs_t getExpectedCallbackTime(VSyncTracker& tracker, nsecs_t now, const VSyncDispatch::ScheduleTiming& timing) { const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom( std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration)); - return getExpectedCallbackTime(nextVsyncTime, timing); + return getExpectedCallbackTime(now, nextVsyncTime, timing); } } // namespace @@ -105,11 +107,11 @@ ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTim mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance))); if (flags::dont_skip_on_early()) { if (wouldSkipAVsyncTarget || wouldSkipAWakeup) { - return getExpectedCallbackTime(mArmedInfo->mActualVsyncTime, timing); + return getExpectedCallbackTime(now, mArmedInfo->mActualVsyncTime, timing); } } else { if (wouldSkipAVsyncTarget && wouldSkipAWakeup) { - return getExpectedCallbackTime(nextVsyncTime, timing); + return getExpectedCallbackTime(now, nextVsyncTime, timing); } } @@ -119,7 +121,7 @@ ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTim auto const nextReadyTime = nextVsyncTime - timing.readyDuration; mScheduleTiming = timing; mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime}; - return getExpectedCallbackTime(nextVsyncTime, timing); + return getExpectedCallbackTime(now, nextVsyncTime, timing); } void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming timing) { diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp index b8fdce1dce..1dc5498221 100644 --- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp @@ -759,6 +759,8 @@ TEST_F(VSyncDispatchTimerQueueTest, canMoveCallbackBackwardsInTime) { // b/1450138150 TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync) { + SET_FLAG_FOR_TEST(flags::dont_skip_on_early, false); + EXPECT_CALL(mMockClock, alarmAt(_, 500)); CountingCallback cb(mDispatch); auto result = @@ -772,6 +774,29 @@ TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipASchedule {.workDuration = 800, .readyDuration = 0, .earliestVsync = 1000}); EXPECT_TRUE(result.has_value()); EXPECT_EQ(1200, *result); + + advanceToNextCallback(); + ASSERT_THAT(cb.mCalls.size(), Eq(1)); +} + +// b/1450138150 +TEST_F(VSyncDispatchTimerQueueTest, movesCallbackBackwardsAndSkipAScheduledTargetVSync) { + SET_FLAG_FOR_TEST(flags::dont_skip_on_early, true); + + EXPECT_CALL(mMockClock, alarmAt(_, 500)); + CountingCallback cb(mDispatch); + auto result = + mDispatch->schedule(cb, + {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000}); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(500, *result); + mMockClock.advanceBy(400); + + result = mDispatch->schedule(cb, + {.workDuration = 800, .readyDuration = 0, .earliestVsync = 1000}); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(400, *result); + advanceToNextCallback(); ASSERT_THAT(cb.mCalls.size(), Eq(1)); } @@ -826,6 +851,8 @@ TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) { } TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) { + SET_FLAG_FOR_TEST(flags::dont_skip_on_early, false); + EXPECT_CALL(mMockClock, alarmAt(_, 600)); CountingCallback cb(mDispatch); @@ -843,6 +870,26 @@ TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) advanceToNextCallback(); } +TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesAffectSchedulingState) { + SET_FLAG_FOR_TEST(flags::dont_skip_on_early, true); + + EXPECT_CALL(mMockClock, alarmAt(_, 600)); + + CountingCallback cb(mDispatch); + auto result = + mDispatch->schedule(cb, + {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(600, *result); + + result = mDispatch->schedule(cb, + {.workDuration = 1400, .readyDuration = 0, .earliestVsync = 1000}); + EXPECT_TRUE(result.has_value()); + EXPECT_EQ(0, *result); + + advanceToNextCallback(); +} + TEST_F(VSyncDispatchTimerQueueTest, helperMove) { EXPECT_CALL(mMockClock, alarmAt(_, 500)).Times(1); EXPECT_CALL(mMockClock, alarmCancel()).Times(1); @@ -1045,6 +1092,8 @@ TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithReadyDuration) { } TEST_F(VSyncDispatchTimerQueueTest, updatesVsyncTimeForCloseWakeupTime) { + SET_FLAG_FOR_TEST(flags::dont_skip_on_early, false); + Sequence seq; EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq); @@ -1065,6 +1114,29 @@ TEST_F(VSyncDispatchTimerQueueTest, updatesVsyncTimeForCloseWakeupTime) { EXPECT_THAT(cb.mReadyTime[0], Eq(2000)); } +TEST_F(VSyncDispatchTimerQueueTest, doesNotUpdatesVsyncTimeForCloseWakeupTime) { + SET_FLAG_FOR_TEST(flags::dont_skip_on_early, true); + + Sequence seq; + EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq); + + CountingCallback cb(mDispatch); + + mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000}); + mDispatch->schedule(cb, {.workDuration = 1400, .readyDuration = 0, .earliestVsync = 1000}); + + advanceToNextCallback(); + + advanceToNextCallback(); + + ASSERT_THAT(cb.mCalls.size(), Eq(1)); + EXPECT_THAT(cb.mCalls[0], Eq(1000)); + ASSERT_THAT(cb.mWakeupTime.size(), Eq(1)); + EXPECT_THAT(cb.mWakeupTime[0], Eq(600)); + ASSERT_THAT(cb.mReadyTime.size(), Eq(1)); + EXPECT_THAT(cb.mReadyTime[0], Eq(1000)); +} + TEST_F(VSyncDispatchTimerQueueTest, skipAVsyc) { SET_FLAG_FOR_TEST(flags::dont_skip_on_early, false); @@ -1101,7 +1173,7 @@ TEST_F(VSyncDispatchTimerQueueTest, dontskipAVsyc) { result = mDispatch->schedule(cb, {.workDuration = 800, .readyDuration = 0, .earliestVsync = 1000}); EXPECT_TRUE(result.has_value()); - EXPECT_EQ(200, *result); + EXPECT_EQ(300, *result); advanceToNextCallback(); ASSERT_THAT(cb.mCalls.size(), Eq(1)); -- GitLab From e4da7a81bc095651375e27f4815e4dc897ab753c Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Tue, 8 Aug 2023 20:46:53 +0000 Subject: [PATCH 0880/1187] Make ANGLE loadable from system image. Previously ANGLE was built as part of vendor partition, and hence when it was the default OpenGL ES driver, the loader should use sphal namespace to dlopen it. However, having ANGLE in vendor partition also means Android OS relies on updates of the vendor partition to get ANGLE. While in general ANGLE has an implicit dependency on the Vulkan driver in the vendor partition, we should be able to update it outside of the vendor parition. This patch changes the loading the ANGLE binaries with the assumption that ANGLE binaries is part of the system image. This will give Android OS the benefit to ship and update ANGLE independently from vendor partition and hence shipping ANGLE is no longer blocked by updating the vendor partition. This will also allow Android to have minimal requirements on ANGLE. Bug: b/293503000 Test: atest CtsAngleIntegrationHostTestCases -c Change-Id: If32dd9ff8b023dc975930cb7bce7b003c10618e4 --- libs/graphicsenv/GraphicsEnv.cpp | 14 ++- opengl/libs/EGL/Loader.cpp | 149 ++++++++++++++----------- opengl/libs/EGL/egl_angle_platform.cpp | 4 +- 3 files changed, 97 insertions(+), 70 deletions(-) diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index ed5d5c1095..394a0002ed 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -575,17 +575,23 @@ android_namespace_t* GraphicsEnv::getAngleNamespace() { return mAngleNamespace; } - if (mAnglePath.empty() && !mShouldUseSystemAngle) { - ALOGV("mAnglePath is empty and not using system ANGLE, abort creating ANGLE namespace"); + // If ANGLE path is not set, it means ANGLE should not be used for this process; + // or if ANGLE path is set and set to use system ANGLE, then a namespace is not needed + // because: + // 1) if the default OpenGL ES driver is already ANGLE, then the loader will skip; + // 2) if the default OpenGL ES driver is native, then there's no symbol conflict; + // 3) if there's no OpenGL ES driver is preloaded, then there's no symbol conflict. + if (mAnglePath.empty() || mShouldUseSystemAngle) { + ALOGV("mAnglePath is empty or use system ANGLE, abort creating ANGLE namespace"); return nullptr; } // Construct the search paths for system ANGLE. const char* const defaultLibraryPaths = #if defined(__LP64__) - "/vendor/lib64/egl:/system/lib64/egl"; + "/vendor/lib64/egl:/system/lib64"; #else - "/vendor/lib/egl:/system/lib/egl"; + "/vendor/lib/egl:/system/lib"; #endif // If the application process will run on top of system ANGLE, construct the namespace diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 04e2fffaef..3d31e67289 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -66,6 +66,7 @@ namespace android { static const char* PERSIST_DRIVER_SUFFIX_PROPERTY = "persist.graphics.egl"; static const char* RO_DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl"; static const char* RO_BOARD_PLATFORM_PROPERTY = "ro.board.platform"; +static const char* ANGLE_SUFFIX_VALUE = "angle"; static const char* HAL_SUBNAME_KEY_PROPERTIES[3] = { PERSIST_DRIVER_SUFFIX_PROPERTY, @@ -80,6 +81,13 @@ static const char* const VENDOR_LIB_EGL_DIR = "/vendor/lib/egl"; #endif +static const char* const SYSTEM_LIB_DIR = +#if defined(__LP64__) + "/system/lib64"; +#else + "/system/lib"; +#endif + static void* do_dlopen(const char* path, int mode) { ATRACE_CALL(); return dlopen(path, mode); @@ -434,98 +442,108 @@ void Loader::init_api(void* dso, } } -static void* load_system_driver(const char* kind, const char* suffix, const bool exact) { - ATRACE_CALL(); - class MatchFile { - public: - static std::string find(const char* libraryName, const bool exact) { - std::string absolutePath; - if (findLibPath(absolutePath, libraryName, exact)) { - return absolutePath; - } - - // Driver not found. gah. - return std::string(); +static std::string findLibrary(const std::string libraryName, const std::string searchPath, + const bool exact) { + if (exact) { + std::string absolutePath = searchPath + "/" + libraryName + ".so"; + if (!access(absolutePath.c_str(), R_OK)) { + return absolutePath; } - private: - static bool findLibPath(std::string& result, const std::string& pattern, bool exact) { - const std::string vendorLibEglDirString = std::string(VENDOR_LIB_EGL_DIR); - if (exact) { - std::string absolutePath = vendorLibEglDirString + "/" + pattern + ".so"; - if (!access(absolutePath.c_str(), R_OK)) { - result = absolutePath; - return true; - } - return false; - } + return std::string(); + } - DIR* d = opendir(VENDOR_LIB_EGL_DIR); - if (d != nullptr) { - struct dirent* e; - while ((e = readdir(d)) != nullptr) { - if (e->d_type == DT_DIR) { - continue; - } - if (!strcmp(e->d_name, "libGLES_android.so")) { - // always skip the software renderer - continue; - } - if (strstr(e->d_name, pattern.c_str()) == e->d_name) { - if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) { - result = vendorLibEglDirString + "/" + e->d_name; - closedir(d); - return true; - } - } + DIR* d = opendir(searchPath.c_str()); + if (d != nullptr) { + struct dirent* e; + while ((e = readdir(d)) != nullptr) { + if (e->d_type == DT_DIR) { + continue; + } + if (!strcmp(e->d_name, "libGLES_android.so")) { + // always skip the software renderer + continue; + } + if (strstr(e->d_name, libraryName.c_str()) == e->d_name) { + if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) { + std::string result = searchPath + "/" + e->d_name; + closedir(d); + return result; } - closedir(d); } - return false; } - }; + closedir(d); + } + // Driver not found. gah. + return std::string(); +} + +static void* load_system_driver(const char* kind, const char* suffix, const bool exact) { + ATRACE_CALL(); std::string libraryName = std::string("lib") + kind; if (suffix) { libraryName += std::string("_") + suffix; } else if (!exact) { - // Deprecated: we look for files that match - // libGLES_*.so, or: + // Deprecated for devices launching in Android 14 + // Look for files that match + // libGLES_*.so, or, // libEGL_*.so, libGLESv1_CM_*.so, libGLESv2_*.so libraryName += std::string("_"); } - std::string absolutePath = MatchFile::find(libraryName.c_str(), exact); + + void* dso = nullptr; + + // Only use sphal namespace when system ANGLE binaries are not the default drivers. + const bool useSphalNamespace = strcmp(suffix, ANGLE_SUFFIX_VALUE) != 0; + + const std::string absolutePath = + findLibrary(libraryName, useSphalNamespace ? VENDOR_LIB_EGL_DIR : SYSTEM_LIB_PATH, + exact); if (absolutePath.empty()) { // this happens often, we don't want to log an error return nullptr; } - const char* const driver_absolute_path = absolutePath.c_str(); + const char* const driverAbsolutePath = absolutePath.c_str(); + + // Currently the default driver is unlikely to be ANGLE on most devices, + // hence put this first. + if (useSphalNamespace) { + // Try to load drivers from the 'sphal' namespace, if it exist. Fall back to + // the original routine when the namespace does not exist. + // See /system/linkerconfig/contents/namespace for the configuration of the + // sphal namespace. + dso = do_android_load_sphal_library(driverAbsolutePath, RTLD_NOW | RTLD_LOCAL); + } else { + // Try to load drivers from the default namespace. + // See /system/linkerconfig/contents/namespace for the configuration of the + // default namespace. + dso = do_dlopen(driverAbsolutePath, RTLD_NOW | RTLD_LOCAL); + } - // Try to load drivers from the 'sphal' namespace, if it exist. Fall back to - // the original routine when the namespace does not exist. - // See /system/core/rootdir/etc/ld.config.txt for the configuration of the - // sphal namespace. - void* dso = do_android_load_sphal_library(driver_absolute_path, - RTLD_NOW | RTLD_LOCAL); if (dso == nullptr) { const char* err = dlerror(); - ALOGE("load_driver(%s): %s", driver_absolute_path, err ? err : "unknown"); + ALOGE("load_driver(%s): %s", driverAbsolutePath, err ? err : "unknown"); return nullptr; } - ALOGD("loaded %s", driver_absolute_path); + ALOGV("loaded %s", driverAbsolutePath); return dso; } static void* load_angle(const char* kind, android_namespace_t* ns) { - const android_dlextinfo dlextinfo = { - .flags = ANDROID_DLEXT_USE_NAMESPACE, - .library_namespace = ns, - }; - std::string name = std::string("lib") + kind + "_angle.so"; + void* so = nullptr; - void* so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo); + if (android::GraphicsEnv::getInstance().shouldUseSystemAngle()) { + so = do_dlopen(name.c_str(), RTLD_NOW | RTLD_LOCAL); + } else { + const android_dlextinfo dlextinfo = { + .flags = ANDROID_DLEXT_USE_NAMESPACE, + .library_namespace = ns, + }; + so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo); + } if (so) { return so; @@ -563,11 +581,13 @@ Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) { ATRACE_CALL(); android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace(); - if (!ns) { + // ANGLE namespace is used for loading ANGLE from apk, and hence if namespace is not + // constructed, it means ANGLE apk is not set to be the OpenGL ES driver. + // Hence skip if ANGLE apk and system ANGLE are not set to be the OpenGL ES driver. + if (!ns && !android::GraphicsEnv::getInstance().shouldUseSystemAngle()) { return nullptr; } - android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::ANGLE); driver_t* hnd = nullptr; // ANGLE doesn't ship with GLES library, and thus we skip GLES driver. @@ -592,6 +612,7 @@ void Loader::attempt_to_init_angle_backend(void* dso, egl_connection_t* cnx) { if (pANGLEGetDisplayPlatform) { ALOGV("ANGLE GLES library loaded"); cnx->angleLoaded = true; + android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::ANGLE); } else { ALOGV("Native GLES library loaded"); cnx->angleLoaded = false; diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp index ee605c2011..a8395d99c4 100644 --- a/opengl/libs/EGL/egl_angle_platform.cpp +++ b/opengl/libs/EGL/egl_angle_platform.cpp @@ -128,8 +128,8 @@ bool initializeAnglePlatform(EGLDisplay dpy) { return false; } } else { - // If we are here, ANGLE is loaded as built-in gl driver in the sphal. - so = android_load_sphal_library(kAngleEs2Lib, kAngleDlFlags); + // If we are here, ANGLE is loaded as the default OpenGL ES driver. + so = dlopen(kAngleEs2Lib, kAngleDlFlags); if (so) { ALOGD("dlopen (%s) success at %p", kAngleEs2Lib, so); } else { -- GitLab From 80aa2e697c90f7b940060afa035c4e22df3b5237 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Mon, 23 Oct 2023 14:36:18 +0900 Subject: [PATCH 0881/1187] Add prebuilt_etc for secure_element XML files Bug: 300011111 Test: VtsHalSecureElementTargetTest Change-Id: I5d5afbe6e1d6cb7f07493a701f117ea6770a3425 --- data/etc/Android.bp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 1418e1f7a6..e65aa5d852 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -130,6 +130,24 @@ prebuilt_etc { defaults: ["frameworks_native_data_etc_defaults"], } +prebuilt_etc { + name: "android.hardware.se.omapi.ese.prebuilt.xml", + src: "android.hardware.se.omapi.ese.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + +prebuilt_etc { + name: "android.hardware.se.omapi.sd.prebuilt.xml", + src: "android.hardware.se.omapi.sd.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + +prebuilt_etc { + name: "android.hardware.se.omapi.uicc.prebuilt.xml", + src: "android.hardware.se.omapi.uicc.xml", + defaults: ["frameworks_native_data_etc_defaults"], +} + prebuilt_etc { name: "android.hardware.sensor.accelerometer_limited_axes_uncalibrated.prebuilt.xml", src: "android.hardware.sensor.accelerometer_limited_axes_uncalibrated.xml", -- GitLab From 853b73a7ac95b19a9caf60e4016746604cdd43fc Mon Sep 17 00:00:00 2001 From: Kean Mariotti Date: Thu, 27 Jul 2023 12:40:30 +0000 Subject: [PATCH 0882/1187] Adapt dumpstate to perfetto-based SurfaceFlinger tracing - Include system trace (perfetto) into the pre-dumped data. - Snapshot the system trace (perfetto) first to avoid that dumpsys critical's activity pushes out interesting data from the trace ring buffer. Bug: b/293429094 Bug: b/296650898 Test: atest dumpstate_test && \ atest com.android.os.bugreports.tests.BugreportManagerTest Ignore-AOSP-First: depends on changes (surfaceflinger) that cannot go into AOSP Change-Id: Iccf9f92989c317a29ffa4c806afd6eab1da7976a --- cmds/dumpstate/dumpstate.cpp | 85 +++++++++---------------- cmds/dumpstate/dumpstate.h | 6 -- cmds/dumpstate/tests/dumpstate_test.cpp | 1 - 3 files changed, 31 insertions(+), 61 deletions(-) diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 33f6d38cc6..ea3090349e 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -1088,8 +1088,14 @@ static void MaybeAddSystemTraceToZip() { // This function copies into the .zip the system trace that was snapshotted // by the early call to MaybeSnapshotSystemTrace(), if any background // tracing was happening. - if (!ds.has_system_trace_) { - // No background trace was happening at the time dumpstate was invoked. + bool system_trace_exists = access(SYSTEM_TRACE_SNAPSHOT, F_OK) == 0; + if (!system_trace_exists) { + // No background trace was happening at the time MaybeSnapshotSystemTrace() was invoked. + if (!PropertiesHelper::IsUserBuild()) { + MYLOGI( + "No system traces found. Check for previously uploaded traces by looking for " + "go/trace-uuid in logcat") + } return; } ds.AddZipEntry( @@ -1649,8 +1655,6 @@ Dumpstate::RunStatus Dumpstate::dumpstate() { dump_board = ds.dump_pool_->enqueueTaskWithFd( DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1); dump_checkins = ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1); - post_process_ui_traces = ds.dump_pool_->enqueueTask( - POST_PROCESS_UI_TRACES_TASK, &Dumpstate::MaybePostProcessUiTraces, &ds); } // Dump various things. Note that anything that takes "long" (i.e. several seconds) should @@ -1860,12 +1864,6 @@ Dumpstate::RunStatus Dumpstate::dumpstate() { DumpIncidentReport); } - if (ds.dump_pool_) { - WaitForTask(std::move(post_process_ui_traces)); - } else { - RUN_SLOW_FUNCTION_AND_LOG(POST_PROCESS_UI_TRACES_TASK, MaybePostProcessUiTraces); - } - MaybeAddUiTracesToZip(); return Dumpstate::RunStatus::OK; @@ -3071,6 +3069,7 @@ void Dumpstate::Cancel() { } void Dumpstate::PreDumpUiData() { + MaybeSnapshotSystemTrace(); MaybeSnapshotUiTraces(); } @@ -3257,25 +3256,23 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, // duration is logged into MYLOG instead. PrintHeader(); - bool is_dumpstate_restricted = options_->telephony_only - || options_->wifi_only - || options_->limited_only; - if (!is_dumpstate_restricted) { - // Invoke critical dumpsys first to preserve system state, before doing anything else. - RunDumpsysCritical(); - } - MaybeTakeEarlyScreenshot(); - + bool is_dumpstate_restricted = + options_->telephony_only || options_->wifi_only || options_->limited_only; if (!is_dumpstate_restricted) { // Snapshot the system trace now (if running) to avoid that dumpstate's // own activity pushes out interesting data from the trace ring buffer. // The trace file is added to the zip by MaybeAddSystemTraceToZip(). MaybeSnapshotSystemTrace(); + // Invoke critical dumpsys to preserve system state, before doing anything else. + RunDumpsysCritical(); + // Snapshot the UI traces now (if running). // The trace files will be added to bugreport later. MaybeSnapshotUiTraces(); } + + MaybeTakeEarlyScreenshot(); onUiIntensiveBugreportDumpsFinished(calling_uid); MaybeCheckUserConsent(calling_uid, calling_package); if (options_->telephony_only) { @@ -3372,6 +3369,19 @@ void Dumpstate::MaybeTakeEarlyScreenshot() { } void Dumpstate::MaybeSnapshotSystemTrace() { + // When capturing traces via bugreport handler (BH), this function will be invoked twice: + // 1) When BH invokes IDumpstate::PreDumpUiData() + // 2) When BH invokes IDumpstate::startBugreport(flags = BUGREPORT_USE_PREDUMPED_UI_DATA) + // In this case we don't want to re-invoke perfetto in step 2. + // In all other standard invocation states, this function is invoked once + // without the flag BUGREPORT_USE_PREDUMPED_UI_DATA. + if (options_->use_predumped_ui_data) { + return; + } + + // If a stale file exists already, remove it. + unlink(SYSTEM_TRACE_SNAPSHOT); + // If a background system trace is happening and is marked as "suitable for // bugreport" (i.e. bugreport_score > 0 in the trace config), this command // will stop it and serialize into SYSTEM_TRACE_SNAPSHOT. In the (likely) @@ -3379,14 +3389,8 @@ void Dumpstate::MaybeSnapshotSystemTrace() { // Note: this should not be enqueued as we need to freeze the trace before // dumpstate starts. Otherwise the trace ring buffers will contain mostly // the dumpstate's own activity which is irrelevant. - int res = RunCommand( - "SERIALIZE PERFETTO TRACE", - {"perfetto", "--save-for-bugreport"}, - CommandOptions::WithTimeout(10) - .DropRoot() - .CloseAllFileDescriptorsOnExec() - .Build()); - has_system_trace_ = res == 0; + RunCommand("SERIALIZE PERFETTO TRACE", {"perfetto", "--save-for-bugreport"}, + CommandOptions::WithTimeout(10).DropRoot().CloseAllFileDescriptorsOnExec().Build()); // MaybeAddSystemTraceToZip() will take care of copying the trace in the zip // file in the later stages. } @@ -3413,33 +3417,6 @@ void Dumpstate::MaybeSnapshotUiTraces() { "", command, CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build()); } - - // This command needs to be run as root - static const auto SURFACEFLINGER_COMMAND_SAVE_ALL_TRACES = std::vector { - "service", "call", "SurfaceFlinger", "1042" - }; - // Empty name because it's not intended to be classified as a bugreport section. - // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport. - RunCommand( - "", SURFACEFLINGER_COMMAND_SAVE_ALL_TRACES, - CommandOptions::WithTimeout(10).Always().AsRoot().RedirectStderr().Build()); -} - -void Dumpstate::MaybePostProcessUiTraces() { - if (PropertiesHelper::IsUserBuild()) { - return; - } - - RunCommand( - // Empty name because it's not intended to be classified as a bugreport section. - // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport. - "", { - "/system/xbin/su", "system", - "/system/bin/layertracegenerator", - "/data/misc/wmtrace/transactions_trace.winscope", - "/data/misc/wmtrace/layers_trace_from_transactions.winscope" - }, - CommandOptions::WithTimeout(120).Always().RedirectStderr().Build()); } void Dumpstate::MaybeAddUiTracesToZip() { diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 0a032ecfc3..5913f6b1a7 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -473,11 +473,6 @@ class Dumpstate { // Whether it should take an screenshot earlier in the process. bool do_early_screenshot_ = false; - // This is set to true when the trace snapshot request in the early call to - // MaybeSnapshotSystemTrace(). When this is true, the later stages of - // dumpstate will append the trace to the zip archive. - bool has_system_trace_ = false; - std::unique_ptr progress_; // When set, defines a socket file-descriptor use to report progress to bugreportz @@ -570,7 +565,6 @@ class Dumpstate { void MaybeTakeEarlyScreenshot(); void MaybeSnapshotSystemTrace(); void MaybeSnapshotUiTraces(); - void MaybePostProcessUiTraces(); void MaybeAddUiTracesToZip(); void onUiIntensiveBugreportDumpsFinished(int32_t calling_uid); diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index a417837ef9..fc828864d5 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -1000,7 +1000,6 @@ TEST_F(DumpstateTest, DumpPool_withParallelRunDisabled_isNull) { TEST_F(DumpstateTest, PreDumpUiData) { // These traces are always enabled, i.e. they are always pre-dumped const std::vector uiTraces = { - std::filesystem::path{"/data/misc/wmtrace/transactions_trace.winscope"}, std::filesystem::path{"/data/misc/wmtrace/wm_transition_trace.winscope"}, std::filesystem::path{"/data/misc/wmtrace/shell_transition_trace.winscope"}, }; -- GitLab From 54adbb2bd72a887bb1a5a83ce228b828895c49e9 Mon Sep 17 00:00:00 2001 From: Cody Northrop Date: Mon, 23 Oct 2023 15:39:38 +0000 Subject: [PATCH 0883/1187] EGL: Close Multifile Blobcache files after mapping When loading entries from disk, we don't need to keep the files open after mapping their contents. Per mmap documentation: After the mmap() call has returned, the file descriptor, fd, can be closed immediately without invalidating the mapping. https://man7.org/linux/man-pages/man2/mmap.2.html This will prevent consuming excessive file descriptors, which are a limited resource. Added new test that ensures file descriptors do not remain open. Test: libEGL_test, EGL_test, restricted_trace_perf.py Bug: b/286809755 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:5f8117acd45348704629a8aa7bd2169a5ad6a547) Merged-In: I6317fdbce340a8e7cbf3020ad41386cf9915dd2d Change-Id: I6317fdbce340a8e7cbf3020ad41386cf9915dd2d --- opengl/libs/EGL/MultifileBlobCache.cpp | 16 ++++-- opengl/libs/EGL/MultifileBlobCache_test.cpp | 54 +++++++++++++++++++++ 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/opengl/libs/EGL/MultifileBlobCache.cpp b/opengl/libs/EGL/MultifileBlobCache.cpp index 7ffdac7ea7..ed3c616b92 100644 --- a/opengl/libs/EGL/MultifileBlobCache.cpp +++ b/opengl/libs/EGL/MultifileBlobCache.cpp @@ -48,9 +48,8 @@ namespace { void freeHotCacheEntry(android::MultifileHotCache& entry) { if (entry.entryFd != -1) { // If we have an fd, then this entry was added to hot cache via INIT or GET - // We need to unmap and close the entry + // We need to unmap the entry munmap(entry.entryBuffer, entry.entrySize); - close(entry.entryFd); } else { // Otherwise, this was added to hot cache during SET, so it was never mapped // and fd was only on the deferred thread. @@ -143,6 +142,7 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s if (result != sizeof(MultifileHeader)) { ALOGE("Error reading MultifileHeader from cache entry (%s): %s", fullPath.c_str(), std::strerror(errno)); + close(fd); return; } @@ -152,6 +152,7 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s if (remove(fullPath.c_str()) != 0) { ALOGE("Error removing %s: %s", fullPath.c_str(), std::strerror(errno)); } + close(fd); continue; } @@ -161,6 +162,10 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s // Memory map the file uint8_t* mappedEntry = reinterpret_cast( mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fd, 0)); + + // We can close the file now and the mmap will remain + close(fd); + if (mappedEntry == MAP_FAILED) { ALOGE("Failed to mmap cacheEntry, error: %s", std::strerror(errno)); return; @@ -206,13 +211,11 @@ MultifileBlobCache::MultifileBlobCache(size_t maxKeySize, size_t maxValueSize, s if (!addToHotCache(entryHash, fd, mappedEntry, fileSize)) { ALOGE("INIT Failed to add %u to hot cache", entryHash); munmap(mappedEntry, fileSize); - close(fd); return; } } else { // If we're not keeping it in hot cache, unmap it now munmap(mappedEntry, fileSize); - close(fd); } } closedir(dir); @@ -401,9 +404,12 @@ EGLsizeiANDROID MultifileBlobCache::get(const void* key, EGLsizeiANDROID keySize // Memory map the file cacheEntry = reinterpret_cast(mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fd, 0)); + + // We can close the file now and the mmap will remain + close(fd); + if (cacheEntry == MAP_FAILED) { ALOGE("Failed to mmap cacheEntry, error: %s", std::strerror(errno)); - close(fd); return 0; } diff --git a/opengl/libs/EGL/MultifileBlobCache_test.cpp b/opengl/libs/EGL/MultifileBlobCache_test.cpp index dbee13bb2e..1639be6480 100644 --- a/opengl/libs/EGL/MultifileBlobCache_test.cpp +++ b/opengl/libs/EGL/MultifileBlobCache_test.cpp @@ -42,6 +42,8 @@ protected: virtual void TearDown() { mMBC.reset(); } + int getFileDescriptorCount(); + std::unique_ptr mTempFile; std::unique_ptr mMBC; }; @@ -216,4 +218,56 @@ TEST_F(MultifileBlobCacheTest, CacheMinKeyAndValueSizeSucceeds) { ASSERT_EQ('y', buf[0]); } +int MultifileBlobCacheTest::getFileDescriptorCount() { + DIR* directory = opendir("/proc/self/fd"); + + int fileCount = 0; + struct dirent* entry; + while ((entry = readdir(directory)) != NULL) { + fileCount++; + // printf("File: %s\n", entry->d_name); + } + + closedir(directory); + return fileCount; +} + +TEST_F(MultifileBlobCacheTest, EnsureFileDescriptorsClosed) { + // Populate the cache with a bunch of entries + size_t kLargeNumberOfEntries = 1024; + for (int i = 0; i < kLargeNumberOfEntries; i++) { + // printf("Caching: %i", i); + + // Use the index as the key and value + mMBC->set(&i, sizeof(i), &i, sizeof(i)); + + int result = 0; + ASSERT_EQ(sizeof(i), mMBC->get(&i, sizeof(i), &result, sizeof(result))); + ASSERT_EQ(i, result); + } + + // Ensure we don't have a bunch of open fds + ASSERT_LT(getFileDescriptorCount(), kLargeNumberOfEntries / 2); + + // Close the cache so everything writes out + mMBC->finish(); + mMBC.reset(); + + // Now open it again and ensure we still don't have a bunch of open fds + mMBC.reset( + new MultifileBlobCache(kMaxKeySize, kMaxValueSize, kMaxTotalSize, &mTempFile->path[0])); + + // Check after initialization + ASSERT_LT(getFileDescriptorCount(), kLargeNumberOfEntries / 2); + + for (int i = 0; i < kLargeNumberOfEntries; i++) { + int result = 0; + ASSERT_EQ(sizeof(i), mMBC->get(&i, sizeof(i), &result, sizeof(result))); + ASSERT_EQ(i, result); + } + + // And again after we've actually used it + ASSERT_LT(getFileDescriptorCount(), kLargeNumberOfEntries / 2); +} + } // namespace android -- GitLab From 657de462d7f1a06067345b9615b379a035c332f4 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Mon, 23 Oct 2023 17:18:30 +0000 Subject: [PATCH 0884/1187] Mention in safety comment that Parcel can't be Sync. Bug: 300462758 Change-Id: I096814fae6bc9fcd67d72a8d11025557d2112034 --- libs/binder/rust/src/parcel.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs index 3c615edbc0..f9f135d572 100644 --- a/libs/binder/rust/src/parcel.rs +++ b/libs/binder/rust/src/parcel.rs @@ -54,6 +54,10 @@ pub struct Parcel { /// Safety: This type guarantees that it owns the AParcel and that all access to /// the AParcel happens through the Parcel, so it is ok to send across threads. +/// +/// It would not be okay to implement Sync, because that would allow you to call +/// the reading methods from several threads in parallel, which would be a data +/// race on the cursor position inside the AParcel. unsafe impl Send for Parcel {} /// Container for a message (data and object references) that can be sent -- GitLab From 33558d327bdce855e88b7c17330d840d051b38b4 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 23 Oct 2023 20:20:25 +0000 Subject: [PATCH 0885/1187] libbinder_ndk: doc waitForService waits This doc incorrectly stated before that this API will wait forever if a service is not declared, but actually it has nothing to do with whether the service is declared. The idea was that if a service is not declared (and therefore not installed) it will wait forever. However, we should just not mention whether the service is declared and focus on whether the service is installed or not because that will determine whether this API returns. Bug: N/A Test: N/A Change-Id: Id07b5b5653a5b40b4c0d5a7e4f88e6b2440fff0a --- libs/binder/ndk/include_platform/android/binder_manager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h index 89fd7a38c1..316a79cfee 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_platform/android/binder_manager.h @@ -120,7 +120,7 @@ binder_status_t AServiceManager_registerLazyService(AIBinder* binder, const char /** * Gets a binder object with this specific instance name. Efficiently waits for the service. - * If the service is not declared, it will wait indefinitely. Requires the threadpool + * If the service is not ever registered, it will wait indefinitely. Requires the threadpool * to be started in the service. * This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible * for calling AIBinder_decStrong). -- GitLab From 851dbb83f9f3de3064c0e4293246f1388cdddcb4 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Mon, 23 Oct 2023 17:08:05 +0000 Subject: [PATCH 0886/1187] Limit number of fds written in parcel Certain input sequence causes fuzzers to pick a single fd from getRandomFd and write it to parcel. Check object count before writing more fds and binders in parcel. Test: m incidentd_service_fuzzer && adb sync data && adb shell /data/fuzz/x86_64/incidentd_service_fuzzer/incidentd_service_fuzzer -runs=1000 Test: atest fuzz_service_test Test: atest binderRecordReplayTest Bug: 296516864 Change-Id: I84359a7128fde359828c26ea43ac2559d1236708 --- libs/binder/tests/parcel_fuzzer/random_parcel.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp index f0beed234b..f367b419af 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp @@ -66,6 +66,11 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti }, // write FD [&]() { + // b/296516864 - Limit number of objects written to a parcel. + if (p->objectsCount() > 100) { + return; + } + if (options->extraFds.size() > 0 && provider.ConsumeBool()) { const base::unique_fd& fd = options->extraFds.at( provider.ConsumeIntegralInRange(0, @@ -82,7 +87,6 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti CHECK(OK == p->writeFileDescriptor(fds.begin()->release(), true /*takeOwnership*/)); - options->extraFds.insert(options->extraFds.end(), std::make_move_iterator(fds.begin() + 1), std::make_move_iterator(fds.end())); @@ -90,6 +94,11 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti }, // write binder [&]() { + // b/296516864 - Limit number of objects written to a parcel. + if (p->objectsCount() > 100) { + return; + } + sp binder; if (options->extraBinders.size() > 0 && provider.ConsumeBool()) { binder = options->extraBinders.at( -- GitLab From 1c6fe002e37b320594ac76d80dda0b74aedcf7a7 Mon Sep 17 00:00:00 2001 From: AdityaK Date: Mon, 23 Oct 2023 10:52:32 -0700 Subject: [PATCH 0887/1187] Fix visitor ``` external/libcxx/include/variant:587:19: error: static assertion failed due to requirement 'is_invocable_v<(anonymous namespace)::Visitor<(lambda at external/libchrome-gestures/src/activity_log.cc:310:7), (lambda at external/libchrome-gestures/src/activity_log.cc:314:7), (lambda at external/libchrome-gestures/src/activity_log.cc:318:7), (lambda at external/libchrome-gestures/src/activity_log.cc:322:7), (lambda at external/libchrome-gestures/src/activity_log.cc:326:7)>, const unsigned char &>': `std::visit` requires the visitor to be exhaustive. 587 | static_assert(is_invocable_v<_Visitor, _Values...>, ``` Change-Id: Idc9df90d9ca653c241e42818c5a80857ed945730 --- services/inputflinger/InputListener.cpp | 2 +- services/inputflinger/NotifyArgs.cpp | 2 +- .../inputflinger/reader/mapper/gestures/PropertyProvider.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp index aa55873aa5..ca5d5a11d5 100644 --- a/services/inputflinger/InputListener.cpp +++ b/services/inputflinger/InputListener.cpp @@ -39,7 +39,7 @@ std::list& operator+=(std::list& keep, std::list -struct Visitor : V... {}; +struct Visitor : V... { using V::operator()...; }; // explicit deduction guide (not needed as of C++20) template Visitor(V...) -> Visitor; diff --git a/services/inputflinger/NotifyArgs.cpp b/services/inputflinger/NotifyArgs.cpp index 408fbed99e..35d60eaaa2 100644 --- a/services/inputflinger/NotifyArgs.cpp +++ b/services/inputflinger/NotifyArgs.cpp @@ -233,7 +233,7 @@ NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs( // Helper to std::visit with lambdas. template -struct Visitor : V... {}; +struct Visitor : V... { using V::operator()...; }; // explicit deduction guide (not needed as of C++20) template Visitor(V...) -> Visitor; diff --git a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp index be2bfed691..69264f84ed 100644 --- a/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp +++ b/services/inputflinger/reader/mapper/gestures/PropertyProvider.cpp @@ -239,7 +239,7 @@ namespace { // Helper to std::visit with lambdas. template -struct Visitor : V... {}; +struct Visitor : V... { using V::operator()...; }; // explicit deduction guide (not needed as of C++20) template Visitor(V...) -> Visitor; -- GitLab From c62948ec5d29035a930c174f2105e8c76581629a Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 23 Oct 2023 07:22:01 -0700 Subject: [PATCH 0888/1187] Return unique_ptr from readFromParcel When KeyCharacterMap is read from parcel, there's no need to force the caller to store the object in a shared pointer. We can return a unique_ptr first, and let the caller decide on how exactly that lifetime should be managed. Bug: 274058082 Test: presubmit Change-Id: I8c5ec1e32a9304f6ad186bc0279f4c7bcbab77d8 --- include/input/KeyCharacterMap.h | 2 +- libs/input/KeyCharacterMap.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h index b2e8baade3..dfcf766402 100644 --- a/include/input/KeyCharacterMap.h +++ b/include/input/KeyCharacterMap.h @@ -146,7 +146,7 @@ public: #ifdef __linux__ /* Reads a key map from a parcel. */ - static std::shared_ptr readFromParcel(Parcel* parcel); + static std::unique_ptr readFromParcel(Parcel* parcel); /* Writes a key map to a parcel. */ void writeToParcel(Parcel* parcel) const; diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp index a4cd239a92..e2feabcbbe 100644 --- a/libs/input/KeyCharacterMap.cpp +++ b/libs/input/KeyCharacterMap.cpp @@ -613,14 +613,14 @@ void KeyCharacterMap::addLockedMetaKey(Vector& outEvents, } #ifdef __linux__ -std::shared_ptr KeyCharacterMap::readFromParcel(Parcel* parcel) { +std::unique_ptr KeyCharacterMap::readFromParcel(Parcel* parcel) { if (parcel == nullptr) { ALOGE("%s: Null parcel", __func__); return nullptr; } std::string loadFileName = parcel->readCString(); - std::shared_ptr map = - std::shared_ptr(new KeyCharacterMap(loadFileName)); + std::unique_ptr map = + std::make_unique(KeyCharacterMap(loadFileName)); map->mType = static_cast(parcel->readInt32()); map->mLayoutOverlayApplied = parcel->readBool(); size_t numKeys = parcel->readInt32(); -- GitLab From a2dce3e13b3b86ac0bf0e6ce081cc594029fac95 Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 24 Oct 2023 20:34:26 +0000 Subject: [PATCH 0889/1187] Prevent keyboards from being recognized as a stylus We are getting reports of keyboards and other peripherals being misconfigured as a stylus, because they report support for stylus buttons. To eliminate some of these misconfigurations, prevent anything detected as a alphabetical keyboard from being categorized as a stylus. Bug: 293996865 Test: None (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:3c28b94505b5c6edaeb7e0df3ace7cf3f8125887) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:0824e928e70da8c0fb78d9793a5a3f8f4f8f9db0) Merged-In: I3f071d2ac6a2b70abc1130b4d5df1509452bb63b Change-Id: I3f071d2ac6a2b70abc1130b4d5df1509452bb63b --- services/inputflinger/reader/EventHub.cpp | 3 ++- .../inputflinger/tests/InputReader_test.cpp | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 0354164155..c468d45c02 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -2409,7 +2409,8 @@ void EventHub::openDeviceLocked(const std::string& devicePath) { } // See if this device has any stylus buttons that we would want to fuse with touch data. - if (!device->classes.any(InputDeviceClass::TOUCH | InputDeviceClass::TOUCH_MT)) { + if (!device->classes.any(InputDeviceClass::TOUCH | InputDeviceClass::TOUCH_MT) && + !device->classes.any(InputDeviceClass::ALPHAKEY)) { for (int32_t keycode : STYLUS_BUTTON_KEYCODES) { if (device->hasKeycodeLocked(keycode)) { device->classes |= InputDeviceClass::EXTERNAL_STYLUS; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 5141acb5b9..a70f10b81c 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1476,6 +1476,24 @@ TEST_F(InputReaderIntegrationTest, ExternalStylusesButtons) { AllOf(UP, WithKeyCode(AKEYCODE_STYLUS_BUTTON_TERTIARY)))); } +TEST_F(InputReaderIntegrationTest, KeyboardWithStylusButtons) { + std::unique_ptr keyboard = + createUinputDevice("KeyboardWithStylusButtons", /*productId=*/99, + std::initializer_list{KEY_Q, KEY_W, KEY_E, + KEY_R, KEY_T, KEY_Y, + BTN_STYLUS, BTN_STYLUS2, + BTN_STYLUS3}); + ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); + + const auto device = findDeviceByName(keyboard->getName()); + ASSERT_TRUE(device.has_value()); + + // An alphabetical keyboard that reports stylus buttons should not be recognized as a stylus. + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, device->getSources()) + << "Unexpected source " << inputEventSourceToString(device->getSources()).c_str(); + ASSERT_EQ(AINPUT_KEYBOARD_TYPE_ALPHABETIC, device->getKeyboardType()); +} + /** * The Steam controller sends BTN_GEAR_DOWN and BTN_GEAR_UP for the two "paddle" buttons * on the back. In this test, we make sure that BTN_GEAR_DOWN / BTN_WHEEL and BTN_GEAR_UP -- GitLab From cddfc361807b9966e2583208ff8da447054e806f Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Tue, 22 Aug 2023 23:20:16 +0000 Subject: [PATCH 0890/1187] Add test to ensure a keyboard with HID usage support is not a stylus Bug: 291529805 Test: atest inputflinger_tests (cherry picked from commit 37a819b8cddc3944777b32d3ae4263ae89c33598) (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:79c90068a20e802c351ed3dedd975cc004d57b0c) Merged-In: I8a3565a827fe183997573f685110805e5b5bc306 Change-Id: I8a3565a827fe183997573f685110805e5b5bc306 --- .../inputflinger/tests/InputReader_test.cpp | 22 +++++++++++++++++++ services/inputflinger/tests/UinputDevice.cpp | 12 ++++++++++ services/inputflinger/tests/UinputDevice.h | 19 +++++++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index a70f10b81c..38b32b3632 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -1494,6 +1494,28 @@ TEST_F(InputReaderIntegrationTest, KeyboardWithStylusButtons) { ASSERT_EQ(AINPUT_KEYBOARD_TYPE_ALPHABETIC, device->getKeyboardType()); } +TEST_F(InputReaderIntegrationTest, HidUsageKeyboardIsNotAStylus) { + // Create a Uinput keyboard that simulates a keyboard that can report HID usage codes. The + // hid-input driver reports HID usage codes using the value for EV_MSC MSC_SCAN event. + std::unique_ptr keyboard = + createUinputDevice( + std::initializer_list{KEY_VOLUMEUP, KEY_VOLUMEDOWN}); + ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); + + const auto device = findDeviceByName(keyboard->getName()); + ASSERT_TRUE(device.has_value()); + + ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, device->getSources()) + << "Unexpected source " << inputEventSourceToString(device->getSources()).c_str(); + + // If a device supports reporting HID usage codes, it shouldn't automatically support + // stylus keys. + const std::vector keycodes{AKEYCODE_STYLUS_BUTTON_PRIMARY}; + uint8_t outFlags[] = {0}; + ASSERT_TRUE(mReader->hasKeys(device->getId(), AINPUT_SOURCE_KEYBOARD, keycodes, outFlags)); + ASSERT_EQ(0, outFlags[0]) << "Keyboard should not have stylus button"; +} + /** * The Steam controller sends BTN_GEAR_DOWN and BTN_GEAR_UP for the two "paddle" buttons * on the back. In this test, we make sure that BTN_GEAR_DOWN / BTN_WHEEL and BTN_GEAR_UP diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp index 97a26141e0..5a654c907d 100644 --- a/services/inputflinger/tests/UinputDevice.cpp +++ b/services/inputflinger/tests/UinputDevice.cpp @@ -157,6 +157,18 @@ void UinputExternalStylusWithPressure::setPressure(int32_t pressure) { injectEvent(EV_SYN, SYN_REPORT, 0); } +// --- UinputKeyboardWithHidUsage --- + +UinputKeyboardWithHidUsage::UinputKeyboardWithHidUsage(std::initializer_list keys) + : UinputKeyboard(DEVICE_NAME, PRODUCT_ID, keys) {} + +void UinputKeyboardWithHidUsage::configureDevice(int fd, uinput_user_dev* device) { + UinputKeyboard::configureDevice(fd, device); + + ioctl(fd, UI_SET_EVBIT, EV_MSC); + ioctl(fd, UI_SET_MSCBIT, MSC_SCAN); +} + // --- UinputTouchScreen --- UinputTouchScreen::UinputTouchScreen(const Rect& size) diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h index 51e331df8f..55996b8bfe 100644 --- a/services/inputflinger/tests/UinputDevice.h +++ b/services/inputflinger/tests/UinputDevice.h @@ -165,13 +165,30 @@ private: explicit UinputExternalStylusWithPressure(); }; +// --- UinputKeyboardWithUsage --- +// A keyboard that supports EV_MSC MSC_SCAN through which it can report HID usage codes. + +class UinputKeyboardWithHidUsage : public UinputKeyboard { +public: + static constexpr const char* DEVICE_NAME = "Test Uinput Keyboard With Usage"; + static constexpr int16_t PRODUCT_ID = 47; + + template + friend std::unique_ptr createUinputDevice(Ts... args); + +protected: + explicit UinputKeyboardWithHidUsage(std::initializer_list keys); + + void configureDevice(int fd, uinput_user_dev* device) override; +}; + // --- UinputTouchScreen --- // A multi-touch touchscreen device with specific size that also supports styluses. class UinputTouchScreen : public UinputKeyboard { public: static constexpr const char* DEVICE_NAME = "Test Uinput Touch Screen"; - static constexpr int16_t PRODUCT_ID = 47; + static constexpr int16_t PRODUCT_ID = 48; static const int32_t RAW_TOUCH_MIN = 0; static const int32_t RAW_TOUCH_MAX = 31; -- GitLab From 6eec688e0b670a9ae1e19dce57a1933da1c8e300 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 24 Oct 2023 23:00:02 +0000 Subject: [PATCH 0891/1187] libbinder_ndk: add __ANDROID_VENDOR__ error __ANDROID_VNDK__ is not enough, or it never was Bug: 295996418 Test: N/A Change-Id: Id004d64f0be9cc459cb9dc8c4f05e3ff631f8133 --- libs/binder/ndk/stability.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/binder/ndk/stability.cpp b/libs/binder/ndk/stability.cpp index 7eafb9c025..73eb863706 100644 --- a/libs/binder/ndk/stability.cpp +++ b/libs/binder/ndk/stability.cpp @@ -27,6 +27,10 @@ using ::android::internal::Stability; #error libbinder_ndk should only be built in a system context #endif +#ifdef __ANDROID_VENDOR__ +#error libbinder_ndk should only be built in a system context +#endif + #ifdef __ANDROID_NDK__ #error libbinder_ndk should only be built in a system context #endif -- GitLab From 8b731c1a050deb07ba3ab97179bbe9d648920900 Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Tue, 24 Oct 2023 09:56:24 -0500 Subject: [PATCH 0892/1187] TransactionTraceWriter - always overwrite old files Update TransactionTraceWriter to overwrite files older than ten minutes, even when overwrite is set to false. Bug: 302249537 Bug: 306466281 Test: TransactionTraceWriterTest Change-Id: Ic49662251debe3ccd2f0bba37535680733793c2d --- services/surfaceflinger/Android.bp | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 16 +++++++++- services/surfaceflinger/fuzzer/Android.bp | 1 + .../unittests/TransactionTraceWriterTest.cpp | 31 ++++++++++++++++++- 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 9d0f2858ec..17fa7bedf7 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -245,6 +245,7 @@ cc_defaults { ], static_libs: [ "android.frameworks.displayservice@1.0", + "libc++fs", "libdisplayservicehidl", "libserviceutils", ], diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9b9a67aa5f..dc19cbdb60 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -103,6 +103,7 @@ #include #include #include +#include #include #include #include @@ -309,6 +310,19 @@ uint32_t getLayerIdFromSurfaceControl(sp surfaceControl) { return LayerHandle::getLayerId(surfaceControl->getHandle()); } +/** + * Returns true if the file at path exists and is newer than duration. + */ +bool fileNewerThan(const std::string& path, std::chrono::minutes duration) { + using Clock = std::filesystem::file_time_type::clock; + std::error_code error; + std::filesystem::file_time_type updateTime = std::filesystem::last_write_time(path, error); + if (error) { + return false; + } + return duration > (Clock::now() - updateTime); +} + } // namespace anonymous // --------------------------------------------------------------------------- @@ -899,7 +913,7 @@ void SurfaceFlinger::initTransactionTraceWriter() { TransactionTraceWriter::getInstance().setWriterFunction( [&](const std::string& filename, bool overwrite) { auto writeFn = [&]() { - if (!overwrite && access(filename.c_str(), F_OK) == 0) { + if (!overwrite && fileNewerThan(filename, std::chrono::minutes{10})) { ALOGD("TransactionTraceWriter: file=%s already exists", filename.c_str()); return; } diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp index 0f9060dbdb..910e6852a9 100644 --- a/services/surfaceflinger/fuzzer/Android.bp +++ b/services/surfaceflinger/fuzzer/Android.bp @@ -31,6 +31,7 @@ cc_defaults { ], static_libs: [ "android.hardware.graphics.composer@2.1-resources", + "libc++fs", "libgmock", "libgui_mocks", "libgmock_ndk", diff --git a/services/surfaceflinger/tests/unittests/TransactionTraceWriterTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTraceWriterTest.cpp index 379135e270..4a83d445fc 100644 --- a/services/surfaceflinger/tests/unittests/TransactionTraceWriterTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionTraceWriterTest.cpp @@ -45,12 +45,21 @@ protected: TestableSurfaceFlinger mFlinger; }; -TEST_F(TransactionTraceWriterTest, canWriteToFile) { +// Check that a new file is written if overwrite=true and no file exists. +TEST_F(TransactionTraceWriterTest, canWriteToFile_overwriteTrue) { TransactionTraceWriter::getInstance().invokeForTest(mFilename, /* overwrite */ true); EXPECT_EQ(access(mFilename.c_str(), F_OK), 0); verifyTraceFile(); } +// Check that a new file is written if overwrite=false and no file exists. +TEST_F(TransactionTraceWriterTest, canWriteToFile_overwriteFalse) { + TransactionTraceWriter::getInstance().invokeForTest(mFilename, /* overwrite */ false); + EXPECT_EQ(access(mFilename.c_str(), F_OK), 0); + verifyTraceFile(); +} + +// Check that an existing file is overwritten when overwrite=true. TEST_F(TransactionTraceWriterTest, canOverwriteFile) { std::string testLine = "test"; { @@ -61,6 +70,7 @@ TEST_F(TransactionTraceWriterTest, canOverwriteFile) { verifyTraceFile(); } +// Check that an existing file isn't overwritten when it is new and overwrite=false. TEST_F(TransactionTraceWriterTest, doNotOverwriteFile) { std::string testLine = "test"; { @@ -76,4 +86,23 @@ TEST_F(TransactionTraceWriterTest, doNotOverwriteFile) { EXPECT_EQ(line, testLine); } } + +// Check that an existing file is overwritten when it is old and overwrite=false. +TEST_F(TransactionTraceWriterTest, overwriteOldFile) { + std::string testLine = "test"; + { + std::ofstream file(mFilename, std::ios::out); + file << testLine; + } + + // Update file modification time to 15 minutes ago. + using Clock = std::filesystem::file_time_type::clock; + std::error_code error; + std::filesystem::last_write_time(mFilename, Clock::now() - std::chrono::minutes{15}, error); + ASSERT_EQ(error.value(), 0); + + TransactionTraceWriter::getInstance().invokeForTest(mFilename, /* overwrite */ false); + verifyTraceFile(); +} + } // namespace android \ No newline at end of file -- GitLab From 3caae303bdeff661b0551ea32b5ac679aeb1f38a Mon Sep 17 00:00:00 2001 From: Tomasz Wasilczyk Date: Thu, 12 Oct 2023 20:57:02 +0000 Subject: [PATCH 0893/1187] Migrate off of base::StringPrintf Bug: 302723053 Test: mma Change-Id: Id7f0b1d0a11747a5a61a2550f05d7caaabf339a3 --- libs/binder/RpcState.cpp | 33 ++++++++++--------- libs/binder/servicedispatcher.cpp | 11 +++---- libs/binder/tests/binderRpcTest.cpp | 13 ++++---- libs/binder/tests/binderRpcTestCommon.h | 4 +-- .../tests/binderRpcTestServiceTrusty.cpp | 2 -- libs/binder/tests/binderRpcTestTrusty.cpp | 1 - libs/binder/tests/format.h | 29 ++++++++++++++++ libs/binder/trusty/binderRpcTest/rules.mk | 1 + .../trusty/binderRpcTest/service/rules.mk | 1 + 9 files changed, 62 insertions(+), 33 deletions(-) create mode 100644 libs/binder/tests/format.h diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 5046253837..26a2f4fa39 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -30,6 +29,7 @@ #include "Utils.h" #include +#include #include @@ -39,8 +39,6 @@ namespace android { -using base::StringPrintf; - #if RPC_FLAKE_PRONE void rpcMaybeWaitToFlake() { [[clang::no_destroy]] static std::random_device r; @@ -329,8 +327,10 @@ std::string RpcState::BinderNode::toString() const { desc = "(not promotable)"; } - return StringPrintf("node{%p times sent: %zu times recd: %zu type: %s}", - this->binder.unsafe_get(), this->timesSent, this->timesRecd, desc); + std::stringstream ss; + ss << "node{" << intptr_t(this->binder.unsafe_get()) << " times sent: " << this->timesSent + << " times recd: " << this->timesRecd << " type: " << desc << "}"; + return ss.str(); } RpcState::CommandData::CommandData(size_t size) : mSize(size) { @@ -1220,10 +1220,11 @@ status_t RpcState::validateParcel(const sp& session, const Parcel& p uint32_t protocolVersion = session->getProtocolVersion().value(); if (protocolVersion < RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE && !rpcFields->mObjectPositions.empty()) { - *errorMsg = StringPrintf("Parcel has attached objects but the session's protocol version " - "(%" PRIu32 ") is too old, must be at least %" PRIu32, - protocolVersion, - RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE); + std::stringstream ss; + ss << "Parcel has attached objects but the session's protocol version (" << protocolVersion + << ") is too old, must be at least " + << RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE; + *errorMsg = ss.str(); return BAD_VALUE; } @@ -1236,9 +1237,10 @@ status_t RpcState::validateParcel(const sp& session, const Parcel& p case RpcSession::FileDescriptorTransportMode::UNIX: { constexpr size_t kMaxFdsPerMsg = 253; if (rpcFields->mFds->size() > kMaxFdsPerMsg) { - *errorMsg = StringPrintf("Too many file descriptors in Parcel for unix " - "domain socket: %zu (max is %zu)", - rpcFields->mFds->size(), kMaxFdsPerMsg); + std::stringstream ss; + ss << "Too many file descriptors in Parcel for unix domain socket: " + << rpcFields->mFds->size() << " (max is " << kMaxFdsPerMsg << ")"; + *errorMsg = ss.str(); return BAD_VALUE; } break; @@ -1249,9 +1251,10 @@ status_t RpcState::validateParcel(const sp& session, const Parcel& p // available on Android constexpr size_t kMaxFdsPerMsg = 8; if (rpcFields->mFds->size() > kMaxFdsPerMsg) { - *errorMsg = StringPrintf("Too many file descriptors in Parcel for Trusty " - "IPC connection: %zu (max is %zu)", - rpcFields->mFds->size(), kMaxFdsPerMsg); + std::stringstream ss; + ss << "Too many file descriptors in Parcel for Trusty IPC connection: " + << rpcFields->mFds->size() << " (max is " << kMaxFdsPerMsg << ")"; + *errorMsg = ss.str(); return BAD_VALUE; } break; diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp index 5bf9680284..f2693dda95 100644 --- a/libs/binder/servicedispatcher.cpp +++ b/libs/binder/servicedispatcher.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -46,7 +45,6 @@ using android::base::LogdLogger; using android::base::LogId; using android::base::LogSeverity; using android::base::StdioLogger; -using android::base::StringPrintf; using std::string_view_literals::operator""sv; namespace { @@ -57,11 +55,12 @@ using android::debug::IAdbManager; int Usage(const char* program) { auto basename = Basename(program); - auto format = R"(dispatch calls to RPC service. + // clang-format off + LOG(ERROR) << R"(dispatch calls to RPC service. Usage: - %s [-g] [-i ] + )" << basename << R"( [-g] [-i ] : the service to connect to. - %s [-g] manager + )" << basename << R"( [-g] manager Runs an RPC-friendly service that redirects calls to servicemanager. -g: use getService() instead of checkService(). @@ -71,7 +70,7 @@ Usage: blocks until killed. Otherwise, writes error message to stderr and exits with non-zero code. )"; - LOG(ERROR) << StringPrintf(format, basename.c_str(), basename.c_str()); + // clang-format on return EX_USAGE; } diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 1340ea1d2c..bc34d4c36f 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -18,7 +18,6 @@ // only used on NDK tests outside of vendor #include #endif -#include #include #include @@ -59,12 +58,12 @@ constexpr char kTrustyIpcDevice[] = "/dev/trusty-ipc-dev0"; static std::string WaitStatusToString(int wstatus) { if (WIFEXITED(wstatus)) { - return base::StringPrintf("exit status %d", WEXITSTATUS(wstatus)); + return std::format("exit status {}", WEXITSTATUS(wstatus)); } if (WIFSIGNALED(wstatus)) { - return base::StringPrintf("term signal %d", WTERMSIG(wstatus)); + return std::format("term signal {}", WTERMSIG(wstatus)); } - return base::StringPrintf("unexpected state %d", wstatus); + return std::format("unexpected state {}", wstatus); } static void debugBacktrace(pid_t pid) { @@ -260,9 +259,9 @@ std::unique_ptr BinderRpc::createRpcTestSocketServerProcessEtc( bool noKernel = GetParam().noKernel; std::string path = android::base::GetExecutableDirectory(); - auto servicePath = android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(), - singleThreaded ? "_single_threaded" : "", - noKernel ? "_no_kernel" : ""); + auto servicePath = + std::format("{}/binder_rpc_test_service{}{}", path, + singleThreaded ? "_single_threaded" : "", noKernel ? "_no_kernel" : ""); base::unique_fd bootstrapClientFd, socketFd; diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h index eceff35e3e..786fab8133 100644 --- a/libs/binder/tests/binderRpcTestCommon.h +++ b/libs/binder/tests/binderRpcTestCommon.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -58,6 +57,7 @@ #include "../BuildFlags.h" #include "../FdTrigger.h" #include "../RpcState.h" // for debugging +#include "format.h" #include "utils/Errors.h" namespace android { @@ -91,7 +91,7 @@ static inline std::vector testVersions() { } static inline std::string trustyIpcPort(uint32_t serverVersion) { - return base::StringPrintf("com.android.trusty.binderRpcTestService.V%" PRIu32, serverVersion); + return std::format("com.android.trusty.binderRpcTestService.V{}", serverVersion); } enum class SocketType { diff --git a/libs/binder/tests/binderRpcTestServiceTrusty.cpp b/libs/binder/tests/binderRpcTestServiceTrusty.cpp index cb632e95bf..aaca8d091a 100644 --- a/libs/binder/tests/binderRpcTestServiceTrusty.cpp +++ b/libs/binder/tests/binderRpcTestServiceTrusty.cpp @@ -16,7 +16,6 @@ #define TLOG_TAG "binderRpcTestService" -#include #include #include #include @@ -28,7 +27,6 @@ #include "binderRpcTestCommon.h" using namespace android; -using android::base::StringPrintf; using binder::Status; static int gConnectionCounter = 0; diff --git a/libs/binder/tests/binderRpcTestTrusty.cpp b/libs/binder/tests/binderRpcTestTrusty.cpp index fcb83bdabd..8acaae6e95 100644 --- a/libs/binder/tests/binderRpcTestTrusty.cpp +++ b/libs/binder/tests/binderRpcTestTrusty.cpp @@ -16,7 +16,6 @@ #define LOG_TAG "binderRpcTest" -#include #include #include #include diff --git a/libs/binder/tests/format.h b/libs/binder/tests/format.h new file mode 100644 index 0000000000..b5440a43e4 --- /dev/null +++ b/libs/binder/tests/format.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 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. + */ + +// TODO(b/302723053): remove this header and replace with once b/175635923 is done +// ETA for this blocker is 2023-10-27~2023-11-10. +// Also, remember to remove fmtlib's format.cc from trusty makefiles. + +#if __has_include() +#include +#else +#include + +namespace std { +using fmt::format; +} +#endif \ No newline at end of file diff --git a/libs/binder/trusty/binderRpcTest/rules.mk b/libs/binder/trusty/binderRpcTest/rules.mk index 975f689d1a..e46ccfb967 100644 --- a/libs/binder/trusty/binderRpcTest/rules.mk +++ b/libs/binder/trusty/binderRpcTest/rules.mk @@ -21,6 +21,7 @@ MODULE := $(LOCAL_DIR) MANIFEST := $(LOCAL_DIR)/manifest.json MODULE_SRCS += \ + $(FMTLIB_DIR)/src/format.cc \ $(LIBBINDER_TESTS_DIR)/binderRpcUniversalTests.cpp \ $(LIBBINDER_TESTS_DIR)/binderRpcTestCommon.cpp \ $(LIBBINDER_TESTS_DIR)/binderRpcTestTrusty.cpp \ diff --git a/libs/binder/trusty/binderRpcTest/service/rules.mk b/libs/binder/trusty/binderRpcTest/service/rules.mk index 5d1a51dca2..50ae3d25fa 100644 --- a/libs/binder/trusty/binderRpcTest/service/rules.mk +++ b/libs/binder/trusty/binderRpcTest/service/rules.mk @@ -21,6 +21,7 @@ MODULE := $(LOCAL_DIR) MANIFEST := $(LOCAL_DIR)/manifest.json MODULE_SRCS := \ + $(FMTLIB_DIR)/src/format.cc \ $(LIBBINDER_TESTS_DIR)/binderRpcTestCommon.cpp \ $(LIBBINDER_TESTS_DIR)/binderRpcTestServiceTrusty.cpp \ -- GitLab From 1715bac153cc8c0ac78b29074e9c590384426c5d Mon Sep 17 00:00:00 2001 From: Avichal Rakesh Date: Wed, 4 Oct 2023 15:10:39 -0700 Subject: [PATCH 0894/1187] NativeWindow: implement functions expected by AIDL ANativeWindow is now parcelable over stable interfaces by being wrapped in NativeWindow or Surface. The readFromParcel and writeToParcel functions are implemented for this class, but AIDL also expects some comparators and a toString function to be implemented for custom parcelables. This CL implements the comparison operators, and the toString function to allow NativeWindow/Surface to be used with AIDL interfaces and Parcelables. The operations simply compare/print the ANativeWindow pointer that is being managed by the object. Bug: 283283111 Test: Verified that Surface can be used in an AIDL file. Change-Id: I28ceded9ee1358884a6b1214269bb04a90749fc0 --- .../include/android/native_window_aidl.h | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/libs/nativewindow/include/android/native_window_aidl.h b/libs/nativewindow/include/android/native_window_aidl.h index a252245a10..adc1bf11a8 100644 --- a/libs/nativewindow/include/android/native_window_aidl.h +++ b/libs/nativewindow/include/android/native_window_aidl.h @@ -34,6 +34,9 @@ #include #include +#include +#include + __BEGIN_DECLS /** @@ -80,7 +83,7 @@ namespace aidl::android::hardware { * Takes ownership of the ANativeWindow* given to it in reset() and will automatically * destroy it in the destructor, similar to a smart pointer container */ -class NativeWindow { +class NativeWindow final { public: NativeWindow() noexcept {} explicit NativeWindow(ANativeWindow* _Nullable window) { @@ -123,15 +126,29 @@ public: } mWindow = window; } - inline ANativeWindow* _Nullable operator-> () const { return mWindow; } + inline ANativeWindow* _Nullable get() const { return mWindow; } - inline explicit operator bool () const { return mWindow != nullptr; } NativeWindow& operator=(NativeWindow&& other) noexcept { mWindow = other.release(); // steal ownership from r-value return *this; } + inline ANativeWindow* _Nullable operator->() const { return mWindow; } + inline explicit operator bool() const { return mWindow != nullptr; } + inline bool operator==(const NativeWindow& rhs) const { return mWindow == rhs.mWindow; } + inline bool operator!=(const NativeWindow& rhs) const { return !(*this == rhs); } + inline bool operator<(const NativeWindow& rhs) const { return mWindow < rhs.mWindow; } + inline bool operator>(const NativeWindow& rhs) const { return rhs < *this; } + inline bool operator>=(const NativeWindow& rhs) const { return !(*this < rhs); } + inline bool operator<=(const NativeWindow& rhs) const { return !(*this > rhs); } + + std::string toString() const { + std::ostringstream ss; + ss << "NativeWindow: " << mWindow; + return ss.str(); + } + /** * Stops managing any contained ANativeWindow*, returning it to the caller. Ownership * is released. -- GitLab From 0b156bb5edc005550e94c3c8a88933bee06d1ae7 Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Wed, 25 Oct 2023 15:11:41 -0700 Subject: [PATCH 0895/1187] Add CtsSurfaceControlTestsStaging to SF presubmit It passes the SLO so it can be moved from postsubmit to presubmit. Bug: 284911776 Test: presubmit Change-Id: I398b844759ac646491c94dd03ac883d0c8133617 --- services/surfaceflinger/TEST_MAPPING | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/services/surfaceflinger/TEST_MAPPING b/services/surfaceflinger/TEST_MAPPING index f339d22896..3b2bbb0cf3 100644 --- a/services/surfaceflinger/TEST_MAPPING +++ b/services/surfaceflinger/TEST_MAPPING @@ -31,6 +31,9 @@ }, { "name": "CtsSurfaceControlTests" + }, + { + "name": "CtsSurfaceControlTestsStaging" } ], "hwasan-presubmit": [ @@ -40,10 +43,5 @@ { "name": "libsurfaceflinger_unittest" } - ], - "postsubmit": [ - { - "name": "CtsSurfaceControlTestsStaging" - } ] } -- GitLab From 414f4080a92c039c0f777b9b43a47fe0a376eb1f Mon Sep 17 00:00:00 2001 From: Rachel Lee Date: Mon, 23 Oct 2023 14:48:44 -0700 Subject: [PATCH 0896/1187] Non-visible layers are now "inactive" When setting "explicit_refresh_rate_hints", we saw the perfetto trace is very noisy in LayerHistory/RefreshRateSelector. This change fixes this in a few ways: - Non-visible layers should now be inactive in LayerHistory. This should be safe because non-visible layers were treated as NoVote, and does not affect the refresh rate chosen. - LayerInfo for ExplicitCategory now considers NoVote (from non-visible layer). - RefreshRateSelector::calculateLayerScoreLocked does not have any interesting trace calls itself, so remove its ATRACE_CALL. Bug: 305008279 Test: atest libsurfaceflinger_unittest Test: atest SetFrameRateTest Test: perfetto trace not noisy Change-Id: I40056ea48b8323b7be0936e7717706bf9a0926f9 --- .../surfaceflinger/Scheduler/LayerHistory.cpp | 9 ++- .../surfaceflinger/Scheduler/LayerInfo.cpp | 15 +++-- .../Scheduler/RefreshRateSelector.cpp | 1 - .../unittests/LayerHistoryIntegrationTest.cpp | 32 ++++++++- .../tests/unittests/LayerHistoryTest.cpp | 66 +++++++++++++++++++ .../tests/unittests/TestableSurfaceFlinger.h | 2 +- 6 files changed, 115 insertions(+), 10 deletions(-) diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 069d89bc42..ff829143d3 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -21,6 +21,7 @@ #include "LayerHistory.h" #include +#include #include #include #include @@ -39,8 +40,14 @@ namespace android::scheduler { namespace { +using namespace com::android::graphics::surfaceflinger; + bool isLayerActive(const LayerInfo& info, nsecs_t threshold) { - // Layers with an explicit frame rate or frame rate category are always kept active, + if (flags::misc1() && !info.isVisible()) { + return false; + } + + // Layers with an explicit frame rate or frame rate category are kept active, // but ignore NoVote. if (info.getSetFrameRateVote().isValid() && !info.getSetFrameRateVote().isNoVote()) { return true; diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 36f2475d8e..54e9022add 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -304,19 +304,22 @@ LayerInfo::RefreshRateVotes LayerInfo::getRefreshRateVote(const RefreshRateSelec if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) { if (mLayerVote.category != FrameRateCategory::Default) { - ATRACE_FORMAT_INSTANT("ExplicitCategory (%s)", + const auto voteType = mLayerVote.type == LayerHistory::LayerVoteType::NoVote + ? LayerHistory::LayerVoteType::NoVote + : LayerHistory::LayerVoteType::ExplicitCategory; + ATRACE_FORMAT_INSTANT("Vote %s (category=%s)", ftl::enum_string(voteType).c_str(), ftl::enum_string(mLayerVote.category).c_str()); - ALOGV("%s uses frame rate category: %d", mName.c_str(), - static_cast(mLayerVote.category)); - votes.push_back({LayerHistory::LayerVoteType::ExplicitCategory, Fps(), - Seamlessness::Default, mLayerVote.category, + ALOGV("%s voted %s with category: %s", mName.c_str(), + ftl::enum_string(voteType).c_str(), + ftl::enum_string(mLayerVote.category).c_str()); + votes.push_back({voteType, Fps(), Seamlessness::Default, mLayerVote.category, mLayerVote.categorySmoothSwitchOnly}); } if (mLayerVote.fps.isValid() || mLayerVote.type != LayerHistory::LayerVoteType::ExplicitDefault) { ATRACE_FORMAT_INSTANT("Vote %s", ftl::enum_string(mLayerVote.type).c_str()); - ALOGV("%s voted %d ", mName.c_str(), static_cast(mLayerVote.type)); + ALOGV("%s voted %d", mName.c_str(), static_cast(mLayerVote.type)); votes.push_back(mLayerVote); } diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp index 1d23fb5f38..eb69d0bf22 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp @@ -401,7 +401,6 @@ float RefreshRateSelector::calculateDistanceScoreFromMax(Fps refreshRate) const float RefreshRateSelector::calculateLayerScoreLocked(const LayerRequirement& layer, Fps refreshRate, bool isSeamlessSwitch) const { - ATRACE_CALL(); // Slightly prefer seamless switches. constexpr float kSeamedSwitchPenalty = 0.95f; const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty; diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp index 631adf11c8..2f6058f7a6 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp @@ -18,12 +18,14 @@ #define LOG_TAG "LayerHistoryIntegrationTest" #include +#include #include #include #include #include +#include "FlagUtils.h" #include "FpsOps.h" #include "LayerHierarchyTest.h" #include "Scheduler/LayerHistory.h" @@ -36,6 +38,7 @@ namespace android::scheduler { using android::mock::createDisplayMode; +using namespace com::android::graphics::surfaceflinger; class LayerHistoryIntegrationTest : public surfaceflinger::frontend::LayerSnapshotTestBase { protected: @@ -492,7 +495,9 @@ TEST_F(LayerHistoryIntegrationTest, inactiveLayers) { EXPECT_EQ(1, frequentLayerCount(time)); } -TEST_F(LayerHistoryIntegrationTest, invisibleExplicitLayer) { +TEST_F(LayerHistoryIntegrationTest, invisibleExplicitLayerIsActive) { + SET_FLAG_FOR_TEST(flags::misc1, false); + auto explicitVisiblelayer = createLegacyAndFrontedEndLayer(1); auto explicitInvisiblelayer = createLegacyAndFrontedEndLayer(2); hideLayer(2); @@ -515,6 +520,31 @@ TEST_F(LayerHistoryIntegrationTest, invisibleExplicitLayer) { EXPECT_EQ(2, frequentLayerCount(time)); } +TEST_F(LayerHistoryIntegrationTest, invisibleExplicitLayerIsNotActive) { + SET_FLAG_FOR_TEST(flags::misc1, true); + + auto explicitVisiblelayer = createLegacyAndFrontedEndLayer(1); + auto explicitInvisiblelayer = createLegacyAndFrontedEndLayer(2); + hideLayer(2); + setFrameRate(1, 60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + setFrameRate(2, 90.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); + nsecs_t time = systemTime(); + + // Post a buffer to the layers to make them active + setBufferWithPresentTime(explicitVisiblelayer, time); + setBufferWithPresentTime(explicitInvisiblelayer, time); + + EXPECT_EQ(2u, layerCount()); + ASSERT_EQ(1u, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, + summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(1u, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); +} + TEST_F(LayerHistoryIntegrationTest, infrequentAnimatingLayer) { auto layer = createLegacyAndFrontedEndLayer(1); diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 33c1d86847..e8831ab51f 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -22,10 +22,12 @@ #define LOG_TAG "LayerHistoryTest" #include +#include #include #include #include +#include "FlagUtils.h" #include "FpsOps.h" #include "Scheduler/LayerHistory.h" #include "Scheduler/LayerInfo.h" @@ -149,6 +151,8 @@ protected: namespace { +using namespace com::android::graphics::surfaceflinger; + TEST_F(LayerHistoryTest, singleLayerNoVoteDefaultCompatibility) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); @@ -555,6 +559,33 @@ TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategory) { EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory); } +TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategoryNotVisibleDoesNotVote) { + SET_FLAG_FOR_TEST(flags::misc1, true); + + auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()) + .WillRepeatedly( + Return(Layer::FrameRate(12.34_Hz, Layer::FrameRateCompatibility::Default, + Seamlessness::OnlySeamless, FrameRateCategory::High))); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { + history().record(layer->getSequence(), layer->getLayerProps(), time, time, + LayerHistory::LayerUpdateType::Buffer); + time += HI_FPS_PERIOD; + } + + // Layer is not visible, so the layer is moved to inactive, infrequent, and it will not have + // votes to consider for refresh rate selection. + ASSERT_EQ(0, summarizeLayerHistory(time).size()); + EXPECT_EQ(0, activeLayerCount()); + EXPECT_EQ(0, frequentLayerCount(time)); +} + TEST_F(LayerHistoryTest, multipleLayers) { auto layer1 = createLayer("A"); auto layer2 = createLayer("B"); @@ -780,6 +811,8 @@ TEST_F(LayerHistoryTest, inactiveLayers) { } TEST_F(LayerHistoryTest, invisibleExplicitLayer) { + SET_FLAG_FOR_TEST(flags::misc1, false); + auto explicitVisiblelayer = createLayer(); auto explicitInvisiblelayer = createLayer(); @@ -810,6 +843,39 @@ TEST_F(LayerHistoryTest, invisibleExplicitLayer) { EXPECT_EQ(2, frequentLayerCount(time)); } +TEST_F(LayerHistoryTest, invisibleExplicitLayerDoesNotVote) { + SET_FLAG_FOR_TEST(flags::misc1, true); + + auto explicitVisiblelayer = createLayer(); + auto explicitInvisiblelayer = createLayer(); + + EXPECT_CALL(*explicitVisiblelayer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*explicitVisiblelayer, getFrameRateForLayerTree()) + .WillRepeatedly(Return( + Layer::FrameRate(60_Hz, Layer::FrameRateCompatibility::ExactOrMultiple))); + + EXPECT_CALL(*explicitInvisiblelayer, isVisible()).WillRepeatedly(Return(false)); + EXPECT_CALL(*explicitInvisiblelayer, getFrameRateForLayerTree()) + .WillRepeatedly(Return( + Layer::FrameRate(90_Hz, Layer::FrameRateCompatibility::ExactOrMultiple))); + + nsecs_t time = systemTime(); + + // Post a buffer to the layers to make them active + history().record(explicitVisiblelayer->getSequence(), explicitVisiblelayer->getLayerProps(), + time, time, LayerHistory::LayerUpdateType::Buffer); + history().record(explicitInvisiblelayer->getSequence(), explicitInvisiblelayer->getLayerProps(), + time, time, LayerHistory::LayerUpdateType::Buffer); + + EXPECT_EQ(2, layerCount()); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple, + summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); + EXPECT_EQ(1, activeLayerCount()); + EXPECT_EQ(1, frequentLayerCount(time)); +} + TEST_F(LayerHistoryTest, infrequentAnimatingLayer) { auto layer = createLayer(); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 8f1982d6c3..03af56cc71 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -271,7 +271,7 @@ public: resetScheduler(mScheduler); } - void setupMockScheduler(test::MockSchedulerOptions options = {}) { + void setupMockScheduler(surfaceflinger::test::MockSchedulerOptions options = {}) { using testing::_; using testing::Return; -- GitLab From 7c3fb7c74c1b070dbc3f1865f23c94b540354574 Mon Sep 17 00:00:00 2001 From: Kholoud Mohamed Date: Wed, 18 Oct 2023 12:56:22 +0000 Subject: [PATCH 0897/1187] Add ability to retrieve bugreport multiple times If specified by the caller, it keeps the bugreport stored in the framework after it's retrieved, allowing it to be retrieved multiple times. Bug: 304272173 Bug: 302517677 Test: manual testing Change-Id: I2aaf0a7bea629bdad92aab567c96b2a9e7d64633 --- cmds/dumpstate/Android.bp | 2 ++ cmds/dumpstate/DumpstateService.cpp | 9 +++++++-- cmds/dumpstate/DumpstateService.h | 2 ++ .../dumpstate/binder/android/os/IDumpstate.aidl | 9 ++++++++- cmds/dumpstate/dumpstate.cpp | 17 ++++++++++++----- cmds/dumpstate/dumpstate.h | 10 +++++++--- 6 files changed, 38 insertions(+), 11 deletions(-) diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp index 860a2d82e6..23f185e305 100644 --- a/cmds/dumpstate/Android.bp +++ b/cmds/dumpstate/Android.bp @@ -104,6 +104,8 @@ cc_defaults { "libvintf", "libbinderdebug", "packagemanager_aidl-cpp", + "server_configurable_flags", + "device_policy_aconfig_flags_c_lib", ], srcs: [ "DumpstateService.cpp", diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp index c787113765..ba0a38aad9 100644 --- a/cmds/dumpstate/DumpstateService.cpp +++ b/cmds/dumpstate/DumpstateService.cpp @@ -37,6 +37,8 @@ struct DumpstateInfo { Dumpstate* ds = nullptr; int32_t calling_uid = -1; std::string calling_package; + int32_t user_id = -1; + bool keep_bugreport_on_retrieval = false; }; static binder::Status exception(uint32_t code, const std::string& msg, @@ -60,7 +62,7 @@ static binder::Status exception(uint32_t code, const std::string& msg, [[noreturn]] static void* dumpstate_thread_retrieve(void* data) { std::unique_ptr ds_info(static_cast(data)); - ds_info->ds->Retrieve(ds_info->calling_uid, ds_info->calling_package); + ds_info->ds->Retrieve(ds_info->calling_uid, ds_info->calling_package, ds_info->keep_bugreport_on_retrieval); MYLOGD("Finished retrieving a bugreport. Exiting.\n"); exit(0); } @@ -201,9 +203,10 @@ binder::Status DumpstateService::cancelBugreport(int32_t calling_uid, } binder::Status DumpstateService::retrieveBugreport( - int32_t calling_uid, const std::string& calling_package, + int32_t calling_uid, const std::string& calling_package, int32_t user_id, android::base::unique_fd bugreport_fd, const std::string& bugreport_file, + const bool keep_bugreport_on_retrieval, const sp& listener) { ds_ = &(Dumpstate::GetInstance()); @@ -211,6 +214,8 @@ binder::Status DumpstateService::retrieveBugreport( ds_info->ds = ds_; ds_info->calling_uid = calling_uid; ds_info->calling_package = calling_package; + ds_info->user_id = user_id; + ds_info->keep_bugreport_on_retrieval = keep_bugreport_on_retrieval; ds_->listener_ = listener; std::unique_ptr options = std::make_unique(); // Use a /dev/null FD when initializing options since none is provided. diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h index dd7331932c..7b76c36380 100644 --- a/cmds/dumpstate/DumpstateService.h +++ b/cmds/dumpstate/DumpstateService.h @@ -48,8 +48,10 @@ class DumpstateService : public BinderService, public BnDumpst binder::Status retrieveBugreport(int32_t calling_uid, const std::string& calling_package, + int32_t user_id, android::base::unique_fd bugreport_fd, const std::string& bugreport_file, + const bool keep_bugreport_on_retrieval, const sp& listener) override; diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl index fa9bcf351c..97c470e08c 100644 --- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl +++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl @@ -58,6 +58,9 @@ interface IDumpstate { // Defer user consent. const int BUGREPORT_FLAG_DEFER_CONSENT = 0x2; + // Keep bugreport stored after retrieval. + const int BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL = 0x4; + /** * Speculatively pre-dumps UI data for a bugreport request that might come later. * @@ -116,12 +119,16 @@ interface IDumpstate { * * @param callingUid UID of the original application that requested the report. * @param callingPackage package of the original application that requested the report. + * @param userId user Id of the original package that requested the report. * @param bugreportFd the file to which the zipped bugreport should be written * @param bugreportFile the path of the bugreport file + * @param keepBugreportOnRetrieval boolean to indicate if the bugreport should be kept in the + * platform after it has been retrieved by the caller. * @param listener callback for updates; optional */ - void retrieveBugreport(int callingUid, @utf8InCpp String callingPackage, + void retrieveBugreport(int callingUid, @utf8InCpp String callingPackage, int userId, FileDescriptor bugreportFd, @utf8InCpp String bugreportFile, + boolean keepBugreportOnRetrieval, IDumpstateListener listener); } diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 33f6d38cc6..4f80190954 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -59,6 +59,7 @@ #include #include +#include #include #include #include @@ -2977,14 +2978,17 @@ Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& call return status; } -Dumpstate::RunStatus Dumpstate::Retrieve(int32_t calling_uid, const std::string& calling_package) { - Dumpstate::RunStatus status = RetrieveInternal(calling_uid, calling_package); +Dumpstate::RunStatus Dumpstate::Retrieve(int32_t calling_uid, const std::string& calling_package, + const bool keep_bugreport_on_retrieval) { + Dumpstate::RunStatus status = RetrieveInternal(calling_uid, calling_package, + keep_bugreport_on_retrieval); HandleRunStatus(status); return status; } Dumpstate::RunStatus Dumpstate::RetrieveInternal(int32_t calling_uid, - const std::string& calling_package) { + const std::string& calling_package, + const bool keep_bugreport_on_retrieval) { consent_callback_ = new ConsentCallback(); const String16 incidentcompanion("incidentcompanion"); sp ics( @@ -3019,9 +3023,12 @@ Dumpstate::RunStatus Dumpstate::RetrieveInternal(int32_t calling_uid, bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get()); - if (copy_succeeded) { - android::os::UnlinkAndLogOnError(path_); + + if (copy_succeeded && (!android::app::admin::flags::onboarding_bugreport_v2_enabled() + || !keep_bugreport_on_retrieval)) { + android::os::UnlinkAndLogOnError(path_); } + return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR; } diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 0a032ecfc3..d01cfcef4d 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -210,7 +210,9 @@ class Dumpstate { BUGREPORT_USE_PREDUMPED_UI_DATA = android::os::IDumpstate::BUGREPORT_FLAG_USE_PREDUMPED_UI_DATA, BUGREPORT_FLAG_DEFER_CONSENT = - android::os::IDumpstate::BUGREPORT_FLAG_DEFER_CONSENT + android::os::IDumpstate::BUGREPORT_FLAG_DEFER_CONSENT, + BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL = + android::os::IDumpstate::BUGREPORT_FLAG_KEEP_BUGREPORT_ON_RETRIEVAL }; static android::os::dumpstate::CommandOptions DEFAULT_DUMPSYS; @@ -361,7 +363,8 @@ class Dumpstate { * * Initialize() dumpstate before calling this method. */ - RunStatus Retrieve(int32_t calling_uid, const std::string& calling_package); + RunStatus Retrieve(int32_t calling_uid, const std::string& calling_package, + const bool keep_bugreport_on_retrieval); @@ -562,7 +565,8 @@ class Dumpstate { private: RunStatus RunInternal(int32_t calling_uid, const std::string& calling_package); - RunStatus RetrieveInternal(int32_t calling_uid, const std::string& calling_package); + RunStatus RetrieveInternal(int32_t calling_uid, const std::string& calling_package, + const bool keep_bugreport_on_retrieval); RunStatus DumpstateDefaultAfterCritical(); RunStatus dumpstate(); -- GitLab From 3d84add9f03e2c95d0300c5661e59c0b0ef53deb Mon Sep 17 00:00:00 2001 From: Arpit Singh Date: Tue, 10 Oct 2023 19:08:29 +0000 Subject: [PATCH 0898/1187] Add flag for additional touchpad palm rejection while typing Flag to enable additional touchpad palm rejection while typing on a physical keyboard. This flag will be used in upcoming changes. Bug: 301055381 Test: atest GestureConverterTest Change-Id: Iedc78261fc8973eaf2f8c704674321607517351f --- libs/input/input_flags.aconfig | 7 +++++++ .../mapper/gestures/GestureConverter.cpp | 9 +++++++-- .../tests/GestureConverter_test.cpp | 19 +++++++++++++++---- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index 6302ff5ff3..978a80f9b3 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -41,3 +41,10 @@ flag { description: "Brings back fatal logging for inconsistent event streams originating from accessibility." bug: "299977100" } + +flag { + name: "enable_touchpad_typing_palm_rejection" + namespace: "input" + description: "Enable additional palm rejection on touchpad while typing" + bug: "301055381" +} diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp index 7006e9efc1..4d2b66d56d 100644 --- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp +++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -28,10 +29,14 @@ #include "TouchCursorInputMapperCommon.h" #include "input/Input.h" +namespace input_flags = com::android::input::flags; + namespace android { namespace { +const bool ENABLE_TOUCHPAD_PALM_REJECTION = input_flags::enable_touchpad_typing_palm_rejection(); + uint32_t gesturesButtonToMotionEventButton(uint32_t gesturesButton) { switch (gesturesButton) { case GESTURES_BUTTON_LEFT: @@ -158,7 +163,7 @@ NotifyMotionArgs GestureConverter::handleMove(nsecs_t when, nsecs_t readTime, const Gesture& gesture) { float deltaX = gesture.details.move.dx; float deltaY = gesture.details.move.dy; - if (std::abs(deltaX) > 0 || std::abs(deltaY) > 0) { + if (ENABLE_TOUCHPAD_PALM_REJECTION && (std::abs(deltaX) > 0 || std::abs(deltaY) > 0)) { enableTapToClick(); } rotateDelta(mOrientation, &deltaX, &deltaY); @@ -200,7 +205,7 @@ std::list GestureConverter::handleButtonsChange(nsecs_t when, nsecs_ coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0); coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0); - if (mReaderContext.isPreventingTouchpadTaps()) { + if (ENABLE_TOUCHPAD_PALM_REJECTION && mReaderContext.isPreventingTouchpadTaps()) { enableTapToClick(); if (gesture.details.buttons.is_tap) { // return early to prevent this tap diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp index d7dc800c82..41c7392cbc 100644 --- a/services/inputflinger/tests/GestureConverter_test.cpp +++ b/services/inputflinger/tests/GestureConverter_test.cpp @@ -16,7 +16,8 @@ #include -#include +#include +#include #include #include #include @@ -34,6 +35,13 @@ namespace android { +namespace { + +const auto TOUCHPAD_PALM_REJECTION = + ACONFIG_FLAG(com::android::input::flags, enable_touchpad_typing_palm_rejection); + +} // namespace + using testing::AllOf; class GestureConverterTest : public testing::Test { @@ -1161,7 +1169,8 @@ TEST_F(GestureConverterTest, Click) { WithDisplayId(ADISPLAY_ID_DEFAULT))); } -TEST_F(GestureConverterTest, TapWithTapToClickDisabled) { +TEST_F_WITH_FLAGS(GestureConverterTest, TapWithTapToClickDisabled, + REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) { // Tap should be ignored when disabled mReader->getContext()->setPreventingTouchpadTaps(true); @@ -1193,7 +1202,8 @@ TEST_F(GestureConverterTest, TapWithTapToClickDisabled) { ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); } -TEST_F(GestureConverterTest, ClickWithTapToClickDisabled) { +TEST_F_WITH_FLAGS(GestureConverterTest, ClickWithTapToClickDisabled, + REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) { // Click should still produce button press/release events mReader->getContext()->setPreventingTouchpadTaps(true); @@ -1260,7 +1270,8 @@ TEST_F(GestureConverterTest, ClickWithTapToClickDisabled) { ASSERT_FALSE(mReader->getContext()->isPreventingTouchpadTaps()); } -TEST_F(GestureConverterTest, MoveEnablesTapToClick) { +TEST_F_WITH_FLAGS(GestureConverterTest, MoveEnablesTapToClick, + REQUIRES_FLAGS_ENABLED(TOUCHPAD_PALM_REJECTION)) { // initially disable tap-to-click mReader->getContext()->setPreventingTouchpadTaps(true); -- GitLab From b5260907d932609ba0ced79cb992278e20d33bf6 Mon Sep 17 00:00:00 2001 From: Solti Date: Tue, 24 Oct 2023 21:48:02 +0000 Subject: [PATCH 0899/1187] include system ANGLE usage as ANGLE usage This CL set the system ANGLE usage as GpuStatsInfo::Driver::ANGLE. Previously it was categorized as GpuStatsInfo::Driver::GL. The reason is ANGLE will be shipped as a system driver, not as APK. We want to monitor the adoption of system ANGLE driver. Test: collect the GPU stats before and after the CL. Check the GPU stats reflects ANGLE traffic. See details in b/294867368#comment17 Bug: b/294867368 Change-Id: I5fcc6a9b86f186ec5058cd3b2ddc262b4ef1b352 --- libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h | 2 +- opengl/libs/EGL/Loader.cpp | 9 ++++++++- services/gpuservice/gpustats/GpuStats.cpp | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h index 47607a0ab9..9ebaf16eb4 100644 --- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h +++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h @@ -104,7 +104,7 @@ public: GL_UPDATED = 2, VULKAN = 3, VULKAN_UPDATED = 4, - ANGLE = 5, + ANGLE = 5, // cover both system ANGLE and ANGLE APK }; enum Stats { diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 04e2fffaef..7b2f39cd9c 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -567,6 +567,7 @@ Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) { return nullptr; } + // use ANGLE APK driver android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::ANGLE); driver_t* hnd = nullptr; @@ -635,7 +636,13 @@ Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix, const bool exact) { ATRACE_CALL(); - android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL); + if (strcmp(suffix, "angle") == 0) { + // use system ANGLE driver + android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::ANGLE); + } else { + android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL); + } + driver_t* hnd = nullptr; void* dso = load_system_driver("GLES", suffix, exact); if (dso) { diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp index f06a0457d3..d447d1e91a 100644 --- a/services/gpuservice/gpustats/GpuStats.cpp +++ b/services/gpuservice/gpustats/GpuStats.cpp @@ -163,11 +163,11 @@ void GpuStats::insertDriverStats(const std::string& driverPackageName, addLoadingTime(driver, driverLoadingTime, &appInfo); appInfo.appPackageName = appPackageName; appInfo.driverVersionCode = driverVersionCode; - appInfo.angleInUse = driverPackageName == "angle"; + appInfo.angleInUse = driver == GpuStatsInfo::Driver::ANGLE; appInfo.lastAccessTime = std::chrono::system_clock::now(); mAppStats.insert({appStatsKey, appInfo}); } else { - mAppStats[appStatsKey].angleInUse = driverPackageName == "angle"; + mAppStats[appStatsKey].angleInUse = driver == GpuStatsInfo::Driver::ANGLE; addLoadingTime(driver, driverLoadingTime, &mAppStats[appStatsKey]); mAppStats[appStatsKey].lastAccessTime = std::chrono::system_clock::now(); } -- GitLab From eaac2b49afcdffa78fca694ed7bc0556b1161275 Mon Sep 17 00:00:00 2001 From: Avichal Rakesh Date: Thu, 26 Oct 2023 14:01:39 -0700 Subject: [PATCH 0900/1187] native_window_aidl: include cpp headers only when needed native_window_aidl.h only enables the AIDL glue for CPP/NDK backends, so the headers required for AIDL glue should only be included for CPP/NDK backends. This CL includes headers required by AIDL glue only when the AIDL glue is actually being enabled. Bug: 283283111 Test: Verified that Surface can be used in an AIDL file. Change-Id: I1945d3cfc247bfa507ca4fef03044e1078e598f0 --- libs/nativewindow/include/android/native_window_aidl.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/nativewindow/include/android/native_window_aidl.h b/libs/nativewindow/include/android/native_window_aidl.h index adc1bf11a8..0d5727d0e6 100644 --- a/libs/nativewindow/include/android/native_window_aidl.h +++ b/libs/nativewindow/include/android/native_window_aidl.h @@ -34,8 +34,11 @@ #include #include +// Only required by the AIDL glue helper +#ifdef __cplusplus #include #include +#endif // __cplusplus __BEGIN_DECLS -- GitLab From 4b01c0ae686691af89d23bdb492a39fc26f6559d Mon Sep 17 00:00:00 2001 From: Carlos Martinez Romero Date: Tue, 10 Oct 2023 16:24:51 +0000 Subject: [PATCH 0901/1187] Updated the BufferStreamsDemoApp UI to jetpack compose. The project is no longer using Java and now the MainActivity uses Kotlin, calling JNI from Kotlin is fairly simiar. Currently there are 3 empty demo screens, the first demo screen will call a JNI function but there is no support for logs. Bug: 296272152 Test: Built and ran on device. Change-Id: I92f0951899fb6379e1506abdc8e1d67002433787 --- libs/bufferstreams/examples/app/Android.bp | 21 ++- .../examples/app/AndroidManifest.xml | 7 +- .../bufferstreamsdemoapp/BufferDemosAppBar.kt | 40 ++++++ .../bufferstreamsdemoapp/BufferStreamJNI.kt | 27 ++++ .../bufferstreamsdemoapp/DemoScreen1.kt | 33 +++++ .../bufferstreamsdemoapp/DemoScreen2.kt | 7 + .../bufferstreamsdemoapp/DemoScreen3.kt | 7 + .../bufferstreamsdemoapp/MainActivity.java | 39 ----- .../bufferstreamsdemoapp/MainActivity.kt | 136 ++++++++++++++++++ .../graphics/bufferstreamsdemoapp/ui/Color.kt | 11 ++ .../graphics/bufferstreamsdemoapp/ui/Theme.kt | 60 ++++++++ .../graphics/bufferstreamsdemoapp/ui/Type.kt | 18 +++ libs/bufferstreams/examples/app/jni/main.cpp | 8 +- .../examples/app/res/layout/activity_main.xml | 18 --- .../examples/app/res/values/strings.xml | 5 + .../examples/app/res/values/themes.xml | 4 + 16 files changed, 376 insertions(+), 65 deletions(-) create mode 100644 libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt create mode 100644 libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferStreamJNI.kt create mode 100644 libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen1.kt create mode 100644 libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen2.kt create mode 100644 libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen3.kt delete mode 100644 libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.java create mode 100644 libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.kt create mode 100644 libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Color.kt create mode 100644 libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Theme.kt create mode 100644 libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Type.kt delete mode 100644 libs/bufferstreams/examples/app/res/layout/activity_main.xml create mode 100644 libs/bufferstreams/examples/app/res/values/themes.xml diff --git a/libs/bufferstreams/examples/app/Android.bp b/libs/bufferstreams/examples/app/Android.bp index 0ecf94c48d..d6305f895c 100644 --- a/libs/bufferstreams/examples/app/Android.bp +++ b/libs/bufferstreams/examples/app/Android.bp @@ -14,14 +14,33 @@ android_app { name: "BufferStreamsDemoApp", - srcs: ["java/**/*.java"], + srcs: ["java/**/*.kt"], sdk_version: "current", jni_uses_platform_apis: true, jni_libs: ["libbufferstreamdemoapp"], use_embedded_native_libs: true, + kotlincflags: [ + "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api", + ], + + resource_dirs: ["res"], static_libs: [ + "androidx.activity_activity-compose", "androidx.appcompat_appcompat", + "androidx.compose.foundation_foundation", + "androidx.compose.material3_material3", + "androidx.compose.runtime_runtime", + "androidx.compose.ui_ui", + "androidx.compose.ui_ui-graphics", + "androidx.compose.ui_ui-tooling-preview", + "androidx.core_core-ktx", + "androidx.lifecycle_lifecycle-runtime-ktx", + "androidx.navigation_navigation-common-ktx", + "androidx.navigation_navigation-compose", + "androidx.navigation_navigation-fragment-ktx", + "androidx.navigation_navigation-runtime-ktx", + "androidx.navigation_navigation-ui-ktx", ], } diff --git a/libs/bufferstreams/examples/app/AndroidManifest.xml b/libs/bufferstreams/examples/app/AndroidManifest.xml index 872193c4e6..a5e2fa8a63 100644 --- a/libs/bufferstreams/examples/app/AndroidManifest.xml +++ b/libs/bufferstreams/examples/app/AndroidManifest.xml @@ -9,14 +9,15 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/Theme.AppCompat.Light" + android:theme="@style/Theme.Jetpack" tools:targetApi="34"> + android:exported="true" + android:label="@string/app_name" + android:theme="@style/Theme.Jetpack"> - diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt new file mode 100644 index 0000000000..ff3ae5a090 --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt @@ -0,0 +1,40 @@ +package com.android.graphics.bufferstreamsdemoapp + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource + +@Composable +fun BufferDemosAppBar( + currentScreen: BufferDemoScreen, + canNavigateBack: Boolean, + navigateUp: () -> Unit, + modifier: Modifier = Modifier +) { + TopAppBar( + title = { Text(stringResource(currentScreen.title)) }, + colors = + TopAppBarDefaults.mediumTopAppBarColors( + containerColor = MaterialTheme.colorScheme.primaryContainer + ), + modifier = modifier, + navigationIcon = { + if (canNavigateBack) { + IconButton(onClick = navigateUp) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = stringResource(R.string.back_button) + ) + } + } + } + ) +} \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferStreamJNI.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferStreamJNI.kt new file mode 100644 index 0000000000..a2db9349aa --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferStreamJNI.kt @@ -0,0 +1,27 @@ +package com.android.graphics.bufferstreamsdemoapp + +class BufferStreamJNI { + // Used to load the 'bufferstreamsdemoapp' library on application startup. + init { + System.loadLibrary("bufferstreamdemoapp") + } + + /** + * A native method that is implemented by the 'bufferstreamsdemoapp' native library, which is + * packaged with this application. + */ + external fun stringFromJNI() + external fun testBufferQueueCreation() + + companion object { + fun companion_stringFromJNI() { + val instance = BufferStreamJNI() + instance.stringFromJNI() + } + + fun companion_testBufferQueueCreation() { + val instance = BufferStreamJNI() + instance.testBufferQueueCreation() + } + } +} \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen1.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen1.kt new file mode 100644 index 0000000000..46ce0283b4 --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen1.kt @@ -0,0 +1,33 @@ +package com.android.graphics.bufferstreamsdemoapp + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.Card +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun DemoScreen1(modifier: Modifier = Modifier) { + Column(modifier = modifier, verticalArrangement = Arrangement.SpaceBetween) { + Card(modifier = Modifier.fillMaxWidth().weight(1f, false).padding(16.dp).height(400.dp)) { + Text("Log output", modifier = Modifier.padding(16.dp)) + } + Row(modifier = Modifier.weight(1f, false).padding(16.dp)) { + Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { + Button( + modifier = Modifier.fillMaxWidth(), + onClick = { BufferStreamJNI.companion_testBufferQueueCreation() } + ) { Text("Run") } + OutlinedButton(modifier = Modifier.fillMaxWidth(), onClick = {}) { Text("Clear") } + } + } + } +} \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen2.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen2.kt new file mode 100644 index 0000000000..5efee92f76 --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen2.kt @@ -0,0 +1,7 @@ +package com.android.graphics.bufferstreamsdemoapp + +import androidx.compose.runtime.Composable + +@Composable +fun DemoScreen2() { +} \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen3.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen3.kt new file mode 100644 index 0000000000..8cba857737 --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/DemoScreen3.kt @@ -0,0 +1,7 @@ +package com.android.graphics.bufferstreamsdemoapp + +import androidx.compose.runtime.Composable + +@Composable +fun DemoScreen3() { +} \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.java b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.java deleted file mode 100644 index 67b95a5349..0000000000 --- a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.java +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (C) 2023 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. - -package com.android.graphics.bufferstreamsdemoapp; - -import android.os.Bundle; -import android.widget.TextView; -import androidx.appcompat.app.AppCompatActivity; - -public class MainActivity extends AppCompatActivity { - // Used to load the 'bufferstreamsdemoapp' library on application startup. - static { System.loadLibrary("bufferstreamdemoapp"); } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - RunBufferQueue(); - System.out.println("stringFromJNI: " + stringFromJNI()); - } - - /** - * A native method that is implemented by the 'bufferstreamsdemoapp' native - * library, which is packaged with this application. - */ - public native String stringFromJNI(); - public native void RunBufferQueue(); -} \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.kt new file mode 100644 index 0000000000..f3f440482f --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/MainActivity.kt @@ -0,0 +1,136 @@ +package com.android.graphics.bufferstreamsdemoapp + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.annotation.StringRes +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.material3.Button +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController +import com.android.graphics.bufferstreamsdemoapp.ui.theme.JetpackTheme + +class MainActivity : ComponentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + JetpackTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { BufferDemosApp() } + } + } + } +} + +enum class BufferDemoScreen(val route: String, @StringRes val title: Int) { + Start(route = "start", title = R.string.start), + Demo1(route = "demo1", title = R.string.demo1), + Demo2(route = "demo2", title = R.string.demo2), + Demo3(route = "demo3", title = R.string.demo3); + + companion object { + fun findByRoute(route: String): BufferDemoScreen { + return values().find { it.route == route }!! + } + } +} + +@Composable +fun BufferDemosApp() { + var navController: NavHostController = rememberNavController() + // Get current back stack entry + val backStackEntry by navController.currentBackStackEntryAsState() + // Get the name of the current screen + val currentScreen = + BufferDemoScreen.findByRoute( + backStackEntry?.destination?.route ?: BufferDemoScreen.Start.route + ) + + Scaffold( + topBar = { + BufferDemosAppBar( + currentScreen = currentScreen, + canNavigateBack = navController.previousBackStackEntry != null, + navigateUp = { navController.navigateUp() } + ) + } + ) { + NavHost( + navController = navController, + startDestination = BufferDemoScreen.Start.route, + modifier = Modifier.padding(10.dp) + ) { + composable(route = BufferDemoScreen.Start.route) { + DemoList( + onButtonClicked = { + navController.navigate(it) + }, + ) + } + composable(route = BufferDemoScreen.Demo1.route) { + DemoScreen1(modifier = Modifier.fillMaxHeight().padding(top = 100.dp)) + } + composable(route = BufferDemoScreen.Demo2.route) { DemoScreen2() } + composable(route = BufferDemoScreen.Demo3.route) { DemoScreen3() } + } + } +} + +@Composable +fun DemoList(onButtonClicked: (String) -> Unit) { + var modifier = Modifier.fillMaxSize().padding(16.dp) + + Column(modifier = modifier, verticalArrangement = Arrangement.SpaceBetween) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Spacer(modifier = Modifier.height(100.dp)) + Text(text = "Buffer Demos", style = MaterialTheme.typography.titleLarge) + Spacer(modifier = Modifier.height(8.dp)) + } + Row(modifier = Modifier.weight(2f, false)) { + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + for (item in BufferDemoScreen.values()) { + if (item.route != BufferDemoScreen.Start.route) + SelectDemoButton(name = stringResource(item.title), onClick = { onButtonClicked(item.route) }) + } + } + } + } +} + +@Composable +fun SelectDemoButton(name: String, onClick: () -> Unit, modifier: Modifier = Modifier) { + Button(onClick = onClick, modifier = modifier.widthIn(min = 250.dp)) { Text(name) } +} diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Color.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Color.kt new file mode 100644 index 0000000000..d85ea724de --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Color.kt @@ -0,0 +1,11 @@ +package com.android.graphics.bufferstreamsdemoapp.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Theme.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Theme.kt new file mode 100644 index 0000000000..fccd93a10b --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Theme.kt @@ -0,0 +1,60 @@ +package com.android.graphics.bufferstreamsdemoapp.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 +) + +@Composable +fun JetpackTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = colorScheme.primary.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme + } + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Type.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Type.kt new file mode 100644 index 0000000000..06814ead8b --- /dev/null +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/ui/Type.kt @@ -0,0 +1,18 @@ +package com.android.graphics.bufferstreamsdemoapp.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) +) \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/jni/main.cpp b/libs/bufferstreams/examples/app/jni/main.cpp index 34e0eb451c..3d3fee4c6a 100644 --- a/libs/bufferstreams/examples/app/jni/main.cpp +++ b/libs/bufferstreams/examples/app/jni/main.cpp @@ -19,16 +19,16 @@ extern "C" { JNIEXPORT jstring JNICALL - Java_com_android_graphics_bufferstreamsdemoapp_MainActivity_stringFromJNI( - JNIEnv *env, + Java_com_android_graphics_bufferstreamsdemoapp_BufferStreamJNI_stringFromJNI( + JNIEnv* env, jobject /* this */) { const char* hello = "Hello from C++"; return env->NewStringUTF(hello); } JNIEXPORT void JNICALL - Java_com_android_graphics_bufferstreamsdemoapp_MainActivity_RunBufferQueue( - JNIEnv *env, + Java_com_android_graphics_bufferstreamsdemoapp_BufferStreamJNI_testBufferQueueCreation( + JNIEnv* /* env */, jobject /* this */) { android::sp producer; android::sp consumer; diff --git a/libs/bufferstreams/examples/app/res/layout/activity_main.xml b/libs/bufferstreams/examples/app/res/layout/activity_main.xml deleted file mode 100644 index 79fb331f09..0000000000 --- a/libs/bufferstreams/examples/app/res/layout/activity_main.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/res/values/strings.xml b/libs/bufferstreams/examples/app/res/values/strings.xml index e652102cb3..75c8ab5e1c 100644 --- a/libs/bufferstreams/examples/app/res/values/strings.xml +++ b/libs/bufferstreams/examples/app/res/values/strings.xml @@ -1,3 +1,8 @@ Buffer Demos + Start + Demo 1 + Demo 2 + Demo 3 + Back \ No newline at end of file diff --git a/libs/bufferstreams/examples/app/res/values/themes.xml b/libs/bufferstreams/examples/app/res/values/themes.xml new file mode 100644 index 0000000000..eeb308ae44 --- /dev/null +++ b/libs/bufferstreams/examples/app/res/values/themes.xml @@ -0,0 +1,4 @@ + + +