Merge "Fix shader calculation equations that causes SDR grayscale mess-up." into tm-dev
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index c2793ac..dbccf30 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -165,6 +165,17 @@
mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
mNumAcquired = 0;
mNumFrameAvailable = 0;
+
+ TransactionCompletedListener::getInstance()->addQueueStallListener(
+ [&]() {
+ std::function<void(bool)> callbackCopy;
+ {
+ std::unique_lock _lock{mMutex};
+ callbackCopy = mTransactionHangCallback;
+ }
+ if (callbackCopy) callbackCopy(true);
+ }, this);
+
BQA_LOGV("BLASTBufferQueue created");
}
@@ -175,6 +186,7 @@
}
BLASTBufferQueue::~BLASTBufferQueue() {
+ TransactionCompletedListener::getInstance()->removeQueueStallListener(this);
if (mPendingTransactions.empty()) {
return;
}
@@ -1113,4 +1125,9 @@
return SurfaceControl::isSameSurface(mSurfaceControl, surfaceControl);
}
+void BLASTBufferQueue::setTransactionHangCallback(std::function<void(bool)> callback) {
+ std::unique_lock _lock{mMutex};
+ mTransactionHangCallback = callback;
+}
+
} // namespace android
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index f7392d4..e4b8bad 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -29,6 +29,7 @@
enum class Tag : uint32_t {
ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION,
ON_RELEASE_BUFFER,
+ ON_TRANSACTION_QUEUE_STALLED,
LAST = ON_RELEASE_BUFFER,
};
@@ -277,6 +278,11 @@
callbackId, releaseFence,
currentMaxAcquiredBufferCount);
}
+
+ void onTransactionQueueStalled() override {
+ callRemoteAsync<decltype(&ITransactionCompletedListener::onTransactionQueueStalled)>(
+ Tag::ON_TRANSACTION_QUEUE_STALLED);
+ }
};
// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
@@ -297,6 +303,9 @@
&ITransactionCompletedListener::onTransactionCompleted);
case Tag::ON_RELEASE_BUFFER:
return callLocalAsync(data, reply, &ITransactionCompletedListener::onReleaseBuffer);
+ case Tag::ON_TRANSACTION_QUEUE_STALLED:
+ return callLocalAsync(data, reply,
+ &ITransactionCompletedListener::onTransactionQueueStalled);
}
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 6642ec6..501f8cf 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -447,6 +447,27 @@
}
}
+void TransactionCompletedListener::onTransactionQueueStalled() {
+ std::unordered_map<void*, std::function<void()>> callbackCopy;
+ {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ callbackCopy = mQueueStallListeners;
+ }
+ for (auto const& it : callbackCopy) {
+ it.second();
+ }
+}
+
+void TransactionCompletedListener::addQueueStallListener(std::function<void()> stallListener,
+ void* id) {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ mQueueStallListeners[id] = stallListener;
+}
+void TransactionCompletedListener::removeQueueStallListener(void *id) {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ mQueueStallListeners.erase(id);
+}
+
void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId,
sp<Fence> releaseFence,
uint32_t currentMaxAcquiredBufferCount) {
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 65fc04d..9328a54 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -113,6 +113,14 @@
uint64_t getLastAcquiredFrameNum();
void abandon();
+ /**
+ * Set a callback to be invoked when we are hung. The boolean parameter
+ * indicates whether the hang is due to an unfired fence.
+ * TODO: The boolean is always true atm, unfired fence is
+ * the only case we detect.
+ */
+ void setTransactionHangCallback(std::function<void(bool)> callback);
+
virtual ~BLASTBufferQueue();
private:
@@ -269,6 +277,8 @@
// transaction that will be applied by some sync consumer.
bool mAppliedLastTransaction = false;
uint64_t mLastAppliedFrameNumber = 0;
+
+ std::function<void(bool)> mTransactionHangCallback;
};
} // namespace android
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index a791c66..cc136bb 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -194,6 +194,7 @@
virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence,
uint32_t currentMaxAcquiredBufferCount) = 0;
+ virtual void onTransactionQueueStalled() = 0;
};
class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0cc43d8..efbdb36 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -772,6 +772,7 @@
// This is protected by mSurfaceStatsListenerMutex, but GUARDED_BY isn't supported for
// std::recursive_mutex
std::multimap<int32_t, SurfaceStatsCallbackEntry> mSurfaceStatsListeners;
+ std::unordered_map<void*, std::function<void()>> mQueueStallListeners;
public:
static sp<TransactionCompletedListener> getInstance();
@@ -789,6 +790,9 @@
const sp<SurfaceControl>& surfaceControl,
const std::unordered_set<CallbackId, CallbackIdHash>& callbackIds);
+ void addQueueStallListener(std::function<void()> stallListener, void* id);
+ void removeQueueStallListener(void *id);
+
/*
* Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific
* surface. Jank classifications arrive as part of the transaction callbacks about previous
@@ -817,6 +821,8 @@
// For Testing Only
static void setInstance(const sp<TransactionCompletedListener>&);
+ void onTransactionQueueStalled() override;
+
private:
ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&);
static sp<TransactionCompletedListener> sInstance;
diff --git a/libs/renderengine/TEST_MAPPING b/libs/renderengine/TEST_MAPPING
index 995dba1..db00118 100644
--- a/libs/renderengine/TEST_MAPPING
+++ b/libs/renderengine/TEST_MAPPING
@@ -3,5 +3,11 @@
{
"name": "librenderengine_test"
}
+ ],
+
+ "imports": [
+ {
+ "path": "frameworks/native/services/surfaceflinger"
+ }
]
}
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
index beca7f1..86c788d 100644
--- a/opengl/libs/EGL/BlobCache.cpp
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -52,35 +52,37 @@
ALOGV("initializing random seed using %lld", (unsigned long long)now);
}
-void BlobCache::set(const void* key, size_t keySize, const void* value, size_t valueSize) {
+BlobCache::InsertResult BlobCache::set(const void* key, size_t keySize, const void* value,
+ size_t valueSize) {
if (mMaxKeySize < keySize) {
ALOGV("set: not caching because the key is too large: %zu (limit: %zu)", keySize,
mMaxKeySize);
- return;
+ return InsertResult::kKeyTooBig;
}
if (mMaxValueSize < valueSize) {
ALOGV("set: not caching because the value is too large: %zu (limit: %zu)", valueSize,
mMaxValueSize);
- return;
+ return InsertResult::kValueTooBig;
}
if (mMaxTotalSize < keySize + valueSize) {
ALOGV("set: not caching because the combined key/value size is too "
"large: %zu (limit: %zu)",
keySize + valueSize, mMaxTotalSize);
- return;
+ return InsertResult::kCombinedTooBig;
}
if (keySize == 0) {
ALOGW("set: not caching because keySize is 0");
- return;
+ return InsertResult::kInvalidKeySize;
}
- if (valueSize <= 0) {
+ if (valueSize == 0) {
ALOGW("set: not caching because valueSize is 0");
- return;
+ return InsertResult::kInvalidValueSize;
}
std::shared_ptr<Blob> cacheKey(new Blob(key, keySize, false));
CacheEntry cacheEntry(cacheKey, nullptr);
+ bool didClean = false;
while (true) {
auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), cacheEntry);
if (index == mCacheEntries.end() || cacheEntry < *index) {
@@ -92,13 +94,14 @@
if (isCleanable()) {
// Clean the cache and try again.
clean();
+ didClean = true;
continue;
} else {
ALOGV("set: not caching new key/value pair because the "
"total cache size limit would be exceeded: %zu "
"(limit: %zu)",
keySize + valueSize, mMaxTotalSize);
- break;
+ return InsertResult::kNotEnoughSpace;
}
}
mCacheEntries.insert(index, CacheEntry(keyBlob, valueBlob));
@@ -114,12 +117,13 @@
if (isCleanable()) {
// Clean the cache and try again.
clean();
+ didClean = true;
continue;
} else {
ALOGV("set: not caching new value because the total cache "
"size limit would be exceeded: %zu (limit: %zu)",
keySize + valueSize, mMaxTotalSize);
- break;
+ return InsertResult::kNotEnoughSpace;
}
}
index->setValue(valueBlob);
@@ -128,7 +132,7 @@
"value",
keySize, valueSize);
}
- break;
+ return didClean ? InsertResult::kDidClean : InsertResult::kInserted;
}
}
diff --git a/opengl/libs/EGL/BlobCache.h b/opengl/libs/EGL/BlobCache.h
index 50b4e4c..ff03d30 100644
--- a/opengl/libs/EGL/BlobCache.h
+++ b/opengl/libs/EGL/BlobCache.h
@@ -39,6 +39,26 @@
// (key sizes plus value sizes) will not exceed maxTotalSize.
BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize);
+ // Return value from set(), below.
+ enum class InsertResult {
+ // The key is larger than maxKeySize specified in the constructor.
+ kKeyTooBig,
+ // The value is larger than maxValueSize specified in the constructor.
+ kValueTooBig,
+ // The combined key + value is larger than maxTotalSize specified in the constructor.
+ kCombinedTooBig,
+ // keySize is 0
+ kInvalidKeySize,
+ // valueSize is 0
+ kInvalidValueSize,
+ // Unable to free enough space to fit the new entry.
+ kNotEnoughSpace,
+ // The new entry was inserted, but an old entry had to be evicted.
+ kDidClean,
+ // There was enough room in the cache and the new entry was inserted.
+ kInserted,
+
+ };
// set inserts a new binary value into the cache and associates it with the
// given binary key. If the key or value are too large for the cache then
// the cache remains unchanged. This includes the case where a different
@@ -54,7 +74,7 @@
// 0 < keySize
// value != NULL
// 0 < valueSize
- void set(const void* key, size_t keySize, const void* value, size_t valueSize);
+ InsertResult set(const void* key, size_t keySize, const void* value, size_t valueSize);
// get retrieves from the cache the binary value associated with a given
// binary key. If the key is present in the cache then the length of the
diff --git a/opengl/libs/EGL/BlobCache_test.cpp b/opengl/libs/EGL/BlobCache_test.cpp
index d31373b..ceea0fb 100644
--- a/opengl/libs/EGL/BlobCache_test.cpp
+++ b/opengl/libs/EGL/BlobCache_test.cpp
@@ -49,7 +49,7 @@
TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
ASSERT_EQ('e', buf[0]);
ASSERT_EQ('f', buf[1]);
@@ -59,8 +59,8 @@
TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
unsigned char buf[2] = {0xee, 0xee};
- mBC->set("ab", 2, "cd", 2);
- mBC->set("ef", 2, "gh", 2);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("ab", 2, "cd", 2));
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("ef", 2, "gh", 2));
ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
ASSERT_EQ('c', buf[0]);
ASSERT_EQ('d', buf[1]);
@@ -71,7 +71,7 @@
TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
unsigned char buf[6] = {0xee, 0xee, 0xee, 0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf + 1, 4));
ASSERT_EQ(0xee, buf[0]);
ASSERT_EQ('e', buf[1]);
@@ -83,7 +83,7 @@
TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
unsigned char buf[3] = {0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
ASSERT_EQ(0xee, buf[0]);
ASSERT_EQ(0xee, buf[1]);
@@ -91,14 +91,14 @@
}
TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
- mBC->set("abcd", 4, "efgh", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, nullptr, 0));
}
TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
unsigned char buf[4] = {0xee, 0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
- mBC->set("abcd", 4, "ijkl", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "ijkl", 4));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
ASSERT_EQ('i', buf[0]);
ASSERT_EQ('j', buf[1]);
@@ -108,8 +108,8 @@
TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
unsigned char buf[MAX_VALUE_SIZE + 1] = {0xee, 0xee, 0xee, 0xee};
- mBC->set("abcd", 4, "efgh", 4);
- mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, "efgh", 4));
+ ASSERT_EQ(BlobCache::InsertResult::kValueTooBig, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1));
ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
ASSERT_EQ('e', buf[0]);
ASSERT_EQ('f', buf[1]);
@@ -123,7 +123,7 @@
for (int i = 0; i < MAX_KEY_SIZE + 1; i++) {
key[i] = 'a';
}
- mBC->set(key, MAX_KEY_SIZE + 1, "bbbb", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kKeyTooBig, mBC->set(key, MAX_KEY_SIZE + 1, "bbbb", 4));
ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE + 1, buf, 4));
ASSERT_EQ(0xee, buf[0]);
ASSERT_EQ(0xee, buf[1]);
@@ -136,7 +136,7 @@
for (int i = 0; i < MAX_VALUE_SIZE + 1; i++) {
buf[i] = 'b';
}
- mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1);
+ ASSERT_EQ(BlobCache::InsertResult::kValueTooBig, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE + 1));
for (int i = 0; i < MAX_VALUE_SIZE + 1; i++) {
buf[i] = 0xee;
}
@@ -163,7 +163,8 @@
buf[i] = 'b';
}
- mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE);
+ ASSERT_EQ(BlobCache::InsertResult::kCombinedTooBig,
+ mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE));
ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
}
@@ -173,7 +174,7 @@
for (int i = 0; i < MAX_KEY_SIZE; i++) {
key[i] = 'a';
}
- mBC->set(key, MAX_KEY_SIZE, "wxyz", 4);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(key, MAX_KEY_SIZE, "wxyz", 4));
ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4));
ASSERT_EQ('w', buf[0]);
ASSERT_EQ('x', buf[1]);
@@ -186,7 +187,7 @@
for (int i = 0; i < MAX_VALUE_SIZE; i++) {
buf[i] = 'b';
}
- mBC->set("abcd", 4, buf, MAX_VALUE_SIZE);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("abcd", 4, buf, MAX_VALUE_SIZE));
for (int i = 0; i < MAX_VALUE_SIZE; i++) {
buf[i] = 0xee;
}
@@ -212,13 +213,45 @@
buf[i] = 'b';
}
- mBC->set(key, MAX_KEY_SIZE, buf, bufSize);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(key, MAX_KEY_SIZE, buf, bufSize));
ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
}
+// Verify that kNotEnoughSpace is returned from BlobCache::set when expected.
+// Note: This relies on internal knowledge of how BlobCache works.
+TEST_F(BlobCacheTest, NotEnoughSpace) {
+ // Insert a small entry into the cache.
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("x", 1, "y", 1));
+
+ // Attempt to put a max size entry into the cache. If the cache were empty,
+ // as in CacheMaxKeyValuePairSizeSucceeds, this would succeed. Based on the
+ // current logic of BlobCache, the small entry is not big enough to allow it
+ // to be cleaned to insert the new entry.
+ ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+ enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE };
+
+ char key[MAX_KEY_SIZE];
+ char buf[bufSize];
+ for (int i = 0; i < MAX_KEY_SIZE; i++) {
+ key[i] = 'a';
+ }
+ for (int i = 0; i < bufSize; i++) {
+ buf[i] = 'b';
+ }
+
+ ASSERT_EQ(BlobCache::InsertResult::kNotEnoughSpace, mBC->set(key, MAX_KEY_SIZE, buf, bufSize));
+ ASSERT_EQ(0, mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
+
+ // The original entry remains in the cache.
+ unsigned char buf2[1] = {0xee};
+ ASSERT_EQ(size_t(1), mBC->get("x", 1, buf2, 1));
+ ASSERT_EQ('y', buf2[0]);
+}
+
TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
unsigned char buf[1] = {0xee};
- mBC->set("x", 1, "y", 1);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set("x", 1, "y", 1));
ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
ASSERT_EQ('y', buf[0]);
}
@@ -243,12 +276,12 @@
const int maxEntries = MAX_TOTAL_SIZE / 2;
for (int i = 0; i < maxEntries; i++) {
uint8_t k = i;
- mBC->set(&k, 1, "x", 1);
+ ASSERT_EQ(BlobCache::InsertResult::kInserted, mBC->set(&k, 1, "x", 1));
}
// Insert one more entry, causing a cache overflow.
{
uint8_t k = maxEntries;
- mBC->set(&k, 1, "x", 1);
+ ASSERT_EQ(BlobCache::InsertResult::kDidClean, mBC->set(&k, 1, "x", 1));
}
// Count the number of entries in the cache.
int numCached = 0;
@@ -261,6 +294,14 @@
ASSERT_EQ(maxEntries / 2 + 1, numCached);
}
+TEST_F(BlobCacheTest, InvalidKeySize) {
+ ASSERT_EQ(BlobCache::InsertResult::kInvalidKeySize, mBC->set("", 0, "efgh", 4));
+}
+
+TEST_F(BlobCacheTest, InvalidValueSize) {
+ ASSERT_EQ(BlobCache::InsertResult::kInvalidValueSize, mBC->set("abcd", 4, "", 0));
+}
+
class BlobCacheFlattenTest : public BlobCacheTest {
protected:
virtual void SetUp() {
diff --git a/services/inputflinger/dispatcher/DragState.h b/services/inputflinger/dispatcher/DragState.h
index 4636820..d1c8b8a 100644
--- a/services/inputflinger/dispatcher/DragState.h
+++ b/services/inputflinger/dispatcher/DragState.h
@@ -26,7 +26,8 @@
namespace inputdispatcher {
struct DragState {
- DragState(const sp<android::gui::WindowInfoHandle>& windowHandle) : dragWindow(windowHandle) {}
+ DragState(const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t pointerId)
+ : dragWindow(windowHandle), pointerId(pointerId) {}
void dump(std::string& dump, const char* prefix = "");
// The window being dragged.
@@ -37,6 +38,8 @@
bool isStartDrag = false;
// Indicate if the stylus button is down at the start of the drag.
bool isStylusButtonDownAtStart = false;
+ // Indicate which pointer id is tracked by the drag and drop.
+ const int32_t pointerId;
};
} // namespace inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 5d8df5f..7852b30 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1747,18 +1747,12 @@
}
void InputDispatcher::enqueueDragEventLocked(const sp<WindowInfoHandle>& windowHandle,
- bool isExiting, const MotionEntry& motionEntry) {
- // If the window needs enqueue a drag event, the pointerCount should be 1 and the action should
- // be AMOTION_EVENT_ACTION_MOVE, that could guarantee the first pointer is always valid.
- LOG_ALWAYS_FATAL_IF(motionEntry.pointerCount != 1);
- PointerCoords pointerCoords;
- pointerCoords.copyFrom(motionEntry.pointerCoords[0]);
- pointerCoords.transform(windowHandle->getInfo()->transform);
-
+ bool isExiting, const int32_t rawX,
+ const int32_t rawY) {
+ const vec2 xy = windowHandle->getInfo()->transform.transform(vec2(rawX, rawY));
std::unique_ptr<DragEntry> dragEntry =
- std::make_unique<DragEntry>(mIdGenerator.nextId(), motionEntry.eventTime,
- windowHandle->getToken(), isExiting, pointerCoords.getX(),
- pointerCoords.getY());
+ std::make_unique<DragEntry>(mIdGenerator.nextId(), now(), windowHandle->getToken(),
+ isExiting, xy.x, xy.y);
enqueueInboundEventLocked(std::move(dragEntry));
}
@@ -2546,13 +2540,14 @@
vec2 local = dropWindow->getInfo()->transform.transform(x, y);
sendDropWindowCommandLocked(dropWindow->getToken(), local.x, local.y);
} else {
+ ALOGW("No window found when drop.");
sendDropWindowCommandLocked(nullptr, 0, 0);
}
mDragState.reset();
}
void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
- if (entry.pointerCount != 1 || !mDragState) {
+ if (!mDragState) {
return;
}
@@ -2562,42 +2557,75 @@
(entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
}
- int32_t maskedAction = entry.action & AMOTION_EVENT_ACTION_MASK;
- int32_t x = static_cast<int32_t>(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = static_cast<int32_t>(entry.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
- if (maskedAction == AMOTION_EVENT_ACTION_MOVE) {
- // Handle the special case : stylus button no longer pressed.
- bool isStylusButtonDown = (entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
- if (mDragState->isStylusButtonDownAtStart && !isStylusButtonDown) {
- finishDragAndDrop(entry.displayId, x, y);
- return;
+ // Find the pointer index by id.
+ int32_t pointerIndex = 0;
+ for (; static_cast<uint32_t>(pointerIndex) < entry.pointerCount; pointerIndex++) {
+ const PointerProperties& pointerProperties = entry.pointerProperties[pointerIndex];
+ if (pointerProperties.id == mDragState->pointerId) {
+ break;
}
+ }
- // Prevent stylus interceptor windows from affecting drag and drop behavior for now, until
- // we have an explicit reason to support it.
- constexpr bool isStylus = false;
-
- const sp<WindowInfoHandle> hoverWindowHandle =
- findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/, isStylus,
- false /*addOutsideTargets*/, true /*ignoreDragWindow*/);
- // enqueue drag exit if needed.
- if (hoverWindowHandle != mDragState->dragHoverWindowHandle &&
- !haveSameToken(hoverWindowHandle, mDragState->dragHoverWindowHandle)) {
- if (mDragState->dragHoverWindowHandle != nullptr) {
- enqueueDragEventLocked(mDragState->dragHoverWindowHandle, true /*isExiting*/,
- entry);
- }
- mDragState->dragHoverWindowHandle = hoverWindowHandle;
- }
- // enqueue drag location if needed.
- if (hoverWindowHandle != nullptr) {
- enqueueDragEventLocked(hoverWindowHandle, false /*isExiting*/, entry);
- }
- } else if (maskedAction == AMOTION_EVENT_ACTION_UP) {
- finishDragAndDrop(entry.displayId, x, y);
- } else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
+ if (uint32_t(pointerIndex) == entry.pointerCount) {
+ LOG_ALWAYS_FATAL("Should find a valid pointer index by id %d", mDragState->pointerId);
sendDropWindowCommandLocked(nullptr, 0, 0);
mDragState.reset();
+ return;
+ }
+
+ const int32_t maskedAction = entry.action & AMOTION_EVENT_ACTION_MASK;
+ const int32_t x = entry.pointerCoords[pointerIndex].getX();
+ const int32_t y = entry.pointerCoords[pointerIndex].getY();
+
+ switch (maskedAction) {
+ case AMOTION_EVENT_ACTION_MOVE: {
+ // Handle the special case : stylus button no longer pressed.
+ bool isStylusButtonDown =
+ (entry.buttonState & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY) != 0;
+ if (mDragState->isStylusButtonDownAtStart && !isStylusButtonDown) {
+ finishDragAndDrop(entry.displayId, x, y);
+ return;
+ }
+
+ // Prevent stylus interceptor windows from affecting drag and drop behavior for now,
+ // until we have an explicit reason to support it.
+ constexpr bool isStylus = false;
+
+ const sp<WindowInfoHandle> hoverWindowHandle =
+ findTouchedWindowAtLocked(entry.displayId, x, y, nullptr /*touchState*/,
+ isStylus, false /*addOutsideTargets*/,
+ true /*ignoreDragWindow*/);
+ // enqueue drag exit if needed.
+ if (hoverWindowHandle != mDragState->dragHoverWindowHandle &&
+ !haveSameToken(hoverWindowHandle, mDragState->dragHoverWindowHandle)) {
+ if (mDragState->dragHoverWindowHandle != nullptr) {
+ enqueueDragEventLocked(mDragState->dragHoverWindowHandle, true /*isExiting*/, x,
+ y);
+ }
+ mDragState->dragHoverWindowHandle = hoverWindowHandle;
+ }
+ // enqueue drag location if needed.
+ if (hoverWindowHandle != nullptr) {
+ enqueueDragEventLocked(hoverWindowHandle, false /*isExiting*/, x, y);
+ }
+ break;
+ }
+
+ case AMOTION_EVENT_ACTION_POINTER_UP:
+ if (getMotionEventActionPointerIndex(entry.action) != pointerIndex) {
+ break;
+ }
+ // The drag pointer is up.
+ [[fallthrough]];
+ case AMOTION_EVENT_ACTION_UP:
+ finishDragAndDrop(entry.displayId, x, y);
+ break;
+ case AMOTION_EVENT_ACTION_CANCEL: {
+ ALOGD("Receiving cancel when drag and drop.");
+ sendDropWindowCommandLocked(nullptr, 0, 0);
+ mDragState.reset();
+ break;
+ }
}
}
@@ -5117,7 +5145,15 @@
// Store the dragging window.
if (isDragDrop) {
- mDragState = std::make_unique<DragState>(toWindowHandle);
+ if (pointerIds.count() > 1) {
+ ALOGW("The drag and drop cannot be started when there is more than 1 pointer on the"
+ " window.");
+ return false;
+ }
+ // If the window didn't not support split or the source is mouse, the pointerIds count
+ // would be 0, so we have to track the pointer 0.
+ const int32_t id = pointerIds.count() == 0 ? 0 : pointerIds.firstMarkedBit();
+ mDragState = std::make_unique<DragState>(toWindowHandle, id);
}
// Synthesize cancel for old window and down for new window.
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index f3dac19..34aed3b 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -221,7 +221,8 @@
const std::string& reason) REQUIRES(mLock);
// Enqueues a drag event.
void enqueueDragEventLocked(const sp<android::gui::WindowInfoHandle>& windowToken,
- bool isExiting, const MotionEntry& motionEntry) REQUIRES(mLock);
+ bool isExiting, const int32_t rawX, const int32_t rawY)
+ REQUIRES(mLock);
// Adds an event to a queue of recent events for debugging purposes.
void addRecentEventLocked(std::shared_ptr<EventEntry> entry) REQUIRES(mLock);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index b688898..61e5fe3 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -6110,8 +6110,7 @@
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
}
- // Start performing drag, we will create a drag window and transfer touch to it.
- void performDrag() {
+ void injectDown() {
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
{50, 50}))
@@ -6119,6 +6118,15 @@
// Window should receive motion event.
mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ }
+
+ // Start performing drag, we will create a drag window and transfer touch to it.
+ // @param sendDown : if true, send a motion down on first window before perform drag and drop.
+ // Returns true on success.
+ bool performDrag(bool sendDown = true) {
+ if (sendDown) {
+ injectDown();
+ }
// The drag window covers the entire display
mDragWindow = new FakeWindowHandle(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT);
@@ -6126,10 +6134,14 @@
{{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}});
// Transfer touch focus to the drag window
- mDispatcher->transferTouchFocus(mWindow->getToken(), mDragWindow->getToken(),
- true /* isDragDrop */);
- mWindow->consumeMotionCancel();
- mDragWindow->consumeMotionDown();
+ bool transferred =
+ mDispatcher->transferTouchFocus(mWindow->getToken(), mDragWindow->getToken(),
+ true /* isDragDrop */);
+ if (transferred) {
+ mWindow->consumeMotionCancel();
+ mDragWindow->consumeMotionDown();
+ }
+ return transferred;
}
// Start performing drag, we will create a drag window and transfer touch to it.
@@ -6276,7 +6288,7 @@
mSecondWindow->assertNoEvents();
}
-TEST_F(InputDispatcherDragTests, DragAndDrop_InvalidWindow) {
+TEST_F(InputDispatcherDragTests, DragAndDropOnInvalidWindow) {
performDrag();
// Set second window invisible.
@@ -6312,6 +6324,89 @@
mSecondWindow->assertNoEvents();
}
+TEST_F(InputDispatcherDragTests, NoDragAndDropWhenMultiFingers) {
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {50, 50}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ 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(75).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ mWindow->consumeMotionPointerDown(1 /* pointerIndex */);
+
+ // Should not perform drag and drop when window has multi fingers.
+ ASSERT_FALSE(performDrag(false));
+}
+
+TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouch) {
+ // First 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";
+
+ mSecondWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ // Second down on first window.
+ 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(150).y(50))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_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";
+ mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ // Perform drag and drop from first window.
+ ASSERT_TRUE(performDrag(false));
+
+ // Move on window.
+ 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))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerMoveEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT));
+ mDragWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT);
+ mWindow->consumeDragEvent(false, 50, 50);
+ mSecondWindow->consumeMotionMove();
+
+ // Release the drag pointer should perform drop.
+ 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))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT));
+ mDragWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT);
+ mFakePolicy->assertDropTargetEquals(mWindow->getToken());
+ mWindow->assertNoEvents();
+ mSecondWindow->consumeMotionMove();
+}
+
class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp
index 14f9a12..94de55c 100644
--- a/services/sensorservice/BatteryService.cpp
+++ b/services/sensorservice/BatteryService.cpp
@@ -74,23 +74,6 @@
}
}
-void BatteryService::cleanupImpl(uid_t uid) {
- if (checkService()) {
- Mutex::Autolock _l(mActivationsLock);
- int64_t identity = IPCThreadState::self()->clearCallingIdentity();
- for (size_t i=0 ; i<mActivations.size() ; ) {
- const Info& info(mActivations[i]);
- if (info.uid == uid) {
- mBatteryStatService->noteStopSensor(info.uid, info.handle);
- mActivations.removeAt(i);
- } else {
- i++;
- }
- }
- IPCThreadState::self()->restoreCallingIdentity(identity);
- }
-}
-
bool BatteryService::checkService() {
if (mBatteryStatService == nullptr) {
const sp<IServiceManager> sm(defaultServiceManager());
diff --git a/services/sensorservice/BatteryService.h b/services/sensorservice/BatteryService.h
index 09eb2c1..13fc58a 100644
--- a/services/sensorservice/BatteryService.h
+++ b/services/sensorservice/BatteryService.h
@@ -32,7 +32,6 @@
void enableSensorImpl(uid_t uid, int handle);
void disableSensorImpl(uid_t uid, int handle);
- void cleanupImpl(uid_t uid);
struct Info {
uid_t uid;
@@ -58,9 +57,6 @@
static void disableSensor(uid_t uid, int handle) {
BatteryService::getInstance().disableSensorImpl(uid, handle);
}
- static void cleanup(uid_t uid) {
- BatteryService::getInstance().cleanupImpl(uid);
- }
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 53a3025..de050e0 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -612,8 +612,10 @@
return SENSORS_DEVICE_API_VERSION_1_4;
}
-status_t SensorDevice::flush(void* /*ident*/, int handle) {
+status_t SensorDevice::flush(void* ident, int handle) {
if (mHalWrapper == nullptr) return NO_INIT;
+ if (isClientDisabled(ident)) return INVALID_OPERATION;
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
return mHalWrapper->flush(handle);
}
@@ -754,6 +756,13 @@
status_t SensorDevice::injectSensorData(const sensors_event_t* injected_sensor_event) {
if (mHalWrapper == nullptr) return NO_INIT;
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
+ injected_sensor_event->sensor, injected_sensor_event->timestamp,
+ injected_sensor_event->data[0], injected_sensor_event->data[1],
+ injected_sensor_event->data[2], injected_sensor_event->data[3],
+ injected_sensor_event->data[4], injected_sensor_event->data[5]);
+
return mHalWrapper->injectSensorData(injected_sensor_event);
}
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 8b81d48..88cf5ab 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1611,7 +1611,9 @@
} else {
ALOGE("sensor interface of handle=0x%08x is null!", handle);
}
- c->removeSensor(handle);
+ if (c->removeSensor(handle)) {
+ BatteryService::disableSensor(c->getUid(), handle);
+ }
}
SensorRecord* rec = mActiveSensors.valueAt(i);
ALOGE_IF(!rec, "mActiveSensors[%zu] is null (handle=0x%08x)!", i, handle);
@@ -1631,7 +1633,6 @@
}
c->updateLooperRegistration(mLooper);
mConnectionHolder.removeEventConnection(connection);
- BatteryService::cleanup(c->getUid());
if (c->needsWakeLock()) {
checkWakeLockStateLocked(&connLock);
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 3a3c91e..862ab1d 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3368,7 +3368,6 @@
static constexpr float kDefaultMaxLuminance = 0.9f;
static constexpr float kDefaultAvgLuminance = 0.7f;
static constexpr float kDefaultMinLuminance = 0.1f;
- static constexpr float kUnknownLuminance = -1.f;
static constexpr float kDisplayLuminance = 400.f;
static constexpr float kClientTargetLuminanceNits = 200.f;
static constexpr float kClientTargetBrightness = 0.5f;
@@ -3766,7 +3765,7 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrMixedComposition) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3775,7 +3774,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
@@ -3820,7 +3819,7 @@
forHdrMixedCompositionWithDimmingStage) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(
aidl::android::hardware::graphics::composer3::DimmingStage::GAMMA_OETF)
.withRenderIntent(
@@ -3830,7 +3829,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
@@ -3848,7 +3847,7 @@
forHdrMixedCompositionWithRenderIntent) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(aidl::android::hardware::graphics::composer3::RenderIntent::ENHANCE)
.andIfSkipColorTransform(false)
@@ -3856,7 +3855,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
@@ -3873,7 +3872,7 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrMixedComposition) {
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(false)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3882,7 +3881,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
@@ -3899,7 +3898,7 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forHdrOnlyClientComposition) {
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3908,7 +3907,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = false,
@@ -3925,7 +3924,7 @@
TEST_F(OutputComposeSurfacesTest_UsesExpectedDisplaySettings, forNonHdrOnlyClientComposition) {
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(false)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3934,7 +3933,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = false,
@@ -3952,7 +3951,7 @@
usesExpectedDisplaySettingsForHdrOnlyClientCompositionWithSkipClientTransform) {
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
- .withDisplayBrightnessNits(kUnknownLuminance)
+ .withDisplayBrightnessNits(kDisplayLuminance)
.withDimmingStage(aidl::android::hardware::graphics::composer3::DimmingStage::LINEAR)
.withRenderIntent(
aidl::android::hardware::graphics::composer3::RenderIntent::COLORIMETRIC)
@@ -3961,7 +3960,7 @@
{.physicalDisplay = kDefaultOutputDestinationClip,
.clip = kDefaultOutputViewport,
.maxLuminance = kDefaultMaxLuminance,
- .currentLuminanceNits = kDefaultMaxLuminance,
+ .currentLuminanceNits = kDisplayLuminance,
.outputDataspace = kDefaultOutputDataspace,
.colorTransform = kDefaultColorTransformMat,
.deviceHandlesColorTransform = true,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e72e21c..e6b64c1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3721,12 +3721,13 @@
auto& transaction = transactionQueue.front();
const auto ready =
- transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
- transaction.isAutoTimestamp,
- transaction.desiredPresentTime,
- transaction.originUid, transaction.states,
- bufferLayersReadyToPresent, transactions.size(),
- tryApplyUnsignaled);
+ transactionIsReadyToBeApplied(transaction,
+ transaction.frameTimelineInfo,
+ transaction.isAutoTimestamp,
+ transaction.desiredPresentTime,
+ transaction.originUid, transaction.states,
+ bufferLayersReadyToPresent, transactions.size(),
+ tryApplyUnsignaled);
ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
if (ready == TransactionReadiness::NotReady) {
setTransactionFlags(eTransactionFlushNeeded);
@@ -3803,7 +3804,7 @@
return TransactionReadiness::NotReady;
}
- return transactionIsReadyToBeApplied(transaction.frameTimelineInfo,
+ return transactionIsReadyToBeApplied(transaction, transaction.frameTimelineInfo,
transaction.isAutoTimestamp,
transaction.desiredPresentTime,
transaction.originUid, transaction.states,
@@ -3965,7 +3966,7 @@
return true;
}
-auto SurfaceFlinger::transactionIsReadyToBeApplied(
+auto SurfaceFlinger::transactionIsReadyToBeApplied(TransactionState& transaction,
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
uid_t originUid, const Vector<ComposerState>& states,
const std::unordered_map<
@@ -3994,8 +3995,10 @@
}
bool fenceUnsignaled = false;
+ auto queueProcessTime = systemTime();
for (const ComposerState& state : states) {
const layer_state_t& s = state.state;
+
sp<Layer> layer = nullptr;
if (s.surface) {
layer = fromHandle(s.surface).promote();
@@ -4031,6 +4034,15 @@
s.bufferData->acquireFence->getStatus() == Fence::Status::Unsignaled);
if (fenceUnsignaled && !allowLatchUnsignaled) {
+ if (!transaction.sentFenceTimeoutWarning &&
+ queueProcessTime - transaction.queueTime > std::chrono::nanoseconds(4s).count()) {
+ transaction.sentFenceTimeoutWarning = true;
+ auto listener = s.bufferData->releaseBufferListener;
+ if (listener) {
+ listener->onTransactionQueueStalled();
+ }
+ }
+
ATRACE_NAME("fence unsignaled");
return TransactionReadiness::NotReady;
}
@@ -4050,6 +4062,8 @@
}
void SurfaceFlinger::queueTransaction(TransactionState& state) {
+ state.queueTime = systemTime();
+
Mutex::Autolock lock(mQueueLock);
// Generate a CountDownLatch pending state if this is a synchronous transaction.
@@ -6789,7 +6803,7 @@
BlurSetting::Disabled
: compositionengine::LayerFE::ClientCompositionTargetSettings::
BlurSetting::Enabled,
- isHdrDataspace(dataspace) ? displayBrightnessNits : sdrWhitePointNits,
+ isHdrLayer(layer) ? displayBrightnessNits : sdrWhitePointNits,
};
std::vector<compositionengine::LayerFE::LayerSettings> results =
@@ -6804,7 +6818,7 @@
if (regionSampling) {
settings.backgroundBlurRadius = 0;
}
- captureResults.capturedHdrLayers |= isHdrDataspace(settings.sourceDataspace);
+ captureResults.capturedHdrLayers |= isHdrLayer(layer);
}
clientCompositionLayers.insert(clientCompositionLayers.end(),
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c70e174..fc27b62 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -809,7 +809,7 @@
Ready,
ReadyUnsignaled,
};
- TransactionReadiness transactionIsReadyToBeApplied(
+ TransactionReadiness transactionIsReadyToBeApplied(TransactionState& state,
const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime,
uid_t originUid, const Vector<ComposerState>& states,
const std::unordered_map<
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index bab5326..900d566 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -98,6 +98,8 @@
int originUid;
uint64_t id;
std::shared_ptr<CountDownLatch> transactionCommittedSignal;
+ int64_t queueTime = 0;
+ bool sentFenceTimeoutWarning = false;
};
class CountDownLatch {