Merge "Remove ASan from gpuservice_unittest" am: 008cdaf9b1 am: 60cd806a7a
Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/2482577
Change-Id: I8003a191ec77646391e939bac60683b2f1dd5a96
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index dd46494..000f458 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -132,6 +132,11 @@
}
}
+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),
@@ -480,20 +485,26 @@
mSyncedFrameNumbers.erase(callbackId.framenumber);
}
-void BLASTBufferQueue::acquireNextBufferLocked(
+status_t BLASTBufferQueue::acquireNextBufferLocked(
const std::optional<SurfaceComposerClient::Transaction*> transaction) {
- // If the next transaction is set, we want to guarantee the our acquire will not fail, so don't
- // include the extra buffer when checking if we can acquire the next buffer.
- const bool includeExtraAcquire = !transaction;
- const bool maxAcquired = maxBuffersAcquired(includeExtraAcquire);
- if (mNumFrameAvailable == 0 || maxAcquired) {
- BQA_LOGV("Can't process next buffer maxBuffersAcquired=%s", boolToString(maxAcquired));
- return;
+ // Check if we have frames available and we have not acquired the maximum number of buffers.
+ // Even with this check, the consumer can fail to acquire an additional buffer if the consumer
+ // has already acquired (mMaxAcquiredBuffers + 1) and the new buffer is not droppable. In this
+ // case mBufferItemConsumer->acquireBuffer will return with NO_BUFFER_AVAILABLE.
+ if (mNumFrameAvailable == 0) {
+ BQA_LOGV("Can't acquire next buffer. No available frames");
+ return BufferQueue::NO_BUFFER_AVAILABLE;
+ }
+
+ if (mNumAcquired >= (mMaxAcquiredBuffers + 2)) {
+ BQA_LOGV("Can't acquire next buffer. Already acquired max frames %d max:%d + 2",
+ mNumAcquired, mMaxAcquiredBuffers);
+ return BufferQueue::NO_BUFFER_AVAILABLE;
}
if (mSurfaceControl == nullptr) {
BQA_LOGE("ERROR : surface control is null");
- return;
+ return NAME_NOT_FOUND;
}
SurfaceComposerClient::Transaction localTransaction;
@@ -510,10 +521,10 @@
mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
if (status == BufferQueue::NO_BUFFER_AVAILABLE) {
BQA_LOGV("Failed to acquire a buffer, err=NO_BUFFER_AVAILABLE");
- return;
+ return status;
} else if (status != OK) {
BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str());
- return;
+ return status;
}
auto buffer = bufferItem.mGraphicBuffer;
@@ -523,7 +534,7 @@
if (buffer == nullptr) {
mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
BQA_LOGE("Buffer was empty");
- return;
+ return BAD_VALUE;
}
if (rejectBuffer(bufferItem)) {
@@ -532,8 +543,7 @@
mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height,
buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
- acquireNextBufferLocked(transaction);
- return;
+ return acquireNextBufferLocked(transaction);
}
mNumAcquired++;
@@ -587,9 +597,23 @@
t->setDesiredPresentTime(bufferItem.mTimestamp);
}
- if (!mNextFrameTimelineInfoQueue.empty()) {
- t->setFrameTimelineInfo(mNextFrameTimelineInfoQueue.front());
- mNextFrameTimelineInfoQueue.pop();
+ // Drop stale frame timeline infos
+ while (!mPendingFrameTimelines.empty() &&
+ mPendingFrameTimelines.front().first < bufferItem.mFrameNumber) {
+ ATRACE_FORMAT_INSTANT("dropping stale frameNumber: %" PRIu64 " vsyncId: %" PRId64,
+ mPendingFrameTimelines.front().first,
+ mPendingFrameTimelines.front().second.vsyncId);
+ mPendingFrameTimelines.pop();
+ }
+
+ if (!mPendingFrameTimelines.empty() &&
+ mPendingFrameTimelines.front().first == bufferItem.mFrameNumber) {
+ ATRACE_FORMAT_INSTANT("Transaction::setFrameTimelineInfo frameNumber: %" PRIu64
+ " vsyncId: %" PRId64,
+ bufferItem.mFrameNumber,
+ mPendingFrameTimelines.front().second.vsyncId);
+ t->setFrameTimelineInfo(mPendingFrameTimelines.front().second);
+ mPendingFrameTimelines.pop();
}
{
@@ -621,6 +645,7 @@
bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "",
static_cast<uint32_t>(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(),
bufferItem.mAutoRefresh ? " mAutoRefresh" : "", bufferItem.mTransform);
+ return OK;
}
Rect BLASTBufferQueue::computeCrop(const BufferItem& item) {
@@ -643,44 +668,19 @@
mBufferItemConsumer->releaseBuffer(bufferItem, bufferItem.mFence);
}
-void BLASTBufferQueue::flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock) {
- if (!mSyncedFrameNumbers.empty() && mNumFrameAvailable > 0) {
- // We are waiting on a previous sync's transaction callback so allow another sync
- // transaction to proceed.
- //
- // We need to first flush out the transactions that were in between the two syncs.
- // We do this by merging them into mSyncTransaction so any buffer merging will get
- // a release callback invoked. The release callback will be async so we need to wait
- // on max acquired to make sure we have the capacity to acquire another buffer.
- if (maxBuffersAcquired(false /* includeExtraAcquire */)) {
- BQA_LOGD("waiting to flush shadow queue...");
- mCallbackCV.wait(lock);
- }
- while (mNumFrameAvailable > 0) {
- // flush out the shadow queue
- acquireAndReleaseBuffer();
- }
- }
-
- while (maxBuffersAcquired(false /* includeExtraAcquire */)) {
- BQA_LOGD("waiting for free buffer.");
- mCallbackCV.wait(lock);
- }
-}
-
void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
std::function<void(SurfaceComposerClient::Transaction*)> prevCallback = nullptr;
SurfaceComposerClient::Transaction* prevTransaction = nullptr;
- bool waitForTransactionCallback = !mSyncedFrameNumbers.empty();
{
- BBQ_TRACE();
std::unique_lock _lock{mMutex};
+ BBQ_TRACE();
+
+ bool waitForTransactionCallback = !mSyncedFrameNumbers.empty();
const bool syncTransactionSet = mTransactionReadyCallback != nullptr;
BQA_LOGV("onFrameAvailable-start syncTransactionSet=%s", boolToString(syncTransactionSet));
if (syncTransactionSet) {
- bool mayNeedToWaitForBuffer = true;
// If we are going to re-use the same mSyncTransaction, release the buffer that may
// already be set in the Transaction. This is to allow us a free slot early to continue
// processing a new buffer.
@@ -691,14 +691,29 @@
bufferData->frameNumber);
releaseBuffer(bufferData->generateReleaseCallbackId(),
bufferData->acquireFence);
- // Because we just released a buffer, we know there's no need to wait for a free
- // buffer.
- mayNeedToWaitForBuffer = false;
}
}
- if (mayNeedToWaitForBuffer) {
- flushAndWaitForFreeBuffer(_lock);
+ if (waitForTransactionCallback) {
+ // We are waiting on a previous sync's transaction callback so allow another sync
+ // transaction to proceed.
+ //
+ // We need to first flush out the transactions that were in between the two syncs.
+ // We do this by merging them into mSyncTransaction so any buffer merging will get
+ // a release callback invoked.
+ while (mNumFrameAvailable > 0) {
+ // flush out the shadow queue
+ acquireAndReleaseBuffer();
+ }
+ } else {
+ // Make sure the frame available count is 0 before proceeding with a sync to ensure
+ // the correct frame is used for the sync. The only way mNumFrameAvailable would be
+ // greater than 0 is if we already ran out of buffers previously. This means we
+ // need to flush the buffers before proceeding with the sync.
+ while (mNumFrameAvailable > 0) {
+ BQA_LOGD("waiting until no queued buffers");
+ mCallbackCV.wait(_lock);
+ }
}
}
@@ -714,14 +729,23 @@
item.mFrameNumber, boolToString(syncTransactionSet));
if (syncTransactionSet) {
- acquireNextBufferLocked(mSyncTransaction);
+ // Add to mSyncedFrameNumbers before waiting in case any buffers are released
+ // while waiting for a free buffer. The release and commit callback will try to
+ // acquire buffers if there are any available, but we don't want it to acquire
+ // in the case where a sync transaction wants the buffer.
+ mSyncedFrameNumbers.emplace(item.mFrameNumber);
+ // If there's no available buffer and we're in a sync transaction, we need to wait
+ // instead of returning since we guarantee a buffer will be acquired for the sync.
+ while (acquireNextBufferLocked(mSyncTransaction) == BufferQueue::NO_BUFFER_AVAILABLE) {
+ BQA_LOGD("waiting for available buffer");
+ mCallbackCV.wait(_lock);
+ }
// Only need a commit callback when syncing to ensure the buffer that's synced has been
// sent to SF
incStrong((void*)transactionCommittedCallbackThunk);
mSyncTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk,
static_cast<void*>(this));
- mSyncedFrameNumbers.emplace(item.mFrameNumber);
if (mAcquireSingleBuffer) {
prevCallback = mTransactionReadyCallback;
prevTransaction = mSyncTransaction;
@@ -824,15 +848,6 @@
return mSize != bufferSize;
}
-// Check if we have acquired the maximum number of buffers.
-// Consumer can acquire an additional buffer if that buffer is not droppable. Set
-// includeExtraAcquire is true to include this buffer to the count. Since this depends on the state
-// of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE.
-bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const {
- int maxAcquiredBuffers = mMaxAcquiredBuffers + (includeExtraAcquire ? 2 : 1);
- return mNumAcquired >= maxAcquiredBuffers;
-}
-
class BBQSurface : public Surface {
private:
std::mutex mMutex;
@@ -869,12 +884,13 @@
return mBbq->setFrameRate(frameRate, compatibility, changeFrameRateStrategy);
}
- status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override {
+ status_t setFrameTimelineInfo(uint64_t frameNumber,
+ const FrameTimelineInfo& frameTimelineInfo) override {
std::unique_lock _lock{mMutex};
if (mDestroyed) {
return DEAD_OBJECT;
}
- return mBbq->setFrameTimelineInfo(frameTimelineInfo);
+ return mBbq->setFrameTimelineInfo(frameNumber, frameTimelineInfo);
}
void destroy() override {
@@ -896,9 +912,12 @@
return t.setFrameRate(mSurfaceControl, frameRate, compatibility, shouldBeSeamless).apply();
}
-status_t BLASTBufferQueue::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) {
+status_t BLASTBufferQueue::setFrameTimelineInfo(uint64_t frameNumber,
+ const FrameTimelineInfo& frameTimelineInfo) {
+ ATRACE_FORMAT("%s(%s) frameNumber: %" PRIu64 " vsyncId: %" PRId64, __func__, mName.c_str(),
+ frameNumber, frameTimelineInfo.vsyncId);
std::unique_lock _lock{mMutex};
- mNextFrameTimelineInfoQueue.push(frameTimelineInfo);
+ mPendingFrameTimelines.push({frameNumber, frameTimelineInfo});
return OK;
}
@@ -1039,8 +1058,9 @@
// can be non-blocking when the producer is in the client process.
class BBQBufferQueueProducer : public BufferQueueProducer {
public:
- BBQBufferQueueProducer(const sp<BufferQueueCore>& core)
- : BufferQueueProducer(core, false /* consumerIsSurfaceFlinger*/) {}
+ BBQBufferQueueProducer(const sp<BufferQueueCore>& core, wp<BLASTBufferQueue> bbq)
+ : BufferQueueProducer(core, false /* consumerIsSurfaceFlinger*/),
+ mBLASTBufferQueue(std::move(bbq)) {}
status_t connect(const sp<IProducerListener>& listener, int api, bool producerControlledByApp,
QueueBufferOutput* output) override {
@@ -1052,6 +1072,26 @@
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<BLASTBufferQueue> 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;
@@ -1059,6 +1099,9 @@
}
return BufferQueueProducer::query(what, value);
}
+
+private:
+ const wp<BLASTBufferQueue> mBLASTBufferQueue;
};
// Similar to BufferQueue::createBufferQueue but creates an adapter specific bufferqueue producer.
@@ -1073,7 +1116,7 @@
sp<BufferQueueCore> core(new BufferQueueCore());
LOG_ALWAYS_FATAL_IF(core == nullptr, "BLASTBufferQueue: failed to create BufferQueueCore");
- sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core));
+ sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core, this));
LOG_ALWAYS_FATAL_IF(producer == nullptr,
"BLASTBufferQueue: failed to create BBQBufferQueueProducer");
@@ -1086,6 +1129,16 @@
*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 5fe5e71..9eb1a9f 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -119,6 +119,12 @@
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 @@
return NO_INIT;
}
+ *maxBufferCount = mCore->getMaxBufferCountLocked();
+
if (maxDequeuedBuffers == mCore->mMaxDequeuedBufferCount) {
return NO_ERROR;
}
@@ -183,6 +191,7 @@
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 e2ea3f9..f3eb4e8 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -168,10 +168,11 @@
} // 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<FrameEvents>(MAX_FRAME_HISTORY)) {}
+FrameEventHistory::FrameEventHistory()
+ : mFrames(std::vector<FrameEvents>(INITIAL_MAX_FRAME_HISTORY)) {}
FrameEventHistory::~FrameEventHistory() = default;
@@ -227,7 +228,6 @@
}
}
-
// ============================================================================
// ProducerFrameEventHistory
// ============================================================================
@@ -273,6 +273,13 @@
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 @@
return std::make_shared<FenceTime>(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<FrameEvents> 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<FrameEventDirtyFields>(MAX_FRAME_HISTORY)) {}
+ : mFramesDirty(std::vector<FrameEventDirtyFields>(INITIAL_MAX_FRAME_HISTORY)) {}
ConsumerFrameEventHistory::~ConsumerFrameEventHistory() = default;
@@ -489,6 +531,36 @@
}
}
+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<FrameEvents> newFrames(newSize);
+ std::vector<FrameEventDirtyFields> 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 @@
return NO_MEMORY;
}
- if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY ||
- mIndex > std::numeric_limits<uint16_t>::max()) {
+ if (mIndex >= UINT8_MAX || mIndex < 0) {
return BAD_VALUE;
}
@@ -601,7 +672,7 @@
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 @@
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>* fence) const {
+ if (mDisplayPresentFence.fence == Fence::NO_FENCE) {
+ return false;
+ }
+ *fence = mDisplayPresentFence.fence;
+ return true;
+}
// ============================================================================
// FrameEventHistoryDelta
@@ -665,7 +755,7 @@
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 @@
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 @@
return NO_ERROR;
}
+std::vector<FrameEventsDelta>::const_iterator FrameEventHistoryDelta::begin() const {
+ return mDeltas.begin();
+}
+
+std::vector<FrameEventsDelta>::const_iterator FrameEventHistoryDelta::end() const {
+ return mDeltas.end();
+}
} // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 502031c..74e6ae6 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -353,6 +353,27 @@
}
}
+void DisplayState::sanitize(int32_t permissions) {
+ if (what & DisplayState::eLayerStackChanged) {
+ if (!(permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER)) {
+ what &= ~DisplayState::eLayerStackChanged;
+ ALOGE("Stripped attempt to set eLayerStackChanged in sanitize");
+ }
+ }
+ if (what & DisplayState::eDisplayProjectionChanged) {
+ if (!(permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER)) {
+ what &= ~DisplayState::eDisplayProjectionChanged;
+ ALOGE("Stripped attempt to set eDisplayProjectionChanged in sanitize");
+ }
+ }
+ if (what & DisplayState::eSurfaceChanged) {
+ if (!(permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER)) {
+ what &= ~DisplayState::eSurfaceChanged;
+ ALOGE("Stripped attempt to set eSurfaceChanged in sanitize");
+ }
+ }
+}
+
void layer_state_t::sanitize(int32_t permissions) {
// TODO: b/109894387
//
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 3b13708..8f45425 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1865,12 +1865,13 @@
int Surface::dispatchSetFrameTimelineInfo(va_list args) {
ATRACE_CALL();
+ auto frameNumber = static_cast<uint64_t>(va_arg(args, uint64_t));
auto frameTimelineVsyncId = static_cast<int64_t>(va_arg(args, int64_t));
auto inputEventId = static_cast<int32_t>(va_arg(args, int32_t));
auto startTimeNanos = static_cast<int64_t>(va_arg(args, int64_t));
ALOGV("Surface::%s", __func__);
- return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId, startTimeNanos});
+ return setFrameTimelineInfo(frameNumber, {frameTimelineVsyncId, inputEventId, startTimeNanos});
}
bool Surface::transformToDisplayInverse() const {
@@ -2644,7 +2645,8 @@
changeFrameRateStrategy);
}
-status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) {
+status_t Surface::setFrameTimelineInfo(uint64_t /*frameNumber*/,
+ const FrameTimelineInfo& frameTimelineInfo) {
return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo);
}
diff --git a/libs/gui/bufferqueue/1.0/Conversion.cpp b/libs/gui/bufferqueue/1.0/Conversion.cpp
index 55462c3..9667954 100644
--- a/libs/gui/bufferqueue/1.0/Conversion.cpp
+++ b/libs/gui/bufferqueue/1.0/Conversion.cpp
@@ -725,12 +725,7 @@
// These were written as uint8_t for alignment.
uint8_t temp = 0;
FlattenableUtils::read(buffer, size, temp);
- size_t index = static_cast<size_t>(temp);
- if (index >= ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
- return BAD_VALUE;
- }
- t->index = static_cast<uint32_t>(index);
-
+ t->index = static_cast<uint32_t>(temp);
FlattenableUtils::read(buffer, size, temp);
t->addPostCompositeCalled = static_cast<bool>(temp);
FlattenableUtils::read(buffer, size, temp);
@@ -786,8 +781,7 @@
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<uint32_t>(FrameEventHistory::MAX_FRAME_HISTORY)
- || t.index > std::numeric_limits<uint8_t>::max()) {
+ if (t.index > UINT8_MAX || t.index < 0) {
return BAD_VALUE;
}
@@ -887,8 +881,7 @@
uint32_t deltaCount = 0;
FlattenableUtils::read(buffer, size, deltaCount);
- if (static_cast<size_t>(deltaCount) >
- ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+ if (deltaCount > UINT8_MAX) {
return BAD_VALUE;
}
t->deltas.resize(deltaCount);
@@ -919,7 +912,7 @@
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 cee1b81..f684874 100644
--- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -725,8 +725,7 @@
std::vector<native_handle_t*>* 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<uint32_t>(FrameEventHistory::MAX_FRAME_HISTORY)
- || t.index > std::numeric_limits<uint8_t>::max()) {
+ if (t.index > UINT8_MAX || t.index < 0) {
return BAD_VALUE;
}
@@ -829,7 +828,7 @@
HGraphicBufferProducer::FrameEventHistoryDelta const& t,
std::vector<std::vector<native_handle_t*> >* 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 48226b9..40ffea6 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -54,6 +54,8 @@
nsecs_t dequeueReadyTime) REQUIRES(mMutex);
void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect);
+ void resizeFrameEventHistory(size_t newSize);
+
protected:
void onSidebandStreamChanged() override REQUIRES(mMutex);
@@ -109,7 +111,7 @@
void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format);
status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
- status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
+ status_t setFrameTimelineInfo(uint64_t frameNumber, const FrameTimelineInfo& info);
void setSidebandStream(const sp<NativeHandle>& stream);
@@ -129,6 +131,7 @@
private:
friend class BLASTBufferQueueHelper;
+ friend class BBQBufferQueueProducer;
// can't be copied
BLASTBufferQueue& operator = (const BLASTBufferQueue& rhs);
@@ -136,12 +139,13 @@
void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer);
- void acquireNextBufferLocked(
+ void resizeFrameEventHistory(size_t newSize);
+
+ status_t acquireNextBufferLocked(
const std::optional<SurfaceComposerClient::Transaction*> transaction) REQUIRES(mMutex);
Rect computeCrop(const BufferItem& item) REQUIRES(mMutex);
// Return true if we need to reject the buffer based on the scaling mode and the buffer size.
bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex);
- bool maxBuffersAcquired(bool includeExtraAcquire) const REQUIRES(mMutex);
static PixelFormat convertBufferFormat(PixelFormat& format);
void mergePendingTransactions(SurfaceComposerClient::Transaction* t, uint64_t frameNumber)
REQUIRES(mMutex);
@@ -150,7 +154,6 @@
void acquireAndReleaseBuffer() REQUIRES(mMutex);
void releaseBuffer(const ReleaseCallbackId& callbackId, const sp<Fence>& releaseFence)
REQUIRES(mMutex);
- void flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock);
std::string mName;
// Represents the queued buffer count from buffer queue,
@@ -239,7 +242,7 @@
std::vector<std::tuple<uint64_t /* framenumber */, SurfaceComposerClient::Transaction>>
mPendingTransactions GUARDED_BY(mMutex);
- std::queue<FrameTimelineInfo> mNextFrameTimelineInfoQueue GUARDED_BY(mMutex);
+ std::queue<std::pair<uint64_t, FrameTimelineInfo>> mPendingFrameTimelines GUARDED_BY(mMutex);
// Tracks the last acquired frame number
uint64_t mLastAcquiredFrameNumber GUARDED_BY(mMutex) = 0;
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index 0ad3075..1d13dab 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -202,6 +202,11 @@
// 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<IBinder>& who);
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
index dd3de58..968aa2b 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -114,9 +114,11 @@
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<FrameEvents> mFrames;
CompositorTiming mCompositorTiming;
@@ -155,6 +157,8 @@
virtual std::shared_ptr<FenceTime> createFenceTime(
const sp<Fence>& fence) const;
+ void resize(size_t newSize);
+
size_t mAcquireOffset{0};
// The consumer updates it's timelines in Layer and SurfaceFlinger since
@@ -225,6 +229,8 @@
void getAndResetDelta(FrameEventHistoryDelta* delta);
+ void resize(size_t newSize);
+
private:
void getFrameDelta(FrameEventHistoryDelta* delta,
const std::vector<FrameEvents>::iterator& frame);
@@ -267,6 +273,10 @@
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>* fence) const;
+
private:
static constexpr size_t minFlattenedSize();
@@ -327,6 +337,9 @@
status_t unflatten(void const*& buffer, size_t& size, int const*& fds,
size_t& count);
+ std::vector<FrameEventsDelta>::const_iterator begin() const;
+ std::vector<FrameEventsDelta>::const_iterator end() const;
+
private:
static constexpr size_t minFlattenedSize();
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 0a9b75a..0071d48 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -320,6 +320,7 @@
DisplayState();
void merge(const DisplayState& other);
+ void sanitize(int32_t permissions);
uint32_t what = 0;
uint32_t flags = 0;
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 77615fe..4a552b6 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -211,7 +211,7 @@
virtual status_t setFrameRate(float frameRate, int8_t compatibility,
int8_t changeFrameRateStrategy);
- virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
+ virtual status_t setFrameTimelineInfo(uint64_t frameNumber, const FrameTimelineInfo& info);
protected:
virtual ~Surface();
diff --git a/libs/gui/include/gui/TraceUtils.h b/libs/gui/include/gui/TraceUtils.h
index e5d2684..0009615 100644
--- a/libs/gui/include/gui/TraceUtils.h
+++ b/libs/gui/include/gui/TraceUtils.h
@@ -27,6 +27,8 @@
#define ATRACE_FORMAT_BEGIN(fmt, ...) TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__)
+#define ATRACE_FORMAT_INSTANT(fmt, ...) TraceUtils::intantFormat(fmt, ##__VA_ARGS__)
+
namespace android {
class TraceUtils {
@@ -50,6 +52,20 @@
ATRACE_BEGIN(buf);
}
+ static void intantFormat(const char* fmt, ...) {
+ if (CC_LIKELY(!ATRACE_ENABLED())) return;
+
+ const int BUFFER_SIZE = 256;
+ va_list ap;
+ char buf[BUFFER_SIZE];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, BUFFER_SIZE, fmt, ap);
+ va_end(ap);
+
+ ATRACE_INSTANT(buf);
+ }
+
}; // class TraceUtils
} /* namespace android */
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index a54af1f..86e76c4 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -1043,11 +1043,12 @@
}
static inline int native_window_set_frame_timeline_info(struct ANativeWindow* window,
+ uint64_t frameNumber,
int64_t frameTimelineVsyncId,
int32_t inputEventId,
int64_t startTimeNanos) {
- return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, frameTimelineVsyncId,
- inputEventId, startTimeNanos);
+ return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, frameNumber,
+ frameTimelineVsyncId, inputEventId, startTimeNanos);
}
// ------------------------------------------------------------------------------------------------
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index a6cacad..93c95b9 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -66,7 +66,11 @@
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 @@
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/Sensor.cpp b/libs/sensor/Sensor.cpp
index ec0ced8..b865c4d 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -632,7 +632,13 @@
return false;
}
outputString8.setTo(static_cast<char const*>(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;
}
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 0ba9704..40061cd 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -92,6 +92,16 @@
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);
@@ -166,6 +176,11 @@
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<Sensor const**>(malloc(count * sizeof(Sensor*)));
LOG_ALWAYS_FATAL_IF(mSensorList == nullptr, "mSensorList NULL");
diff --git a/libs/sensor/include/sensor/SensorManager.h b/libs/sensor/include/sensor/SensorManager.h
index 8d0a8a4..7c9d604 100644
--- a/libs/sensor/include/sensor/SensorManager.h
+++ b/libs/sensor/include/sensor/SensorManager.h
@@ -54,6 +54,7 @@
{
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/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 96164c0..b9cb4ad 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2208,8 +2208,31 @@
// Update the temporary touch state.
BitSet32 pointerIds;
pointerIds.markBit(entry.pointerProperties[pointerIndex].id);
-
tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds);
+
+ // 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 (maskedAction == AMOTION_EVENT_ACTION_DOWN ||
+ maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) {
+ if ((targetFlags & InputTarget::FLAG_FOREGROUND) &&
+ windowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
+ sp<WindowInfoHandle> wallpaper = findWallpaperWindowBelow(windowHandle);
+ if (wallpaper != nullptr) {
+ int32_t wallpaperFlags = InputTarget::FLAG_WINDOW_IS_OBSCURED |
+ InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED |
+ InputTarget::FLAG_DISPATCH_AS_IS;
+ if (isSplit) {
+ wallpaperFlags |= InputTarget::FLAG_SPLIT;
+ }
+ tempTouchState.addOrUpdateWindow(wallpaper, wallpaperFlags, pointerIds);
+ }
+ }
+ }
}
} else {
/* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
@@ -2286,6 +2309,10 @@
BitSet32 pointerIds;
pointerIds.markBit(entry.pointerProperties[0].id);
tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
+
+ // Check if the wallpaper window should deliver the corresponding event.
+ slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle,
+ tempTouchState, pointerIds);
}
}
@@ -2391,39 +2418,6 @@
}
}
- // If this is the first 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 (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
- sp<WindowInfoHandle> foregroundWindowHandle =
- tempTouchState.getFirstForegroundWindowHandle();
- if (foregroundWindowHandle &&
- foregroundWindowHandle->getInfo()->inputConfig.test(
- WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
- const std::vector<sp<WindowInfoHandle>>& windowHandles =
- getWindowHandlesLocked(displayId);
- for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
- const WindowInfo* info = windowHandle->getInfo();
- if (info->displayId == displayId &&
- windowHandle->getInfo()->inputConfig.test(
- WindowInfo::InputConfig::IS_WALLPAPER)) {
- BitSet32 pointerIds;
- pointerIds.markBit(entry.pointerProperties[0].id);
- tempTouchState
- .addOrUpdateWindow(windowHandle,
- InputTarget::FLAG_WINDOW_IS_OBSCURED |
- InputTarget::
- FLAG_WINDOW_IS_PARTIALLY_OBSCURED |
- InputTarget::FLAG_DISPATCH_AS_IS,
- pointerIds);
- }
- }
- }
- }
-
// Success! Output targets.
injectionResult = InputEventInjectionResult::SUCCEEDED;
@@ -3702,7 +3696,7 @@
}
void InputDispatcher::synthesizePointerDownEventsForConnectionLocked(
- const sp<Connection>& connection) {
+ const sp<Connection>& connection, int32_t targetFlags) {
if (connection->status == Connection::Status::BROKEN) {
return;
}
@@ -3730,7 +3724,7 @@
target.globalScaleFactor = windowInfo->globalScaleFactor;
}
target.inputChannel = connection->inputChannel;
- target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+ target.flags = targetFlags;
const bool wasEmpty = connection->outboundQueue.empty();
@@ -3765,6 +3759,16 @@
}
}
+void InputDispatcher::synthesizeCancelationEventsForWindowLocked(
+ const sp<WindowInfoHandle>& windowHandle, const CancelationOptions& options) {
+ if (windowHandle != nullptr) {
+ sp<Connection> wallpaperConnection = getConnectionLocked(windowHandle->getToken());
+ if (wallpaperConnection != nullptr) {
+ synthesizeCancelationEventsForConnectionLocked(wallpaperConnection, options);
+ }
+ }
+}
+
std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent(
const MotionEntry& originalMotionEntry, BitSet32 pointerIds) {
ALOG_ASSERT(pointerIds.value != 0);
@@ -4792,14 +4796,7 @@
touchedWindow.windowHandle->getInfo()->inputConfig.test(
gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
sp<WindowInfoHandle> wallpaper = state.getWallpaperWindow();
- if (wallpaper != nullptr) {
- sp<Connection> wallpaperConnection =
- getConnectionLocked(wallpaper->getToken());
- if (wallpaperConnection != nullptr) {
- synthesizeCancelationEventsForConnectionLocked(wallpaperConnection,
- options);
- }
- }
+ synthesizeCancelationEventsForWindowLocked(wallpaper, options);
}
}
state.windows.erase(state.windows.begin() + i);
@@ -5112,6 +5109,7 @@
// Erase old window.
int32_t oldTargetFlags = touchedWindow->targetFlags;
BitSet32 pointerIds = touchedWindow->pointerIds;
+ sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle;
state->removeWindowByToken(fromToken);
// Add new window.
@@ -5143,7 +5141,10 @@
options(CancelationOptions::CANCEL_POINTER_EVENTS,
"transferring touch focus from this window to another window");
synthesizeCancelationEventsForConnectionLocked(fromConnection, options);
- synthesizePointerDownEventsForConnectionLocked(toConnection);
+ synthesizePointerDownEventsForConnectionLocked(toConnection, newTargetFlags);
+ // Check if the wallpaper window should deliver the corresponding event.
+ transferWallpaperTouch(oldTargetFlags, newTargetFlags, fromWindowHandle, toWindowHandle,
+ *state, pointerIds);
}
if (DEBUG_FOCUS) {
@@ -6428,4 +6429,97 @@
mMonitorDispatchingTimeout = timeout;
}
+void InputDispatcher::slipWallpaperTouch(int32_t targetFlags,
+ const sp<WindowInfoHandle>& oldWindowHandle,
+ const sp<WindowInfoHandle>& newWindowHandle,
+ TouchState& state, const BitSet32& pointerIds) {
+ const bool oldHasWallpaper = oldWindowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
+ const bool newHasWallpaper = (targetFlags & InputTarget::FLAG_FOREGROUND) &&
+ newWindowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
+ const sp<WindowInfoHandle> oldWallpaper =
+ oldHasWallpaper ? state.getWallpaperWindow() : nullptr;
+ const sp<WindowInfoHandle> newWallpaper =
+ newHasWallpaper ? findWallpaperWindowBelow(newWindowHandle) : nullptr;
+ if (oldWallpaper == newWallpaper) {
+ return;
+ }
+
+ if (oldWallpaper != nullptr) {
+ state.addOrUpdateWindow(oldWallpaper, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT,
+ BitSet32(0));
+ }
+
+ if (newWallpaper != nullptr) {
+ state.addOrUpdateWindow(newWallpaper,
+ InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER |
+ InputTarget::FLAG_WINDOW_IS_OBSCURED |
+ InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED,
+ pointerIds);
+ }
+}
+
+void InputDispatcher::transferWallpaperTouch(int32_t oldTargetFlags, int32_t newTargetFlags,
+ const sp<WindowInfoHandle> fromWindowHandle,
+ const sp<WindowInfoHandle> toWindowHandle,
+ TouchState& state, const BitSet32& pointerIds) {
+ const bool oldHasWallpaper = (oldTargetFlags & InputTarget::FLAG_FOREGROUND) &&
+ fromWindowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
+ const bool newHasWallpaper = (newTargetFlags & InputTarget::FLAG_FOREGROUND) &&
+ toWindowHandle->getInfo()->inputConfig.test(
+ gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
+
+ const sp<WindowInfoHandle> oldWallpaper =
+ oldHasWallpaper ? state.getWallpaperWindow() : nullptr;
+ const sp<WindowInfoHandle> newWallpaper =
+ newHasWallpaper ? findWallpaperWindowBelow(toWindowHandle) : nullptr;
+ if (oldWallpaper == newWallpaper) {
+ return;
+ }
+
+ if (oldWallpaper != nullptr) {
+ CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
+ "transferring touch focus to another window");
+ state.removeWindowByToken(oldWallpaper->getToken());
+ synthesizeCancelationEventsForWindowLocked(oldWallpaper, options);
+ }
+
+ if (newWallpaper != nullptr) {
+ int32_t wallpaperFlags =
+ oldTargetFlags & (InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS);
+ wallpaperFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED |
+ InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+ state.addOrUpdateWindow(newWallpaper, wallpaperFlags, pointerIds);
+ sp<Connection> wallpaperConnection = getConnectionLocked(newWallpaper->getToken());
+ if (wallpaperConnection != nullptr) {
+ sp<Connection> toConnection = getConnectionLocked(toWindowHandle->getToken());
+ toConnection->inputState.mergePointerStateTo(wallpaperConnection->inputState);
+ synthesizePointerDownEventsForConnectionLocked(wallpaperConnection, wallpaperFlags);
+ }
+ }
+}
+
+sp<WindowInfoHandle> InputDispatcher::findWallpaperWindowBelow(
+ const sp<WindowInfoHandle>& windowHandle) const {
+ const std::vector<sp<WindowInfoHandle>>& windowHandles =
+ getWindowHandlesLocked(windowHandle->getInfo()->displayId);
+ bool foundWindow = false;
+ for (const sp<WindowInfoHandle>& otherHandle : windowHandles) {
+ if (!foundWindow && otherHandle != windowHandle) {
+ continue;
+ }
+ if (windowHandle == otherHandle) {
+ foundWindow = true;
+ continue;
+ }
+
+ if (otherHandle->getInfo()->inputConfig.test(WindowInfo::InputConfig::IS_WALLPAPER)) {
+ return otherHandle;
+ }
+ }
+ return nullptr;
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 24e7432..7769b9e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -622,8 +622,12 @@
const CancelationOptions& options)
REQUIRES(mLock);
- void synthesizePointerDownEventsForConnectionLocked(const sp<Connection>& connection)
- REQUIRES(mLock);
+ void synthesizePointerDownEventsForConnectionLocked(const sp<Connection>& connection,
+ int32_t targetFlags) REQUIRES(mLock);
+
+ void synthesizeCancelationEventsForWindowLocked(
+ const sp<android::gui::WindowInfoHandle>& windowHandle,
+ const CancelationOptions& options) REQUIRES(mLock);
// Splitting motion events across windows.
std::unique_ptr<MotionEntry> splitMotionEvent(const MotionEntry& originalMotionEntry,
@@ -685,6 +689,18 @@
bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
sp<InputReporterInterface> mReporter;
+
+ void slipWallpaperTouch(int32_t targetFlags,
+ const sp<android::gui::WindowInfoHandle>& oldWindowHandle,
+ const sp<android::gui::WindowInfoHandle>& newWindowHandle,
+ TouchState& state, const BitSet32& pointerIds) REQUIRES(mLock);
+ void transferWallpaperTouch(int32_t oldTargetFlags, int32_t newTargetFlags,
+ const sp<android::gui::WindowInfoHandle> fromWindowHandle,
+ const sp<android::gui::WindowInfoHandle> toWindowHandle,
+ TouchState& state, const BitSet32& pointerIds) REQUIRES(mLock);
+
+ sp<android::gui::WindowInfoHandle> findWallpaperWindowBelow(
+ const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock);
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index e860e3c..b23b88a 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -58,6 +58,8 @@
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);
+static constexpr int32_t POINTER_0_UP =
+ AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
static constexpr int32_t POINTER_1_UP =
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
@@ -73,6 +75,9 @@
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;
+
struct PointF {
float x;
float y;
@@ -1670,8 +1675,6 @@
sp<FakeWindowHandle> wallpaperWindow =
new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setIsWallpaper(true);
- constexpr int expectedWallpaperFlags =
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1714,8 +1717,6 @@
sp<FakeWindowHandle> wallpaperWindow =
new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setIsWallpaper(true);
- constexpr int expectedWallpaperFlags =
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}});
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1745,24 +1746,27 @@
foregroundWindow->consumeMotionCancel();
}
+class ShouldSplitTouchFixture : public InputDispatcherTest,
+ public ::testing::WithParamInterface<bool> {};
+INSTANTIATE_TEST_SUITE_P(InputDispatcherTest, ShouldSplitTouchFixture,
+ ::testing::Values(true, false));
/**
* A single window that receives touch (on top), and a wallpaper window underneath it.
* The top window gets a multitouch gesture.
* Ensure that wallpaper gets the same gesture.
*/
-TEST_F(InputDispatcherTest, WallpaperWindow_ReceivesMultiTouch) {
+TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
- window->setDupTouchToWallpaper(true);
+ sp<FakeWindowHandle> foregroundWindow =
+ new FakeWindowHandle(application, mDispatcher, "Foreground", ADISPLAY_ID_DEFAULT);
+ foregroundWindow->setDupTouchToWallpaper(true);
+ foregroundWindow->setPreventSplitting(GetParam());
sp<FakeWindowHandle> wallpaperWindow =
new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setIsWallpaper(true);
- constexpr int expectedWallpaperFlags =
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}});
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {foregroundWindow, wallpaperWindow}}});
// Touch down on top window
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1771,7 +1775,7 @@
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
// Both top window and its wallpaper should receive the touch down
- window->consumeMotionDown();
+ foregroundWindow->consumeMotionDown();
wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
// Second finger down on the top window
@@ -1790,11 +1794,34 @@
InputEventInjectionSync::WAIT_FOR_RESULT))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionPointerDown(1 /* pointerIndex */);
+ foregroundWindow->consumeMotionPointerDown(1 /* pointerIndex */);
wallpaperWindow->consumeMotionPointerDown(1 /* pointerIndex */, ADISPLAY_ID_DEFAULT,
expectedWallpaperFlags);
- window->assertNoEvents();
- wallpaperWindow->assertNoEvents();
+
+ const MotionEvent secondFingerUpEvent =
+ 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))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ 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,
+ injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 100}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ foregroundWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
}
/**
@@ -1821,8 +1848,6 @@
new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setFrame(Rect(0, 0, 400, 200));
wallpaperWindow->setIsWallpaper(true);
- constexpr int expectedWallpaperFlags =
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
mDispatcher->setInputWindows(
{{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow, wallpaperWindow}}});
@@ -1887,62 +1912,49 @@
wallpaperWindow->assertNoEvents();
}
-TEST_F(InputDispatcherTest, WallpaperWindowReceivesMultiTouch) {
+/**
+ * Two windows: a window on the left with dup touch to wallpaper and window on the right without it.
+ * The touch slips to the right window. so left window and wallpaper should receive ACTION_CANCEL
+ * The right window should receive ACTION_DOWN.
+ */
+TEST_F(InputDispatcherTest, WallpaperWindowWhenSlippery) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
- sp<FakeWindowHandle> window =
- sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
- window->setDupTouchToWallpaper(true);
+ sp<FakeWindowHandle> leftWindow =
+ new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
+ leftWindow->setFrame(Rect(0, 0, 200, 200));
+ leftWindow->setDupTouchToWallpaper(true);
+ leftWindow->setSlippery(true);
+
+ sp<FakeWindowHandle> rightWindow =
+ new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
+ rightWindow->setFrame(Rect(200, 0, 400, 200));
sp<FakeWindowHandle> wallpaperWindow =
- sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+ new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
wallpaperWindow->setIsWallpaper(true);
- constexpr int expectedWallpaperFlags =
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
- wallpaperWindow->setPreventSplitting(true);
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}});
+ mDispatcher->setInputWindows(
+ {{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow, wallpaperWindow}}});
+ // Touch down on left window
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
- {50, 50}))
+ {100, 100}))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ // Both foreground window and its wallpaper should receive the touch down
+ leftWindow->consumeMotionDown();
wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
- const MotionEvent secondFingerDownEvent =
- 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(10).y(10))
- .build();
+ // Move to right window, the left window should receive cancel.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
- InputEventInjectionSync::WAIT_FOR_RESULT))
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {201, 100}))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionPointerDown(1);
- wallpaperWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
-
- const MotionEvent secondFingerUpEvent =
- MotionEventBuilder(POINTER_1_UP, 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(10).y(10))
- .build();
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
- InputEventInjectionSync::WAIT_FOR_RESULT))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionPointerUp(1);
- wallpaperWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
-
- ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50}))
- << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
- window->consumeMotionUp(ADISPLAY_ID_DEFAULT);
- wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+ leftWindow->consumeMotionCancel();
+ rightWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ wallpaperWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
}
/**
@@ -2696,20 +2708,26 @@
// Create a couple of windows
sp<FakeWindowHandle> firstWindow =
new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ firstWindow->setDupTouchToWallpaper(true);
+
sp<FakeWindowHandle> secondWindow =
new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
-
+ sp<FakeWindowHandle> wallpaper =
+ new FakeWindowHandle(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT);
+ wallpaper->setIsWallpaper(true);
// Add the windows to the dispatcher
- mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
+ 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);
+
// Only the first window should get the down event
firstWindow->consumeMotionDown();
secondWindow->assertNoEvents();
+ wallpaper->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
// Transfer touch to the second window
TransferFunction f = GetParam();
@@ -2718,6 +2736,7 @@
// The first window gets cancel and the second gets down
firstWindow->consumeMotionCancel();
secondWindow->consumeMotionDown();
+ wallpaper->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
// Send up event to the second window
NotifyMotionArgs upMotionArgs =
@@ -2727,6 +2746,7 @@
// The first window gets no events and the second gets up
firstWindow->assertNoEvents();
secondWindow->consumeMotionUp();
+ wallpaper->assertNoEvents();
}
/**
@@ -2848,6 +2868,65 @@
secondWindow->consumeMotionUp();
}
+TEST_P(TransferTouchFixture, TransferTouch_MultipleWallpapers) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+ // Create a couple of windows
+ sp<FakeWindowHandle> firstWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "First Window",
+ ADISPLAY_ID_DEFAULT);
+ firstWindow->setDupTouchToWallpaper(true);
+ sp<FakeWindowHandle> secondWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Second Window",
+ ADISPLAY_ID_DEFAULT);
+ secondWindow->setDupTouchToWallpaper(true);
+
+ sp<FakeWindowHandle> wallpaper1 =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper1", ADISPLAY_ID_DEFAULT);
+ wallpaper1->setIsWallpaper(true);
+
+ sp<FakeWindowHandle> wallpaper2 =
+ sp<FakeWindowHandle>::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}}});
+
+ // Send down to the first window
+ NotifyMotionArgs downMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+ mDispatcher->notifyMotion(&downMotionArgs);
+
+ // Only the first window should get the down event
+ firstWindow->consumeMotionDown();
+ secondWindow->assertNoEvents();
+ wallpaper1->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+ wallpaper2->assertNoEvents();
+
+ // Transfer touch focus to the second window
+ TransferFunction f = GetParam();
+ bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
+ ASSERT_TRUE(success);
+
+ // The first window gets cancel and the second gets down
+ firstWindow->consumeMotionCancel();
+ secondWindow->consumeMotionDown();
+ wallpaper1->consumeMotionCancel(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+ 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);
+ // The first window gets no events and the second gets up
+ firstWindow->assertNoEvents();
+ secondWindow->consumeMotionUp();
+ wallpaper1->assertNoEvents();
+ wallpaper2->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags);
+}
+
// For the cases of single pointer touch and two pointers non-split touch, the api's
// 'transferTouch' and 'transferTouchFocus' are equivalent in behaviour. They only differ
// for the case where there are multiple pointers split across several windows.
diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp
index 9380600..0a4e684 100644
--- a/services/sensorservice/hidl/SensorManager.cpp
+++ b/services/sensorservice/hidl/SensorManager.cpp
@@ -60,6 +60,9 @@
if (mPollThread.joinable()) {
mPollThread.join();
}
+
+ ::android::SensorManager::removeInstanceForPackage(
+ String16(ISensorManager::descriptor));
}
// Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 86ad4ef..b49c95d 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -174,7 +174,7 @@
void DisplayDevice::setPowerMode(hal::PowerMode mode) {
if (mode == hal::PowerMode::OFF || mode == hal::PowerMode::ON) {
- if (mStagedBrightness && mBrightness != *mStagedBrightness) {
+ if (mStagedBrightness && mBrightness != mStagedBrightness) {
getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
mBrightness = *mStagedBrightness;
}
@@ -336,7 +336,7 @@
}
void DisplayDevice::persistBrightness(bool needsComposite) {
- if (mStagedBrightness && mBrightness != *mStagedBrightness) {
+ if (mStagedBrightness && mBrightness != mStagedBrightness) {
if (needsComposite) {
getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index f14bef3..b91dece 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -284,8 +284,8 @@
// allow initial power mode as null.
std::optional<hardware::graphics::composer::hal::PowerMode> mPowerMode;
DisplayModePtr mActiveMode;
- std::optional<float> mStagedBrightness = std::nullopt;
- float mBrightness = -1.f;
+ std::optional<float> mStagedBrightness;
+ std::optional<float> mBrightness;
const DisplayModes mSupportedModes;
std::atomic<nsecs_t> mLastHwVsync = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 866958d..52b7620 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4227,7 +4227,7 @@
bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo,
Vector<ComposerState>& states,
- const Vector<DisplayState>& displays, uint32_t flags,
+ Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
const int64_t desiredPresentTime, bool isAutoTimestamp,
const client_cache_t& uncacheBuffer,
@@ -4236,7 +4236,8 @@
const std::vector<ListenerCallbacks>& listenerCallbacks,
int originPid, int originUid, uint64_t transactionId) {
uint32_t transactionFlags = 0;
- for (const DisplayState& display : displays) {
+ for (DisplayState& display : displays) {
+ display.sanitize(permissions);
transactionFlags |= setDisplayStateLocked(display);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3e3830d..7c44bf4 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -763,7 +763,7 @@
* Transactions
*/
bool applyTransactionState(const FrameTimelineInfo& info, Vector<ComposerState>& state,
- const Vector<DisplayState>& displays, uint32_t flags,
+ Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
const int64_t desiredPresentTime, bool isAutoTimestamp,
const client_cache_t& uncacheBuffer, const int64_t postTime,
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 2dc96b8..c58fe48 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -149,4 +149,4 @@
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
index 225ad16..ac5e927 100644
--- a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
@@ -96,5 +96,23 @@
EXPECT_EQ(std::nullopt, displayDevice->getCompositionDisplay()->getState().displayBrightness);
}
+TEST_F(SetDisplayBrightnessTest, firstDisplayBrightnessWithComposite) {
+ ftl::FakeGuard guard(kMainThreadContext);
+ sp<DisplayDevice> displayDevice = getDisplayDevice();
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+
+ constexpr float kDisplayBrightness = -1.0f;
+ displayDevice->stageBrightness(kDisplayBrightness);
+
+ EXPECT_EQ(-1.0f, displayDevice->getStagedBrightness());
+
+ displayDevice->persistBrightness(true);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(kDisplayBrightness,
+ displayDevice->getCompositionDisplay()->getState().displayBrightness);
+}
+
} // namespace
} // namespace android