Merge "TransactionCallbackInvoker: Send callbacks on thread"
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 235990a..5fe4ea1 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -185,6 +185,12 @@
}
prebuilt_etc {
+ name: "android.hardware.wifi.passpoint.prebuilt.xml",
+ src: "android.hardware.wifi.passpoint.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.software.device_id_attestation.prebuilt.xml",
src: "android.software.device_id_attestation.xml",
defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 89a31c5..bb1b513 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -303,6 +303,14 @@
"aidl/android/content/pm/ApexStagedEvent.aidl",
"aidl/android/content/pm/StagedApexInfo.aidl",
],
+ backend: {
+ rust: {
+ apex_available: [
+ "com.android.virt",
+ ],
+ enabled: true,
+ },
+ },
}
aidl_interface {
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 4465b8e..37f6c7f 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -61,7 +61,7 @@
LOG_RPC_DETAIL("RpcSession destroyed %p", this);
std::lock_guard<std::mutex> _l(mMutex);
- LOG_ALWAYS_FATAL_IF(mThreadState.mIncomingConnections.size() != 0,
+ LOG_ALWAYS_FATAL_IF(mConnections.mIncoming.size() != 0,
"Should not be able to destroy a session with servers in use.");
}
@@ -78,12 +78,10 @@
void RpcSession::setMaxThreads(size_t threads) {
std::lock_guard<std::mutex> _l(mMutex);
- LOG_ALWAYS_FATAL_IF(!mThreadState.mOutgoingConnections.empty() ||
- !mThreadState.mIncomingConnections.empty(),
+ LOG_ALWAYS_FATAL_IF(!mConnections.mOutgoing.empty() || !mConnections.mIncoming.empty(),
"Must set max threads before setting up connections, but has %zu client(s) "
"and %zu server(s)",
- mThreadState.mOutgoingConnections.size(),
- mThreadState.mIncomingConnections.size());
+ mConnections.mOutgoing.size(), mConnections.mIncoming.size());
mMaxThreads = threads;
}
@@ -197,7 +195,7 @@
LOG_ALWAYS_FATAL_IF(mShutdownListener == nullptr, "Shutdown listener not installed");
mShutdownListener->waitForShutdown(_l, sp<RpcSession>::fromExisting(this));
- LOG_ALWAYS_FATAL_IF(!mThreadState.mThreads.empty(), "Shutdown failed");
+ LOG_ALWAYS_FATAL_IF(!mConnections.mThreads.empty(), "Shutdown failed");
}
_l.unlock();
@@ -263,11 +261,11 @@
void RpcSession::WaitForShutdownListener::waitForShutdown(std::unique_lock<std::mutex>& lock,
const sp<RpcSession>& session) {
- while (session->mThreadState.mIncomingConnections.size() > 0) {
+ while (session->mConnections.mIncoming.size() > 0) {
if (std::cv_status::timeout == mCv.wait_for(lock, std::chrono::seconds(1))) {
ALOGE("Waiting for RpcSession to shut down (1s w/o progress): %zu incoming connections "
"still.",
- session->mThreadState.mIncomingConnections.size());
+ session->mConnections.mIncoming.size());
}
}
}
@@ -277,7 +275,7 @@
{
std::lock_guard<std::mutex> _l(mMutex);
- mThreadState.mThreads[thread.get_id()] = std::move(thread);
+ mConnections.mThreads[thread.get_id()] = std::move(thread);
}
}
@@ -380,10 +378,10 @@
sp<RpcSession::EventListener> listener;
{
std::lock_guard<std::mutex> _l(session->mMutex);
- auto it = session->mThreadState.mThreads.find(std::this_thread::get_id());
- LOG_ALWAYS_FATAL_IF(it == session->mThreadState.mThreads.end());
+ auto it = session->mConnections.mThreads.find(std::this_thread::get_id());
+ LOG_ALWAYS_FATAL_IF(it == session->mConnections.mThreads.end());
it->second.detach();
- session->mThreadState.mThreads.erase(it);
+ session->mConnections.mThreads.erase(it);
listener = session->mEventListener.promote();
}
@@ -414,9 +412,9 @@
bool incoming)>& connectAndInit) {
{
std::lock_guard<std::mutex> _l(mMutex);
- LOG_ALWAYS_FATAL_IF(mThreadState.mOutgoingConnections.size() != 0,
+ LOG_ALWAYS_FATAL_IF(mConnections.mOutgoing.size() != 0,
"Must only setup session once, but already has %zu clients",
- mThreadState.mOutgoingConnections.size());
+ mConnections.mOutgoing.size());
}
if (auto status = initShutdownTrigger(); status != OK) return status;
@@ -439,7 +437,7 @@
// downgrade again
mProtocolVersion = oldProtocolVersion;
- mThreadState = {};
+ mConnections = {};
});
if (status_t status = connectAndInit({}, false /*incoming*/); status != OK) return status;
@@ -662,7 +660,7 @@
std::lock_guard<std::mutex> _l(mMutex);
connection->rpcTransport = std::move(rpcTransport);
connection->exclusiveTid = gettid();
- mThreadState.mOutgoingConnections.push_back(connection);
+ mConnections.mOutgoing.push_back(connection);
}
status_t status = OK;
@@ -699,9 +697,9 @@
std::unique_ptr<RpcTransport> rpcTransport) {
std::lock_guard<std::mutex> _l(mMutex);
- if (mThreadState.mIncomingConnections.size() >= mMaxThreads) {
+ if (mConnections.mIncoming.size() >= mMaxThreads) {
ALOGE("Cannot add thread to session with %zu threads (max is set to %zu)",
- mThreadState.mIncomingConnections.size(), mMaxThreads);
+ mConnections.mIncoming.size(), mMaxThreads);
return nullptr;
}
@@ -709,7 +707,7 @@
// happens when new connections are still being established as part of a
// very short-lived session which shuts down after it already started
// accepting new connections.
- if (mThreadState.mIncomingConnections.size() < mThreadState.mMaxIncomingConnections) {
+ if (mConnections.mIncoming.size() < mConnections.mMaxIncoming) {
return nullptr;
}
@@ -717,19 +715,19 @@
session->rpcTransport = std::move(rpcTransport);
session->exclusiveTid = gettid();
- mThreadState.mIncomingConnections.push_back(session);
- mThreadState.mMaxIncomingConnections = mThreadState.mIncomingConnections.size();
+ mConnections.mIncoming.push_back(session);
+ mConnections.mMaxIncoming = mConnections.mIncoming.size();
return session;
}
bool RpcSession::removeIncomingConnection(const sp<RpcConnection>& connection) {
std::unique_lock<std::mutex> _l(mMutex);
- if (auto it = std::find(mThreadState.mIncomingConnections.begin(),
- mThreadState.mIncomingConnections.end(), connection);
- it != mThreadState.mIncomingConnections.end()) {
- mThreadState.mIncomingConnections.erase(it);
- if (mThreadState.mIncomingConnections.size() == 0) {
+ if (auto it =
+ std::find(mConnections.mIncoming.begin(), mConnections.mIncoming.end(), connection);
+ it != mConnections.mIncoming.end()) {
+ mConnections.mIncoming.erase(it);
+ if (mConnections.mIncoming.size() == 0) {
sp<EventListener> listener = mEventListener.promote();
if (listener) {
_l.unlock();
@@ -754,7 +752,7 @@
pid_t tid = gettid();
std::unique_lock<std::mutex> _l(session->mMutex);
- session->mThreadState.mWaitingThreads++;
+ session->mConnections.mWaitingThreads++;
while (true) {
sp<RpcConnection> exclusive;
sp<RpcConnection> available;
@@ -762,11 +760,11 @@
// CHECK FOR DEDICATED CLIENT SOCKET
//
// A server/looper should always use a dedicated connection if available
- findConnection(tid, &exclusive, &available, session->mThreadState.mOutgoingConnections,
- session->mThreadState.mOutgoingConnectionsOffset);
+ findConnection(tid, &exclusive, &available, session->mConnections.mOutgoing,
+ session->mConnections.mOutgoingOffset);
// WARNING: this assumes a server cannot request its client to send
- // a transaction, as mIncomingConnections is excluded below.
+ // a transaction, as mIncoming is excluded below.
//
// Imagine we have more than one thread in play, and a single thread
// sends a synchronous, then an asynchronous command. Imagine the
@@ -776,9 +774,8 @@
// command. So, we move to considering the second available thread
// for subsequent calls.
if (use == ConnectionUse::CLIENT_ASYNC && (exclusive != nullptr || available != nullptr)) {
- session->mThreadState.mOutgoingConnectionsOffset =
- (session->mThreadState.mOutgoingConnectionsOffset + 1) %
- session->mThreadState.mOutgoingConnections.size();
+ session->mConnections.mOutgoingOffset = (session->mConnections.mOutgoingOffset + 1) %
+ session->mConnections.mOutgoing.size();
}
// USE SERVING SOCKET (e.g. nested transaction)
@@ -786,7 +783,7 @@
sp<RpcConnection> exclusiveIncoming;
// server connections are always assigned to a thread
findConnection(tid, &exclusiveIncoming, nullptr /*available*/,
- session->mThreadState.mIncomingConnections, 0 /* index hint */);
+ session->mConnections.mIncoming, 0 /* index hint */);
// asynchronous calls cannot be nested, we currently allow ref count
// calls to be nested (so that you can use this without having extra
@@ -815,20 +812,20 @@
break;
}
- if (session->mThreadState.mOutgoingConnections.size() == 0) {
+ if (session->mConnections.mOutgoing.size() == 0) {
ALOGE("Session has no client connections. This is required for an RPC server to make "
"any non-nested (e.g. oneway or on another thread) calls. Use: %d. Server "
"connections: %zu",
- static_cast<int>(use), session->mThreadState.mIncomingConnections.size());
+ static_cast<int>(use), session->mConnections.mIncoming.size());
return WOULD_BLOCK;
}
LOG_RPC_DETAIL("No available connections (have %zu clients and %zu servers). Waiting...",
- session->mThreadState.mOutgoingConnections.size(),
- session->mThreadState.mIncomingConnections.size());
+ session->mConnections.mOutgoing.size(),
+ session->mConnections.mIncoming.size());
session->mAvailableConnectionCv.wait(_l);
}
- session->mThreadState.mWaitingThreads--;
+ session->mConnections.mWaitingThreads--;
return OK;
}
@@ -867,7 +864,7 @@
if (!mReentrant && mConnection != nullptr) {
std::unique_lock<std::mutex> _l(mSession->mMutex);
mConnection->exclusiveTid = std::nullopt;
- if (mSession->mThreadState.mWaitingThreads > 0) {
+ if (mSession->mConnections.mWaitingThreads > 0) {
_l.unlock();
mSession->mAvailableConnectionCv.notify_one();
}
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index d71f496..7c99f76 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -144,5 +144,5 @@
* Get information of APEX which is staged ready for installation.
* Returns null if no such APEX is found.
*/
- StagedApexInfo getStagedApexInfo(in @utf8InCpp String moduleName);
+ @nullable StagedApexInfo getStagedApexInfo(in @utf8InCpp String moduleName);
}
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 19888b7..0fcee90 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -281,13 +281,13 @@
const std::unique_ptr<RpcTransportCtx> mCtx;
- // On the other side of a session, for each of mOutgoingConnections here, there should
- // be one of mIncomingConnections on the other side (and vice versa).
+ // On the other side of a session, for each of mOutgoing here, there should
+ // be one of mIncoming on the other side (and vice versa).
//
// For the simplest session, a single server with one client, you would
// have:
- // - the server has a single 'mIncomingConnections' and a thread listening on this
- // - the client has a single 'mOutgoingConnections' and makes calls to this
+ // - the server has a single 'mIncoming' and a thread listening on this
+ // - the client has a single 'mOutgoing' and makes calls to this
// - here, when the client makes a call, the server can call back into it
// (nested calls), but outside of this, the client will only ever read
// calls from the server when it makes a call itself.
@@ -315,12 +315,12 @@
struct ThreadState {
size_t mWaitingThreads = 0;
// hint index into clients, ++ when sending an async transaction
- size_t mOutgoingConnectionsOffset = 0;
- std::vector<sp<RpcConnection>> mOutgoingConnections;
- size_t mMaxIncomingConnections = 0;
- std::vector<sp<RpcConnection>> mIncomingConnections;
+ size_t mOutgoingOffset = 0;
+ std::vector<sp<RpcConnection>> mOutgoing;
+ size_t mMaxIncoming = 0;
+ std::vector<sp<RpcConnection>> mIncoming;
std::map<std::thread::id, std::thread> mThreads;
- } mThreadState;
+ } mConnections;
};
} // namespace android
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 680f0ed..86da588 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -87,6 +87,7 @@
srcs: ["binderParcelUnitTest.cpp", "binderBinderUnitTest.cpp"],
shared_libs: [
"libbinder",
+ "libcutils",
"libutils",
],
test_suites: ["general-tests"],
diff --git a/libs/binder/tests/binderParcelUnitTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp
index 841d47b..4950b23 100644
--- a/libs/binder/tests/binderParcelUnitTest.cpp
+++ b/libs/binder/tests/binderParcelUnitTest.cpp
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
+#include <binder/Parcel.h>
+#include <cutils/ashmem.h>
#include <gtest/gtest.h>
using android::IPCThreadState;
@@ -146,3 +147,18 @@
TEST_READ_WRITE_INVERSE(int8_t, Byte, {-1, 0, 1});
TEST_READ_WRITE_INVERSE(String8, String8, {String8(), String8("a"), String8("asdf")});
TEST_READ_WRITE_INVERSE(String16, String16, {String16(), String16("a"), String16("asdf")});
+
+TEST(Parcel, GetOpenAshmemSize) {
+ constexpr size_t kSize = 1024;
+ constexpr size_t kCount = 3;
+
+ Parcel p;
+
+ for (size_t i = 0; i < kCount; i++) {
+ int fd = ashmem_create_region("test-getOpenAshmemSize", kSize);
+ ASSERT_GE(fd, 0);
+ ASSERT_EQ(OK, p.writeFileDescriptor(fd, true /* take ownership */));
+
+ ASSERT_EQ((kSize * (i + 1)), p.getOpenAshmemSize());
+ }
+}
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 2b17616..36de581 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -162,6 +162,7 @@
ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
+ mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
mTransformHint = mSurfaceControl->getTransformHint();
mBufferItemConsumer->setTransformHint(mTransformHint);
@@ -325,31 +326,23 @@
// So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer.
// Otherwise, this is a no-op.
static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, const ReleaseCallbackId& id,
- const sp<Fence>& releaseFence, uint32_t transformHint,
- uint32_t currentMaxAcquiredBufferCount) {
+ const sp<Fence>& releaseFence,
+ std::optional<uint32_t> currentMaxAcquiredBufferCount) {
sp<BLASTBufferQueue> blastBufferQueue = context.promote();
if (blastBufferQueue) {
- blastBufferQueue->releaseBufferCallback(id, releaseFence, transformHint,
- currentMaxAcquiredBufferCount);
+ blastBufferQueue->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount);
} else {
ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str());
}
}
-void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id,
- const sp<Fence>& releaseFence, uint32_t transformHint,
- uint32_t currentMaxAcquiredBufferCount) {
+void BLASTBufferQueue::releaseBufferCallback(
+ const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
+ std::optional<uint32_t> currentMaxAcquiredBufferCount) {
ATRACE_CALL();
std::unique_lock _lock{mMutex};
BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str());
- if (mSurfaceControl != nullptr) {
- mTransformHint = transformHint;
- mSurfaceControl->setTransformHint(transformHint);
- mBufferItemConsumer->setTransformHint(mTransformHint);
- BQA_LOGV("updated mTransformHint=%d", mTransformHint);
- }
-
// Calculate how many buffers we need to hold before we release them back
// to the buffer queue. This will prevent higher latency when we are running
// on a lower refresh rate than the max supported. We only do that for EGL
@@ -359,8 +352,12 @@
return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL;
}();
+ if (currentMaxAcquiredBufferCount) {
+ mCurrentMaxAcquiredBufferCount = *currentMaxAcquiredBufferCount;
+ }
+
const auto numPendingBuffersToHold =
- isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0;
+ isEGL ? std::max(0u, mMaxAcquiredBuffers - mCurrentMaxAcquiredBufferCount) : 0;
mPendingRelease.emplace_back(ReleasedBuffer{id, releaseFence});
// Release all buffers that are beyond the ones that we need to hold
@@ -374,7 +371,7 @@
return;
}
mNumAcquired--;
- BQA_LOGV("released %s", id.to_string().c_str());
+ BQA_LOGV("released %s", releaseBuffer.callbackId.to_string().c_str());
mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence);
mSubmitted.erase(it);
processNextBufferLocked(false /* useNextTransaction */);
@@ -466,8 +463,7 @@
auto releaseBufferCallback =
std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
- std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
- std::placeholders::_4);
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseCallbackId,
releaseBufferCallback);
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 98e8b54..aa7ebc9 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -254,11 +254,10 @@
}
void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence,
- uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) override {
+ uint32_t currentMaxAcquiredBufferCount) override {
callRemoteAsync<decltype(
&ITransactionCompletedListener::onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER,
callbackId, releaseFence,
- transformHint,
currentMaxAcquiredBufferCount);
}
};
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index aca59b6..2713be0 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -214,12 +214,6 @@
mReleaseBufferCallbacks[callbackId] = listener;
}
-void TransactionCompletedListener::removeReleaseBufferCallback(
- const ReleaseCallbackId& callbackId) {
- std::scoped_lock<std::mutex> lock(mMutex);
- mReleaseBufferCallbacks.erase(callbackId);
-}
-
void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie,
sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) {
std::scoped_lock<std::recursive_mutex> lock(mSurfaceStatsListenerMutex);
@@ -343,7 +337,6 @@
surfaceStats.previousReleaseFence
? surfaceStats.previousReleaseFence
: Fence::NO_FENCE,
- surfaceStats.transformHint,
surfaceStats.currentMaxAcquiredBufferCount);
}
}
@@ -389,7 +382,7 @@
}
void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId,
- sp<Fence> releaseFence, uint32_t transformHint,
+ sp<Fence> releaseFence,
uint32_t currentMaxAcquiredBufferCount) {
ReleaseBufferCallback callback;
{
@@ -401,7 +394,11 @@
callbackId.to_string().c_str());
return;
}
- callback(callbackId, releaseFence, transformHint, currentMaxAcquiredBufferCount);
+ std::optional<uint32_t> optionalMaxAcquiredBufferCount =
+ currentMaxAcquiredBufferCount == UINT_MAX
+ ? std::nullopt
+ : std::make_optional<uint32_t>(currentMaxAcquiredBufferCount);
+ callback(callbackId, releaseFence, optionalMaxAcquiredBufferCount);
}
ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked(
@@ -712,11 +709,34 @@
return NO_ERROR;
}
+void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_state_t& state) {
+ if (!(state.what & layer_state_t::eBufferChanged)) {
+ return;
+ }
+
+ auto listener = state.bufferData.releaseBufferListener;
+ sp<Fence> fence =
+ state.bufferData.acquireFence ? state.bufferData.acquireFence : Fence::NO_FENCE;
+ if (state.bufferData.releaseBufferEndpoint ==
+ IInterface::asBinder(TransactionCompletedListener::getIInstance())) {
+ // if the callback is in process, run on a different thread to avoid any lock contigency
+ // issues in the client.
+ SurfaceComposerClient::getDefault()
+ ->mReleaseCallbackThread.addReleaseCallback(state.bufferData.releaseCallbackId,
+ fence);
+ } else {
+ listener->onReleaseBuffer(state.bufferData.releaseCallbackId, fence, UINT_MAX);
+ }
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
for (auto const& [handle, composerState] : other.mComposerStates) {
if (mComposerStates.count(handle) == 0) {
mComposerStates[handle] = composerState;
} else {
+ if (composerState.state.what & layer_state_t::eBufferChanged) {
+ releaseBufferIfOverwriting(mComposerStates[handle].state);
+ }
mComposerStates[handle].state.merge(composerState.state);
}
}
@@ -1296,7 +1316,9 @@
mStatus = BAD_INDEX;
return *this;
}
- removeReleaseBufferCallback(s);
+
+ releaseBufferIfOverwriting(*s);
+
BufferData bufferData;
bufferData.buffer = buffer;
if (frameNumber) {
@@ -1321,15 +1343,6 @@
return *this;
}
-void SurfaceComposerClient::Transaction::removeReleaseBufferCallback(layer_state_t* s) {
- if (!(s->what & layer_state_t::eBufferChanged)) {
- return;
- }
-
- auto listener = TransactionCompletedListener::getInstance();
- listener->removeReleaseBufferCallback(s->bufferData.releaseCallbackId);
-}
-
void SurfaceComposerClient::Transaction::setReleaseBufferCallback(BufferData* bufferData,
const ReleaseCallbackId& id,
ReleaseBufferCallback callback) {
@@ -2210,4 +2223,43 @@
return s->captureLayers(captureArgs, captureListener);
}
+// ---------------------------------------------------------------------------------
+
+void ReleaseCallbackThread::addReleaseCallback(const ReleaseCallbackId callbackId,
+ sp<Fence> releaseFence) {
+ std::scoped_lock<std::mutex> lock(mMutex);
+ if (!mStarted) {
+ mThread = std::thread(&ReleaseCallbackThread::threadMain, this);
+ mStarted = true;
+ }
+
+ mCallbackInfos.emplace(callbackId, std::move(releaseFence));
+ mReleaseCallbackPending.notify_one();
+}
+
+void ReleaseCallbackThread::threadMain() {
+ const auto listener = TransactionCompletedListener::getInstance();
+ std::queue<std::tuple<const ReleaseCallbackId, const sp<Fence>>> callbackInfos;
+ while (true) {
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ callbackInfos = std::move(mCallbackInfos);
+ mCallbackInfos = {};
+ }
+
+ while (!callbackInfos.empty()) {
+ auto [callbackId, releaseFence] = callbackInfos.front();
+ listener->onReleaseBuffer(callbackId, std::move(releaseFence), UINT_MAX);
+ callbackInfos.pop();
+ }
+
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (mCallbackInfos.size() == 0) {
+ mReleaseCallbackPending.wait(lock);
+ }
+ }
+ }
+}
+
} // namespace android
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 1f517f6..49ece6e 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -91,7 +91,7 @@
void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
const std::vector<SurfaceControlStats>& stats);
void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
- uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount);
+ std::optional<uint32_t> currentMaxAcquiredBufferCount);
void setNextTransaction(SurfaceComposerClient::Transaction *t);
void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
void applyPendingTransactions(uint64_t frameNumber);
@@ -236,6 +236,8 @@
// Keep track of SurfaceControls that have submitted a transaction and BBQ is waiting on a
// callback for them.
std::queue<sp<SurfaceControl>> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex);
+
+ uint32_t mCurrentMaxAcquiredBufferCount;
};
} // namespace android
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 937095c..0df5822 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -192,7 +192,6 @@
virtual void onTransactionCompleted(ListenerStats stats) = 0;
virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence,
- uint32_t transformHint,
uint32_t currentMaxAcquiredBufferCount) = 0;
};
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 82249a3..e62c76e 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <set>
+#include <thread>
#include <unordered_map>
#include <unordered_set>
@@ -84,7 +85,7 @@
const std::vector<SurfaceControlStats>& /*stats*/)>;
using ReleaseBufferCallback =
std::function<void(const ReleaseCallbackId&, const sp<Fence>& /*releaseFence*/,
- uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount)>;
+ std::optional<uint32_t> currentMaxAcquiredBufferCount)>;
using SurfaceStatsCallback =
std::function<void(void* /*context*/, nsecs_t /*latchTime*/,
@@ -93,6 +94,22 @@
// ---------------------------------------------------------------------------
+class ReleaseCallbackThread {
+public:
+ void addReleaseCallback(const ReleaseCallbackId, sp<Fence>);
+ void threadMain();
+
+private:
+ std::thread mThread;
+ std::mutex mMutex;
+ bool mStarted GUARDED_BY(mMutex) = false;
+ std::condition_variable mReleaseCallbackPending;
+ std::queue<std::tuple<const ReleaseCallbackId, const sp<Fence>>> mCallbackInfos
+ GUARDED_BY(mMutex);
+};
+
+// ---------------------------------------------------------------------------
+
class SurfaceComposerClient : public RefBase
{
friend class Composer;
@@ -350,6 +367,7 @@
private:
static std::atomic<uint32_t> idCounter;
int64_t generateId();
+ void releaseBufferIfOverwriting(const layer_state_t& state);
protected:
std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates;
@@ -400,7 +418,6 @@
void cacheBuffers();
void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
void setReleaseBufferCallback(BufferData*, const ReleaseCallbackId&, ReleaseBufferCallback);
- void removeReleaseBufferCallback(layer_state_t*);
public:
Transaction();
@@ -625,6 +642,9 @@
status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
+protected:
+ ReleaseCallbackThread mReleaseCallbackThread;
+
private:
virtual void onFirstRef();
@@ -725,11 +745,10 @@
void removeSurfaceStatsListener(void* context, void* cookie);
void setReleaseBufferCallback(const ReleaseCallbackId&, ReleaseBufferCallback);
- void removeReleaseBufferCallback(const ReleaseCallbackId&);
// BnTransactionCompletedListener overrides
void onTransactionCompleted(ListenerStats stats) override;
- void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence, uint32_t transformHint,
+ void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence,
uint32_t currentMaxAcquiredBufferCount) override;
// For Testing Only
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 75f2385..2db9992 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -133,12 +133,41 @@
int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace) {
static_assert(static_cast<int>(ADATASPACE_UNKNOWN) == static_cast<int>(HAL_DATASPACE_UNKNOWN));
- static_assert(static_cast<int>(ADATASPACE_SCRGB_LINEAR) == static_cast<int>(HAL_DATASPACE_V0_SCRGB_LINEAR));
+ static_assert(static_cast<int>(STANDARD_SHIFT) == static_cast<int>(HAL_DATASPACE_STANDARD_SHIFT));
+ static_assert(static_cast<int>(STANDARD_MASK) == static_cast<int>(HAL_DATASPACE_STANDARD_MASK));
+ static_assert(static_cast<int>(STANDARD_UNSPECIFIED) == static_cast<int>(HAL_DATASPACE_STANDARD_UNSPECIFIED));
+ static_assert(static_cast<int>(STANDARD_BT709) == static_cast<int>(HAL_DATASPACE_STANDARD_BT709));
+ static_assert(static_cast<int>(STANDARD_BT601_625) == static_cast<int>(HAL_DATASPACE_STANDARD_BT601_625));
+ static_assert(static_cast<int>(STANDARD_BT601_625_UNADJUSTED) == static_cast<int>(HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED));
+ static_assert(static_cast<int>(STANDARD_BT601_525) == static_cast<int>(HAL_DATASPACE_STANDARD_BT601_525));
+ static_assert(static_cast<int>(STANDARD_BT601_525_UNADJUSTED) == static_cast<int>(HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED));
+ static_assert(static_cast<int>(STANDARD_BT470M) == static_cast<int>(HAL_DATASPACE_STANDARD_BT470M));
+ static_assert(static_cast<int>(STANDARD_FILM) == static_cast<int>(HAL_DATASPACE_STANDARD_FILM));
+ static_assert(static_cast<int>(STANDARD_DCI_P3) == static_cast<int>(HAL_DATASPACE_STANDARD_DCI_P3));
+ static_assert(static_cast<int>(STANDARD_ADOBE_RGB) == static_cast<int>(HAL_DATASPACE_STANDARD_ADOBE_RGB));
+ static_assert(static_cast<int>(TRANSFER_SHIFT) == static_cast<int>(HAL_DATASPACE_TRANSFER_SHIFT));
+ static_assert(static_cast<int>(TRANSFER_MASK) == static_cast<int>(HAL_DATASPACE_TRANSFER_MASK));
+ static_assert(static_cast<int>(TRANSFER_UNSPECIFIED) == static_cast<int>(HAL_DATASPACE_TRANSFER_UNSPECIFIED));
+ static_assert(static_cast<int>(TRANSFER_LINEAR) == static_cast<int>(HAL_DATASPACE_TRANSFER_LINEAR));
+ static_assert(static_cast<int>(TRANSFER_SMPTE_170M) == static_cast<int>(HAL_DATASPACE_TRANSFER_SMPTE_170M));
+ static_assert(static_cast<int>(TRANSFER_GAMMA2_2) == static_cast<int>(HAL_DATASPACE_TRANSFER_GAMMA2_2));
+ static_assert(static_cast<int>(TRANSFER_GAMMA2_6) == static_cast<int>(HAL_DATASPACE_TRANSFER_GAMMA2_6));
+ static_assert(static_cast<int>(TRANSFER_GAMMA2_8) == static_cast<int>(HAL_DATASPACE_TRANSFER_GAMMA2_8));
+ static_assert(static_cast<int>(TRANSFER_ST2084) == static_cast<int>(HAL_DATASPACE_TRANSFER_ST2084));
+ static_assert(static_cast<int>(TRANSFER_HLG) == static_cast<int>(HAL_DATASPACE_TRANSFER_HLG));
+ static_assert(static_cast<int>(RANGE_MASK) == static_cast<int>(HAL_DATASPACE_RANGE_MASK));
+ static_assert(static_cast<int>(RANGE_UNSPECIFIED) == static_cast<int>(HAL_DATASPACE_RANGE_UNSPECIFIED));
+ static_assert(static_cast<int>(RANGE_FULL) == static_cast<int>(HAL_DATASPACE_RANGE_FULL));
+ static_assert(static_cast<int>(RANGE_LIMITED) == static_cast<int>(HAL_DATASPACE_RANGE_LIMITED));
+ static_assert(static_cast<int>(RANGE_EXTENDED) == static_cast<int>(HAL_DATASPACE_RANGE_EXTENDED));
static_assert(static_cast<int>(ADATASPACE_SRGB) == static_cast<int>(HAL_DATASPACE_V0_SRGB));
static_assert(static_cast<int>(ADATASPACE_SCRGB) == static_cast<int>(HAL_DATASPACE_V0_SCRGB));
static_assert(static_cast<int>(ADATASPACE_DISPLAY_P3) == static_cast<int>(HAL_DATASPACE_DISPLAY_P3));
static_assert(static_cast<int>(ADATASPACE_BT2020_PQ) == static_cast<int>(HAL_DATASPACE_BT2020_PQ));
static_assert(static_cast<int>(ADATASPACE_ADOBE_RGB) == static_cast<int>(HAL_DATASPACE_ADOBE_RGB));
+ static_assert(static_cast<int>(ADATASPACE_JFIF) == static_cast<int>(HAL_DATASPACE_V0_JFIF));
+ static_assert(static_cast<int>(ADATASPACE_BT601_625) == static_cast<int>(HAL_DATASPACE_V0_BT601_625));
+ static_assert(static_cast<int>(ADATASPACE_BT601_525) == static_cast<int>(HAL_DATASPACE_V0_BT601_525));
static_assert(static_cast<int>(ADATASPACE_BT2020) == static_cast<int>(HAL_DATASPACE_BT2020));
static_assert(static_cast<int>(ADATASPACE_BT709) == static_cast<int>(HAL_DATASPACE_V0_BT709));
static_assert(static_cast<int>(ADATASPACE_DCI_P3) == static_cast<int>(HAL_DATASPACE_DCI_P3));
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index e759513..612fb39 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -43,6 +43,346 @@
ADATASPACE_UNKNOWN = 0,
/**
+ * Color-description aspects
+ *
+ * The following aspects define various characteristics of the color
+ * specification. These represent bitfields, so that a data space value
+ * can specify each of them independently.
+ */
+
+ /**
+ * Standard aspect
+ *
+ * Defines the chromaticity coordinates of the source primaries in terms of
+ * the CIE 1931 definition of x and y specified in ISO 11664-1.
+ */
+ STANDARD_SHIFT = 16,
+
+ STANDARD_MASK = 63 << 16, // 63 << STANDARD_SHIFT = 0x3F
+
+ /**
+ * Chromacity coordinates are unknown or are determined by the application.
+ * Implementations shall use the following suggested standards:
+ *
+ * All YCbCr formats: BT709 if size is 720p or larger (since most video
+ * content is letterboxed this corresponds to width is
+ * 1280 or greater, or height is 720 or greater).
+ * BT601_625 if size is smaller than 720p or is JPEG.
+ * All RGB formats: BT709.
+ *
+ * For all other formats standard is undefined, and implementations should use
+ * an appropriate standard for the data represented.
+ */
+ STANDARD_UNSPECIFIED = 0 << 16, // STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.300 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_BT709 = 1 << 16, // 1 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+ * for RGB conversion from the one purely determined by the primaries
+ * to minimize the color shift into RGB space that uses BT.709
+ * primaries.
+ */
+ STANDARD_BT601_625 = 2 << 16, // 2 << STANDARD_SHIFT,
+
+ /**
+ * Primaries: x y
+ * green 0.290 0.600
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_BT601_625_UNADJUSTED = 3 << 16, // 3 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.310 0.595
+ * blue 0.155 0.070
+ * red 0.630 0.340
+ * white (D65) 0.3127 0.3290
+ *
+ * KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+ * for RGB conversion from the one purely determined by the primaries
+ * to minimize the color shift into RGB space that uses BT.709
+ * primaries.
+ */
+ STANDARD_BT601_525 = 4 << 16, // 4 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.310 0.595
+ * blue 0.155 0.070
+ * red 0.630 0.340
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
+ * for RGB conversion (as in SMPTE 240M).
+ */
+ STANDARD_BT601_525_UNADJUSTED = 5 << 16, // 5 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.170 0.797
+ * blue 0.131 0.046
+ * red 0.708 0.292
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_BT2020 = 6 << 16, // 6 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.170 0.797
+ * blue 0.131 0.046
+ * red 0.708 0.292
+ * white (D65) 0.3127 0.3290
+ *
+ * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+ * for RGB conversion using the linear domain.
+ */
+ STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16, // 7 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.21 0.71
+ * blue 0.14 0.08
+ * red 0.67 0.33
+ * white (C) 0.310 0.316
+ *
+ * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_BT470M = 8 << 16, // 8 << STANDARD_SHIFT
+
+ /**
+ * Primaries: x y
+ * green 0.243 0.692
+ * blue 0.145 0.049
+ * red 0.681 0.319
+ * white (C) 0.310 0.316
+ *
+ * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
+ * for RGB conversion.
+ */
+ STANDARD_FILM = 9 << 16, // 9 << STANDARD_SHIFT
+
+ /**
+ * SMPTE EG 432-1 and SMPTE RP 431-2. (DCI-P3)
+ * Primaries: x y
+ * green 0.265 0.690
+ * blue 0.150 0.060
+ * red 0.680 0.320
+ * white (D65) 0.3127 0.3290
+ */
+ STANDARD_DCI_P3 = 10 << 16, // 10 << STANDARD_SHIFT
+
+ /**
+ * Adobe RGB
+ * Primaries: x y
+ * green 0.210 0.710
+ * blue 0.150 0.060
+ * red 0.640 0.330
+ * white (D65) 0.3127 0.3290
+ */
+ STANDARD_ADOBE_RGB = 11 << 16, // 11 << STANDARD_SHIFT
+
+ /**
+ * Transfer aspect
+ *
+ * Transfer characteristics are the opto-electronic transfer characteristic
+ * at the source as a function of linear optical intensity (luminance).
+ *
+ * For digital signals, E corresponds to the recorded value. Normally, the
+ * transfer function is applied in RGB space to each of the R, G and B
+ * components independently. This may result in color shift that can be
+ * minized by applying the transfer function in Lab space only for the L
+ * component. Implementation may apply the transfer function in RGB space
+ * for all pixel formats if desired.
+ */
+ TRANSFER_SHIFT = 22,
+
+ TRANSFER_MASK = 31 << 22, // 31 << TRANSFER_SHIFT = 0x1F
+
+ /**
+ * Transfer characteristics are unknown or are determined by the
+ * application.
+ *
+ * Implementations should use the following transfer functions:
+ *
+ * For YCbCr formats: use TRANSFER_SMPTE_170M
+ * For RGB formats: use TRANSFER_SRGB
+ *
+ * For all other formats transfer function is undefined, and implementations
+ * should use an appropriate standard for the data represented.
+ */
+ TRANSFER_UNSPECIFIED = 0 << 22, // 0 << TRANSFER_SHIFT
+
+ /**
+ * Transfer characteristic curve:
+ * E = L
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_LINEAR = 1 << 22, // 1 << TRANSFER_SHIFT
+
+ /**
+ * Transfer characteristic curve:
+ *
+ * E = 1.055 * L^(1/2.4) - 0.055 for 0.0031308 <= L <= 1
+ * = 12.92 * L for 0 <= L < 0.0031308
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_SRGB = 2 << 22, // 2 << TRANSFER_SHIFT
+
+ /**
+ * BT.601 525, BT.601 625, BT.709, BT.2020
+ *
+ * Transfer characteristic curve:
+ * E = 1.099 * L ^ 0.45 - 0.099 for 0.018 <= L <= 1
+ * = 4.500 * L for 0 <= L < 0.018
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_SMPTE_170M = 3 << 22, // 3 << TRANSFER_SHIFT
+
+ /**
+ * Assumed display gamma 2.2.
+ *
+ * Transfer characteristic curve:
+ * E = L ^ (1/2.2)
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_GAMMA2_2 = 4 << 22, // 4 << TRANSFER_SHIFT
+
+ /**
+ * display gamma 2.6.
+ *
+ * Transfer characteristic curve:
+ * E = L ^ (1/2.6)
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_GAMMA2_6 = 5 << 22, // 5 << TRANSFER_SHIFT
+
+ /**
+ * display gamma 2.8.
+ *
+ * Transfer characteristic curve:
+ * E = L ^ (1/2.8)
+ * L - luminance of image 0 <= L <= 1 for conventional colorimetry
+ * E - corresponding electrical signal
+ */
+ TRANSFER_GAMMA2_8 = 6 << 22, // 6 << TRANSFER_SHIFT
+
+ /**
+ * SMPTE ST 2084 (Dolby Perceptual Quantizer)
+ *
+ * Transfer characteristic curve:
+ * E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
+ * c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
+ * c2 = 32 * 2413 / 4096 = 18.8515625
+ * c3 = 32 * 2392 / 4096 = 18.6875
+ * m = 128 * 2523 / 4096 = 78.84375
+ * n = 0.25 * 2610 / 4096 = 0.1593017578125
+ * L - luminance of image 0 <= L <= 1 for HDR colorimetry.
+ * L = 1 corresponds to 10000 cd/m2
+ * E - corresponding electrical signal
+ */
+ TRANSFER_ST2084 = 7 << 22, // 7 << TRANSFER_SHIFT
+
+ /**
+ * ARIB STD-B67 Hybrid Log Gamma
+ *
+ * Transfer characteristic curve:
+ * E = r * L^0.5 for 0 <= L <= 1
+ * = a * ln(L - b) + c for 1 < L
+ * a = 0.17883277
+ * b = 0.28466892
+ * c = 0.55991073
+ * r = 0.5
+ * L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
+ * to reference white level of 100 cd/m2
+ * E - corresponding electrical signal
+ */
+ TRANSFER_HLG = 8 << 22, // 8 << TRANSFER_SHIFT
+
+ /**
+ * Range aspect
+ *
+ * Defines the range of values corresponding to the unit range of 0-1.
+ * This is defined for YCbCr only, but can be expanded to RGB space.
+ */
+ RANGE_SHIFT = 27,
+
+ RANGE_MASK = 7 << 27, // 7 << RANGE_SHIFT = 0x7
+
+ /**
+ * Range is unknown or are determined by the application. Implementations
+ * shall use the following suggested ranges:
+ *
+ * All YCbCr formats: limited range.
+ * All RGB or RGBA formats (including RAW and Bayer): full range.
+ * All Y formats: full range
+ *
+ * For all other formats range is undefined, and implementations should use
+ * an appropriate range for the data represented.
+ */
+ RANGE_UNSPECIFIED = 0 << 27, // 0 << RANGE_SHIFT = 0x0
+
+ /**
+ * Full range uses all values for Y, Cb and Cr from
+ * 0 to 2^b-1, where b is the bit depth of the color format.
+ */
+ RANGE_FULL = 1 << 27, // 1 << RANGE_SHIFT = 0x8000000
+
+ /**
+ * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
+ * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of
+ * the color format.
+ *
+ * E.g. For 8-bit-depth formats:
+ * Luma (Y) samples should range from 16 to 235, inclusive
+ * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+ *
+ * For 10-bit-depth formats:
+ * Luma (Y) samples should range from 64 to 940, inclusive
+ * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+ */
+ RANGE_LIMITED = 2 << 27, // 2 << RANGE_SHIFT = 0x10000000
+
+ /**
+ * Extended range is used for scRGB. Intended for use with
+ * floating point pixel formats. [0.0 - 1.0] is the standard
+ * sRGB space. Values outside the range 0.0 - 1.0 can encode
+ * color outside the sRGB gamut.
+ * Used to blend / merge multiple dataspaces on a single display.
+ */
+ RANGE_EXTENDED = 3 << 27, // 3 << RANGE_SHIFT = 0x18000000
+
+ /**
* scRGB linear encoding:
*
* The red, green, and blue components are stored in extended sRGB space,
@@ -112,6 +452,33 @@
ADATASPACE_ADOBE_RGB = 151715840, // STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2 | RANGE_FULL
/**
+ * JPEG File Interchange Format (JFIF)
+ *
+ * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
+ *
+ * Use full range, SMPTE 170M transfer and BT.601_625 standard.
+ */
+ ADATASPACE_JFIF = 146931712, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL
+
+ /**
+ * ITU-R Recommendation 601 (BT.601) - 525-line
+ *
+ * Standard-definition television, 525 Lines (NTSC)
+ *
+ * Use limited range, SMPTE 170M transfer and BT.601_525 standard.
+ */
+ ADATASPACE_BT601_625 = 281149440, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+ /**
+ * ITU-R Recommendation 709 (BT.709)
+ *
+ * High-definition television
+ *
+ * Use limited range, SMPTE 170M transfer and BT.709 standard.
+ */
+ ADATASPACE_BT601_525 = 281280512, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+ /**
* ITU-R Recommendation 2020 (BT.2020)
*
* Ultra High-definition television
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 1baa100..25b3005 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -88,6 +88,9 @@
// Log debug messages about input focus tracking.
constexpr bool DEBUG_FOCUS = false;
+// Log debug messages about touch mode event
+constexpr bool DEBUG_TOUCH_MODE = false;
+
// Log debug messages about touch occlusion
// STOPSHIP(b/169067926): Set to false
constexpr bool DEBUG_TOUCH_OCCLUSION = true;
@@ -534,6 +537,23 @@
return transformedXy - transformedOrigin;
}
+// Returns true if the event type passed as argument represents a user activity.
+bool isUserActivityEvent(const EventEntry& eventEntry) {
+ switch (eventEntry.type) {
+ case EventEntry::Type::FOCUS:
+ case EventEntry::Type::POINTER_CAPTURE_CHANGED:
+ case EventEntry::Type::DRAG:
+ case EventEntry::Type::TOUCH_MODE_CHANGED:
+ case EventEntry::Type::SENSOR:
+ case EventEntry::Type::CONFIGURATION_CHANGED:
+ return false;
+ case EventEntry::Type::DEVICE_RESET:
+ case EventEntry::Type::KEY:
+ case EventEntry::Type::MOTION:
+ return true;
+ }
+}
+
} // namespace
// --- InputDispatcher ---
@@ -552,7 +572,7 @@
// mInTouchMode will be initialized by the WindowManager to the default device config.
// To avoid leaking stack in case that call never comes, and for tests,
// initialize it here anyways.
- mInTouchMode(true),
+ mInTouchMode(kDefaultInTouchMode),
mMaximumObscuringOpacityForTouch(1.0f),
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mWindowTokenWithPointerCapture(nullptr),
@@ -1789,9 +1809,9 @@
displayId = motionEntry.displayId;
break;
}
+ case EventEntry::Type::TOUCH_MODE_CHANGED:
case EventEntry::Type::POINTER_CAPTURE_CHANGED:
case EventEntry::Type::FOCUS:
- case EventEntry::Type::TOUCH_MODE_CHANGED:
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET:
case EventEntry::Type::SENSOR:
@@ -2541,24 +2561,9 @@
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
ui::Transform t;
if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
- // Input monitors always get un-rotated display coordinates. We undo the display
- // rotation that is present in the display transform so that display rotation is not
- // applied to these input targets.
- const auto& displayInfo = it->second;
- int32_t width = displayInfo.logicalWidth;
- int32_t height = displayInfo.logicalHeight;
- const auto orientation = displayInfo.transform.getOrientation();
- uint32_t inverseOrientation = orientation;
- if (orientation == ui::Transform::ROT_90) {
- inverseOrientation = ui::Transform::ROT_270;
- std::swap(width, height);
- } else if (orientation == ui::Transform::ROT_270) {
- inverseOrientation = ui::Transform::ROT_90;
- std::swap(width, height);
- }
- target.displayTransform =
- ui::Transform(inverseOrientation, width, height) * displayInfo.transform;
- t = t * target.displayTransform;
+ const auto& displayTransform = it->second.transform;
+ target.displayTransform = displayTransform;
+ t = displayTransform;
}
target.setDefaultPointerTransform(t);
inputTargets.push_back(target);
@@ -2772,11 +2777,8 @@
}
void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) {
- if (eventEntry.type == EventEntry::Type::FOCUS ||
- eventEntry.type == EventEntry::Type::POINTER_CAPTURE_CHANGED ||
- eventEntry.type == EventEntry::Type::DRAG) {
- // Focus or pointer capture changed events are passed to apps, but do not represent user
- // activity.
+ if (!isUserActivityEvent(eventEntry)) {
+ // Not poking user activity if the event type does not represent a user activity
return;
}
int32_t displayId = getTargetDisplayId(eventEntry);
@@ -2812,16 +2814,7 @@
eventType = USER_ACTIVITY_EVENT_BUTTON;
break;
}
- case EventEntry::Type::TOUCH_MODE_CHANGED: {
- break;
- }
-
- case EventEntry::Type::FOCUS:
- case EventEntry::Type::CONFIGURATION_CHANGED:
- case EventEntry::Type::DEVICE_RESET:
- case EventEntry::Type::SENSOR:
- case EventEntry::Type::POINTER_CAPTURE_CHANGED:
- case EventEntry::Type::DRAG: {
+ default: {
LOG_ALWAYS_FATAL("%s events are not user activity",
ftl::enum_string(eventEntry.type).c_str());
break;
@@ -3796,7 +3789,7 @@
ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args->eventTime);
}
- bool needWake;
+ bool needWake = false;
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -3891,7 +3884,7 @@
std::to_string(t.duration().count()).c_str());
}
- bool needWake;
+ bool needWake = false;
{ // acquire lock
mLock.lock();
@@ -3968,7 +3961,7 @@
std::to_string(t.duration().count()).c_str());
}
- bool needWake;
+ bool needWake = false;
{ // acquire lock
mLock.lock();
@@ -4033,7 +4026,7 @@
ftl::enum_string(args->sensorType).c_str());
}
- bool needWake;
+ bool needWake = false;
{ // acquire lock
mLock.lock();
@@ -4083,7 +4076,7 @@
args->deviceId);
}
- bool needWake;
+ bool needWake = false;
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -4103,7 +4096,7 @@
args->request.enable ? "true" : "false");
}
- bool needWake;
+ bool needWake = false;
{ // acquire lock
std::scoped_lock _l(mLock);
auto entry = std::make_unique<PointerCaptureChangedEntry>(args->id, args->eventTime,
@@ -4924,9 +4917,29 @@
}
void InputDispatcher::setInTouchMode(bool inTouchMode) {
- std::scoped_lock lock(mLock);
- mInTouchMode = inTouchMode;
- // TODO(b/193718270): Fire TouchModeEvent here.
+ bool needWake = false;
+ {
+ std::scoped_lock lock(mLock);
+ if (mInTouchMode == inTouchMode) {
+ return;
+ }
+ if (DEBUG_TOUCH_MODE) {
+ ALOGD("Request to change touch mode from %s to %s", toString(mInTouchMode),
+ toString(inTouchMode));
+ // TODO(b/198487159): Also print the current last interacted apps.
+ }
+
+ // TODO(b/198499018): Store touch mode per display.
+ mInTouchMode = inTouchMode;
+
+ // TODO(b/198487159): Enforce that only last interacted apps can change touch mode.
+ auto entry = std::make_unique<TouchModeEntry>(mIdGenerator.nextId(), now(), inTouchMode);
+ needWake = enqueueInboundEventLocked(std::move(entry));
+ } // release lock
+
+ if (needWake) {
+ mLooper->wake();
+ }
}
void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 55ca6c9..8a551cf 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -82,6 +82,8 @@
*/
class InputDispatcher : public android::InputDispatcherInterface {
public:
+ static constexpr bool kDefaultInTouchMode = true;
+
explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
~InputDispatcher() override;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index ca77d7a..1879cec 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -817,6 +817,9 @@
case AINPUT_EVENT_TYPE_CAPTURE: {
FAIL() << "Use 'consumeCaptureEvent' for CAPTURE events";
}
+ case AINPUT_EVENT_TYPE_TOUCH_MODE: {
+ FAIL() << "Use 'consumeTouchModeEvent' for TOUCH_MODE events";
+ }
case AINPUT_EVENT_TYPE_DRAG: {
FAIL() << "Use 'consumeDragEvent' for DRAG events";
}
@@ -874,6 +877,20 @@
EXPECT_EQ(y, dragEvent.getY());
}
+ void consumeTouchModeEvent(bool inTouchMode) {
+ const InputEvent* event = consume();
+ ASSERT_NE(nullptr, event) << mName.c_str()
+ << ": consumer should have returned non-NULL event.";
+ ASSERT_EQ(AINPUT_EVENT_TYPE_TOUCH_MODE, event->getType())
+ << "Got " << inputEventTypeToString(event->getType())
+ << " event instead of TOUCH_MODE event";
+
+ ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
+ << mName.c_str() << ": event displayId should always be NONE.";
+ const auto& touchModeEvent = static_cast<const TouchModeEvent&>(*event);
+ EXPECT_EQ(inTouchMode, touchModeEvent.isInTouchMode());
+ }
+
void assertNoEvents() {
InputEvent* event = consume();
if (event == nullptr) {
@@ -895,6 +912,10 @@
const auto& captureEvent = static_cast<CaptureEvent&>(*event);
ADD_FAILURE() << "Received capture event, pointerCaptureEnabled = "
<< (captureEvent.getPointerCaptureEnabled() ? "true" : "false");
+ } else if (event->getType() == AINPUT_EVENT_TYPE_TOUCH_MODE) {
+ const auto& touchModeEvent = static_cast<TouchModeEvent&>(*event);
+ ADD_FAILURE() << "Received touch mode event, inTouchMode = "
+ << (touchModeEvent.isInTouchMode() ? "true" : "false");
}
FAIL() << mName.c_str()
<< ": should not have received any events, so consume() should return NULL";
@@ -976,14 +997,18 @@
void setApplicationToken(sp<IBinder> token) { mInfo.applicationInfo.token = token; }
- void setFrame(const Rect& frame) {
+ void setFrame(const Rect& frame, const ui::Transform& displayTransform = ui::Transform()) {
mInfo.frameLeft = frame.left;
mInfo.frameTop = frame.top;
mInfo.frameRight = frame.right;
mInfo.frameBottom = frame.bottom;
- mInfo.transform.set(-frame.left, -frame.top);
mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(frame);
+
+ const Rect logicalDisplayFrame = displayTransform.transform(frame);
+ ui::Transform translate;
+ translate.set(-logicalDisplayFrame.left, -logicalDisplayFrame.top);
+ mInfo.transform = translate * displayTransform;
}
void setType(WindowInfo::Type type) { mInfo.type = type; }
@@ -1087,6 +1112,12 @@
mInputReceiver->consumeDragEvent(isExiting, x, y);
}
+ void consumeTouchModeEvent(bool inTouchMode) {
+ ASSERT_NE(mInputReceiver, nullptr)
+ << "Cannot consume events from a window with no receiver";
+ mInputReceiver->consumeTouchModeEvent(inTouchMode);
+ }
+
std::optional<uint32_t> receiveEvent(InputEvent** outEvent = nullptr) {
if (mInputReceiver == nullptr) {
ADD_FAILURE() << "Invalid receive event on window with no receiver";
@@ -1422,6 +1453,21 @@
window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
}
+TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+ // Inject a MotionEvent to an unknown display.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_NONE))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ // Window should receive motion event.
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+}
+
/**
* Calling setInputWindows once with FLAG_NOT_TOUCH_MODAL should not cause any issues.
* To ensure that window receives only events that were directly inside of it, add
@@ -1945,6 +1991,119 @@
0 /*expectedFlags*/);
}
+/**
+ * Ensure the correct coordinate spaces are used by InputDispatcher.
+ *
+ * InputDispatcher works in the display space, so its coordinate system is relative to the display
+ * panel. Windows get events in the window space, and get raw coordinates in the logical display
+ * space.
+ */
+class InputDispatcherDisplayProjectionTest : public InputDispatcherTest {
+public:
+ void SetUp() override {
+ InputDispatcherTest::SetUp();
+ mDisplayInfos.clear();
+ mWindowInfos.clear();
+ }
+
+ void addDisplayInfo(int displayId, const ui::Transform& transform) {
+ gui::DisplayInfo info;
+ info.displayId = displayId;
+ info.transform = transform;
+ mDisplayInfos.push_back(std::move(info));
+ mDispatcher->onWindowInfosChanged(mWindowInfos, mDisplayInfos);
+ }
+
+ void addWindow(const sp<WindowInfoHandle>& windowHandle) {
+ mWindowInfos.push_back(*windowHandle->getInfo());
+ mDispatcher->onWindowInfosChanged(mWindowInfos, mDisplayInfos);
+ }
+
+ // Set up a test scenario where the display has a scaled projection and there are two windows
+ // on the display.
+ std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
+ // The display has a projection that has a scale factor of 2 and 4 in the x and y directions
+ // respectively.
+ ui::Transform displayTransform;
+ displayTransform.set(2, 0, 0, 4);
+ addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
+
+ std::shared_ptr<FakeApplicationHandle> application =
+ std::make_shared<FakeApplicationHandle>();
+
+ // Add two windows to the display. Their frames are represented in the display space.
+ sp<FakeWindowHandle> firstWindow =
+ new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+ firstWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
+ addWindow(firstWindow);
+
+ sp<FakeWindowHandle> secondWindow =
+ new FakeWindowHandle(application, mDispatcher, "Second Window",
+ ADISPLAY_ID_DEFAULT);
+ secondWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+ secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
+ addWindow(secondWindow);
+ return {std::move(firstWindow), std::move(secondWindow)};
+ }
+
+private:
+ std::vector<gui::DisplayInfo> mDisplayInfos;
+ std::vector<gui::WindowInfo> mWindowInfos;
+};
+
+TEST_F(InputDispatcherDisplayProjectionTest, HitTestsInDisplaySpace) {
+ auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
+ // Send down to the first window. The point is represented in the display space. The point is
+ // selected so that if the hit test was done with the transform applied to it, then it would
+ // end up in the incorrect window.
+ NotifyMotionArgs downMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {PointF{75, 55}});
+ mDispatcher->notifyMotion(&downMotionArgs);
+
+ firstWindow->consumeMotionDown();
+ secondWindow->assertNoEvents();
+}
+
+// Ensure that when a MotionEvent is injected through the InputDispatcher::injectInputEvent() API,
+// the event should be treated as being in the logical display space.
+TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) {
+ auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
+ // Send down to the first window. The point is represented in the logical display space. The
+ // point is selected so that if the hit test was done in logical display space, then it would
+ // end up in the incorrect window.
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ PointF{75 * 2, 55 * 4});
+
+ firstWindow->consumeMotionDown();
+ secondWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) {
+ auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
+
+ // Send down to the second window.
+ NotifyMotionArgs downMotionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {PointF{150, 220}});
+ mDispatcher->notifyMotion(&downMotionArgs);
+
+ firstWindow->assertNoEvents();
+ const MotionEvent* event = secondWindow->consumeMotion();
+ EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
+
+ // Ensure that the events from the "getRaw" API are in logical display coordinates.
+ EXPECT_EQ(300, event->getRawX(0));
+ EXPECT_EQ(880, event->getRawY(0));
+
+ // Ensure that the x and y values are in the window's coordinate space.
+ // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
+ // the logical display space. This will be the origin of the window space.
+ EXPECT_EQ(100, event->getX(0));
+ EXPECT_EQ(80, event->getY(0));
+}
+
using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
sp<IBinder>, sp<IBinder>)>;
@@ -2725,7 +2884,6 @@
SCOPED_TRACE("Check default value of touch mode");
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
setFocusedWindow(window);
-
window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
SCOPED_TRACE("Remove the window to trigger focus loss");
@@ -2735,6 +2893,7 @@
SCOPED_TRACE("Disable touch mode");
mDispatcher->setInTouchMode(false);
+ window->consumeTouchModeEvent(false);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
setFocusedWindow(window);
@@ -2747,6 +2906,7 @@
SCOPED_TRACE("Enable touch mode again");
mDispatcher->setInTouchMode(true);
+ window->consumeTouchModeEvent(true);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
setFocusedWindow(window);
@@ -5892,4 +6052,43 @@
window->assertNoEvents();
}
+class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
+protected:
+ std::shared_ptr<FakeApplicationHandle> mApp;
+ sp<FakeWindowHandle> mWindow;
+ sp<FakeWindowHandle> mSecondWindow;
+
+ void SetUp() override {
+ InputDispatcherTest::SetUp();
+
+ mApp = std::make_shared<FakeApplicationHandle>();
+ mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+ mWindow->setFocusable(true);
+ mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
+ mSecondWindow->setFocusable(true);
+
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
+
+ setFocusedWindow(mWindow);
+ mWindow->consumeFocusEvent(true);
+ }
+
+ void changeAndVerifyTouchMode(bool inTouchMode) {
+ mDispatcher->setInTouchMode(inTouchMode);
+ mWindow->consumeTouchModeEvent(inTouchMode);
+ mSecondWindow->consumeTouchModeEvent(inTouchMode);
+ }
+};
+
+TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchModeOnFocusedWindow) {
+ changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode);
+}
+
+TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
+ mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode);
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index ef05fe2..82c91e7 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -223,7 +223,7 @@
* of a camera where the buffer remains in native orientation,
* we want the pixels to always be upright.
*/
- sp<Layer> p = mDrawingParent.promote();
+ auto p = mDrawingParent;
if (p != nullptr) {
const auto parentTransform = p->getTransform();
tr = tr * inverseOrientation(parentTransform.getOrientation());
@@ -346,13 +346,13 @@
}
} // namespace
-bool BufferLayer::onPostComposition(const DisplayDevice* display,
+void BufferLayer::onPostComposition(const DisplayDevice* display,
const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
const CompositorTiming& compositorTiming) {
// mFrameLatencyNeeded is true when a new frame was latched for the
// composition.
- if (!mBufferInfo.mFrameLatencyNeeded) return false;
+ if (!mBufferInfo.mFrameLatencyNeeded) return;
// Update mFrameEventHistory.
{
@@ -426,7 +426,6 @@
mFrameTracker.advanceFrame();
mBufferInfo.mFrameLatencyNeeded = false;
- return true;
}
void BufferLayer::gatherBufferInfo() {
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 2da73f8..61e7ac5 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -77,7 +77,7 @@
bool isHdrY410() const override;
- bool onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& glDoneFence,
+ void onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
const CompositorTiming&) override;
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 96b2247..c79fa11 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -438,7 +438,7 @@
}
void BufferLayerConsumer::onSidebandStreamChanged() {
- FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
+ [[maybe_unused]] FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
{
Mutex::Autolock lock(mFrameAvailableMutex);
unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get();
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 8bbe438..f98681e 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -65,16 +65,6 @@
mConsumer->setTransformHint(mTransformHint);
}
-std::vector<OccupancyTracker::Segment> BufferQueueLayer::getOccupancyHistory(bool forceFlush) {
- std::vector<OccupancyTracker::Segment> history;
- status_t result = mConsumer->getOccupancyHistory(forceFlush, &history);
- if (result != NO_ERROR) {
- ALOGW("[%s] Failed to obtain occupancy history (%d)", getDebugName(), result);
- return {};
- }
- return history;
-}
-
void BufferQueueLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
if (!mConsumer->releasePendingBuffer()) {
return;
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index be2902b..a3bd725 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -44,8 +44,6 @@
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
- std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
-
// If a buffer was replaced this frame, release the former buffer
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 4eeaba1..132ee9d 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -40,13 +40,13 @@
namespace {
void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
const sp<GraphicBuffer>& buffer, uint64_t framenumber,
- const sp<Fence>& releaseFence, uint32_t transformHint,
+ const sp<Fence>& releaseFence,
uint32_t currentMaxAcquiredBufferCount) {
if (!listener) {
return;
}
listener->onReleaseBuffer({buffer->getId(), framenumber},
- releaseFence ? releaseFence : Fence::NO_FENCE, transformHint,
+ releaseFence ? releaseFence : Fence::NO_FENCE,
currentMaxAcquiredBufferCount);
}
} // namespace
@@ -64,7 +64,7 @@
if (mBufferInfo.mBuffer != nullptr && !isClone()) {
callReleaseBufferCallback(mDrawingState.releaseBufferListener,
mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber,
- mBufferInfo.mFence, mTransformHint,
+ mBufferInfo.mFence,
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
mOwnerUid));
}
@@ -479,7 +479,7 @@
// call any release buffer callbacks if set.
callReleaseBufferCallback(mDrawingState.releaseBufferListener,
mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
- mDrawingState.acquireFence, mTransformHint,
+ mDrawingState.acquireFence,
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
mOwnerUid));
decrementPendingBufferCount();
@@ -491,9 +491,9 @@
} else if (mLastClientCompositionFence != nullptr) {
callReleaseBufferCallback(mDrawingState.releaseBufferListener,
mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
- mLastClientCompositionFence, mTransformHint,
+ mLastClientCompositionFence,
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
- mOwnerUid));
+ mOwnerUid));
mLastClientCompositionFence = nullptr;
}
}
@@ -989,7 +989,7 @@
* how to go from screen space back to window space.
*/
ui::Transform BufferStateLayer::getInputTransform() const {
- sp<Layer> parent = mDrawingParent.promote();
+ auto parent = mDrawingParent;
if (parent == nullptr) {
return ui::Transform();
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index ecfd901..e958549 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -381,12 +381,7 @@
if (outputDependentState.overrideInfo.buffer != nullptr) {
displayFrame = outputDependentState.overrideInfo.displayFrame;
- sourceCrop =
- FloatRect(0.f, 0.f,
- static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
- ->getWidth()),
- static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
- ->getHeight()));
+ sourceCrop = displayFrame.toFloatRect();
}
ALOGV("Writing display frame [%d, %d, %d, %d]", displayFrame.left, displayFrame.top,
@@ -737,7 +732,7 @@
// framebuffer space of the override buffer to layer space.
const ProjectionSpace& layerSpace = getOutput().getState().layerStackSpace;
const ui::Transform transform = getState().overrideInfo.displaySpace.getTransform(layerSpace);
- const Rect boundaries = transform.transform(getState().overrideInfo.displayFrame);
+ const Rect boundaries = transform.transform(getState().overrideInfo.displaySpace.getContent());
LayerFE::LayerSettings settings;
settings.geometry = renderengine::Geometry{
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index ad5e931..2272099 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -315,7 +315,7 @@
state.overrideInfo = {
.buffer = mNewCachedSet->getBuffer(),
.acquireFence = mNewCachedSet->getDrawFence(),
- .displayFrame = mNewCachedSet->getTextureBounds(),
+ .displayFrame = mNewCachedSet->getBounds(),
.dataspace = mNewCachedSet->getOutputDataspace(),
.displaySpace = mNewCachedSet->getOutputSpace(),
.damageRegion = Region::INVALID_REGION,
@@ -355,7 +355,7 @@
state.overrideInfo = {
.buffer = currentLayerIter->getBuffer(),
.acquireFence = currentLayerIter->getDrawFence(),
- .displayFrame = currentLayerIter->getTextureBounds(),
+ .displayFrame = currentLayerIter->getBounds(),
.dataspace = currentLayerIter->getOutputDataspace(),
.displaySpace = currentLayerIter->getOutputSpace(),
.damageRegion = Region(),
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 53b71b7..fbc2089 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -876,7 +876,7 @@
84.f / 255.f};
const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
const Rect OutputLayerWriteStateToHWCTest::kOverrideDisplayFrame{1002, 1003, 1004, 20044};
-const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{0.f, 0.f, 4.f, 5.f};
+const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{1002, 1003, 1004, 20044};
const Region OutputLayerWriteStateToHWCTest::kOutputSpaceVisibleRegion{
Rect{1005, 1006, 1007, 1008}};
const Region OutputLayerWriteStateToHWCTest::kOverrideVisibleRegion{Rect{1006, 1007, 1008, 1009}};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 87afa22..5707c67 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -179,9 +179,23 @@
if (mDrawingState.sidebandStream != nullptr) {
mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount();
}
+
if (mHadClonedChild) {
mFlinger->mNumClones--;
}
+
+ for (auto const& child : mCurrentChildren) {
+ if (child->mCurrentParent == this) child->mCurrentParent = nullptr;
+ if (child->mDrawingParent == this) {
+ child->mDrawingParent = nullptr;
+ }
+ }
+ for (auto const& child : mDrawingChildren) {
+ if (child->mCurrentParent == this) child->mCurrentParent = nullptr;
+ if (child->mDrawingParent == this) {
+ child->mDrawingParent = nullptr;
+ }
+ }
}
LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp<Client> client, std::string name,
@@ -237,7 +251,7 @@
}
sp<Layer> Layer::getRootLayer() {
- sp<Layer> parent = getParent();
+ auto parent = getParent();
if (parent == nullptr) {
return this;
}
@@ -426,20 +440,6 @@
void Layer::prepareGeometryCompositionState() {
const auto& drawingState{getDrawingState()};
-
- int type = drawingState.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
- int appId = drawingState.metadata.getInt32(METADATA_OWNER_UID, 0);
- sp<Layer> parent = mDrawingParent.promote();
- if (parent.get()) {
- auto& parentState = parent->getDrawingState();
- const int parentType = parentState.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
- const int parentAppId = parentState.metadata.getInt32(METADATA_OWNER_UID, 0);
- if (parentType > 0 && parentAppId > 0) {
- type = parentType;
- appId = parentAppId;
- }
- }
-
auto* compositionState = editCompositionState();
compositionState->geomBufferSize = getBufferSize(drawingState);
@@ -676,7 +676,7 @@
return true;
}
- const auto p = mDrawingParent.promote();
+ const auto p = mDrawingParent;
return (p != nullptr) ? p->isSecure() : false;
}
@@ -859,7 +859,7 @@
if (getDrawingState().isTrustedOverlay) {
return true;
}
- const auto& p = mDrawingParent.promote();
+ const auto p = mDrawingParent;
return (p != nullptr) && p->isTrustedOverlay();
}
@@ -1039,7 +1039,7 @@
return mDrawingState.frameRateSelectionPriority;
}
// If not, search whether its parents have it set.
- sp<Layer> parent = getParent();
+ auto parent = getParent();
if (parent != nullptr) {
return parent->getFrameRateSelectionPriority();
}
@@ -1052,10 +1052,11 @@
};
ui::LayerStack Layer::getLayerStack() const {
- if (const auto parent = mDrawingParent.promote()) {
- return parent->getLayerStack();
+ auto p = mDrawingParent;
+ if (p == nullptr) {
+ return getDrawingState().layerStack;
}
- return getDrawingState().layerStack;
+ return mDrawingParent->getLayerStack();
}
bool Layer::setShadowRadius(float shadowRadius) {
@@ -1100,7 +1101,7 @@
return mDrawingState.stretchEffect;
}
- sp<Layer> parent = getParent();
+ auto parent = mDrawingParent;
if (parent != nullptr) {
auto effect = parent->getStretchEffect();
if (effect.hasEffect()) {
@@ -1315,7 +1316,7 @@
bool Layer::isHiddenByPolicy() const {
const State& s(mDrawingState);
- const auto& parent = mDrawingParent.promote();
+ auto parent = mDrawingParent;
if (parent != nullptr && parent->isHiddenByPolicy()) {
return true;
}
@@ -1362,7 +1363,7 @@
LayerDebugInfo info;
const State& ds = getDrawingState();
info.mName = getName();
- sp<Layer> parent = mDrawingParent.promote();
+ auto parent = mDrawingParent;
info.mParentName = parent ? parent->getName() : "none"s;
info.mType = getType();
info.mTransparentRegion = ds.activeTransparentRegion_legacy;
@@ -1594,7 +1595,7 @@
void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
for (const sp<Layer>& child : mDrawingChildren) {
- child->mDrawingParent = newParent;
+ child->mDrawingParent = newParent.get();
child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform,
newParent->mEffectiveShadowRadius);
}
@@ -1614,7 +1615,7 @@
}
}
- sp<Layer> parent = getParent();
+ auto parent = getParent();
if (parent != nullptr) {
parent->removeChild(this);
}
@@ -1649,7 +1650,7 @@
mat4 Layer::getColorTransform() const {
mat4 colorTransform = mat4(getDrawingState().colorTransform);
- if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
+ if (auto parent = mDrawingParent; parent != nullptr) {
colorTransform = parent->getColorTransform() * colorTransform;
}
return colorTransform;
@@ -1657,7 +1658,7 @@
bool Layer::hasColorTransform() const {
bool hasColorTransform = getDrawingState().hasColorTransform;
- if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
+ if (auto parent = mDrawingParent; parent != nullptr) {
hasColorTransform = hasColorTransform || parent->hasColorTransform();
}
return hasColorTransform;
@@ -1671,7 +1672,7 @@
}
void Layer::setParent(const sp<Layer>& layer) {
- mCurrentParent = layer;
+ mCurrentParent = layer.get();
}
int32_t Layer::getZ(LayerVector::StateSet) const {
@@ -1875,7 +1876,7 @@
}
half Layer::getAlpha() const {
- const auto& p = mDrawingParent.promote();
+ auto p = mDrawingParent;
half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
return parentAlpha * getDrawingState().color.a;
@@ -1886,7 +1887,7 @@
if (fixedTransformHint != ui::Transform::ROT_INVALID) {
return fixedTransformHint;
}
- const auto& p = mCurrentParent.promote();
+ auto p = mCurrentParent;
if (!p) return fixedTransformHint;
return p->getFixedTransformHint();
}
@@ -1897,7 +1898,7 @@
}
int32_t Layer::getBackgroundBlurRadius() const {
- const auto& p = mDrawingParent.promote();
+ auto p = mDrawingParent;
half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
return parentAlpha * getDrawingState().backgroundBlurRadius;
@@ -1915,9 +1916,8 @@
Layer::RoundedCornerState Layer::getRoundedCornerState() const {
// Get parent settings
RoundedCornerState parentSettings;
- const auto& parent = mDrawingParent.promote();
- if (parent != nullptr) {
- parentSettings = parent->getRoundedCornerState();
+ if (mDrawingParent != nullptr) {
+ parentSettings = mDrawingParent->getRoundedCornerState();
if (parentSettings.radius > 0) {
ui::Transform t = getActiveTransform(getDrawingState());
t = t.inverse();
@@ -1936,8 +1936,9 @@
Rect layerCropRect = getCroppedBufferSize(getDrawingState());
const float radius = getDrawingState().cornerRadius;
RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius);
+ const bool layerSettingsValid = layerSettings.radius > 0 && layerCropRect.isValid();
- if (layerSettings.radius > 0 && parentSettings.radius > 0) {
+ if (layerSettingsValid && parentSettings.radius > 0) {
// If the parent and the layer have rounded corner settings, use the parent settings if the
// parent crop is entirely inside the layer crop.
// This has limitations and cause rendering artifacts. See b/200300845 for correct fix.
@@ -1949,7 +1950,7 @@
} else {
return layerSettings;
}
- } else if (layerSettings.radius > 0) {
+ } else if (layerSettingsValid) {
return layerSettings;
} else if (parentSettings.radius > 0) {
return parentSettings;
@@ -2132,7 +2133,7 @@
LayerProtoHelper::writeToProtoDeprecated(requestedTransform,
layerInfo->mutable_requested_transform());
- auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
+ auto parent = useDrawing ? mDrawingParent : mCurrentParent;
if (parent != nullptr) {
layerInfo->set_parent(parent->sequence);
} else {
@@ -2279,9 +2280,9 @@
}
void Layer::fillTouchOcclusionMode(WindowInfo& info) {
- sp<Layer> p = this;
+ Layer* p = this;
while (p != nullptr && !p->hasInputInfo()) {
- p = p->mDrawingParent.promote();
+ p = p->mDrawingParent;
}
if (p != nullptr) {
info.touchOcclusionMode = p->mDrawingState.inputInfo.touchOcclusionMode;
@@ -2293,9 +2294,8 @@
if (mode == gui::DropInputMode::ALL) {
return mode;
}
- sp<Layer> parent = mDrawingParent.promote();
- if (parent) {
- gui::DropInputMode parentMode = parent->getDropInputMode();
+ if (mDrawingParent) {
+ gui::DropInputMode parentMode = mDrawingParent->getDropInputMode();
if (parentMode != gui::DropInputMode::NONE) {
return parentMode;
}
@@ -2322,8 +2322,7 @@
}
// Check if the parent has set an alpha on the layer
- sp<Layer> parent = mDrawingParent.promote();
- if (parent && parent->getAlpha() != 1.0_hf) {
+ if (mDrawingParent && mDrawingParent->getAlpha() != 1.0_hf) {
info.inputFeatures |= WindowInfo::Feature::DROP_INPUT;
ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(),
static_cast<float>(getAlpha()));
@@ -2421,10 +2420,10 @@
if (mClonedChild != nullptr) {
return this;
}
- if (mDrawingParent == nullptr || mDrawingParent.promote() == nullptr) {
+ if (mDrawingParent == nullptr) {
return nullptr;
}
- return mDrawingParent.promote()->getClonedRoot();
+ return mDrawingParent->getClonedRoot();
}
bool Layer::hasInputInfo() const {
@@ -2611,8 +2610,7 @@
return true;
}
- sp<Layer> parent = mDrawingParent.promote();
- return parent && parent->isInternalDisplayOverlay();
+ return mDrawingParent && mDrawingParent->isInternalDisplayOverlay();
}
void Layer::setClonedChild(const sp<Layer>& clonedChild) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index d17c05b..07b2eb5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -525,12 +525,10 @@
* called after composition.
* returns true if the layer latched a new buffer this frame.
*/
- virtual bool onPostComposition(const DisplayDevice*,
+ virtual void onPostComposition(const DisplayDevice*,
const std::shared_ptr<FenceTime>& /*glDoneFence*/,
const std::shared_ptr<FenceTime>& /*presentFence*/,
- const CompositorTiming&) {
- return false;
- }
+ const CompositorTiming&) {}
// If a buffer was replaced this frame, release the former buffer
virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
@@ -591,10 +589,6 @@
}
virtual FrameRate getFrameRateForLayerTree() const;
- virtual std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool /*forceFlush*/) {
- return {};
- }
-
virtual bool getTransformToDisplayInverse() const { return false; }
// Returns how rounded corners should be drawn for this layer.
@@ -801,12 +795,12 @@
// Returns index if removed, or negative value otherwise
// for symmetry with Vector::remove
ssize_t removeChild(const sp<Layer>& layer);
- sp<Layer> getParent() const { return mCurrentParent.promote(); }
// Should be called with the surfaceflinger statelock held
bool isAtRoot() const { return mIsAtRoot; }
void setIsAtRoot(bool isAtRoot) { mIsAtRoot = isAtRoot; }
+ Layer* getParent() const { return mCurrentParent; }
bool hasParent() const { return getParent() != nullptr; }
Rect getScreenBounds(bool reduceTransparentRegion = true) const;
bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
@@ -1013,8 +1007,8 @@
LayerVector mCurrentChildren{LayerVector::StateSet::Current};
LayerVector mDrawingChildren{LayerVector::StateSet::Drawing};
- wp<Layer> mCurrentParent;
- wp<Layer> mDrawingParent;
+ Layer* mCurrentParent = nullptr;
+ Layer* mDrawingParent = nullptr;
// Window types from WindowManager.LayoutParams
const gui::WindowInfo::Type mWindowType;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e90af3a..acb81dc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2308,13 +2308,9 @@
}
for (const auto& layer: mLayersWithQueuedFrames) {
- const bool frameLatched =
- layer->onPostComposition(display, glCompositionDoneFenceTime,
- mPreviousPresentFences[0].fenceTime, compositorTiming);
+ layer->onPostComposition(display, glCompositionDoneFenceTime,
+ mPreviousPresentFences[0].fenceTime, compositorTiming);
layer->releasePendingBuffer(/*dequeueReadyTime*/ now);
- if (frameLatched) {
- recordBufferingStats(layer->getName(), layer->getOccupancyHistory(false));
- }
}
std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>>
@@ -3244,8 +3240,6 @@
if (!mLayersPendingRemoval.isEmpty()) {
// Notify removed layers now that they can't be drawn from
for (const auto& l : mLayersPendingRemoval) {
- recordBufferingStats(l->getName(), l->getOccupancyHistory(true));
-
// Ensure any buffers set to display on any children are released.
if (l->isRemovedFromCurrentState()) {
l->latchAndReleaseBuffer();
@@ -3418,6 +3412,7 @@
states.add(composerState);
lbc->updateTransformHint(mActiveDisplayTransformHint);
+
if (outTransformHint) {
*outTransformHint = mActiveDisplayTransformHint;
}
@@ -3962,7 +3957,7 @@
}
if (what & layer_state_t::eLayerChanged) {
// NOTE: index needs to be calculated before we update the state
- const auto& p = layer->getParent();
+ auto p = layer->getParent();
if (p == nullptr) {
ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
if (layer->setLayer(s.z) && idx >= 0) {
@@ -3980,7 +3975,7 @@
}
if (what & layer_state_t::eRelativeLayerChanged) {
// NOTE: index needs to be calculated before we update the state
- const auto& p = layer->getParent();
+ auto p = layer->getParent();
const auto& relativeHandle = s.relativeLayerSurfaceControl ?
s.relativeLayerSurfaceControl->getHandle() : nullptr;
if (p == nullptr) {
@@ -4814,24 +4809,6 @@
bucketTimeSec, percent);
}
-void SurfaceFlinger::recordBufferingStats(const std::string& layerName,
- std::vector<OccupancyTracker::Segment>&& history) {
- Mutex::Autolock lock(getBE().mBufferingStatsMutex);
- auto& stats = getBE().mBufferingStats[layerName];
- for (const auto& segment : history) {
- if (!segment.usedThirdBuffer) {
- stats.twoBufferTime += segment.totalTime;
- }
- if (segment.occupancyAverage < 1.0f) {
- stats.doubleBufferedTime += segment.totalTime;
- } else if (segment.occupancyAverage < 2.0f) {
- stats.tripleBufferedTime += segment.totalTime;
- }
- ++stats.numSegments;
- stats.totalTime += segment.totalTime;
- }
-}
-
void SurfaceFlinger::dumpFrameEventsLocked(std::string& result) {
result.append("Layer frame timestamps:\n");
// Traverse all layers to dump frame-events for each layer
@@ -4839,38 +4816,6 @@
[&] (Layer* layer) { layer->dumpFrameEvents(result); });
}
-void SurfaceFlinger::dumpBufferingStats(std::string& result) const {
- result.append("Buffering stats:\n");
- result.append(" [Layer name] <Active time> <Two buffer> "
- "<Double buffered> <Triple buffered>\n");
- Mutex::Autolock lock(getBE().mBufferingStatsMutex);
- typedef std::tuple<std::string, float, float, float> BufferTuple;
- std::map<float, BufferTuple, std::greater<float>> sorted;
- for (const auto& statsPair : getBE().mBufferingStats) {
- const char* name = statsPair.first.c_str();
- const SurfaceFlingerBE::BufferingStats& stats = statsPair.second;
- if (stats.numSegments == 0) {
- continue;
- }
- float activeTime = ns2ms(stats.totalTime) / 1000.0f;
- float twoBufferRatio = static_cast<float>(stats.twoBufferTime) /
- stats.totalTime;
- float doubleBufferRatio = static_cast<float>(
- stats.doubleBufferedTime) / stats.totalTime;
- float tripleBufferRatio = static_cast<float>(
- stats.tripleBufferedTime) / stats.totalTime;
- sorted.insert({activeTime, {name, twoBufferRatio,
- doubleBufferRatio, tripleBufferRatio}});
- }
- for (const auto& sortedPair : sorted) {
- float activeTime = sortedPair.first;
- const BufferTuple& values = sortedPair.second;
- StringAppendF(&result, " [%s] %.2f %.3f %.3f %.3f\n", std::get<0>(values).c_str(),
- activeTime, std::get<1>(values), std::get<2>(values), std::get<3>(values));
- }
- result.append("\n");
-}
-
void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const {
for (const auto& [token, display] : mDisplays) {
const auto displayId = PhysicalDisplayId::tryCast(display->getId());
@@ -5062,8 +5007,6 @@
StringAppendF(&result, "HWC missed frame count: %u\n", mHwcFrameMissedCount.load());
StringAppendF(&result, "GPU missed frame count: %u\n\n", mGpuFrameMissedCount.load());
- dumpBufferingStats(result);
-
/*
* Dump the visible layer list
*/
@@ -6183,7 +6126,7 @@
return;
}
- sp<Layer> p = layer;
+ auto p = layer;
while (p != nullptr) {
if (excludeLayers.count(p) != 0) {
return;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1217d63..1f0e42d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -32,7 +32,6 @@
#include <gui/ISurfaceComposerClient.h>
#include <gui/ITransactionCompletedListener.h>
#include <gui/LayerState.h>
-#include <gui/OccupancyTracker.h>
#include <layerproto/LayerProtoHeader.h>
#include <math/mat4.h>
#include <renderengine/LayerSettings.h>
@@ -155,22 +154,6 @@
nsecs_t mFrameBuckets[NUM_BUCKETS] = {};
nsecs_t mTotalTime = 0;
std::atomic<nsecs_t> mLastSwapTime = 0;
-
- // Double- vs. triple-buffering stats
- struct BufferingStats {
- size_t numSegments = 0;
- nsecs_t totalTime = 0;
-
- // "Two buffer" means that a third buffer was never used, whereas
- // "double-buffered" means that on average the segment only used two
- // buffers (though it may have used a third for some part of the
- // segment)
- nsecs_t twoBufferTime = 0;
- nsecs_t doubleBufferedTime = 0;
- nsecs_t tripleBufferedTime = 0;
- };
- mutable Mutex mBufferingStatsMutex;
- std::unordered_map<std::string, BufferingStats> mBufferingStats;
};
class SurfaceFlinger : public BnSurfaceComposer,
@@ -1158,10 +1141,6 @@
void dumpStaticScreenStats(std::string& result) const;
// Not const because each Layer needs to query Fences and cache timestamps.
void dumpFrameEventsLocked(std::string& result);
-
- void recordBufferingStats(const std::string& layerName,
- std::vector<OccupancyTracker::Segment>&& history);
- void dumpBufferingStats(std::string& result) const;
void dumpDisplayIdentificationData(std::string& result) const REQUIRES(mStateLock);
void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const;
void dumpWideColorInfo(std::string& result) const REQUIRES(mStateLock);
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 7c1f21f..bf2038b 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -564,7 +564,7 @@
layerRecords += record.second.stats.size();
}
- return mTimeStats.stats.size() < MAX_NUM_LAYER_STATS;
+ return layerRecords < MAX_NUM_LAYER_STATS;
}
void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index e5872c1..9cb617a 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -208,6 +208,37 @@
}
}
+// b/200781179 - don't round a layer without a valid crop
+// This behaviour should be fixed since we treat buffer layers differently than
+// effect or container layers.
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusInvalidCrop) {
+ sp<SurfaceControl> parent;
+ sp<SurfaceControl> child;
+ const uint8_t size = 64;
+ const uint8_t testArea = 4;
+ const float cornerRadius = 20.0f;
+ ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::GREEN, size, size));
+ ASSERT_NO_FATAL_FAILURE(child = createColorLayer("child", Color::RED));
+
+ Transaction().setCornerRadius(child, cornerRadius).reparent(child, parent).show(child).apply();
+ {
+ const uint8_t bottom = size - 1;
+ const uint8_t right = size - 1;
+ auto shot = getScreenCapture();
+ std::this_thread::sleep_for(std::chrono::seconds(5));
+ // Solid corners since we don't round a layer without a valid crop
+ shot->expectColor(Rect(0, 0, testArea, testArea), Color::RED);
+ shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::RED);
+ shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::RED);
+ shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::RED);
+ // Solid center
+ shot->expectColor(Rect(size / 2 - testArea / 2, size / 2 - testArea / 2,
+ size / 2 + testArea / 2, size / 2 + testArea / 2),
+ Color::RED);
+ }
+}
+
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusRotated) {
sp<SurfaceControl> parent;
sp<SurfaceControl> child;
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index 3847a51..e50c2fc 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -31,7 +31,7 @@
public:
static void function(void* callbackContext, ReleaseCallbackId callbackId,
const sp<Fence>& releaseFence,
- uint32_t /*currentMaxAcquiredBufferCount*/) {
+ std::optional<uint32_t> /*currentMaxAcquiredBufferCount*/) {
if (!callbackContext) {
FAIL() << "failed to get callback context";
}
@@ -385,4 +385,84 @@
ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
}
+TEST_F(ReleaseBufferCallbackTest, DISABLED_SetBuffer_OverwriteBuffers) {
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+ // Create transaction with a buffer.
+ Transaction transaction;
+ transaction.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
+ firstBufferCallbackId, releaseCallback->getCallback());
+
+ sp<GraphicBuffer> secondBuffer = getBuffer();
+ ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
+
+ // Call setBuffer on the same transaction with a different buffer.
+ transaction.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
+ secondBufferCallbackId, releaseCallback->getCallback());
+
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
+TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Transactions_OverwriteBuffers) {
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+ // Create transaction with a buffer.
+ Transaction transaction1;
+ transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
+ firstBufferCallbackId, releaseCallback->getCallback());
+
+ sp<GraphicBuffer> secondBuffer = getBuffer();
+ ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
+
+ // Create a second transaction with a new buffer for the same layer.
+ Transaction transaction2;
+ transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
+ secondBufferCallbackId, releaseCallback->getCallback());
+
+ // merge transaction1 into transaction2 so ensure we get a proper buffer release callback.
+ transaction1.merge(std::move(transaction2));
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
+TEST_F(ReleaseBufferCallbackTest, DISABLED_MergeBuffers_Different_Processes) {
+ sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener();
+ sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener();
+
+ TransactionCompletedListener::setInstance(firstCompletedListener);
+
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+ Transaction transaction1;
+ transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
+ firstBufferCallbackId, releaseCallback->getCallback());
+
+ // Sent a second buffer to allow the first buffer to get released.
+ sp<GraphicBuffer> secondBuffer = getBuffer();
+ ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
+
+ Transaction transaction2;
+ transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
+ secondBufferCallbackId, releaseCallback->getCallback());
+
+ // Set a different TransactionCompletedListener to mimic a second process
+ TransactionCompletedListener::setInstance(secondCompletedListener);
+ Transaction().merge(std::move(transaction1)).merge(std::move(transaction2)).apply();
+
+ // Make sure we can still get the release callback even though the merge happened in a different
+ // process.
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 7072439..db3b572 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -289,7 +289,7 @@
}
static void setLayerDrawingParent(const sp<Layer>& layer, const sp<Layer>& drawingParent) {
- layer->mDrawingParent = drawingParent;
+ layer->mDrawingParent = drawingParent.get();
}
/* ------------------------------------------------------------------------